summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTae-Young Chung <ty83.chung@samsung.com>2018-03-13 17:04:17 +0900
committerTae-Young Chung <ty83.chung@samsung.com>2018-03-13 17:06:54 +0900
commit45032639c6c5ee11b79d2d3faaca6e9be6e4be3b (patch)
tree1d636d696c1f1ea6d79fb469758c465f27a3d37c /src
parent125c0b85df1bf388ae210fc7a87872984f865769 (diff)
downloadhdf5-master.tar.gz
hdf5-master.tar.bz2
hdf5-master.zip
Import upstream hdf5-1.10.1HEADupstream/1.10.1upstreammaster
Upstream repository is https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.1/src/ Change-Id: I4ec4c291940b7bb75722ea16813fbe55736374a6 Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt992
-rw-r--r--src/COPYING13
-rw-r--r--src/H5.c1110
-rw-r--r--src/H5A.c1748
-rw-r--r--src/H5AC.c3336
-rw-r--r--src/H5ACdbg.c492
-rw-r--r--src/H5AClog.c1105
-rw-r--r--src/H5ACmodule.h33
-rw-r--r--src/H5ACmpio.c2306
-rw-r--r--src/H5ACpkg.h506
-rw-r--r--src/H5ACprivate.h502
-rw-r--r--src/H5ACproxy_entry.c661
-rw-r--r--src/H5ACpublic.h574
-rw-r--r--src/H5Abtree2.c548
-rw-r--r--src/H5Adense.c1906
-rw-r--r--src/H5Adeprec.c411
-rw-r--r--src/H5Aint.c2435
-rw-r--r--src/H5Amodule.h33
-rw-r--r--src/H5Apkg.h275
-rw-r--r--src/H5Aprivate.h89
-rw-r--r--src/H5Apublic.h118
-rw-r--r--src/H5Atest.c148
-rw-r--r--src/H5B.c2107
-rw-r--r--src/H5B2.c1632
-rw-r--r--src/H5B2cache.c1362
-rw-r--r--src/H5B2dbg.c376
-rw-r--r--src/H5B2hdr.c741
-rw-r--r--src/H5B2int.c1948
-rw-r--r--src/H5B2internal.c1441
-rw-r--r--src/H5B2leaf.c1063
-rw-r--r--src/H5B2module.h34
-rw-r--r--src/H5B2pkg.h487
-rw-r--r--src/H5B2private.h162
-rw-r--r--src/H5B2public.h52
-rw-r--r--src/H5B2stat.c147
-rw-r--r--src/H5B2test.c687
-rw-r--r--src/H5Bcache.c387
-rw-r--r--src/H5Bdbg.c291
-rw-r--r--src/H5Bmodule.h33
-rw-r--r--src/H5Bpkg.h94
-rw-r--r--src/H5Bprivate.h180
-rw-r--r--src/H5Bpublic.h39
-rw-r--r--src/H5C.c8952
-rw-r--r--src/H5CS.c330
-rw-r--r--src/H5CSprivate.h36
-rw-r--r--src/H5Cdbg.c1597
-rw-r--r--src/H5Cepoch.c240
-rw-r--r--src/H5Cimage.c3569
-rw-r--r--src/H5Clog.c368
-rw-r--r--src/H5Cmodule.h33
-rw-r--r--src/H5Cmpio.c1632
-rw-r--r--src/H5Cpkg.h4956
-rw-r--r--src/H5Cprefetched.c350
-rw-r--r--src/H5Cprivate.h2355
-rw-r--r--src/H5Cpublic.h59
-rw-r--r--src/H5Cquery.c484
-rw-r--r--src/H5Ctag.c907
-rw-r--r--src/H5Ctest.c161
-rw-r--r--src/H5D.c1089
-rw-r--r--src/H5Dbtree.c1527
-rw-r--r--src/H5Dbtree2.c1575
-rw-r--r--src/H5Dchunk.c6491
-rw-r--r--src/H5Dcompact.c597
-rw-r--r--src/H5Dcontig.c1585
-rw-r--r--src/H5Ddbg.c98
-rw-r--r--src/H5Ddeprec.c378
-rw-r--r--src/H5Dearray.c1834
-rw-r--r--src/H5Defl.c618
-rw-r--r--src/H5Dfarray.c1687
-rw-r--r--src/H5Dfill.c713
-rw-r--r--src/H5Dint.c3676
-rw-r--r--src/H5Dio.c1313
-rw-r--r--src/H5Dlayout.c703
-rw-r--r--src/H5Dmodule.h33
-rw-r--r--src/H5Dmpio.c1839
-rw-r--r--src/H5Dnone.c495
-rw-r--r--src/H5Doh.c467
-rw-r--r--src/H5Dpkg.h783
-rw-r--r--src/H5Dprivate.h209
-rw-r--r--src/H5Dpublic.h198
-rw-r--r--src/H5Dscatgath.c1106
-rw-r--r--src/H5Dselect.c314
-rw-r--r--src/H5Dsingle.c555
-rw-r--r--src/H5Dtest.c269
-rw-r--r--src/H5Dvirtual.c2945
-rw-r--r--src/H5E.c1742
-rw-r--r--src/H5EA.c1066
-rw-r--r--src/H5EAcache.c2226
-rw-r--r--src/H5EAdbg.c476
-rw-r--r--src/H5EAdblkpage.c341
-rw-r--r--src/H5EAdblock.c485
-rw-r--r--src/H5EAhdr.c826
-rw-r--r--src/H5EAiblock.c514
-rw-r--r--src/H5EAint.c139
-rw-r--r--src/H5EAmodule.h33
-rw-r--r--src/H5EApkg.h483
-rw-r--r--src/H5EAprivate.h157
-rw-r--r--src/H5EAsblock.c451
-rw-r--r--src/H5EAstat.c114
-rw-r--r--src/H5EAtest.c485
-rw-r--r--src/H5Edefin.h230
-rw-r--r--src/H5Edeprec.c445
-rw-r--r--src/H5Einit.h888
-rw-r--r--src/H5Eint.c1016
-rw-r--r--src/H5Emodule.h34
-rw-r--r--src/H5Epkg.h149
-rw-r--r--src/H5Eprivate.h192
-rw-r--r--src/H5Epubgen.h406
-rw-r--r--src/H5Epublic.h226
-rw-r--r--src/H5Eterm.h232
-rw-r--r--src/H5F.c2126
-rw-r--r--src/H5FA.c814
-rw-r--r--src/H5FAcache.c1305
-rw-r--r--src/H5FAdbg.c283
-rw-r--r--src/H5FAdblkpage.c349
-rw-r--r--src/H5FAdblock.c450
-rw-r--r--src/H5FAhdr.c594
-rw-r--r--src/H5FAint.c137
-rw-r--r--src/H5FAmodule.h33
-rw-r--r--src/H5FApkg.h320
-rw-r--r--src/H5FAprivate.h142
-rw-r--r--src/H5FAstat.c111
-rw-r--r--src/H5FAtest.c420
-rw-r--r--src/H5FD.c2078
-rw-r--r--src/H5FDcore.c1546
-rw-r--r--src/H5FDcore.h38
-rw-r--r--src/H5FDdirect.c1387
-rw-r--r--src/H5FDdirect.h53
-rw-r--r--src/H5FDdrvr_module.h33
-rw-r--r--src/H5FDfamily.c1400
-rw-r--r--src/H5FDfamily.h40
-rw-r--r--src/H5FDint.c435
-rw-r--r--src/H5FDlog.c1729
-rw-r--r--src/H5FDlog.h72
-rw-r--r--src/H5FDmodule.h33
-rw-r--r--src/H5FDmpi.c518
-rw-r--r--src/H5FDmpi.h60
-rw-r--r--src/H5FDmpio.c2087
-rw-r--r--src/H5FDmpio.h64
-rw-r--r--src/H5FDmulti.c2004
-rw-r--r--src/H5FDmulti.h43
-rw-r--r--src/H5FDpkg.h64
-rw-r--r--src/H5FDprivate.h208
-rw-r--r--src/H5FDpublic.h383
-rw-r--r--src/H5FDsec2.c979
-rw-r--r--src/H5FDsec2.h37
-rw-r--r--src/H5FDspace.c458
-rw-r--r--src/H5FDstdio.c1174
-rw-r--r--src/H5FDstdio.h38
-rw-r--r--src/H5FDtest.c116
-rw-r--r--src/H5FDwindows.c67
-rw-r--r--src/H5FDwindows.h37
-rw-r--r--src/H5FL.c2533
-rw-r--r--src/H5FLmodule.h33
-rw-r--r--src/H5FLprivate.h428
-rw-r--r--src/H5FO.c602
-rw-r--r--src/H5FOprivate.h51
-rw-r--r--src/H5FS.c1236
-rw-r--r--src/H5FScache.c1518
-rw-r--r--src/H5FSdbg.c302
-rw-r--r--src/H5FSint.c143
-rw-r--r--src/H5FSmodule.h33
-rw-r--r--src/H5FSpkg.h251
-rw-r--r--src/H5FSprivate.h230
-rw-r--r--src/H5FSpublic.h52
-rw-r--r--src/H5FSsection.c2682
-rw-r--r--src/H5FSstat.c104
-rw-r--r--src/H5FStest.c155
-rw-r--r--src/H5Faccum.c1108
-rw-r--r--src/H5Fcwfs.c325
-rw-r--r--src/H5Fdbg.c148
-rw-r--r--src/H5Fdeprec.c147
-rw-r--r--src/H5Fefc.c945
-rw-r--r--src/H5Ffake.c102
-rw-r--r--src/H5Fint.c2820
-rw-r--r--src/H5Fio.c370
-rw-r--r--src/H5Fmodule.h33
-rw-r--r--src/H5Fmount.c757
-rw-r--r--src/H5Fmpi.c384
-rw-r--r--src/H5Fpkg.h472
-rw-r--r--src/H5Fprivate.h872
-rw-r--r--src/H5Fpublic.h305
-rw-r--r--src/H5Fquery.c1382
-rw-r--r--src/H5Fsfile.c223
-rw-r--r--src/H5Fspace.c224
-rw-r--r--src/H5Fsuper.c1642
-rw-r--r--src/H5Fsuper_cache.c1090
-rw-r--r--src/H5Ftest.c220
-rw-r--r--src/H5G.c803
-rw-r--r--src/H5Gbtree2.c538
-rw-r--r--src/H5Gcache.c350
-rw-r--r--src/H5Gcompact.c646
-rw-r--r--src/H5Gdense.c1890
-rw-r--r--src/H5Gdeprec.c1149
-rw-r--r--src/H5Gent.c605
-rw-r--r--src/H5Gint.c1273
-rw-r--r--src/H5Glink.c567
-rw-r--r--src/H5Gloc.c938
-rw-r--r--src/H5Gmodule.h33
-rw-r--r--src/H5Gname.c1349
-rw-r--r--src/H5Gnode.c1580
-rw-r--r--src/H5Gobj.c1227
-rw-r--r--src/H5Goh.c417
-rw-r--r--src/H5Gpkg.h531
-rw-r--r--src/H5Gprivate.h301
-rw-r--r--src/H5Gpublic.h178
-rw-r--r--src/H5Groot.c412
-rw-r--r--src/H5Gstab.c1226
-rw-r--r--src/H5Gtest.c813
-rw-r--r--src/H5Gtraverse.c875
-rw-r--r--src/H5HF.c952
-rw-r--r--src/H5HFbtree2.c1072
-rw-r--r--src/H5HFcache.c3511
-rw-r--r--src/H5HFdbg.c932
-rw-r--r--src/H5HFdblock.c730
-rw-r--r--src/H5HFdtable.c370
-rw-r--r--src/H5HFhdr.c1524
-rw-r--r--src/H5HFhuge.c1199
-rw-r--r--src/H5HFiblock.c1781
-rw-r--r--src/H5HFiter.c663
-rw-r--r--src/H5HFman.c685
-rw-r--r--src/H5HFmodule.h33
-rw-r--r--src/H5HFpkg.h839
-rw-r--r--src/H5HFprivate.h142
-rw-r--r--src/H5HFpublic.h52
-rw-r--r--src/H5HFsection.c4185
-rw-r--r--src/H5HFspace.c638
-rw-r--r--src/H5HFstat.c179
-rw-r--r--src/H5HFtest.c551
-rw-r--r--src/H5HFtiny.c404
-rw-r--r--src/H5HG.c894
-rw-r--r--src/H5HGcache.c494
-rw-r--r--src/H5HGdbg.c177
-rw-r--r--src/H5HGmodule.h33
-rw-r--r--src/H5HGpkg.h144
-rw-r--r--src/H5HGprivate.h77
-rw-r--r--src/H5HGpublic.h31
-rw-r--r--src/H5HGquery.c143
-rw-r--r--src/H5HL.c1047
-rw-r--r--src/H5HLcache.c967
-rw-r--r--src/H5HLdbg.c129
-rw-r--r--src/H5HLdblk.c274
-rw-r--r--src/H5HLint.c220
-rw-r--r--src/H5HLmodule.h33
-rw-r--r--src/H5HLpkg.h152
-rw-r--r--src/H5HLprfx.c164
-rw-r--r--src/H5HLprivate.h76
-rw-r--r--src/H5HLpublic.h37
-rw-r--r--src/H5HP.c919
-rw-r--r--src/H5HPprivate.h69
-rw-r--r--src/H5I.c2300
-rw-r--r--src/H5Imodule.h33
-rw-r--r--src/H5Ipkg.h74
-rw-r--r--src/H5Iprivate.h86
-rw-r--r--src/H5Ipublic.h102
-rw-r--r--src/H5Itest.c96
-rw-r--r--src/H5L.c3297
-rw-r--r--src/H5Lexternal.c731
-rw-r--r--src/H5Lmodule.h34
-rw-r--r--src/H5Lpkg.h62
-rw-r--r--src/H5Lprivate.h98
-rw-r--r--src/H5Lpublic.h200
-rw-r--r--src/H5MF.c3919
-rw-r--r--src/H5MFaggr.c902
-rw-r--r--src/H5MFdbg.c332
-rw-r--r--src/H5MFmodule.h33
-rw-r--r--src/H5MFpkg.h215
-rw-r--r--src/H5MFprivate.h94
-rw-r--r--src/H5MFsection.c1093
-rw-r--r--src/H5MM.c572
-rw-r--r--src/H5MMprivate.h54
-rw-r--r--src/H5MMpublic.h45
-rw-r--r--src/H5MP.c474
-rw-r--r--src/H5MPmodule.h33
-rw-r--r--src/H5MPpkg.h104
-rw-r--r--src/H5MPprivate.h60
-rw-r--r--src/H5MPtest.c235
-rw-r--r--src/H5O.c3725
-rw-r--r--src/H5Oainfo.c543
-rw-r--r--src/H5Oalloc.c2543
-rw-r--r--src/H5Oattr.c884
-rw-r--r--src/H5Oattribute.c2019
-rw-r--r--src/H5Obogus.c240
-rw-r--r--src/H5Obtreek.c257
-rw-r--r--src/H5Ocache.c1671
-rw-r--r--src/H5Ocache_image.c377
-rw-r--r--src/H5Ochunk.c451
-rw-r--r--src/H5Ocont.c288
-rw-r--r--src/H5Ocopy.c1989
-rw-r--r--src/H5Odbg.c591
-rw-r--r--src/H5Odrvinfo.c313
-rw-r--r--src/H5Odtype.c2166
-rw-r--r--src/H5Oefl.c574
-rw-r--r--src/H5Ofill.c1024
-rw-r--r--src/H5Oflush.c419
-rw-r--r--src/H5Ofsinfo.c406
-rw-r--r--src/H5Oginfo.c351
-rw-r--r--src/H5Olayout.c1284
-rw-r--r--src/H5Olinfo.c592
-rw-r--r--src/H5Olink.c877
-rw-r--r--src/H5Omessage.c2305
-rw-r--r--src/H5Omodule.h33
-rw-r--r--src/H5Omtime.c500
-rw-r--r--src/H5Oname.c307
-rw-r--r--src/H5Onull.c55
-rw-r--r--src/H5Opkg.h666
-rw-r--r--src/H5Opline.c691
-rw-r--r--src/H5Oprivate.h976
-rw-r--r--src/H5Opublic.h215
-rw-r--r--src/H5Orefcount.c324
-rw-r--r--src/H5Osdspace.c539
-rw-r--r--src/H5Oshared.c762
-rw-r--r--src/H5Oshared.h489
-rw-r--r--src/H5Oshmesg.c247
-rw-r--r--src/H5Ostab.c449
-rw-r--r--src/H5Otest.c747
-rw-r--r--src/H5Ounknown.c88
-rw-r--r--src/H5P.c1657
-rw-r--r--src/H5PB.c1537
-rw-r--r--src/H5PBmodule.h32
-rw-r--r--src/H5PBpkg.h58
-rw-r--r--src/H5PBprivate.h106
-rw-r--r--src/H5PL.c1008
-rw-r--r--src/H5PLextern.h44
-rw-r--r--src/H5PLmodule.h34
-rw-r--r--src/H5PLpkg.h48
-rw-r--r--src/H5PLprivate.h50
-rw-r--r--src/H5PLpublic.h58
-rw-r--r--src/H5Pacpl.c88
-rw-r--r--src/H5Pdapl.c1294
-rw-r--r--src/H5Pdcpl.c3735
-rw-r--r--src/H5Pdeprec.c620
-rw-r--r--src/H5Pdxpl.c2242
-rw-r--r--src/H5Pencdec.c789
-rw-r--r--src/H5Pfapl.c4809
-rw-r--r--src/H5Pfcpl.c1517
-rw-r--r--src/H5Pfmpl.c134
-rw-r--r--src/H5Pgcpl.c706
-rw-r--r--src/H5Pint.c5524
-rw-r--r--src/H5Plapl.c1308
-rw-r--r--src/H5Plcpl.c208
-rw-r--r--src/H5Pmodule.h33
-rw-r--r--src/H5Pocpl.c1983
-rw-r--r--src/H5Pocpypl.c918
-rw-r--r--src/H5Ppkg.h208
-rw-r--r--src/H5Pprivate.h207
-rw-r--r--src/H5Ppublic.h547
-rw-r--r--src/H5Pstrcpl.c285
-rw-r--r--src/H5Ptest.c125
-rw-r--r--src/H5R.c1050
-rw-r--r--src/H5RS.c497
-rw-r--r--src/H5RSprivate.h59
-rw-r--r--src/H5Rdeprec.c189
-rw-r--r--src/H5Rmodule.h34
-rw-r--r--src/H5Rpkg.h62
-rw-r--r--src/H5Rprivate.h29
-rw-r--r--src/H5Rpublic.h91
-rw-r--r--src/H5S.c2259
-rw-r--r--src/H5SL.c2571
-rw-r--r--src/H5SLmodule.h33
-rw-r--r--src/H5SLprivate.h98
-rw-r--r--src/H5SM.c2830
-rw-r--r--src/H5SMbtree2.c255
-rw-r--r--src/H5SMcache.c787
-rw-r--r--src/H5SMmessage.c359
-rw-r--r--src/H5SMmodule.h33
-rw-r--r--src/H5SMpkg.h288
-rw-r--r--src/H5SMprivate.h78
-rw-r--r--src/H5SMtest.c121
-rw-r--r--src/H5ST.c795
-rw-r--r--src/H5STprivate.h64
-rw-r--r--src/H5Sall.c1039
-rw-r--r--src/H5Sdbg.c123
-rw-r--r--src/H5Shyper.c10452
-rw-r--r--src/H5Smodule.h33
-rw-r--r--src/H5Smpio.c1095
-rw-r--r--src/H5Snone.c968
-rw-r--r--src/H5Spkg.h283
-rw-r--r--src/H5Spoint.c1766
-rw-r--r--src/H5Sprivate.h324
-rw-r--r--src/H5Spublic.h155
-rw-r--r--src/H5Sselect.c2453
-rw-r--r--src/H5Stest.c109
-rw-r--r--src/H5T.c5610
-rw-r--r--src/H5TS.c521
-rw-r--r--src/H5TSprivate.h129
-rw-r--r--src/H5Tarray.c427
-rw-r--r--src/H5Tbit.c712
-rw-r--r--src/H5Tcommit.c854
-rw-r--r--src/H5Tcompound.c646
-rw-r--r--src/H5Tconv.c9905
-rw-r--r--src/H5Tcset.c124
-rw-r--r--src/H5Tdbg.c442
-rw-r--r--src/H5Tdeprec.c205
-rw-r--r--src/H5Tenum.c582
-rw-r--r--src/H5Tfields.c486
-rw-r--r--src/H5Tfixed.c153
-rw-r--r--src/H5Tfloat.c396
-rw-r--r--src/H5Tmodule.h33
-rw-r--r--src/H5Tnative.c911
-rw-r--r--src/H5Toffset.c274
-rw-r--r--src/H5Toh.c233
-rw-r--r--src/H5Topaque.c115
-rw-r--r--src/H5Torder.c283
-rw-r--r--src/H5Tpad.c121
-rw-r--r--src/H5Tpkg.h1323
-rw-r--r--src/H5Tprecis.c286
-rw-r--r--src/H5Tprivate.h165
-rw-r--r--src/H5Tpublic.h621
-rw-r--r--src/H5Tstrpad.c137
-rw-r--r--src/H5Tvisit.c166
-rw-r--r--src/H5Tvlen.c1259
-rw-r--r--src/H5UC.c128
-rw-r--r--src/H5UCprivate.h64
-rw-r--r--src/H5VM.c1755
-rw-r--r--src/H5VMprivate.h550
-rw-r--r--src/H5WB.c289
-rw-r--r--src/H5WBprivate.h62
-rw-r--r--src/H5Z.c1717
-rw-r--r--src/H5Zdeflate.c206
-rw-r--r--src/H5Zfletcher32.c164
-rw-r--r--src/H5Zmodule.h33
-rw-r--r--src/H5Znbit.c1631
-rw-r--r--src/H5Zpkg.h55
-rw-r--r--src/H5Zprivate.h109
-rw-r--r--src/H5Zpublic.h248
-rw-r--r--src/H5Zscaleoffset.c1694
-rw-r--r--src/H5Zshuffle.c289
-rw-r--r--src/H5Zszip.c371
-rw-r--r--src/H5Ztrans.c1796
-rw-r--r--src/H5api_adpt.h254
-rw-r--r--src/H5checksum.c494
-rw-r--r--src/H5config.h.in657
-rw-r--r--src/H5dbg.c144
-rw-r--r--src/H5detect.c1789
-rw-r--r--src/H5err.txt275
-rw-r--r--src/H5make_libsettings.c294
-rw-r--r--src/H5overflow.h2252
-rw-r--r--src/H5overflow.txt44
-rw-r--r--src/H5private.h2620
-rw-r--r--src/H5public.h349
-rw-r--r--src/H5system.c1239
-rw-r--r--src/H5timer.c271
-rw-r--r--src/H5trace.c2658
-rw-r--r--src/H5vers.txt75
-rw-r--r--src/H5version.h562
-rw-r--r--src/H5win32defs.h153
-rw-r--r--src/Makefile.am205
-rw-r--r--src/Makefile.in2109
-rw-r--r--src/hdf5.h54
-rw-r--r--src/libhdf5.settings.in85
451 files changed, 363908 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..e2acd30
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,992 @@
+cmake_minimum_required (VERSION 3.2.2)
+PROJECT (HDF5_SRC C CXX)
+
+#-----------------------------------------------------------------------------
+# Apply Definitions to compiler in this directory and below
+#-----------------------------------------------------------------------------
+add_definitions (${HDF_EXTRA_C_FLAGS})
+
+#-----------------------------------------------------------------------------
+# List Source Files
+#-----------------------------------------------------------------------------
+set (H5_SOURCES
+ ${HDF5_SRC_DIR}/H5.c
+ ${HDF5_SRC_DIR}/H5checksum.c
+ ${HDF5_SRC_DIR}/H5dbg.c
+ ${HDF5_SRC_DIR}/H5system.c
+ ${HDF5_SRC_DIR}/H5timer.c
+ ${HDF5_SRC_DIR}/H5trace.c
+)
+
+set (H5_HDRS
+ ${HDF5_SRC_DIR}/hdf5.h
+ ${HDF5_SRC_DIR}/H5api_adpt.h
+ ${HDF5_SRC_DIR}/H5public.h
+ #${HDF5_SRC_DIR}/H5version.h
+ #${HDF5_SRC_DIR}/H5overflow.h
+)
+IDE_GENERATED_PROPERTIES ("H5" "${H5_HDRS}" "${H5_SOURCES}" )
+
+set (H5A_SOURCES
+ ${HDF5_SRC_DIR}/H5A.c
+ ${HDF5_SRC_DIR}/H5Abtree2.c
+ ${HDF5_SRC_DIR}/H5Adense.c
+ ${HDF5_SRC_DIR}/H5Adeprec.c
+ ${HDF5_SRC_DIR}/H5Aint.c
+ ${HDF5_SRC_DIR}/H5Atest.c
+)
+
+set (H5A_HDRS
+ ${HDF5_SRC_DIR}/H5Apkg.h
+ ${HDF5_SRC_DIR}/H5Apublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5A" "${H5A_HDRS}" "${H5A_SOURCES}" )
+
+set (H5AC_SOURCES
+ ${HDF5_SRC_DIR}/H5AC.c
+ ${HDF5_SRC_DIR}/H5ACdbg.c
+ ${HDF5_SRC_DIR}/H5AClog.c
+ ${HDF5_SRC_DIR}/H5ACmpio.c
+ ${HDF5_SRC_DIR}/H5ACproxy_entry.c
+)
+
+set (H5AC_HDRS
+ ${HDF5_SRC_DIR}/H5ACpkg.h
+ ${HDF5_SRC_DIR}/H5ACpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5AC" "${H5AC_HDRS}" "${H5AC_SOURCES}" )
+
+set (H5B_SOURCES
+ ${HDF5_SRC_DIR}/H5B.c
+ ${HDF5_SRC_DIR}/H5Bcache.c
+ ${HDF5_SRC_DIR}/H5Bdbg.c
+)
+set (H5B_HDRS
+ ${HDF5_SRC_DIR}/H5Bpkg.h
+ ${HDF5_SRC_DIR}/H5Bpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5B" "${H5B_HDRS}" "${H5B_SOURCES}" )
+
+
+set (H5B2_SOURCES
+ ${HDF5_SRC_DIR}/H5B2.c
+ ${HDF5_SRC_DIR}/H5B2cache.c
+ ${HDF5_SRC_DIR}/H5B2dbg.c
+ ${HDF5_SRC_DIR}/H5B2hdr.c
+ ${HDF5_SRC_DIR}/H5B2int.c
+ ${HDF5_SRC_DIR}/H5B2internal.c
+ ${HDF5_SRC_DIR}/H5B2leaf.c
+ ${HDF5_SRC_DIR}/H5B2stat.c
+ ${HDF5_SRC_DIR}/H5B2test.c
+)
+set (H5B2_HDRS
+ ${HDF5_SRC_DIR}/H5B2pkg.h
+ ${HDF5_SRC_DIR}/H5B2public.h
+)
+IDE_GENERATED_PROPERTIES ("H5B2" "${H5B2_HDRS}" "${H5B2_SOURCES}" )
+
+
+set (H5C_SOURCES
+ ${HDF5_SRC_DIR}/H5C.c
+ ${HDF5_SRC_DIR}/H5Cdbg.c
+ ${HDF5_SRC_DIR}/H5Cepoch.c
+ ${HDF5_SRC_DIR}/H5Cimage.c
+ ${HDF5_SRC_DIR}/H5Clog.c
+ ${HDF5_SRC_DIR}/H5Cmpio.c
+ ${HDF5_SRC_DIR}/H5Cprefetched.c
+ ${HDF5_SRC_DIR}/H5Cquery.c
+ ${HDF5_SRC_DIR}/H5Ctag.c
+ ${HDF5_SRC_DIR}/H5Ctest.c
+)
+set (H5C_HDRS
+ ${HDF5_SRC_DIR}/H5Cpkg.h
+ ${HDF5_SRC_DIR}/H5Cpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5C" "${H5C_HDRS}" "${H5C_SOURCES}" )
+
+
+set (H5CS_SOURCES
+ ${HDF5_SRC_DIR}/H5CS.c
+)
+set (H5CS_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5CS" "${H5CS_HDRS}" "${H5CS_SOURCES}" )
+
+
+set (H5D_SOURCES
+ ${HDF5_SRC_DIR}/H5D.c
+ ${HDF5_SRC_DIR}/H5Dbtree.c
+ ${HDF5_SRC_DIR}/H5Dbtree2.c
+ ${HDF5_SRC_DIR}/H5Dchunk.c
+ ${HDF5_SRC_DIR}/H5Dcompact.c
+ ${HDF5_SRC_DIR}/H5Dcontig.c
+ ${HDF5_SRC_DIR}/H5Ddbg.c
+ ${HDF5_SRC_DIR}/H5Ddeprec.c
+ ${HDF5_SRC_DIR}/H5Dearray.c
+ ${HDF5_SRC_DIR}/H5Defl.c
+ ${HDF5_SRC_DIR}/H5Dfarray.c
+ ${HDF5_SRC_DIR}/H5Dfill.c
+ ${HDF5_SRC_DIR}/H5Dint.c
+ ${HDF5_SRC_DIR}/H5Dio.c
+ ${HDF5_SRC_DIR}/H5Dlayout.c
+ ${HDF5_SRC_DIR}/H5Dmpio.c
+ ${HDF5_SRC_DIR}/H5Dnone.c
+ ${HDF5_SRC_DIR}/H5Doh.c
+ ${HDF5_SRC_DIR}/H5Dscatgath.c
+ ${HDF5_SRC_DIR}/H5Dselect.c
+ ${HDF5_SRC_DIR}/H5Dsingle.c
+ ${HDF5_SRC_DIR}/H5Dtest.c
+ ${HDF5_SRC_DIR}/H5Dvirtual.c
+)
+
+set (H5D_HDRS
+ ${HDF5_SRC_DIR}/H5Dpkg.h
+ ${HDF5_SRC_DIR}/H5Dpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5D" "${H5D_HDRS}" "${H5D_SOURCES}" )
+
+set (H5E_SOURCES
+ ${HDF5_SRC_DIR}/H5E.c
+ ${HDF5_SRC_DIR}/H5Edeprec.c
+ ${HDF5_SRC_DIR}/H5Eint.c
+)
+
+set (H5E_HDRS
+ #${HDF5_SRC_DIR}/H5Edefin.h
+ #${HDF5_SRC_DIR}/H5Einit.h
+ ${HDF5_SRC_DIR}/H5Epkg.h
+ #${HDF5_SRC_DIR}/H5Epubgen.h
+ ${HDF5_SRC_DIR}/H5Epublic.h
+ #${HDF5_SRC_DIR}/H5Eterm.h
+)
+IDE_GENERATED_PROPERTIES ("H5E" "${H5E_HDRS}" "${H5E_SOURCES}" )
+
+
+set (H5EA_SOURCES
+ ${HDF5_SRC_DIR}/H5EA.c
+ ${HDF5_SRC_DIR}/H5EAcache.c
+ ${HDF5_SRC_DIR}/H5EAdbg.c
+ ${HDF5_SRC_DIR}/H5EAdblkpage.c
+ ${HDF5_SRC_DIR}/H5EAdblock.c
+ ${HDF5_SRC_DIR}/H5EAhdr.c
+ ${HDF5_SRC_DIR}/H5EAiblock.c
+ ${HDF5_SRC_DIR}/H5EAint.c
+ ${HDF5_SRC_DIR}/H5EAsblock.c
+ ${HDF5_SRC_DIR}/H5EAstat.c
+ ${HDF5_SRC_DIR}/H5EAtest.c
+)
+set (H5EA_HDRS
+ ${HDF5_SRC_DIR}/H5EApkg.h
+)
+IDE_GENERATED_PROPERTIES ("H5EA" "${H5EA_HDRS}" "${H5EA_SOURCES}" )
+
+
+set (H5F_SOURCES
+ ${HDF5_SRC_DIR}/H5F.c
+ ${HDF5_SRC_DIR}/H5Faccum.c
+ ${HDF5_SRC_DIR}/H5Fcwfs.c
+ ${HDF5_SRC_DIR}/H5Fdbg.c
+ ${HDF5_SRC_DIR}/H5Fdeprec.c
+ ${HDF5_SRC_DIR}/H5Fefc.c
+ ${HDF5_SRC_DIR}/H5Ffake.c
+ ${HDF5_SRC_DIR}/H5Fint.c
+ ${HDF5_SRC_DIR}/H5Fio.c
+ ${HDF5_SRC_DIR}/H5Fmount.c
+ ${HDF5_SRC_DIR}/H5Fmpi.c
+ ${HDF5_SRC_DIR}/H5Fquery.c
+ ${HDF5_SRC_DIR}/H5Fsfile.c
+ ${HDF5_SRC_DIR}/H5Fspace.c
+ ${HDF5_SRC_DIR}/H5Fsuper.c
+ ${HDF5_SRC_DIR}/H5Fsuper_cache.c
+ ${HDF5_SRC_DIR}/H5Ftest.c
+)
+
+set (H5F_HDRS
+ ${HDF5_SRC_DIR}/H5Fpkg.h
+ ${HDF5_SRC_DIR}/H5Fpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5F" "${H5F_HDRS}" "${H5F_SOURCES}" )
+
+
+set (H5FA_SOURCES
+ ${HDF5_SRC_DIR}/H5FA.c
+ ${HDF5_SRC_DIR}/H5FAcache.c
+ ${HDF5_SRC_DIR}/H5FAdbg.c
+ ${HDF5_SRC_DIR}/H5FAdblkpage.c
+ ${HDF5_SRC_DIR}/H5FAdblock.c
+ ${HDF5_SRC_DIR}/H5FAhdr.c
+ ${HDF5_SRC_DIR}/H5FAint.c
+ ${HDF5_SRC_DIR}/H5FAstat.c
+ ${HDF5_SRC_DIR}/H5FAtest.c
+)
+set (H5FA_HDRS
+ ${HDF5_SRC_DIR}/H5FApkg.h
+)
+IDE_GENERATED_PROPERTIES ("H5FA" "${H5FA_HDRS}" "${H5FA_SOURCES}" )
+
+
+set (H5FD_SOURCES
+ ${HDF5_SRC_DIR}/H5FD.c
+ ${HDF5_SRC_DIR}/H5FDcore.c
+ ${HDF5_SRC_DIR}/H5FDdirect.c
+ ${HDF5_SRC_DIR}/H5FDfamily.c
+ ${HDF5_SRC_DIR}/H5FDint.c
+ ${HDF5_SRC_DIR}/H5FDlog.c
+ ${HDF5_SRC_DIR}/H5FDmpi.c
+ ${HDF5_SRC_DIR}/H5FDmpio.c
+ ${HDF5_SRC_DIR}/H5FDmulti.c
+ ${HDF5_SRC_DIR}/H5FDsec2.c
+ ${HDF5_SRC_DIR}/H5FDspace.c
+ ${HDF5_SRC_DIR}/H5FDstdio.c
+ ${HDF5_SRC_DIR}/H5FDtest.c
+ ${HDF5_SRC_DIR}/H5FDwindows.c
+)
+
+set (H5FD_HDRS
+ ${HDF5_SRC_DIR}/H5FDcore.h
+ ${HDF5_SRC_DIR}/H5FDdirect.h
+ ${HDF5_SRC_DIR}/H5FDfamily.h
+ ${HDF5_SRC_DIR}/H5FDlog.h
+ ${HDF5_SRC_DIR}/H5FDmpi.h
+ ${HDF5_SRC_DIR}/H5FDmpio.h
+ ${HDF5_SRC_DIR}/H5FDmulti.h
+ ${HDF5_SRC_DIR}/H5FDpkg.h
+ ${HDF5_SRC_DIR}/H5FDpublic.h
+ ${HDF5_SRC_DIR}/H5FDsec2.h
+ ${HDF5_SRC_DIR}/H5FDstdio.h
+ ${HDF5_SRC_DIR}/H5FDwindows.h
+)
+IDE_GENERATED_PROPERTIES ("H5FD" "${H5FD_HDRS}" "${H5FD_SOURCES}" )
+
+
+set (H5FL_SOURCES
+ ${HDF5_SRC_DIR}/H5FL.c
+)
+set (H5FL_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5FL" "${H5FL_HDRS}" "${H5FL_SOURCES}" )
+
+
+set (H5FO_SOURCES
+ ${HDF5_SRC_DIR}/H5FO.c
+)
+set (H5FO_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5FO" "${H5FO_HDRS}" "${H5FO_SOURCES}" )
+
+
+set (H5FS_SOURCES
+ ${HDF5_SRC_DIR}/H5FS.c
+ ${HDF5_SRC_DIR}/H5FScache.c
+ ${HDF5_SRC_DIR}/H5FSdbg.c
+ ${HDF5_SRC_DIR}/H5FSint.c
+ ${HDF5_SRC_DIR}/H5FSsection.c
+ ${HDF5_SRC_DIR}/H5FSstat.c
+ ${HDF5_SRC_DIR}/H5FStest.c
+)
+
+set (H5FS_HDRS
+ ${HDF5_SRC_DIR}/H5FSpkg.h
+ ${HDF5_SRC_DIR}/H5FSpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5FS" "${H5FS_HDRS}" "${H5FS_SOURCES}" )
+
+set (H5G_SOURCES
+ ${HDF5_SRC_DIR}/H5G.c
+ ${HDF5_SRC_DIR}/H5Gbtree2.c
+ ${HDF5_SRC_DIR}/H5Gcache.c
+ ${HDF5_SRC_DIR}/H5Gcompact.c
+ ${HDF5_SRC_DIR}/H5Gdense.c
+ ${HDF5_SRC_DIR}/H5Gdeprec.c
+ ${HDF5_SRC_DIR}/H5Gent.c
+ ${HDF5_SRC_DIR}/H5Gint.c
+ ${HDF5_SRC_DIR}/H5Glink.c
+ ${HDF5_SRC_DIR}/H5Gloc.c
+ ${HDF5_SRC_DIR}/H5Gname.c
+ ${HDF5_SRC_DIR}/H5Gnode.c
+ ${HDF5_SRC_DIR}/H5Gobj.c
+ ${HDF5_SRC_DIR}/H5Goh.c
+ ${HDF5_SRC_DIR}/H5Groot.c
+ ${HDF5_SRC_DIR}/H5Gstab.c
+ ${HDF5_SRC_DIR}/H5Gtest.c
+ ${HDF5_SRC_DIR}/H5Gtraverse.c
+)
+
+set (H5G_HDRS
+ ${HDF5_SRC_DIR}/H5Gpkg.h
+ ${HDF5_SRC_DIR}/H5Gpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5G" "${H5G_HDRS}" "${H5G_SOURCES}" )
+
+set (H5HF_SOURCES
+ ${HDF5_SRC_DIR}/H5HF.c
+ ${HDF5_SRC_DIR}/H5HFbtree2.c
+ ${HDF5_SRC_DIR}/H5HFcache.c
+ ${HDF5_SRC_DIR}/H5HFdbg.c
+ ${HDF5_SRC_DIR}/H5HFdblock.c
+ ${HDF5_SRC_DIR}/H5HFdtable.c
+ ${HDF5_SRC_DIR}/H5HFhdr.c
+ ${HDF5_SRC_DIR}/H5HFhuge.c
+ ${HDF5_SRC_DIR}/H5HFiblock.c
+ ${HDF5_SRC_DIR}/H5HFiter.c
+ ${HDF5_SRC_DIR}/H5HFman.c
+ ${HDF5_SRC_DIR}/H5HFsection.c
+ ${HDF5_SRC_DIR}/H5HFspace.c
+ ${HDF5_SRC_DIR}/H5HFstat.c
+ ${HDF5_SRC_DIR}/H5HFtest.c
+ ${HDF5_SRC_DIR}/H5HFtiny.c
+)
+
+set (H5HF_HDRS
+ ${HDF5_SRC_DIR}/H5HFpkg.h
+ ${HDF5_SRC_DIR}/H5HFpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5HF" "${H5HF_HDRS}" "${H5HF_SOURCES}" )
+
+set (H5HG_SOURCES
+ ${HDF5_SRC_DIR}/H5HG.c
+ ${HDF5_SRC_DIR}/H5HGcache.c
+ ${HDF5_SRC_DIR}/H5HGdbg.c
+ ${HDF5_SRC_DIR}/H5HGquery.c
+)
+
+set (H5HG_HDRS
+ ${HDF5_SRC_DIR}/H5HGpkg.h
+ ${HDF5_SRC_DIR}/H5HGpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5HG" "${H5HG_HDRS}" "${H5HG_SOURCES}" )
+
+set (H5HL_SOURCES
+ ${HDF5_SRC_DIR}/H5HL.c
+ ${HDF5_SRC_DIR}/H5HLcache.c
+ ${HDF5_SRC_DIR}/H5HLdbg.c
+ ${HDF5_SRC_DIR}/H5HLdblk.c
+ ${HDF5_SRC_DIR}/H5HLint.c
+ ${HDF5_SRC_DIR}/H5HLprfx.c
+)
+
+set (H5HL_HDRS
+ ${HDF5_SRC_DIR}/H5HLpkg.h
+ ${HDF5_SRC_DIR}/H5HLpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5HL" "${H5HL_HDRS}" "${H5HL_SOURCES}" )
+
+
+set (H5HP_SOURCES
+ ${HDF5_SRC_DIR}/H5HP.c
+)
+set (H5HP_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5HP" "${H5HP_HDRS}" "${H5HP_SOURCES}" )
+
+
+set (H5I_SOURCES
+ ${HDF5_SRC_DIR}/H5I.c
+ ${HDF5_SRC_DIR}/H5Itest.c
+)
+set (H5I_HDRS
+ ${HDF5_SRC_DIR}/H5Ipkg.h
+ ${HDF5_SRC_DIR}/H5Ipublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5I" "${H5I_HDRS}" "${H5I_SOURCES}" )
+
+
+set (H5L_SOURCES
+ ${HDF5_SRC_DIR}/H5L.c
+ ${HDF5_SRC_DIR}/H5Lexternal.c
+)
+set (H5L_HDRS
+ ${HDF5_SRC_DIR}/H5Lpkg.h
+ ${HDF5_SRC_DIR}/H5Lpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5L" "${H5L_HDRS}" "${H5L_SOURCES}" )
+
+
+set (H5MF_SOURCES
+ ${HDF5_SRC_DIR}/H5MF.c
+ ${HDF5_SRC_DIR}/H5MFaggr.c
+ ${HDF5_SRC_DIR}/H5MFdbg.c
+ ${HDF5_SRC_DIR}/H5MFsection.c
+)
+
+set (H5MF_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5MF" "${H5MF_HDRS}" "${H5MF_SOURCES}" )
+
+
+set (H5MM_SOURCES
+ ${HDF5_SRC_DIR}/H5MM.c
+)
+set (H5MM_HDRS
+ ${HDF5_SRC_DIR}/H5MMpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5MM" "${H5MM_HDRS}" "${H5MM_SOURCES}" )
+
+
+set (H5MP_SOURCES
+ ${HDF5_SRC_DIR}/H5MP.c
+ ${HDF5_SRC_DIR}/H5MPtest.c
+)
+
+set (H5MP_HDRS
+ ${HDF5_SRC_DIR}/H5MPpkg.h
+)
+IDE_GENERATED_PROPERTIES ("H5MP" "${H5MP_HDRS}" "${H5MP_SOURCES}" )
+
+set (H5O_SOURCES
+ ${HDF5_SRC_DIR}/H5O.c
+ ${HDF5_SRC_DIR}/H5Oainfo.c
+ ${HDF5_SRC_DIR}/H5Oalloc.c
+ ${HDF5_SRC_DIR}/H5Oattr.c
+ ${HDF5_SRC_DIR}/H5Oattribute.c
+ ${HDF5_SRC_DIR}/H5Obogus.c
+ ${HDF5_SRC_DIR}/H5Obtreek.c
+ ${HDF5_SRC_DIR}/H5Ocache.c
+ ${HDF5_SRC_DIR}/H5Ocache_image.c
+ ${HDF5_SRC_DIR}/H5Ochunk.c
+ ${HDF5_SRC_DIR}/H5Ocont.c
+ ${HDF5_SRC_DIR}/H5Ocopy.c
+ ${HDF5_SRC_DIR}/H5Odbg.c
+ ${HDF5_SRC_DIR}/H5Odrvinfo.c
+ ${HDF5_SRC_DIR}/H5Odtype.c
+ ${HDF5_SRC_DIR}/H5Oefl.c
+ ${HDF5_SRC_DIR}/H5Ofill.c
+ ${HDF5_SRC_DIR}/H5Oflush.c
+ ${HDF5_SRC_DIR}/H5Ofsinfo.c
+ ${HDF5_SRC_DIR}/H5Oginfo.c
+ ${HDF5_SRC_DIR}/H5Olayout.c
+ ${HDF5_SRC_DIR}/H5Olinfo.c
+ ${HDF5_SRC_DIR}/H5Olink.c
+ ${HDF5_SRC_DIR}/H5Omessage.c
+ ${HDF5_SRC_DIR}/H5Omtime.c
+ ${HDF5_SRC_DIR}/H5Oname.c
+ ${HDF5_SRC_DIR}/H5Onull.c
+ ${HDF5_SRC_DIR}/H5Opline.c
+ ${HDF5_SRC_DIR}/H5Orefcount.c
+ ${HDF5_SRC_DIR}/H5Osdspace.c
+ ${HDF5_SRC_DIR}/H5Oshared.c
+ ${HDF5_SRC_DIR}/H5Oshmesg.c
+ ${HDF5_SRC_DIR}/H5Ostab.c
+ ${HDF5_SRC_DIR}/H5Otest.c
+ ${HDF5_SRC_DIR}/H5Ounknown.c
+)
+
+set (H5O_HDRS
+ ${HDF5_SRC_DIR}/H5Opkg.h
+ ${HDF5_SRC_DIR}/H5Opublic.h
+ ${HDF5_SRC_DIR}/H5Oshared.h
+)
+IDE_GENERATED_PROPERTIES ("H5O" "${H5O_HDRS}" "${H5O_SOURCES}" )
+
+set (H5P_SOURCES
+ ${HDF5_SRC_DIR}/H5P.c
+ ${HDF5_SRC_DIR}/H5Pacpl.c
+ ${HDF5_SRC_DIR}/H5Pdapl.c
+ ${HDF5_SRC_DIR}/H5Pdcpl.c
+ ${HDF5_SRC_DIR}/H5Pdeprec.c
+ ${HDF5_SRC_DIR}/H5Pdxpl.c
+ ${HDF5_SRC_DIR}/H5Pencdec.c
+ ${HDF5_SRC_DIR}/H5Pfapl.c
+ ${HDF5_SRC_DIR}/H5Pfcpl.c
+ ${HDF5_SRC_DIR}/H5Pfmpl.c
+ ${HDF5_SRC_DIR}/H5Pgcpl.c
+ ${HDF5_SRC_DIR}/H5Pint.c
+ ${HDF5_SRC_DIR}/H5Plapl.c
+ ${HDF5_SRC_DIR}/H5Plcpl.c
+ ${HDF5_SRC_DIR}/H5Pocpl.c
+ ${HDF5_SRC_DIR}/H5Pocpypl.c
+ ${HDF5_SRC_DIR}/H5Pstrcpl.c
+ ${HDF5_SRC_DIR}/H5Ptest.c
+)
+
+set (H5P_HDRS
+ ${HDF5_SRC_DIR}/H5Ppkg.h
+ ${HDF5_SRC_DIR}/H5Ppublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5P" "${H5P_HDRS}" "${H5P_SOURCES}" )
+
+set (H5PB_SOURCES
+ ${HDF5_SRC_DIR}/H5PB.c
+)
+
+set (H5PB_HDRS
+ ${HDF5_SRC_DIR}/H5PBpkg.h
+)
+IDE_GENERATED_PROPERTIES ("H5PB" "${H5PB_HDRS}" "${H5PB_SOURCES}" )
+
+set (H5PL_SOURCES
+ ${HDF5_SRC_DIR}/H5PL.c
+)
+
+set (H5PL_HDRS
+ ${HDF5_SRC_DIR}/H5PLextern.h
+ ${HDF5_SRC_DIR}/H5PLpkg.h
+ ${HDF5_SRC_DIR}/H5PLpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5PL" "${H5PL_HDRS}" "${H5PL_SOURCES}" )
+
+
+set (H5R_SOURCES
+ ${HDF5_SRC_DIR}/H5R.c
+ ${HDF5_SRC_DIR}/H5Rdeprec.c
+)
+set (H5R_HDRS
+ ${HDF5_SRC_DIR}/H5Rpkg.h
+ ${HDF5_SRC_DIR}/H5Rpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5R" "${H5R_HDRS}" "${H5R_SOURCES}" )
+
+
+set (H5RS_SOURCES
+ ${HDF5_SRC_DIR}/H5RS.c
+)
+set (H5RS_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5RS" "${H5RS_HDRS}" "${H5RS_SOURCES}" )
+
+
+set (H5S_SOURCES
+ ${HDF5_SRC_DIR}/H5S.c
+ ${HDF5_SRC_DIR}/H5Sall.c
+ ${HDF5_SRC_DIR}/H5Sdbg.c
+ ${HDF5_SRC_DIR}/H5Shyper.c
+ ${HDF5_SRC_DIR}/H5Smpio.c
+ ${HDF5_SRC_DIR}/H5Snone.c
+ ${HDF5_SRC_DIR}/H5Spoint.c
+ ${HDF5_SRC_DIR}/H5Sselect.c
+ ${HDF5_SRC_DIR}/H5Stest.c
+)
+
+set (H5S_HDRS
+ ${HDF5_SRC_DIR}/H5Spkg.h
+ ${HDF5_SRC_DIR}/H5Spublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5S" "${H5S_HDRS}" "${H5S_SOURCES}" )
+
+
+set (H5SL_SOURCES
+ ${HDF5_SRC_DIR}/H5SL.c
+)
+set (H5SL_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5SL" "${H5SL_HDRS}" "${H5SL_SOURCES}" )
+
+
+set (H5SM_SOURCES
+ ${HDF5_SRC_DIR}/H5SM.c
+ ${HDF5_SRC_DIR}/H5SMbtree2.c
+ ${HDF5_SRC_DIR}/H5SMcache.c
+ ${HDF5_SRC_DIR}/H5SMmessage.c
+ ${HDF5_SRC_DIR}/H5SMtest.c
+)
+
+set (H5SM_HDRS
+ ${HDF5_SRC_DIR}/H5SMpkg.h
+)
+IDE_GENERATED_PROPERTIES ("H5SM" "${H5SM_HDRS}" "${H5SM_SOURCES}" )
+
+
+set (H5ST_SOURCES
+ ${HDF5_SRC_DIR}/H5ST.c
+)
+set (H5ST_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5ST" "${H5ST_HDRS}" "${H5ST_SOURCES}" )
+
+
+set (H5T_SOURCES
+ ${HDF5_SRC_DIR}/H5T.c
+ ${HDF5_SRC_DIR}/H5Tarray.c
+ ${HDF5_SRC_DIR}/H5Tbit.c
+ ${HDF5_SRC_DIR}/H5Tcommit.c
+ ${HDF5_SRC_DIR}/H5Tcompound.c
+ ${HDF5_SRC_DIR}/H5Tconv.c
+ ${HDF5_SRC_DIR}/H5Tcset.c
+ ${HDF5_SRC_DIR}/H5Tdbg.c
+ ${HDF5_SRC_DIR}/H5Tdeprec.c
+ ${HDF5_SRC_DIR}/H5Tenum.c
+ ${HDF5_SRC_DIR}/H5Tfields.c
+ ${HDF5_SRC_DIR}/H5Tfixed.c
+ ${HDF5_SRC_DIR}/H5Tfloat.c
+ ${HDF5_SRC_DIR}/H5Tnative.c
+ ${HDF5_SRC_DIR}/H5Toffset.c
+ ${HDF5_SRC_DIR}/H5Toh.c
+ ${HDF5_SRC_DIR}/H5Topaque.c
+ ${HDF5_SRC_DIR}/H5Torder.c
+ ${HDF5_SRC_DIR}/H5Tpad.c
+ ${HDF5_SRC_DIR}/H5Tprecis.c
+ ${HDF5_SRC_DIR}/H5Tstrpad.c
+ ${HDF5_SRC_DIR}/H5Tvisit.c
+ ${HDF5_SRC_DIR}/H5Tvlen.c
+)
+
+set (H5T_HDRS
+ ${HDF5_SRC_DIR}/H5Tpkg.h
+ ${HDF5_SRC_DIR}/H5Tpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5T" "${H5T_HDRS}" "${H5T_SOURCES}" )
+
+
+set (H5TS_SOURCES
+ ${HDF5_SRC_DIR}/H5TS.c
+)
+set (H5TS_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5TS" "${H5TS_HDRS}" "${H5TS_SOURCES}" )
+
+
+set (H5UC_SOURCES
+ ${HDF5_SRC_DIR}/H5UC.c
+)
+set (H5UC_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5UC" "${H5UC_HDRS}" "${H5UC_SOURCES}" )
+
+
+set (H5VM_SOURCES
+ ${HDF5_SRC_DIR}/H5VM.c
+)
+set (H5VM_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5VM" "${H5VM_HDRS}" "${H5VM_SOURCES}" )
+
+
+set (H5WB_SOURCES
+ ${HDF5_SRC_DIR}/H5WB.c
+)
+set (H5WB_HDRS
+)
+IDE_GENERATED_PROPERTIES ("H5WB" "${H5WB_HDRS}" "${H5WB_SOURCES}" )
+
+
+set (H5Z_SOURCES
+ ${HDF5_SRC_DIR}/H5Z.c
+ ${HDF5_SRC_DIR}/H5Zdeflate.c
+ ${HDF5_SRC_DIR}/H5Zfletcher32.c
+ ${HDF5_SRC_DIR}/H5Znbit.c
+ ${HDF5_SRC_DIR}/H5Zscaleoffset.c
+ ${HDF5_SRC_DIR}/H5Zshuffle.c
+ ${HDF5_SRC_DIR}/H5Zszip.c
+ ${HDF5_SRC_DIR}/H5Ztrans.c
+)
+if (H5_ZLIB_HEADER)
+ SET_PROPERTY(SOURCE ${HDF5_SRC_DIR}/H5Zdeflate.c PROPERTY
+ COMPILE_DEFINITIONS H5_ZLIB_HEADER="${H5_ZLIB_HEADER}")
+endif ()
+
+
+set (H5Z_HDRS
+ ${HDF5_SRC_DIR}/H5Zpkg.h
+ ${HDF5_SRC_DIR}/H5Zpublic.h
+)
+IDE_GENERATED_PROPERTIES ("H5Z" "${H5Z_HDRS}" "${H5Z_SOURCES}" )
+
+set (common_SRCS
+ ${H5_SOURCES}
+ ${H5A_SOURCES}
+ ${H5AC_SOURCES}
+ ${H5B_SOURCES}
+ ${H5B2_SOURCES}
+ ${H5C_SOURCES}
+ ${H5CS_SOURCES}
+ ${H5D_SOURCES}
+ ${H5E_SOURCES}
+ ${H5EA_SOURCES}
+ ${H5F_SOURCES}
+ ${H5FA_SOURCES}
+ ${H5FD_SOURCES}
+ ${H5FL_SOURCES}
+ ${H5FO_SOURCES}
+ ${H5FS_SOURCES}
+ ${H5G_SOURCES}
+ ${H5HF_SOURCES}
+ ${H5HG_SOURCES}
+ ${H5HL_SOURCES}
+ ${H5HP_SOURCES}
+ ${H5I_SOURCES}
+ ${H5L_SOURCES}
+ ${H5MF_SOURCES}
+ ${H5MM_SOURCES}
+ ${H5MP_SOURCES}
+ ${H5O_SOURCES}
+ ${H5P_SOURCES}
+ ${H5PB_SOURCES}
+ ${H5PL_SOURCES}
+ ${H5R_SOURCES}
+ ${H5UC_SOURCES}
+ ${H5RS_SOURCES}
+ ${H5S_SOURCES}
+ ${H5SL_SOURCES}
+ ${H5SM_SOURCES}
+ ${H5ST_SOURCES}
+ ${H5T_SOURCES}
+ ${H5TS_SOURCES}
+ ${H5VM_SOURCES}
+ ${H5WB_SOURCES}
+ ${H5Z_SOURCES}
+)
+
+set (H5_PUBLIC_HEADERS
+ ${H5_HDRS}
+ ${H5A_HDRS}
+ ${H5AC_HDRS}
+ ${H5B_HDRS}
+ ${H5B2_HDRS}
+ ${H5C_HDRS}
+ ${H5D_HDRS}
+ ${H5E_HDRS}
+ ${H5EA_HDRS}
+ ${H5F_HDRS}
+ ${H5FA_HDRS}
+ ${H5FD_HDRS}
+ ${H5FS_HDRS}
+ ${H5G_HDRS}
+ ${H5HF_HDRS}
+ ${H5HG_HDRS}
+ ${H5HL_HDRS}
+ ${H5I_HDRS}
+ ${H5L_HDRS}
+ ${H5MF_HDRS}
+ ${H5MM_HDRS}
+ ${H5MP_HDRS}
+ ${H5O_HDRS}
+ ${H5P_HDRS}
+ ${H5PB_HDRS}
+ ${H5PL_HDRS}
+ ${H5R_HDRS}
+ ${H5S_HDRS}
+ ${H5SM_HDRS}
+ ${H5T_HDRS}
+ ${H5Z_HDRS}
+)
+
+set (H5_PRIVATE_HEADERS
+ ${HDF5_SRC_DIR}/H5private.h
+ ${HDF5_SRC_DIR}/H5Aprivate.h
+ ${HDF5_SRC_DIR}/H5ACprivate.h
+ ${HDF5_SRC_DIR}/H5B2private.h
+ ${HDF5_SRC_DIR}/H5Bprivate.h
+ ${HDF5_SRC_DIR}/H5Cprivate.h
+ ${HDF5_SRC_DIR}/H5CSprivate.h
+ ${HDF5_SRC_DIR}/H5Dprivate.h
+ ${HDF5_SRC_DIR}/H5Eprivate.h
+ ${HDF5_SRC_DIR}/H5EAprivate.h
+ ${HDF5_SRC_DIR}/H5FAprivate.h
+ ${HDF5_SRC_DIR}/H5FDprivate.h
+ ${HDF5_SRC_DIR}/H5Fprivate.h
+ ${HDF5_SRC_DIR}/H5FLprivate.h
+ ${HDF5_SRC_DIR}/H5FOprivate.h
+ ${HDF5_SRC_DIR}/H5MFprivate.h
+ ${HDF5_SRC_DIR}/H5MMprivate.h
+ ${HDF5_SRC_DIR}/H5Cprivate.h
+ ${HDF5_SRC_DIR}/H5FSprivate.h
+ ${HDF5_SRC_DIR}/H5Gprivate.h
+ ${HDF5_SRC_DIR}/H5HFprivate.h
+ ${HDF5_SRC_DIR}/H5HGprivate.h
+ ${HDF5_SRC_DIR}/H5HLprivate.h
+ ${HDF5_SRC_DIR}/H5HPprivate.h
+ ${HDF5_SRC_DIR}/H5Iprivate.h
+ ${HDF5_SRC_DIR}/H5Lprivate.h
+ ${HDF5_SRC_DIR}/H5MPprivate.h
+ ${HDF5_SRC_DIR}/H5Oprivate.h
+ ${HDF5_SRC_DIR}/H5Pprivate.h
+ ${HDF5_SRC_DIR}/H5PBprivate.h
+ ${HDF5_SRC_DIR}/H5PLprivate.h
+ ${HDF5_SRC_DIR}/H5UCprivate.h
+ ${HDF5_SRC_DIR}/H5Rprivate.h
+ ${HDF5_SRC_DIR}/H5RSprivate.h
+ ${HDF5_SRC_DIR}/H5SLprivate.h
+ ${HDF5_SRC_DIR}/H5SMprivate.h
+ ${HDF5_SRC_DIR}/H5Sprivate.h
+ ${HDF5_SRC_DIR}/H5STprivate.h
+ ${HDF5_SRC_DIR}/H5Tprivate.h
+ ${HDF5_SRC_DIR}/H5TSprivate.h
+ ${HDF5_SRC_DIR}/H5VMprivate.h
+ ${HDF5_SRC_DIR}/H5WBprivate.h
+ ${HDF5_SRC_DIR}/H5Zprivate.h
+ ${HDF5_SRC_DIR}/H5win32defs.h
+)
+
+set (H5_GENERATED_HEADERS
+ ${HDF5_SRC_DIR}/H5Edefin.h
+ ${HDF5_SRC_DIR}/H5Einit.h
+ ${HDF5_SRC_DIR}/H5Epubgen.h
+ ${HDF5_SRC_DIR}/H5Eterm.h
+ ${HDF5_SRC_DIR}/H5version.h
+ ${HDF5_SRC_DIR}/H5overflow.h
+)
+
+option (HDF5_GENERATE_HEADERS "Rebuild Generated Files" OFF)
+if (HDF5_GENERATE_HEADERS)
+ set_source_files_properties(${H5_GENERATED_HEADERS} PROPERTIES GENERATED TRUE)
+ find_package (Perl)
+ if (PERL_FOUND)
+ execute_process (
+ COMMAND ${PERL_EXECUTABLE} ${HDF5_SOURCE_DIR}/bin/make_err ${HDF5_SRC_DIR}/H5err.txt OUTPUT_VARIABLE SCRIPT_OUTPUT
+ )
+ message(STATUS ${SCRIPT_OUTPUT})
+ execute_process (
+ COMMAND ${PERL_EXECUTABLE} ${HDF5_SOURCE_DIR}/bin/make_vers ${HDF5_SRC_DIR}/H5vers.txt OUTPUT_VARIABLE SCRIPT_OUTPUT
+ )
+ message(STATUS ${SCRIPT_OUTPUT})
+ execute_process (
+ COMMAND ${PERL_EXECUTABLE} ${HDF5_SOURCE_DIR}/bin/make_overflow ${HDF5_SRC_DIR}/H5overflow.txt OUTPUT_VARIABLE SCRIPT_OUTPUT
+ )
+ message(STATUS ${SCRIPT_OUTPUT})
+ else ()
+ message (STATUS "Cannot generate headers - perl not found")
+ endif ()
+endif ()
+
+#-----------------------------------------------------------------------------
+# Setup the H5Detect utility which generates H5Tinit with platform
+# specific type checks inside
+#-----------------------------------------------------------------------------
+add_executable (H5detect ${HDF5_SRC_DIR}/H5detect.c)
+TARGET_C_PROPERTIES (H5detect STATIC " " " ")
+if (MSVC OR MINGW)
+ target_link_libraries (H5detect "ws2_32.lib")
+endif ()
+
+set (CMD $<TARGET_FILE:H5detect>)
+add_custom_command (
+ OUTPUT ${HDF5_BINARY_DIR}/H5Tinit.c
+ COMMAND ${CMD}
+ ARGS > ${HDF5_BINARY_DIR}/H5Tinit.c
+ DEPENDS H5detect
+)
+
+add_executable (H5make_libsettings ${HDF5_SRC_DIR}/H5make_libsettings.c)
+TARGET_C_PROPERTIES (H5make_libsettings STATIC " " " ")
+if (MSVC OR MINGW)
+ target_link_libraries (H5make_libsettings "ws2_32.lib")
+endif ()
+
+set (CMD $<TARGET_FILE:H5make_libsettings>)
+add_custom_command (
+ OUTPUT ${HDF5_BINARY_DIR}/H5lib_settings.c
+ COMMAND ${CMD}
+ ARGS > ${HDF5_BINARY_DIR}/H5lib_settings.c
+ DEPENDS H5make_libsettings
+ WORKING_DIRECTORY ${HDF5_BINARY_DIR}
+)
+
+#-----------------------------------------------------------------------------
+# Add H5Tinit source to build - generated by H5Detect/CMake at configure time
+#-----------------------------------------------------------------------------
+set (gen_SRCS ${HDF5_BINARY_DIR}/H5Tinit.c ${HDF5_BINARY_DIR}/H5lib_settings.c)
+
+add_library (${HDF5_LIB_TARGET} STATIC ${common_SRCS} ${gen_SRCS} ${H5_PUBLIC_HEADERS} ${H5_PRIVATE_HEADERS} ${H5_GENERATED_HEADERS})
+TARGET_C_PROPERTIES (${HDF5_LIB_TARGET} STATIC " " " ")
+target_link_libraries (${HDF5_LIB_TARGET} ${LINK_LIBS})
+if (NOT WIN32)
+ target_link_libraries (${HDF5_LIB_TARGET} dl)
+endif ()
+if (H5_HAVE_PARALLEL AND MPI_C_FOUND)
+ target_link_libraries (${HDF5_LIB_TARGET} ${MPI_C_LIBRARIES})
+endif ()
+set_global_variable (HDF5_LIBRARIES_TO_EXPORT ${HDF5_LIB_TARGET})
+H5_SET_LIB_OPTIONS (${HDF5_LIB_TARGET} ${HDF5_LIB_NAME} STATIC)
+set_target_properties (${HDF5_LIB_TARGET} PROPERTIES
+ FOLDER libraries
+ INTERFACE_INCLUDE_DIRECTORIES "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>"
+)
+
+option (HDF5_ENABLE_DEBUG_APIS "Turn on extra debug output in all packages" OFF)
+if (HDF5_ENABLE_DEBUG_APIS)
+ set_target_properties (${HDF5_LIB_TARGET} PROPERTIES
+ COMPILE_DEFINITIONS
+ "H5Z_DEBUG;H5T_DEBUG;H5ST_DEBUG;H5S_DEBUG;H5O_DEBUG;H5I_DEBUG;H5HL_DEBUG;H5F_DEBUG;H5D_DEBUG;H5B2_DEBUG;H5AC_DEBUG"
+ )
+endif ()
+set (install_targets ${HDF5_LIB_TARGET})
+
+if (BUILD_SHARED_LIBS)
+ file (MAKE_DIRECTORY "${HDF5_BINARY_DIR}/shared")
+ set (CMD $<TARGET_FILE:H5detect>)
+ add_custom_command (
+ OUTPUT ${HDF5_BINARY_DIR}/shared/H5Tinit.c
+ COMMAND ${CMD}
+ ARGS > ${HDF5_BINARY_DIR}/shared/H5Tinit.c
+ DEPENDS H5detect
+ WORKING_DIRECTORY ${HDF5_BINARY_DIR}/shared
+ )
+ set (CMD $<TARGET_FILE:H5make_libsettings>)
+ add_custom_command (
+ OUTPUT ${HDF5_BINARY_DIR}/shared/H5lib_settings.c
+ COMMAND ${CMD}
+ ARGS > ${HDF5_BINARY_DIR}/shared/H5lib_settings.c
+ DEPENDS H5make_libsettings
+ WORKING_DIRECTORY ${HDF5_BINARY_DIR}
+ )
+ set (shared_gen_SRCS ${HDF5_BINARY_DIR}/shared/H5Tinit.c ${HDF5_BINARY_DIR}/shared/H5lib_settings.c)
+ add_library (${HDF5_LIBSH_TARGET} SHARED ${common_SRCS} ${shared_gen_SRCS} ${H5_PUBLIC_HEADERS} ${H5_PRIVATE_HEADERS} ${H5_GENERATED_HEADERS})
+ TARGET_C_PROPERTIES (${HDF5_LIBSH_TARGET} SHARED " " " ")
+ target_link_libraries (${HDF5_LIBSH_TARGET} ${LINK_SHARED_LIBS})
+ if (NOT WIN32)
+ target_link_libraries (${HDF5_LIBSH_TARGET} dl)
+ endif ()
+ if (H5_HAVE_PARALLEL AND MPI_C_FOUND)
+ target_link_libraries (${HDF5_LIBSH_TARGET} ${MPI_C_LIBRARIES})
+ endif ()
+ set_global_variable (HDF5_LIBRARIES_TO_EXPORT "${HDF5_LIBRARIES_TO_EXPORT};${HDF5_LIBSH_TARGET}")
+ H5_SET_LIB_OPTIONS (${HDF5_LIBSH_TARGET} ${HDF5_LIB_NAME} SHARED ${HDF5_PACKAGE_SOVERSION})
+ set_target_properties (${HDF5_LIBSH_TARGET} PROPERTIES
+ FOLDER libraries
+ COMPILE_DEFINITIONS "H5_BUILT_AS_DYNAMIC_LIB"
+ INTERFACE_INCLUDE_DIRECTORIES "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>"
+ INTERFACE_COMPILE_DEFINITIONS H5_BUILT_AS_DYNAMIC_LIB=1
+ )
+ if (HDF5_ENABLE_THREADSAFE)
+ set_property (TARGET ${HDF5_LIBSH_TARGET}
+ APPEND PROPERTY COMPILE_DEFINITIONS
+ "H5_HAVE_THREADSAFE"
+ )
+ target_link_libraries (${HDF5_LIBSH_TARGET} Threads::Threads)
+ endif ()
+
+ if (HDF5_ENABLE_DEBUG_APIS)
+ set_property (TARGET ${HDF5_LIBSH_TARGET}
+ APPEND PROPERTY COMPILE_DEFINITIONS
+ "H5Z_DEBUG;H5T_DEBUG;H5ST_DEBUG;H5S_DEBUG;H5O_DEBUG;H5I_DEBUG;H5HL_DEBUG;H5F_DEBUG;H5D_DEBUG;H5B2_DEBUG;H5AC_DEBUG"
+ )
+ endif ()
+ set (install_targets ${install_targets} ${HDF5_LIBSH_TARGET})
+endif ()
+
+#-----------------------------------------------------------------------------
+# Add file(s) to CMake Install
+#-----------------------------------------------------------------------------
+if (NOT HDF5_INSTALL_NO_DEVELOPMENT)
+ install (
+ FILES
+ ${H5_PUBLIC_HEADERS}
+ ${H5_GENERATED_HEADERS}
+ DESTINATION
+ ${HDF5_INSTALL_INCLUDE_DIR}
+ COMPONENT
+ headers
+ )
+endif ()
+
+#-----------------------------------------------------------------------------
+# Add Target(s) to CMake Install for import into other projects
+#-----------------------------------------------------------------------------
+if (HDF5_EXPORTED_TARGETS)
+ if (BUILD_SHARED_LIBS)
+ INSTALL_TARGET_PDB (${HDF5_LIBSH_TARGET} ${HDF5_INSTALL_BIN_DIR} libraries)
+ endif ()
+ INSTALL_TARGET_PDB (${HDF5_LIB_TARGET} ${HDF5_INSTALL_BIN_DIR} libraries)
+
+ install (
+ TARGETS
+ ${install_targets}
+ EXPORT
+ ${HDF5_EXPORTED_TARGETS}
+ LIBRARY DESTINATION ${HDF5_INSTALL_LIB_DIR} COMPONENT libraries
+ ARCHIVE DESTINATION ${HDF5_INSTALL_LIB_DIR} COMPONENT libraries
+ RUNTIME DESTINATION ${HDF5_INSTALL_BIN_DIR} COMPONENT libraries
+ FRAMEWORK DESTINATION ${HDF5_INSTALL_FWRK_DIR} COMPONENT libraries
+ INCLUDES DESTINATION include
+ )
+endif ()
diff --git a/src/COPYING b/src/COPYING
new file mode 100644
index 0000000..6497ace
--- /dev/null
+++ b/src/COPYING
@@ -0,0 +1,13 @@
+
+ Copyright by The HDF Group and
+ The Board of Trustees of the University of Illinois.
+ All rights reserved.
+
+ The files and subdirectories in this directory are part of HDF5.
+ The full HDF5 copyright notice, including terms governing use,
+ modification, and redistribution, is contained in the COPYING file
+ which can be found at the root of the source code distribution tree
+ or in https://support.hdfgroup.org/ftp/HDF5/releases. If you do
+ not have access to either file, you may request a copy from
+ help@hdfgroup.org.
+
diff --git a/src/H5.c b/src/H5.c
new file mode 100644
index 0000000..1068fc6
--- /dev/null
+++ b/src/H5.c
@@ -0,0 +1,1110 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SLprivate.h" /* Skip lists */
+#include "H5Tprivate.h" /* Datatypes */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static void H5_debug_mask(const char*);
+#ifdef H5_HAVE_PARALLEL
+static int H5_mpi_delete_cb(MPI_Comm comm, int keyval, void *attr_val, int *flag);
+#endif /*H5_HAVE_PARALLEL*/
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* HDF5 API Entered variable */
+/* (move to H5.c when new FUNC_ENTER macros in actual use -QAK) */
+hbool_t H5_api_entered_g = FALSE;
+
+/* statically initialize block for pthread_once call used in initializing */
+/* the first global mutex */
+#ifdef H5_HAVE_THREADSAFE
+H5_api_t H5_g;
+#else
+hbool_t H5_libinit_g = FALSE; /* Library hasn't been initialized */
+hbool_t H5_libterm_g = FALSE; /* Library isn't being shutdown */
+#endif
+
+#ifdef H5_HAVE_MPE
+hbool_t H5_MPEinit_g = FALSE; /* MPE Library hasn't been initialized */
+#endif
+
+char H5_lib_vers_info_g[] = H5_VERS_INFO;
+static hbool_t H5_dont_atexit_g = FALSE;
+H5_debug_t H5_debug_g; /*debugging info */
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5_init_library -- Initialize library-global information
+ * USAGE
+ * herr_t H5_init_library()
+ *
+ * RETURNS
+ * Non-negative on success/Negative on failure
+ *
+ * DESCRIPTION
+ * Initializes any library-global data or routines.
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5_init_library(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+#ifdef H5_HAVE_PARALLEL
+ {
+ int mpi_initialized;
+ int mpi_finalized;
+ int mpi_code;
+
+ MPI_Initialized(&mpi_initialized);
+ MPI_Finalized(&mpi_finalized);
+
+#ifdef H5_HAVE_MPE
+ /* Initialize MPE instrumentation library. */
+ if (!H5_MPEinit_g) {
+ int mpe_code;
+ if (mpi_initialized && !mpi_finalized) {
+ mpe_code = MPE_Init_log();
+ HDassert(mpe_code >=0);
+ H5_MPEinit_g = TRUE;
+ }
+ }
+#endif /*H5_HAVE_MPE*/
+
+ /* add an attribute on MPI_COMM_SELF to call H5_term_library
+ when it is destroyed, i.e. on MPI_Finalize */
+ if (mpi_initialized && !mpi_finalized) {
+ int key_val;
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Comm_create_keyval(MPI_NULL_COPY_FN,
+ (MPI_Comm_delete_attr_function *)H5_mpi_delete_cb,
+ &key_val, NULL)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Comm_create_keyval failed", mpi_code)
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Comm_set_attr(MPI_COMM_SELF, key_val, NULL)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Comm_set_attr failed", mpi_code)
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Comm_free_keyval(&key_val)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Comm_free_keyval failed", mpi_code)
+ }
+ }
+#endif /*H5_HAVE_PARALLEL*/
+
+ /*
+ * Make sure the package information is updated.
+ */
+ HDmemset(&H5_debug_g, 0, sizeof H5_debug_g);
+ H5_debug_g.pkg[H5_PKG_A].name = "a";
+ H5_debug_g.pkg[H5_PKG_AC].name = "ac";
+ H5_debug_g.pkg[H5_PKG_B].name = "b";
+ H5_debug_g.pkg[H5_PKG_D].name = "d";
+ H5_debug_g.pkg[H5_PKG_E].name = "e";
+ H5_debug_g.pkg[H5_PKG_F].name = "f";
+ H5_debug_g.pkg[H5_PKG_G].name = "g";
+ H5_debug_g.pkg[H5_PKG_HG].name = "hg";
+ H5_debug_g.pkg[H5_PKG_HL].name = "hl";
+ H5_debug_g.pkg[H5_PKG_I].name = "i";
+ H5_debug_g.pkg[H5_PKG_MF].name = "mf";
+ H5_debug_g.pkg[H5_PKG_MM].name = "mm";
+ H5_debug_g.pkg[H5_PKG_O].name = "o";
+ H5_debug_g.pkg[H5_PKG_P].name = "p";
+ H5_debug_g.pkg[H5_PKG_S].name = "s";
+ H5_debug_g.pkg[H5_PKG_T].name = "t";
+ H5_debug_g.pkg[H5_PKG_V].name = "v";
+ H5_debug_g.pkg[H5_PKG_Z].name = "z";
+
+ /*
+ * Install atexit() library cleanup routines unless the H5dont_atexit()
+ * has been called. Once we add something to the atexit() list it stays
+ * there permanently, so we set H5_dont_atexit_g after we add it to prevent
+ * adding it again later if the library is cosed and reopened.
+ */
+ if (!H5_dont_atexit_g) {
+
+#if defined(H5_HAVE_THREADSAFE) && defined(H5_HAVE_WIN_THREADS)
+ /* Clean up Win32 thread resources. Pthreads automatically cleans up.
+ * This must be entered before the library cleanup code so it's
+ * executed in LIFO order (i.e., last).
+ */
+ (void)HDatexit(H5TS_win32_process_exit);
+#endif /* H5_HAVE_THREADSAFE && H5_HAVE_WIN_THREADS */
+
+ /* Normal library termination code */
+ (void)HDatexit(H5_term_library);
+
+ H5_dont_atexit_g = TRUE;
+ } /* end if */
+
+ /*
+ * Initialize interfaces that might not be able to initialize themselves
+ * soon enough. The file & dataset interfaces must be initialized because
+ * calling H5P_create() might require the file/dataset property classes to be
+ * initialized. The property interface must be initialized before the file
+ * & dataset interfaces though, in order to provide them with the proper
+ * property classes.
+ * The link interface needs to be initialized so that link property lists
+ * have their properties registered.
+ */
+ if(H5E_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize error interface")
+ if(H5P_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize property list interface")
+ if(H5T_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize datatype interface")
+ if(H5D_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize dataset interface")
+ if(H5AC_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize metadata caching interface")
+ if(H5L_init() < 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize link interface")
+
+ /* Debugging? */
+ H5_debug_mask("-all");
+ H5_debug_mask(HDgetenv("HDF5_DEBUG"));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_init_library() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_term_library
+ *
+ * Purpose: Terminate interfaces in a well-defined order due to
+ * dependencies among the interfaces, then terminate
+ * library-specific data.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 20, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5_term_library(void)
+{
+ int pending, ntries = 0, n;
+ size_t at = 0;
+ char loop[1024];
+ H5E_auto2_t func;
+
+#ifdef H5_HAVE_THREADSAFE
+ /* explicit locking of the API */
+ H5_FIRST_THREAD_INIT
+ H5_API_LOCK
+#endif
+
+ /* Don't do anything if the library is already closed */
+ if(!(H5_INIT_GLOBAL))
+ goto done;
+
+ /* Indicate that the library is being shut down */
+ H5_TERM_GLOBAL = TRUE;
+
+ /* Check if we should display error output */
+ (void)H5Eget_auto2(H5E_DEFAULT, &func, NULL);
+
+ /*
+ * Terminate each interface. The termination functions return a positive
+ * value if they do something that might affect some other interface in a
+ * way that would necessitate some cleanup work in the other interface.
+ */
+#define DOWN(F) \
+ (((n = H5##F##_term_package()) && (at + 8) < sizeof loop)? \
+ (sprintf(loop + at, "%s%s", (at ? "," : ""), #F), \
+ at += HDstrlen(loop + at), \
+ n): \
+ ((n > 0 && (at + 5) < sizeof loop) ? \
+ (sprintf(loop + at, "..."), \
+ at += HDstrlen(loop + at), \
+ n) : n))
+
+ do {
+ pending = 0;
+
+ /* Try to organize these so the "higher" level components get shut
+ * down before "lower" level components that they might rely on. -QAK
+ */
+ pending += DOWN(L);
+
+ /* Close the "top" of various interfaces (IDs, etc) but don't shut
+ * down the whole interface yet, so that the object header messages
+ * get serialized correctly for entries in the metadata cache and the
+ * symbol table entry in the superblock gets serialized correctly, etc.
+ * all of which is performed in the 'F' shutdown.
+ */
+ pending += DOWN(A_top);
+ pending += DOWN(D_top);
+ pending += DOWN(G_top);
+ pending += DOWN(R_top);
+ pending += DOWN(S_top);
+ pending += DOWN(T_top);
+
+ /* Don't shut down the file code until objects in files are shut down */
+ if(pending == 0)
+ pending += DOWN(F);
+
+ /* Don't shut down the property list code until all objects that might
+ * use property lists are shut down */
+ if(pending == 0)
+ pending += DOWN(P);
+
+ /* Wait to shut down the "bottom" of various interfaces until the
+ * files are closed, so pieces of the file can be serialized
+ * correctly.
+ */
+ if(pending == 0) {
+ /* Shut down the "bottom" of the attribute, dataset, group,
+ * reference, dataspace, and datatype interfaces, fully closing
+ * out the interfaces now.
+ */
+ pending += DOWN(A);
+ pending += DOWN(D);
+ pending += DOWN(G);
+ pending += DOWN(R);
+ pending += DOWN(S);
+ pending += DOWN(T);
+ } /* end if */
+
+ /* Don't shut down "low-level" components until "high-level" components
+ * have successfully shut down. This prevents property lists and IDs
+ * from being closed "out from underneath" of the high-level objects
+ * that depend on them. -QAK
+ */
+ if(pending == 0) {
+ pending += DOWN(AC);
+ pending += DOWN(Z);
+ pending += DOWN(FD);
+ pending += DOWN(PL);
+ /* Don't shut down the error code until other APIs which use it are shut down */
+ if(pending == 0)
+ pending += DOWN(E);
+ /* Don't shut down the ID code until other APIs which use them are shut down */
+ if(pending == 0)
+ pending += DOWN(I);
+ /* Don't shut down the skip list code until everything that uses it is down */
+ if(pending == 0)
+ pending += DOWN(SL);
+ /* Don't shut down the free list code until _everything_ else is down */
+ if(pending == 0)
+ pending += DOWN(FL);
+ } /* end if */
+ } while(pending && ntries++ < 100);
+
+ if(pending) {
+ /* Only display the error message if the user is interested in them. */
+ if(func) {
+ fprintf(stderr, "HDF5: infinite loop closing library\n");
+ fprintf(stderr, " %s\n", loop);
+#ifndef NDEBUG
+ HDabort();
+#endif /* NDEBUG */
+ } /* end if */
+ } /* end if */
+
+#ifdef H5_HAVE_MPE
+ /* Close MPE instrumentation library. May need to move this
+ * down if any of the below code involves using the instrumentation code.
+ */
+ if(H5_MPEinit_g) {
+ int mpi_initialized;
+ int mpi_finalized;
+ int mpe_code;
+
+ MPI_Initialized(&mpi_initialized);
+ MPI_Finalized(&mpi_finalized);
+
+ if (mpi_initialized && !mpi_finalized) {
+ mpe_code = MPE_Finish_log("h5log");
+ HDassert(mpe_code >=0);
+ } /* end if */
+ H5_MPEinit_g = FALSE; /* turn it off no matter what */
+ } /* end if */
+#endif
+
+ /* Free open debugging streams */
+ while(H5_debug_g.open_stream) {
+ H5_debug_open_stream_t *tmp_open_stream;
+
+ tmp_open_stream = H5_debug_g.open_stream;
+ (void)HDfclose(H5_debug_g.open_stream->stream);
+ H5_debug_g.open_stream = H5_debug_g.open_stream->next;
+ (void)H5MM_free(tmp_open_stream);
+ } /* end while */
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ /* Sanity check memory allocations */
+ H5MM_final_sanity_check();
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+ /* Reset flag indicating that the library is being shut down */
+ H5_TERM_GLOBAL = FALSE;
+
+ /* Mark library as closed */
+ H5_INIT_GLOBAL = FALSE;
+
+done:
+#ifdef H5_HAVE_THREADSAFE
+ H5_API_UNLOCK
+#endif /* H5_HAVE_THREADSAFE */
+
+ return;
+} /* end H5_term_library() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5dont_atexit
+ *
+ * Purpose: Indicates that the library is not to clean up after itself
+ * when the application exits by calling exit() or returning
+ * from main(). This function must be called before any other
+ * HDF5 function or constant is used or it will have no effect.
+ *
+ * If this function is used then certain memory buffers will not
+ * be de-allocated nor will open files be flushed automatically.
+ * The application may still call H5close() explicitly to
+ * accomplish these things.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative if this function is called more than
+ * once or if it is called too late.
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 20, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5dont_atexit(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API_NOINIT_NOERR_NOFS
+ H5TRACE0("e","");
+
+ if(H5_dont_atexit_g)
+ ret_value = FAIL;
+ else
+ H5_dont_atexit_g = TRUE;
+
+ FUNC_LEAVE_API_NOFS(ret_value)
+} /* end H5dont_atexit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5garbage_collect
+ *
+ * Purpose: Walks through all the garbage collection routines for the
+ * library, which are supposed to free any unused memory they have
+ * allocated.
+ *
+ * These should probably be registered dynamicly in a linked list of
+ * functions to call, but there aren't that many right now, so we
+ * hard-wire them...
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 11, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5garbage_collect(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE0("e","");
+
+ /* Call the garbage collection routines in the library */
+ if(H5FL_garbage_coll()<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect objects")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5garbage_collect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5set_free_list_limits
+ *
+ * Purpose: Sets limits on the different kinds of free lists. Setting a value
+ * of -1 for a limit means no limit of that type. These limits are global
+ * for the entire library. Each "global" limit only applies to free lists
+ * of that type, so if an application sets a limit of 1 MB on each of the
+ * global lists, up to 3 MB of total storage might be allocated (1MB on
+ * each of regular, array and block type lists).
+ *
+ * The settings for block free lists are duplicated to factory free lists.
+ * Factory free list limits cannot be set independently currently.
+ *
+ * Parameters:
+ * int reg_global_lim; IN: The limit on all "regular" free list memory used
+ * int reg_list_lim; IN: The limit on memory used in each "regular" free list
+ * int arr_global_lim; IN: The limit on all "array" free list memory used
+ * int arr_list_lim; IN: The limit on memory used in each "array" free list
+ * int blk_global_lim; IN: The limit on all "block" free list memory used
+ * int blk_list_lim; IN: The limit on memory used in each "block" free list
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 2, 2000
+ *
+ * Modifications: Neil Fortner
+ * Wednesday, April 8, 2009
+ * Added support for factory free lists
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim,
+ int arr_list_lim, int blk_global_lim, int blk_list_lim)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "IsIsIsIsIsIs", reg_global_lim, reg_list_lim, arr_global_lim,
+ arr_list_lim, blk_global_lim, blk_list_lim);
+
+ /* Call the free list function to actually set the limits */
+ if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim,
+ blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5set_free_list_limits() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_debug_mask
+ *
+ * Purpose: Set runtime debugging flags according to the string S. The
+ * string should contain file numbers and package names
+ * separated by other characters. A file number applies to all
+ * following package names up to the next file number. The
+ * initial file number is `2' (the standard error stream). Each
+ * package name can be preceded by a `+' or `-' to add or remove
+ * the package from the debugging list (`+' is the default). The
+ * special name `all' means all packages.
+ *
+ * The name `trace' indicates that API tracing is to be turned
+ * on or off.
+ *
+ * The name 'ttop' indicates that only top-level API calls
+ * should be shown. This also turns on tracing as if the
+ * 'trace' word was shown.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5_debug_mask(const char *s)
+{
+ FILE *stream = stderr;
+ char pkg_name[32], *rest;
+ size_t i;
+ hbool_t clear;
+
+ while (s && *s) {
+
+ if (HDisalpha(*s) || '-'==*s || '+'==*s) {
+
+ /* Enable or Disable debugging? */
+ if ('-'==*s) {
+ clear = TRUE;
+ s++;
+ } else if ('+'==*s) {
+ clear = FALSE;
+ s++;
+ } else {
+ clear = FALSE;
+ } /* end if */
+
+ /* Get the name */
+ for (i=0; HDisalpha(*s); i++, s++)
+ if (i<sizeof pkg_name)
+ pkg_name[i] = *s;
+ pkg_name[MIN(sizeof(pkg_name)-1, i)] = '\0';
+
+ /* Trace, all, or one? */
+ if (!HDstrcmp(pkg_name, "trace")) {
+ H5_debug_g.trace = clear ? NULL : stream;
+ } else if (!HDstrcmp(pkg_name, "ttop")) {
+ H5_debug_g.trace = stream;
+ H5_debug_g.ttop = (hbool_t)!clear;
+ } else if (!HDstrcmp(pkg_name, "ttimes")) {
+ H5_debug_g.trace = stream;
+ H5_debug_g.ttimes = (hbool_t)!clear;
+ } else if (!HDstrcmp(pkg_name, "all")) {
+ for (i=0; i<(size_t)H5_NPKGS; i++)
+ H5_debug_g.pkg[i].stream = clear ? NULL : stream;
+ } else {
+ for (i=0; i<(size_t)H5_NPKGS; i++) {
+ if (!HDstrcmp(H5_debug_g.pkg[i].name, pkg_name)) {
+ H5_debug_g.pkg[i].stream = clear ? NULL : stream;
+ break;
+ } /* end if */
+ } /* end for */
+ if (i>=(size_t)H5_NPKGS)
+ fprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name);
+ } /* end if-else */
+
+ } else if (HDisdigit(*s)) {
+ int fd = (int)HDstrtol(s, &rest, 0);
+ H5_debug_open_stream_t *open_stream;
+
+ if((stream = HDfdopen(fd, "w")) != NULL) {
+ (void)HDsetvbuf(stream, NULL, _IOLBF, (size_t)0);
+
+ if(NULL == (open_stream = (H5_debug_open_stream_t *)H5MM_malloc(sizeof(H5_debug_open_stream_t)))) {
+ (void)HDfclose(stream);
+ return;
+ } /* end if */
+
+ open_stream->stream = stream;
+ open_stream->next = H5_debug_g.open_stream;
+ H5_debug_g.open_stream = open_stream;
+ } /* end if */
+
+ s = rest;
+ } else {
+ s++;
+ } /* end if-else */
+ } /* end while */
+
+ return;
+
+} /* end H5_debug_mask() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5_mpi_delete_cb
+ *
+ * Purpose: Callback attribute on MPI_COMM_SELF to terminate the HDF5
+ * library when the communicator is destroyed, i.e. on MPI_Finalize.
+ *
+ * Return: MPI_SUCCESS
+ *
+ * Programmer: Mohamad Chaarawi, February 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int H5_mpi_delete_cb(MPI_Comm H5_ATTR_UNUSED comm, int H5_ATTR_UNUSED keyval, void H5_ATTR_UNUSED *attr_val, int H5_ATTR_UNUSED *flag)
+{
+ H5_term_library();
+ return MPI_SUCCESS;
+}
+#endif /*H5_HAVE_PARALLEL*/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5get_libversion
+ *
+ * Purpose: Returns the library version numbers through arguments. MAJNUM
+ * will be the major revision number of the library, MINNUM the
+ * minor revision number, and RELNUM the release revision number.
+ *
+ * Note: When printing an HDF5 version number it should be printed as
+ *
+ * printf("%u.%u.%u", maj, min, rel) or
+ * printf("version %u.%u release %u", maj, min, rel)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Unknown
+ *
+ * Modifications:
+ * Robb Matzke, 4 Mar 1998
+ * Now use "normal" data types for the interface. Any of the arguments
+ * may be null pointers
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "*Iu*Iu*Iu", majnum, minnum, relnum);
+
+ /* Set the version information */
+ if (majnum) *majnum = H5_VERS_MAJOR;
+ if (minnum) *minnum = H5_VERS_MINOR;
+ if (relnum) *relnum = H5_VERS_RELEASE;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5get_libversion() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5check_version
+ *
+ * Purpose: Verifies that the arguments match the version numbers
+ * compiled into the library. This function is intended to be
+ * called from user to verify that the versions of header files
+ * compiled into the application match the version of the hdf5
+ * library.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: abort()
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, April 21, 1998
+ *
+ * Modifications:
+ * Albert Cheng, May 12, 2001
+ * Added verification of H5_VERS_INFO.
+ *
+ *-------------------------------------------------------------------------
+ */
+#define VERSION_MISMATCH_WARNING \
+ "Warning! ***HDF5 library version mismatched error***\n" \
+ "The HDF5 header files used to compile this application do not match\n" \
+ "the version used by the HDF5 library to which this application is linked.\n" \
+ "Data corruption or segmentation faults may occur if the application continues.\n" \
+ "This can happen when an application was compiled by one version of HDF5 but\n" \
+ "linked with a different version of static or shared HDF5 library.\n" \
+ "You should recompile the application or check your shared library related\n" \
+ "settings such as 'LD_LIBRARY_PATH'.\n"
+
+herr_t
+H5check_version(unsigned majnum, unsigned minnum, unsigned relnum)
+{
+ char lib_str[256];
+ char substr[] = H5_VERS_SUBRELEASE;
+ static int checked = 0; /* If we've already checked the version info */
+ static unsigned int disable_version_check = 0; /* Set if the version check should be disabled */
+ static const char *version_mismatch_warning = VERSION_MISMATCH_WARNING;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API_NOINIT_NOERR_NOFS
+ H5TRACE3("e", "IuIuIu", majnum, minnum, relnum);
+
+ /* Don't check again, if we already have */
+ if (checked)
+ HGOTO_DONE(SUCCEED)
+
+ { const char *s; /* Environment string for disabling version check */
+
+ /* Allow different versions of the header files and library? */
+ s = HDgetenv ("HDF5_DISABLE_VERSION_CHECK");
+
+ if (s && HDisdigit(*s))
+ disable_version_check = (unsigned int)HDstrtol (s, NULL, 0);
+ }
+
+ if (H5_VERS_MAJOR!=majnum || H5_VERS_MINOR!=minnum ||
+ H5_VERS_RELEASE!=relnum) {
+ switch (disable_version_check) {
+ case 0:
+ HDfprintf(stderr, "%s%s", version_mismatch_warning,
+ "You can, at your own risk, disable this warning by setting the environment\n"
+ "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.\n"
+ "Setting it to 2 or higher will suppress the warning messages totally.\n");
+ /* Mention the versions we are referring to */
+ HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n",
+ majnum, minnum, relnum,
+ (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE);
+ /* Show library settings if available */
+ HDfprintf (stderr, "%s", H5libhdf5_settings);
+
+ /* Bail out now. */
+ HDfputs ("Bye...\n", stderr);
+ HDabort ();
+ case 1:
+ /* continue with a warning */
+ /* Note that the warning message is embedded in the format string.*/
+ HDfprintf (stderr,
+ "%s'HDF5_DISABLE_VERSION_CHECK' "
+ "environment variable is set to %d, application will\n"
+ "continue at your own risk.\n",
+ version_mismatch_warning, disable_version_check);
+ /* Mention the versions we are referring to */
+ HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n",
+ majnum, minnum, relnum,
+ (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE);
+ /* Show library settings if available */
+ HDfprintf (stderr, "%s", H5libhdf5_settings);
+ break;
+ default:
+ /* 2 or higer: continue silently */
+ break;
+ } /* end switch */
+
+ } /* end if */
+
+ /* Indicate that the version check has been performed */
+ checked = 1;
+
+ if (!disable_version_check){
+ /*
+ * Verify if H5_VERS_INFO is consistent with the other version information.
+ * Check only the first sizeof(lib_str) char. Assume the information
+ * will fit within this size or enough significance.
+ */
+ HDsnprintf(lib_str, sizeof(lib_str), "HDF5 library version: %d.%d.%d",
+ H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE);
+ if(*substr) {
+ HDstrncat(lib_str, "-", (size_t)1);
+ HDstrncat(lib_str, substr, (sizeof(lib_str) - HDstrlen(lib_str)) - 1);
+ } /* end if */
+ if (HDstrcmp(lib_str, H5_lib_vers_info_g)){
+ HDfputs ("Warning! Library version information error.\n"
+ "The HDF5 library version information are not "
+ "consistent in its source code.\nThis is NOT a fatal error "
+ "but should be corrected. Setting the environment\n"
+ "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of 1 "
+ "will suppress\nthis warning.\n",
+ stderr);
+ HDfprintf (stderr, "Library version information are:\n"
+ "H5_VERS_MAJOR=%d, H5_VERS_MINOR=%d, H5_VERS_RELEASE=%d, "
+ "H5_VERS_SUBRELEASE=%s,\nH5_VERS_INFO=%s\n",
+ H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE,
+ H5_VERS_SUBRELEASE, H5_VERS_INFO);
+ } /* end if */
+ }
+
+done:
+ FUNC_LEAVE_API_NOFS(ret_value)
+} /* end H5check_version() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5open
+ *
+ * Purpose: Initialize the library. This is normally called
+ * automatically, but if you find that an HDF5 library function
+ * is failing inexplicably, then try calling this function
+ * first.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5open(void)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE0("e","");
+ /* all work is done by FUNC_ENTER() */
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5close
+ *
+ * Purpose: Terminate the library and release all resources.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5close(void)
+{
+ /*
+ * Don't call normal FUNC_ENTER() since we don't want to initialize the
+ * whole library just to release it all right away. It is safe to call
+ * this function for an uninitialized library.
+ */
+ FUNC_ENTER_API_NOINIT_NOERR_NOFS
+ H5TRACE0("e","");
+
+ H5_term_library();
+
+ FUNC_LEAVE_API_NOFS(SUCCEED)
+} /* end H5close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5allocate_memory
+ *
+ * Purpose: Allocate a memory buffer with the semantics of malloc().
+ *
+ * NOTE: This function is intended for use with filter
+ * plugins so that all allocation and free operations
+ * use the same memory allocator. It is not intended for
+ * use as a general memory allocator in applications.
+ *
+ * Parameters:
+ *
+ * size: The size of the buffer.
+ *
+ * clear: Whether or not to memset the buffer to 0.
+ *
+ * Return:
+ *
+ * Success: A pointer to the allocated buffer.
+ *
+ * Failure: NULL
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5allocate_memory(size_t size, hbool_t clear)
+{
+ void *ret_value = NULL;
+
+ FUNC_ENTER_API_NOINIT
+ H5TRACE2("*x", "zb", size, clear);
+
+ if(clear)
+ ret_value = H5MM_calloc(size);
+ else
+ ret_value = H5MM_malloc(size);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5allocate_memory() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5resize_memory
+ *
+ * Purpose: Resize a memory buffer with the semantics of realloc().
+ *
+ * NOTE: This function is intended for use with filter
+ * plugins so that all allocation and free operations
+ * use the same memory allocator. It is not intended for
+ * use as a general memory allocator in applications.
+ *
+ * Parameters:
+ *
+ * mem: The buffer to be resized.
+ *
+ * size: The size of the buffer.
+ *
+ * Return:
+ *
+ * Success: A pointer to the resized buffer.
+ *
+ * Failure: NULL (the input buffer will be unchanged)
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5resize_memory(void *mem, size_t size)
+{
+ void *ret_value = NULL;
+
+ FUNC_ENTER_API_NOINIT
+ H5TRACE2("*x", "*xz", mem, size);
+
+ ret_value = H5MM_realloc(mem, size);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5resize_memory() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5free_memory
+ *
+ * Purpose: Frees memory allocated by the library that it is the user's
+ * responsibility to free. Ensures that the same library
+ * that was used to allocate the memory frees it. Passing
+ * NULL pointers is allowed.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5free_memory(void *mem)
+{
+ FUNC_ENTER_API_NOINIT
+ H5TRACE1("e", "*x", mem);
+
+ /* At this time, it is impossible for this to fail. */
+ H5MM_xfree(mem);
+
+ FUNC_LEAVE_API(SUCCEED)
+} /* end H5free_memory() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5is_library_threadsafe
+ *
+ * Purpose: Checks to see if the library was built with thread-safety
+ * enabled.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5is_library_threadsafe(hbool_t *is_ts)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API_NOINIT
+ H5TRACE1("e", "*b", is_ts);
+
+ HDassert(is_ts);
+
+#ifdef H5_HAVE_THREADSAFE
+ *is_ts = TRUE;
+#else /* H5_HAVE_THREADSAFE */
+ *is_ts = FALSE;
+#endif /* H5_HAVE_THREADSAFE */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5is_library_threadsafe() */
+
+
+#if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) \
+ && defined(H5_HAVE_WIN32_API) && defined(H5_HAVE_WIN_THREADS)
+/*-------------------------------------------------------------------------
+ * Function: DllMain
+ *
+ * Purpose: Handles various conditions in the library on Windows.
+ *
+ * NOTE: The main purpose of this is for handling Win32 thread cleanup
+ * on thread/process detach.
+ *
+ * Only enabled when the shared Windows library is built with
+ * thread safety enabled.
+ *
+ * Return: TRUE on success, FALSE on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+BOOL WINAPI
+DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
+{
+ /* Don't add our function enter/leave macros since this function will be
+ * called before the library is initialized.
+ *
+ * NOTE: Do NOT call any CRT functions in DllMain!
+ * This includes any functions that are called by from here!
+ */
+
+ BOOL fOkay = TRUE;
+
+ switch(fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+
+ case DLL_THREAD_ATTACH:
+#ifdef H5_HAVE_WIN_THREADS
+ if(H5TS_win32_thread_enter() < 0)
+ fOkay = FALSE;
+#endif /* H5_HAVE_WIN_THREADS */
+ break;
+
+ case DLL_THREAD_DETACH:
+#ifdef H5_HAVE_WIN_THREADS
+ if(H5TS_win32_thread_exit() < 0)
+ fOkay = FALSE;
+#endif /* H5_HAVE_WIN_THREADS */
+ break;
+
+ default:
+ /* Shouldn't get here */
+ fOkay = FALSE;
+ break;
+ }
+
+ return fOkay;
+}
+#endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB && H5_HAVE_WIN_THREADS && H5_HAVE_THREADSAFE*/
+
diff --git a/src/H5A.c b/src/H5A.c
new file mode 100644
index 0000000..cf48232
--- /dev/null
+++ b/src/H5A.c
@@ -0,0 +1,1748 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspace functions */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Object header iterator callbacks */
+/* Data structure for callback for locating the index by name */
+typedef struct H5A_iter_cb1 {
+ const char *name;
+ int idx;
+} H5A_iter_cb1;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare the free lists of H5A_t */
+H5FL_DEFINE(H5A_t);
+
+/* Declare the free lists for H5A_shared_t's */
+H5FL_DEFINE(H5A_shared_t);
+
+/* Declare a free list to manage blocks of type conversion data */
+H5FL_BLK_DEFINE(attr_buf);
+
+/* Attribute ID class */
+static const H5I_class_t H5I_ATTR_CLS[1] = {{
+ H5I_ATTR, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5A_close /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5A_top_package_initialize_s = FALSE;
+
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5A__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5A__init_package()
+
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t
+H5A__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Create attribute ID type.
+ */
+ if(H5I_register_type(H5I_ATTR_CLS) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Mark "top" of interface as initialized, too */
+ H5A_top_package_initialize_s = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__init_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A_top_term_package
+ PURPOSE
+ Terminate various H5A objects
+ USAGE
+ void H5A_top_term_package()
+ RETURNS
+ DESCRIPTION
+ Release IDs for the atom group, deferring full interface shutdown
+ until later (in H5A_term_package).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5A_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5A_top_package_initialize_s) {
+ if(H5I_nmembers(H5I_ATTR) > 0) {
+ (void)H5I_clear_type(H5I_ATTR, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Mark closed */
+ if(0 == n)
+ H5A_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* H5A_top_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A_term_package
+ PURPOSE
+ Terminate various H5A objects
+ USAGE
+ void H5A_term_package()
+ RETURNS
+ DESCRIPTION
+ Release any other resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+
+ Finishes shutting down the interface, after H5A_top_term_package()
+ is called
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5A_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity checks */
+ HDassert(0 == H5I_nmembers(H5I_ATTR));
+ HDassert(FALSE == H5A_top_package_initialize_s);
+
+ /* Destroy the attribute object id group */
+ n += (H5I_dec_type_ref(H5I_ATTR) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* H5A_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Acreate2
+ PURPOSE
+ Creates an attribute on an object
+ USAGE
+ hid_t H5Acreate2(loc_id, attr_name, type_id, space_id, acpl_id,
+ aapl_id)
+ hid_t loc_id; IN: Object (dataset or group) to be attached to
+ const char *attr_name; IN: Name of attribute to locate and open
+ hid_t type_id; IN: ID of datatype for attribute
+ hid_t space_id; IN: ID of dataspace for attribute
+ hid_t acpl_id; IN: ID of creation property list (currently not used)
+ hid_t aapl_id; IN: Attribute access property list
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function creates an attribute which is attached to the object
+ specified with 'loc_id'. The name specified with 'attr_name' for
+ each attribute for an object must be unique for that object. The 'type_id'
+ and 'space_id' are created with the H5T and H5S interfaces respectively.
+ The 'aapl_id' property list is currently unused, but will be used in the
+ future for optional attribute access properties. The attribute ID returned
+ from this function must be released with H5Aclose or resource leaks will
+ develop.
+
+--------------------------------------------------------------------------*/
+hid_t
+H5Acreate2(hid_t loc_id, const char *attr_name, hid_t type_id, hid_t space_id,
+ hid_t acpl_id, hid_t aapl_id)
+{
+ H5A_t *attr = NULL; /* Attribute created */
+ H5G_loc_t loc; /* Object location */
+ H5T_t *type; /* Datatype to use for attribute */
+ H5S_t *space; /* Dataspace to use for attribute */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("i", "i*siiii", loc_id, attr_name, type_id, space_id, acpl_id, aapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(0 == (H5F_INTENT(loc.oloc->file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_ARGS, H5E_WRITEERROR, FAIL, "no write intent on file")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a type")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Go do the real work for attaching the attribute to the object */
+ if(NULL == (attr = H5A_create(&loc, attr_name, type, space, acpl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create attribute")
+
+ /* Register the new attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0 && attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Acreate2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Acreate_by_name
+ PURPOSE
+ Creates an attribute on an object
+ USAGE
+ hid_t H5Acreate_by_name(loc_id, obj_name, attr_name, type_id, space_id, acpl_id,
+ aapl_id, lapl_id)
+ hid_t loc_id; IN: Object (dataset or group) to be attached to
+ const char *obj_name; IN: Name of object relative to location
+ const char *attr_name; IN: Name of attribute to locate and open
+ hid_t type_id; IN: ID of datatype for attribute
+ hid_t space_id; IN: ID of dataspace for attribute
+ hid_t acpl_id; IN: ID of creation property list (currently not used)
+ hid_t aapl_id; IN: Attribute access property list
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function creates an attribute which is attached to the object
+ specified with 'loc_id/obj_name'. The name specified with 'attr_name' for
+ each attribute for an object must be unique for that object. The 'type_id'
+ and 'space_id' are created with the H5T and H5S interfaces respectively.
+ The 'aapl_id' property list is currently unused, but will be used in the
+ future for optional attribute access properties. The attribute ID returned
+ from this function must be released with H5Aclose or resource leaks will
+ develop.
+
+--------------------------------------------------------------------------*/
+hid_t
+H5Acreate_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ hid_t type_id, hid_t space_id, hid_t acpl_id, hid_t aapl_id,
+ hid_t lapl_id)
+{
+ H5A_t *attr = NULL; /* Attribute created */
+ H5G_loc_t loc; /* Object location */
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ H5T_t *type; /* Datatype to use for attribute */
+ H5S_t *space; /* Dataspace to use for attribute */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("i", "i*s*siiiii", loc_id, obj_name, attr_name, type_id, space_id,
+ acpl_id, aapl_id, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(0 == (H5F_INTENT(loc.oloc->file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_ARGS, H5E_WRITEERROR, FAIL, "no write intent on file")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a type")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Go do the real work for attaching the attribute to the dataset */
+ if(NULL == (attr = H5A_create(&obj_loc, attr_name, type, space, acpl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create attribute")
+
+ /* Register the new attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+ if(ret_value < 0 && attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Acreate_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aopen
+ PURPOSE
+ Opens an attribute for an object by looking up the attribute name
+ USAGE
+ hid_t H5Aopen(loc_id, attr_name, aapl_id)
+ hid_t loc_id; IN: Object that attribute is attached to
+ const char *attr_name; IN: Name of attribute to locate and open
+ hid_t aapl_id; IN: Attribute access property list
+ RETURNS
+ ID of attribute on success, negative on failure
+
+ DESCRIPTION
+ This function opens an existing attribute for access. The attribute
+ name specified is used to look up the corresponding attribute for the
+ object. The attribute ID returned from this function must be released with
+ H5Aclose or resource leaks will develop.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aopen(hid_t loc_id, const char *attr_name, hid_t aapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute opened */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*si", loc_id, attr_name, aapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Read in attribute from object header */
+ if(NULL == (attr = H5O_attr_open_by_name(loc.oloc, attr_name, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to load attribute info from object header for attribute: '%s'", attr_name)
+
+ /* Finish initializing attribute */
+ if(H5A__open_common(&loc, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to initialize attribute")
+
+ /* Register the attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aopen() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aopen_by_name
+ PURPOSE
+ Opens an attribute for an object by looking up the attribute name
+ USAGE
+ hid_t H5Aopen_by_name(loc_id, obj_name, attr_name, aapl_id, lapl_id)
+ hid_t loc_id; IN: Object that attribute is attached to
+ const char *obj_name; IN: Name of object relative to location
+ const char *attr_name; IN: Name of attribute to locate and open
+ hid_t aapl_id; IN: Attribute access property list
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ ID of attribute on success, negative on failure
+
+ DESCRIPTION
+ This function opens an existing attribute for access. The attribute
+ name specified is used to look up the corresponding attribute for the
+ object. The attribute ID returned from this function must be released with
+ H5Aclose or resource leaks will develop.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aopen_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ hid_t aapl_id, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute opened */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("i", "i*s*sii", loc_id, obj_name, attr_name, aapl_id, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+ if(H5P_DEFAULT == lapl_id)
+ lapl_id = H5P_LINK_ACCESS_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the attribute on the object header */
+ if(NULL == (attr = H5A_open_by_name(&loc, obj_name, attr_name, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute")
+
+ /* Register the attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aopen_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aopen_by_idx
+ PURPOSE
+ Opens the n'th attribute for an object, according to the order within
+ an index
+ USAGE
+ hid_t H5Aopen_by_idx(loc_id, obj_ame, idx_type, order, n, aapl_id, lapl_id)
+ hid_t loc_id; IN: Object that attribute is attached to
+ const char *obj_name; IN: Name of object relative to location
+ H5_index_t idx_type; IN: Type of index to use
+ H5_iter_order_t order; IN: Order to iterate over index
+ hsize_t n; IN: Index (0-based) attribute to open
+ hid_t aapl_id; IN: Attribute access property list
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ ID of attribute on success, negative on failure
+
+ DESCRIPTION
+ This function opens an existing attribute for access. The attribute
+ index specified is used to look up the corresponding attribute for the
+ object. The attribute ID returned from this function must be released with
+ H5Aclose or resource leaks will develop.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aopen_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t aapl_id, hid_t lapl_id)
+{
+ H5A_t *attr = NULL; /* Attribute opened */
+ H5G_loc_t loc; /* Object location */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("i", "i*sIiIohii", loc_id, obj_name, idx_type, order, n, aapl_id,
+ lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(H5P_DEFAULT == lapl_id)
+ lapl_id = H5P_LINK_ACCESS_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the attribute in the object header */
+ if(NULL == (attr = H5A_open_by_idx(&loc, obj_name, idx_type, order, n, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open attribute")
+
+ /* Register the attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aopen_by_idx() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Awrite
+ PURPOSE
+ Write out data to an attribute
+ USAGE
+ herr_t H5Awrite (attr_id, dtype_id, buf)
+ hid_t attr_id; IN: Attribute to write
+ hid_t dtype_id; IN: Memory datatype of buffer
+ const void *buf; IN: Buffer of data to write
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function writes a complete attribute to disk.
+--------------------------------------------------------------------------*/
+herr_t
+H5Awrite(hid_t attr_id, hid_t dtype_id, const void *buf)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ H5T_t *mem_type; /* Memory datatype */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t aapl_id = H5P_DEFAULT; /* temp access plist */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii*x", attr_id, dtype_id, buf);
+
+ /* check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+ if(NULL == (mem_type = (H5T_t *)H5I_object_verify(dtype_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(NULL == buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null attribute buffer")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, attr_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Go write the actual data to the attribute */
+ if((ret_value = H5A__write(attr, mem_type, buf, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "unable to write attribute")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Awrite() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aread
+ PURPOSE
+ Read in data from an attribute
+ USAGE
+ herr_t H5Aread (attr_id, dtype_id, buf)
+ hid_t attr_id; IN: Attribute to read
+ hid_t dtype_id; IN: Memory datatype of buffer
+ void *buf; IN: Buffer for data to read
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function reads a complete attribute from disk.
+--------------------------------------------------------------------------*/
+herr_t
+H5Aread(hid_t attr_id, hid_t dtype_id, void *buf)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ H5T_t *mem_type; /* Memory datatype */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t aapl_id = H5P_DEFAULT; /* temp access plist */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii*x", attr_id, dtype_id, buf);
+
+ /* check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+ if(NULL == (mem_type = (H5T_t *)H5I_object_verify(dtype_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(NULL == buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null attribute buffer")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&aapl_id, H5P_CLS_AACC, &dxpl_id, attr_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Go write the actual data to the attribute */
+ if((ret_value = H5A__read(attr, mem_type, buf, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_READERROR, FAIL, "unable to read attribute")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aread() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aget_space
+ PURPOSE
+ Gets a copy of the dataspace for an attribute
+ USAGE
+ hid_t H5Aget_space (attr_id)
+ hid_t attr_id; IN: Attribute to get dataspace of
+ RETURNS
+ A dataspace ID on success, negative on failure
+
+ DESCRIPTION
+ This function retrieves a copy of the dataspace for an attribute.
+ The dataspace ID returned from this function must be released with H5Sclose
+ or resource leaks will develop.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aget_space(hid_t attr_id)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ H5S_t *ds = NULL;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", attr_id);
+
+ /* check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ if(NULL == (ds = H5A_get_space(attr)))
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, FAIL, "can't get space ID of attribute")
+
+ /* Atomize */
+ if((ret_value = H5I_register(H5I_DATASPACE, ds, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ if(ret_value < 0) {
+ if(ds && (H5S_close(ds) < 0))
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aget_space() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aget_type
+ PURPOSE
+ Gets a copy of the datatype for an attribute
+ USAGE
+ hid_t H5Aget_type (attr_id)
+ hid_t attr_id; IN: Attribute to get datatype of
+ RETURNS
+ A datatype ID on success, negative on failure
+
+ DESCRIPTION
+ This function retrieves a copy of the datatype for an attribute.
+ The datatype ID returned from this function must be released with H5Tclose
+ or resource leaks will develop.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aget_type(hid_t attr_id)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ H5T_t *dt = NULL;
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", attr_id);
+
+ /* check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ if(NULL == (dt = H5A_get_type(attr)))
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, FAIL, "can't get space ID of attribute")
+
+ /* Create an atom */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ if(ret_value < 0) {
+ if(dt && (H5T_close(dt) < 0))
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aget_type() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aget_create_plist
+ PURPOSE
+ Gets a copy of the creation property list for an attribute
+ USAGE
+ hssize_t H5Aget_create_plist (attr_id, buf_size, buf)
+ hid_t attr_id; IN: Attribute to get name of
+ RETURNS
+ This function returns the ID of a copy of the attribute's creation
+ property list, or negative on failure.
+
+ ERRORS
+
+ DESCRIPTION
+ This function returns a copy of the creation property list for
+ an attribute. The resulting ID must be closed with H5Pclose() or
+ resource leaks will occur.
+--------------------------------------------------------------------------*/
+hid_t
+H5Aget_create_plist(hid_t attr_id)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", attr_id);
+
+ HDassert(H5P_LST_ATTRIBUTE_CREATE_ID_g != -1);
+
+ /* Get attribute and default attribute creation property list*/
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ if((ret_value = H5A_get_create_plist(attr)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, FAIL, "can't get creation property list for attr")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_create_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aget_name
+ PURPOSE
+ Gets a copy of the name for an attribute
+ USAGE
+ hssize_t H5Aget_name (attr_id, buf_size, buf)
+ hid_t attr_id; IN: Attribute to get name of
+ size_t buf_size; IN: The size of the buffer to store the string in.
+ char *buf; IN: Buffer to store name in
+ RETURNS
+ This function returns the length of the attribute's name (which may be
+ longer than 'buf_size') on success or negative for failure.
+
+ DESCRIPTION
+ This function retrieves the name of an attribute for an attribute ID.
+ Up to 'buf_size' characters are stored in 'buf' followed by a '\0' string
+ terminator. If the name of the attribute is longer than 'buf_size'-1,
+ the string terminator is stored in the last position of the buffer to
+ properly terminate the string.
+--------------------------------------------------------------------------*/
+ssize_t
+H5Aget_name(hid_t attr_id, size_t buf_size, char *buf)
+{
+ H5A_t *my_attr; /* Attribute object for ID */
+ ssize_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "iz*s", attr_id, buf_size, buf);
+
+ /* check arguments */
+ if(NULL == (my_attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+ if(!buf && buf_size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid buffer")
+
+ /* Call private function in turn */
+ if(0 > (ret_value = H5A__get_name(my_attr, buf_size, buf)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get attribute name")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aget_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aget_name_by_idx
+ *
+ * Purpose: Retrieve name of an attribute, according to the
+ * order within an index.
+ *
+ * Same pattern of behavior as H5Iget_name.
+ *
+ * Return: Success: Non-negative length of name, with information
+ * in NAME buffer
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Aget_name_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, char *name /*out*/, size_t size,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute object for name */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("Zs", "i*sIiIohxzi", loc_id, obj_name, idx_type, order, n, name, size,
+ lapl_id);
+
+ /* Check args */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the attribute on the object header */
+ if(NULL == (attr = H5A_open_by_idx(&loc, obj_name, idx_type, order, n, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute")
+
+ /* Get the length of the name */
+ ret_value = (ssize_t)HDstrlen(attr->shared->name);
+
+ /* Copy the name into the user's buffer, if given */
+ if(name) {
+ HDstrncpy(name, attr->shared->name, MIN((size_t)(ret_value + 1), size));
+ if((size_t)ret_value >= size)
+ name[size - 1]='\0';
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aget_storage_size
+ *
+ * Purpose: Returns the amount of storage size that is required for this
+ * attribute.
+ *
+ * Return: Success: The amount of storage size allocated for the
+ * attribute. The return value may be zero
+ * if no data has been stored.
+ *
+ * Failure: Zero
+ *
+ * Programmer: Raymond Lu
+ * October 23, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5Aget_storage_size(hid_t attr_id)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE1("h", "i", attr_id);
+
+ /* Check args */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not an attribute")
+
+ /* Set return value */
+ ret_value = attr->shared->data_size;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_storage_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aget_info
+ *
+ * Purpose: Retrieve information about an attribute.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Aget_info(hid_t attr_id, H5A_info_t *ainfo)
+{
+ H5A_t *attr; /* Attribute object for name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", attr_id, ainfo);
+
+ /* Check args */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ /* Get the attribute information */
+ if(H5A__get_info(attr, ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to get attribute info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aget_info_by_name
+ *
+ * Purpose: Retrieve information about an attribute by name.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Aget_info_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ H5A_info_t *ainfo, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute object for name */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*s*s*xi", loc_id, obj_name, attr_name, ainfo, lapl_id);
+
+ /* Check args */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+ if(NULL == ainfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid info pointer")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the attribute on the object header */
+ if(NULL == (attr = H5A_open_by_name(&loc, obj_name, attr_name, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute")
+
+ /* Get the attribute information */
+ if(H5A__get_info(attr, ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to get attribute info")
+
+done:
+ /* Cleanup on failure */
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_info_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aget_info_by_idx
+ *
+ * Purpose: Retrieve information about an attribute, according to the
+ * order within an index.
+ *
+ * Return: Success: Non-negative with information in AINFO
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Aget_info_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, H5A_info_t *ainfo, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute object for name */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIoh*xi", loc_id, obj_name, idx_type, order, n, ainfo,
+ lapl_id);
+
+ /* Check args */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(NULL == ainfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid info pointer")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the attribute on the object header */
+ if(NULL == (attr = H5A_open_by_idx(&loc, obj_name, idx_type, order, n, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute")
+
+ /* Get the attribute information */
+ if(H5A__get_info(attr, ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to get attribute info")
+
+done:
+ /* Release resources */
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Aget_info_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Arename
+ *
+ * Purpose: Rename an attribute
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * October 23, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Arename(hid_t loc_id, const char *old_name, const char *new_name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*s", loc_id, old_name, new_name);
+
+ /* check arguments */
+ if(!old_name || !new_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "name is nil")
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+
+ /* Avoid thrashing things if the names are the same */
+ if(HDstrcmp(old_name, new_name)) {
+ H5G_loc_t loc; /* Object location */
+
+ if(H5G_loc(loc_id, & loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Call private attribute rename routine */
+ if(H5O_attr_rename(loc.oloc, H5AC_ind_read_dxpl_id, old_name, new_name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRENAME, FAIL, "can't rename attribute")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Arename() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Arename_by_name
+ *
+ * Purpose: Rename an attribute
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Arename_by_name(hid_t loc_id, const char *obj_name, const char *old_attr_name,
+ const char *new_attr_name, hid_t lapl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*s*s*si", loc_id, obj_name, old_attr_name, new_attr_name,
+ lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!old_attr_name || !*old_attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no old attribute name")
+ if(!new_attr_name || !*new_attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new attribute name")
+
+ /* Avoid thrashing things if the names are the same */
+ if(HDstrcmp(old_attr_name, new_attr_name)) {
+ H5G_loc_t loc; /* Object location */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by the library */
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ if(H5G_loc(loc_id, & loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Call private attribute rename routine */
+ if(H5A_rename_by_name(loc, obj_name, old_attr_name, new_attr_name, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRENAME, FAIL, "can't rename attribute")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Arename_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aiterate2
+ PURPOSE
+ Calls a user's function for each attribute on an object
+ USAGE
+ herr_t H5Aiterate2(loc_id, idx_type, order, idx, op, op_data)
+ hid_t loc_id; IN: Base location for object
+ H5_index_t idx_type; IN: Type of index to use
+ H5_iter_order_t order; IN: Order to iterate over index
+ hsize_t *idx; IN/OUT: Starting (IN) & Ending (OUT) attribute
+ in index & order
+ H5A_operator2_t op; IN: User's function to pass each attribute to
+ void *op_data; IN/OUT: User's data to pass through to iterator
+ operator function
+ RETURNS
+ Returns a negative value if an error occurs, the return value of the
+ last operator if it was non-zero (which can be a negative value), or zero
+ if all attributes were processed.
+
+ DESCRIPTION
+ This function interates over the attributes of dataset or group
+ specified with 'loc_id' & 'obj_name'. For each attribute of the object,
+ the 'op_data' and some additional information (specified below) are passed
+ to the 'op' function. The iteration begins with the '*idx'
+ object in the group and the next attribute to be processed by the operator
+ is returned in '*idx'.
+ The operation receives the ID for the group or dataset being iterated
+ over ('loc_id'), the name of the current attribute about the object
+ ('attr_name'), the attribute's "info" struct ('ainfo') and the pointer to
+ the operator data passed in to H5Aiterate2 ('op_data'). The return values
+ from an operator are:
+ A. Zero causes the iterator to continue, returning zero when all
+ attributes have been processed.
+ B. Positive causes the iterator to immediately return that positive
+ value, indicating short-circuit success. The iterator can be
+ restarted at the next attribute.
+ C. Negative causes the iterator to immediately return that value,
+ indicating failure. The iterator can be restarted at the next
+ attribute.
+--------------------------------------------------------------------------*/
+herr_t
+H5Aiterate2(hid_t loc_id, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t *idx, H5A_operator2_t op, void *op_data)
+{
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+ hsize_t start_idx; /* Index of attribute to start iterating at */
+ hsize_t last_attr; /* Index of last attribute examined */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iIiIo*hx*x", loc_id, idx_type, order, idx, op, op_data);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Build attribute operator info */
+ attr_op.op_type = H5A_ATTR_OP_APP2;
+ attr_op.u.app_op2 = op;
+
+ /* Call attribute iteration routine */
+ last_attr = start_idx = (idx ? *idx : 0);
+ if((ret_value = H5O_attr_iterate(loc_id, H5AC_ind_read_dxpl_id, idx_type, order, start_idx, &last_attr, &attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+
+ /* Set the last attribute information */
+ if(idx)
+ *idx = last_attr;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aiterate2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aiterate_by_name
+ PURPOSE
+ Calls a user's function for each attribute on an object
+ USAGE
+ herr_t H5Aiterate2(loc_id, obj_name, idx_type, order, idx, op, op_data, lapl_id)
+ hid_t loc_id; IN: Base location for object
+ const char *obj_name; IN: Name of object relative to location
+ H5_index_t idx_type; IN: Type of index to use
+ H5_iter_order_t order; IN: Order to iterate over index
+ hsize_t *idx; IN/OUT: Starting (IN) & Ending (OUT) attribute
+ in index & order
+ H5A_operator2_t op; IN: User's function to pass each attribute to
+ void *op_data; IN/OUT: User's data to pass through to iterator
+ operator function
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ Returns a negative value if an error occurs, the return value of the
+ last operator if it was non-zero (which can be a negative value), or zero
+ if all attributes were processed.
+
+ DESCRIPTION
+ This function interates over the attributes of dataset or group
+ specified with 'loc_id' & 'obj_name'. For each attribute of the object,
+ the 'op_data' and some additional information (specified below) are passed
+ to the 'op' function. The iteration begins with the '*idx'
+ object in the group and the next attribute to be processed by the operator
+ is returned in '*idx'.
+ The operation receives the ID for the group or dataset being iterated
+ over ('loc_id'), the name of the current attribute about the object
+ ('attr_name'), the attribute's "info" struct ('ainfo') and the pointer to
+ the operator data passed in to H5Aiterate_by_name ('op_data'). The return values
+ from an operator are:
+ A. Zero causes the iterator to continue, returning zero when all
+ attributes have been processed.
+ B. Positive causes the iterator to immediately return that positive
+ value, indicating short-circuit success. The iterator can be
+ restarted at the next attribute.
+ C. Negative causes the iterator to immediately return that value,
+ indicating failure. The iterator can be restarted at the next
+ attribute.
+--------------------------------------------------------------------------*/
+herr_t
+H5Aiterate_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t *idx, H5A_operator2_t op, void *op_data,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ hid_t obj_loc_id = (-1); /* ID for object located */
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+ hsize_t start_idx; /* Index of attribute to start iterating at */
+ hsize_t last_attr; /* Index of last attribute examined */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("e", "i*sIiIo*hx*xi", loc_id, obj_name, idx_type, order, idx, op,
+ op_data, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Open the object */
+ if((obj_loc_id = H5O_open_by_loc(&obj_loc, lapl_id, dxpl_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+ /* Build attribute operator info */
+ attr_op.op_type = H5A_ATTR_OP_APP2;
+ attr_op.u.app_op2 = op;
+
+ /* Call attribute iteration routine */
+ last_attr = start_idx = (idx ? *idx : 0);
+ if((ret_value = H5O_attr_iterate(obj_loc_id, dxpl_id, idx_type, order, start_idx, &last_attr, &attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+
+ /* Set the last attribute information */
+ if(idx)
+ *idx = last_attr;
+
+done:
+ /* Release resources */
+ if(obj_loc_id > 0) {
+ if(H5I_dec_app_ref(obj_loc_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ } /* end if */
+ else if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aiterate_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Adelete
+ PURPOSE
+ Deletes an attribute from a location
+ USAGE
+ herr_t H5Adelete(loc_id, name)
+ hid_t loc_id; IN: Object (dataset or group) to have attribute deleted from
+ const char *name; IN: Name of attribute to delete
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function removes the named attribute from a dataset or group.
+--------------------------------------------------------------------------*/
+herr_t
+H5Adelete(hid_t loc_id, const char *name)
+{
+ H5G_loc_t loc; /* Object location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", loc_id, name);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Delete the attribute from the location */
+ if(H5O_attr_remove(loc.oloc, name, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Adelete() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Adelete_by_name
+ PURPOSE
+ Deletes an attribute from a location
+ USAGE
+ herr_t H5Adelete_by_name(loc_id, obj_name, attr_name, lapl_id)
+ hid_t loc_id; IN: Base location for object
+ const char *obj_name; IN: Name of object relative to location
+ const char *attr_name; IN: Name of attribute to delete
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function removes the named attribute from an object.
+--------------------------------------------------------------------------*/
+herr_t
+H5Adelete_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*s*si", loc_id, obj_name, attr_name, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Delete the attribute from the location */
+ if(H5O_attr_remove(obj_loc.oloc, attr_name, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Adelete_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Adelete_by_idx
+ PURPOSE
+ Deletes an attribute from a location, according to the order within an index
+ USAGE
+ herr_t H5Adelete_by_idx(loc_id, obj_name, idx_type, order, n, lapl_id)
+ hid_t loc_id; IN: Base location for object
+ const char *obj_name; IN: Name of object relative to location
+ H5_index_t idx_type; IN: Type of index to use
+ H5_iter_order_t order; IN: Order to iterate over index
+ hsize_t n; IN: Offset within index
+ hid_t lapl_id; IN: Link access property list
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function removes an attribute from an object, using the IDX_TYPE
+ index to delete the N'th attribute in ORDER direction in the index. The
+ object is specified relative to the LOC_ID with the OBJ_NAME path. To
+ remove an attribute on the object specified by LOC_ID, pass in "." for
+ OBJ_NAME. The link access property list, LAPL_ID, controls aspects of
+ the group hierarchy traversal when using the OBJ_NAME to locate the final
+ object to operate on.
+--------------------------------------------------------------------------*/
+herr_t
+H5Adelete_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*sIiIohi", loc_id, obj_name, idx_type, order, n, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Delete the attribute from the location */
+ if(H5O_attr_remove_by_idx(obj_loc.oloc, idx_type, order, n, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Adelete_by_idx() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aclose
+ PURPOSE
+ Close an attribute ID
+ USAGE
+ herr_t H5Aclose (attr_id)
+ hid_t attr_id; IN: Attribute to release access to
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function releases an attribute from use. Further use of the
+ attribute ID will result in undefined behavior.
+--------------------------------------------------------------------------*/
+herr_t
+H5Aclose(hid_t attr_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", attr_id);
+
+ /* check arguments */
+ if(NULL == H5I_object_verify(attr_id, H5I_ATTR))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ /* Decrement references to that atom (and close it) */
+ if(H5I_dec_app_ref(attr_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "can't close attribute")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aexists
+ *
+ * Purpose: Checks if an attribute with a given name exists on an opened
+ * object.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Aexists(hid_t obj_id, const char *attr_name)
+{
+ H5G_loc_t loc; /* Object location */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "i*s", obj_id, attr_name);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(obj_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+
+ /* Check if the attribute exists */
+ if((ret_value = H5O_attr_exists(loc.oloc, attr_name, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to determine if attribute exists")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aexists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Aexists_by_name
+ *
+ * Purpose: Checks if an attribute with a given name exists on an object.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Aexists_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Object location */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("t", "i*s*si", loc_id, obj_name, attr_name, lapl_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name")
+ if(!attr_name || !*attr_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ if((ret_value = H5A_exists_by_name(loc, obj_name, attr_name, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to determine if attribute exists")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aexists_by_name() */
+
diff --git a/src/H5AC.c b/src/H5AC.c
new file mode 100644
index 0000000..4223158
--- /dev/null
+++ b/src/H5AC.c
@@ -0,0 +1,3336 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5AC.c
+ * Jul 9 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Functions in this file implement a cache for
+ * things which exist on disk. All "things" associated
+ * with a particular HDF file share the same cache; each
+ * HDF file has it's own cache.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5ACmodule.h" /* This source code file is part of the H5AC module */
+#define H5F_FRIEND /* Suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata cache */
+#include "H5Cprivate.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SLprivate.h" /* Skip Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5AC__check_if_write_permitted(const H5F_t *f,
+ hbool_t *write_permitted_ptr);
+static herr_t H5AC__ext_config_2_int_config(H5AC_cache_config_t *ext_conf_ptr,
+ H5C_auto_size_ctl_t *int_conf_ptr);
+#if H5AC_DO_TAGGING_SANITY_CHECKS
+static herr_t H5AC__verify_tag(hid_t dxpl_id, const H5AC_class_t * type);
+#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Default dataset transfer property list for metadata I/O calls (coll write, ind read) */
+hid_t H5AC_ind_read_dxpl_id = (-1);
+#ifdef H5_HAVE_PARALLEL
+/* collective metadata read property */
+hid_t H5AC_coll_read_dxpl_id = (-1);
+#endif /* H5_HAVE_PARALLEL */
+
+/* DXPL to be used in operations that will not result in I/O calls */
+hid_t H5AC_noio_dxpl_id = (-1);
+
+/* Default DXPL to be used for raw data I/O operations when one is not
+ provided by the user (fill values in H5Dcreate) */
+hid_t H5AC_rawdata_dxpl_id = (-1);
+
+#ifdef H5_HAVE_PARALLEL
+/* Environment variable for collective API sanity checks */
+hbool_t H5_coll_api_sanity_check_g = false;
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Metadata entry class list */
+
+/* Remember to add new type ID to the H5AC_type_t enum in H5ACprivate.h when
+ * adding a new class.
+ */
+
+static const H5AC_class_t *const H5AC_class_s[] = {
+ H5AC_BT, /* ( 0) B-tree nodes */
+ H5AC_SNODE, /* ( 1) symbol table nodes */
+ H5AC_LHEAP_PRFX, /* ( 2) local heap prefix */
+ H5AC_LHEAP_DBLK, /* ( 3) local heap data block */
+ H5AC_GHEAP, /* ( 4) global heap */
+ H5AC_OHDR, /* ( 5) object header */
+ H5AC_OHDR_CHK, /* ( 6) object header chunk */
+ H5AC_BT2_HDR, /* ( 7) v2 B-tree header */
+ H5AC_BT2_INT, /* ( 8) v2 B-tree internal node */
+ H5AC_BT2_LEAF, /* ( 9) v2 B-tree leaf node */
+ H5AC_FHEAP_HDR, /* (10) fractal heap header */
+ H5AC_FHEAP_DBLOCK, /* (11) fractal heap direct block */
+ H5AC_FHEAP_IBLOCK, /* (12) fractal heap indirect block */
+ H5AC_FSPACE_HDR, /* (13) free space header */
+ H5AC_FSPACE_SINFO, /* (14) free space sections */
+ H5AC_SOHM_TABLE, /* (15) shared object header message master table */
+ H5AC_SOHM_LIST, /* (16) shared message index stored as a list */
+ H5AC_EARRAY_HDR, /* (17) extensible array header */
+ H5AC_EARRAY_IBLOCK, /* (18) extensible array index block */
+ H5AC_EARRAY_SBLOCK, /* (19) extensible array super block */
+ H5AC_EARRAY_DBLOCK, /* (20) extensible array data block */
+ H5AC_EARRAY_DBLK_PAGE, /* (21) extensible array data block page */
+ H5AC_FARRAY_HDR, /* (22) fixed array header */
+ H5AC_FARRAY_DBLOCK, /* (23) fixed array data block */
+ H5AC_FARRAY_DBLK_PAGE, /* (24) fixed array data block page */
+ H5AC_SUPERBLOCK, /* (25) file superblock */
+ H5AC_DRVRINFO, /* (26) driver info block (supplements superblock) */
+ H5AC_EPOCH_MARKER, /* (27) epoch marker - always internal to cache */
+ H5AC_PROXY_ENTRY, /* (28) cache entry proxy */
+ H5AC_PREFETCHED_ENTRY /* (29) prefetched entry - always internal to cache */
+};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_init
+ *
+ * Purpose: Initialize the interface from some other layer.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 18, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__init_package
+ *
+ * Purpose: Initialize interface-specific information
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 18, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__init_package(void)
+{
+#if defined H5_DEBUG_BUILD | defined H5_HAVE_PARALLEL
+ H5P_genplist_t *xfer_plist; /* Dataset transfer property list object */
+#endif /* defined H5_DEBUG_BUILD | defined H5_HAVE_PARALLEL */
+#ifdef H5_DEBUG_BUILD
+ H5FD_dxpl_type_t dxpl_type; /* Property indicating the type of the internal dxpl */
+#endif /* H5_DEBUG_BUILD */
+#ifdef H5_HAVE_PARALLEL
+ H5P_coll_md_read_flag_t coll_meta_read;
+#endif /* H5_HAVE_PARALLEL */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+#ifdef H5_HAVE_PARALLEL
+ /* check whether to enable strict collective function calling
+ sanity checks using MPI barriers */
+ {
+ const char *s; /* String for environment variables */
+
+ s = HDgetenv("H5_COLL_API_SANITY_CHECK");
+ if(s && HDisdigit(*s))
+ H5_coll_api_sanity_check_g = (hbool_t)HDstrtol(s, NULL, 0);
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+#if defined(H5_HAVE_PARALLEL) || defined(H5_DEBUG_BUILD)
+ /* Get an ID for the internal independent metadata dxpl */
+ if((H5AC_ind_read_dxpl_id = H5P_create_id(H5P_CLS_DATASET_XFER_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
+
+ /* Get an ID for the no I/O internal dxpl */
+ if((H5AC_noio_dxpl_id = H5P_create_id(H5P_CLS_DATASET_XFER_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
+
+ /* Get an ID for the raw data (H5AC) dxpl */
+ if((H5AC_rawdata_dxpl_id = H5P_create_id(H5P_CLS_DATASET_XFER_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
+
+ /* if this is a debug build, set the dxpl type flag on the
+ independent metadata dxpl and create the noio and raw data internal dxpls */
+#ifdef H5_DEBUG_BUILD
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+ /* Insert the dxpl type property */
+ dxpl_type = H5FD_METADATA_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't set dxpl type property")
+
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(H5AC_noio_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+ /* Insert the dxpl type property */
+ dxpl_type = H5FD_NOIO_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't set dxpl type property")
+
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+ /* Insert the dxpl type property */
+ dxpl_type = H5FD_RAWDATA_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't set dxpl type property")
+#endif /* H5_DEBUG_BUILD */
+
+ /* if this is a parallel build, create an internal dxpl for
+ collective metadata reads */
+#ifdef H5_HAVE_PARALLEL
+ /* Get an ID for H5AC_coll_read_dxpl_id */
+ if((H5AC_coll_read_dxpl_id = H5P_create_id(H5P_CLS_DATASET_XFER_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(H5AC_coll_read_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+ /* set 'collective metadata read' property */
+ coll_meta_read = H5P_USER_TRUE;
+ if(H5P_set(xfer_plist, H5_COLL_MD_READ_FLAG_NAME, &coll_meta_read) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set collective metadata read flag")
+
+ /* if we have a debug build, set the dxpl type to metadata on the
+ collective metadata dxpl */
+#ifdef H5_DEBUG_BUILD
+ /* set metadata dxpl type */
+ dxpl_type = H5FD_METADATA_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't set dxpl type property")
+#endif /* H5_DEBUG_BUILD */
+#endif /* H5_HAVE_PARALLEL */
+
+#else /* defined(H5_HAVE_PARALLEL) || defined(H5_DEBUG_BUILD) */
+ H5AC_ind_read_dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ H5AC_noio_dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ H5AC_rawdata_dxpl_id = H5P_DATASET_XFER_DEFAULT;
+#endif /* defined(H5_HAVE_PARALLEL) || defined(H5_DEBUG_BUILD) */
+
+#if defined(H5_DEBUG_BUILD) | defined(H5_HAVE_PARALLEL)
+done:
+#endif /* defined(H5_DEBUG_BUILD) | defined(H5_HAVE_PARALLEL) */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_term_package
+ *
+ * Purpose: Terminate this interface.
+ *
+ * Return: Success: Positive if anything was done that might
+ * affect other interfaces; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 18, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5AC_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ if(H5AC_ind_read_dxpl_id > 0 || H5AC_noio_dxpl_id > 0 || H5AC_rawdata_dxpl_id > 0
+#ifdef H5_HAVE_PARALLEL
+ || H5AC_coll_read_dxpl_id > 0
+#endif /* H5_HAVE_PARALLEL */
+ ) {
+#if defined(H5_HAVE_PARALLEL) || defined(H5_DEBUG_BUILD)
+ /* Indicate more work to do */
+ n = 1; /* H5I */
+
+ /* Close H5AC dxpls */
+ if(H5I_dec_ref(H5AC_ind_read_dxpl_id) < 0 ||
+ H5I_dec_ref(H5AC_noio_dxpl_id) < 0 ||
+ H5I_dec_ref(H5AC_rawdata_dxpl_id) < 0
+#ifdef H5_HAVE_PARALLEL
+ || H5I_dec_ref(H5AC_coll_read_dxpl_id) < 0
+#endif /* H5_HAVE_PARALLEL */
+ )
+ H5E_clear_stack(NULL); /*ignore error*/
+#endif /* defined(H5_HAVE_PARALLEL) || defined(H5_DEBUG_BUILD) */
+
+ /* Reset static IDs */
+ H5AC_ind_read_dxpl_id = (-1);
+ H5AC_noio_dxpl_id = (-1);
+ H5AC_rawdata_dxpl_id = (-1);
+#ifdef H5_HAVE_PARALLEL
+ H5AC_coll_read_dxpl_id = (-1);
+#endif /* H5_HAVE_PARALLEL */
+ } /* end if */
+
+ /* Reset interface initialization flag */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5AC_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_cache_image_pending()
+ *
+ * Purpose: Debugging function that tests to see if the load of a
+ * metadata cache image load is pending (i.e. will be executed
+ * on the next protect or insert)
+ *
+ * Returns TRUE if a cache image load is pending, and FALSE
+ * if not. Throws an assertion failure on error.
+ *
+ * Return: TRUE if a cache image load is pending, and FALSE otherwise.
+ *
+ * Programmer: John Mainzer, 1/10/17
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5AC_cache_image_pending(const H5F_t *f)
+{
+ H5C_t *cache_ptr;
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ ret_value = H5C_cache_image_pending(cache_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_cache_image_pending() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_create
+ *
+ * Purpose: Initialize the cache just after a file is opened. The
+ * SIZE_HINT is the number of cache slots desired. If you
+ * pass an invalid value then H5AC_NSLOTS is used. You can
+ * turn off caching by using 1 for the SIZE_HINT value.
+ *
+ * Return: Success: Number of slots actually used.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_create(const H5F_t *f, H5AC_cache_config_t *config_ptr, H5AC_cache_image_config_t * image_config_ptr)
+{
+#ifdef H5_HAVE_PARALLEL
+ char prefix[H5C__PREFIX_LEN] = "";
+ H5AC_aux_t * aux_ptr = NULL;
+#endif /* H5_HAVE_PARALLEL */
+ struct H5C_cache_image_ctl_t int_ci_config = H5C__DEFAULT_CACHE_IMAGE_CTL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(NULL == f->shared->cache);
+ HDassert(config_ptr != NULL) ;
+ HDassert(image_config_ptr != NULL) ;
+ HDassert(image_config_ptr->version == H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION);
+ HDcompile_assert(NELMTS(H5AC_class_s) == H5AC_NTYPES);
+ HDcompile_assert(H5C__MAX_NUM_TYPE_IDS == H5AC_NTYPES);
+
+ /* Validate configurations */
+ if(H5AC_validate_config(config_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache configuration")
+ if(H5AC_validate_cache_image_config(image_config_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache image configuration")
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ MPI_Comm mpi_comm;
+ int mpi_rank;
+ int mpi_size;
+
+ if(MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(f)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI communicator")
+
+ if((mpi_rank = H5F_mpi_get_rank(f)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi rank")
+
+ if((mpi_size = H5F_mpi_get_size(f)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi size")
+
+ if(NULL == (aux_ptr = H5FL_CALLOC(H5AC_aux_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate H5AC auxilary structure")
+
+ aux_ptr->magic = H5AC__H5AC_AUX_T_MAGIC;
+ aux_ptr->mpi_comm = mpi_comm;
+ aux_ptr->mpi_rank = mpi_rank;
+ aux_ptr->mpi_size = mpi_size;
+ aux_ptr->write_permitted = FALSE;
+ aux_ptr->dirty_bytes_threshold = H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD;
+ aux_ptr->dirty_bytes = 0;
+ aux_ptr->metadata_write_strategy = H5AC__DEFAULT_METADATA_WRITE_STRATEGY;
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->dirty_bytes_propagations = 0;
+ aux_ptr->unprotect_dirty_bytes = 0;
+ aux_ptr->unprotect_dirty_bytes_updates = 0;
+ aux_ptr->insert_dirty_bytes = 0;
+ aux_ptr->insert_dirty_bytes_updates = 0;
+ aux_ptr->move_dirty_bytes = 0;
+ aux_ptr->move_dirty_bytes_updates = 0;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+ aux_ptr->d_slist_ptr = NULL;
+ aux_ptr->c_slist_ptr = NULL;
+ aux_ptr->candidate_slist_ptr = NULL;
+ aux_ptr->write_done = NULL;
+ aux_ptr->sync_point_done = NULL;
+ aux_ptr->p0_image_len = 0;
+
+ sprintf(prefix, "%d:", mpi_rank);
+
+ if(mpi_rank == 0) {
+ if(NULL == (aux_ptr->d_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create dirtied entry list")
+
+ if(NULL == (aux_ptr->c_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cleaned entry list")
+ } /* end if */
+
+ /* construct the candidate slist for all processes.
+ * when the distributed strategy is selected as all processes
+ * will use it in the case of a flush.
+ */
+ if(NULL == (aux_ptr->candidate_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create candidate entry list")
+
+ if(aux_ptr != NULL)
+ if(aux_ptr->mpi_rank == 0)
+ f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
+ H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1),
+ H5AC_class_s,
+ H5AC__check_if_write_permitted, TRUE, H5AC__log_flushed_entry,
+ (void *)aux_ptr);
+ else
+ f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
+ H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1),
+ H5AC_class_s,
+ H5AC__check_if_write_permitted, TRUE, NULL,
+ (void *)aux_ptr);
+ else
+ f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
+ H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1),
+ H5AC_class_s,
+ H5AC__check_if_write_permitted, TRUE, NULL, NULL);
+ } /* end if */
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ /* The default max cache size and min clean size will frequently be
+ * overwritten shortly by the subsequent set resize config call.
+ * -- JRM
+ */
+ f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
+ H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1),
+ H5AC_class_s,
+ H5AC__check_if_write_permitted, TRUE, NULL, NULL);
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+
+ if(NULL == f->shared->cache)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+#ifdef H5_HAVE_PARALLEL
+ if(aux_ptr != NULL)
+ if(H5C_set_prefix(f->shared->cache, prefix) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "H5C_set_prefix() failed")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Turn on metadata cache logging, if being used */
+ if(H5F_USE_MDC_LOGGING(f)) {
+ if(H5C_set_up_logging(f->shared->cache, H5F_MDC_LOG_LOCATION(f), H5F_START_MDC_LOG_ON_ACCESS(f)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINIT, FAIL, "mdc logging setup failed")
+
+ /* Write the log header regardless of current logging status */
+ if(H5AC__write_create_cache_log_msg(f->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+ } /* end if */
+
+ /* Set the cache parameters */
+ if(H5AC_set_cache_auto_resize_config(f->shared->cache, config_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "auto resize configuration failed")
+
+ /* Don't need to get the current H5C image config here since the
+ * cache has just been created, and thus f->shared->cache->image_ctl
+ * must still set to its initial value (H5C__DEFAULT_CACHE_IMAGE_CTL).
+ * Note that this not true as soon as control returns to the application
+ * program, as some test code modifies f->shared->cache->image_ctl.
+ */
+ int_ci_config.version = image_config_ptr->version;
+ int_ci_config.generate_image = image_config_ptr->generate_image;
+ int_ci_config.save_resize_status = image_config_ptr->save_resize_status;
+ int_ci_config.entry_ageout = image_config_ptr->entry_ageout;
+ if(H5C_set_cache_image_config(f, f->shared->cache, &int_ci_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "auto resize configuration failed")
+
+done:
+#ifdef H5_HAVE_PARALLEL
+ /* if there is a failure, try to tidy up the auxilary structure */
+ if(ret_value < 0) {
+ if(aux_ptr != NULL) {
+ if(aux_ptr->d_slist_ptr != NULL)
+ H5SL_close(aux_ptr->d_slist_ptr);
+ if(aux_ptr->c_slist_ptr != NULL)
+ H5SL_close(aux_ptr->c_slist_ptr);
+ if(aux_ptr->candidate_slist_ptr != NULL)
+ H5SL_close(aux_ptr->candidate_slist_ptr);
+ aux_ptr->magic = 0;
+ aux_ptr = H5FL_FREE(H5AC_aux_t, aux_ptr);
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_dest
+ *
+ * Purpose: Flushes all data to disk and destroys the cache.
+ * This function fails if any object are protected since the
+ * resulting file might not be consistent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_dest(H5F_t *f, hid_t dxpl_id)
+{
+#ifdef H5_HAVE_PARALLEL
+ H5AC_aux_t * aux_ptr = NULL;
+#endif /* H5_HAVE_PARALLEL */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+#if H5AC_DUMP_STATS_ON_CLOSE
+ /* Dump debugging info */
+ H5AC_stats(f);
+#endif /* H5AC_DUMP_STATS_ON_CLOSE */
+
+#if H5AC__TRACE_FILE_ENABLED
+ if(H5AC__close_trace_file(f->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__close_trace_file() failed")
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ if(H5F_USE_MDC_LOGGING(f)) {
+ /* Write the log footer regardless of current logging status */
+ if(H5AC__write_destroy_cache_log_msg(f->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+ if(H5C_tear_down_logging(f->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "mdc logging tear-down failed")
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ /* destroying the cache, so clear all collective entries */
+ if(H5C_clear_coll_entries(f->shared->cache, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_clear_coll_entries() failed")
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache);
+ if(aux_ptr)
+ /* Sanity check */
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ /* If the file was opened R/W, attempt to flush all entries
+ * from rank 0 & Bcast clean list to other ranks.
+ *
+ * Must not flush in the R/O case, as this will trigger the
+ * free space manager settle routines.
+ */
+ if ( ( H5F_ACC_RDWR & H5F_INTENT(f) ) &&
+ ( H5AC__flush_entries(f, dxpl_id) < 0 ) )
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush")
+
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Destroy the cache */
+ if(H5C_dest(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't destroy cache")
+ f->shared->cache = NULL;
+
+#ifdef H5_HAVE_PARALLEL
+ if(aux_ptr != NULL) {
+ if(aux_ptr->d_slist_ptr != NULL) {
+ HDassert(H5SL_count(aux_ptr->d_slist_ptr) == 0);
+ H5SL_close(aux_ptr->d_slist_ptr);
+ } /* end if */
+ if(aux_ptr->c_slist_ptr != NULL) {
+ HDassert(H5SL_count(aux_ptr->c_slist_ptr) == 0);
+ H5SL_close(aux_ptr->c_slist_ptr);
+ } /* end if */
+ if(aux_ptr->candidate_slist_ptr != NULL) {
+ HDassert(H5SL_count(aux_ptr->candidate_slist_ptr) == 0);
+ H5SL_close(aux_ptr->candidate_slist_ptr);
+ } /* end if */
+ aux_ptr->magic = 0;
+ aux_ptr = H5FL_FREE(H5AC_aux_t, aux_ptr);
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_evict
+ *
+ * Purpose: Evict all entries except the pinned entries
+ * in the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_evict(H5F_t *f, hid_t dxpl_id)
+{
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Evict all entries in the cache except the pinned superblock entry */
+ if(H5C_evict(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't evict cache")
+
+done:
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_evict_cache_log_msg(f->shared->cache, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_evict() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_expunge_entry
+ *
+ * Purpose: Expunge the target entry from the cache without writing it
+ * to disk even if it is dirty. The entry must not be either
+ * pinned or protected.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/30/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type,
+ haddr_t addr, unsigned flags)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(type->serialize);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#if H5AC__TRACE_FILE_ENABLED
+{
+ H5AC_t * cache_ptr = f->shared->cache;
+
+ /* For the expunge entry call, only the addr, and type id are really
+ * necessary in the trace file. Write the return value to catch occult
+ * errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s 0x%lx %d", FUNC, (unsigned long)addr, (int)(type->id));
+}
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ if(H5C_expunge_entry(f, dxpl_id, type, addr, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "H5C_expunge_entry() failed")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_expunge_entry_log_msg(f->shared->cache, addr, type->id, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_expunge_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_flush
+ *
+ * Purpose: Flush (and possibly destroy) the metadata cache associated
+ * with the specified file.
+ *
+ * If the cache contains protected entries, the function will
+ * fail, as protected entries cannot be flushed. However
+ * all unprotected entries should be flushed before the
+ * function returns failure.
+ *
+ * Return: Non-negative on success/Negative on failure if there was a
+ * request to flush all items and something was protected.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_flush(H5F_t *f, hid_t dxpl_id)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the flush, only the flags are really necessary in the trace file.
+ * Write the result to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s", FUNC);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+#ifdef H5_HAVE_PARALLEL
+ /* flushing the cache, so clear all collective entries */
+ if(H5C_clear_coll_entries(f->shared->cache, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_clear_coll_entries() failed")
+
+ /* Attempt to flush all entries from rank 0 & Bcast clean list to other ranks */
+ if(H5AC__flush_entries(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Flush the cache */
+ /* (Again, in parallel - writes out the superblock) */
+ if(H5C_flush_cache(f, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_flush_cache_log_msg(f->shared->cache, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_force_cache_image_load()
+ *
+ * Purpose: On rare occasions, it is necessary to run
+ * H5MF_tidy_self_referential_fsm_hack() prior to the first
+ * metadata cache access. This is a problem as if there is a
+ * cache image at the end of the file, that routine will
+ * discard it.
+ *
+ * We solve this issue by calling this function, which will
+ * load the cache image and then call
+ * H5MF_tidy_self_referential_fsm_hack() to discard it.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 1/11/17
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_force_cache_image_load(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ if(H5C_force_cache_image_load(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "Can't load cache image")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_force_cache_image_load() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_entry_status
+ *
+ * Purpose: Given a file address, determine whether the metadata
+ * cache contains an entry at that location. If it does,
+ * also determine whether the entry is dirty, protected,
+ * pinned, etc. and return that information to the caller
+ * in *status.
+ *
+ * If the specified entry doesn't exist, set *status_ptr
+ * to zero.
+ *
+ * On error, the value of *status is undefined.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/27/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_entry_status(const H5F_t *f, haddr_t addr, unsigned *status)
+{
+ hbool_t in_cache; /* Entry @ addr is in the cache */
+ hbool_t is_dirty; /* Entry @ addr is in the cache and dirty */
+ hbool_t is_protected; /* Entry @ addr is in the cache and protected */
+ hbool_t is_pinned; /* Entry @ addr is in the cache and pinned */
+ hbool_t is_corked;
+ hbool_t is_flush_dep_child; /* Entry @ addr is in the cache and is a flush dependency child */
+ hbool_t is_flush_dep_parent; /* Entry @ addr is in the cache and is a flush dependency parent */
+ hbool_t image_is_up_to_date; /* Entry @ addr is in the cache and has an up to date image */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((f == NULL) || (!H5F_addr_defined(addr)) || (status == NULL))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad param(s) on entry")
+
+ if(H5C_get_entry_status(f, addr, NULL, &in_cache, &is_dirty,
+ &is_protected, &is_pinned, &is_corked, &is_flush_dep_parent, &is_flush_dep_child, &image_is_up_to_date) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_entry_status() failed")
+
+ if(in_cache) {
+ *status |= H5AC_ES__IN_CACHE;
+ if(is_dirty)
+ *status |= H5AC_ES__IS_DIRTY;
+ if(is_protected)
+ *status |= H5AC_ES__IS_PROTECTED;
+ if(is_pinned)
+ *status |= H5AC_ES__IS_PINNED;
+ if(is_corked)
+ *status |= H5AC_ES__IS_CORKED;
+ if(is_flush_dep_parent)
+ *status |= H5AC_ES__IS_FLUSH_DEP_PARENT;
+ if(is_flush_dep_child)
+ *status |= H5AC_ES__IS_FLUSH_DEP_CHILD;
+ if(image_is_up_to_date)
+ *status |= H5AC_ES__IMAGE_IS_UP_TO_DATE;
+ } /* end if */
+ else
+ *status = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_entry_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_insert_entry
+ *
+ * Purpose: Adds the specified thing to the cache. The thing need not
+ * exist on disk yet, but it must have an address and disk
+ * space reserved.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr,
+ void *thing, unsigned int flags)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ size_t trace_entry_size = 0;
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(type->serialize);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(thing);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Check for invalid access request */
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "no write intent on file")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the insert, only the addr, size, type id and flags are really
+ * necessary in the trace file. Write the result to catch occult
+ * errors.
+ *
+ * Note that some data is not available right now -- put what we can
+ * in the trace buffer now, and fill in the rest at the end.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s 0x%lx %d 0x%x", FUNC, (unsigned long)addr, type->id,
+ flags);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+#if H5AC_DO_TAGGING_SANITY_CHECKS
+ if(!H5C_get_ignore_tags(f->shared->cache) && H5AC__verify_tag(dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Bad tag value")
+#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */
+
+ /* Insert entry into metadata cache */
+ if(H5C_insert_entry(f, dxpl_id, type, addr, thing, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C_insert_entry() failed")
+
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ /* make note of the entry size */
+ trace_entry_size = ((H5C_cache_entry_t *)thing)->size;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ if(NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache))) {
+ /* Log the new entry */
+ if(H5AC__log_inserted_entry((H5AC_info_t *)thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5AC__log_inserted_entry() failed")
+
+ /* Check if we should try to flush */
+ if(aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold)
+ if(H5AC__run_sync_point(f, dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point")
+ } /* end if */
+}
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d %d\n", trace, (int)trace_entry_size, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_insert_entry_log_msg(f->shared->cache, addr, type->id, flags, ((H5C_cache_entry_t *)thing)->size, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_load_cache_image_on_next_protect
+ *
+ * Purpose: Load the cache image block at the specified location,
+ * decode it, and insert its contents into the metadata
+ * cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_load_cache_image_on_next_protect(H5F_t * f, haddr_t addr, hsize_t len,
+ hbool_t rw)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ if(H5C_load_cache_image_on_next_protect(f, addr, len, rw) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "call to H5C_load_cache_image_on_next_protect failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_load_cache_image_on_next_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_mark_entry_dirty
+ *
+ * Purpose: Mark a pinned or protected entry as dirty. The target
+ * entry MUST be either pinned, protected, or both.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/16/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_mark_entry_dirty(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+ /* Set up entry & cache pointers */
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the mark pinned or protected entry dirty call, only the addr
+ * is really necessary in the trace file. Write the result to catch
+ * occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC, (unsigned long)(entry_ptr->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if((!entry_ptr->is_dirty) && (!entry_ptr->is_protected) &&
+ (entry_ptr->is_pinned) && (NULL != aux_ptr))
+ if(H5AC__log_dirtied_entry(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry")
+}
+#endif /* H5_HAVE_PARALLEL */
+
+ if(H5C_mark_entry_dirty(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't mark pinned or protected entry dirty")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_mark_dirty_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_mark_entry_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_mark_entry_clean
+ *
+ * Purpose: Mark a pinned entry as dirty. The target
+ * entry MUST be pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 7/23/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_mark_entry_clean(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the mark pinned or protected entry clean call, only the addr
+ * is really necessary in the trace file. Write the result to catch
+ * occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if((!entry_ptr->is_dirty) && (!entry_ptr->is_protected) &&
+ (entry_ptr->is_pinned) && (NULL != aux_ptr))
+ if(H5AC__log_cleaned_entry(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "can't log cleaned entry")
+}
+#endif /* H5_HAVE_PARALLEL */
+
+ if(H5C_mark_entry_clean(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "can't mark pinned or protected entry clean")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_mark_clean_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_mark_entry_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_mark_entry_unserialized
+ *
+ * Purpose: Mark a pinned or protected entry as unserialized. The target
+ * entry MUST be either pinned, protected, or both.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 12/22/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_mark_entry_unserialized(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+ /* Set up entry & cache pointers */
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the mark entry unserialized call, only the addr
+ * is really necessary in the trace file. Write the result to catch
+ * occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC, (unsigned long)(entry_ptr->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "unable to get logging status")
+
+ if(H5C_mark_entry_unserialized(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKUNSERIALIZED, FAIL, "can't mark entry unserialized")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_mark_unserialized_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_mark_entry_unserialized() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_mark_entry_serialized
+ *
+ * Purpose: Mark a pinned entry as serialized. The target
+ * entry MUST be pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 12/22/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_mark_entry_serialized(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the mark entry serializedn call, only the addr
+ * is really necessary in the trace file. Write the result to catch
+ * occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "unable to get logging status")
+
+ if(H5C_mark_entry_serialized(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "can't mark entry serialized")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_mark_serialized_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_mark_entry_serialized() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_move_entry
+ *
+ * Purpose: Use this function to notify the cache that an object's
+ * file address changed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_move_entry(H5F_t *f, const H5AC_class_t *type, haddr_t old_addr,
+ haddr_t new_addr, hid_t
+#ifndef H5_HAVE_PARALLEL
+H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ dxpl_id)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+#ifdef H5_HAVE_PARALLEL
+ H5AC_aux_t *aux_ptr;
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(H5F_addr_defined(old_addr));
+ HDassert(H5F_addr_defined(new_addr));
+ HDassert(H5F_addr_ne(old_addr, new_addr));
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the move call, only the old addr and new addr are really
+ * necessary in the trace file. Include the type id so we don't have to
+ * look it up. Also write the result to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s 0x%lx 0x%lx %d", FUNC, (unsigned long)old_addr,
+ (unsigned long)new_addr, (int)(type->id));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Log moving the entry */
+ if(NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache)))
+ if(H5AC__log_moved_entry(f, old_addr, new_addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log moved entry")
+#endif /* H5_HAVE_PARALLEL */
+
+ if(H5C_move_entry(f->shared->cache, type, old_addr, new_addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "H5C_move_entry() failed")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check if we should try to flush */
+ if(NULL != aux_ptr && aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold)
+ if(H5AC__run_sync_point(f, dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point")
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_move_entry_log_msg(f->shared->cache, old_addr, new_addr, type->id, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_move_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_pin_protected_entry()
+ *
+ * Purpose: Pin a protected cache entry. The entry must be protected
+ * at the time of call, and must be unpinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/27/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_pin_protected_entry(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the pin protected entry call, only the addr is really necessary
+ * in the trace file. Also write the result to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Pin entry */
+ if(H5C_pin_protected_entry(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "can't pin entry")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_pin_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_pin_protected_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_prep_for_file_close
+ *
+ * Purpose: This function should be called just prior to the cache
+ * flushes at file close.
+ *
+ * The objective of the call is to allow the metadata cache
+ * to do any preparatory work prior to generation of a
+ * cache image.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/3/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_prep_for_file_close(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ if(H5C_prep_for_file_close(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cache prep for file close failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_prep_for_file_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_create_flush_dependency()
+ *
+ * Purpose: Create a flush dependency between two entries in the metadata
+ * cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/24/09
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_create_flush_dependency(void * parent_thing, void * child_thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(parent_thing);
+ HDassert(child_thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(parent_thing)))
+ sprintf(trace, "%s %lx %lx", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)parent_thing)->addr),
+ (unsigned long)(((H5C_cache_entry_t *)child_thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)parent_thing;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Create the flush dependency */
+ if(H5C_create_flush_dependency(parent_thing, child_thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "H5C_create_flush_dependency() failed")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_create_fd_log_msg(cache_ptr, (H5AC_info_t *)parent_thing, (H5AC_info_t *)child_thing, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_create_flush_dependency() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_protect
+ *
+ * Purpose: If the target entry is not in the cache, load it. If
+ * necessary, attempt to evict one or more entries to keep
+ * the cache within its maximum size.
+ *
+ * Mark the target entry as protected, and return its address
+ * to the caller. The caller must call H5AC_unprotect() when
+ * finished with the entry.
+ *
+ * While it is protected, the entry may not be either evicted
+ * or flushed -- nor may it be accessed by another call to
+ * H5AC_protect. Any attempt to do so will result in a failure.
+ *
+ * Return: Success: Ptr to the object.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Sep 2 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr,
+ void *udata, unsigned flags)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ size_t trace_entry_size = 0;
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ void * thing = NULL; /* Pointer to native data structure for entry */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(type->serialize);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "unable to get logging status")
+
+ /* Check for unexpected flags -- H5C__FLUSH_COLLECTIVELY_FLAG
+ * only permitted in the parallel case.
+ */
+#ifdef H5_HAVE_PARALLEL
+ HDassert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | \
+ H5C__FLUSH_LAST_FLAG | \
+ H5C__FLUSH_COLLECTIVELY_FLAG))));
+#else /* H5_HAVE_PARALLEL */
+ HDassert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | \
+ H5C__FLUSH_LAST_FLAG))));
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Check for invalid access request */
+ if((0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) && (0 == (flags & H5C__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "no write intent on file")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the protect call, only the addr, size, type id, and flags are
+ * necessary in the trace file. Also indicate whether the call was
+ * successful to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s 0x%lx %d 0x%x", FUNC, (unsigned long)addr,
+ (int)(type->id), flags);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+#if H5AC_DO_TAGGING_SANITY_CHECKS
+ if(!H5C_get_ignore_tags(f->shared->cache) && H5AC__verify_tag(dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Bad tag value")
+#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */
+
+ if(NULL == (thing = H5C_protect(f, dxpl_id, type, addr, udata, flags)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C_protect() failed")
+
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ /* Make note of the entry size */
+ trace_entry_size = ((H5C_cache_entry_t *)thing)->size;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* Set return value */
+ ret_value = thing;
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d %d\n", trace, (int)trace_entry_size, (int)(ret_value != NULL));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging) {
+ herr_t fake_ret_value = (NULL == ret_value) ? FAIL : SUCCEED;
+
+ if(H5AC__write_protect_entry_log_msg(f->shared->cache, (H5AC_info_t *)thing, flags, fake_ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, NULL, "unable to emit log message")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_resize_entry
+ *
+ * Purpose: Resize a pinned or protected entry.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/5/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_resize_entry(void *thing, size_t new_size)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the resize pinned entry call, only the addr, and new_size are
+ * really necessary in the trace file. Write the result to catch
+ * occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx %d", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)thing)->addr),
+ (int)new_size);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Resize the entry */
+ if(H5C_resize_entry(thing, new_size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, "can't resize entry")
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if((!entry_ptr->is_dirty) && (NULL != aux_ptr))
+ if(H5AC__log_dirtied_entry(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry")
+}
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_resize_entry_log_msg(cache_ptr, entry_ptr, new_size, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_resize_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_unpin_entry()
+ *
+ * Purpose: Unpin a cache entry. The entry must be unprotected at
+ * the time of call, and must be pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/11/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_unpin_entry(void *thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the unpin entry call, only the addr is really necessary
+ * in the trace file. Also write the result to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(thing)))
+ sprintf(trace, "%s 0x%lx", FUNC,
+ (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)thing;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Unpin the entry */
+ if(H5C_unpin_entry(thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "can't unpin entry")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_unpin_entry_log_msg(cache_ptr, entry_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_unpin_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_destroy_flush_dependency()
+ *
+ * Purpose: Destroy a flush dependency between two entries.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/24/09
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_destroy_flush_dependency(void * parent_thing, void * child_thing)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */
+ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(parent_thing);
+ HDassert(child_thing);
+
+#if H5AC__TRACE_FILE_ENABLED
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(parent_thing)))
+ sprintf(trace, "%s %llx %llx", FUNC,
+ (unsigned long long)(((H5C_cache_entry_t *)parent_thing)->addr),
+ (unsigned long long)(((H5C_cache_entry_t *)child_thing)->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ entry_ptr = (H5AC_info_t *)parent_thing;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Destroy the flush dependency */
+ if(H5C_destroy_flush_dependency(parent_thing, child_thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "H5C_destroy_flush_dependency() failed")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_destroy_fd_log_msg(cache_ptr, (H5AC_info_t *)parent_thing, (H5AC_info_t *)child_thing, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_destroy_flush_dependency() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_unprotect
+ *
+ * Purpose: Undo an H5AC_protect() call -- specifically, mark the
+ * entry as unprotected, remove it from the protected list,
+ * and give it back to the replacement policy.
+ *
+ * The TYPE and ADDR arguments must be the same as those in
+ * the corresponding call to H5AC_protect() and the THING
+ * argument must be the value returned by that call to
+ * H5AC_protect().
+ *
+ * If the deleted flag is TRUE, simply remove the target entry
+ * from the cache, clear it, and free it without writing it to
+ * disk.
+ *
+ * This verion of the function is a complete re-write to
+ * use the new metadata cache. While there isn't all that
+ * much difference between the old and new Purpose sections,
+ * the original version is given below.
+ *
+ * Original purpose section:
+ *
+ * This function should be called to undo the effect of
+ * H5AC_protect(). The TYPE and ADDR arguments should be the
+ * same as the corresponding call to H5AC_protect() and the
+ * THING argument should be the value returned by H5AC_protect().
+ * If the DELETED flag is set, then this object has been deleted
+ * from the file and should not be returned to the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Sep 2 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr,
+ void *thing, unsigned flags)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t dirtied;
+ hbool_t deleted;
+#ifdef H5_HAVE_PARALLEL
+ H5AC_aux_t * aux_ptr = NULL;
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(type->deserialize);
+ HDassert(type->image_len);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(thing);
+ HDassert( ((H5AC_info_t *)thing)->addr == addr );
+ HDassert( ((H5AC_info_t *)thing)->type == type );
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the unprotect call, only the addr, type id, flags, and possible
+ * new size are really necessary in the trace file. Write the return
+ * value to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ sprintf(trace, "%s 0x%lx %d", FUNC, (unsigned long)addr, (int)(type->id));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ dirtied = (hbool_t)(((flags & H5AC__DIRTIED_FLAG) == H5AC__DIRTIED_FLAG) ||
+ (((H5AC_info_t *)thing)->dirtied));
+ deleted = (hbool_t)((flags & H5C__DELETED_FLAG) == H5C__DELETED_FLAG);
+
+ /* Check if the size changed out from underneath us, if we're not deleting
+ * the entry.
+ */
+ if(dirtied && !deleted) {
+ size_t curr_size = 0;
+
+ if((type->image_len)(thing, &curr_size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGETSIZE, FAIL, "Can't get size of thing")
+
+ if(((H5AC_info_t *)thing)->size != curr_size)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, FAIL, "size of entry changed")
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ if(NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache))) {
+ if(dirtied && ((H5AC_info_t *)thing)->is_dirty == FALSE)
+ if(H5AC__log_dirtied_entry((H5AC_info_t *)thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log dirtied entry")
+
+ if(deleted && aux_ptr->mpi_rank == 0)
+ if(H5AC__log_deleted_entry((H5AC_info_t *)thing) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5AC__log_deleted_entry() failed")
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ if(H5C_unprotect(f, dxpl_id, addr, thing, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5C_unprotect() failed")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check if we should try to flush */
+ if((aux_ptr != NULL) && (aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold))
+ if(H5AC__run_sync_point(f, dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point")
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr != NULL)
+ HDfprintf(trace_file_ptr, "%s 0x%x %d\n", trace, (unsigned)flags, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_unprotect_entry_log_msg(f->shared->cache, (H5AC_info_t *)thing, type->id, flags, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_cache_auto_resize_config
+ *
+ * Purpose: Wrapper function for H5C_get_cache_auto_resize_config().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 3/10/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_cache_auto_resize_config(const H5AC_t *cache_ptr,
+ H5AC_cache_config_t *config_ptr)
+{
+ H5C_auto_size_ctl_t internal_config;
+ hbool_t evictions_enabled;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if((cache_ptr == NULL) || (config_ptr == NULL) ||
+ (config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr or config_ptr on entry")
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if((aux_ptr != NULL) && (aux_ptr->magic != H5AC__H5AC_AUX_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad aux_ptr on entry")
+}
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Retrieve the configuration */
+ if(H5C_get_cache_auto_resize_config((const H5C_t *)cache_ptr, &internal_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_auto_resize_config() failed")
+ if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_resize_enabled() failed")
+
+ /* Set the information to return */
+ if(internal_config.rpt_fcn == NULL)
+ config_ptr->rpt_fcn_enabled = FALSE;
+ else
+ config_ptr->rpt_fcn_enabled = TRUE;
+ config_ptr->open_trace_file = FALSE;
+ config_ptr->close_trace_file = FALSE;
+ config_ptr->trace_file_name[0] = '\0';
+ config_ptr->evictions_enabled = evictions_enabled;
+ config_ptr->set_initial_size = internal_config.set_initial_size;
+ config_ptr->initial_size = internal_config.initial_size;
+ config_ptr->min_clean_fraction = internal_config.min_clean_fraction;
+ config_ptr->max_size = internal_config.max_size;
+ config_ptr->min_size = internal_config.min_size;
+ config_ptr->epoch_length = (long)(internal_config.epoch_length);
+ config_ptr->incr_mode = internal_config.incr_mode;
+ config_ptr->lower_hr_threshold = internal_config.lower_hr_threshold;
+ config_ptr->increment = internal_config.increment;
+ config_ptr->apply_max_increment = internal_config.apply_max_increment;
+ config_ptr->max_increment = internal_config.max_increment;
+ config_ptr->decr_mode = internal_config.decr_mode;
+ config_ptr->upper_hr_threshold = internal_config.upper_hr_threshold;
+ config_ptr->flash_incr_mode = internal_config.flash_incr_mode;
+ config_ptr->flash_multiple = internal_config.flash_multiple;
+ config_ptr->flash_threshold = internal_config.flash_threshold;
+ config_ptr->decrement = internal_config.decrement;
+ config_ptr->apply_max_decrement = internal_config.apply_max_decrement;
+ config_ptr->max_decrement = internal_config.max_decrement;
+ config_ptr->epochs_before_eviction = (int)(internal_config.epochs_before_eviction);
+ config_ptr->apply_empty_reserve = internal_config.apply_empty_reserve;
+ config_ptr->empty_reserve = internal_config.empty_reserve;
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ if(NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr))) {
+ config_ptr->dirty_bytes_threshold = aux_ptr->dirty_bytes_threshold;
+ config_ptr->metadata_write_strategy = aux_ptr->metadata_write_strategy;
+ } /* end if */
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ config_ptr->dirty_bytes_threshold = H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD;
+ config_ptr->metadata_write_strategy = H5AC__DEFAULT_METADATA_WRITE_STRATEGY;
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+}
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_cache_auto_resize_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_cache_size
+ *
+ * Purpose: Wrapper function for H5C_get_cache_size().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 3/11/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_cache_size(H5AC_t *cache_ptr, size_t *max_size_ptr, size_t *min_clean_size_ptr,
+ size_t *cur_size_ptr, uint32_t *cur_num_entries_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5C_get_cache_size((H5C_t *)cache_ptr, max_size_ptr, min_clean_size_ptr,
+ cur_size_ptr, cur_num_entries_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_size() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_cache_hit_rate
+ *
+ * Purpose: Wrapper function for H5C_get_cache_hit_rate().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 3/10/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_cache_hit_rate(H5AC_t *cache_ptr, double *hit_rate_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5C_get_cache_hit_rate((H5C_t *)cache_ptr, hit_rate_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_hit_rate() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_cache_hit_rate() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_reset_cache_hit_rate_stats()
+ *
+ * Purpose: Wrapper function for H5C_reset_cache_hit_rate_stats().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer, 3/10/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_reset_cache_hit_rate_stats(H5AC_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5C_reset_cache_hit_rate_stats((H5C_t *)cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_reset_cache_hit_rate_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_set_cache_auto_resize_config
+ *
+ * Purpose: Wrapper function for H5C_set_cache_auto_resize_config().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 3/10/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_set_cache_auto_resize_config(H5AC_t *cache_ptr, H5AC_cache_config_t *config_ptr)
+{
+#if H5AC__TRACE_FILE_ENABLED
+ H5AC_cache_config_t trace_config = H5AC__DEFAULT_CACHE_CONFIG;
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ H5C_auto_size_ctl_t internal_config;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache_ptr, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* Make note of the new configuration. Don't look up the trace file
+ * pointer, as that may change before we use it.
+ */
+ if(config_ptr != NULL)
+ trace_config = *config_ptr;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ if(cache_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad cache_ptr on entry")
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if((aux_ptr != NULL) && (aux_ptr->magic != H5AC__H5AC_AUX_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad aux_ptr on entry")
+}
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Validate external configuration */
+ if(H5AC_validate_config(config_ptr) != SUCCEED)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache configuration")
+
+ if(config_ptr->open_trace_file) {
+ FILE * file_ptr;
+
+ if(NULL == (file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_trace_file_ptr() failed")
+
+ if((!(config_ptr->close_trace_file)) && (file_ptr != NULL))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Trace file already open")
+ } /* end if */
+
+ /* Close & reopen trace file, if requested */
+ if(config_ptr->close_trace_file)
+ if(H5AC__close_trace_file(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__close_trace_file() failed")
+ if(config_ptr->open_trace_file)
+ if(H5AC__open_trace_file(cache_ptr, config_ptr->trace_file_name) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "H5AC__open_trace_file() failed")
+
+ /* Convert external configuration to internal representation */
+ if(H5AC__ext_config_2_int_config(config_ptr, &internal_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__ext_config_2_int_config() failed")
+
+ /* Set configuration */
+ if(H5C_set_cache_auto_resize_config(cache_ptr, &internal_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_cache_auto_resize_config() failed")
+ if(H5C_set_evictions_enabled(cache_ptr, config_ptr->evictions_enabled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_evictions_enabled() failed")
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr;
+
+ /* Set parallel configuration values */
+ /* (Which are only held in the H5AC layer -QAK) */
+ if(NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr))) {
+ aux_ptr->dirty_bytes_threshold = config_ptr->dirty_bytes_threshold;
+ aux_ptr->metadata_write_strategy = config_ptr->metadata_write_strategy;
+ } /* end if */
+}
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the set cache auto resize config call, only the contents
+ * of the config is necessary in the trace file. Write the return
+ * value to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ HDfprintf(trace_file_ptr,
+ "%s %d %d %d %d \"%s\" %d %d %d %f %d %d %ld %d %f %f %d %f %f %d %d %d %f %f %d %d %d %d %f %zu %d %d\n",
+ "H5AC_set_cache_auto_resize_config",
+ trace_config.version,
+ (int)(trace_config.rpt_fcn_enabled),
+ (int)(trace_config.open_trace_file),
+ (int)(trace_config.close_trace_file),
+ trace_config.trace_file_name,
+ (int)(trace_config.evictions_enabled),
+ (int)(trace_config.set_initial_size),
+ (int)(trace_config.initial_size),
+ trace_config.min_clean_fraction,
+ (int)(trace_config.max_size),
+ (int)(trace_config.min_size),
+ trace_config.epoch_length,
+ (int)(trace_config.incr_mode),
+ trace_config.lower_hr_threshold,
+ trace_config.increment,
+ (int)(trace_config.flash_incr_mode),
+ trace_config.flash_multiple,
+ trace_config.flash_threshold,
+ (int)(trace_config.apply_max_increment),
+ (int)(trace_config.max_increment),
+ (int)(trace_config.decr_mode),
+ trace_config.upper_hr_threshold,
+ trace_config.decrement,
+ (int)(trace_config.apply_max_decrement),
+ (int)(trace_config.max_decrement),
+ trace_config.epochs_before_eviction,
+ (int)(trace_config.apply_empty_reserve),
+ trace_config.empty_reserve,
+ trace_config.dirty_bytes_threshold,
+ trace_config.metadata_write_strategy,
+ (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_set_cache_config_log_msg(cache_ptr, config_ptr, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_set_cache_auto_resize_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_validate_config()
+ *
+ * Purpose: Run a sanity check on the contents of the supplied
+ * instance of H5AC_cache_config_t.
+ *
+ * Do nothing and return SUCCEED if no errors are detected,
+ * and flag an error and return FAIL otherwise.
+ *
+ * At present, this function operates by packing the data
+ * from the instance of H5AC_cache_config_t into an instance
+ * of H5C_auto_size_ctl_t, and then calling
+ * H5C_validate_resize_config(). As H5AC_cache_config_t and
+ * H5C_auto_size_ctl_t diverge, we may have to change this.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/6/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_validate_config(H5AC_cache_config_t *config_ptr)
+{
+ H5C_auto_size_ctl_t internal_config;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL config_ptr on entry")
+ if(config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Unknown config version")
+
+ /* don't bother to test trace_file_name unless open_trace_file is TRUE */
+ if(config_ptr->open_trace_file) {
+ size_t name_len;
+
+ /* Can't really test the trace_file_name field without trying to
+ * open the file, so we will content ourselves with a couple of
+ * sanity checks on the length of the file name.
+ */
+ name_len = HDstrlen(config_ptr->trace_file_name);
+ if(name_len == 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name is empty")
+ else if(name_len > H5AC__MAX_TRACE_FILE_NAME_LEN)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name too long")
+ } /* end if */
+
+ if((config_ptr->evictions_enabled == FALSE) &&
+ ((config_ptr->incr_mode != H5C_incr__off) ||
+ (config_ptr->flash_incr_mode != H5C_flash_incr__off) ||
+ (config_ptr->decr_mode != H5C_decr__off)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Can't disable evictions while auto-resize is enabled")
+
+ if(config_ptr->dirty_bytes_threshold < H5AC__MIN_DIRTY_BYTES_THRESHOLD)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too small")
+ else if(config_ptr->dirty_bytes_threshold > H5AC__MAX_DIRTY_BYTES_THRESHOLD)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too big")
+
+ if((config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY) &&
+ (config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->metadata_write_strategy out of range")
+
+ if(H5AC__ext_config_2_int_config(config_ptr, &internal_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__ext_config_2_int_config() failed")
+
+ if(H5C_validate_resize_config(&internal_config, H5C_RESIZE_CFG__VALIDATE_ALL) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "error(s) in new config")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_validate_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_validate_cache_image_config()
+ *
+ * Purpose: Run a sanity check on the contents of the supplied
+ * instance of H5AC_cache_image_config_t.
+ *
+ * Do nothing and return SUCCEED if no errors are detected,
+ * and flag an error and return FAIL otherwise.
+ *
+ * At present, this function operates by packing the data
+ * from the instance of H5AC_cache_image_config_t into an
+ * instance of H5C_cache_image_ctl_t, and then calling
+ * H5C_validate_cache_image_config(). If and when
+ * H5AC_cache_image_config_t and H5C_cache_image_ctl_t
+ * diverge, we may have to change this.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/25/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_validate_cache_image_config(H5AC_cache_image_config_t *config_ptr)
+{
+ H5C_cache_image_ctl_t internal_config = H5C__DEFAULT_CACHE_IMAGE_CTL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL config_ptr on entry")
+
+ if(config_ptr->version != H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Unknown image config version")
+
+ /* don't need to get the current H5C image config here since the
+ * default values of fields not in the H5AC config will always be
+ * valid.
+ */
+ internal_config.version = config_ptr->version;
+ internal_config.generate_image = config_ptr->generate_image;
+ internal_config.save_resize_status = config_ptr->save_resize_status;
+ internal_config.entry_ageout = config_ptr->entry_ageout;
+
+ if(H5C_validate_cache_image_config(&internal_config) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "error(s) in new cache image config")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_validate_cache_image_config() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__check_if_write_permitted
+ *
+ * Purpose: Determine if a write is permitted under the current
+ * circumstances, and set *write_permitted_ptr accordingly.
+ * As a general rule it is, but when we are running in parallel
+ * mode with collective I/O, we must ensure that a read cannot
+ * cause a write.
+ *
+ * In the event of failure, the value of *write_permitted_ptr
+ * is undefined.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/15/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__check_if_write_permitted(const H5F_t
+#ifndef H5_HAVE_PARALLEL
+H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ *f, hbool_t *write_permitted_ptr)
+{
+#ifdef H5_HAVE_PARALLEL
+ H5AC_aux_t * aux_ptr = NULL;
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t write_permitted = TRUE;
+
+ FUNC_ENTER_STATIC_NOERR
+
+#ifdef H5_HAVE_PARALLEL
+ /* Sanity checks */
+ HDassert(f != NULL);
+ HDassert(f->shared != NULL);
+ HDassert(f->shared->cache != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache);
+ if(aux_ptr != NULL) {
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ if((aux_ptr->mpi_rank == 0) || (aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED))
+ write_permitted = aux_ptr->write_permitted;
+ else
+ write_permitted = FALSE;
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ *write_permitted_ptr = write_permitted;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__check_if_write_permitted() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__ext_config_2_int_config()
+ *
+ * Purpose: Utility function to translate an instance of
+ * H5AC_cache_config_t to an instance of H5C_auto_size_ctl_t.
+ *
+ * Places translation in *int_conf_ptr and returns SUCCEED
+ * if successful. Returns FAIL on failure.
+ *
+ * Does only minimal sanity checking.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 1/26/06
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__ext_config_2_int_config(H5AC_cache_config_t *ext_conf_ptr,
+ H5C_auto_size_ctl_t *int_conf_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if((ext_conf_ptr == NULL) || (ext_conf_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION) ||
+ (int_conf_ptr == NULL))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad ext_conf_ptr or inf_conf_ptr on entry")
+
+ int_conf_ptr->version = H5C__CURR_AUTO_SIZE_CTL_VER;
+ if(ext_conf_ptr->rpt_fcn_enabled)
+ int_conf_ptr->rpt_fcn = H5C_def_auto_resize_rpt_fcn;
+ else
+ int_conf_ptr->rpt_fcn = NULL;
+
+ int_conf_ptr->set_initial_size = ext_conf_ptr->set_initial_size;
+ int_conf_ptr->initial_size = ext_conf_ptr->initial_size;
+ int_conf_ptr->min_clean_fraction = ext_conf_ptr->min_clean_fraction;
+ int_conf_ptr->max_size = ext_conf_ptr->max_size;
+ int_conf_ptr->min_size = ext_conf_ptr->min_size;
+ int_conf_ptr->epoch_length = (int64_t)(ext_conf_ptr->epoch_length);
+
+ int_conf_ptr->incr_mode = ext_conf_ptr->incr_mode;
+ int_conf_ptr->lower_hr_threshold = ext_conf_ptr->lower_hr_threshold;
+ int_conf_ptr->increment = ext_conf_ptr->increment;
+ int_conf_ptr->apply_max_increment = ext_conf_ptr->apply_max_increment;
+ int_conf_ptr->max_increment = ext_conf_ptr->max_increment;
+ int_conf_ptr->flash_incr_mode = ext_conf_ptr->flash_incr_mode;
+ int_conf_ptr->flash_multiple = ext_conf_ptr->flash_multiple;
+ int_conf_ptr->flash_threshold = ext_conf_ptr->flash_threshold;
+
+ int_conf_ptr->decr_mode = ext_conf_ptr->decr_mode;
+ int_conf_ptr->upper_hr_threshold = ext_conf_ptr->upper_hr_threshold;
+ int_conf_ptr->decrement = ext_conf_ptr->decrement;
+ int_conf_ptr->apply_max_decrement = ext_conf_ptr->apply_max_decrement;
+ int_conf_ptr->max_decrement = ext_conf_ptr->max_decrement;
+ int_conf_ptr->epochs_before_eviction = (int32_t)(ext_conf_ptr->epochs_before_eviction);
+ int_conf_ptr->apply_empty_reserve = ext_conf_ptr->apply_empty_reserve;
+ int_conf_ptr->empty_reserve = ext_conf_ptr->empty_reserve;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__ext_config_2_int_config() */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_ignore_tags()
+ *
+ * Purpose: Override all assertion frameworks and force application of
+ * global tag everywhere. This should really only be used in the
+ * tests that need to access functions without going through
+ * API paths.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * December 1, 2009
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_ignore_tags(const H5F_t *f)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ /* Set up a new metadata tag */
+ if(H5C_ignore_tags(f->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "H5C_ignore_tags() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_ignore_tags() */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_tag()
+ *
+ * Purpose: Sets the metadata tag property in the provided property list.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * December 1, 2009
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t *prev_tag)
+{
+ H5P_genplist_t *dxpl; /* Dataset transfer property list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check Arguments */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the current tag value and return that (if prev_tag is NOT null) */
+ if(prev_tag) {
+ haddr_t tag; /* Tag value */
+
+ if((H5P_get(dxpl, H5AC_TAG_NAME, &tag)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query dxpl")
+ *prev_tag = tag;
+ } /* end if */
+
+ /* Set the provided tag in the dxpl_id. */
+ if(H5P_set(dxpl, H5AC_TAG_NAME, &metadata_tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't set tag in dxpl")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_tag */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_retag_copied_metadata()
+ *
+ * Purpose: Searches through cache index for all entries with the
+ * H5AC__COPIED_TAG, indicating that it was created as a
+ * result of an object copy, and applies the provided tag.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * March 17, 2010
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_retag_copied_metadata(const H5F_t *f, haddr_t metadata_tag)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Call cache-level function to re-tag entries with the COPIED tag */
+ if(H5C_retag_entries(f->shared->cache, H5AC__COPIED_TAG, metadata_tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "Can't retag metadata")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_retag_copied_metadata() */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_flush_tagged_metadata()
+ *
+ * Purpose: Wrapper for cache level function which flushes all metadata
+ * that contains the specific tag.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id)
+{
+ /* Variable Declarations */
+ herr_t ret_value = SUCCEED;
+
+ /* Function Enter Macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Assertions */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Call cache level function to flush metadata entries with specified tag */
+ if(H5C_flush_tagged_entries(f, dxpl_id, metadata_tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot flush metadata")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_flush_tagged_metadata */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_evict_tagged_metadata()
+ *
+ * Purpose: Wrapper for cache level function which flushes all metadata
+ * that contains the specific tag.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hbool_t match_global, hid_t dxpl_id)
+{
+ /* Variable Declarations */
+ herr_t ret_value = SUCCEED;
+
+ /* Function Enter Macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Assertions */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Call cache level function to evict metadata entries with specified tag */
+ if(H5C_evict_tagged_entries(f, dxpl_id, metadata_tag, match_global) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_evict_tagged_metadata() */
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_expunge_tag_type_metadata()
+ *
+ * Purpose: Wrapper for cache level function which expunge entries with
+ * a specific tag and type id.
+ *
+ * Return: SUCCEED on success, FAIL otherwise.
+ *
+ * Programmer: Vailin Choi; May 2016
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id, unsigned flags)
+{
+ /* Variable Declarations */
+ herr_t ret_value = SUCCEED;
+
+ /* Function Enter Macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Assertions */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Call cache level function to expunge entries with specified tag and type id */
+ if(H5C_expunge_tag_type_metadata(f, dxpl_id, tag, type_id, flags)<0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot expunge tagged type entries")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_expunge_tag_type_metadata*/
+
+
+/*------------------------------------------------------------------------------
+ * Function: H5AC_get_tag()
+ *
+ * Purpose: Get the tag for a metadata cache entry.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2016
+ *
+ *------------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_tag(const void *thing, haddr_t *tag)
+{
+ /* Variable Declarations */
+ herr_t ret_value = SUCCEED;
+
+ /* Function Enter Macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Assertions */
+ HDassert(thing);
+ HDassert(tag);
+
+ /* Call cache level function to get the tag */
+ if(H5C_get_tag(thing, tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot get tag for metadata cache entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_get_tag() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_cork
+ *
+ * Purpose: To cork/uncork/get cork status for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Jan 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_cork(H5F_t *f, haddr_t obj_addr, unsigned action, hbool_t *corked)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(action == H5AC__SET_CORK || action == H5AC__UNCORK || action == H5AC__GET_CORKED);
+
+ if(action == H5AC__GET_CORKED)
+ HDassert(corked);
+
+ if(H5C_cork(f->shared->cache, obj_addr, action, corked) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Cannot perform the cork action")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_cork() */
+
+#if H5AC_DO_TAGGING_SANITY_CHECKS
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__verify_tag
+ *
+ * Purpose: Performs sanity checking on an entry type and tag value
+ * stored in a supplied dxpl_id.
+ *
+ * Return: SUCCEED or FAIL.
+ *
+ * Programmer: Mike McGreevy
+ * October 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__verify_tag(hid_t dxpl_id, const H5AC_class_t *type)
+{
+ H5P_genplist_t *dxpl; /* DXPL for operation */
+ haddr_t tag; /* Entry tag to validate */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the tag from the DXPL */
+ if((H5P_get(dxpl, H5AC_TAG_NAME, &tag)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value")
+
+ /* Verify legal tag value */
+ if(H5C_verify_tag(type->id, tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "tag verification failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__verify_tag */
+#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_entry_ring
+ *
+ * Purpose: Given a file address, retrieve the ring for an entry at that
+ * address.
+ *
+ * On error, the value of *ring is not modified.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 9/8/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_entry_ring(const H5F_t *f, haddr_t addr, H5AC_ring_t *ring)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(ring);
+
+ /* Retrieve the ring value for the entry at address */
+ if(H5C_get_entry_ring(f, addr, ring) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "Can't retrieve ring for entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_entry_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_set_ring
+ *
+ * Purpose: Routine to set the ring on a DXPL (for passing through
+ * to the metadata cache).
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_set_ring(hid_t dxpl_id, H5AC_ring_t ring, H5P_genplist_t **dxpl,
+ H5AC_ring_t *orig_ring)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(dxpl);
+ HDassert(orig_ring);
+
+ /* Set the ring type in the DXPL */
+ if(NULL == ((*dxpl) = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if((H5P_get((*dxpl), H5AC_RING_NAME, orig_ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get original ring value")
+ if((H5P_set((*dxpl), H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set ring value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_set_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_reset_ring
+ *
+ * Purpose: Routine to reset the original ring on a DXPL (after passing
+ * through to the metadata cache).
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_reset_ring(H5P_genplist_t *dxpl, H5AC_ring_t orig_ring)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Reset the ring in the DXPL, if it's been changed */
+ if(orig_ring) {
+ /* Sanity check */
+ HDassert(dxpl);
+
+ if((H5P_set(dxpl, H5AC_RING_NAME, &orig_ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set property value")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_reset_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_unsettle_entry_ring()
+ *
+ * Purpose: Advise the metadata cache that the specified entry's metadata
+ * cache manager ring is no longer settled (if it was on entry).
+ *
+ * If the target metadata cache manager ring is already
+ * unsettled, do nothing, and return SUCCEED.
+ *
+ * If the target metadata cache manager ring is settled, and
+ * we are not in the process of a file shutdown, mark
+ * the ring as unsettled, and return SUCCEED.
+ *
+ * If the target metadata cache manager is settled, and we
+ * are in the process of a file shutdown, post an error
+ * message, and return FAIL.
+ *
+ * Note that this function simply passes the call on to
+ * the metadata cache proper, and returns the result.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_unsettle_entry_ring(void *_entry)
+{
+ H5AC_info_t *entry = (H5AC_info_t *)_entry; /* Entry to remove */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+
+ /* Unsettle the entry's ring */
+ if(H5C_unsettle_entry_ring(entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_unsettle_entry_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_unsettle_ring()
+ *
+ * Purpose: Advise the metadata cache that the specified free space
+ * manager ring is no longer settled (if it was on entry).
+ *
+ * If the target free space manager ring is already
+ * unsettled, do nothing, and return SUCCEED.
+ *
+ * If the target free space manager ring is settled, and
+ * we are not in the process of a file shutdown, mark
+ * the ring as unsettled, and return SUCCEED.
+ *
+ * If the target free space manager is settled, and we
+ * are in the process of a file shutdown, post an error
+ * message, and return FAIL.
+ *
+ * Note that this function simply passes the call on to
+ * the metadata cache proper, and returns the result.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 10/15/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_unsettle_ring(H5F_t * f, H5C_ring_t ring)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(FAIL == (ret_value = H5C_unsettle_ring(f, ring)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_unsettle_ring() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_unsettle_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_remove_entry()
+ *
+ * Purpose: Remove an entry from the cache. Must be not protected, pinned,
+ * dirty, involved in flush dependencies, etc.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_remove_entry(void *_entry)
+{
+ H5AC_info_t *entry = (H5AC_info_t *)_entry; /* Entry to remove */
+ H5C_t *cache = NULL; /* Pointer to the entry's associated metadata cache */
+#if H5AC__TRACE_FILE_ENABLED
+ char trace[128] = "";
+ FILE * trace_file_ptr = NULL;
+#endif /* H5AC__TRACE_FILE_ENABLED */
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+ cache = entry->cache_ptr;
+ HDassert(cache);
+
+#if H5AC__TRACE_FILE_ENABLED
+ /* For the remove entry call, only the addr is really necessary
+ * in the trace file. Also write the result to catch occult errors.
+ */
+ if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr_from_entry(entry)))
+ sprintf(trace, "%s 0x%lx", FUNC, (unsigned long)(entry->addr));
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "unable to get logging status")
+
+ /* Remove the entry from the cache*/
+ if(H5C_remove_entry(entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry")
+
+done:
+#if H5AC__TRACE_FILE_ENABLED
+ if(trace_file_ptr)
+ HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
+#endif /* H5AC__TRACE_FILE_ENABLED */
+
+ /* If currently logging, generate a message */
+ if(curr_logging)
+ if(H5AC__write_remove_entry_log_msg(cache, entry, ret_value) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to emit log message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_remove_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_mdc_image_info
+ *
+ * Purpose: Wrapper function for H5C_get_mdc_image_info().
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: Vailin Choi; March 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_get_mdc_image_info(H5AC_t *cache_ptr, haddr_t *image_addr, hsize_t *image_len)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5C_get_mdc_image_info((H5C_t *)cache_ptr, image_addr, image_len) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't retrieve cache image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_mdc_image_info() */
+
diff --git a/src/H5ACdbg.c b/src/H5ACdbg.c
new file mode 100644
index 0000000..c6d71a8
--- /dev/null
+++ b/src/H5ACdbg.c
@@ -0,0 +1,492 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5ACdbg.c
+ *
+ * Purpose: Functions for debugging the metadata cache
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+#include "H5ACmodule.h" /* This source code file is part of the H5AC module */
+#define H5F_FRIEND /* Suppress error about including H5Fpkg */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_stats
+ *
+ * Purpose: Prints statistics about the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 30, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_stats(const H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ /* at present, this can't fail */
+ (void)H5C_stats(f->shared->cache, H5F_OPEN_NAME(f), FALSE);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC_stats() */
+
+#ifndef NDEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_dump_cache
+ *
+ * Purpose: Dumps a summary of the contents of the metadata cache
+ * to stdout.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * Sunday, October 10, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_dump_cache(const H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ if(H5C_dump_cache(f->shared->cache, H5F_OPEN_NAME(f)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_dump_cache() failed.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_dump_cache() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__close_trace_file()
+ *
+ * Purpose: If a trace file is open, stop logging calls to the cache,
+ * and close the file.
+ *
+ * Note that the function does nothing if there is no trace
+ * file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__close_trace_file(H5AC_t *cache_ptr)
+{
+ FILE * trace_file_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ if(cache_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL cache_ptr on entry.")
+
+ if(NULL == (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_trace_file_ptr() failed.")
+
+ if(trace_file_ptr != NULL) {
+ if(H5C_set_trace_file_ptr(cache_ptr, NULL) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_trace_file_ptr() failed.")
+
+ if(HDfclose(trace_file_ptr) != 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close metadata cache trace file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__close_trace_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__open_trace_file()
+ *
+ * Purpose: Open a trace file, and start logging calls to the cache.
+ *
+ * This logging is done at the H5C level, and will only take
+ * place if H5C_TRACE_FILE_ENABLED (defined in H5Cprivate.h)
+ * is TRUE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/1/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__open_trace_file(H5AC_t *cache_ptr, const char *trace_file_name)
+{
+ char file_name[H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 2];
+ FILE * file_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(cache_ptr);
+
+ /* Check args */
+ if(cache_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "cache_ptr NULL on entry.")
+ if(trace_file_name == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL trace_file_name on entry.")
+ if(HDstrlen(trace_file_name) > H5AC__MAX_TRACE_FILE_NAME_LEN)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "trace file name too long.")
+ if(NULL != (file_ptr = H5C_get_trace_file_ptr(cache_ptr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_FILEOPEN, FAIL, "trace file already open.")
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t * aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ if(aux_ptr == NULL)
+ sprintf(file_name, "%s", trace_file_name);
+ else {
+ if(aux_ptr->magic != H5AC__H5AC_AUX_T_MAGIC)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad aux_ptr->magic.")
+
+ sprintf(file_name, "%s.%d", trace_file_name, aux_ptr->mpi_rank);
+ } /* end else */
+
+ if(HDstrlen(file_name) > H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 1)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cooked trace file name too long.")
+}
+#else /* H5_HAVE_PARALLEL */
+ HDsnprintf(file_name, (size_t)(H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 1),
+ "%s", trace_file_name);
+#endif /* H5_HAVE_PARALLEL */
+
+ if((file_ptr = HDfopen(file_name, "w")) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "trace file open failed.")
+
+ HDfprintf(file_ptr, "### HDF5 metadata cache trace file version 1 ###\n");
+
+ if(H5C_set_trace_file_ptr(cache_ptr, file_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_trace_file_ptr() failed.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__open_trace_file() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_get_entry_ptr_from_addr()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, returns a pointer
+ * to the entry in *entry_ptr_ptr. If the entry is not in the
+ * cache, *entry_ptr_ptr is set to NULL.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * As heavy use of this function is almost certainly a
+ * bad idea, the metadata cache tracks the number of
+ * successful calls to this function, and (if
+ * H5C_DO_SANITY_CHECKS is defined) displays any
+ * non-zero count on cache shutdown.
+ *
+ * This function is just a wrapper that calls the H5C
+ * version of the function.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5AC_get_entry_ptr_from_addr(const H5F_t *f, haddr_t addr, void **entry_ptr_ptr)
+{
+ H5C_t *cache_ptr; /* Ptr to cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ if(H5C_get_entry_ptr_from_addr(cache_ptr, addr, entry_ptr_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_entry_ptr_from_addr() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_entry_ptr_from_addr() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_flush_dependency_exists()
+ *
+ * Purpose: Test to see if a flush dependency relationship exists
+ * between the supplied parent and child. Both parties
+ * are indicated by addresses so as to avoid the necessity
+ * of protect / unprotect calls prior to this call.
+ *
+ * If either the parent or the child is not in the metadata
+ * cache, the function sets *fd_exists_ptr to FALSE.
+ *
+ * If both are in the cache, the childs list of parents is
+ * searched for the proposed parent. If the proposed parent
+ * is found in the childs parent list, the function sets
+ * *fd_exists_ptr to TRUE. In all other non-error cases,
+ * the function sets *fd_exists_ptr FALSE.
+ *
+ * Return: SUCCEED on success/FAIL on failure. Note that
+ * *fd_exists_ptr is undefined on failure.
+ *
+ * Programmer: John Mainzer
+ * 9/28/16
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5AC_flush_dependency_exists(H5F_t *f, haddr_t parent_addr, haddr_t child_addr,
+ hbool_t *fd_exists_ptr)
+{
+ H5C_t *cache_ptr; /* Ptr to cache */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ ret_value = H5C_flush_dependency_exists(cache_ptr, parent_addr, child_addr, fd_exists_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_flush_dependency_exists() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_verify_entry_type()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, test to see if its
+ * type field contains the expected value.
+ *
+ * If the specified entry is in cache, *in_cache_ptr is set
+ * to TRUE, and *type_ok_ptr is set to TRUE or FALSE depending
+ * on whether the entries type field matches the
+ * expected_type parameter
+ *
+ * If the target entry is not in cache, *in_cache_ptr is
+ * set to FALSE, and *type_ok_ptr is undefined.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * This function is just a wrapper that calls the H5C
+ * version of the function.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ * Changes: None.
+ *
+ * JRM -- 9/17/16
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5AC_verify_entry_type(const H5F_t *f, haddr_t addr,
+ const H5AC_class_t *expected_type, hbool_t *in_cache_ptr,
+ hbool_t *type_ok_ptr)
+{
+ H5C_t * cache_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ if(H5C_verify_entry_type(cache_ptr, addr, expected_type, in_cache_ptr, type_ok_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_verify_entry_type() failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_verify_entry_type() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_get_serialization_in_progress
+ *
+ * Purpose: Return the current value of
+ * cache_ptr->serialization_in_progress.
+ *
+ * Return: Current value of cache_ptr->serialization_in_progress.
+ *
+ * Programmer: John Mainzer
+ * 8/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+hbool_t
+H5AC_get_serialization_in_progress(H5F_t *f)
+{
+ H5C_t * cache_ptr;
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ /* Set return value */
+ ret_value = H5C_get_serialization_in_progress(cache_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_get_serialization_in_progress() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_cache_is_clean()
+ *
+ * Purpose: Debugging function that verifies that all rings in the
+ * metadata cache are clean from the outermost ring, inwards
+ * to the inner ring specified.
+ *
+ * Returns TRUE if all specified rings are clean, and FALSE
+ * if not. Throws an assertion failure on error.
+ *
+ * Return: TRUE if the indicated ring(s) are clean, and FALSE otherwise.
+ *
+ * Programmer: John Mainzer, 6/18/16
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+hbool_t
+H5AC_cache_is_clean(const H5F_t *f, H5AC_ring_t inner_ring)
+{
+ H5C_t *cache_ptr;
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+
+ ret_value = H5C_cache_is_clean(cache_ptr, inner_ring);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_cache_is_clean() */
+#endif /* NDEBUG */
+
diff --git a/src/H5AClog.c b/src/H5AClog.c
new file mode 100644
index 0000000..51a2050
--- /dev/null
+++ b/src/H5AClog.c
@@ -0,0 +1,1105 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5AClog.c
+ *
+ * Purpose: Functions for metadata cache logging in JSON format
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+#include "H5ACmodule.h" /* This source code file is part of the H5AC module */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata cache */
+#include "H5Cprivate.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define MSG_SIZE 128
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_create_cache_log_msg
+ *
+ * Purpose: Write a log message for cache creation.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_create_cache_log_msg(H5AC_t *cache)
+{
+ char msg[MSG_SIZE];
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Since we're about to override the current logging flag,
+ * check the "log enabled" flag to see if we didn't get here
+ * by mistake.
+ */
+ if(!log_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "attempt to write opening log message when logging is disabled")
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\n\
+\"create_time\":%lld,\n\
+\"messages\":\n\
+[\n\
+"
+ , (long long)HDtime(NULL));
+
+ /* Have to temporarily enable logging, if it isn't currently */
+ if(!curr_logging)
+ if(H5C_start_logging(cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to start mdc logging")
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+ /* Stop logging, if it wasn't started originally */
+ if(!curr_logging)
+ if(H5C_stop_logging(cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to stop mdc logging")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_create_cache_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_destroy_cache_log_msg
+ *
+ * Purpose: Write a log message for cache destruction.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_destroy_cache_log_msg(H5AC_t *cache)
+{
+ char msg[MSG_SIZE];
+ hbool_t log_enabled; /* TRUE if logging was set up */
+ hbool_t curr_logging; /* TRUE if currently logging */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Check if log messages are being emitted */
+ if(H5C_get_logging_status(cache, &log_enabled, &curr_logging) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status")
+
+ /* Since we're about to override the current logging flag,
+ * check the "log enabled" flag to see if we didn't get here
+ * by mistake.
+ */
+ if(!log_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "attempt to write closing log message when logging is disabled")
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+],\n\
+\"close_time\":%lld,\n\
+}\n\
+"
+ , (long long)HDtime(NULL));
+
+ /* Have to temporarily enable logging, if it isn't currently */
+ if(!curr_logging)
+ if(H5C_start_logging(cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to start mdc logging")
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+ /* Stop logging, if it wasn't started originally */
+ if(!curr_logging)
+ if(H5C_stop_logging(cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_LOGFAIL, FAIL, "unable to stop mdc logging")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_destroy_cache_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_evict_cache_log_msg
+ *
+ * Purpose: Write a log message for eviction of cache entries.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_evict_cache_log_msg(const H5AC_t *cache,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"evict\",\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_evict_cache_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_expunge_entry_log_msg
+ *
+ * Purpose: Write a log message for expunge of cache entries.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_expunge_entry_log_msg(const H5AC_t *cache,
+ haddr_t address,
+ int type_id,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"expunge\",\
+\"address\":0x%lx,\
+\"type_id\":%d,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)address, (int)type_id, (int)fxn_ret_value);
+
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_expunge_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_flush_cache_log_msg
+ *
+ * Purpose: Write a log message for cache flushes.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_flush_cache_log_msg(const H5AC_t *cache,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"flush\",\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_flush_cache_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_insert_entry_log_msg
+ *
+ * Purpose: Write a log message for insertion of cache entries.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_insert_entry_log_msg(const H5AC_t *cache,
+ haddr_t address,
+ int type_id,
+ unsigned flags,
+ size_t size,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"insert\",\
+\"address\":0x%lx,\
+\"flags\":0x%x,\
+\"type_id\":%d,\
+\"size\":%d,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)address, flags, type_id,
+ (int)size, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_insert_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_mark_dirty_entry_log_msg
+ *
+ * Purpose: Write a log message for marking cache entries as dirty.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_mark_dirty_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"dirty\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_mark_dirty_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_mark_clean_entry_log_msg
+ *
+ * Purpose: Write a log message for marking cache entries as clean.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 23, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_mark_clean_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE]; /* Log message buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"clean\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_mark_clean_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_mark_unserialized_entry_log_msg
+ *
+ * Purpose: Write a log message for marking cache entries as unserialized.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 22, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_mark_unserialized_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"unserialized\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_mark_unserialized_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_mark_serialize_entry_log_msg
+ *
+ * Purpose: Write a log message for marking cache entries as serialize.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 22, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_mark_serialized_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE]; /* Log message buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"serialized\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_mark_serialized_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_move_entry_log_msg
+ *
+ * Purpose: Write a log message for moving a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_move_entry_log_msg(const H5AC_t *cache,
+ haddr_t old_addr,
+ haddr_t new_addr,
+ int type_id,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"move\",\
+\"old_address\":0x%lx,\
+\"new_address\":0x%lx,\
+\"type_id\":%d,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)old_addr,
+ (unsigned long)new_addr, type_id, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_move_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_pin_entry_log_msg
+ *
+ * Purpose: Write a log message for pinning a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_pin_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"pin\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_pin_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_create_fd_log_msg
+ *
+ * Purpose: Write a log message for creating a flush dependency between
+ * two cache entries.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_create_fd_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *parent,
+ const H5AC_info_t *child,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(parent);
+ HDassert(child);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"create_fd\",\
+\"parent_addr\":0x%lx,\
+\"child_addr\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)parent->addr,
+ (unsigned long)child->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_create_fd_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_protect_entry_log_msg
+ *
+ * Purpose: Write a log message for protecting a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_protect_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ unsigned flags,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ char rw_s[16];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ if(H5AC__READ_ONLY_FLAG == flags)
+ HDstrcpy(rw_s, "READ");
+ else
+ HDstrcpy(rw_s, "WRITE");
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"protect\",\
+\"address\":0x%lx,\
+\"readwrite\":\"%s\",\
+\"size\":%d,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ rw_s, (int)entry->size, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_protect_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_resize_entry_log_msg
+ *
+ * Purpose: Write a log message for resizing a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_resize_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ size_t new_size,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"resize\",\
+\"address\":0x%lx,\
+\"new_size\":%d,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ (int)new_size, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_resize_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_unpin_entry_log_msg
+ *
+ * Purpose: Write a log message for unpinning a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_unpin_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"unpin\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_unpin_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_destroy_fd_log_msg
+ *
+ * Purpose: Write a log message for destroying a flush dependency
+ * between two cache entries.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_destroy_fd_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *parent,
+ const H5AC_info_t *child,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(parent);
+ HDassert(child);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"destroy_fd\",\
+\"parent_addr\":0x%lx,\
+\"child_addr\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)parent->addr,
+ (unsigned long)child->addr, (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_destroy_fd_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_unprotect_entry_log_msg
+ *
+ * Purpose: Write a log message for unprotecting a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_unprotect_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ int type_id,
+ unsigned flags,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"unprotect\",\
+\"address\":0x%lx,\
+\"id\":%d,\
+\"flags\":%x,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ type_id, flags, (int)fxn_ret_value);
+
+ HDsnprintf(msg, MSG_SIZE, " ");
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_unprotect_entry_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_set_cache_config_log_msg
+ *
+ * Purpose: Write a log message for setting the cache configuration.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_set_cache_config_log_msg(const H5AC_t *cache,
+ const H5AC_cache_config_t *config,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(config);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"set_config\",\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (int)fxn_ret_value);
+
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_set_cache_config_log_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__write_remove_entry_log_msg
+ *
+ * Purpose: Write a log message for removing a cache entry.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__write_remove_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry,
+ herr_t fxn_ret_value)
+{
+ char msg[MSG_SIZE];
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache);
+ HDassert(entry);
+
+ /* Create the log message string */
+ HDsnprintf(msg, MSG_SIZE,
+"\
+{\
+\"timestamp\":%lld,\
+\"action\":\"remove\",\
+\"address\":0x%lx,\
+\"returned\":%d\
+},\n\
+"
+ , (long long)HDtime(NULL), (unsigned long)entry->addr,
+ (int)fxn_ret_value);
+
+ /* Write the log message to the file */
+ if(H5C_write_log_message(cache, msg) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to emit log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__write_remove_entry_log_msg() */
+
diff --git a/src/H5ACmodule.h b/src/H5ACmodule.h
new file mode 100644
index 0000000..e218b31
--- /dev/null
+++ b/src/H5ACmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5AC package. Including this header means that the source file
+ * is part of the H5AC package.
+ */
+#ifndef _H5ACmodule_H
+#define _H5ACmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5AC_MODULE
+#define H5_MY_PKG H5AC
+#define H5_MY_PKG_ERR H5E_CACHE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5ACmodule_H */
+
diff --git a/src/H5ACmpio.c b/src/H5ACmpio.c
new file mode 100644
index 0000000..d03c17b
--- /dev/null
+++ b/src/H5ACmpio.c
@@ -0,0 +1,2306 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5ACmpio.c
+ * Jun 20 2015
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Functions in this file implement support for parallel
+ * I/O cache functionality
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5ACmodule.h" /* This source code file is part of the H5AC module */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata cache */
+#include "H5Cprivate.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5MMprivate.h" /* Memory management */
+
+#ifdef H5_HAVE_PARALLEL
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/****************************************************************************
+ *
+ * structure H5AC_slist_entry_t
+ *
+ * The dirty entry list maintained via the d_slist_ptr field of H5AC_aux_t
+ * and the cleaned entry list maintained via the c_slist_ptr field of
+ * H5AC_aux_t are just lists of the file offsets of the dirty/cleaned
+ * entries. Unfortunately, the slist code makes us define a dynamically
+ * allocated structure to store these offsets in. This structure serves
+ * that purpose. Its fields are as follows:
+ *
+ * addr: file offset of a metadata entry. Entries are added to this
+ * list (if they aren't there already) when they are marked
+ * dirty in an unprotect, inserted, or moved. They are
+ * removed when they appear in a clean entries broadcast.
+ *
+ ****************************************************************************/
+typedef struct H5AC_slist_entry_t
+{
+ haddr_t addr;
+} H5AC_slist_entry_t;
+
+/* User data for address list building callbacks */
+typedef struct H5AC_addr_list_ud_t
+{
+ H5AC_aux_t * aux_ptr; /* 'Auxiliary' parallel cache info */
+ haddr_t * addr_buf_ptr; /* Array to store addresses */
+ unsigned u; /* Counter for position in array */
+} H5AC_addr_list_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5AC__broadcast_candidate_list(H5AC_t *cache_ptr,
+ unsigned *num_entries_ptr, haddr_t **haddr_buf_ptr_ptr);
+static herr_t H5AC__broadcast_clean_list(H5AC_t *cache_ptr);
+static herr_t H5AC__construct_candidate_list(H5AC_t *cache_ptr,
+ H5AC_aux_t *aux_ptr, int sync_point_op);
+static herr_t H5AC__copy_candidate_list_to_buffer(const H5AC_t *cache_ptr,
+ unsigned *num_entries_ptr, haddr_t **haddr_buf_ptr_ptr);
+static herr_t H5AC__propagate_and_apply_candidate_list(H5F_t *f, hid_t dxpl_id);
+static herr_t H5AC__propagate_flushed_and_still_clean_entries_list(H5F_t *f,
+ hid_t dxpl_id);
+static herr_t H5AC__receive_haddr_list(MPI_Comm mpi_comm, unsigned *num_entries_ptr,
+ haddr_t **haddr_buf_ptr_ptr);
+static herr_t H5AC__receive_candidate_list(const H5AC_t *cache_ptr,
+ unsigned *num_entries_ptr, haddr_t **haddr_buf_ptr_ptr);
+static herr_t H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t dxpl_id);
+static herr_t H5AC__tidy_cache_0_lists(H5AC_t *cache_ptr, unsigned num_candidates,
+ haddr_t *candidates_list_ptr);
+static herr_t H5AC__rsp__dist_md_write__flush(H5F_t *f, hid_t dxpl_id);
+static herr_t H5AC__rsp__dist_md_write__flush_to_min_clean(H5F_t *f, hid_t dxpl_id);
+static herr_t H5AC__rsp__p0_only__flush(H5F_t *f, hid_t dxpl_id);
+static herr_t H5AC__rsp__p0_only__flush_to_min_clean(H5F_t *f, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5AC_aux_t struct */
+H5FL_DEFINE(H5AC_aux_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5AC_slist_entry_t struct */
+H5FL_DEFINE_STATIC(H5AC_slist_entry_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__set_sync_point_done_callback
+ *
+ * Purpose: Set the value of the sync_point_done callback. This
+ * callback is used by the parallel test code to verify
+ * that the expected writes and only the expected writes
+ * take place during a sync point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/9/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__set_sync_point_done_callback(H5C_t * cache_ptr,
+ void (* sync_point_done)(unsigned num_writes, haddr_t * written_entries_tbl))
+{
+ H5AC_aux_t * aux_ptr;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ aux_ptr->sync_point_done = sync_point_done;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__set_sync_point_done_callback() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__set_write_done_callback
+ *
+ * Purpose: Set the value of the write_done callback. This callback
+ * is used to improve performance of the parallel test bed
+ * for the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/11/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__set_write_done_callback(H5C_t * cache_ptr, void (* write_done)(void))
+{
+ H5AC_aux_t * aux_ptr;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ aux_ptr->write_done = write_done;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__set_write_done_callback() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_add_candidate()
+ *
+ * Purpose: Add the supplied metadata entry address to the candidate
+ * list. Verify that each entry added does not appear in
+ * the list prior to its insertion.
+ *
+ * This function is intended for used in constructing list
+ * of entried to be flushed during sync points. It shouldn't
+ * be called anywhere else.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_add_candidate(H5AC_t * cache_ptr, haddr_t addr)
+{
+ H5AC_aux_t * aux_ptr;
+ H5AC_slist_entry_t * slist_entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert(aux_ptr->candidate_slist_ptr != NULL);
+
+ /* Construct an entry for the supplied address, and insert
+ * it into the candidate slist.
+ */
+ if(NULL == (slist_entry_ptr = H5FL_MALLOC(H5AC_slist_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate candidate slist entry")
+ slist_entry_ptr->addr = addr;
+
+ if(H5SL_insert(aux_ptr->candidate_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist")
+
+done:
+ /* Clean up on error */
+ if(ret_value < 0)
+ if(slist_entry_ptr)
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_add_candidate() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__broadcast_candidate_list()
+ *
+ * Purpose: Broadcast the contents of the process 0 candidate entry
+ * slist. In passing, also remove all entries from said
+ * list. As the application of this will be handled by
+ * the same functions on all processes, construct and
+ * return a copy of the list in the same format as that
+ * received by the other processes. Note that if this
+ * copy is returned in *haddr_buf_ptr_ptr, the caller
+ * must free it.
+ *
+ * This function must only be called by the process with
+ * MPI_rank 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 7/1/05
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__broadcast_candidate_list(H5AC_t *cache_ptr, unsigned *num_entries_ptr,
+ haddr_t **haddr_buf_ptr_ptr)
+{
+ H5AC_aux_t * aux_ptr = NULL;
+ haddr_t * haddr_buf_ptr = NULL;
+ int mpi_result;
+ unsigned num_entries;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank == 0);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert(aux_ptr->candidate_slist_ptr != NULL);
+ HDassert(num_entries_ptr != NULL);
+ HDassert(*num_entries_ptr == 0);
+ HDassert(haddr_buf_ptr_ptr != NULL);
+ HDassert(*haddr_buf_ptr_ptr == NULL);
+
+ /* First broadcast the number of entries in the list so that the
+ * receivers can set up buffers to receive them. If there aren't
+ * any, we are done.
+ */
+ num_entries = (unsigned)H5SL_count(aux_ptr->candidate_slist_ptr);
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ if(num_entries > 0) {
+ size_t buf_size = 0;
+ unsigned chk_num_entries = 0;
+
+ /* convert the candidate list into the format we
+ * are used to receiving from process 0, and also load it
+ * into a buffer for transmission.
+ */
+ if(H5AC__copy_candidate_list_to_buffer(cache_ptr, &chk_num_entries, &haddr_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate buffer.")
+ HDassert(chk_num_entries == num_entries);
+ HDassert(haddr_buf_ptr != NULL);
+
+ /* Now broadcast the list of candidate entries */
+ buf_size = sizeof(haddr_t) * num_entries;
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)haddr_buf_ptr, (int)buf_size, MPI_BYTE, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+ } /* end if */
+
+ /* Pass the number of entries and the buffer pointer
+ * back to the caller. Do this so that we can use the same code
+ * to apply the candidate list to all the processes.
+ */
+ *num_entries_ptr = num_entries;
+ *haddr_buf_ptr_ptr = haddr_buf_ptr;
+
+done:
+ if(ret_value < 0)
+ if(haddr_buf_ptr)
+ haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__broadcast_candidate_list() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__broadcast_clean_list_cb()
+ *
+ * Purpose: Skip list callback for building array of addresses for
+ * broadcasting the clean list.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: Quincey Koziol, 6/12/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__broadcast_clean_list_cb(void *_item, void H5_ATTR_UNUSED *_key,
+ void *_udata)
+{
+ H5AC_slist_entry_t * slist_entry_ptr = (H5AC_slist_entry_t *)_item; /* Address of item */
+ H5AC_addr_list_ud_t * udata = (H5AC_addr_list_ud_t *)_udata; /* Context for callback */
+ haddr_t addr;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(slist_entry_ptr);
+ HDassert(udata);
+
+ /* Store the entry's address in the buffer */
+ addr = slist_entry_ptr->addr;
+ udata->addr_buf_ptr[udata->u] = addr;
+ udata->u++;
+
+ /* now release the entry */
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ /* and also remove the matching entry from the dirtied list
+ * if it exists.
+ */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(udata->aux_ptr->d_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__broadcast_clean_list_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__broadcast_clean_list()
+ *
+ * Purpose: Broadcast the contents of the process 0 cleaned entry
+ * slist. In passing, also remove all entries from said
+ * list, and also remove any matching entries from the dirtied
+ * slist.
+ *
+ * This function must only be called by the process with
+ * MPI_rank 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 7/1/05
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__broadcast_clean_list(H5AC_t * cache_ptr)
+{
+ haddr_t * addr_buf_ptr = NULL;
+ H5AC_aux_t * aux_ptr;
+ int mpi_result;
+ unsigned num_entries = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank == 0);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* First broadcast the number of entries in the list so that the
+ * receives can set up a buffer to receive them. If there aren't
+ * any, we are done.
+ */
+ num_entries = (unsigned)H5SL_count(aux_ptr->c_slist_ptr);
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ if(num_entries > 0) {
+ H5AC_addr_list_ud_t udata;
+ size_t buf_size;
+
+ /* allocate a buffer to store the list of entry base addresses in */
+ buf_size = sizeof(haddr_t) * num_entries;
+ if(NULL == (addr_buf_ptr = (haddr_t *)H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for addr buffer")
+
+ /* Set up user data for callback */
+ udata.aux_ptr = aux_ptr;
+ udata.addr_buf_ptr = addr_buf_ptr;
+ udata.u = 0;
+
+ /* Free all the clean list entries, building the address list in the callback */
+ /* (Callback also removes the matching entries from the dirtied list) */
+ if(H5SL_free(aux_ptr->c_slist_ptr, H5AC__broadcast_clean_list_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "Can't build address list for clean entries")
+
+ /* Now broadcast the list of cleaned entries */
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)addr_buf_ptr, (int)buf_size, MPI_BYTE, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+ } /* end if */
+
+ /* if it is defined, call the sync point done callback. Note
+ * that this callback is defined purely for testing purposes,
+ * and should be undefined under normal operating circumstances.
+ */
+ if(aux_ptr->sync_point_done)
+ (aux_ptr->sync_point_done)(num_entries, addr_buf_ptr);
+
+done:
+ if(addr_buf_ptr)
+ addr_buf_ptr = (haddr_t *)H5MM_xfree((void *)addr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__broadcast_clean_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__construct_candidate_list()
+ *
+ * Purpose: In the parallel case when the metadata_write_strategy is
+ * H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED, process 0 uses
+ * this function to construct the list of cache entries to
+ * be flushed. This list is then propagated to the other
+ * caches, and then flushed in a distributed fashion.
+ *
+ * The sync_point_op parameter is used to determine the extent
+ * of the flush.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__construct_candidate_list(H5AC_t *cache_ptr, H5AC_aux_t *aux_ptr,
+ int sync_point_op)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert((sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_CACHE) || (aux_ptr->mpi_rank == 0));
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+ HDassert(H5SL_count(aux_ptr->c_slist_ptr) == 0);
+ HDassert(aux_ptr->candidate_slist_ptr != NULL);
+ HDassert(H5SL_count(aux_ptr->candidate_slist_ptr) == 0);
+ HDassert((sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) || (sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_CACHE));
+
+ switch(sync_point_op) {
+ case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
+ if(H5C_construct_candidate_list__min_clean((H5C_t *)cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_construct_candidate_list__min_clean() failed.")
+ break;
+
+ case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
+ if(H5C_construct_candidate_list__clean_cache((H5C_t *)cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_construct_candidate_list__clean_cache() failed.")
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown sync point operation.")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__construct_candidate_list() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__copy_candidate_list_to_buffer_cb
+ *
+ * Purpose: Skip list callback for building array of addresses for
+ * broadcasting the candidate list.
+ *
+ * Return: Return SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: Quincey Koziol, 6/12/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__copy_candidate_list_to_buffer_cb(void *_item, void H5_ATTR_UNUSED *_key,
+ void *_udata)
+{
+ H5AC_slist_entry_t * slist_entry_ptr = (H5AC_slist_entry_t *)_item; /* Address of item */
+ H5AC_addr_list_ud_t * udata = (H5AC_addr_list_ud_t *)_udata; /* Context for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(slist_entry_ptr);
+ HDassert(udata);
+
+ /* Store the entry's address in the buffer */
+ udata->addr_buf_ptr[udata->u] = slist_entry_ptr->addr;
+ udata->u++;
+
+ /* now release the entry */
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__copy_candidate_list_to_buffer_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__copy_candidate_list_to_buffer
+ *
+ * Purpose: Allocate buffer(s) and copy the contents of the candidate
+ * entry slist into it (them). In passing, remove all
+ * entries from the candidate slist. Note that the
+ * candidate slist must not be empty.
+ *
+ * If MPI_Offset_buf_ptr_ptr is not NULL, allocate a buffer
+ * of MPI_Offset, copy the contents of the candidate
+ * entry list into it with the appropriate conversions,
+ * and return the base address of the buffer in
+ * *MPI_Offset_buf_ptr. Note that this is the buffer
+ * used by process 0 to transmit the list of entries to
+ * be flushed to all other processes (in this file group).
+ *
+ * Similarly, allocate a buffer of haddr_t, load the contents
+ * of the candidate list into this buffer, and return its
+ * base address in *haddr_buf_ptr_ptr. Note that this
+ * latter buffer is constructed unconditionally.
+ *
+ * In passing, also remove all entries from the candidate
+ * entry slist.
+ *
+ * Return: Return SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer, 4/19/10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__copy_candidate_list_to_buffer(const H5AC_t *cache_ptr, unsigned *num_entries_ptr,
+ haddr_t **haddr_buf_ptr_ptr)
+{
+ H5AC_aux_t * aux_ptr = NULL;
+ H5AC_addr_list_ud_t udata;
+ haddr_t * haddr_buf_ptr = NULL;
+ size_t buf_size;
+ unsigned num_entries = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert(aux_ptr->candidate_slist_ptr != NULL);
+ HDassert(H5SL_count(aux_ptr->candidate_slist_ptr) > 0);
+ HDassert(num_entries_ptr != NULL);
+ HDassert(*num_entries_ptr == 0);
+ HDassert(haddr_buf_ptr_ptr != NULL);
+ HDassert(*haddr_buf_ptr_ptr == NULL);
+
+ num_entries = (unsigned)H5SL_count(aux_ptr->candidate_slist_ptr);
+
+ /* allocate a buffer(s) to store the list of candidate entry
+ * base addresses in
+ */
+ buf_size = sizeof(haddr_t) * num_entries;
+ if(NULL == (haddr_buf_ptr = (haddr_t *)H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for haddr buffer")
+
+ /* Set up user data for callback */
+ udata.aux_ptr = aux_ptr;
+ udata.addr_buf_ptr = haddr_buf_ptr;
+ udata.u = 0;
+
+ /* Free all the candidate list entries, building the address list in the callback */
+ if(H5SL_free(aux_ptr->candidate_slist_ptr, H5AC__copy_candidate_list_to_buffer_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "Can't build address list for candidate entries")
+
+ /* Pass the number of entries and the buffer pointer
+ * back to the caller.
+ */
+ *num_entries_ptr = num_entries;
+ *haddr_buf_ptr_ptr = haddr_buf_ptr;
+
+done:
+ if(ret_value < 0)
+ if(haddr_buf_ptr)
+ haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__copy_candidate_list_to_buffer() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_deleted_entry()
+ *
+ * Purpose: Log an entry which has been deleted.
+ *
+ * Only called for mpi_rank 0. We must make sure that the entry
+ * doesn't appear in the cleaned or dirty entry lists.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 6/29/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_deleted_entry(const H5AC_info_t *entry_ptr)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ H5AC_slist_entry_t * slist_entry_ptr = NULL;
+ haddr_t addr;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ addr = entry_ptr->addr;
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank == 0);
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* if the entry appears in the dirtied entry slist, remove it. */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ /* if the entry appears in the cleaned entry slist, remove it. */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__log_deleted_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_dirtied_entry()
+ *
+ * Purpose: Update the dirty_bytes count for a newly dirtied entry.
+ *
+ * If mpi_rank isn't 0, this simply means adding the size
+ * of the entries to the dirty_bytes count.
+ *
+ * If mpi_rank is 0, we must first check to see if the entry
+ * appears in the dirty entries slist. If it is, do nothing.
+ * If it isn't, add the size to the dirty_bytes count, add the
+ * entry to the dirty entries slist, and remove it from the
+ * cleaned list (if it is present there).
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 6/29/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_dirtied_entry(const H5AC_info_t *entry_ptr)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->is_dirty == FALSE);
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ if(aux_ptr->mpi_rank == 0) {
+ H5AC_slist_entry_t *slist_entry_ptr;
+ haddr_t addr = entry_ptr->addr;
+
+ /* Sanity checks */
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ if(NULL == H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr))) {
+ /* insert the address of the entry in the dirty entry list, and
+ * add its size to the dirty_bytes count.
+ */
+ if(NULL == (slist_entry_ptr = H5FL_MALLOC(H5AC_slist_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate dirty slist entry .")
+ slist_entry_ptr->addr = addr;
+
+ if(H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist.")
+
+ aux_ptr->dirty_bytes += entry_ptr->size;
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->unprotect_dirty_bytes += entry_ptr->size;
+ aux_ptr->unprotect_dirty_bytes_updates += 1;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+ } /* end if */
+
+ /* the entry is dirty. If it exists on the cleaned entries list,
+ * remove it.
+ */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+ } /* end if */
+ else {
+ aux_ptr->dirty_bytes += entry_ptr->size;
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->unprotect_dirty_bytes += entry_size;
+ aux_ptr->unprotect_dirty_bytes_updates += 1;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__log_dirtied_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_cleaned_entry()
+ *
+ * Purpose: Treat this operation as a 'clear' and remove the entry
+ * from both the cleaned and dirtied lists if it is present.
+ * Reduces the dirty_bytes count by the size of the entry.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * 7/23/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_cleaned_entry(const H5AC_info_t *entry_ptr)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->is_dirty == FALSE);
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ if(aux_ptr->mpi_rank == 0) {
+ H5AC_slist_entry_t *slist_entry_ptr;
+ haddr_t addr = entry_ptr->addr;
+
+ /* Sanity checks */
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* Remove it from both the cleaned list and the dirtied list. */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ } /* end if */
+
+ /* Decrement the dirty byte count */
+ aux_ptr->dirty_bytes -= entry_ptr->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__log_cleaned_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_flushed_entry()
+ *
+ * Purpose: Update the clean entry slist for the flush of an entry --
+ * specifically, if the entry has been cleared, remove it
+ * from both the cleaned and dirtied lists if it is present.
+ * Otherwise, if the entry was dirty, insert the indicated
+ * entry address in the clean slist if it isn't there already.
+ *
+ * This function is only used in PHDF5, and should only
+ * be called for the process with mpi rank 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 6/29/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_flushed_entry(H5C_t *cache_ptr, haddr_t addr, hbool_t was_dirty,
+ unsigned flags)
+{
+ hbool_t cleared;
+ H5AC_aux_t * aux_ptr;
+ H5AC_slist_entry_t * slist_entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank == 0);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* Set local flags */
+ cleared = ((flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0);
+
+ if(cleared) {
+ /* If the entry has been cleared, must remove it from both the
+ * cleaned list and the dirtied list.
+ */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+ } /* end if */
+ else if(was_dirty) {
+ if(NULL == H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr))) {
+ /* insert the address of the entry in the clean entry list. */
+ if(NULL == (slist_entry_ptr = H5FL_MALLOC(H5AC_slist_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate clean slist entry .")
+ slist_entry_ptr->addr = addr;
+
+ if(H5SL_insert(aux_ptr->c_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into clean entry slist.")
+ } /* end if */
+ } /* end else-if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__log_flushed_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_inserted_entry()
+ *
+ * Purpose: Update the dirty_bytes count for a newly inserted entry.
+ *
+ * If mpi_rank isnt 0, this simply means adding the size
+ * of the entry to the dirty_bytes count.
+ *
+ * If mpi_rank is 0, we must also add the entry to the
+ * dirty entries slist.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 6/30/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_inserted_entry(const H5AC_info_t *entry_ptr)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ if(aux_ptr->mpi_rank == 0) {
+ H5AC_slist_entry_t *slist_entry_ptr;
+
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* Entry to insert should not be in dirty list currently */
+ if(NULL != H5SL_search(aux_ptr->d_slist_ptr, (const void *)(&entry_ptr->addr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Inserted entry already in dirty slist.")
+
+ /* insert the address of the entry in the dirty entry list, and
+ * add its size to the dirty_bytes count.
+ */
+ if(NULL == (slist_entry_ptr = H5FL_MALLOC(H5AC_slist_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate dirty slist entry .")
+ slist_entry_ptr->addr = entry_ptr->addr;
+ if(H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist.")
+
+ /* Entry to insert should not be in clean list either */
+ if(NULL != H5SL_search(aux_ptr->c_slist_ptr, (const void *)(&entry_ptr->addr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Inserted entry in clean slist.")
+ } /* end if */
+
+ aux_ptr->dirty_bytes += entry_ptr->size;
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->insert_dirty_bytes += size;
+ aux_ptr->insert_dirty_bytes_updates += 1;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__log_inserted_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__log_moved_entry()
+ *
+ * Purpose: Update the dirty_bytes count for a moved entry.
+ *
+ * WARNING
+ *
+ * At present, the way that the move call is used ensures
+ * that the moved entry is present in all caches by
+ * moving in a collective operation and immediately after
+ * unprotecting the target entry.
+ *
+ * This function uses this invariant, and will cause arcane
+ * failures if it is not met. If maintaining this invariant
+ * becomes impossible, we will have to rework this function
+ * extensively, and likely include a bit of IPC for
+ * synchronization. A better option might be to subsume
+ * move in the unprotect operation.
+ *
+ * Given that the target entry is in all caches, the function
+ * proceeds as follows:
+ *
+ * For processes with mpi rank other 0, it simply checks to
+ * see if the entry was dirty prior to the move, and adds
+ * the entries size to the dirty bytes count.
+ *
+ * In the process with mpi rank 0, the function first checks
+ * to see if the entry was dirty prior to the move. If it
+ * was, and if the entry doesn't appear in the dirtied list
+ * under its old address, it adds the entry's size to the
+ * dirty bytes count.
+ *
+ * The rank 0 process then removes any references to the
+ * entry under its old address from the cleands and dirtied
+ * lists, and inserts an entry in the dirtied list under the
+ * new address.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 6/30/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__log_moved_entry(const H5F_t *f, haddr_t old_addr, haddr_t new_addr)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ hbool_t entry_in_cache;
+ hbool_t entry_dirty;
+ size_t entry_size;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = (H5AC_t *)f->shared->cache;
+ HDassert(cache_ptr);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ /* get entry status, size, etc here */
+ if(H5C_get_entry_status(f, old_addr, &entry_size, &entry_in_cache,
+ &entry_dirty, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get entry status.")
+ if(!entry_in_cache)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry not in cache.")
+
+ if(aux_ptr->mpi_rank == 0) {
+ H5AC_slist_entry_t * slist_entry_ptr;
+
+ HDassert(aux_ptr->d_slist_ptr != NULL);
+ HDassert(aux_ptr->c_slist_ptr != NULL);
+
+ /* if the entry appears in the cleaned entry slist, under its old
+ * address, remove it.
+ */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&old_addr))))
+ slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
+
+ /* if the entry appears in the dirtied entry slist under its old
+ * address, remove it, but don't free it. Set addr to new_addr.
+ */
+ if(NULL != (slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&old_addr))))
+ slist_entry_ptr->addr = new_addr;
+ else {
+ /* otherwise, allocate a new entry that is ready
+ * for insertion, and increment dirty_bytes.
+ *
+ * Note that the fact that the entry wasn't in the dirtied
+ * list under its old address implies that it must have
+ * been clean to start with.
+ */
+ HDassert(!entry_dirty);
+ if(NULL == (slist_entry_ptr = H5FL_MALLOC(H5AC_slist_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate dirty slist entry .")
+ slist_entry_ptr->addr = new_addr;
+
+ aux_ptr->dirty_bytes += entry_size;
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->move_dirty_bytes += entry_size;
+ aux_ptr->move_dirty_bytes_updates += 1;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+ } /* end else */
+
+ /* insert / reinsert the entry in the dirty slist */
+ if(H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist.")
+ } /* end if */
+ else if(!entry_dirty) {
+ aux_ptr->dirty_bytes += entry_size;
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->move_dirty_bytes += entry_size;
+ aux_ptr->move_dirty_bytes_updates += 1;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+ } /* end else-if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__log_moved_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__propagate_and_apply_candidate_list
+ *
+ * Purpose: Prior to the addition of support for multiple metadata
+ * write strategies, in PHDF5, only the metadata cache with
+ * mpi rank 0 was allowed to write to file. All other
+ * metadata caches on processes with rank greater than 0
+ * were required to retain dirty entries until they were
+ * notified that the entry was clean.
+ *
+ * This constraint is relaxed with the distributed
+ * metadata write strategy, in which a list of candidate
+ * metadata cache entries is constructed by the process 0
+ * cache and then distributed to the caches of all the other
+ * processes. Once the listed is distributed, many (if not
+ * all) processes writing writing a unique subset of the
+ * entries, and marking the remainder clean. The subsets
+ * are chosen so that each entry in the list of candidates
+ * is written by exactly one cache, and all entries are
+ * marked as being clean in all caches.
+ *
+ * While the list of candidate cache entries is prepared
+ * elsewhere, this function is the main routine for distributing
+ * and applying the list. It must be run simultaniously on
+ * all processes that have the relevant file open. To ensure
+ * proper synchronization, there is a barrier at the beginning
+ * of this function.
+ *
+ * At present, this function is called under one of two
+ * circumstances:
+ *
+ * 1) Dirty byte creation exceeds some user specified value.
+ *
+ * While metadata reads may occur independently, all
+ * operations writing metadata must be collective. Thus
+ * all metadata caches see the same sequence of operations,
+ * and therefore the same dirty data creation.
+ *
+ * This fact is used to synchronize the caches for purposes
+ * of propagating the list of candidate entries, by simply
+ * calling this function from all caches whenever some user
+ * specified threshold on dirty data is exceeded. (the
+ * process 0 cache creates the candidate list just before
+ * calling this function).
+ *
+ * 2) Under direct user control -- this operation must be
+ * collective.
+ *
+ * The operations to be managed by this function are as
+ * follows:
+ *
+ * All processes:
+ *
+ * 1) Participate in an opening barrier.
+ *
+ * For the process with mpi rank 0:
+ *
+ * 1) Load the contents of the candidate list
+ * (candidate_slist_ptr) into a buffer, and broadcast that
+ * buffer to all the other caches. Clear the candidate
+ * list in passing.
+ *
+ * If there is a positive number of candidates, proceed with
+ * the following:
+ *
+ * 2) Apply the candidate entry list.
+ *
+ * 3) Particpate in a closing barrier.
+ *
+ * 4) Remove from the dirty list (d_slist_ptr) and from the
+ * flushed and still clean entries list (c_slist_ptr),
+ * all addresses that appeared in the candidate list, as
+ * these entries are now clean.
+ *
+ *
+ * For all processes with mpi rank greater than 0:
+ *
+ * 1) Receive the candidate entry list broadcast
+ *
+ * If there is a positive number of candidates, proceed with
+ * the following:
+ *
+ * 2) Apply the candidate entry list.
+ *
+ * 3) Particpate in a closing barrier.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__propagate_and_apply_candidate_list(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ haddr_t * candidates_list_ptr = NULL;
+ int mpi_result;
+ unsigned num_candidates = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+
+ /* to prevent "messages from the future" we must synchronize all
+ * processes before we write any entries.
+ */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ if(aux_ptr->mpi_rank == 0) {
+ if(H5AC__broadcast_candidate_list(cache_ptr, &num_candidates, &candidates_list_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't broadcast candidate slist.")
+
+ HDassert(H5SL_count(aux_ptr->candidate_slist_ptr) == 0);
+ } /* end if */
+ else {
+ if(H5AC__receive_candidate_list(cache_ptr, &num_candidates, &candidates_list_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't receive candidate broadcast.")
+ } /* end else */
+
+ if(num_candidates > 0) {
+ herr_t result;
+
+ /* all processes apply the candidate list.
+ * H5C_apply_candidate_list() handles the details of
+ * distributing the writes across the processes.
+ */
+
+ /* Enable writes during this operation */
+ aux_ptr->write_permitted = TRUE;
+
+ /* Apply the candidate list */
+ result = H5C_apply_candidate_list(f, dxpl_id, cache_ptr, num_candidates,
+ candidates_list_ptr, aux_ptr->mpi_rank, aux_ptr->mpi_size);
+
+ /* Disable writes again */
+ aux_ptr->write_permitted = FALSE;
+
+ /* Check for error on the write operation */
+ if(result < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't apply candidate list.")
+
+ /* this code exists primarily for the test bed -- it allows us to
+ * enforce posix semantics on the server that pretends to be a
+ * file system in our parallel tests.
+ */
+ if(aux_ptr->write_done)
+ (aux_ptr->write_done)();
+
+ /* to prevent "messages from the past" we must synchronize all
+ * processes again before we go on.
+ */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ /* if this is process zero, tidy up the dirtied,
+ * and flushed and still clean lists.
+ */
+ if(aux_ptr->mpi_rank == 0)
+ if(H5AC__tidy_cache_0_lists(cache_ptr, num_candidates, candidates_list_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't tidy up process 0 lists.")
+ } /* end if */
+
+ /* if it is defined, call the sync point done callback. Note
+ * that this callback is defined purely for testing purposes,
+ * and should be undefined under normal operating circumstances.
+ */
+ if(aux_ptr->sync_point_done)
+ (aux_ptr->sync_point_done)(num_candidates, candidates_list_ptr);
+
+done:
+ if(candidates_list_ptr)
+ candidates_list_ptr = (haddr_t *)H5MM_xfree((void *)candidates_list_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__propagate_and_apply_candidate_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__propagate_flushed_and_still_clean_entries_list
+ *
+ * Purpose: In PHDF5, if the process 0 only metadata write strategy
+ * is selected, only the metadata cache with mpi rank 0 is
+ * allowed to write to file. All other metadata caches on
+ * processes with rank greater than 0 must retain dirty
+ * entries until they are notified that the entry is now
+ * clean.
+ *
+ * This function is the main routine for handling this
+ * notification proceedure. It must be called
+ * simultaniously on all processes that have the relevant
+ * file open. To this end, it is called only during a
+ * sync point, with a barrier prior to the call.
+ *
+ * Note that any metadata entry writes by process 0 will
+ * occur after the barrier and just before this call.
+ *
+ * Typicaly, calls to this function will be triggered in
+ * one of two ways:
+ *
+ * 1) Dirty byte creation exceeds some user specified value.
+ *
+ * While metadata reads may occur independently, all
+ * operations writing metadata must be collective. Thus
+ * all metadata caches see the same sequence of operations,
+ * and therefore the same dirty data creation.
+ *
+ * This fact is used to synchronize the caches for purposes
+ * of propagating the list of flushed and still clean
+ * entries, by simply calling this function from all
+ * caches whenever some user specified threshold on dirty
+ * data is exceeded.
+ *
+ * 2) Under direct user control -- this operation must be
+ * collective.
+ *
+ * The operations to be managed by this function are as
+ * follows:
+ *
+ * For the process with mpi rank 0:
+ *
+ * 1) Load the contents of the flushed and still clean entries
+ * list (c_slist_ptr) into a buffer, and broadcast that
+ * buffer to all the other caches.
+ *
+ * 2) Clear the flushed and still clean entries list
+ * (c_slist_ptr).
+ *
+ *
+ * For all processes with mpi rank greater than 0:
+ *
+ * 1) Receive the flushed and still clean entries list broadcast
+ *
+ * 2) Mark the specified entries as clean.
+ *
+ *
+ * For all processes:
+ *
+ * 1) Reset the dirtied bytes count to 0.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * July 5, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__propagate_flushed_and_still_clean_entries_list(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY);
+
+ if(aux_ptr->mpi_rank == 0) {
+ if(H5AC__broadcast_clean_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't broadcast clean slist.")
+ HDassert(H5SL_count(aux_ptr->c_slist_ptr) == 0);
+ } /* end if */
+ else {
+ if(H5AC__receive_and_apply_clean_list(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't receive and/or process clean slist broadcast.")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__propagate_flushed_and_still_clean_entries_list() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_receive_haddr_list()
+ *
+ * Purpose: Receive the list of entry addresses from process 0,
+ * and return it in a buffer pointed to by *haddr_buf_ptr_ptr.
+ * Note that the caller must free this buffer if it is
+ * returned.
+ *
+ * This function must only be called by the process with
+ * MPI_rank greater than 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: Quincey Koziol, 6/11/2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__receive_haddr_list(MPI_Comm mpi_comm, unsigned *num_entries_ptr,
+ haddr_t **haddr_buf_ptr_ptr)
+{
+ haddr_t * haddr_buf_ptr = NULL;
+ int mpi_result;
+ unsigned num_entries;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(num_entries_ptr != NULL);
+ HDassert(*num_entries_ptr == 0);
+ HDassert(haddr_buf_ptr_ptr != NULL);
+ HDassert(*haddr_buf_ptr_ptr == NULL);
+
+ /* First receive the number of entries in the list so that we
+ * can set up a buffer to receive them. If there aren't
+ * any, we are done.
+ */
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_UNSIGNED, 0, mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ if(num_entries > 0) {
+ size_t buf_size;
+
+ /* allocate buffers to store the list of entry base addresses in */
+ buf_size = sizeof(haddr_t) * num_entries;
+ if(NULL == (haddr_buf_ptr = (haddr_t *)H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for haddr buffer")
+
+ /* Now receive the list of candidate entries */
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)haddr_buf_ptr, (int)buf_size, MPI_BYTE, 0, mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+ } /* end if */
+
+ /* finally, pass the number of entries and the buffer pointer
+ * back to the caller.
+ */
+ *num_entries_ptr = num_entries;
+ *haddr_buf_ptr_ptr = haddr_buf_ptr;
+
+done:
+ if(ret_value < 0)
+ if(haddr_buf_ptr)
+ haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_receive_haddr_list() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__receive_and_apply_clean_list()
+ *
+ * Purpose: Receive the list of cleaned entries from process 0,
+ * and mark the specified entries as clean.
+ *
+ * This function must only be called by the process with
+ * MPI_rank greater than 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 7/4/05
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ haddr_t * haddr_buf_ptr = NULL;
+ unsigned num_entries = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank != 0);
+
+ /* Retrieve the clean list from process 0 */
+ if(H5AC__receive_haddr_list(aux_ptr->mpi_comm, &num_entries, &haddr_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't receive clean list")
+
+ if(num_entries > 0)
+ /* mark the indicated entries as clean */
+ if(H5C_mark_entries_as_clean(f, dxpl_id, num_entries, haddr_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't mark entries clean.")
+
+ /* if it is defined, call the sync point done callback. Note
+ * that this callback is defined purely for testing purposes,
+ * and should be undefined under normal operating circumstances.
+ */
+ if(aux_ptr->sync_point_done)
+ (aux_ptr->sync_point_done)(num_entries, haddr_buf_ptr);
+
+done:
+ if(haddr_buf_ptr)
+ haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__receive_and_apply_clean_list() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC__receive_candidate_list()
+ *
+ * Purpose: Receive the list of candidate entries from process 0,
+ * and return it in a buffer pointed to by *haddr_buf_ptr_ptr.
+ * Note that the caller must free this buffer if it is
+ * returned.
+ *
+ * This function must only be called by the process with
+ * MPI_rank greater than 0.
+ *
+ * Return SUCCEED on success, and FAIL on failure.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__receive_candidate_list(const H5AC_t *cache_ptr, unsigned *num_entries_ptr,
+ haddr_t **haddr_buf_ptr_ptr)
+{
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->mpi_rank != 0);
+ HDassert(aux_ptr-> metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert(num_entries_ptr != NULL);
+ HDassert(*num_entries_ptr == 0);
+ HDassert(haddr_buf_ptr_ptr != NULL);
+ HDassert(*haddr_buf_ptr_ptr == NULL);
+
+ /* Retrieve the candidate list from process 0 */
+ if(H5AC__receive_haddr_list(aux_ptr->mpi_comm, num_entries_ptr, haddr_buf_ptr_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't receive clean list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__receive_candidate_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__rsp__dist_md_write__flush
+ *
+ * Purpose: Routine for handling the details of running a sync point
+ * that is triggered by a flush -- which in turn must have been
+ * triggered by either a flush API call or a file close --
+ * when the distributed metadata write strategy is selected.
+ *
+ * Upon entry, each process generates it own candidate list,
+ * being a sorted list of all dirty metadata entries currently
+ * in the metadata cache. Note that this list must be idendical
+ * across all processes, as all processes see the same stream
+ * of dirty metadata coming in, and use the same lists of
+ * candidate entries at each sync point. (At first glance, this
+ * argument sounds circular, but think of it in the sense of
+ * a recursive proof).
+ *
+ * If this this list is empty, we are done, and the function
+ * returns
+ *
+ * Otherwise, after the sorted list dirty metadata entries is
+ * constructed, each process uses the same algorithm to assign
+ * each entry on the candidate list to exactly one process for
+ * flushing.
+ *
+ * At this point, all processes participate in a barrier to
+ * avoid messages from the past/future bugs.
+ *
+ * Each process then flushes the entries assigned to it, and
+ * marks all other entries on the candidate list as clean.
+ *
+ * Finally, all processes participate in a second barrier to
+ * avoid messages from the past/future bugs.
+ *
+ * At the end of this process, process 0 and only process 0
+ * must tidy up its lists of dirtied and cleaned entries.
+ * These lists are not used in the distributed metadata write
+ * strategy, but they must be maintained should we shift
+ * to a strategy that uses them.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * April 28, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__rsp__dist_md_write__flush(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ haddr_t * haddr_buf_ptr = NULL;
+ int mpi_result;
+ unsigned num_entries = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+
+ /* first construct the candidate list -- initially, this will be in the
+ * form of a skip list. We will convert it later.
+ */
+ if(H5C_construct_candidate_list__clean_cache(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate list.")
+
+ if(H5SL_count(aux_ptr->candidate_slist_ptr) > 0) {
+ herr_t result;
+
+ /* convert the candidate list into the format we
+ * are used to receiving from process 0.
+ */
+ if(H5AC__copy_candidate_list_to_buffer(cache_ptr, &num_entries, &haddr_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate buffer.")
+
+ /* initial sync point barrier */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ /* Enable writes during this operation */
+ aux_ptr->write_permitted = TRUE;
+
+ /* Apply the candidate list */
+ result = H5C_apply_candidate_list(f, dxpl_id, cache_ptr, num_entries,
+ haddr_buf_ptr, aux_ptr->mpi_rank, aux_ptr->mpi_size);
+
+ /* Disable writes again */
+ aux_ptr->write_permitted = FALSE;
+
+ /* Check for error on the write operation */
+ if(result < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't apply candidate list.")
+
+ /* this code exists primarily for the test bed -- it allows us to
+ * enforce posix semantics on the server that pretends to be a
+ * file system in our parallel tests.
+ */
+ if(aux_ptr->write_done)
+ (aux_ptr->write_done)();
+
+ /* final sync point barrier */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ /* if this is process zero, tidy up the dirtied,
+ * and flushed and still clean lists.
+ */
+ if(aux_ptr->mpi_rank == 0)
+ if(H5AC__tidy_cache_0_lists(cache_ptr, num_entries, haddr_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't tidy up process 0 lists.")
+ } /* end if */
+
+ /* if it is defined, call the sync point done callback. Note
+ * that this callback is defined purely for testing purposes,
+ * and should be undefined under normal operating circumstances.
+ */
+ if(aux_ptr->sync_point_done)
+ (aux_ptr->sync_point_done)(num_entries, haddr_buf_ptr);
+
+done:
+ if(haddr_buf_ptr)
+ haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__rsp__dist_md_write__flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__rsp__dist_md_write__flush_to_min_clean
+ *
+ * Purpose: Routine for handling the details of running a sync point
+ * triggered by the accumulation of dirty metadata (as
+ * opposed to a flush call to the API) when the distributed
+ * metadata write strategy is selected.
+ *
+ * After invocation and initial sanity checking this function
+ * first checks to see if evictions are enabled -- if they
+ * are not, the function does nothing and returns.
+ *
+ * Otherwise, process zero constructs a list of entries to
+ * be flushed in order to bring the process zero cache back
+ * within its min clean requirement. Note that this list
+ * (the candidate list) may be empty.
+ *
+ * Then, all processes participate in a barrier.
+ *
+ * After the barrier, process 0 broadcasts the number of
+ * entries in the candidate list prepared above, and all
+ * other processes receive this number.
+ *
+ * If this number is zero, we are done, and the function
+ * returns without further action.
+ *
+ * Otherwise, process 0 broadcasts the sorted list of
+ * candidate entries, and all other processes receive it.
+ *
+ * Then, each process uses the same algorithm to assign
+ * each entry on the candidate list to exactly one process
+ * for flushing.
+ *
+ * Each process then flushes the entries assigned to it, and
+ * marks all other entries on the candidate list as clean.
+ *
+ * Finally, all processes participate in a second barrier to
+ * avoid messages from the past/future bugs.
+ *
+ * At the end of this process, process 0 and only process 0
+ * must tidy up its lists of dirtied and cleaned entries.
+ * These lists are not used in the distributed metadata write
+ * strategy, but they must be maintained should we shift
+ * to a strategy that uses them.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * April 28, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__rsp__dist_md_write__flush_to_min_clean(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ hbool_t evictions_enabled;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+
+ /* Query if evictions are allowed */
+ if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_get_evictions_enabled() failed.")
+
+ if(evictions_enabled) {
+ /* construct candidate list -- process 0 only */
+ if(aux_ptr->mpi_rank == 0)
+ if(H5AC__construct_candidate_list(cache_ptr, aux_ptr, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate list.")
+
+ /* propagate and apply candidate list -- all processes */
+ if(H5AC__propagate_and_apply_candidate_list(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate and apply candidate list.")
+ } /* evictions enabled */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__rsp__dist_md_write__flush_to_min_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__rsp__p0_only__flush
+ *
+ * Purpose: Routine for handling the details of running a sync point
+ * that is triggered a flush -- which in turn must have been
+ * triggered by either a flush API call or a file close --
+ * when the process 0 only metadata write strategy is selected.
+ *
+ * First, all processes participate in a barrier.
+ *
+ * Then process zero flushes all dirty entries, and broadcasts
+ * they number of clean entries (if any) to all the other
+ * caches.
+ *
+ * If this number is zero, we are done.
+ *
+ * Otherwise, process 0 broadcasts the list of cleaned
+ * entries, and all other processes which are part of this
+ * file group receive it, and mark the listed entries as
+ * clean in their caches.
+ *
+ * Since all processes have the same set of dirty
+ * entries at the beginning of the sync point, and all
+ * entries that will be written are written before
+ * process zero broadcasts the number of cleaned entries,
+ * there is no need for a closing barrier.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * April 28, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__rsp__p0_only__flush(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ int mpi_result;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY);
+
+ /* to prevent "messages from the future" we must
+ * synchronize all processes before we start the flush.
+ * Hence the following barrier.
+ */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ /* Flush data to disk, from rank 0 process */
+ if(aux_ptr->mpi_rank == 0) {
+ herr_t result;
+
+ /* Enable writes during this operation */
+ aux_ptr->write_permitted = TRUE;
+
+ /* Flush the cache */
+ result = H5C_flush_cache(f, dxpl_id, H5AC__NO_FLAGS_SET);
+
+ /* Disable writes again */
+ aux_ptr->write_permitted = FALSE;
+
+ /* Check for error on the write operation */
+ if(result < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush.")
+
+ /* this code exists primarily for the test bed -- it allows us to
+ * enforce posix semantics on the server that pretends to be a
+ * file system in our parallel tests.
+ */
+ if(aux_ptr->write_done)
+ (aux_ptr->write_done)();
+ } /* end if */
+
+ /* Propagate cleaned entries to other ranks. */
+ if(H5AC__propagate_flushed_and_still_clean_entries_list(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate clean entries list.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__rsp__p0_only__flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__rsp__p0_only__flush_to_min_clean
+ *
+ * Purpose: Routine for handling the details of running a sync point
+ * triggered by the accumulation of dirty metadata (as
+ * opposed to a flush call to the API) when the process 0
+ * only metadata write strategy is selected.
+ *
+ * After invocation and initial sanity checking this function
+ * first checks to see if evictions are enabled -- if they
+ * are not, the function does nothing and returns.
+ *
+ * Otherwise, all processes participate in a barrier.
+ *
+ * After the barrier, if this is process 0, the function
+ * causes the cache to flush sufficient entries to get the
+ * cache back within its minimum clean fraction, and broadcast
+ * the number of entries which have been flushed since
+ * the last sync point, and are still clean.
+ *
+ * If this number is zero, we are done.
+ *
+ * Otherwise, process 0 broadcasts the list of cleaned
+ * entries, and all other processes which are part of this
+ * file group receive it, and mark the listed entries as
+ * clean in their caches.
+ *
+ * Since all processes have the same set of dirty
+ * entries at the beginning of the sync point, and all
+ * entries that will be written are written before
+ * process zero broadcasts the number of cleaned entries,
+ * there is no need for a closing barrier.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * April 28, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__rsp__p0_only__flush_to_min_clean(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ hbool_t evictions_enabled;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY);
+
+ /* Query if evictions are allowed */
+ if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_get_evictions_enabled() failed.")
+
+ /* Flush if evictions are allowed -- following call
+ * will cause process 0 to flush to min clean size,
+ * and then propagate the newly clean entries to the
+ * other processes.
+ *
+ * Otherwise, do nothing.
+ */
+ if(evictions_enabled) {
+ int mpi_result;
+
+ /* to prevent "messages from the future" we must synchronize all
+ * processes before we start the flush. This synchronization may
+ * already be done -- hence the do_barrier parameter.
+ */
+ if(MPI_SUCCESS != (mpi_result = MPI_Barrier(aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_result)
+
+ if(0 == aux_ptr->mpi_rank) {
+ herr_t result;
+
+ /* here, process 0 flushes as many entries as necessary to
+ * comply with the currently specified min clean size.
+ * Note that it is quite possible that no entries will be
+ * flushed.
+ */
+
+ /* Enable writes during this operation */
+ aux_ptr->write_permitted = TRUE;
+
+ /* Flush the cache */
+ result = H5C_flush_to_min_clean(f, dxpl_id);
+
+ /* Disable writes again */
+ aux_ptr->write_permitted = FALSE;
+
+ /* Check for error on the write operation */
+ if(result < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_flush_to_min_clean() failed.")
+
+ /* this call exists primarily for the test code -- it is used
+ * to enforce POSIX semantics on the process used to simulate
+ * reads and writes in t_cache.c.
+ */
+ if(aux_ptr->write_done)
+ (aux_ptr->write_done)();
+ } /* end if */
+
+ if(H5AC__propagate_flushed_and_still_clean_entries_list(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate clean entries list.")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__rsp__p0_only__flush_to_min_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__run_sync_point
+ *
+ * Purpose: Top level routine for managing a sync point between all
+ * meta data caches in the parallel case. Since all caches
+ * see the same sequence of dirty metadata, we simply count
+ * bytes of dirty metadata, and run a sync point whenever the
+ * number of dirty bytes of metadata seen since the last
+ * sync point exceeds a threshold that is common across all
+ * processes. We also run sync points in response to
+ * HDF5 API calls triggering either a flush or a file close.
+ *
+ * In earlier versions of PHDF5, only the metadata cache with
+ * mpi rank 0 was allowed to write to file. All other
+ * metadata caches on processes with rank greater than 0 were
+ * required to retain dirty entries until they were notified
+ * that the entry is was clean.
+ *
+ * This function was created to make it easier for us to
+ * experiment with other options, as it is a single point
+ * for the execution of sync points.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * March 11, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__run_sync_point(H5F_t *f, hid_t dxpl_id, int sync_point_op)
+{
+ H5AC_t * cache_ptr;
+ H5AC_aux_t * aux_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert((sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) ||
+ (sync_point_op == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED));
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+HDfprintf(stdout, "%d:H5AC_propagate...:%u: (u/uu/i/iu/r/ru) = %zu/%u/%zu/%u/%zu/%u\n",
+ aux_ptr->mpi_rank,
+ aux_ptr->dirty_bytes_propagations,
+ aux_ptr->unprotect_dirty_bytes,
+ aux_ptr->unprotect_dirty_bytes_updates,
+ aux_ptr->insert_dirty_bytes,
+ aux_ptr->insert_dirty_bytes_updates,
+ aux_ptr->rename_dirty_bytes,
+ aux_ptr->rename_dirty_bytes_updates);
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+
+ /* clear collective access flag on half of the entries in the
+ cache and mark them as independent in case they need to be
+ evicted later. All ranks are guranteed to mark the same entries
+ since we don't modify the order of the collectively accessed
+ entries except through collective access. */
+ if(H5C_clear_coll_entries(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_clear_coll_entries() failed.")
+
+ switch(aux_ptr->metadata_write_strategy) {
+ case H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY:
+ switch(sync_point_op) {
+ case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
+ if(H5AC__rsp__p0_only__flush_to_min_clean(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC__rsp__p0_only__flush_to_min_clean() failed.")
+ break;
+
+ case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
+ if(H5AC__rsp__p0_only__flush(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC__rsp__p0_only__flush() failed.")
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown flush op");
+ break;
+ } /* end switch */
+ break;
+
+ case H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED:
+ switch(sync_point_op) {
+ case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
+ if(H5AC__rsp__dist_md_write__flush_to_min_clean(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC__rsp__dist_md_write__flush_to_min_clean() failed.")
+ break;
+
+ case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
+ if(H5AC__rsp__dist_md_write__flush(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC__rsp__dist_md_write__flush() failed.")
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown flush op");
+ break;
+ } /* end switch */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown metadata write strategy.")
+ break;
+ } /* end switch */
+
+ /* reset the dirty bytes count */
+ aux_ptr->dirty_bytes = 0;
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+ aux_ptr->dirty_bytes_propagations += 1;
+ aux_ptr->unprotect_dirty_bytes = 0;
+ aux_ptr->unprotect_dirty_bytes_updates = 0;
+ aux_ptr->insert_dirty_bytes = 0;
+ aux_ptr->insert_dirty_bytes_updates = 0;
+ aux_ptr->rename_dirty_bytes = 0;
+ aux_ptr->rename_dirty_bytes_updates = 0;
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__run_sync_point() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__tidy_cache_0_lists()
+ *
+ * Purpose: In the distributed metadata write strategy, not all dirty
+ * entries are written by process 0 -- thus we must tidy
+ * up the dirtied, and flushed and still clean lists
+ * maintained by process zero after each sync point.
+ *
+ * This procedure exists to tend to this issue.
+ *
+ * At this point, all entries that process 0 cleared should
+ * have been removed from both the dirty and flushed and
+ * still clean lists, and entries that process 0 has flushed
+ * should have been removed from the dirtied list and added
+ * to the flushed and still clean list.
+ *
+ * However, since the distributed metadata write strategy
+ * doesn't make use of these lists, the objective is simply
+ * to maintain these lists in consistent state that allows
+ * them to be used should the metadata write strategy change
+ * to one that uses these lists.
+ *
+ * Thus for our purposes, all we need to do is remove from
+ * the dirtied and flushed and still clean lists all
+ * references to entries that appear in the candidate list.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * 4/20/10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__tidy_cache_0_lists(H5AC_t *cache_ptr, unsigned num_candidates,
+ haddr_t *candidates_list_ptr)
+{
+ H5AC_aux_t * aux_ptr;
+ unsigned u;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr);
+ HDassert(aux_ptr != NULL);
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ HDassert(aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED);
+ HDassert(aux_ptr->mpi_rank == 0);
+ HDassert(num_candidates > 0);
+ HDassert(candidates_list_ptr != NULL);
+
+ /* clean up dirtied and flushed and still clean lists by removing
+ * all entries on the candidate list. Cleared entries should
+ * have been removed from both the dirty and cleaned lists at
+ * this point, flushed entries should have been added to the
+ * cleaned list. However, for this metadata write strategy,
+ * we just want to remove all references to the candidate entries.
+ */
+ for(u = 0; u < num_candidates; u++) {
+ H5AC_slist_entry_t * d_slist_entry_ptr;
+ H5AC_slist_entry_t * c_slist_entry_ptr;
+ haddr_t addr;
+
+ addr = candidates_list_ptr[u];
+
+ /* addr may be either on the dirtied list, or on the flushed
+ * and still clean list. Remove it.
+ */
+ if(NULL != (d_slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->d_slist_ptr, (void *)&addr)))
+ d_slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, d_slist_entry_ptr);
+ if(NULL != (c_slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_remove(aux_ptr->c_slist_ptr, (void *)&addr)))
+ c_slist_entry_ptr = H5FL_FREE(H5AC_slist_entry_t, c_slist_entry_ptr);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5AC__tidy_cache_0_lists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__flush_entries
+ *
+ * Purpose: Flush the metadata cache associated with the specified file,
+ * only writing from rank 0, but propagating the cleaned entries
+ * to all ranks.
+ *
+ * Return: Non-negative on success/Negative on failure if there was a
+ * request to flush all items and something was protected.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 22 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC__flush_entries(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared->cache);
+
+ /* Check if we have >1 ranks */
+ if(H5C_get_aux_ptr(f->shared->cache))
+ if(H5AC__run_sync_point(f, dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_CACHE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__flush_entries() */
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5ACpkg.h b/src/H5ACpkg.h
new file mode 100644
index 0000000..ea7f0bf
--- /dev/null
+++ b/src/H5ACpkg.h
@@ -0,0 +1,506 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: John Mainzer -- 4/19/06
+ *
+ * Purpose: This file contains declarations which are normally visible
+ * only within the H5AC package (just H5AC.c at present).
+ *
+ * Source files outside the H5AC package should include
+ * H5ACprivate.h instead.
+ *
+ * The one exception to this rule is testpar/t_cache.c. The
+ * test code is easier to write if it can look at H5AC_aux_t.
+ * Indeed, this is the main reason why this file was created.
+ *
+ */
+
+#if !(defined H5AC_FRIEND || defined H5AC_MODULE)
+#error "Do not include this file outside the H5AC package!"
+#endif
+
+#ifndef _H5ACpkg_H
+#define _H5ACpkg_H
+
+/* Get package's private header */
+#include "H5ACprivate.h" /* Metadata cache */
+
+
+/* Get needed headers */
+#include "H5Cprivate.h" /* Cache */
+#include "H5FLprivate.h" /* Free Lists */
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage the H5AC_aux_t struct */
+H5FL_EXTERN(H5AC_aux_t);
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+#define H5AC_DEBUG_DIRTY_BYTES_CREATION 0
+
+#ifdef H5_HAVE_PARALLEL
+
+/* the following #defined are used to specify the operation required
+ * at a sync point.
+ */
+
+#define H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN 0
+#define H5AC_SYNC_POINT_OP__FLUSH_CACHE 1
+
+#endif /* H5_HAVE_PARALLEL */
+
+/*-------------------------------------------------------------------------
+ * It is a bit difficult to set ranges of allowable values on the
+ * dirty_bytes_threshold field of H5AC_aux_t. The following are
+ * probably broader than they should be.
+ *-------------------------------------------------------------------------
+ */
+
+#define H5AC__MIN_DIRTY_BYTES_THRESHOLD (size_t) \
+ (H5C__MIN_MAX_CACHE_SIZE / 2)
+#define H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD (256 * 1024)
+#define H5AC__MAX_DIRTY_BYTES_THRESHOLD (size_t) \
+ (H5C__MAX_MAX_CACHE_SIZE / 4)
+
+
+/****************************************************************************
+ *
+ * structure H5AC_aux_t
+ *
+ * While H5AC has become a wrapper for the cache implemented in H5C.c, there
+ * are some features of the metadata cache that are specific to it, and which
+ * therefore do not belong in the more generic H5C cache code.
+ *
+ * In particular, there is the matter of synchronizing writes from the
+ * metadata cache to disk in the PHDF5 case.
+ *
+ * Prior to this update, the presumption was that all metadata caches would
+ * write the same data at the same time since all operations modifying
+ * metadata must be performed collectively. Given this assumption, it was
+ * safe to allow only the writes from process 0 to actually make it to disk,
+ * while metadata writes from all other processes were discarded.
+ *
+ * Unfortunately, this presumption is in error as operations that read
+ * metadata need not be collective, but can change the location of dirty
+ * entries in the metadata cache LRU lists. This can result in the same
+ * metadata write operation triggering writes from the metadata caches on
+ * some processes, but not all (causing a hang), or in different sets of
+ * entries being written from different caches (potentially resulting in
+ * metadata corruption in the file).
+ *
+ * To deal with this issue, I decided to apply a paradigm shift to the way
+ * metadata is written to disk.
+ *
+ * With this set of changes, only the metadata cache on process 0 is able
+ * to write metadata to disk, although metadata caches on all other
+ * processes can read metadata from disk as before.
+ *
+ * To keep all the other caches from getting plugged up with dirty metadata,
+ * process 0 periodically broadcasts a list of entries that it has flushed
+ * since that last notice, and which are currently clean. The other caches
+ * mark these entries as clean as well, which allows them to evict the
+ * entries as needed.
+ *
+ * One obvious problem in this approach is synchronizing the broadcasts
+ * and receptions, as different caches may see different amounts of
+ * activity.
+ *
+ * The current solution is for the caches to track the number of bytes
+ * of newly generated dirty metadata, and to broadcast and receive
+ * whenever this value exceeds some user specified threshold.
+ *
+ * Maintaining this count is easy for all processes not on process 0 --
+ * all that is necessary is to add the size of the entry to the total
+ * whenever there is an insertion, a move of a previously clean entry,
+ * or whever a previously clean entry is marked dirty in an unprotect.
+ *
+ * On process 0, we have to be careful not to count dirty bytes twice.
+ * If an entry is marked dirty, flushed, and marked dirty again, all
+ * within a single reporting period, it only th first marking should
+ * be added to the dirty bytes generated tally, as that is all that
+ * the other processes will see.
+ *
+ * At present, this structure exists to maintain the fields needed to
+ * implement the above scheme, and thus is only used in the parallel
+ * case. However, other uses may arise in the future.
+ *
+ * Instance of this structure are associated with metadata caches via
+ * the aux_ptr field of H5C_t (see H5Cpkg.h). The H5AC code is
+ * responsible for allocating, maintaining, and discarding instances
+ * of H5AC_aux_t.
+ *
+ * The remainder of this header comments documents the individual fields
+ * of the structure.
+ *
+ * JRM - 6/27/05
+ *
+ * Update: When the above was written, I planned to allow the process
+ * 0 metadata cache to write dirty metadata between sync points.
+ * However, testing indicated that this allowed occasional
+ * messages from the future to reach the caches on other processes.
+ *
+ * To resolve this, the code was altered to require that all metadata
+ * writes take place during sync points -- which solved the problem.
+ * Initially all writes were performed by the process 0 cache. This
+ * approach was later replaced with a distributed write approach
+ * in which each process writes a subset of the metadata to be
+ * written.
+ *
+ * After thinking on the matter for a while, I arrived at the
+ * conclusion that the process 0 cache could be allowed to write
+ * dirty metadata between sync points if it restricted itself to
+ * entries that had been dirty at the time of the previous sync point.
+ *
+ * To date, there has been no attempt to implement this optimization.
+ * However, should it be attempted, much of the supporting code
+ * should still be around.
+ *
+ * JRM -- 1/6/15
+ *
+ * magic: Unsigned 32 bit integer always set to
+ * H5AC__H5AC_AUX_T_MAGIC. This field is used to validate
+ * pointers to instances of H5AC_aux_t.
+ *
+ * mpi_comm: MPI communicator associated with the file for which the
+ * cache has been created.
+ *
+ * mpi_rank: MPI rank of this process within mpi_comm.
+ *
+ * mpi_size: Number of processes in mpi_comm.
+ *
+ * write_permitted: Boolean flag used to control whether the cache
+ * is permitted to write to file.
+ *
+ * dirty_bytes_threshold: Integer field containing the dirty bytes
+ * generation threashold. Whenever dirty byte creation
+ * exceeds this value, the metadata cache on process 0
+ * broadcasts a list of the entries it has flushed since
+ * the last broadcast (or since the beginning of execution)
+ * and which are currently clean (if they are still in the
+ * cache)
+ *
+ * Similarly, metadata caches on processes other than process
+ * 0 will attempt to receive a list of clean entries whenever
+ * the threshold is exceeded.
+ *
+ * dirty_bytes: Integer field containing the number of bytes of dirty
+ * metadata generated since the beginning of the computation,
+ * or (more typically) since the last clean entries list
+ * broadcast. This field is reset to zero after each such
+ * broadcast.
+ *
+ * metadata_write_strategy: Integer code indicating how we will be
+ * writing the metadata. In the first incarnation of
+ * this code, all writes were done from process 0. This
+ * field exists to facilitate experiments with other
+ * strategies.
+ *
+ * At present, this field must be set to either
+ * H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY or
+ * H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED.
+ *
+ * dirty_bytes_propagations: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of times the cleaned list
+ * has been propagated from process 0 to the other
+ * processes.
+ *
+ * unprotect_dirty_bytes: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of dirty bytes created
+ * via unprotect operations since the last time the cleaned
+ * list was propagated.
+ *
+ * unprotect_dirty_bytes_updates: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of times dirty bytes have
+ * been created via unprotect operations since the last time
+ * the cleaned list was propagated.
+ *
+ * insert_dirty_bytes: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of dirty bytes created
+ * via insert operations since the last time the cleaned
+ * list was propagated.
+ *
+ * insert_dirty_bytes_updates: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of times dirty bytes have
+ * been created via insert operations since the last time
+ * the cleaned list was propagated.
+ *
+ * move_dirty_bytes: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of dirty bytes created
+ * via move operations since the last time the cleaned
+ * list was propagated.
+ *
+ * move_dirty_bytes_updates: This field only exists when the
+ * H5AC_DEBUG_DIRTY_BYTES_CREATION #define is TRUE.
+ *
+ * It is used to track the number of times dirty bytes have
+ * been created via move operations since the last time
+ * the cleaned list was propagated.
+ *
+ * Things have changed a bit since the following four fields were defined.
+ * If metadata_write_strategy is H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY,
+ * all comments hold as before -- with the caviate that pending further
+ * coding, the process 0 metadata cache is forbidden to flush entries outside
+ * of a sync point.
+ *
+ * However, for different metadata write strategies, these fields are used
+ * only to maintain the correct dirty byte count on process zero -- and in
+ * most if not all cases, this is redundant, as process zero will be barred
+ * from flushing entries outside of a sync point.
+ *
+ * JRM -- 3/16/10
+ *
+ * d_slist_ptr: Pointer to an instance of H5SL_t used to maintain a list
+ * of entries that have been dirtied since the last time they
+ * were listed in a clean entries broadcast. This list is
+ * only maintained by the metadata cache on process 0 -- it
+ * it used to maintain a view of the dirty entries as seen
+ * by the other caches, so as to keep the dirty bytes count
+ * in synchronization with them.
+ *
+ * Thus on process 0, the dirty_bytes count is incremented
+ * only if either
+ *
+ * 1) an entry is inserted in the metadata cache, or
+ *
+ * 2) a previously clean entry is moved, and it does not
+ * already appear in the dirty entry list, or
+ *
+ * 3) a previously clean entry is unprotected with the
+ * dirtied flag set and the entry does not already appear
+ * in the dirty entry list.
+ *
+ * Entries are added to the dirty entry list whever they cause
+ * the dirty bytes count to be increased. They are removed
+ * when they appear in a clean entries broadcast. Note that
+ * moves must be reflected in the dirty entry list.
+ *
+ * To reitterate, this field is only used on process 0 -- it
+ * should be NULL on all other processes.
+ *
+ * c_slist_ptr: Pointer to an instance of H5SL_t used to maintain a list
+ * of entries that were dirty, have been flushed
+ * to disk since the last clean entries broadcast, and are
+ * still clean. Since only process 0 can write to disk, this
+ * list only exists on process 0.
+ *
+ * In essence, this slist is used to assemble the contents of
+ * the next clean entries broadcast. The list emptied after
+ * each broadcast.
+ *
+ * The following two fields are used only when metadata_write_strategy
+ * is H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED.
+ *
+ * candidate_slist_ptr: Pointer to an instance of H5SL_t used by process 0
+ * to construct a list of entries to be flushed at this sync
+ * point. This list is then broadcast to the other processes,
+ * which then either flush or mark clean all entries on it.
+ *
+ * write_done: In the parallel test bed, it is necessary to ensure that
+ * all writes to the server process from cache 0 complete
+ * before it enters the barrier call with the other caches.
+ *
+ * The write_done callback allows t_cache to do this without
+ * requiring an ACK on each write. Since these ACKs greatly
+ * increase the run time on some platforms, this is a
+ * significant optimization.
+ *
+ * This field must be set to NULL when the callback is not
+ * needed.
+ *
+ * Note: This field has been extended for use by all processes
+ * with the addition of support for the distributed
+ * metadata write strategy.
+ * JRM -- 5/9/10
+ *
+ * sync_point_done: In the parallel test bed, it is necessary to verify
+ * that the expected writes, and only the expected writes,
+ * have taken place at the end of each sync point.
+ *
+ * The sync_point_done callback allows t_cache to perform
+ * this verification. The field is set to NULL when the
+ * callback is not needed.
+ *
+ * The following field supports the metadata cache image feature.
+ *
+ * p0_image_len: unsiged integer containing the length of the metadata cache
+ * image constructed by MPI process 0. This field should be 0
+ * if the value is unknown, or if cache image is not enabled.
+ *
+ ****************************************************************************/
+
+#ifdef H5_HAVE_PARALLEL
+
+#define H5AC__H5AC_AUX_T_MAGIC (unsigned)0x00D0A01
+
+typedef struct H5AC_aux_t
+{
+ uint32_t magic;
+
+ MPI_Comm mpi_comm;
+
+ int mpi_rank;
+
+ int mpi_size;
+
+ hbool_t write_permitted;
+
+ size_t dirty_bytes_threshold;
+
+ size_t dirty_bytes;
+
+ int32_t metadata_write_strategy;
+
+#if H5AC_DEBUG_DIRTY_BYTES_CREATION
+
+ unsigned dirty_bytes_propagations;
+
+ size_t unprotect_dirty_bytes;
+ unsigned unprotect_dirty_bytes_updates;
+
+ size_t insert_dirty_bytes;
+ unsigned insert_dirty_bytes_updates;
+
+ size_t move_dirty_bytes;
+ unsigned move_dirty_bytes_updates;
+
+#endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
+
+ H5SL_t * d_slist_ptr;
+
+ H5SL_t * c_slist_ptr;
+
+ H5SL_t * candidate_slist_ptr;
+
+ void (* write_done)(void);
+
+ void (* sync_point_done)(unsigned num_writes,
+ haddr_t * written_entries_tbl);
+
+ unsigned p0_image_len;
+
+} H5AC_aux_t; /* struct H5AC_aux_t */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+#ifdef H5_HAVE_PARALLEL
+/* Parallel I/O routines */
+H5_DLL herr_t H5AC__log_deleted_entry(const H5AC_info_t *entry_ptr);
+H5_DLL herr_t H5AC__log_dirtied_entry(const H5AC_info_t *entry_ptr);
+H5_DLL herr_t H5AC__log_cleaned_entry(const H5AC_info_t *entry_ptr);
+H5_DLL herr_t H5AC__log_flushed_entry(H5C_t *cache_ptr, haddr_t addr,
+ hbool_t was_dirty, unsigned flags);
+H5_DLL herr_t H5AC__log_inserted_entry(const H5AC_info_t *entry_ptr);
+H5_DLL herr_t H5AC__log_moved_entry(const H5F_t *f, haddr_t old_addr,
+ haddr_t new_addr);
+H5_DLL herr_t H5AC__flush_entries(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC__run_sync_point(H5F_t *f, hid_t dxpl_id, int sync_point_op);
+H5_DLL herr_t H5AC__set_sync_point_done_callback(H5C_t *cache_ptr,
+ void (*sync_point_done)(unsigned num_writes, haddr_t *written_entries_tbl));
+H5_DLL herr_t H5AC__set_write_done_callback(H5C_t * cache_ptr,
+ void (* write_done)(void));
+#endif /* H5_HAVE_PARALLEL */
+
+/* Trace file routines */
+H5_DLL herr_t H5AC__close_trace_file(H5AC_t *cache_ptr);
+H5_DLL herr_t H5AC__open_trace_file(H5AC_t *cache_ptr, const char *trace_file_name);
+
+/* Cache logging routines */
+H5_DLL herr_t H5AC__write_create_cache_log_msg(H5AC_t *cache);
+H5_DLL herr_t H5AC__write_destroy_cache_log_msg(H5AC_t *cache);
+H5_DLL herr_t H5AC__write_evict_cache_log_msg(const H5AC_t *cache,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_expunge_entry_log_msg(const H5AC_t *cache,
+ haddr_t address,
+ int type_id,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_flush_cache_log_msg(const H5AC_t *cache,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_insert_entry_log_msg(const H5AC_t *cache,
+ haddr_t address,
+ int type_id,
+ unsigned flags,
+ size_t size,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_mark_dirty_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_mark_clean_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry, herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_mark_unserialized_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry, herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_mark_serialized_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry, herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_move_entry_log_msg(const H5AC_t *cache,
+ haddr_t old_addr,
+ haddr_t new_addr,
+ int type_id,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_pin_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_create_fd_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *parent,
+ const H5AC_info_t *child,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_protect_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ unsigned flags,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_resize_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ size_t new_size,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_unpin_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_destroy_fd_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *parent,
+ const H5AC_info_t *child,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_unprotect_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ int type_id,
+ unsigned flags,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_set_cache_config_log_msg(const H5AC_t *cache,
+ const H5AC_cache_config_t *config,
+ herr_t fxn_ret_value);
+H5_DLL herr_t H5AC__write_remove_entry_log_msg(const H5AC_t *cache,
+ const H5AC_info_t *entry,
+ herr_t fxn_ret_value);
+
+#endif /* _H5ACpkg_H */
+
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
new file mode 100644
index 0000000..b9e2a60
--- /dev/null
+++ b/src/H5ACprivate.h
@@ -0,0 +1,502 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5ACprivate.h
+ * Jul 9 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Constants and typedefs available to the rest of the
+ * library.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5ACprivate_H
+#define _H5ACprivate_H
+
+#include "H5ACpublic.h" /*public prototypes */
+
+/* Pivate headers needed by this header */
+#include "H5private.h" /* Generic Functions */
+#include "H5Cprivate.h" /* Cache */
+#include "H5Fprivate.h" /* File access */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SLprivate.h" /* Skip lists */
+
+#ifdef H5_METADATA_TRACE_FILE
+#define H5AC__TRACE_FILE_ENABLED 1
+#else /* H5_METADATA_TRACE_FILE */
+#define H5AC__TRACE_FILE_ENABLED 0
+#endif /* H5_METADATA_TRACE_FILE */
+
+/* Global metadata tag values */
+#define H5AC__INVALID_TAG (haddr_t)0
+#define H5AC__IGNORE_TAG (haddr_t)1
+#define H5AC__COPIED_TAG (haddr_t)2
+#define H5AC__SUPERBLOCK_TAG (haddr_t)3
+#define H5AC__FREESPACE_TAG (haddr_t)4
+#define H5AC__SOHM_TAG (haddr_t)5
+#define H5AC__GLOBALHEAP_TAG (haddr_t)6
+
+/* Definitions for cache "tag" property */
+#define H5AC_TAG_NAME "H5AC_tag"
+#define H5AC_TAG_SIZE sizeof(haddr_t)
+#define H5AC_TAG_DEF (H5AC__INVALID_TAG)
+
+/* Types of metadata objects cached */
+typedef enum {
+ H5AC_BT_ID = 0, /* ( 0) B-tree nodes */
+ H5AC_SNODE_ID, /* ( 1) symbol table nodes */
+ H5AC_LHEAP_PRFX_ID, /* ( 2) local heap prefix */
+ H5AC_LHEAP_DBLK_ID, /* ( 3) local heap data block */
+ H5AC_GHEAP_ID, /* ( 4) global heap */
+ H5AC_OHDR_ID, /* ( 5) object header */
+ H5AC_OHDR_CHK_ID, /* ( 6) object header chunk */
+ H5AC_BT2_HDR_ID, /* ( 7) v2 B-tree header */
+ H5AC_BT2_INT_ID, /* ( 8) v2 B-tree internal node */
+ H5AC_BT2_LEAF_ID, /* ( 9) v2 B-tree leaf node */
+ H5AC_FHEAP_HDR_ID, /* (10) fractal heap header */
+ H5AC_FHEAP_DBLOCK_ID, /* (11) fractal heap direct block */
+ H5AC_FHEAP_IBLOCK_ID, /* (12) fractal heap indirect block */
+ H5AC_FSPACE_HDR_ID, /* (13) free space header */
+ H5AC_FSPACE_SINFO_ID, /* (14) free space sections */
+ H5AC_SOHM_TABLE_ID, /* (15) shared object header message master table */
+ H5AC_SOHM_LIST_ID, /* (16) shared message index stored as a list */
+ H5AC_EARRAY_HDR_ID, /* (17) extensible array header */
+ H5AC_EARRAY_IBLOCK_ID, /* (18) extensible array index block */
+ H5AC_EARRAY_SBLOCK_ID, /* (19) extensible array super block */
+ H5AC_EARRAY_DBLOCK_ID, /* (20) extensible array data block */
+ H5AC_EARRAY_DBLK_PAGE_ID, /* (21) extensible array data block page */
+ H5AC_FARRAY_HDR_ID, /* (22) fixed array header */
+ H5AC_FARRAY_DBLOCK_ID, /* (23) fixed array data block */
+ H5AC_FARRAY_DBLK_PAGE_ID, /* (24) fixed array data block page */
+ H5AC_SUPERBLOCK_ID, /* (25) file superblock */
+ H5AC_DRVRINFO_ID, /* (26) driver info block (supplements superblock) */
+ H5AC_EPOCH_MARKER_ID, /* (27) epoch marker - always internal to cache */
+ H5AC_PROXY_ENTRY_ID, /* (28) cache entry proxy */
+ H5AC_PREFETCHED_ENTRY_ID, /* (29) prefetched entry - always internal to cache */
+ H5AC_NTYPES /* Number of types, must be last */
+} H5AC_type_t;
+
+/* H5AC_DUMP_STATS_ON_CLOSE should always be FALSE when
+ * H5C_COLLECT_CACHE_STATS is FALSE.
+ *
+ * When H5C_COLLECT_CACHE_STATS is TRUE, H5AC_DUMP_STATS_ON_CLOSE must
+ * be FALSE for "make check" to succeed, but may be set to TRUE at other
+ * times for debugging purposes.
+ *
+ * Hence the following, somewhat odd set of #defines.
+ *
+ * NOTE: test/cache plays games with the f->shared->cache, and thus
+ * setting H5AC_DUMP_STATS_ON_CLOSE will generate constant,
+ * irrelevant data when run with that test program. See
+ * comments on setup_cache() / takedown_cache() in test/cache_common.c.
+ * for details.
+ *
+ * If you need to dump stats at file close in test/cache.c,
+ * use the dump_stats parameter to takedown_cache(), or call
+ * H5C_stats() directly.
+ * JRM -- 4/12/15
+ *
+ * Added the H5AC_DUMP_IMAGE_STATS_ON_CLOSE #define, which works much
+ * the same way as H5AC_DUMP_STATS_ON_CLOSE. However, the set of stats
+ * displayed is much smaller, and directed purely at the cache image feature.
+ *
+ * JRM -- 11/1/15
+ */
+#if H5C_COLLECT_CACHE_STATS
+
+#define H5AC_DUMP_STATS_ON_CLOSE 0
+#define H5AC_DUMP_IMAGE_STATS_ON_CLOSE 0
+
+#else /* H5C_COLLECT_CACHE_STATS */
+
+#define H5AC_DUMP_STATS_ON_CLOSE 0
+#define H5AC_DUMP_IMAGE_STATS_ON_CLOSE 0
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+/* Default max metadata cache size and min clean size are give here.
+ * At present, these are the same as those given in H5Cprivate.h.
+ */
+
+#define H5AC__DEFAULT_MAX_CACHE_SIZE H5C__DEFAULT_MAX_CACHE_SIZE
+#define H5AC__DEFAULT_MIN_CLEAN_SIZE H5C__DEFAULT_MIN_CLEAN_SIZE
+
+/* Check if we are sanity checking tagging */
+#if H5C_DO_TAGGING_SANITY_CHECKS
+#define H5AC_DO_TAGGING_SANITY_CHECKS 1
+#else
+#define H5AC_DO_TAGGING_SANITY_CHECKS 0
+#endif
+
+/*
+ * Class methods pertaining to caching. Each type of cached object will
+ * have a constant variable with permanent life-span that describes how
+ * to cache the object.
+ */
+
+#define H5AC__SERIALIZE_RESIZED_FLAG H5C__SERIALIZE_RESIZED_FLAG
+#define H5AC__SERIALIZE_MOVED_FLAG H5C__SERIALIZE_MOVED_FLAG
+
+/* Cork actions: cork/uncork/get cork status of an object */
+#define H5AC__SET_CORK H5C__SET_CORK
+#define H5AC__UNCORK H5C__UNCORK
+#define H5AC__GET_CORKED H5C__GET_CORKED
+
+/* Aliases for the "ring" type and values */
+typedef H5C_ring_t H5AC_ring_t;
+#define H5AC_RING_INV H5C_RING_UNDEFINED
+#define H5AC_RING_USER H5C_RING_USER
+#define H5AC_RING_RDFSM H5C_RING_RDFSM
+#define H5AC_RING_MDFSM H5C_RING_MDFSM
+#define H5AC_RING_SBE H5C_RING_SBE
+#define H5AC_RING_SB H5C_RING_SB
+#define H5AC_RING_NTYPES H5C_RING_NTYPES
+
+/* Aliases for 'notify action' type & values */
+typedef H5C_notify_action_t H5AC_notify_action_t;
+#define H5AC_NOTIFY_ACTION_AFTER_INSERT H5C_NOTIFY_ACTION_AFTER_INSERT
+#define H5AC_NOTIFY_ACTION_AFTER_LOAD H5C_NOTIFY_ACTION_AFTER_LOAD
+#define H5AC_NOTIFY_ACTION_AFTER_FLUSH H5C_NOTIFY_ACTION_AFTER_FLUSH
+#define H5AC_NOTIFY_ACTION_BEFORE_EVICT H5C_NOTIFY_ACTION_BEFORE_EVICT
+#define H5AC_NOTIFY_ACTION_ENTRY_DIRTIED H5C_NOTIFY_ACTION_ENTRY_DIRTIED
+#define H5AC_NOTIFY_ACTION_ENTRY_CLEANED H5C_NOTIFY_ACTION_ENTRY_CLEANED
+#define H5AC_NOTIFY_ACTION_CHILD_DIRTIED H5C_NOTIFY_ACTION_CHILD_DIRTIED
+#define H5AC_NOTIFY_ACTION_CHILD_CLEANED H5C_NOTIFY_ACTION_CHILD_CLEANED
+#define H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED
+#define H5AC_NOTIFY_ACTION_CHILD_SERIALIZED H5C_NOTIFY_ACTION_CHILD_SERIALIZED
+
+#define H5AC__CLASS_NO_FLAGS_SET H5C__CLASS_NO_FLAGS_SET
+#define H5AC__CLASS_SPECULATIVE_LOAD_FLAG H5C__CLASS_SPECULATIVE_LOAD_FLAG
+
+/* The following flags should only appear in test code */
+#define H5AC__CLASS_SKIP_READS H5C__CLASS_SKIP_READS
+#define H5AC__CLASS_SKIP_WRITES H5C__CLASS_SKIP_WRITES
+
+typedef H5C_get_initial_load_size_func_t H5AC_get_initial_load_size_func_t;
+typedef H5C_get_final_load_size_func_t H5AC_get_final_load_size_func_t;
+typedef H5C_verify_chksum_func_t H5AC_verify_chksum_func_t;
+typedef H5C_deserialize_func_t H5AC_deserialize_func_t;
+typedef H5C_image_len_func_t H5AC_image_len_func_t;
+
+#define H5AC__SERIALIZE_NO_FLAGS_SET H5C__SERIALIZE_NO_FLAGS_SET
+#define H5AC__SERIALIZE_RESIZED_FLAG H5C__SERIALIZE_RESIZED_FLAG
+#define H5AC__SERIALIZE_MOVED_FLAG H5C__SERIALIZE_MOVED_FLAG
+
+typedef H5C_pre_serialize_func_t H5AC_pre_serialize_func_t;
+typedef H5C_serialize_func_t H5AC_serialize_func_t;
+typedef H5C_notify_func_t H5AC_notify_func_t;
+typedef H5C_free_icr_func_t H5AC_free_icr_func_t;
+typedef H5C_get_fsf_size_t H5AC_get_fsf_size_t;
+
+typedef H5C_class_t H5AC_class_t;
+
+/* Cache entry info */
+typedef H5C_cache_entry_t H5AC_info_t;
+
+/* Typedef for metadata cache (defined in H5Cpkg.h) */
+typedef H5C_t H5AC_t;
+
+/* Metadata cache proxy entry type */
+typedef struct H5AC_proxy_entry_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions */
+ /* (MUST be first field in structure) */
+
+ /* General fields */
+ haddr_t addr; /* Address of the entry in the file */
+ /* (Should be in 'temporary' address space) */
+
+ /* Parent fields */
+ H5SL_t *parents; /* Skip list to track parent addresses */
+
+ /* Child fields */
+ size_t nchildren; /* Number of children */
+ size_t ndirty_children; /* Number of dirty children */
+ /* (Note that this currently duplicates some cache functionality) */
+ size_t nunser_children; /* Number of unserialized children */
+ /* (Note that this currently duplicates some cache functionality) */
+} H5AC_proxy_entry_t;
+
+
+#define H5AC_RING_NAME "H5AC_ring_type"
+
+/* Dataset transfer property lists for metadata calls */
+H5_DLLVAR hid_t H5AC_ind_read_dxpl_id;
+#ifdef H5_HAVE_PARALLEL
+H5_DLLVAR hid_t H5AC_coll_read_dxpl_id;
+#endif /* H5_HAVE_PARALLEL */
+
+/* DXPL to be used in operations that will not result in I/O calls */
+H5_DLLVAR hid_t H5AC_noio_dxpl_id;
+
+/* DXPL to be used for raw data I/O operations when one is not
+ provided by the user (fill values in H5Dcreate) */
+H5_DLLVAR hid_t H5AC_rawdata_dxpl_id;
+
+/* Default cache configuration. */
+
+#define H5AC__DEFAULT_METADATA_WRITE_STRATEGY \
+ H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED
+
+#ifdef H5_HAVE_PARALLEL
+#define H5AC__DEFAULT_CACHE_CONFIG \
+{ \
+ /* int version = */ H5AC__CURR_CACHE_CONFIG_VERSION, \
+ /* hbool_t rpt_fcn_enabled = */ FALSE, \
+ /* hbool_t open_trace_file = */ FALSE, \
+ /* hbool_t close_trace_file = */ FALSE, \
+ /* char trace_file_name[] = */ "", \
+ /* hbool_t evictions_enabled = */ TRUE, \
+ /* hbool_t set_initial_size = */ TRUE, \
+ /* size_t initial_size = */ ( 2 * 1024 * 1024), \
+ /* double min_clean_fraction = */ 0.3f, \
+ /* size_t max_size = */ (32 * 1024 * 1024), \
+ /* size_t min_size = */ (1 * 1024 * 1024), \
+ /* long int epoch_length = */ 50000, \
+ /* enum H5C_cache_incr_mode incr_mode = */ H5C_incr__threshold, \
+ /* double lower_hr_threshold = */ 0.9f, \
+ /* double increment = */ 2.0f, \
+ /* hbool_t apply_max_increment = */ TRUE, \
+ /* size_t max_increment = */ (4 * 1024 * 1024), \
+ /* enum H5C_cache_flash_incr_mode */ \
+ /* flash_incr_mode = */ H5C_flash_incr__add_space, \
+ /* double flash_multiple = */ 1.0f, \
+ /* double flash_threshold = */ 0.25f, \
+ /* enum H5C_cache_decr_mode decr_mode = */ H5C_decr__age_out_with_threshold, \
+ /* double upper_hr_threshold = */ 0.999f, \
+ /* double decrement = */ 0.9f, \
+ /* hbool_t apply_max_decrement = */ TRUE, \
+ /* size_t max_decrement = */ (1 * 1024 * 1024), \
+ /* int epochs_before_eviction = */ 3, \
+ /* hbool_t apply_empty_reserve = */ TRUE, \
+ /* double empty_reserve = */ 0.1f, \
+ /* size_t dirty_bytes_threshold = */ (256 * 1024), \
+ /* int metadata_write_strategy = */ \
+ H5AC__DEFAULT_METADATA_WRITE_STRATEGY \
+}
+#else /* H5_HAVE_PARALLEL */
+#define H5AC__DEFAULT_CACHE_CONFIG \
+{ \
+ /* int version = */ H5C__CURR_AUTO_SIZE_CTL_VER, \
+ /* hbool_t rpt_fcn_enabled = */ FALSE, \
+ /* hbool_t open_trace_file = */ FALSE, \
+ /* hbool_t close_trace_file = */ FALSE, \
+ /* char trace_file_name[] = */ "", \
+ /* hbool_t evictions_enabled = */ TRUE, \
+ /* hbool_t set_initial_size = */ TRUE, \
+ /* size_t initial_size = */ ( 2 * 1024 * 1024), \
+ /* double min_clean_fraction = */ 0.01f, \
+ /* size_t max_size = */ (32 * 1024 * 1024), \
+ /* size_t min_size = */ ( 1 * 1024 * 1024), \
+ /* long int epoch_length = */ 50000, \
+ /* enum H5C_cache_incr_mode incr_mode = */ H5C_incr__threshold, \
+ /* double lower_hr_threshold = */ 0.9f, \
+ /* double increment = */ 2.0f, \
+ /* hbool_t apply_max_increment = */ TRUE, \
+ /* size_t max_increment = */ (4 * 1024 * 1024), \
+ /* enum H5C_cache_flash_incr_mode */ \
+ /* flash_incr_mode = */ H5C_flash_incr__add_space, \
+ /* double flash_multiple = */ 1.4f, \
+ /* double flash_threshold = */ 0.25f, \
+ /* enum H5C_cache_decr_mode decr_mode = */ H5C_decr__age_out_with_threshold,\
+ /* double upper_hr_threshold = */ 0.999f, \
+ /* double decrement = */ 0.9f, \
+ /* hbool_t apply_max_decrement = */ TRUE, \
+ /* size_t max_decrement = */ (1 * 1024 * 1024), \
+ /* int epochs_before_eviction = */ 3, \
+ /* hbool_t apply_empty_reserve = */ TRUE, \
+ /* double empty_reserve = */ 0.1f, \
+ /* size_t dirty_bytes_threshold = */ (256 * 1024), \
+ /* int metadata_write_strategy = */ \
+ H5AC__DEFAULT_METADATA_WRITE_STRATEGY \
+}
+#endif /* H5_HAVE_PARALLEL */
+
+#define H5AC__DEFAULT_CACHE_IMAGE_CONFIG \
+{ \
+ /* int32_t version = */ H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION, \
+ /* hbool_t generate_image = */ FALSE, \
+ /* hbool_t save_resize_status = */ FALSE, \
+ /* int32_t entry_ageout = */ H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE \
+}
+/*
+ * Library prototypes.
+ */
+
+/* #defines of flags used in the flags parameters in some of the
+ * following function calls. Note that they are just copies of
+ * the equivalent flags from H5Cprivate.h.
+ */
+
+#define H5AC__NO_FLAGS_SET H5C__NO_FLAGS_SET
+#define H5AC__SET_FLUSH_MARKER_FLAG H5C__SET_FLUSH_MARKER_FLAG
+#define H5AC__DELETED_FLAG H5C__DELETED_FLAG
+#define H5AC__DIRTIED_FLAG H5C__DIRTIED_FLAG
+#define H5AC__PIN_ENTRY_FLAG H5C__PIN_ENTRY_FLAG
+#define H5AC__UNPIN_ENTRY_FLAG H5C__UNPIN_ENTRY_FLAG
+#define H5AC__FLUSH_INVALIDATE_FLAG H5C__FLUSH_INVALIDATE_FLAG
+#define H5AC__FLUSH_CLEAR_ONLY_FLAG H5C__FLUSH_CLEAR_ONLY_FLAG
+#define H5AC__FLUSH_MARKED_ENTRIES_FLAG H5C__FLUSH_MARKED_ENTRIES_FLAG
+#define H5AC__FLUSH_IGNORE_PROTECTED_FLAG H5C__FLUSH_IGNORE_PROTECTED_FLAG
+#define H5AC__READ_ONLY_FLAG H5C__READ_ONLY_FLAG
+#define H5AC__FREE_FILE_SPACE_FLAG H5C__FREE_FILE_SPACE_FLAG
+#define H5AC__TAKE_OWNERSHIP_FLAG H5C__TAKE_OWNERSHIP_FLAG
+#define H5AC__FLUSH_LAST_FLAG H5C__FLUSH_LAST_FLAG
+#define H5AC__FLUSH_COLLECTIVELY_FLAG H5C__FLUSH_COLLECTIVELY_FLAG
+
+
+/* #defines of flags used to report entry status in the
+ * H5AC_get_entry_status() call.
+ */
+
+#define H5AC_ES__IN_CACHE 0x0001
+#define H5AC_ES__IS_DIRTY 0x0002
+#define H5AC_ES__IS_PROTECTED 0x0004
+#define H5AC_ES__IS_PINNED 0x0008
+#define H5AC_ES__IS_FLUSH_DEP_PARENT 0x0010
+#define H5AC_ES__IS_FLUSH_DEP_CHILD 0x0020
+#define H5AC_ES__IS_CORKED 0x0040
+#define H5AC_ES__IMAGE_IS_UP_TO_DATE 0x0080
+
+/* Metadata entry class declarations */
+H5_DLLVAR const H5AC_class_t H5AC_BT[1];
+H5_DLLVAR const H5AC_class_t H5AC_SNODE[1];
+H5_DLLVAR const H5AC_class_t H5AC_LHEAP_PRFX[1];
+H5_DLLVAR const H5AC_class_t H5AC_LHEAP_DBLK[1];
+H5_DLLVAR const H5AC_class_t H5AC_GHEAP[1];
+H5_DLLVAR const H5AC_class_t H5AC_OHDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_OHDR_CHK[1];
+H5_DLLVAR const H5AC_class_t H5AC_BT2_HDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_BT2_INT[1];
+H5_DLLVAR const H5AC_class_t H5AC_BT2_LEAF[1];
+H5_DLLVAR const H5AC_class_t H5AC_FHEAP_HDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_FHEAP_DBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_FHEAP_IBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_FSPACE_HDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_FSPACE_SINFO[1];
+H5_DLLVAR const H5AC_class_t H5AC_SOHM_TABLE[1];
+H5_DLLVAR const H5AC_class_t H5AC_SOHM_LIST[1];
+H5_DLLVAR const H5AC_class_t H5AC_EARRAY_HDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_EARRAY_IBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_EARRAY_SBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_EARRAY_DBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1];
+H5_DLLVAR const H5AC_class_t H5AC_FARRAY_HDR[1];
+H5_DLLVAR const H5AC_class_t H5AC_FARRAY_DBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1];
+H5_DLLVAR const H5AC_class_t H5AC_SUPERBLOCK[1];
+H5_DLLVAR const H5AC_class_t H5AC_DRVRINFO[1];
+H5_DLLVAR const H5AC_class_t H5AC_EPOCH_MARKER[1];
+H5_DLLVAR const H5AC_class_t H5AC_PROXY_ENTRY[1];
+H5_DLLVAR const H5AC_class_t H5AC_PREFETCHED_ENTRY[1];
+
+
+/* external function declarations: */
+
+H5_DLL herr_t H5AC_init(void);
+H5_DLL herr_t H5AC_create(const H5F_t *f, H5AC_cache_config_t *config_ptr,
+ H5AC_cache_image_config_t * image_config_ptr);
+H5_DLL herr_t H5AC_get_entry_status(const H5F_t *f, haddr_t addr,
+ unsigned *status_ptr);
+H5_DLL herr_t H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type,
+ haddr_t addr, void *thing, unsigned int flags);
+H5_DLL herr_t H5AC_pin_protected_entry(void *thing);
+H5_DLL herr_t H5AC_prep_for_file_close(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_create_flush_dependency(void *parent_thing, void *child_thing);
+H5_DLL void * H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type,
+ haddr_t addr, void *udata, unsigned flags);
+H5_DLL herr_t H5AC_resize_entry(void *thing, size_t new_size);
+H5_DLL herr_t H5AC_unpin_entry(void *thing);
+H5_DLL herr_t H5AC_destroy_flush_dependency(void *parent_thing, void *child_thing);
+H5_DLL herr_t H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type,
+ haddr_t addr, void *thing, unsigned flags);
+H5_DLL herr_t H5AC_flush(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_mark_entry_dirty(void *thing);
+H5_DLL herr_t H5AC_mark_entry_clean(void *thing);
+H5_DLL herr_t H5AC_mark_entry_unserialized(void *thing);
+H5_DLL herr_t H5AC_mark_entry_serialized(void *thing);
+H5_DLL herr_t H5AC_move_entry(H5F_t *f, const H5AC_class_t *type,
+ haddr_t old_addr, haddr_t new_addr, hid_t dxpl_id);
+H5_DLL herr_t H5AC_dest(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_evict(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id,
+ const H5AC_class_t *type, haddr_t addr, unsigned flags);
+H5_DLL herr_t H5AC_remove_entry(void *entry);
+H5_DLL herr_t H5AC_get_cache_auto_resize_config(const H5AC_t * cache_ptr,
+ H5AC_cache_config_t *config_ptr);
+H5_DLL herr_t H5AC_get_cache_size(H5AC_t *cache_ptr, size_t *max_size_ptr,
+ size_t *min_clean_size_ptr, size_t *cur_size_ptr, uint32_t *cur_num_entries_ptr);
+H5_DLL herr_t H5AC_get_cache_hit_rate(H5AC_t *cache_ptr, double *hit_rate_ptr);
+H5_DLL herr_t H5AC_reset_cache_hit_rate_stats(H5AC_t *cache_ptr);
+H5_DLL herr_t H5AC_set_cache_auto_resize_config(H5AC_t *cache_ptr,
+ H5AC_cache_config_t *config_ptr);
+H5_DLL herr_t H5AC_validate_config(H5AC_cache_config_t *config_ptr);
+
+/* Cache image routines */
+H5_DLL herr_t H5AC_load_cache_image_on_next_protect(H5F_t *f, haddr_t addr,
+ hsize_t len, hbool_t rw);
+H5_DLL herr_t H5AC_validate_cache_image_config(H5AC_cache_image_config_t *config_ptr);
+H5_DLL hbool_t H5AC_cache_image_pending(const H5F_t *f);
+H5_DLL herr_t H5AC_force_cache_image_load(H5F_t * f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_get_mdc_image_info(H5AC_t *cache_ptr, haddr_t *image_addr,
+ hsize_t *image_len);
+
+/* Tag & Ring routines */
+H5_DLL herr_t H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t *prev_tag);
+H5_DLL herr_t H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id);
+H5_DLL herr_t H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hbool_t match_global, hid_t dxpl_id);
+H5_DLL herr_t H5AC_retag_copied_metadata(const H5F_t *f, haddr_t metadata_tag);
+H5_DLL herr_t H5AC_ignore_tags(const H5F_t *f);
+H5_DLL herr_t H5AC_cork(H5F_t *f, haddr_t obj_addr, unsigned action, hbool_t *corked);
+H5_DLL herr_t H5AC_get_entry_ring(const H5F_t *f, haddr_t addr, H5AC_ring_t *ring);
+H5_DLL herr_t H5AC_set_ring(hid_t dxpl_id, H5AC_ring_t ring, H5P_genplist_t **dxpl,
+ H5AC_ring_t *orig_ring);
+H5_DLL herr_t H5AC_reset_ring(H5P_genplist_t *dxpl, H5AC_ring_t orig_ring);
+H5_DLL herr_t H5AC_unsettle_entry_ring(void *entry);
+H5_DLL herr_t H5AC_unsettle_ring(H5F_t * f, H5AC_ring_t ring);
+H5_DLL herr_t H5AC_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id, unsigned flags);
+H5_DLL herr_t H5AC_get_tag(const void *thing, /*OUT*/ haddr_t *tag);
+
+/* Virtual entry routines */
+H5_DLL H5AC_proxy_entry_t *H5AC_proxy_entry_create(void);
+H5_DLL herr_t H5AC_proxy_entry_add_parent(H5AC_proxy_entry_t *pentry, void *parent);
+H5_DLL herr_t H5AC_proxy_entry_remove_parent(H5AC_proxy_entry_t *pentry, void *parent);
+H5_DLL herr_t H5AC_proxy_entry_add_child(H5AC_proxy_entry_t *pentry, H5F_t *f,
+ hid_t dxpl_id, void *child);
+H5_DLL herr_t H5AC_proxy_entry_remove_child(H5AC_proxy_entry_t *pentry, void *child);
+H5_DLL herr_t H5AC_proxy_entry_dest(H5AC_proxy_entry_t *pentry);
+
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5AC_add_candidate(H5AC_t * cache_ptr, haddr_t addr);
+#endif /* H5_HAVE_PARALLEL */
+
+/* Debugging functions */
+H5_DLL herr_t H5AC_stats(const H5F_t *f);
+#ifndef NDEBUG
+H5_DLL herr_t H5AC_dump_cache(const H5F_t *f);
+H5_DLL herr_t H5AC_get_entry_ptr_from_addr(const H5F_t *f, haddr_t addr,
+ void **entry_ptr_ptr);
+H5_DLL herr_t H5AC_flush_dependency_exists(H5F_t *f, haddr_t parent_addr,
+ haddr_t child_addr, hbool_t *fd_exists_ptr);
+H5_DLL herr_t H5AC_verify_entry_type(const H5F_t *f, haddr_t addr,
+ const H5AC_class_t *expected_type, hbool_t *in_cache_ptr,
+ hbool_t *type_ok_ptr);
+H5_DLL hbool_t H5AC_get_serialization_in_progress(H5F_t *f);
+H5_DLL hbool_t H5AC_cache_is_clean(const H5F_t *f, H5AC_ring_t inner_ring);
+#endif /* NDEBUG */ /* end debugging functions */
+
+#endif /* !_H5ACprivate_H */
+
diff --git a/src/H5ACproxy_entry.c b/src/H5ACproxy_entry.c
new file mode 100644
index 0000000..105a531
--- /dev/null
+++ b/src/H5ACproxy_entry.c
@@ -0,0 +1,661 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5ACproxy_entry.c
+ *
+ * Purpose: Functions and a cache client for a "proxy" cache entry.
+ * A proxy cache entry is used as a placeholder for entire
+ * data structures to attach flush dependencies, etc.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+#include "H5ACmodule.h" /* This source code file is part of the H5AC module */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5AC__proxy_entry_image_len(const void *thing, size_t *image_len);
+static herr_t H5AC__proxy_entry_serialize(const H5F_t *f, void *image_ptr,
+ size_t len, void *thing);
+static herr_t H5AC__proxy_entry_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5AC__proxy_entry_free_icr(void *thing);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5AC proxy entries inherit cache-like properties from H5AC */
+const H5AC_class_t H5AC_PROXY_ENTRY[1] = {{
+ H5AC_PROXY_ENTRY_ID, /* Metadata client ID */
+ "Proxy entry", /* Metadata client name (for debugging) */
+ H5FD_MEM_SUPER, /* File space memory type for client */
+ 0, /* Client class behavior flags */
+ NULL, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ NULL, /* 'deserialize' callback */
+ H5AC__proxy_entry_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5AC__proxy_entry_serialize, /* 'serialize' callback */
+ H5AC__proxy_entry_notify, /* 'notify' callback */
+ H5AC__proxy_entry_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage H5AC_proxy_entry_t objects */
+H5FL_DEFINE_STATIC(H5AC_proxy_entry_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_create
+ *
+ * Purpose: Create a new proxy entry
+ *
+ * Return: Success: Pointer to the new proxy entry object.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+H5AC_proxy_entry_t *
+H5AC_proxy_entry_create(void)
+{
+ H5AC_proxy_entry_t *pentry = NULL; /* Pointer to new proxy entry */
+ H5AC_proxy_entry_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate new proxy entry */
+ if(NULL == (pentry = H5FL_CALLOC(H5AC_proxy_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "can't allocate proxy entry")
+
+ /* Set non-zero fields */
+ pentry->addr = HADDR_UNDEF;
+
+ /* Set return value */
+ ret_value = pentry;
+
+done:
+ /* Release resources on error */
+ if(!ret_value)
+ if(pentry)
+ pentry = H5FL_FREE(H5AC_proxy_entry_t, pentry);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_add_parent
+ *
+ * Purpose: Add a parent to a proxy entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_proxy_entry_add_parent(H5AC_proxy_entry_t *pentry, void *_parent)
+{
+ H5AC_info_t *parent = (H5AC_info_t *)_parent; /* Parent entry's cache info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(parent);
+ HDassert(pentry);
+
+ /* Add parent to the list of parents */
+ if(NULL == pentry->parents)
+ if(NULL == (pentry->parents = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to create skip list for parents of proxy entry")
+
+ /* Insert parent address into skip list */
+ if(H5SL_insert(pentry->parents, parent, &parent->addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "unable to insert parent into proxy's skip list")
+
+ /* Add flush dependency on parent */
+ if(pentry->nchildren > 0) {
+ /* Sanity check */
+ HDassert(H5F_addr_defined(pentry->addr));
+
+ if(H5AC_create_flush_dependency(parent, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "unable to set flush dependency on proxy entry")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_add_parent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_remove_parent
+ *
+ * Purpose: Removes a parent from a proxy entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_proxy_entry_remove_parent(H5AC_proxy_entry_t *pentry, void *_parent)
+{
+ H5AC_info_t *parent = (H5AC_info_t *)_parent; /* Pointer to the parent entry */
+ H5AC_info_t *rem_parent; /* Pointer to the removed parent entry */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(pentry);
+ HDassert(pentry->parents);
+ HDassert(parent);
+
+ /* Remove parent from skip list */
+ if(NULL == (rem_parent = (H5AC_info_t *)H5SL_remove(pentry->parents, &parent->addr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "unable to remove proxy entry parent from skip list")
+ if(!H5F_addr_eq(rem_parent->addr, parent->addr))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "removed proxy entry parent not the same as real parent")
+
+ /* Shut down the skip list, if this is the last parent */
+ if(0 == H5SL_count(pentry->parents)) {
+ /* Sanity check */
+ HDassert(0 == pentry->nchildren);
+
+ if(H5SL_close(pentry->parents) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CLOSEERROR, FAIL, "can't close proxy parent skip list")
+ pentry->parents = NULL;
+ } /* end if */
+
+ /* Remove flush dependency between the proxy entry and a parent */
+ if(pentry->nchildren > 0)
+ if(H5AC_destroy_flush_dependency(parent, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "unable to remove flush dependency on proxy entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_remove_parent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_add_child_cb
+ *
+ * Purpose: Callback routine for adding an entry as a flush dependency for
+ * a proxy entry.
+ *
+ * Return: Success: Non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 22, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5AC__proxy_entry_add_child_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5AC_info_t *parent = (H5AC_info_t *)_item; /* Pointer to the parent entry */
+ H5AC_proxy_entry_t *pentry = (H5AC_proxy_entry_t *)_udata; /* Pointer to the proxy entry */
+ int ret_value = H5_ITER_CONT; /* Callback return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Add flush dependency on parent for proxy entry */
+ if(H5AC_create_flush_dependency(parent, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, H5_ITER_ERROR, "unable to set flush dependency for virtual entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC__proxy_entry_add_child_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_add_child
+ *
+ * Purpose: Add a child a proxy entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_proxy_entry_add_child(H5AC_proxy_entry_t *pentry, H5F_t *f, hid_t dxpl_id,
+ void *child)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(pentry);
+ HDassert(child);
+
+ /* Check for first child */
+ if(0 == pentry->nchildren) {
+ /* Get an address, if the proxy doesn't already have one */
+ if(!H5F_addr_defined(pentry->addr))
+ if(HADDR_UNDEF == (pentry->addr = H5MF_alloc_tmp(f, 1)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "temporary file space allocation failed for proxy entry")
+
+ /* Insert the proxy entry into the cache */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_PROXY_ENTRY, pentry->addr, pentry, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "unable to cache proxy entry")
+
+ /* Proxies start out clean (insertions are automatically marked dirty) */
+ if(H5AC_mark_entry_clean(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCLEAN, FAIL, "can't mark proxy entry clean")
+
+ /* Proxies start out serialized (insertions are automatically marked unserialized) */
+ if(H5AC_mark_entry_serialized(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "can't mark proxy entry clean")
+
+ /* If there are currently parents, iterate over the list of parents, creating flush dependency on them */
+ if(pentry->parents)
+ if(H5SL_iterate(pentry->parents, H5AC__proxy_entry_add_child_cb, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "can't visit parents")
+ } /* end if */
+
+ /* Add flush dependency on proxy entry */
+ if(H5AC_create_flush_dependency(pentry, child) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "unable to set flush dependency on proxy entry")
+
+ /* Increment count of children */
+ pentry->nchildren++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_add_child() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_remove_child_cb
+ *
+ * Purpose: Callback routine for removing an entry as a flush dependency for
+ * proxy entry.
+ *
+ * Return: Success: Non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 22, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5AC__proxy_entry_remove_child_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5AC_info_t *parent = (H5AC_info_t *)_item; /* Pointer to the parent entry */
+ H5AC_proxy_entry_t *pentry = (H5AC_proxy_entry_t *)_udata; /* Pointer to the proxy entry */
+ int ret_value = H5_ITER_CONT; /* Callback return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Remove flush dependency on parent for proxy entry */
+ if(H5AC_destroy_flush_dependency(parent, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, H5_ITER_ERROR, "unable to remove flush dependency for proxy entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC__proxy_entry_remove_child_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_remove_child
+ *
+ * Purpose: Remove a child a proxy entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_proxy_entry_remove_child(H5AC_proxy_entry_t *pentry, void *child)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(pentry);
+ HDassert(child);
+
+ /* Remove flush dependency on proxy entry */
+ if(H5AC_destroy_flush_dependency(pentry, child) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "unable to remove flush dependency on proxy entry")
+
+ /* Decrement count of children */
+ pentry->nchildren--;
+
+ /* Check for last child */
+ if(0 == pentry->nchildren) {
+ /* Check for flush dependencies on proxy's parents */
+ if(pentry->parents)
+ /* Iterate over the list of parents, removing flush dependency on them */
+ if(H5SL_iterate(pentry->parents, H5AC__proxy_entry_remove_child_cb, pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "can't visit parents")
+
+ /* Unpin proxy */
+ if(H5AC_unpin_entry(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "can't unpin proxy entry")
+
+ /* Remove proxy entry from cache */
+ if(H5AC_remove_entry(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "unable to remove proxy entry")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_remove_child() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_proxy_entry_dest
+ *
+ * Purpose: Destroys a proxy entry in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_proxy_entry_dest(H5AC_proxy_entry_t *pentry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(pentry);
+ HDassert(NULL == pentry->parents);
+ HDassert(0 == pentry->nchildren);
+ HDassert(0 == pentry->ndirty_children);
+ HDassert(0 == pentry->nunser_children);
+
+ /* Free the proxy entry object */
+ pentry = H5FL_FREE(H5AC_proxy_entry_t, pentry);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC_proxy_entry_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__proxy_entry_image_len(const void H5_ATTR_UNUSED *thing, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image_len);
+
+ /* Set the image length size to 1 byte */
+ *image_len = 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5AC__proxy_entry_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_serialize
+ *
+ * Purpose: Serializes a data structure for writing to disk.
+ *
+ * Note: Should never be invoked.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__proxy_entry_serialize(const H5F_t H5_ATTR_UNUSED *f, void H5_ATTR_UNUSED *image,
+ size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *thing)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ /* Should never be invoked */
+ HDassert(0 && "Invalid callback?!?");
+
+ HERROR(H5E_CACHE, H5E_CANTSERIALIZE, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5AC__proxy_entry_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__proxy_entry_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5AC_proxy_entry_t *pentry = (H5AC_proxy_entry_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(pentry);
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid notify action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Invalid action?!?");
+#endif /* NDEBUG */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid notify action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Invalid action?!?");
+#endif /* NDEBUG */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Sanity checks */
+ HDassert(0 == pentry->ndirty_children);
+ HDassert(0 == pentry->nunser_children);
+
+ /* No action */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ /* Sanity checks */
+ HDassert(pentry->ndirty_children > 0);
+
+ /* No action */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ /* Sanity checks */
+ HDassert(0 == pentry->ndirty_children);
+
+ /* No action */
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ /* Increment # of dirty children */
+ pentry->ndirty_children++;
+
+ /* Check for first dirty child */
+ if(1 == pentry->ndirty_children)
+ if(H5AC_mark_entry_dirty(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDIRTY, FAIL, "can't mark proxy entry dirty")
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ /* Sanity check */
+ HDassert(pentry->ndirty_children > 0);
+
+ /* Decrement # of dirty children */
+ pentry->ndirty_children--;
+
+ /* Check for last dirty child */
+ if(0 == pentry->ndirty_children)
+ if(H5AC_mark_entry_clean(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCLEAN, FAIL, "can't mark proxy entry clean")
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ /* Increment # of unserialized children */
+ pentry->nunser_children++;
+
+ /* Check for first unserialized child */
+ if(1 == pentry->nunser_children)
+ if(H5AC_mark_entry_unserialized(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNSERIALIZE, FAIL, "can't mark proxy entry unserialized")
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* Sanity check */
+ HDassert(pentry->nunser_children > 0);
+
+ /* Decrement # of unserialized children */
+ pentry->nunser_children--;
+
+ /* Check for last unserialized child */
+ if(0 == pentry->nunser_children)
+ if(H5AC_mark_entry_serialized(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "can't mark proxy entry serialized")
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown notify action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5AC__proxy_entry_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC__proxy_entry_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5AC__proxy_entry_free_icr(void *_thing)
+{
+ H5AC_proxy_entry_t *pentry = (H5AC_proxy_entry_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Destroy the proxy entry */
+ if(H5AC_proxy_entry_dest(pentry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to destroy proxy entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC__proxy_entry_free_icr() */
+
diff --git a/src/H5ACpublic.h b/src/H5ACpublic.h
new file mode 100644
index 0000000..c8276cf
--- /dev/null
+++ b/src/H5ACpublic.h
@@ -0,0 +1,574 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5ACpublic.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public include file for cache functions.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5ACpublic_H
+#define _H5ACpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Cpublic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************
+ *
+ * structure H5AC_cache_config_t
+ *
+ * H5AC_cache_config_t is a public structure intended for use in public APIs.
+ * At least in its initial incarnation, it is basicaly a copy of struct
+ * H5C_auto_size_ctl_t, minus the report_fcn field, and plus the
+ * dirty_bytes_threshold field.
+ *
+ * The report_fcn field is omitted, as including it would require us to
+ * make H5C_t structure public.
+ *
+ * The dirty_bytes_threshold field does not appear in H5C_auto_size_ctl_t,
+ * as synchronization between caches on different processes is handled at
+ * the H5AC level, not at the level of H5C. Note however that there is
+ * considerable interaction between this value and the other fields in this
+ * structure.
+ *
+ * Similarly, the open_trace_file, close_trace_file, and trace_file_name
+ * fields do not appear in H5C_auto_size_ctl_t, as most trace file
+ * issues are handled at the H5AC level. The one exception is storage of
+ * the pointer to the trace file, which is handled by H5C.
+ *
+ * The structure is in H5ACpublic.h as we may wish to allow different
+ * configuration options for metadata and raw data caches.
+ *
+ * The fields of the structure are discussed individually below:
+ *
+ * version: Integer field containing the version number of this version
+ * of the H5AC_cache_config_t structure. Any instance of
+ * H5AC_cache_config_t passed to the cache must have a known
+ * version number, or an error will be flagged.
+ *
+ * rpt_fcn_enabled: Boolean field used to enable and disable the default
+ * reporting function. This function is invoked every time the
+ * automatic cache resize code is run, and reports on its activities.
+ *
+ * This is a debugging function, and should normally be turned off.
+ *
+ * open_trace_file: Boolean field indicating whether the trace_file_name
+ * field should be used to open a trace file for the cache.
+ *
+ * *** DEPRECATED *** Use H5Fstart/stop logging functions instead
+ *
+ * The trace file is a debuging feature that allow the capture of
+ * top level metadata cache requests for purposes of debugging and/or
+ * optimization. This field should normally be set to FALSE, as
+ * trace file collection imposes considerable overhead.
+ *
+ * This field should only be set to TRUE when the trace_file_name
+ * contains the full path of the desired trace file, and either
+ * there is no open trace file on the cache, or the close_trace_file
+ * field is also TRUE.
+ *
+ * close_trace_file: Boolean field indicating whether the current trace
+ * file (if any) should be closed.
+ *
+ * *** DEPRECATED *** Use H5Fstart/stop logging functions instead
+ *
+ * See the above comments on the open_trace_file field. This field
+ * should be set to FALSE unless there is an open trace file on the
+ * cache that you wish to close.
+ *
+ * trace_file_name: Full path of the trace file to be opened if the
+ * open_trace_file field is TRUE.
+ *
+ * *** DEPRECATED *** Use H5Fstart/stop logging functions instead
+ *
+ * In the parallel case, an ascii representation of the mpi rank of
+ * the process will be appended to the file name to yield a unique
+ * trace file name for each process.
+ *
+ * The length of the path must not exceed H5AC__MAX_TRACE_FILE_NAME_LEN
+ * characters.
+ *
+ * evictions_enabled: Boolean field used to either report the current
+ * evictions enabled status of the cache, or to set the cache's
+ * evictions enabled status.
+ *
+ * In general, the metadata cache should always be allowed to
+ * evict entries. However, in some cases it is advantageous to
+ * disable evictions briefly, and thereby postpone metadata
+ * writes. However, this must be done with care, as the cache
+ * can grow quickly. If you do this, re-enable evictions as
+ * soon as possible and monitor cache size.
+ *
+ * At present, evictions can only be disabled if automatic
+ * cache resizing is also disabled (that is, ( incr_mode ==
+ * H5C_incr__off ) && ( decr_mode == H5C_decr__off )). There
+ * is no logical reason why this should be so, but it simplifies
+ * implementation and testing, and I can't think of any reason
+ * why it would be desireable. If you can think of one, I'll
+ * revisit the issue.
+ *
+ * set_initial_size: Boolean flag indicating whether the size of the
+ * initial size of the cache is to be set to the value given in
+ * the initial_size field. If set_initial_size is FALSE, the
+ * initial_size field is ignored.
+ *
+ * initial_size: If enabled, this field contain the size the cache is
+ * to be set to upon receipt of this structure. Needless to say,
+ * initial_size must lie in the closed interval [min_size, max_size].
+ *
+ * min_clean_fraction: double in the range 0 to 1 indicating the fraction
+ * of the cache that is to be kept clean. This field is only used
+ * in parallel mode. Typical values are 0.1 to 0.5.
+ *
+ * max_size: Maximum size to which the cache can be adjusted. The
+ * supplied value must fall in the closed interval
+ * [MIN_MAX_CACHE_SIZE, MAX_MAX_CACHE_SIZE]. Also, max_size must
+ * be greater than or equal to min_size.
+ *
+ * min_size: Minimum size to which the cache can be adjusted. The
+ * supplied value must fall in the closed interval
+ * [H5C__MIN_MAX_CACHE_SIZE, H5C__MAX_MAX_CACHE_SIZE]. Also, min_size
+ * must be less than or equal to max_size.
+ *
+ * epoch_length: Number of accesses on the cache over which to collect
+ * hit rate stats before running the automatic cache resize code,
+ * if it is enabled.
+ *
+ * At the end of an epoch, we discard prior hit rate data and start
+ * collecting afresh. The epoch_length must lie in the closed
+ * interval [H5C__MIN_AR_EPOCH_LENGTH, H5C__MAX_AR_EPOCH_LENGTH].
+ *
+ *
+ * Cache size increase control fields:
+ *
+ * incr_mode: Instance of the H5C_cache_incr_mode enumerated type whose
+ * value indicates how we determine whether the cache size should be
+ * increased. At present there are two possible values:
+ *
+ * H5C_incr__off: Don't attempt to increase the size of the cache
+ * automatically.
+ *
+ * When this increment mode is selected, the remaining fields
+ * in the cache size increase section ar ignored.
+ *
+ * H5C_incr__threshold: Attempt to increase the size of the cache
+ * whenever the average hit rate over the last epoch drops
+ * below the value supplied in the lower_hr_threshold
+ * field.
+ *
+ * Note that this attempt will fail if the cache is already
+ * at its maximum size, or if the cache is not already using
+ * all available space.
+ *
+ * Note that you must set decr_mode to H5C_incr__off if you
+ * disable metadata cache entry evictions.
+ *
+ * lower_hr_threshold: Lower hit rate threshold. If the increment mode
+ * (incr_mode) is H5C_incr__threshold and the hit rate drops below the
+ * value supplied in this field in an epoch, increment the cache size by
+ * size_increment. Note that cache size may not be incremented above
+ * max_size, and that the increment may be further restricted by the
+ * max_increment field if it is enabled.
+ *
+ * When enabled, this field must contain a value in the range [0.0, 1.0].
+ * Depending on the incr_mode selected, it may also have to be less than
+ * upper_hr_threshold.
+ *
+ * increment: Double containing the multiplier used to derive the new
+ * cache size from the old if a cache size increment is triggered.
+ * The increment must be greater than 1.0, and should not exceed 2.0.
+ *
+ * The new cache size is obtained my multiplying the current max cache
+ * size by the increment, and then clamping to max_size and to stay
+ * within the max_increment as necessary.
+ *
+ * apply_max_increment: Boolean flag indicating whether the max_increment
+ * field should be used to limit the maximum cache size increment.
+ *
+ * max_increment: If enabled by the apply_max_increment field described
+ * above, this field contains the maximum number of bytes by which the
+ * cache size can be increased in a single re-size.
+ *
+ * flash_incr_mode: Instance of the H5C_cache_flash_incr_mode enumerated
+ * type whose value indicates whether and by which algorithm we should
+ * make flash increases in the size of the cache to accomodate insertion
+ * of large entries and large increases in the size of a single entry.
+ *
+ * The addition of the flash increment mode was occasioned by performance
+ * problems that appear when a local heap is increased to a size in excess
+ * of the current cache size. While the existing re-size code dealt with
+ * this eventually, performance was very bad for the remainder of the
+ * epoch.
+ *
+ * At present, there are two possible values for the flash_incr_mode:
+ *
+ * H5C_flash_incr__off: Don't perform flash increases in the size of
+ * the cache.
+ *
+ * H5C_flash_incr__add_space: Let x be either the size of a newly
+ * newly inserted entry, or the number of bytes by which the
+ * size of an existing entry has been increased.
+ *
+ * If
+ * x > flash_threshold * current max cache size,
+ *
+ * increase the current maximum cache size by x * flash_multiple
+ * less any free space in the cache, and star a new epoch. For
+ * now at least, pay no attention to the maximum increment.
+ *
+ * In both of the above cases, the flash increment pays no attention to
+ * the maximum increment (at least in this first incarnation), but DOES
+ * stay within max_size.
+ *
+ * With a little thought, it should be obvious that the above flash
+ * cache size increase algorithm is not sufficient for all circumstances
+ * -- for example, suppose the user round robins through
+ * (1/flash_threshold) +1 groups, adding one data set to each on each
+ * pass. Then all will increase in size at about the same time, requiring
+ * the max cache size to at least double to maintain acceptable
+ * performance, however the above flash increment algorithm will not be
+ * triggered.
+ *
+ * Hopefully, the add space algorithms detailed above will be sufficient
+ * for the performance problems encountered to date. However, we should
+ * expect to revisit the issue.
+ *
+ * flash_multiple: Double containing the multiple described above in the
+ * H5C_flash_incr__add_space section of the discussion of the
+ * flash_incr_mode section. This field is ignored unless flash_incr_mode
+ * is H5C_flash_incr__add_space.
+ *
+ * flash_threshold: Double containing the factor by which current max cache
+ * size is multiplied to obtain the size threshold for the add_space flash
+ * increment algorithm. The field is ignored unless flash_incr_mode is
+ * H5C_flash_incr__add_space.
+ *
+ *
+ * Cache size decrease control fields:
+ *
+ * decr_mode: Instance of the H5C_cache_decr_mode enumerated type whose
+ * value indicates how we determine whether the cache size should be
+ * decreased. At present there are four possibilities.
+ *
+ * H5C_decr__off: Don't attempt to decrease the size of the cache
+ * automatically.
+ *
+ * When this increment mode is selected, the remaining fields
+ * in the cache size decrease section are ignored.
+ *
+ * H5C_decr__threshold: Attempt to decrease the size of the cache
+ * whenever the average hit rate over the last epoch rises
+ * above the value supplied in the upper_hr_threshold
+ * field.
+ *
+ * H5C_decr__age_out: At the end of each epoch, search the cache for
+ * entries that have not been accessed for at least the number
+ * of epochs specified in the epochs_before_eviction field, and
+ * evict these entries. Conceptually, the maximum cache size
+ * is then decreased to match the new actual cache size. However,
+ * this reduction may be modified by the min_size, the
+ * max_decrement, and/or the empty_reserve.
+ *
+ * H5C_decr__age_out_with_threshold: Same as age_out, but we only
+ * attempt to reduce the cache size when the hit rate observed
+ * over the last epoch exceeds the value provided in the
+ * upper_hr_threshold field.
+ *
+ * Note that you must set decr_mode to H5C_decr__off if you
+ * disable metadata cache entry evictions.
+ *
+ * upper_hr_threshold: Upper hit rate threshold. The use of this field
+ * varies according to the current decr_mode:
+ *
+ * H5C_decr__off or H5C_decr__age_out: The value of this field is
+ * ignored.
+ *
+ * H5C_decr__threshold: If the hit rate exceeds this threshold in any
+ * epoch, attempt to decrement the cache size by size_decrement.
+ *
+ * Note that cache size may not be decremented below min_size.
+ *
+ * Note also that if the upper_threshold is 1.0, the cache size
+ * will never be reduced.
+ *
+ * H5C_decr__age_out_with_threshold: If the hit rate exceeds this
+ * threshold in any epoch, attempt to reduce the cache size
+ * by evicting entries that have not been accessed for more
+ * than the specified number of epochs.
+ *
+ * decrement: This field is only used when the decr_mode is
+ * H5C_decr__threshold.
+ *
+ * The field is a double containing the multiplier used to derive the
+ * new cache size from the old if a cache size decrement is triggered.
+ * The decrement must be in the range 0.0 (in which case the cache will
+ * try to contract to its minimum size) to 1.0 (in which case the
+ * cache will never shrink).
+ *
+ * apply_max_decrement: Boolean flag used to determine whether decrements
+ * in cache size are to be limited by the max_decrement field.
+ *
+ * max_decrement: Maximum number of bytes by which the cache size can be
+ * decreased in a single re-size. Note that decrements may also be
+ * restricted by the min_size of the cache, and (in age out modes) by
+ * the empty_reserve field.
+ *
+ * epochs_before_eviction: Integer field used in H5C_decr__age_out and
+ * H5C_decr__age_out_with_threshold decrement modes.
+ *
+ * This field contains the number of epochs an entry must remain
+ * unaccessed before it is evicted in an attempt to reduce the
+ * cache size. If applicable, this field must lie in the range
+ * [1, H5C__MAX_EPOCH_MARKERS].
+ *
+ * apply_empty_reserve: Boolean field controlling whether the empty_reserve
+ * field is to be used in computing the new cache size when the
+ * decr_mode is H5C_decr__age_out or H5C_decr__age_out_with_threshold.
+ *
+ * empty_reserve: To avoid a constant racheting down of cache size by small
+ * amounts in the H5C_decr__age_out and H5C_decr__age_out_with_threshold
+ * modes, this field allows one to require that any cache size
+ * reductions leave the specified fraction of unused space in the cache.
+ *
+ * The value of this field must be in the range [0.0, 1.0]. I would
+ * expect typical values to be in the range of 0.01 to 0.1.
+ *
+ *
+ * Parallel Configuration Fields:
+ *
+ * In PHDF5, all operations that modify metadata must be executed collectively.
+ *
+ * We used to think that this was enough to ensure consistency across the
+ * metadata caches, but since we allow processes to read metadata individually,
+ * the order of dirty entries in the LRU list can vary across processes,
+ * which can result in inconsistencies between the caches.
+ *
+ * PHDF5 uses several strategies to prevent such inconsistencies in metadata,
+ * all of which use the fact that the same stream of dirty metadata is seen
+ * by all processes for purposes of synchronization. This is done by
+ * having each process count the number of bytes of dirty metadata generated,
+ * and then running a "sync point" whenever this count exceeds a user
+ * specified threshold (see dirty_bytes_threshold below).
+ *
+ * The current metadata write strategy is indicated by the
+ * metadata_write_strategy field. The possible values of this field, along
+ * with the associated metadata write strategies are discussed below.
+ *
+ * dirty_bytes_threshold: Threshold of dirty byte creation used to
+ * synchronize updates between caches. (See above for outline and
+ * motivation.)
+ *
+ * This value MUST be consistant across all processes accessing the
+ * file. This field is ignored unless HDF5 has been compiled for
+ * parallel.
+ *
+ * metadata_write_strategy: Integer field containing a code indicating the
+ * desired metadata write strategy. The valid values of this field
+ * are enumerated and discussed below:
+ *
+ *
+ * H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY:
+ *
+ * When metadata_write_strategy is set to this value, only process
+ * zero is allowed to write dirty metadata to disk. All other
+ * processes must retain dirty metadata until they are informed at
+ * a sync point that the dirty metadata in question has been written
+ * to disk.
+ *
+ * When the sync point is reached (or when there is a user generated
+ * flush), process zero flushes sufficient entries to bring it into
+ * complience with its min clean size (or flushes all dirty entries in
+ * the case of a user generated flush), broad casts the list of
+ * entries just cleaned to all the other processes, and then exits
+ * the sync point.
+ *
+ * Upon receipt of the broadcast, the other processes mark the indicated
+ * entries as clean, and leave the sync point as well.
+ *
+ *
+ * H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED:
+ *
+ * In the distributed metadata write strategy, process zero still makes
+ * the decisions as to what entries should be flushed, but the actual
+ * flushes are distributed across the processes in the computation to
+ * the extent possible.
+ *
+ * In this strategy, when a sync point is triggered (either by dirty
+ * metadata creation or manual flush), all processes enter a barrier.
+ *
+ * On the other side of the barrier, process 0 constructs an ordered
+ * list of the entries to be flushed, and then broadcasts this list
+ * to the caches in all the processes.
+ *
+ * All processes then scan the list of entries to be flushed, flushing
+ * some, and marking the rest as clean. The algorithm for this purpose
+ * ensures that each entry in the list is flushed exactly once, and
+ * all are marked clean in each cache.
+ *
+ * Note that in the case of a flush of the cache, no message passing
+ * is necessary, as all processes have the same list of dirty entries,
+ * and all of these entries must be flushed. Thus in this case it is
+ * sufficient for each process to sort its list of dirty entries after
+ * leaving the initial barrier, and use this list as if it had been
+ * received from process zero.
+ *
+ * To avoid possible messages from the past/future, all caches must
+ * wait until all caches are done before leaving the sync point.
+ *
+ ****************************************************************************/
+
+#define H5AC__CURR_CACHE_CONFIG_VERSION 1
+#define H5AC__MAX_TRACE_FILE_NAME_LEN 1024
+
+#define H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY 0
+#define H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED 1
+
+typedef struct H5AC_cache_config_t
+{
+ /* general configuration fields: */
+ int version;
+
+ hbool_t rpt_fcn_enabled;
+
+ hbool_t open_trace_file;
+ hbool_t close_trace_file;
+ char trace_file_name[H5AC__MAX_TRACE_FILE_NAME_LEN + 1];
+
+ hbool_t evictions_enabled;
+
+ hbool_t set_initial_size;
+ size_t initial_size;
+
+ double min_clean_fraction;
+
+ size_t max_size;
+ size_t min_size;
+
+ long int epoch_length;
+
+
+ /* size increase control fields: */
+ enum H5C_cache_incr_mode incr_mode;
+
+ double lower_hr_threshold;
+
+ double increment;
+
+ hbool_t apply_max_increment;
+ size_t max_increment;
+
+ enum H5C_cache_flash_incr_mode flash_incr_mode;
+ double flash_multiple;
+ double flash_threshold;
+
+
+ /* size decrease control fields: */
+ enum H5C_cache_decr_mode decr_mode;
+
+ double upper_hr_threshold;
+
+ double decrement;
+
+ hbool_t apply_max_decrement;
+ size_t max_decrement;
+
+ int epochs_before_eviction;
+
+ hbool_t apply_empty_reserve;
+ double empty_reserve;
+
+
+ /* parallel configuration fields: */
+ size_t dirty_bytes_threshold;
+ int metadata_write_strategy;
+
+} H5AC_cache_config_t;
+
+
+/****************************************************************************
+ *
+ * structure H5AC_cache_image_config_t
+ *
+ * H5AC_cache_image_ctl_t is a public structure intended for use in public
+ * APIs. At least in its initial incarnation, it is a copy of struct
+ * H5C_cache_image_ctl_t.
+ *
+ * The fields of the structure are discussed individually below:
+ *
+ * version: Integer field containing the version number of this version
+ * of the H5C_image_ctl_t structure. Any instance of
+ * H5C_image_ctl_t passed to the cache must have a known
+ * version number, or an error will be flagged.
+ *
+ * generate_image: Boolean flag indicating whether a cache image should
+ * be created on file close.
+ *
+ * save_resize_status: Boolean flag indicating whether the cache image
+ * should include the adaptive cache resize configuration and status.
+ * Note that this field is ignored at present.
+ *
+ * entry_ageout: Integer field indicating the maximum number of
+ * times a prefetched entry can appear in subsequent cache images.
+ * This field exists to allow the user to avoid the buildup of
+ * infrequently used entries in long sequences of cache images.
+ *
+ * The value of this field must lie in the range
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE (-1) to
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX (100).
+ *
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE means that no limit
+ * is imposed on number of times a prefeteched entry can appear
+ * in subsequent cache images.
+ *
+ * A value of 0 prevents prefetched entries from being included
+ * in cache images.
+ *
+ * Positive integers restrict prefetched entries to the specified
+ * number of appearances.
+ *
+ * Note that the number of subsequent cache images that a prefetched
+ * entry has appeared in is tracked in an 8 bit field. Thus, while
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX can be increased from its
+ * current value, any value in excess of 255 will be the functional
+ * equivalent of H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE.
+ *
+ ****************************************************************************/
+
+#define H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION 1
+
+#define H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE -1
+#define H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX 100
+
+typedef struct H5AC_cache_image_config_t {
+ int version;
+ hbool_t generate_image;
+ hbool_t save_resize_status;
+ int entry_ageout;
+} H5AC_cache_image_config_t;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/src/H5Abtree2.c b/src/H5Abtree2.c
new file mode 100644
index 0000000..ed67e0f
--- /dev/null
+++ b/src/H5Abtree2.c
@@ -0,0 +1,548 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Abtree2.c
+ * Dec 4 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: v2 B-tree callbacks for indexing attributes on objects
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5SMprivate.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/*
+ * Data exchange structure for dense attribute storage. This structure is
+ * passed through the fractal heap layer to compare attributes.
+ */
+typedef struct H5A_fh_ud_cmp_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const char *name; /* Name of attribute to compare */
+ const H5A_dense_bt2_name_rec_t *record; /* v2 B-tree record for attribute */
+ H5A_bt2_found_t found_op; /* Callback when correct attribute is found */
+ void *found_op_data; /* Callback data when correct attribute is found */
+
+ /* upward */
+ int cmp; /* Comparison of two attribute names */
+} H5A_fh_ud_cmp_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* v2 B-tree function callbacks */
+
+/* v2 B-tree driver callbacks for 'creation order' index */
+static herr_t H5A__dense_btree2_corder_store(void *native, const void *udata);
+static herr_t H5A__dense_btree2_corder_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5A__dense_btree2_corder_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5A__dense_btree2_corder_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5A__dense_btree2_corder_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* v2 B-tree driver callbacks for 'name' index */
+static herr_t H5A__dense_btree2_name_store(void *native, const void *udata);
+static herr_t H5A__dense_btree2_name_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5A__dense_btree2_name_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5A__dense_btree2_name_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5A__dense_btree2_name_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* Fractal heap function callbacks */
+static herr_t H5A__dense_fh_name_cmp(const void *obj, size_t obj_len, void *op_data);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+/* v2 B-tree class for indexing 'name' field of attributes */
+const H5B2_class_t H5A_BT2_NAME[1]={{ /* B-tree class information */
+ H5B2_ATTR_DENSE_NAME_ID, /* Type of B-tree */
+ "H5B2_ATTR_DENSE_NAME_ID", /* Name of B-tree class */
+ sizeof(H5A_dense_bt2_name_rec_t), /* Size of native record */
+ NULL, /* Create client callback context */
+ NULL, /* Destroy client callback context */
+ H5A__dense_btree2_name_store, /* Record storage callback */
+ H5A__dense_btree2_name_compare, /* Record comparison callback */
+ H5A__dense_btree2_name_encode, /* Record encoding callback */
+ H5A__dense_btree2_name_decode, /* Record decoding callback */
+ H5A__dense_btree2_name_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for indexing 'creation order' field of attributes */
+const H5B2_class_t H5A_BT2_CORDER[1]={{ /* B-tree class information */
+ H5B2_ATTR_DENSE_CORDER_ID, /* Type of B-tree */
+ "H5B2_ATTR_DENSE_CORDER_ID", /* Name of B-tree class */
+ sizeof(H5A_dense_bt2_corder_rec_t),/* Size of native record */
+ NULL, /* Create client callback context */
+ NULL, /* Destroy client callback context */
+ H5A__dense_btree2_corder_store, /* Record storage callback */
+ H5A__dense_btree2_corder_compare, /* Record comparison callback */
+ H5A__dense_btree2_corder_encode, /* Record encoding callback */
+ H5A__dense_btree2_corder_decode, /* Record decoding callback */
+ H5A__dense_btree2_corder_debug /* Record debugging callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_fh_name_cmp
+ *
+ * Purpose: Compares the name of a attribute in a fractal heap to another
+ * name
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_fh_name_cmp(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5A_fh_ud_cmp_t *udata = (H5A_fh_ud_cmp_t *)_udata; /* User data for 'op' callback */
+ H5A_t *attr = NULL; /* Pointer to attribute created from heap object */
+ hbool_t took_ownership = FALSE; /* Whether the "found" operator took ownership of the attribute */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Decode attribute information */
+ if(NULL == (attr = (H5A_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_ATTR_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode attribute")
+
+ /* Compare the string values */
+ udata->cmp = HDstrcmp(udata->name, attr->shared->name);
+
+ /* Check for correct attribute & callback to make */
+ if(udata->cmp == 0 && udata->found_op) {
+ /* Check whether we should "reconstitute" the shared message info */
+ if(udata->record->flags & H5O_MSG_FLAG_SHARED)
+ H5SM_reconstitute(&(attr->sh_loc), udata->f, H5O_ATTR_ID, udata->record->id);
+
+ /* Set the creation order index for the attribute */
+ attr->shared->crt_idx = udata->record->corder;
+
+ /* Make callback */
+ if((udata->found_op)(attr, &took_ownership, udata->found_op_data) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPERATE, FAIL, "attribute found callback failed")
+ } /* end if */
+
+done:
+ /* Release the space allocated for the attrbute */
+ if(attr && !took_ownership)
+ H5O_msg_free(H5O_ATTR_ID, attr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_fh_name_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_name_store
+ *
+ * Purpose: Store user information into native record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_name_store(void *_nrecord, const void *_udata)
+{
+ const H5A_bt2_ud_ins_t *udata = (const H5A_bt2_ud_ins_t *)_udata;
+ H5A_dense_bt2_name_rec_t *nrecord = (H5A_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Copy user information info native record */
+ nrecord->id = udata->id;
+ nrecord->flags = udata->common.flags;
+ nrecord->corder = udata->common.corder;
+ nrecord->hash = udata->common.name_hash;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_name_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_name_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_name_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
+{
+ const H5A_bt2_ud_common_t *bt2_udata = (const H5A_bt2_ud_common_t *)_bt2_udata;
+ const H5A_dense_bt2_name_rec_t *bt2_rec = (const H5A_dense_bt2_name_rec_t *)_bt2_rec;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(bt2_udata);
+ HDassert(bt2_rec);
+
+ /* Check hash value */
+ if(bt2_udata->name_hash < bt2_rec->hash)
+ *result = (-1);
+ else if(bt2_udata->name_hash > bt2_rec->hash)
+ *result = 1;
+ else {
+ H5A_fh_ud_cmp_t fh_udata; /* User data for fractal heap 'op' callback */
+ H5HF_t *fheap; /* Fractal heap handle to use for finding object */
+
+ /* Sanity check */
+ HDassert(bt2_udata->name_hash == bt2_rec->hash);
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.name = bt2_udata->name;
+ fh_udata.record = bt2_rec;
+ fh_udata.found_op = bt2_udata->found_op;
+ fh_udata.found_op_data = bt2_udata->found_op_data;
+
+ /* up */
+ fh_udata.cmp = 0;
+
+ /* Check for attribute in shared storage */
+ if(bt2_rec->flags & H5O_MSG_FLAG_SHARED)
+ fheap = bt2_udata->shared_fheap;
+ else
+ fheap = bt2_udata->fheap;
+ HDassert(fheap);
+
+ /* Check if the user's attribute and the B-tree's attribute have the same name */
+ if(H5HF_op(fheap, bt2_udata->dxpl_id, &bt2_rec->id, H5A__dense_fh_name_cmp, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ /* Callback will set comparison value */
+ *result = fh_udata.cmp;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A__dense_btree2_name_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_name_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_name_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ const H5A_dense_bt2_name_rec_t *nrecord = (const H5A_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Encode the record's fields */
+ HDmemcpy(raw, nrecord->id.id, (size_t)H5O_FHEAP_ID_LEN);
+ raw += H5O_FHEAP_ID_LEN;
+ *raw++ = nrecord->flags;
+ UINT32ENCODE(raw, nrecord->corder)
+ UINT32ENCODE(raw, nrecord->hash)
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_name_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_name_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_name_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ H5A_dense_bt2_name_rec_t *nrecord = (H5A_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Decode the record's fields */
+ HDmemcpy(nrecord->id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
+ raw += H5O_FHEAP_ID_LEN;
+ nrecord->flags = *raw++;
+ UINT32DECODE(raw, nrecord->corder)
+ UINT32DECODE(raw, nrecord->hash)
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_name_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_name_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_name_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5A_dense_bt2_name_rec_t *nrecord = (const H5A_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%016Hx, %02x, %u, %08lx}\n", indent, "", fwidth,
+ "Record:",
+ (hsize_t)nrecord->id.val, (unsigned)nrecord->flags, (unsigned)nrecord->corder, (unsigned long)nrecord->hash);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_name_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_corder_store
+ *
+ * Purpose: Store user information into native record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_corder_store(void *_nrecord, const void *_udata)
+{
+ const H5A_bt2_ud_ins_t *udata = (const H5A_bt2_ud_ins_t *)_udata;
+ H5A_dense_bt2_corder_rec_t *nrecord = (H5A_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Copy user information info native record */
+ nrecord->id = udata->id;
+ nrecord->flags = udata->common.flags;
+ nrecord->corder = udata->common.corder;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_corder_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_corder_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_corder_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
+{
+ const H5A_bt2_ud_common_t *bt2_udata = (const H5A_bt2_ud_common_t *)_bt2_udata;
+ const H5A_dense_bt2_corder_rec_t *bt2_rec = (const H5A_dense_bt2_corder_rec_t *)_bt2_rec;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(bt2_udata);
+ HDassert(bt2_rec);
+
+ /* Check creation order value */
+ if(bt2_udata->corder < bt2_rec->corder)
+ *result = -1;
+ else if(bt2_udata->corder > bt2_rec->corder)
+ *result = 1;
+ else
+ *result = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_corder_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_corder_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_corder_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ const H5A_dense_bt2_corder_rec_t *nrecord = (const H5A_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Encode the record's fields */
+ HDmemcpy(raw, nrecord->id.id, (size_t)H5O_FHEAP_ID_LEN);
+ raw += H5O_FHEAP_ID_LEN;
+ *raw++ = nrecord->flags;
+ UINT32ENCODE(raw, nrecord->corder)
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_corder_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_corder_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_corder_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ H5A_dense_bt2_corder_rec_t *nrecord = (H5A_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Decode the record's fields */
+ HDmemcpy(nrecord->id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
+ raw += H5O_FHEAP_ID_LEN;
+ nrecord->flags = *raw++;
+ UINT32DECODE(raw, nrecord->corder)
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_corder_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_btree2_corder_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_btree2_corder_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5A_dense_bt2_corder_rec_t *nrecord = (const H5A_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%016Hx, %02x, %u}\n", indent, "", fwidth,
+ "Record:",
+ (hsize_t)nrecord->id.val, (unsigned)nrecord->flags, (unsigned)nrecord->corder);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5A__dense_btree2_corder_debug() */
+
diff --git a/src/H5Adense.c b/src/H5Adense.c
new file mode 100644
index 0000000..b1903a4
--- /dev/null
+++ b/src/H5Adense.c
@@ -0,0 +1,1906 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Adense.c
+ * Dec 4 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Routines for operating on "dense" attribute storage
+ * for an object.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared object header messages */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* v2 B-tree creation macros for 'name' field index */
+#define H5A_NAME_BT2_NODE_SIZE 512
+#define H5A_NAME_BT2_MERGE_PERC 40
+#define H5A_NAME_BT2_SPLIT_PERC 100
+
+/* v2 B-tree creation macros for 'corder' field index */
+#define H5A_CORDER_BT2_NODE_SIZE 512
+#define H5A_CORDER_BT2_MERGE_PERC 40
+#define H5A_CORDER_BT2_SPLIT_PERC 100
+
+/* Size of stack buffer for serialized attributes */
+#define H5A_ATTR_BUF_SIZE 128
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/*
+ * Data exchange structure for dense attribute storage. This structure is
+ * passed through the v2 B-tree layer when modifying the attribute data value.
+ */
+typedef struct H5A_bt2_od_wrt_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle to operate on */
+ H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */
+ H5A_t *attr; /* Attribute to write */
+ haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */
+} H5A_bt2_od_wrt_t;
+
+/*
+ * Data exchange structure to pass through the v2 B-tree layer for the
+ * H5B2_iterate function when iterating over densely stored attributes.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */
+ hsize_t count; /* # of attributes examined */
+
+ /* downward (from application) */
+ hid_t loc_id; /* Object ID for application callback */
+ hsize_t skip; /* Number of attributes to skip */
+ const H5A_attr_iter_op_t *attr_op; /* Callback for each attribute */
+ void *op_data; /* Callback data for each attribute */
+
+ /* upward */
+ int op_ret; /* Return value from callback */
+} H5A_bt2_ud_it_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when copying an attribute stored in densely stored attributes.
+ * (or the shared message heap)
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const H5A_dense_bt2_name_rec_t *record; /* v2 B-tree record for attribute */
+
+ /* upward */
+ H5A_t *attr; /* Copy of attribute */
+} H5A_fh_ud_cp_t;
+
+/*
+ * Data exchange structure for dense attribute storage. This structure is
+ * passed through the v2 B-tree layer when removing attributes.
+ */
+typedef struct H5A_bt2_ud_rm_t {
+ /* downward */
+ H5A_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */
+ haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */
+} H5A_bt2_ud_rm_t;
+
+/*
+ * Data exchange structure for dense attribute storage. This structure is
+ * passed through the v2 B-tree layer when removing attributes by index.
+ */
+typedef struct H5A_bt2_ud_rmbi_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */
+ H5_index_t idx_type; /* Index type for operation */
+ haddr_t other_bt2_addr; /* v2 B-tree address of "other" index */
+} H5A_bt2_ud_rmbi_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_create
+ *
+ * Purpose: Creates dense attribute storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_create(H5F_t *f, hid_t dxpl_id, H5O_ainfo_t *ainfo)
+{
+ H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for names */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+
+ /* Set fractal heap creation parameters */
+/* XXX: Give some control of these to applications? */
+ HDmemset(&fheap_cparam, 0, sizeof(fheap_cparam));
+ fheap_cparam.managed.width = H5O_FHEAP_MAN_WIDTH;
+ fheap_cparam.managed.start_block_size = H5O_FHEAP_MAN_START_BLOCK_SIZE;
+ fheap_cparam.managed.max_direct_size = H5O_FHEAP_MAN_MAX_DIRECT_SIZE;
+ fheap_cparam.managed.max_index = H5O_FHEAP_MAN_MAX_INDEX;
+ fheap_cparam.managed.start_root_rows = H5O_FHEAP_MAN_START_ROOT_ROWS;
+ fheap_cparam.checksum_dblocks = H5O_FHEAP_CHECKSUM_DBLOCKS;
+ fheap_cparam.max_man_size = H5O_FHEAP_MAX_MAN_SIZE;
+
+ /* Create fractal heap for storing attributes */
+ if(NULL == (fheap = H5HF_create(f, dxpl_id, &fheap_cparam)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create fractal heap")
+
+ /* Retrieve the heap's address in the file */
+ if(H5HF_get_heap_addr(fheap, &ainfo->fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get fractal heap address")
+#ifdef QAK
+HDfprintf(stderr, "%s: ainfo->fheap_addr = %a\n", FUNC, ainfo->fheap_addr);
+#endif /* QAK */
+
+#ifndef NDEBUG
+{
+ size_t fheap_id_len; /* Fractal heap ID length */
+
+ /* Retrieve the heap's ID length in the file */
+ if(H5HF_get_id_len(fheap, &fheap_id_len) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length")
+ HDassert(fheap_id_len == H5O_FHEAP_ID_LEN);
+#ifdef QAK
+HDfprintf(stderr, "%s: fheap_id_len = %Zu\n", FUNC, fheap_id_len);
+#endif /* QAK */
+}
+#endif /* NDEBUG */
+
+ /* Create the name index v2 B-tree */
+ HDmemset(&bt2_cparam, 0, sizeof(bt2_cparam));
+ bt2_cparam.cls = H5A_BT2_NAME;
+ bt2_cparam.node_size = (size_t)H5A_NAME_BT2_NODE_SIZE;
+ bt2_cparam.rrec_size = 4 + /* Name's hash value */
+ 4 + /* Creation order index */
+ 1 + /* Message flags */
+ H5O_FHEAP_ID_LEN; /* Fractal heap ID */
+ bt2_cparam.split_percent = H5A_NAME_BT2_SPLIT_PERC;
+ bt2_cparam.merge_percent = H5A_NAME_BT2_MERGE_PERC;
+ if(NULL == (bt2_name = H5B2_create(f, dxpl_id, &bt2_cparam, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for name index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2_name, &ainfo->name_bt2_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get v2 B-tree address for name index")
+#ifdef QAK
+HDfprintf(stderr, "%s: ainfo->name_bt2_addr = %a\n", FUNC, ainfo->name_bt2_addr);
+#endif /* QAK */
+
+ /* Check if we should create a creation order index v2 B-tree */
+ if(ainfo->index_corder) {
+ /* Create the creation order index v2 B-tree */
+ HDmemset(&bt2_cparam, 0, sizeof(bt2_cparam));
+ bt2_cparam.cls = H5A_BT2_CORDER;
+ bt2_cparam.node_size = (size_t)H5A_CORDER_BT2_NODE_SIZE;
+ bt2_cparam.rrec_size = 4 + /* Creation order index */
+ 1 + /* Message flags */
+ H5O_FHEAP_ID_LEN; /* Fractal heap ID */
+ bt2_cparam.split_percent = H5A_CORDER_BT2_SPLIT_PERC;
+ bt2_cparam.merge_percent = H5A_CORDER_BT2_MERGE_PERC;
+ if(NULL == (bt2_corder = H5B2_create(f, dxpl_id, &bt2_cparam, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for creation order index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2_corder, &ainfo->corder_bt2_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get v2 B-tree address for creation order index")
+#ifdef QAK
+HDfprintf(stderr, "%s: ainfo->corder_bt2_addr = %a\n", FUNC, ainfo->corder_bt2_addr);
+#endif /* QAK */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_fnd_cb
+ *
+ * Purpose: Callback when an attribute is located in an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_fnd_cb(const H5A_t *attr, hbool_t *took_ownership, void *_user_attr)
+{
+ H5A_t const **user_attr = (H5A_t const **)_user_attr; /* User data from v2 B-tree attribute lookup */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(attr);
+ HDassert(user_attr);
+
+ /* Take over attribute ownership */
+ *user_attr = attr;
+ *took_ownership = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5A__dense_fnd_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_open
+ *
+ * Purpose: Open an attribute in dense storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_dense_open(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, const char *name)
+{
+ H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ htri_t attr_exists; /* Attribute exists in v2 B-tree */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(name);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap")
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open v2 B-tree for name index")
+
+ /* Create the "udata" information for v2 B-tree record find */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.name = name;
+ udata.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0);
+ udata.flags = 0;
+ udata.corder = 0;
+ udata.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */
+ udata.found_op_data = &ret_value;
+
+ /* Find & copy the attribute in the 'name' index */
+ if((attr_exists = H5B2_find(bt2_name, dxpl_id, &udata, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't search for attribute in name index")
+ else if(attr_exists == FALSE)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute in name index")
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_insert
+ *
+ * Purpose: Insert an attribute into dense storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_insert(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, H5A_t *attr)
+{
+ H5A_bt2_ud_ins_t udata; /* User data for v2 B-tree insertion */
+ H5HF_t *fheap = NULL; /* Fractal heap handle for attributes */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */
+ uint8_t attr_buf[H5A_ATTR_BUF_SIZE]; /* Buffer for serializing message */
+ unsigned mesg_flags = 0; /* Flags for storing message */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(attr);
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
+
+ /* Check if message is already shared */
+ if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared")
+ else if(shared_mesg > 0)
+ /* Mark the message as shared */
+ mesg_flags |= H5O_MSG_FLAG_SHARED;
+ else {
+ /* Should this attribute be written as a SOHM? */
+ if(H5SM_try_share(f, dxpl_id, NULL, 0, H5O_ATTR_ID, attr, &mesg_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared")
+
+ /* Attributes can't be "unique be shareable" yet */
+ HDassert(!(mesg_flags & H5O_MSG_FLAG_SHAREABLE));
+ } /* end else */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Check for inserting shared attribute */
+ if(mesg_flags & H5O_MSG_FLAG_SHARED) {
+ /* Sanity check */
+ HDassert(attr_sharable);
+
+ /* Use heap ID for shared message heap */
+ udata.id = attr->sh_loc.u.heap_id;
+ } /* end if */
+ else {
+ void *attr_ptr; /* Pointer to serialized message */
+ size_t attr_size; /* Size of serialized attribute in the heap */
+
+ /* Find out the size of buffer needed for serialized message */
+ if((attr_size = H5O_msg_raw_size(f, H5O_ATTR_ID, FALSE, attr)) == 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get message size")
+
+ /* Wrap the local buffer for serialized attributes */
+ if(NULL == (wb = H5WB_wrap(attr_buf, sizeof(attr_buf))))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for attribute */
+ if(NULL == (attr_ptr = H5WB_actual(wb, attr_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Create serialized form of attribute or shared message */
+ if(H5O_msg_encode(f, H5O_ATTR_ID, FALSE, (unsigned char *)attr_ptr, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute")
+
+ /* Insert the serialized attribute into the fractal heap */
+ /* (sets the heap ID in the user data) */
+ if(H5HF_insert(fheap, dxpl_id, attr_size, attr_ptr, &udata.id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert attribute into fractal heap")
+ } /* end else */
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Create the callback information for v2 B-tree record insertion */
+ udata.common.f = f;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.fheap = fheap;
+ udata.common.shared_fheap = shared_fheap;
+ udata.common.name = attr->shared->name;
+ udata.common.name_hash = H5_checksum_lookup3(attr->shared->name, HDstrlen(attr->shared->name), 0);
+ H5_CHECKED_ASSIGN(udata.common.flags, uint8_t, mesg_flags, unsigned);
+ udata.common.corder = attr->shared->crt_idx;
+ udata.common.found_op = NULL;
+ udata.common.found_op_data = NULL;
+ /* udata.id already set */
+
+ /* Insert attribute into 'name' tracking v2 B-tree */
+ if(H5B2_insert(bt2_name, dxpl_id, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree")
+
+ /* Check if we should create a creation order index v2 B-tree record */
+ if(ainfo->index_corder) {
+ /* Open the creation order index v2 B-tree */
+ HDassert(H5F_addr_defined(ainfo->corder_bt2_addr));
+ if(NULL == (bt2_corder = H5B2_open(f, dxpl_id, ainfo->corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Insert the record into the creation order index v2 B-tree */
+ if(H5B2_insert(bt2_corder, dxpl_id, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_write_bt2_cb2
+ *
+ * Purpose: v2 B-tree 'modify' callback to update the record for a creation
+ * order index
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_write_bt2_cb2(void *_record, void *_op_data, hbool_t *changed)
+{
+ H5A_dense_bt2_corder_rec_t *record = (H5A_dense_bt2_corder_rec_t *)_record; /* Record from B-tree */
+ H5O_fheap_id_t *new_heap_id = (H5O_fheap_id_t *)_op_data; /* "op data" from v2 B-tree modify */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(record);
+ HDassert(new_heap_id);
+
+ /* Update record's heap ID */
+ record->id = *new_heap_id;
+
+ /* Note that the record changed */
+ *changed = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5A__dense_write_bt2_cb2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_write_bt2_cb
+ *
+ * Purpose: v2 B-tree 'modify' callback to update the data for an attribute
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_write_bt2_cb(void *_record, void *_op_data, hbool_t *changed)
+{
+ H5A_dense_bt2_name_rec_t *record = (H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */
+ H5A_bt2_od_wrt_t *op_data = (H5A_bt2_od_wrt_t *)_op_data; /* "op data" from v2 B-tree modify */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */
+ uint8_t attr_buf[H5A_ATTR_BUF_SIZE]; /* Buffer for serializing attribute */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(record);
+ HDassert(op_data);
+
+ /* Check for modifying shared attribute */
+ if(record->flags & H5O_MSG_FLAG_SHARED) {
+ /* Update the shared attribute in the SOHM info */
+ if(H5O_attr_update_shared(op_data->f, op_data->dxpl_id, NULL, op_data->attr, NULL) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute in shared storage")
+
+ /* Update record's heap ID */
+ record->id = op_data->attr->sh_loc.u.heap_id;
+
+ /* Check if we need to modify the creation order index with new heap ID */
+ if(H5F_addr_defined(op_data->corder_bt2_addr)) {
+ H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */
+
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(op_data->f, op_data->dxpl_id, op_data->corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Create the "udata" information for v2 B-tree record modify */
+ udata.f = op_data->f;
+ udata.dxpl_id = op_data->dxpl_id;
+ udata.fheap = NULL;
+ udata.shared_fheap = NULL;
+ udata.name = NULL;
+ udata.name_hash = 0;
+ udata.flags = 0;
+ udata.corder = op_data->attr->shared->crt_idx;
+ udata.found_op = NULL;
+ udata.found_op_data = NULL;
+
+ /* Modify record for creation order index */
+ if(H5B2_modify(bt2_corder, op_data->dxpl_id, &udata, H5A__dense_write_bt2_cb2, &op_data->attr->sh_loc.u.heap_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to modify record in v2 B-tree")
+ } /* end if */
+
+ /* Note that the record changed */
+ *changed = TRUE;
+ } /* end if */
+ else {
+ void *attr_ptr; /* Pointer to serialized message */
+ size_t attr_size; /* Size of serialized attribute in the heap */
+
+ /* Find out the size of buffer needed for serialized attribute */
+ if((attr_size = H5O_msg_raw_size(op_data->f, H5O_ATTR_ID, FALSE, op_data->attr)) == 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get attribute size")
+
+ /* Wrap the local buffer for serialized attributes */
+ if(NULL == (wb = H5WB_wrap(attr_buf, sizeof(attr_buf))))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for attribute */
+ if(NULL == (attr_ptr = H5WB_actual(wb, attr_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Create serialized form of attribute */
+ if(H5O_msg_encode(op_data->f, H5O_ATTR_ID, FALSE, (unsigned char *)attr_ptr, op_data->attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute")
+
+/* Sanity check */
+#ifndef NDEBUG
+{
+ size_t obj_len; /* Length of existing encoded attribute */
+
+ if(H5HF_get_obj_len(op_data->fheap, op_data->dxpl_id, &record->id, &obj_len) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get object size")
+ HDassert(obj_len == attr_size);
+}
+#endif /* NDEBUG */
+ /* Update existing attribute in heap */
+ /* (might be more efficient as fractal heap 'op' callback, but leave that for later -QAK) */
+ if(H5HF_write(op_data->fheap, op_data->dxpl_id, &record->id, changed, attr_ptr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute in heap")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(bt2_corder && H5B2_close(bt2_corder, op_data->dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_write_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_write
+ *
+ * Purpose: Modify an attribute in dense storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_write(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, H5A_t *attr)
+{
+ H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */
+ H5A_bt2_od_wrt_t op_data; /* "Op data" for v2 B-tree modify */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(H5F_addr_defined(ainfo->fheap_addr));
+ HDassert(H5F_addr_defined(ainfo->name_bt2_addr));
+ HDassert(attr);
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Create the "udata" information for v2 B-tree record modify */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.name = attr->shared->name;
+ udata.name_hash = H5_checksum_lookup3(attr->shared->name, HDstrlen(attr->shared->name), 0);
+ udata.flags = 0;
+ udata.corder = 0;
+ udata.found_op = NULL;
+ udata.found_op_data = NULL;
+
+ /* Create the "op_data" for the v2 B-tree record 'modify' callback */
+ op_data.f = f;
+ op_data.dxpl_id = dxpl_id;
+ op_data.fheap = fheap;
+ op_data.shared_fheap = shared_fheap;
+ op_data.attr = attr;
+ op_data.corder_bt2_addr = ainfo->corder_bt2_addr;
+
+ /* Modify attribute through 'name' tracking v2 B-tree */
+ if(H5B2_modify(bt2_name, dxpl_id, &udata, H5A__dense_write_bt2_cb, &op_data) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to modify record in v2 B-tree")
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_copy_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator, to make copy of attribute
+ * for calling routine
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_copy_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5A_fh_ud_cp_t *udata = (H5A_fh_ud_cp_t *)_udata; /* User data for fractal heap 'op' callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Decode attribute information & keep a copy */
+ /* (we make a copy instead of calling the user/library callback directly in
+ * this routine because this fractal heap 'op' callback routine is called
+ * with the direct block protected and if the callback routine invokes an
+ * HDF5 routine, it could attempt to re-protect that direct block for the
+ * heap, causing the HDF5 routine called to fail)
+ */
+ if(NULL == (udata->attr = (H5A_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_ATTR_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDECODE, FAIL, "can't decode attribute")
+
+ /* Set the creation order index for the attribute */
+ udata->attr->shared->crt_idx = udata->record->corder;
+
+ /* Check whether we should "reconstitute" the shared message info */
+ if(udata->record->flags & H5O_MSG_FLAG_SHARED)
+ H5SM_reconstitute(&(udata->attr->sh_loc), udata->f, H5O_ATTR_ID, udata->record->id);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_copy_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_rename
+ *
+ * Purpose: Rename an attribute in dense storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 3 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_rename(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, const char *old_name,
+ const char *new_name)
+{
+ H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5A_t *attr_copy = NULL; /* Copy of attribute to rename */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
+ htri_t attr_exists; /* Attribute exists in v2 B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(old_name);
+ HDassert(new_name);
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Create the "udata" information for v2 B-tree record modify */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.name = old_name;
+ udata.name_hash = H5_checksum_lookup3(old_name, HDstrlen(old_name), 0);
+ udata.flags = 0;
+ udata.corder = 0;
+ udata.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */
+ udata.found_op_data = &attr_copy;
+
+ /* Get copy of attribute through 'name' tracking v2 B-tree */
+ if((attr_exists = H5B2_find(bt2_name, dxpl_id, &udata, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't search for attribute in name index")
+ else if(attr_exists == FALSE)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute in name index")
+ HDassert(attr_copy);
+
+ /* Check if message is already shared */
+ if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr_copy)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared")
+ else if(shared_mesg > 0) {
+ /* Reset shared status of copy */
+ /* (so it will get shared again if necessary) */
+ attr_copy->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
+ } /* end if */
+
+ /* Change name of attribute */
+ H5MM_xfree(attr_copy->shared->name);
+ attr_copy->shared->name = H5MM_xstrdup(new_name);
+
+ /* Recompute the version to encode the attribute with */
+ if(H5A_set_version(f, attr_copy) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "unable to update attribute version")
+
+ /* Insert renamed attribute back into dense storage */
+ /* (Possibly making it shared) */
+ if(H5A_dense_insert(f, dxpl_id, ainfo, attr_copy) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to add to dense storage")
+
+ /* Was this attribute shared? */
+ if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr_copy)) > 0) {
+ hsize_t attr_rc; /* Attribute's ref count in shared message storage */
+
+ /* Retrieve ref count for shared attribute */
+ if(H5SM_get_refcount(f, dxpl_id, H5O_ATTR_ID, &attr_copy->sh_loc, &attr_rc) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count")
+
+ /* If the newly shared attribute needs to share "ownership" of the shared
+ * components (ie. its reference count is 1), increment the reference
+ * count on any shared components of the attribute, so that they won't
+ * be removed from the file. (Essentially a "copy on write" operation).
+ *
+ * *ick* -QAK, 2007/01/08
+ */
+ if(attr_rc == 1) {
+ /* Increment reference count on attribute components */
+ if(H5O_attr_link(f, dxpl_id, NULL, attr_copy) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count")
+ } /* end if */
+ } /* end if */
+ else if(shared_mesg == 0) {
+ /* Increment reference count on attribute components */
+ /* (so that they aren't deleted when the attribute is removed shortly) */
+ if(H5O_attr_link(f, dxpl_id, NULL, attr_copy) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count")
+ } /* end if */
+ else if(shared_mesg < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared")
+
+ /* Delete old attribute from dense storage */
+ if(H5A_dense_remove(f, dxpl_id, ainfo, old_name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage")
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(attr_copy)
+ H5O_msg_free(H5O_ATTR_ID, attr_copy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_rename() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_iterate_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense attribute storage iterator
+ *
+ * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_iterate_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */
+ H5A_bt2_ud_it_t *bt2_udata = (H5A_bt2_ud_it_t *)_bt2_udata; /* User data for callback */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check for skipping attributes */
+ if(bt2_udata->skip > 0)
+ --bt2_udata->skip;
+ else {
+ H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */
+ H5HF_t *fheap; /* Fractal heap handle for attribute storage */
+
+ /* Check for iterating over shared attribute */
+ if(record->flags & H5O_MSG_FLAG_SHARED)
+ fheap = bt2_udata->shared_fheap;
+ else
+ fheap = bt2_udata->fheap;
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.record = record;
+ fh_udata.attr = NULL;
+
+ /* Call fractal heap 'op' routine, to copy the attribute information */
+ if(H5HF_op(fheap, bt2_udata->dxpl_id, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed")
+
+ /* Check which type of callback to make */
+ switch(bt2_udata->attr_op->op_type) {
+ case H5A_ATTR_OP_APP2:
+ {
+ H5A_info_t ainfo; /* Info for attribute */
+
+ /* Get the attribute information */
+ if(H5A__get_info(fh_udata.attr, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, H5_ITER_ERROR, "unable to get attribute info")
+
+ /* Make the application callback */
+ ret_value = (bt2_udata->attr_op->u.app_op2)(bt2_udata->loc_id, fh_udata.attr->shared->name, &ainfo, bt2_udata->op_data);
+ break;
+ }
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ case H5A_ATTR_OP_APP:
+ /* Make the application callback */
+ ret_value = (bt2_udata->attr_op->u.app_op)(bt2_udata->loc_id, fh_udata.attr->shared->name, bt2_udata->op_data);
+ break;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ case H5A_ATTR_OP_LIB:
+ /* Call the library's callback */
+ ret_value = (bt2_udata->attr_op->u.lib_op)(fh_udata.attr, bt2_udata->op_data);
+ break;
+
+ default:
+ HDassert("unknown attribute op type" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "unsupported attribute op type")
+#endif /* NDEBUG */
+ } /* end switch */
+
+ /* Release the space allocated for the attribute */
+ H5O_msg_free(H5O_ATTR_ID, fh_udata.attr);
+ } /* end else */
+
+ /* Increment the number of attributes passed through */
+ /* (whether we skipped them or not) */
+ bt2_udata->count++;
+
+ /* Check for callback failure and pass along return value */
+ if(ret_value < 0)
+ HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_iterate_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_iterate
+ *
+ * Purpose: Iterate over attributes in dense storage structures for an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_iterate(H5F_t *f, hid_t dxpl_id, hid_t loc_id, const H5O_ainfo_t *ainfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_attr,
+ const H5A_attr_iter_op_t *attr_op, void *op_data)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(H5F_addr_defined(ainfo->fheap_addr));
+ HDassert(H5F_addr_defined(ainfo->name_bt2_addr));
+ HDassert(attr_op);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Check if "native" order is OK - since names are hashed, getting them
+ * in strictly increasing or decreasing order requires building a
+ * table and sorting it.
+ */
+ if(order == H5_ITER_NATIVE) {
+ HDassert(H5F_addr_defined(ainfo->name_bt2_addr));
+ bt2_addr = ainfo->name_bt2_addr;
+ } /* end if */
+ else
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links, a table will be built.
+ */
+ bt2_addr = ainfo->corder_bt2_addr;
+ } /* end else */
+
+ /* Check on iteration order */
+ if(order == H5_ITER_NATIVE && H5F_addr_defined(bt2_addr)) {
+ H5A_bt2_ud_it_t udata; /* User data for iterator callback */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Construct the user data for v2 B-tree iterator callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.loc_id = loc_id;
+ udata.skip = skip;
+ udata.count = 0;
+ udata.attr_op = attr_op;
+ udata.op_data = op_data;
+
+ /* Iterate over the records in the v2 B-tree's "native" order */
+ /* (by hash of name) */
+ if((ret_value = H5B2_iterate(bt2, dxpl_id, H5A__dense_iterate_bt2_cb, &udata)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "attribute iteration failed");
+
+ /* Update the last attribute examined, if requested */
+ if(last_attr)
+ *last_attr = udata.count;
+ } /* end if */
+ else {
+ /* Build the table of attributes for this object */
+ /* (build table using the name index, but sort according to idx_type) */
+ if(H5A_dense_build_table(f, dxpl_id, ainfo, idx_type, order, &atable) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error building table of attributes")
+
+ /* Iterate over attributes in table */
+ if((ret_value = H5A_attr_iterate_table(&atable, skip, last_attr, loc_id, attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed");
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(atable.attrs && H5A_attr_release_table(&atable) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_remove_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense attribute storage record removal
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_remove_bt2_cb(const void *_record, void *_udata)
+{
+ const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record;
+ H5A_bt2_ud_rm_t *udata = (H5A_bt2_ud_rm_t *)_udata; /* User data for callback */
+ H5A_t *attr = *(H5A_t **)udata->common.found_op_data; /* Pointer to attribute to remove */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check for removing the link from the creation order index */
+ if(H5F_addr_defined(udata->corder_bt2_addr)) {
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(udata->common.f, udata->common.dxpl_id, udata->corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata->common.corder = attr->shared->crt_idx;
+
+ /* Remove the record from the creation order index v2 B-tree */
+ if(H5B2_remove(bt2_corder, udata->common.dxpl_id, udata, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from creation order index v2 B-tree")
+ } /* end if */
+
+ /* Check for removing shared attribute */
+ if(record->flags & H5O_MSG_FLAG_SHARED) {
+ /* Decrement the reference count on the shared attribute message */
+ if(H5SM_delete(udata->common.f, udata->common.dxpl_id, NULL, &(attr->sh_loc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute")
+ } /* end if */
+ else {
+ /* Perform the deletion action on the attribute */
+ /* (takes care of shared & committed datatype/dataspace components) */
+ if(H5O_attr_delete(udata->common.f, udata->common.dxpl_id, NULL, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+
+ /* Remove record from fractal heap */
+ if(H5HF_remove(udata->common.fheap, udata->common.dxpl_id, &record->id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from fractal heap")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(bt2_corder && H5B2_close(bt2_corder, udata->common.dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_remove_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_remove
+ *
+ * Purpose: Remove an attribute from the dense storage of an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_remove(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, const char *name)
+{
+ H5A_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5A_t *attr_copy = NULL; /* Copy of attribute to remove */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(name && *name);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata.common.f = f;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.fheap = fheap;
+ udata.common.shared_fheap = shared_fheap;
+ udata.common.name = name;
+ udata.common.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0);
+ udata.common.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */
+ udata.common.found_op_data = &attr_copy;
+ udata.corder_bt2_addr = ainfo->corder_bt2_addr;
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove(bt2_name, dxpl_id, &udata, H5A__dense_remove_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from name index v2 B-tree")
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(attr_copy)
+ H5O_msg_free_real(H5O_MSG_ATTR, attr_copy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_remove_by_idx_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense attribute storage record removal by index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 14 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ H5HF_t *fheap; /* Fractal heap handle */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; /* v2 B-tree record */
+ H5A_bt2_ud_rmbi_t *bt2_udata = (H5A_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */
+ H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */
+ H5O_shared_t sh_loc; /* Shared message info for attribute */
+ hbool_t use_sh_loc; /* Whether to use the attribute's shared location or the separate one */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Set up the user data for fractal heap 'op' callback */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.record = record;
+ fh_udata.attr = NULL;
+
+ /* Get correct fractal heap handle to use for operations */
+ if(record->flags & H5O_MSG_FLAG_SHARED)
+ fheap = bt2_udata->shared_fheap;
+ else
+ fheap = bt2_udata->fheap;
+
+ /* Check whether to make a copy of the attribute or just need the shared location info */
+ if(H5F_addr_defined(bt2_udata->other_bt2_addr) || !(record->flags & H5O_MSG_FLAG_SHARED)) {
+ /* Call fractal heap 'op' routine, to make copy of attribute to remove */
+ if(H5HF_op(fheap, bt2_udata->dxpl_id, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, FAIL, "attribute removal callback failed")
+ HDassert(fh_udata.attr);
+
+ /* Use the attribute's shared location */
+ use_sh_loc = FALSE;
+ } /* end if */
+ else {
+ /* Create a shared message location from the heap ID for this record */
+ H5SM_reconstitute(&sh_loc, bt2_udata->f, H5O_ATTR_ID, record->id);
+
+ /* Use the separate shared location */
+ use_sh_loc = TRUE;
+ } /* end else */
+
+ /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */
+ if(H5F_addr_defined(bt2_udata->other_bt2_addr)) {
+ H5A_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */
+
+ /* Determine the index being used */
+ if(bt2_udata->idx_type == H5_INDEX_NAME) {
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ other_bt2_udata.corder = fh_udata.attr->shared->crt_idx;
+ } /* end if */
+ else {
+ HDassert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER);
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ other_bt2_udata.f = bt2_udata->f;
+ other_bt2_udata.dxpl_id = bt2_udata->dxpl_id;
+ other_bt2_udata.fheap = bt2_udata->fheap;
+ other_bt2_udata.shared_fheap = bt2_udata->shared_fheap;
+ other_bt2_udata.name = fh_udata.attr->shared->name;
+ other_bt2_udata.name_hash = H5_checksum_lookup3(fh_udata.attr->shared->name, HDstrlen(fh_udata.attr->shared->name), 0);
+ other_bt2_udata.found_op = NULL;
+ other_bt2_udata.found_op_data = NULL;
+ } /* end else */
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(bt2_udata->f, bt2_udata->dxpl_id, bt2_udata->other_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Set the common information for the v2 B-tree remove operation */
+
+ /* Remove the record from the "other" index v2 B-tree */
+ if(H5B2_remove(bt2, bt2_udata->dxpl_id, &other_bt2_udata, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove record from 'other' index v2 B-tree")
+ } /* end if */
+
+ /* Check for removing shared attribute */
+ if(record->flags & H5O_MSG_FLAG_SHARED) {
+ H5O_shared_t *sh_loc_ptr; /* Pointer to shared message info for attribute */
+
+ /* Set up pointer to correct shared location */
+ if(use_sh_loc)
+ sh_loc_ptr = &sh_loc;
+ else
+ sh_loc_ptr = &(fh_udata.attr->sh_loc);
+
+ /* Decrement the reference count on the shared attribute message */
+ if(H5SM_delete(bt2_udata->f, bt2_udata->dxpl_id, NULL, sh_loc_ptr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute")
+ } /* end if */
+ else {
+ /* Perform the deletion action on the attribute */
+ /* (takes care of shared & committed datatype/dataspace components) */
+ if(H5O_attr_delete(bt2_udata->f, bt2_udata->dxpl_id, NULL, fh_udata.attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+
+ /* Remove record from fractal heap */
+ if(H5HF_remove(fheap, bt2_udata->dxpl_id, &record->id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from fractal heap")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(bt2 && H5B2_close(bt2, bt2_udata->dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(fh_udata.attr)
+ H5O_msg_free(H5O_ATTR_ID, fh_udata.attr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_remove_by_idx_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_remove_by_idx
+ *
+ * Purpose: Remove an attribute from the dense storage of an object,
+ * according to the order within an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 14 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_remove_by_idx(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Check if "native" order is OK - since names are hashed, getting them
+ * in strictly increasing or decreasing order requires building a
+ * table and sorting it.
+ */
+ if(order == H5_ITER_NATIVE) {
+ bt2_addr = ainfo->name_bt2_addr;
+ HDassert(H5F_addr_defined(bt2_addr));
+ } /* end if */
+ else
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links, a table will be built.
+ */
+ bt2_addr = ainfo->corder_bt2_addr;
+ } /* end else */
+
+ /* If there is an index defined for the field, use it */
+ if(H5F_addr_defined(bt2_addr)) {
+ H5A_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.idx_type = idx_type;
+ udata.other_bt2_addr = idx_type == H5_INDEX_NAME ? ainfo->corder_bt2_addr : ainfo->name_bt2_addr;
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove_by_idx(bt2, dxpl_id, order, n, H5A__dense_remove_by_idx_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from v2 B-tree index")
+ } /* end if */
+ else {
+ /* Build the table of attributes for this object */
+ /* (build table using the name index, but sort according to idx_type) */
+ if(H5A_dense_build_table(f, dxpl_id, ainfo, idx_type, order, &atable) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error building table of attributes")
+
+ /* Check for skipping too many attributes */
+ if(n >= atable.nattrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+
+ /* Delete appropriate attribute from dense storage */
+ if(H5A_dense_remove(f, dxpl_id, ainfo, ((atable.attrs[n])->shared)->name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(atable.attrs && H5A_attr_release_table(&atable) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_exists
+ *
+ * Purpose: Check if an attribute exists in dense storage structures for
+ * an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5A_dense_exists(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo, const char *name)
+{
+ H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t attr_sharable; /* Flag indicating attributes are sharable */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(name);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Check if attributes are shared in this file */
+ if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared")
+
+ /* Get handle for shared message heap, if attributes are sharable */
+ if(attr_sharable) {
+ haddr_t shared_fheap_addr; /* Address of fractal heap to use */
+
+ /* Retrieve the address of the shared message's fractal heap */
+ if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address")
+
+ /* Check if there are any shared messages currently */
+ if(H5F_addr_defined(shared_fheap_addr)) {
+ /* Open the fractal heap for shared header messages */
+ if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+ } /* end if */
+ } /* end if */
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Create the "udata" information for v2 B-tree record 'find' */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = shared_fheap;
+ udata.name = name;
+ udata.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0);
+ udata.flags = 0;
+ udata.corder = 0;
+ udata.found_op = NULL; /* v2 B-tree comparison callback */
+ udata.found_op_data = NULL;
+
+ /* Find the attribute in the 'name' index */
+ if((ret_value = H5B2_find(bt2_name, dxpl_id, &udata, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't search for attribute in name index")
+
+done:
+ /* Release resources */
+ if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_delete_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense attribute storage deletion
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 3 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_delete_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */
+ H5A_bt2_ud_common_t *bt2_udata = (H5A_bt2_ud_common_t *)_bt2_udata; /* User data for callback */
+ H5A_t *attr = NULL; /* Attribute being removed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check for shared attribute */
+ if(record->flags & H5O_MSG_FLAG_SHARED) {
+ H5O_shared_t sh_mesg; /* Temporary shared message info */
+
+ /* "reconstitute" the shared message info for the attribute */
+ H5SM_reconstitute(&sh_mesg, bt2_udata->f, H5O_ATTR_ID, record->id);
+
+ /* Decrement the reference count on the shared attribute message */
+ if(H5SM_delete(bt2_udata->f, bt2_udata->dxpl_id, NULL, &sh_mesg) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute")
+ } /* end if */
+ else {
+ H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.record = record;
+ /* up */
+ fh_udata.attr = NULL;
+
+ /* Call fractal heap 'op' routine, to copy the attribute information */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, FAIL, "heap op callback failed")
+ attr = fh_udata.attr;
+
+ /* Perform the deletion action on the attribute */
+ /* (takes care of shared/committed datatype & dataspace components) */
+ if(H5O_attr_delete(bt2_udata->f, bt2_udata->dxpl_id, NULL, fh_udata.attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(attr)
+ H5O_msg_free_real(H5O_MSG_ATTR, attr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_delete_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_delete
+ *
+ * Purpose: Delete all dense storage structures for attributes on an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_delete(H5F_t *f, hid_t dxpl_id, H5O_ainfo_t *ainfo)
+{
+ H5A_bt2_ud_common_t udata; /* v2 B-tree user data for deleting attributes */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ainfo);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo->fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Create the "udata" information for v2 B-tree 'delete' */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.shared_fheap = NULL;
+ udata.name = NULL;
+ udata.name_hash = 0;
+ udata.flags = 0;
+ udata.found_op = NULL; /* v2 B-tree comparison callback */
+ udata.found_op_data = NULL;
+
+ /* Delete name index v2 B-tree */
+ if(H5B2_delete(f, dxpl_id, ainfo->name_bt2_addr, NULL, H5A__dense_delete_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index")
+ ainfo->name_bt2_addr = HADDR_UNDEF;
+
+ /* Release resources */
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ fheap = NULL;
+
+ /* Check if we should delete the creation order index v2 B-tree */
+ if(H5F_addr_defined(ainfo->corder_bt2_addr)) {
+ /* Delete the creation order index, without adjusting the ref. count on the attributes */
+ if(H5B2_delete(f, dxpl_id, ainfo->corder_bt2_addr, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for creation order index")
+ ainfo->corder_bt2_addr = HADDR_UNDEF;
+ } /* end if */
+
+ /* Delete fractal heap */
+ if(H5HF_delete(f, dxpl_id, ainfo->fheap_addr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
+ ainfo->fheap_addr = HADDR_UNDEF;
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_delete() */
+
diff --git a/src/H5Adeprec.c b/src/H5Adeprec.c
new file mode 100644
index 0000000..9221254
--- /dev/null
+++ b/src/H5Adeprec.c
@@ -0,0 +1,411 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Adeprec.c
+ * November 27 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5A interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Object headers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Acreate1
+ PURPOSE
+ Creates an attribute on an object
+ USAGE
+ hid_t H5Acreate1(loc_id, name, type_id, space_id, plist_id)
+ hid_t loc_id; IN: Object (dataset or group) to be attached to
+ const char *name; IN: Name of attribute to create
+ hid_t type_id; IN: ID of datatype for attribute
+ hid_t space_id; IN: ID of dataspace for attribute
+ hid_t plist_id; IN: ID of creation property list (currently not used)
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function creates an attribute which is attached to the object
+ specified with 'location_id'. The name specified with 'name' for each
+ attribute for an object must be unique for that object. The 'type_id'
+ and 'space_id' are created with the H5T and H5S interfaces respectively.
+ The attribute ID returned from this function must be released with H5Aclose
+ or resource leaks will develop.
+
+ NOTE
+ Deprecated in favor of H5Acreate2
+
+--------------------------------------------------------------------------*/
+hid_t
+H5Acreate1(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id,
+ hid_t plist_id)
+{
+ H5A_t *attr = NULL; /* Attribute created */
+ H5G_loc_t loc; /* Object location */
+ H5T_t *type; /* Datatype to use for attribute */
+ H5S_t *space; /* Dataspace to use for attribute */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("i", "i*siii", loc_id, name, type_id, space_id, plist_id);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(0 == (H5F_INTENT(loc.oloc->file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_ARGS, H5E_WRITEERROR, FAIL, "no write intent on file")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a type")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Go do the real work for attaching the attribute to the dataset */
+ if(NULL==(attr = H5A_create(&loc, name, type, space, plist_id, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create attribute")
+
+ /* Register the new attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Acreate1() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aopen_name
+ PURPOSE
+ Opens an attribute for an object by looking up the attribute name
+ USAGE
+ hid_t H5Aopen_name (loc_id, name)
+ hid_t loc_id; IN: Object (dataset or group) to be attached to
+ const char *name; IN: Name of attribute to locate and open
+ RETURNS
+ ID of attribute on success, negative on failure
+
+ DESCRIPTION
+ This function opens an existing attribute for access. The attribute
+ name specified is used to look up the corresponding attribute for the
+ object. The attribute ID returned from this function must be released with
+ H5Aclose or resource leaks will develop.
+ The location object may be either a group or a dataset, both of
+ which may have any sort of attribute.
+ NOTE
+ Deprecated in favor of H5Aopen
+--------------------------------------------------------------------------*/
+hid_t
+H5Aopen_name(hid_t loc_id, const char *name)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute opened */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "i*s", loc_id, name);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Open the attribute on the object header */
+ if(NULL == (attr = H5A_open_by_name(&loc, ".", name, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute: '%s'", name)
+
+ /* Register the attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aopen_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aopen_idx
+ PURPOSE
+ Opens the n'th attribute for an object
+ USAGE
+ hid_t H5Aopen_idx (loc_id, idx)
+ hid_t loc_id; IN: Object that attribute is attached to
+ unsigned idx; IN: Index (0-based) attribute to open
+ RETURNS
+ ID of attribute on success, negative on failure
+
+ DESCRIPTION
+ This function opens an existing attribute for access. The attribute
+ index specified is used to look up the corresponding attribute for the
+ object. The attribute ID returned from this function must be released with
+ H5Aclose or resource leaks will develop.
+ The location object may be either a group or a dataset, both of
+ which may have any sort of attribute.
+ NOTE
+ Deprecated in favor of H5Aopen_by_idx
+--------------------------------------------------------------------------*/
+hid_t
+H5Aopen_idx(hid_t loc_id, unsigned idx)
+{
+ H5G_loc_t loc; /* Object location */
+ H5A_t *attr = NULL; /* Attribute opened */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "iIu", loc_id, idx);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Open the attribute in the object header */
+ if(NULL == (attr = H5A_open_by_idx(&loc, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)idx, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open attribute")
+
+ /* Register the attribute and get an ID for it */
+ if((ret_value = H5I_register(H5I_ATTR, attr, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "can't close attribute")
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aopen_idx() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aget_num_attrs
+ PURPOSE
+ Determines the number of attributes attached to an object
+ NOTE
+ Deprecated in favor of H5Oget_info[_by_idx]
+ USAGE
+ int H5Aget_num_attrs (loc_id)
+ hid_t loc_id; IN: Object (dataset or group) to be queried
+ RETURNS
+ Number of attributes on success, negative on failure
+ DESCRIPTION
+ This function returns the number of attributes attached to a dataset or
+ group, 'location_id'.
+ NOTE
+ Deprecated in favor of H5Oget_info
+--------------------------------------------------------------------------*/
+int
+H5Aget_num_attrs(hid_t loc_id)
+{
+ H5O_loc_t *loc; /* Object location for attribute */
+ void *obj;
+ int ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", loc_id);
+
+ /* check arguments */
+ if(H5I_BADID == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad location ID")
+ if(H5I_FILE == H5I_get_type(loc_id) || H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+ if(NULL == (obj = H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADATOM, FAIL, "illegal object atom")
+ switch(H5I_get_type (loc_id)) {
+ case H5I_DATASET:
+ if(NULL == (loc = H5D_oloc((H5D_t*)obj)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get location for object")
+ break;
+
+ case H5I_DATATYPE:
+ if(NULL == (loc = H5T_oloc((H5T_t*)obj)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "target datatype is not committed")
+ break;
+
+ case H5I_GROUP:
+ if(NULL == (loc = H5G_oloc((H5G_t*)obj)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get location for object")
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "inappropriate attribute target")
+ } /*lint !e788 All appropriate cases are covered */
+
+ /* Look up the # of attributes for the object */
+ if((ret_value = H5O_attr_count(loc, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOUNT, FAIL, "can't get attribute count for object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aget_num_attrs() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Aiterate1
+ PURPOSE
+ Calls a user's function for each attribute on an object
+ USAGE
+ herr_t H5Aiterate1(loc_id, attr_num, op, data)
+ hid_t loc_id; IN: Object (dataset or group) to be iterated over
+ unsigned *attr_num; IN/OUT: Starting (IN) & Ending (OUT) attribute number
+ H5A_operator1_t op; IN: User's function to pass each attribute to
+ void *op_data; IN/OUT: User's data to pass through to iterator operator function
+ RETURNS
+ Returns a negative value if something is wrong, the return value of the
+ last operator if it was non-zero, or zero if all attributes were processed.
+
+ DESCRIPTION
+ This function interates over the attributes of dataset or group
+ specified with 'loc_id'. For each attribute of the object, the
+ 'op_data' and some additional information (specified below) are passed
+ to the 'op' function. The iteration begins with the '*attr_number'
+ object in the group and the next attribute to be processed by the operator
+ is returned in '*attr_number'.
+ The operation receives the ID for the group or dataset being iterated
+ over ('loc_id'), the name of the current attribute about the object
+ ('attr_name') and the pointer to the operator data passed in to H5Aiterate
+ ('op_data'). The return values from an operator are:
+ A. Zero causes the iterator to continue, returning zero when all
+ attributes have been processed.
+ B. Positive causes the iterator to immediately return that positive
+ value, indicating short-circuit success. The iterator can be
+ restarted at the next attribute.
+ C. Negative causes the iterator to immediately return that value,
+ indicating failure. The iterator can be restarted at the next
+ attribute.
+ NOTE
+ Deprecated in favor of H5Aiterate2
+--------------------------------------------------------------------------*/
+herr_t
+H5Aiterate1(hid_t loc_id, unsigned *attr_num, H5A_operator1_t op, void *op_data)
+{
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+ hsize_t start_idx; /* Index of attribute to start iterating at */
+ hsize_t last_attr; /* Index of last attribute examined */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*Iux*x", loc_id, attr_num, op, op_data);
+
+ /* check arguments */
+ if(H5I_ATTR == H5I_get_type(loc_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute")
+
+ /* Build attribute operator info */
+ attr_op.op_type = H5A_ATTR_OP_APP;
+ attr_op.u.app_op = op;
+
+ /* Call attribute iteration routine */
+ last_attr = start_idx = (hsize_t)(attr_num ? *attr_num : 0);
+ if((ret_value = H5O_attr_iterate(loc_id, H5AC_ind_read_dxpl_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, start_idx, &last_attr, &attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+
+ /* Set the last attribute information */
+ if(attr_num)
+ *attr_num = (unsigned)last_attr;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Aiterate1() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Aint.c b/src/H5Aint.c
new file mode 100644
index 0000000..160c7fb
--- /dev/null
+++ b/src/H5Aint.c
@@ -0,0 +1,2435 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Aint.c
+ * Dec 18 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal routines for managing attributes.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Data exchange structure to use when building table of compact attributes for an object */
+typedef struct {
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5A_attr_table_t *atable; /* Pointer to attribute table to build */
+ size_t curr_attr; /* Current attribute to operate on */
+ hbool_t bogus_crt_idx; /* Whether bogus creation index values need to be set */
+} H5A_compact_bt_ud_t;
+
+/* Data exchange structure to use when building table of dense attributes for an object */
+typedef struct {
+ H5A_attr_table_t *atable; /* Pointer to attribute table to build */
+ size_t curr_attr; /* Current attribute to operate on */
+} H5A_dense_bt_ud_t;
+
+/* Data exchange structure to use when copying an attribute from _SRC to _DST */
+typedef struct {
+ const H5O_ainfo_t *ainfo; /* dense information */
+ H5F_t *file; /* file */
+ hbool_t *recompute_size; /* Flag to indicate if size changed */
+ H5O_copy_t *cpy_info; /* Information on copying options */
+ hid_t dxpl_id; /* DXPL for operation */
+ const H5O_loc_t *oloc_src;
+ H5O_loc_t *oloc_dst;
+} H5A_dense_file_cp_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5A__compact_build_table_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned sequence, unsigned *oh_flags_ptr, void *_udata/*in,out*/);
+static herr_t H5A__dense_build_table_cb(const H5A_t *attr, void *_udata);
+static int H5A__attr_cmp_name_inc(const void *attr1, const void *attr2);
+static int H5A__attr_cmp_name_dec(const void *attr1, const void *attr2);
+static int H5A__attr_cmp_corder_inc(const void *attr1, const void *attr2);
+static int H5A__attr_cmp_corder_dec(const void *attr1, const void *attr2);
+static herr_t H5A__attr_sort_table(H5A_attr_table_t *atable, H5_index_t idx_type,
+ H5_iter_order_t order);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+typedef H5A_t* H5A_t_ptr;
+H5FL_SEQ_DEFINE(H5A_t_ptr);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_create
+ *
+ * Purpose:
+ * This is the guts of creating an attribute.
+ * Usage:
+ * hid_t H5A_create(ent, name, type, space)
+ * const H5G_entry_t *ent; IN: Pointer to symbol table entry for object to attribute
+ * const char *name; IN: Name of attribute
+ * H5T_t *type; IN: Datatype of attribute
+ * H5S_t *space; IN: Dataspace of attribute
+ * hid_t acpl_id IN: Attribute creation property list
+ *
+ * Return: attribute structure on success, NULL on Failure.
+ *
+ * Programmer: Quincey Koziol
+ * April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_create(const H5G_loc_t *loc, const char *name, const H5T_t *type,
+ const H5S_t *space, hid_t acpl_id, hid_t dxpl_id)
+{
+ H5A_t *attr = NULL; /* Attribute created */
+ hssize_t snelmts; /* elements in attribute */
+ size_t nelmts; /* elements in attribute */
+ htri_t exists; /* Whether attribute exists */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->oloc->addr, NULL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(name);
+ HDassert(type);
+ HDassert(space);
+
+ /* Check for existing attribute with same name */
+ /* (technically, the "attribute create" operation will fail for a duplicated
+ * name, but it's going to be hard to unwind all the special cases on
+ * failure, so just check first, for now - QAK)
+ */
+ if((exists = H5O_attr_exists(loc->oloc, name, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "error checking attributes")
+ else if(exists > 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_ALREADYEXISTS, NULL, "attribute already exists")
+
+ /* Check if the dataspace has an extent set (or is NULL) */
+ if(!(H5S_has_extent(space)))
+ HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, NULL, "dataspace extent has not been set")
+
+ /* Check if the datatype is "sensible" for use in a dataset */
+ if(H5T_is_sensible(type) != TRUE)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADTYPE, NULL, "datatype is not sensible")
+
+ /* Build the attribute information */
+ if(NULL == (attr = H5FL_CALLOC(H5A_t)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, NULL, "memory allocation failed for attribute info")
+
+ if(NULL == (attr->shared = H5FL_CALLOC(H5A_shared_t)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, NULL, "can't allocate shared attr structure")
+
+ /* If the creation property list is H5P_DEFAULT, use the default character encoding */
+ if(acpl_id == H5P_DEFAULT)
+ attr->shared->encoding = H5F_DEFAULT_CSET;
+ else {
+ H5P_genplist_t *ac_plist; /* ACPL Property list */
+
+ /* Get a local copy of the attribute creation property list */
+ if(NULL == (ac_plist = (H5P_genplist_t *)H5I_object(acpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property list")
+
+ if(H5P_get(ac_plist, H5P_STRCRT_CHAR_ENCODING_NAME, &(attr->shared->encoding)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get character encoding flag")
+ } /* end else */
+
+ /* Copy the attribute name */
+ attr->shared->name = H5MM_xstrdup(name);
+
+ /* Copy datatype */
+ if(NULL == (attr->shared->dt = H5T_copy(type, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't get shared datatype info")
+
+ /* Convert a datatype (if committed) to a transient type if the committed datatype's file
+ location is different from the file location where the attribute will be created */
+ if(H5T_convert_committed_datatype(attr->shared->dt, loc->oloc->file) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't get shared datatype info")
+
+ /* Mark datatype as being on disk now */
+ if(H5T_set_loc(attr->shared->dt, loc->oloc->file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ /* Set the latest format for datatype, if requested */
+ if(H5F_USE_LATEST_FLAGS(loc->oloc->file, H5F_LATEST_DATATYPE))
+ if(H5T_set_latest_version(attr->shared->dt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest version of datatype")
+
+ /* Copy the dataspace for the attribute */
+ attr->shared->ds = H5S_copy(space, FALSE, TRUE);
+
+ /* Set the latest format for dataspace, if requested */
+ if(H5F_USE_LATEST_FLAGS(loc->oloc->file, H5F_LATEST_DATASPACE))
+ if(H5S_set_latest_version(attr->shared->ds) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest version of dataspace")
+
+ /* Copy the object header information */
+ if(H5O_loc_copy(&(attr->oloc), loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to copy entry")
+
+ /* Deep copy of the group hierarchy path */
+ if(H5G_name_copy(&(attr->path), loc->path, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "unable to copy path")
+
+ /* Check if any of the pieces should be (or are already) shared in the
+ * SOHM table
+ */
+ if(H5SM_try_share(attr->oloc.file, dxpl_id, NULL, 0, H5O_DTYPE_ID, attr->shared->dt, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, NULL, "trying to share datatype failed")
+ if(H5SM_try_share(attr->oloc.file, dxpl_id, NULL, 0, H5O_SDSPACE_ID, attr->shared->ds, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, NULL, "trying to share dataspace failed")
+
+ /* Check whether datatype is committed & increment ref count
+ * (to maintain ref. count incr/decr similarity with "shared message"
+ * type of datatype sharing)
+ */
+ if(H5T_committed(attr->shared->dt)) {
+ /* Increment the reference count on the shared datatype */
+ if(H5T_link(attr->shared->dt, 1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, NULL, "unable to adjust shared datatype link count")
+ } /* end if */
+
+ /* Compute the size of pieces on disk. This is either the size of the
+ * datatype and dataspace messages themselves, or the size of the "shared"
+ * messages if either or both of them are shared.
+ */
+ attr->shared->dt_size = H5O_msg_raw_size(attr->oloc.file, H5O_DTYPE_ID, FALSE, attr->shared->dt);
+ attr->shared->ds_size = H5O_msg_raw_size(attr->oloc.file, H5O_SDSPACE_ID, FALSE, attr->shared->ds);
+
+ /* Get # of elements for attribute's dataspace */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(attr->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOUNT, NULL, "dataspace is invalid")
+ H5_CHECKED_ASSIGN(nelmts, size_t, snelmts, hssize_t);
+
+ HDassert(attr->shared->dt_size > 0);
+ HDassert(attr->shared->ds_size > 0);
+ attr->shared->data_size = nelmts * H5T_GET_SIZE(attr->shared->dt);
+
+ /* Hold the symbol table entry (and file) open */
+ if(H5O_open(&(attr->oloc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open")
+ attr->obj_opened = TRUE;
+
+ /* Set the version to encode the attribute with */
+ if(H5A_set_version(attr->oloc.file, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, NULL, "unable to update attribute version")
+
+ /* Insert the attribute into the object header */
+ if(H5O_attr_create(&(attr->oloc), dxpl_id, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, NULL, "unable to create attribute in object header")
+
+ ret_value = attr;
+done:
+ if(NULL == ret_value && attr && H5A_close(attr))
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "can't close attribute")
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* H5A_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__open_common
+ *
+ * Purpose:
+ * Finishes initializing an attributes the open
+ *
+ * Usage:
+ * herr_t H5A__open_common(loc, name, dxpl_id)
+ * const H5G_loc_t *loc; IN: Pointer to group location for object
+ * H5A_t *attr; IN/OUT: Pointer to attribute to initialize
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * December 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A__open_common(const H5G_loc_t *loc, H5A_t *attr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(loc);
+ HDassert(attr);
+
+#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
+ /* Clear object location */
+ if(H5O_loc_reset(&(attr->oloc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to reset location")
+#endif /* H5_USING_MEMCHECKER */
+
+ /* Free any previous group hier. path */
+ if(H5G_name_free(&(attr->path)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release group hier. path")
+
+ /* Deep copy of the symbol table entry */
+ if(H5O_loc_copy(&(attr->oloc), loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to copy entry")
+
+ /* Deep copy of the group hier. path */
+ if(H5G_name_copy(&(attr->path), loc->path, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "unable to copy entry")
+
+ /* Hold the symbol table entry (and file) open */
+ if(H5O_open(&(attr->oloc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open")
+ attr->obj_opened = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A__open_common() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_open_by_idx
+ *
+ * Purpose: Open an attribute according to its index order
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_open_by_idx(const H5G_loc_t *loc, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ H5A_t *attr = NULL; /* Attribute from object header */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(loc);
+ HDassert(obj_name);
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "object not found")
+ loc_found = TRUE;
+
+ /* Read in attribute from object header */
+ if(NULL == (attr = H5O_attr_open_by_idx(obj_loc.oloc, idx_type, order, n, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to load attribute info from object header")
+
+ /* Finish initializing attribute */
+ if(H5A__open_common(&obj_loc, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to initialize attribute")
+
+ /* Set return value */
+ ret_value = attr;
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, NULL, "can't free location")
+
+ /* Cleanup on failure */
+ if(ret_value == NULL)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_open_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_open_by_name
+ *
+ * Purpose: Open an attribute in an object header, according to it's name
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * December 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_open_by_name(const H5G_loc_t *loc, const char *obj_name, const char *attr_name,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ H5A_t *attr = NULL; /* Attribute from object header */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(obj_name);
+ HDassert(attr_name);
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "object not found")
+ loc_found = TRUE;
+
+ /* Read in attribute from object header */
+ if(NULL == (attr = H5O_attr_open_by_name(obj_loc.oloc, attr_name, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to load attribute info from object header")
+
+ /* Finish initializing attribute */
+ if(H5A__open_common(loc, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to initialize attribute")
+
+ /* Set return value */
+ ret_value = attr;
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, NULL, "can't free location")
+
+ /* Cleanup on failure */
+ if(ret_value == NULL)
+ if(attr && H5A_close(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_open_by_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A__read
+ PURPOSE
+ Actually read in data from an attribute
+ USAGE
+ herr_t H5A__read (attr, mem_type, buf)
+ H5A_t *attr; IN: Attribute to read
+ const H5T_t *mem_type; IN: Memory datatype of buffer
+ void *buf; IN: Buffer for data to read
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function reads a complete attribute from disk.
+--------------------------------------------------------------------------*/
+herr_t
+H5A__read(const H5A_t *attr, const H5T_t *mem_type, void *buf, hid_t dxpl_id)
+{
+ uint8_t *tconv_buf = NULL; /* datatype conv buffer*/
+ uint8_t *bkg_buf = NULL; /* background buffer */
+ hssize_t snelmts; /* elements in attribute */
+ size_t nelmts; /* elements in attribute*/
+ H5T_path_t *tpath = NULL; /* type conversion info */
+ hid_t src_id = -1, dst_id = -1;/* temporary type atoms*/
+ size_t src_type_size; /* size of source type */
+ size_t dst_type_size; /* size of destination type */
+ size_t buf_size; /* desired buffer size */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(attr);
+ HDassert(mem_type);
+ HDassert(buf);
+
+ /* Create buffer for data to store on disk */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(attr->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOUNT, FAIL, "dataspace is invalid")
+ H5_CHECKED_ASSIGN(nelmts, size_t, snelmts, hssize_t);
+
+ if(nelmts > 0) {
+ /* Get the memory and file datatype sizes */
+ src_type_size = H5T_GET_SIZE(attr->shared->dt);
+ dst_type_size = H5T_GET_SIZE(mem_type);
+
+ /* Check if the attribute has any data yet, if not, fill with zeroes */
+ if(attr->obj_opened && !attr->shared->data)
+ HDmemset(buf, 0, (dst_type_size * nelmts));
+ else { /* Attribute exists and has a value */
+ /* Convert memory buffer into disk buffer */
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(attr->shared->dt, mem_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dst datatypes")
+
+ /* Check for type conversion required */
+ if(!H5T_path_noop(tpath)) {
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(attr->shared->dt, H5T_COPY_ALL), FALSE)) < 0 ||
+ (dst_id = H5I_register(H5I_DATATYPE, H5T_copy(mem_type, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+
+ /* Get the maximum buffer size needed and allocate it */
+ buf_size = nelmts * MAX(src_type_size, dst_type_size);
+ if(NULL == (tconv_buf = H5FL_BLK_MALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (bkg_buf = H5FL_BLK_CALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy the attribute data into the buffer for conversion */
+ HDmemcpy(tconv_buf, attr->shared->data, (src_type_size * nelmts));
+
+ /* Perform datatype conversion. */
+ if(H5T_convert(tpath, src_id, dst_id, nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "datatype conversion failed")
+
+ /* Copy the converted data into the user's buffer */
+ HDmemcpy(buf, tconv_buf, (dst_type_size * nelmts));
+ } /* end if */
+ /* No type conversion necessary */
+ else {
+ HDassert(dst_type_size == src_type_size);
+
+ /* Copy the attribute data into the user's buffer */
+ HDmemcpy(buf, attr->shared->data, (dst_type_size * nelmts));
+ } /* end else */
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(src_id >= 0 && H5I_dec_ref(src_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(dst_id >= 0 && H5I_dec_ref(dst_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(tconv_buf)
+ tconv_buf = H5FL_BLK_FREE(attr_buf, tconv_buf);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(attr_buf, bkg_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A__read() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A__write
+ PURPOSE
+ Actually write out data to an attribute
+ USAGE
+ herr_t H5A__write (attr, mem_type, buf)
+ H5A_t *attr; IN: Attribute to write
+ const H5T_t *mem_type; IN: Memory datatype of buffer
+ const void *buf; IN: Buffer of data to write
+ RETURNS
+ Non-negative on success/Negative on failure
+
+ DESCRIPTION
+ This function writes a complete attribute to disk.
+--------------------------------------------------------------------------*/
+herr_t
+H5A__write(H5A_t *attr, const H5T_t *mem_type, const void *buf, hid_t dxpl_id)
+{
+ uint8_t *tconv_buf = NULL; /* datatype conv buffer */
+ hbool_t tconv_owned = FALSE; /* Whether the datatype conv buffer is owned by attribute */
+ uint8_t *bkg_buf = NULL; /* temp conversion buffer */
+ hssize_t snelmts; /* elements in attribute */
+ size_t nelmts; /* elements in attribute */
+ H5T_path_t *tpath = NULL; /* conversion information*/
+ hid_t src_id = -1, dst_id = -1;/* temporary type atoms */
+ size_t src_type_size; /* size of source type */
+ size_t dst_type_size; /* size of destination type*/
+ size_t buf_size; /* desired buffer size */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, attr->oloc.addr, FAIL)
+
+ HDassert(attr);
+ HDassert(mem_type);
+ HDassert(buf);
+
+ /* Get # of elements for attribute's dataspace */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(attr->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOUNT, FAIL, "dataspace is invalid")
+ H5_CHECKED_ASSIGN(nelmts, size_t, snelmts, hssize_t);
+
+ /* If there's actually data elements for the attribute, make a copy of the data passed in */
+ if(nelmts > 0) {
+ /* Get the memory and file datatype sizes */
+ src_type_size = H5T_GET_SIZE(mem_type);
+ dst_type_size = H5T_GET_SIZE(attr->shared->dt);
+
+ /* Convert memory buffer into disk buffer */
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(mem_type, attr->shared->dt, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dst datatypes")
+
+ /* Check for type conversion required */
+ if(!H5T_path_noop(tpath)) {
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(mem_type, H5T_COPY_ALL), FALSE)) < 0 ||
+ (dst_id = H5I_register(H5I_DATATYPE, H5T_copy(attr->shared->dt, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+
+ /* Get the maximum buffer size needed and allocate it */
+ buf_size = nelmts * MAX(src_type_size, dst_type_size);
+ if(NULL == (tconv_buf = H5FL_BLK_MALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ if(NULL == (bkg_buf = H5FL_BLK_CALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Copy the user's data into the buffer for conversion */
+ HDmemcpy(tconv_buf, buf, (src_type_size * nelmts));
+
+ /* Perform datatype conversion */
+ if(H5T_convert(tpath, src_id, dst_id, nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "datatype conversion failed")
+
+ /* Free the previous attribute data buffer, if there is one */
+ if(attr->shared->data)
+ attr->shared->data = H5FL_BLK_FREE(attr_buf, attr->shared->data);
+
+ /* Set the pointer to the attribute data to the converted information */
+ attr->shared->data = tconv_buf;
+ tconv_owned = TRUE;
+ } /* end if */
+ /* No type conversion necessary */
+ else {
+ HDassert(dst_type_size == src_type_size);
+
+ /* Allocate the attribute buffer, if there isn't one */
+ if(attr->shared->data == NULL)
+ if(NULL == (attr->shared->data = H5FL_BLK_MALLOC(attr_buf, dst_type_size * nelmts)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy the attribute data into the user's buffer */
+ HDmemcpy(attr->shared->data, buf, (dst_type_size * nelmts));
+ } /* end else */
+
+ /* Modify the attribute in the object header */
+ if(H5O_attr_write(&(attr->oloc), dxpl_id, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to modify attribute")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(src_id >= 0 && H5I_dec_ref(src_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(dst_id >= 0 && H5I_dec_ref(dst_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(tconv_buf && !tconv_owned)
+ tconv_buf = H5FL_BLK_FREE(attr_buf, tconv_buf);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(attr_buf, bkg_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5A__write() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A__get_name
+ PURPOSE
+ Private function for H5Aget_name. Gets a copy of the name for an
+ attribute
+ RETURNS
+ This function returns the length of the attribute's name (which may be
+ longer than 'buf_size') on success or negative for failure.
+ DESCRIPTION
+ This function retrieves the name of an attribute for an attribute ID.
+ Up to 'buf_size' characters are stored in 'buf' followed by a '\0' string
+ terminator. If the name of the attribute is longer than 'buf_size'-1,
+ the string terminator is stored in the last position of the buffer to
+ properly terminate the string.
+--------------------------------------------------------------------------*/
+ssize_t
+H5A__get_name(H5A_t *attr, size_t buf_size, char *buf)
+{
+ size_t copy_len, nbytes;
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* get the real attribute length */
+ nbytes = HDstrlen(attr->shared->name);
+ HDassert((ssize_t)nbytes >= 0); /*overflow, pretty unlikely --rpm*/
+
+ /* compute the string length which will fit into the user's buffer */
+ copy_len = MIN(buf_size - 1, nbytes);
+
+ /* Copy all/some of the name */
+ if(buf && copy_len > 0) {
+ HDmemcpy(buf, attr->shared->name, copy_len);
+
+ /* Terminate the string */
+ buf[copy_len]='\0';
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (ssize_t)nbytes;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A__get_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_get_space
+ *
+ * Purpose: Returns dataspace of the attribute.
+ *
+ * Return: Success: dataspace
+ *
+ * Failure: NULL
+ *
+ * Programmer: Mohamad Chaarawi
+ * March, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_t *
+H5A_get_space(H5A_t *attr)
+{
+ H5S_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(attr);
+
+ /* Copy the attribute's dataspace */
+ if(NULL == (ret_value = H5S_copy(attr->shared->ds, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to copy dataspace")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_get_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_get_type
+ *
+ * Purpose: Returns datatype of the dataset.
+ *
+ * Return: Success: datatype
+ *
+ * Failure: NULL
+ *
+ * Programmer: Mohamad Chaarawi
+ * March, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5A_get_type(H5A_t *attr)
+{
+ H5T_t *dt = NULL;
+ H5T_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(attr);
+
+ /* Patch the datatype's "top level" file pointer */
+ if(H5T_patch_file(attr->shared->dt, attr->oloc.file) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to patch datatype's file pointer")
+
+ /*
+ * Copy the attribute's datatype. If the type is a named type then
+ * reopen the type before returning it to the user. Make the type
+ * read-only.
+ */
+ if(NULL == (dt = H5T_copy(attr->shared->dt, H5T_COPY_REOPEN)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to copy datatype")
+
+ /* Mark any datatypes as being in memory now */
+ if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ /* Lock copied type */
+ if(H5T_lock(dt, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to lock transient datatype")
+
+ ret_value = dt;
+
+done:
+ if(!ret_value && dt && (H5T_close(dt) < 0))
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, NULL, "unable to release datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_get_type() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5A_get_create_plist
+ PURPOSE
+ private version of H5Aget_create_plist
+ RETURNS
+ This function returns the ID of a copy of the attribute's creation
+ property list, or negative on failure.
+
+ ERRORS
+
+ DESCRIPTION
+ This function returns a copy of the creation property list for
+ an attribute. The resulting ID must be closed with H5Pclose() or
+ resource leaks will occur.
+--------------------------------------------------------------------------*/
+hid_t
+H5A_get_create_plist(H5A_t* attr)
+{
+ H5P_genplist_t *plist; /* Default property list */
+ hid_t new_plist_id; /* ID of ACPL to return */
+ H5P_genplist_t *new_plist; /* ACPL to return */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(H5P_LST_ATTRIBUTE_CREATE_ID_g)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get default ACPL")
+
+ /* Create the property list object to return */
+ if((new_plist_id = H5P_copy_plist(plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy attribute creation properties")
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(new_plist_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Set the character encoding on the new property list */
+ if(H5P_set(new_plist, H5P_STRCRT_CHAR_ENCODING_NAME, &(attr->shared->encoding)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set character encoding")
+
+ ret_value = new_plist_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Aget_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__get_info
+ *
+ * Purpose: Retrieve information about an attribute.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A__get_info(const H5A_t *attr, H5A_info_t *ainfo)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(attr);
+ HDassert(ainfo);
+
+ /* Set info for attribute */
+ ainfo->cset = attr->shared->encoding;
+ ainfo->data_size = attr->shared->data_size;
+ if(attr->shared->crt_idx == H5O_MAX_CRT_ORDER_IDX) {
+ ainfo->corder_valid = FALSE;
+ ainfo->corder = 0;
+ } /* end if */
+ else {
+ ainfo->corder_valid = TRUE;
+ ainfo->corder = attr->shared->crt_idx;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_copy
+ *
+ * Purpose: Copies attribute OLD_ATTR.
+ *
+ * Return: Success: Pointer to a new copy of the OLD_ATTR argument.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ * Modification:Raymond Lu
+ * 4 June 2008
+ * Changed some attribute information to be shared.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_copy(H5A_t *_new_attr, const H5A_t *old_attr)
+{
+ H5A_t *new_attr = NULL;
+ hbool_t allocated_attr = FALSE; /* Whether the attribute was allocated */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(old_attr);
+
+ /* Allocate attribute structure */
+ if(_new_attr == NULL) {
+ if(NULL == (new_attr = H5FL_CALLOC(H5A_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ allocated_attr = TRUE;
+ } /* end if */
+ else
+ new_attr = _new_attr;
+
+ /* Copy the top level of the attribute */
+ new_attr->sh_loc = old_attr->sh_loc;
+
+ /* Deep copy of the group hierarchy path */
+ if(H5G_name_copy(&(new_attr->path), &(old_attr->path), H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "unable to copy path")
+
+ /* Share some attribute information */
+ new_attr->shared = old_attr->shared;
+
+ /* Increment reference count for shared object */
+ new_attr->shared->nrefs++;
+
+ /* Don't open the object header for a copy */
+ new_attr->obj_opened = FALSE;
+
+ /* Set the return value */
+ ret_value = new_attr;
+
+done:
+ if(ret_value == NULL)
+ if(allocated_attr && new_attr && H5A_close(new_attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_free
+ *
+ * Purpose: Frees all memory associated with an attribute, but does not
+ * free the H5A_t structure (which should be done in H5T_close).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 15, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_free(H5A_t *attr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(attr);
+
+ /* Free dynamicly allocated items */
+ if(attr->shared->name) {
+ H5MM_xfree(attr->shared->name);
+ attr->shared->name = NULL;
+ }
+ if(attr->shared->dt) {
+ if(H5T_close(attr->shared->dt) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release datatype info")
+ attr->shared->dt = NULL;
+ }
+ if(attr->shared->ds) {
+ if(H5S_close(attr->shared->ds) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release dataspace info")
+ attr->shared->ds = NULL;
+ }
+ if(attr->shared->data)
+ attr->shared->data = H5FL_BLK_FREE(attr_buf, attr->shared->data);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_close
+ *
+ * Purpose: Frees an attribute and all associated memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ * Modifications:
+ * Raymond Lu
+ * 4 June 2008
+ * Changed some attribute object information to be shared.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_close(H5A_t *attr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(attr);
+ HDassert(attr->shared);
+
+ /* Close the object's symbol-table entry */
+ if(attr->obj_opened && (H5O_close(&(attr->oloc), NULL) < 0))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release object header info")
+
+ /* Reference count can be 0. It only happens when H5A_create fails. */
+ if(attr->shared->nrefs <= 1) {
+ /* Free dynamicly allocated items */
+ if(H5A_free(attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release attribute info")
+
+ /* Destroy shared attribute struct */
+ attr->shared = H5FL_FREE(H5A_shared_t, attr->shared);
+ } /* end if */
+ else {
+ /* There are other references to the shared part of the attribute.
+ * Only decrement the reference count. */
+ --attr->shared->nrefs;
+ } /* end else */
+
+ /* Free group hierarchy path */
+ if(H5G_name_free(&(attr->path)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release group hier. path")
+
+ attr->shared = NULL;
+ attr = H5FL_FREE(H5A_t, attr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_oloc
+ *
+ * Purpose: Return the object location for an attribute. It's the
+ * object location for the object to which the attribute
+ * belongs, not the attribute itself.
+ *
+ * Return: Success: Ptr to entry
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_loc_t *
+H5A_oloc(H5A_t *attr)
+{
+ H5O_loc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(attr);
+
+ /* Set return value */
+ ret_value = &(attr->oloc);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_nameof
+ *
+ * Purpose: Return the group hier. path for an attribute. It's the
+ * group hier. path for the object to which the attribute
+ * belongs, not the attribute itself.
+ *
+ * Return: Success: Ptr to entry
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_name_t *
+H5A_nameof(H5A_t *attr)
+{
+ H5G_name_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(attr);
+
+ /* Set return value */
+ ret_value = &(attr->path);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_nameof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_type
+ *
+ * Purpose: Return the datatype for an attribute.
+ *
+ * Return: Success: Ptr to entry
+ * Failure: NULL
+ *
+ * Programmer: Neil Fortner
+ * Friday, November 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5A_type(const H5A_t *attr)
+{
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(attr);
+
+ /* Set return value */
+ ret_value = attr->shared->dt;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_exists_by_name
+ *
+ * Purpose: Private version of H5Aexists_by_name
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5A_exists_by_name(H5G_loc_t loc, const char *obj_name, const char *attr_name,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Check if the attribute exists */
+ if((ret_value = H5O_attr_exists(obj_loc.oloc, attr_name, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "unable to determine if attribute exists")
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_exists_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__compact_build_table_cb
+ *
+ * Purpose: Object header iterator callback routine to copy attribute
+ * into table.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2006
+ *
+ * Modification:Raymond Lu
+ * 24 June 2008
+ * Changed the table of attribute objects to be the table of
+ * pointers to attribute objects for the ease of operation.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__compact_build_table_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned sequence, unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5A_compact_bt_ud_t *udata = (H5A_compact_bt_ud_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(mesg);
+
+ /* Re-allocate the table if necessary */
+ if(udata->curr_attr == udata->atable->nattrs) {
+ H5A_t **new_table; /* New table for attributes */
+ size_t new_table_size; /* Number of attributes in new table */
+
+ /* Allocate larger table */
+ new_table_size = MAX(1, 2 * udata->atable->nattrs);
+ if(NULL == (new_table = (H5A_t **)H5FL_SEQ_REALLOC(H5A_t_ptr, udata->atable->attrs, new_table_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "unable to extend attribute table")
+
+ /* Update table information in user data */
+ udata->atable->attrs = new_table;
+ udata->atable->nattrs = new_table_size;
+ } /* end if */
+
+ /* Copy attribute into table */
+ if(NULL == (udata->atable->attrs[udata->curr_attr] = H5A_copy(NULL, (const H5A_t *)mesg->native)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute")
+
+ /* Assign [somewhat arbitrary] creation order value, if requested */
+ if(udata->bogus_crt_idx)
+ ((udata->atable->attrs[udata->curr_attr])->shared)->crt_idx = sequence;
+
+ /* Increment current attribute */
+ udata->curr_attr++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__compact_build_table_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_compact_build_table
+ *
+ * Purpose: Builds a table containing a sorted list of attributes for
+ * an object
+ *
+ * Note: Used for building table of attributes in non-native iteration
+ * order for an index
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_compact_build_table(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_index_t idx_type,
+ H5_iter_order_t order, H5A_attr_table_t *atable)
+{
+ H5A_compact_bt_ud_t udata; /* User data for iteration callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(atable);
+
+ /* Initialize table */
+ atable->attrs = NULL;
+ atable->nattrs = 0;
+
+ /* Set up user data for iteration */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.atable = atable;
+ udata.curr_attr = 0;
+ udata.bogus_crt_idx = (hbool_t)((oh->version == H5O_VERSION_1 ||
+ !(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)) ? TRUE : FALSE);
+
+ /* Iterate over existing attributes, checking for attribute with same name */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5A__compact_build_table_cb;
+ if(H5O_msg_iterate_real(f, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error building attribute table")
+
+ /* Correct # of attributes in table */
+ atable->nattrs = udata.curr_attr;
+
+ /* Don't sort an empty table. */
+ if(atable->nattrs > 0) {
+ /* Sort attribute table in correct iteration order */
+ if(H5A__attr_sort_table(atable, idx_type, order) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSORT, FAIL, "error sorting attribute table")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_compact_build_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_build_table_cb
+ *
+ * Purpose: Callback routine for building table of attributes from dense
+ * attribute storage.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_build_table_cb(const H5A_t *attr, void *_udata)
+{
+ H5A_dense_bt_ud_t *udata = (H5A_dense_bt_ud_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(attr);
+ HDassert(udata);
+ HDassert(udata->curr_attr < udata->atable->nattrs);
+
+ /* Allocate attribute for entry in the table */
+ if(NULL == (udata->atable->attrs[udata->curr_attr] = H5FL_CALLOC(H5A_t)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, H5_ITER_ERROR, "can't allocate attribute")
+
+ /* Copy attribute information. Share the attribute object in copying. */
+ if(NULL == H5A_copy(udata->atable->attrs[udata->curr_attr], attr))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute")
+
+ /* Increment number of attributes stored */
+ udata->curr_attr++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_build_table_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_build_table
+ *
+ * Purpose: Builds a table containing a sorted list of attributes for
+ * an object
+ *
+ * Note: Used for building table of attributes in non-native iteration
+ * order for an index. Uses the "name" index to retrieve records,
+ * but the 'idx_type' index for sorting them.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_build_table(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ H5_index_t idx_type, H5_iter_order_t order, H5A_attr_table_t *atable)
+{
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ hsize_t nrec; /* # of records in v2 B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(H5F_addr_defined(ainfo->fheap_addr));
+ HDassert(H5F_addr_defined(ainfo->name_bt2_addr));
+ HDassert(atable);
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Retrieve # of records in "name" B-tree */
+ /* (should be same # of records in all indices) */
+ if(H5B2_get_nrec(bt2_name, &nrec) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve # of records in index")
+
+ /* Set size of table */
+ H5_CHECK_OVERFLOW(nrec, /* From: */ hsize_t, /* To: */ size_t);
+ atable->nattrs = (size_t)nrec;
+
+ /* Allocate space for the table entries */
+ if(atable->nattrs > 0) {
+ H5A_dense_bt_ud_t udata; /* User data for iteration callback */
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+
+ /* Allocate the table to store the attributes */
+ if((atable->attrs = (H5A_t **)H5FL_SEQ_CALLOC(H5A_t_ptr, atable->nattrs)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set up user data for iteration */
+ udata.atable = atable;
+ udata.curr_attr = 0;
+
+ /* Build iterator operator */
+ attr_op.op_type = H5A_ATTR_OP_LIB;
+ attr_op.u.lib_op = H5A__dense_build_table_cb;
+
+ /* Iterate over the links in the group, building a table of the link messages */
+ if(H5A_dense_iterate(f, dxpl_id, (hid_t)0, ainfo, H5_INDEX_NAME,
+ H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table")
+
+ /* Sort attribute table in correct iteration order */
+ if(H5A__attr_sort_table(atable, idx_type, order) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSORT, FAIL, "error sorting attribute table")
+ } /* end if */
+ else
+ atable->attrs = NULL;
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_build_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__attr_cmp_name_inc
+ *
+ * Purpose: Callback routine for comparing two attribute names, in
+ * increasing alphabetic order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * first argument is considered to be respectively less than,
+ * equal to, or greater than the second. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ * (i.e. same as strcmp())
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5A__attr_cmp_name_inc(const void *attr1, const void *attr2)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(HDstrcmp((*(const H5A_t * const *)attr1)->shared->name,
+ (*(const H5A_t * const *)attr2)->shared->name))
+} /* end H5A__attr_cmp_name_inc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__attr_cmp_name_dec
+ *
+ * Purpose: Callback routine for comparing two attribute names, in
+ * decreasing alphabetic order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * second argument is considered to be respectively less than,
+ * equal to, or greater than the first. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ * (i.e. opposite of strcmp())
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 8 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5A__attr_cmp_name_dec(const void *attr1, const void *attr2)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(HDstrcmp((*(const H5A_t * const *)attr2)->shared->name,
+ (*(const H5A_t * const *)attr1)->shared->name))
+} /* end H5A__attr_cmp_name_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__attr_cmp_corder_inc
+ *
+ * Purpose: Callback routine for comparing two attributes, in
+ * increasing creation order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * first argument is considered to be respectively less than,
+ * equal to, or greater than the second. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 8 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5A__attr_cmp_corder_inc(const void *attr1, const void *attr2)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if((*(const H5A_t * const *)attr1)->shared->crt_idx < (*(const H5A_t * const *)attr2)->shared->crt_idx)
+ ret_value = -1;
+ else if((*(const H5A_t * const *)attr1)->shared->crt_idx > (*(const H5A_t * const *)attr2)->shared->crt_idx)
+ ret_value = 1;
+ else
+ ret_value = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__attr_cmp_corder_inc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__attr_cmp_corder_dec
+ *
+ * Purpose: Callback routine for comparing two attributes, in
+ * decreasing creation order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * second argument is considered to be respectively less than,
+ * equal to, or greater than the first. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 8 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5A__attr_cmp_corder_dec(const void *attr1, const void *attr2)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if((*(const H5A_t * const *)attr1)->shared->crt_idx < (*(const H5A_t * const *)attr2)->shared->crt_idx)
+ ret_value = 1;
+ else if((*(const H5A_t * const *)attr1)->shared->crt_idx > (*(const H5A_t * const *)attr2)->shared->crt_idx)
+ ret_value = -1;
+ else
+ ret_value = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__attr_cmp_corder_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__attr_sort_table
+ *
+ * Purpose: Sort table containing a list of attributes for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__attr_sort_table(H5A_attr_table_t *atable, H5_index_t idx_type,
+ H5_iter_order_t order)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(atable);
+
+ /* Pick appropriate comparison routine */
+ if(idx_type == H5_INDEX_NAME) {
+ if(order == H5_ITER_INC)
+ HDqsort(atable->attrs, atable->nattrs, sizeof(H5A_t*), H5A__attr_cmp_name_inc);
+ else if(order == H5_ITER_DEC)
+ HDqsort(atable->attrs, atable->nattrs, sizeof(H5A_t*), H5A__attr_cmp_name_dec);
+ else
+ HDassert(order == H5_ITER_NATIVE);
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+ if(order == H5_ITER_INC)
+ HDqsort(atable->attrs, atable->nattrs, sizeof(H5A_t*), H5A__attr_cmp_corder_inc);
+ else if(order == H5_ITER_DEC)
+ HDqsort(atable->attrs, atable->nattrs, sizeof(H5A_t*), H5A__attr_cmp_corder_dec);
+ else
+ HDassert(order == H5_ITER_NATIVE);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5A__attr_sort_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_attr_iterate_table
+ *
+ * Purpose: Iterate over table containing a list of attributes for an object,
+ * making appropriate callbacks
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_attr_iterate_table(const H5A_attr_table_t *atable, hsize_t skip,
+ hsize_t *last_attr, hid_t loc_id, const H5A_attr_iter_op_t *attr_op,
+ void *op_data)
+{
+ size_t u; /* Local index variable */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(atable);
+ HDassert(attr_op);
+
+ /* Skip over attributes, if requested */
+ if(last_attr)
+ *last_attr = skip;
+
+ /* Iterate over attribute messages */
+ H5_CHECKED_ASSIGN(u, size_t, skip, hsize_t)
+ for(; u < atable->nattrs && !ret_value; u++) {
+ /* Check which type of callback to make */
+ switch(attr_op->op_type) {
+ case H5A_ATTR_OP_APP2:
+ {
+ H5A_info_t ainfo; /* Info for attribute */
+
+ /* Get the attribute information */
+ if(H5A__get_info(atable->attrs[u], &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, H5_ITER_ERROR, "unable to get attribute info")
+
+ /* Make the application callback */
+ ret_value = (attr_op->u.app_op2)(loc_id, ((atable->attrs[u])->shared)->name, &ainfo, op_data);
+ break;
+ }
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ case H5A_ATTR_OP_APP:
+ /* Make the application callback */
+ ret_value = (attr_op->u.app_op)(loc_id, ((atable->attrs[u])->shared)->name, op_data);
+ break;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ case H5A_ATTR_OP_LIB:
+ /* Call the library's callback */
+ ret_value = (attr_op->u.lib_op)((atable->attrs[u]), op_data);
+ break;
+
+ default:
+ HDassert("unknown attribute op type" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "unsupported attribute op type")
+#endif /* NDEBUG */
+ } /* end switch */
+
+ /* Increment the number of entries passed through */
+ if(last_attr)
+ (*last_attr)++;
+ } /* end for */
+
+ /* Check for callback failure and pass along return value */
+ if(ret_value < 0)
+ HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_attr_iterate_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_attr_release_table
+ *
+ * Purpose: Release table containing a list of attributes for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_attr_release_table(H5A_attr_table_t *atable)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(atable);
+
+ /* Release attribute info, if any. */
+ if(atable->nattrs > 0) {
+ size_t u; /* Local index variable */
+
+ /* Free attribute message information */
+ for(u = 0; u < atable->nattrs; u++)
+ if(atable->attrs[u] && H5A_close(atable->attrs[u]) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute")
+ } /* end if */
+ else
+ HDassert(atable->attrs == NULL);
+
+ atable->attrs = (H5A_t **)H5FL_SEQ_FREE(H5A_t_ptr, atable->attrs);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_attr_release_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_get_ainfo
+ *
+ * Purpose: Retrieves the "attribute info" message for an object. Also
+ * sets the number of attributes correctly, if it isn't set up yet.
+ *
+ * Return: Success: TRUE/FALSE whether message was found & retrieved
+ * Failure: FAIL if error occurred
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 11 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5A_get_ainfo(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_ainfo_t *ainfo)
+{
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(ainfo);
+
+ /* Check if the "attribute info" message exists */
+ if((ret_value = H5O_msg_exists_oh(oh, H5O_AINFO_ID)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "unable to check object header")
+ if(ret_value > 0) {
+ /* Retrieve the "attribute info" structure */
+ if(NULL == H5O_msg_read_oh(f, dxpl_id, oh, H5O_AINFO_ID, ainfo))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't read AINFO message")
+
+ /* Check if we don't know how many attributes there are */
+ if(ainfo->nattrs == HSIZET_MAX) {
+ /* Check if we are using "dense" attribute storage */
+ if(H5F_addr_defined(ainfo->fheap_addr)) {
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Retrieve # of records in "name" B-tree */
+ /* (should be same # of records in all indices) */
+ if(H5B2_get_nrec(bt2_name, &ainfo->nattrs) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve # of records in index")
+ } /* end if */
+ else
+ /* Retrieve # of attributes from object header */
+ ainfo->nattrs = oh->attr_msgs_seen;
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5A_get_ainfo() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_set_version
+ *
+ * Purpose: Sets the correct version to encode attribute with.
+ * Chooses the oldest version possible, unless the "use the
+ * latest format" flag is set.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 17 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_set_version(const H5F_t *f, H5A_t *attr)
+{
+ hbool_t type_shared, space_shared; /* Flags to indicate that shared messages are used for this attribute */
+ hbool_t use_latest_format; /* Flag indicating the latest attribute version support is enabled */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(attr);
+
+ /* Get the file's 'use the latest attribute version support' flag */
+ use_latest_format = H5F_USE_LATEST_FLAGS(f, H5F_LATEST_ATTRIBUTE);
+
+ /* Check whether datatype and dataspace are shared */
+ if(H5O_msg_is_shared(H5O_DTYPE_ID, attr->shared->dt) > 0)
+ type_shared = TRUE;
+ else
+ type_shared = FALSE;
+
+ if(H5O_msg_is_shared(H5O_SDSPACE_ID, attr->shared->ds) > 0)
+ space_shared = TRUE;
+ else
+ space_shared = FALSE;
+
+ /* Check which version to encode attribute with */
+ if(use_latest_format)
+ attr->shared->version = H5O_ATTR_VERSION_LATEST; /* Write out latest attribute version */
+ else if(attr->shared->encoding != H5T_CSET_ASCII)
+ attr->shared->version = H5O_ATTR_VERSION_3; /* Write version which includes the character encoding */
+ else if(type_shared || space_shared)
+ attr->shared->version = H5O_ATTR_VERSION_2; /* Write out version with flag for indicating shared datatype or dataspace */
+ else
+ attr->shared->version = H5O_ATTR_VERSION_1; /* Write out basic version */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_set_version() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_attr_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Note that this function assumes that it is copying *all*
+ * the attributes in the object, specifically when it copies
+ * the creation order from source to destination. If this is
+ * to be used to copy only a single attribute, then the
+ * creation order must be handled differently. -NAF
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * November 1, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5A_attr_copy_file(const H5A_t *attr_src, H5F_t *file_dst, hbool_t *recompute_size,
+ H5O_copy_t *cpy_info, hid_t dxpl_id)
+{
+ H5A_t *attr_dst = NULL; /* Destination attribute */
+ hid_t tid_src = -1; /* Datatype ID for source datatype */
+ hid_t tid_dst = -1; /* Datatype ID for destination datatype */
+ hid_t tid_mem = -1; /* Datatype ID for memory datatype */
+ void *buf = NULL; /* Buffer for copying data */
+ void *reclaim_buf = NULL; /* Buffer for reclaiming data */
+ void *bkg_buf = NULL; /* Background buffer */
+ hid_t buf_sid = -1; /* ID for buffer dataspace */
+ hssize_t sdst_nelmts; /* # of elements in destination attribute (signed) */
+ size_t dst_nelmts; /* # of elements in destination attribute */
+ size_t dst_dt_size; /* Size of destination attribute datatype */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(attr_src);
+ HDassert(file_dst);
+ HDassert(cpy_info);
+ HDassert(!cpy_info->copy_without_attr);
+
+ /* Allocate space for the destination message */
+ if(NULL == (attr_dst = H5FL_CALLOC(H5A_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the top level of the attribute */
+ *attr_dst = *attr_src;
+
+ if(NULL == (attr_dst->shared = H5FL_CALLOC(H5A_shared_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate shared attr structure")
+
+ /* Don't have an opened group location for copy */
+ H5O_loc_reset(&(attr_dst->oloc));
+ H5G_name_reset(&(attr_dst->path));
+ attr_dst->obj_opened = FALSE;
+
+ /* Reference count for the header message in the cache */
+ attr_dst->shared->nrefs = 1;
+
+ /* Copy attribute's name */
+ attr_dst->shared->name = H5MM_strdup(attr_src->shared->name);
+ HDassert(attr_dst->shared->name);
+ attr_dst->shared->encoding = attr_src->shared->encoding;
+
+ /* Copy attribute's datatype */
+ /* If source is named, we will keep dst as named, but we will not actually
+ * copy the target and update the message until post copy */
+ if(NULL == (attr_dst->shared->dt = H5T_copy(attr_src->shared->dt, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "cannot copy datatype")
+
+ /* Set the location of the destination datatype */
+ if(H5T_set_loc(attr_dst->shared->dt, file_dst, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "cannot mark datatype on disk")
+
+ if(!H5T_committed(attr_src->shared->dt)) {
+ /* If the datatype is not named, it may have been shared in the
+ * source file's heap. Un-share it for now. We'll try to shared
+ * it in the destination file below.
+ */
+ if(H5O_msg_reset_share(H5O_DTYPE_ID, attr_dst->shared->dt) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to reset datatype sharing")
+ } /* end if */
+
+ /* Copy the dataspace for the attribute. Make sure the maximal dimension is also copied.
+ * Otherwise the comparison in the test may complain about it. SLU 2011/4/12 */
+ attr_dst->shared->ds = H5S_copy(attr_src->shared->ds, FALSE, TRUE);
+ HDassert(attr_dst->shared->ds);
+
+ /* Reset the dataspace's sharing in the source file before trying to share
+ * it in the destination.
+ */
+ if(H5O_msg_reset_share(H5O_SDSPACE_ID, attr_dst->shared->ds) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to reset dataspace sharing")
+
+ /* Simulate trying to share both the datatype and dataset, to determine the
+ * final size of the messages. This does nothing if the datatype is
+ * committed or sharing is disabled.
+ */
+ if(H5SM_try_share(file_dst, dxpl_id, NULL, H5SM_DEFER, H5O_DTYPE_ID, attr_dst->shared->dt, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, NULL, "can't share attribute datatype")
+ if(H5SM_try_share(file_dst, dxpl_id, NULL, H5SM_DEFER, H5O_SDSPACE_ID, attr_dst->shared->ds, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, NULL, "can't share attribute dataspace")
+
+ /* Compute the sizes of the datatype and dataspace. This is their raw
+ * size unless they're shared.
+ */
+ attr_dst->shared->dt_size = H5O_msg_raw_size(file_dst, H5O_DTYPE_ID, FALSE, attr_dst->shared->dt);
+ HDassert(attr_dst->shared->dt_size > 0);
+ attr_dst->shared->ds_size = H5O_msg_raw_size(file_dst, H5O_SDSPACE_ID, FALSE, attr_dst->shared->ds);
+ HDassert(attr_dst->shared->ds_size > 0);
+
+ /* Check whether to recompute the size of the attribute */
+ /* (happens when the datatype or dataspace changes sharing status) */
+ if(attr_dst->shared->dt_size != attr_src->shared->dt_size || attr_dst->shared->ds_size != attr_src->shared->ds_size)
+ *recompute_size = TRUE;
+
+ /* Get # of elements for destination attribute's dataspace */
+ if((sdst_nelmts = H5S_GET_EXTENT_NPOINTS(attr_dst->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOUNT, NULL, "dataspace is invalid")
+ H5_CHECKED_ASSIGN(dst_nelmts, size_t, sdst_nelmts, hssize_t);
+
+ /* Get size of destination attribute's datatype */
+ if(0 == (dst_dt_size = H5T_get_size(attr_dst->shared->dt)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to determine datatype size")
+
+ /* Compute the size of the data */
+ attr_dst->shared->data_size = dst_nelmts * dst_dt_size;
+
+ /* Copy (& convert) the data, if necessary */
+ if(attr_src->shared->data) {
+ if(NULL == (attr_dst->shared->data = H5FL_BLK_MALLOC(attr_buf, attr_dst->shared->data_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Check if we need to convert data */
+ if(H5T_detect_class(attr_src->shared->dt, H5T_VLEN, FALSE) > 0) {
+ H5T_path_t *tpath_src_mem, *tpath_mem_dst; /* Datatype conversion paths */
+ H5T_t *dt_mem; /* Memory datatype */
+ size_t src_dt_size; /* Source datatype size */
+ size_t tmp_dt_size; /* Temp. datatype size */
+ size_t max_dt_size; /* Max atatype size */
+ H5S_t *buf_space; /* Dataspace describing buffer */
+ hsize_t buf_dim; /* Dimension for buffer */
+ size_t nelmts; /* Number of elements in buffer */
+ size_t buf_size; /* Size of copy buffer */
+
+ /* Create datatype ID for src datatype */
+ if((tid_src = H5I_register(H5I_DATATYPE, attr_src->shared->dt, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register source file datatype")
+
+ /* create a memory copy of the variable-length datatype */
+ if(NULL == (dt_mem = H5T_copy(attr_src->shared->dt, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy")
+ if((tid_mem = H5I_register(H5I_DATATYPE, dt_mem, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register memory datatype")
+
+ /* create variable-length datatype at the destinaton file */
+ if((tid_dst = H5I_register(H5I_DATATYPE, attr_dst->shared->dt, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register destination file datatype")
+
+ /* Set up the conversion functions */
+ if(NULL == (tpath_src_mem = H5T_path_find(attr_src->shared->dt, dt_mem, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to convert between src and mem datatypes")
+ if(NULL == (tpath_mem_dst = H5T_path_find(dt_mem, attr_dst->shared->dt, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to convert between mem and dst datatypes")
+
+ /* Determine largest datatype size */
+ if(0 == (src_dt_size = H5T_get_size(attr_src->shared->dt)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to determine datatype size")
+ if(0 == (tmp_dt_size = H5T_get_size(dt_mem)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to determine datatype size")
+ max_dt_size = MAX(src_dt_size, tmp_dt_size);
+ if(0 == (tmp_dt_size = H5T_get_size(attr_dst->shared->dt)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to determine datatype size")
+ max_dt_size = MAX(max_dt_size, tmp_dt_size);
+
+ /* Set number of whole elements that fit in buffer */
+ if(0 == (nelmts = attr_src->shared->data_size / src_dt_size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "element size too large")
+
+ /* Set up number of bytes to copy, and initial buffer size */
+ buf_size = nelmts * max_dt_size;
+
+ /* Create dataspace for number of elements in buffer */
+ buf_dim = nelmts;
+
+ /* Create the space and set the initial extent */
+ if(NULL == (buf_space = H5S_create_simple((unsigned)1, &buf_dim, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "can't create simple dataspace")
+
+ /* Atomize */
+ if((buf_sid = H5I_register(H5I_DATASPACE, buf_space, FALSE)) < 0) {
+ H5S_close(buf_space);
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, NULL, "unable to register dataspace ID")
+ } /* end if */
+
+ /* Allocate memory for recclaim buf */
+ if(NULL == (reclaim_buf = H5FL_BLK_MALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation NULLed for raw data chunk")
+
+ /* Allocate memory for copying the chunk */
+ if(NULL == (buf = H5FL_BLK_MALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation NULLed for raw data chunk")
+
+ HDmemcpy(buf, attr_src->shared->data, attr_src->shared->data_size);
+
+ /* Allocate background memory */
+ if(H5T_path_bkg(tpath_src_mem) || H5T_path_bkg(tpath_mem_dst))
+ if(NULL == (bkg_buf = H5FL_BLK_CALLOC(attr_buf, buf_size)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Convert from source file to memory */
+ if(H5T_convert(tpath_src_mem, tid_src, tid_mem, nelmts, (size_t)0, (size_t)0, buf, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "datatype conversion NULLed")
+
+ HDmemcpy(reclaim_buf, buf, buf_size);
+
+ /* Set background buffer to all zeros */
+ if(bkg_buf)
+ HDmemset(bkg_buf, 0, buf_size);
+
+ /* Convert from memory to destination file */
+ if(H5T_convert(tpath_mem_dst, tid_mem, tid_dst, nelmts, (size_t)0, (size_t)0, buf, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "datatype conversion NULLed")
+
+ HDmemcpy(attr_dst->shared->data, buf, attr_dst->shared->data_size);
+
+ if(H5D_vlen_reclaim(tid_mem, buf_space, dxpl_id, reclaim_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, NULL, "unable to reclaim variable-length data")
+ } /* end if */
+ else {
+ HDassert(attr_dst->shared->data_size == attr_src->shared->data_size);
+ HDmemcpy(attr_dst->shared->data, attr_src->shared->data, attr_src->shared->data_size);
+ } /* end else */
+ } /* end if(attr_src->shared->data) */
+
+ /* Copy the creation order */
+ attr_dst->shared->crt_idx = attr_src->shared->crt_idx;
+
+ /* Recompute the version to encode the destination attribute */
+ if(H5A_set_version(file_dst, attr_dst) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, NULL, "unable to update attribute version")
+
+ /* Recompute the destination attribute's size, if it's a different version */
+ if(attr_src->shared->version != attr_dst->shared->version)
+ *recompute_size = TRUE;
+
+ /* Set return value */
+ ret_value = attr_dst;
+
+done:
+ if(buf_sid > 0 && H5I_dec_ref(buf_sid) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "Can't decrement temporary dataspace ID")
+ if(tid_src > 0)
+ /* Don't decrement ID, we want to keep underlying datatype */
+ if(NULL == H5I_remove(tid_src))
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "Can't decrement temporary datatype ID")
+ if(tid_dst > 0)
+ /* Don't decrement ID, we want to keep underlying datatype */
+ if(NULL == H5I_remove(tid_dst))
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "Can't decrement temporary datatype ID")
+ if(tid_mem > 0)
+ /* Decrement the memory datatype ID, it's transient */
+ if(H5I_dec_ref(tid_mem) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "Can't decrement temporary datatype ID")
+ if(buf)
+ buf = H5FL_BLK_FREE(attr_buf, buf);
+ if(reclaim_buf)
+ reclaim_buf = H5FL_BLK_FREE(attr_buf, reclaim_buf);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(attr_buf, bkg_buf);
+
+ /* Release destination attribute information on failure */
+ if(!ret_value && attr_dst && H5A_close(attr_dst) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_attr_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_attr_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files.
+ * We have to copy the values of a reference attribute in the
+ * post copy because H5O_post_copy_file() fails at the case that
+ * an object may have a reference attribute that points to the
+ * object itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * March 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_attr_post_copy_file(const H5O_loc_t *src_oloc, const H5A_t *attr_src,
+ H5O_loc_t *dst_oloc, const H5A_t *attr_dst, hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ H5F_t *file_src, *file_dst;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(src_oloc);
+ HDassert(dst_oloc);
+ HDassert(attr_dst);
+ HDassert(attr_src);
+
+ file_src = src_oloc->file;
+ file_dst = dst_oloc->file;
+
+ HDassert(file_src);
+ HDassert(file_dst);
+
+ if(H5T_committed(attr_src->shared->dt)) {
+ H5O_loc_t *src_oloc_dt; /* Pointer to source datatype's object location */
+ H5O_loc_t *dst_oloc_dt; /* Pointer to dest. datatype's object location */
+
+ /* Get group entries for source & destination */
+ src_oloc_dt = H5T_oloc(attr_src->shared->dt);
+ HDassert(src_oloc_dt);
+ dst_oloc_dt = H5T_oloc(attr_dst->shared->dt);
+ HDassert(dst_oloc_dt);
+
+ /* Reset object location for new object */
+ H5O_loc_reset(dst_oloc_dt);
+ dst_oloc_dt->file = file_dst;
+
+ /* Copy the shared object from source to destination */
+ if(H5O_copy_header_map(src_oloc_dt, dst_oloc_dt, dxpl_id, cpy_info, FALSE, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Update shared message info from named datatype info */
+ H5T_update_shared(attr_dst->shared->dt);
+ } /* end if */
+
+ /* Try to share both the datatype and dataset. This does nothing if the
+ * datatype is committed or sharing is disabled.
+ */
+ if(H5SM_try_share(file_dst, dxpl_id, NULL, H5SM_WAS_DEFERRED, H5O_DTYPE_ID, attr_dst->shared->dt, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "can't share attribute datatype")
+ if(H5SM_try_share(file_dst, dxpl_id, NULL, H5SM_WAS_DEFERRED, H5O_SDSPACE_ID, attr_dst->shared->ds, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "can't share attribute dataspace")
+
+ /* Only need to fix reference attribute with real data being copied to
+ * another file.
+ */
+ if((NULL != attr_dst->shared->data) && (H5T_get_class(attr_dst->shared->dt, FALSE) == H5T_REFERENCE) ) {
+
+ /* copy object pointed by reference. The current implementation does not
+ * deal with nested reference such as reference in a compound structure
+ */
+
+ /* Check for expanding references */
+ if(cpy_info->expand_ref) {
+ size_t ref_count;
+
+ /* Determine # of reference elements to copy */
+ ref_count = attr_dst->shared->data_size / H5T_get_size(attr_dst->shared->dt);
+
+ /* Copy objects referenced in source buffer to destination file and set destination elements */
+ if(H5O_copy_expand_ref(file_src, attr_dst->shared->data, dxpl_id,
+ file_dst, attr_dst->shared->data, ref_count, H5T_get_ref_type(attr_dst->shared->dt), cpy_info) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "unable to copy reference attribute")
+ } /* end if */
+ else
+ /* Reset value to zero */
+ HDmemset(attr_dst->shared->data, 0, attr_dst->shared->data_size);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_attr_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A__dense_post_copy_file_cb
+ *
+ * Purpose: Callback routine for copying a dense attribute from SRC to DST.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Peter Cao
+ * xcao@hdfgroup.org
+ * July 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5A__dense_post_copy_file_cb(const H5A_t *attr_src, void *_udata)
+{
+ H5A_dense_file_cp_ud_t *udata = (H5A_dense_file_cp_ud_t *)_udata;
+ H5A_t *attr_dst = NULL;
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(attr_src);
+ HDassert(udata);
+ HDassert(udata->ainfo);
+ HDassert(udata->file);
+ HDassert(udata->cpy_info);
+
+ if(NULL == (attr_dst = H5A_attr_copy_file(attr_src, udata->file,
+ udata->recompute_size, udata->cpy_info, udata->dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute")
+
+ if(H5A_attr_post_copy_file(udata->oloc_src, attr_src, udata->oloc_dst, attr_dst,
+ udata->dxpl_id, udata->cpy_info) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute")
+
+ /* Reset shared location information */
+ if(H5O_msg_reset_share(H5O_ATTR_ID, attr_dst) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to reset attribute sharing")
+
+ /* Set COPIED tag for destination object's metadata */
+ H5_BEGIN_TAG(udata->dxpl_id, H5AC__COPIED_TAG, H5_ITER_ERROR);
+
+ /* Insert attribute into dense storage */
+ if(H5A_dense_insert(udata->file, udata->dxpl_id, udata->ainfo, attr_dst) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage")
+
+ /* Reset metadata tag */
+ H5_END_TAG(H5_ITER_ERROR);
+
+done:
+ if(attr_dst && H5A_close(attr_dst) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close destination attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A__dense_post_copy_file_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_dense_post_copy_file_all
+ *
+ * Purpose: Copy all dense attributes from SRC to DST.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Peter Cao
+ * xcao@hdfgroup.org
+ * July 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_dense_post_copy_file_all(const H5O_loc_t *src_oloc, const H5O_ainfo_t *ainfo_src,
+ H5O_loc_t *dst_oloc, H5O_ainfo_t *ainfo_dst, hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ H5A_dense_file_cp_ud_t udata; /* User data for iteration callback */
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+ hbool_t recompute_size = FALSE; /* recompute the size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(ainfo_src);
+ HDassert(ainfo_dst);
+
+ udata.ainfo = ainfo_dst; /* Destination dense information */
+ udata.file = dst_oloc->file; /* Destination file */
+ udata.recompute_size = &recompute_size; /* Flag to indicate if size changed */
+ udata.cpy_info = cpy_info; /* Information on copying options */
+ udata.dxpl_id = dxpl_id; /* DXPL for operation */
+ udata.oloc_src = src_oloc;
+ udata.oloc_dst = dst_oloc;
+
+ attr_op.op_type = H5A_ATTR_OP_LIB;
+ attr_op.u.lib_op = H5A__dense_post_copy_file_cb;
+
+ if(H5A_dense_iterate(src_oloc->file, dxpl_id, (hid_t)0, ainfo_src, H5_INDEX_NAME,
+ H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op, &udata) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_dense_post_copy_file_all */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_rename_by_name
+ *
+ * Purpose: Private version of H5Arename_by_name
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_rename_by_name(H5G_loc_t loc, const char *obj_name, const char *old_attr_name,
+ const char *new_attr_name, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Avoid thrashing things if the names are the same */
+ if(HDstrcmp(old_attr_name, new_attr_name)) {
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Call attribute rename routine */
+ if(H5O_attr_rename(obj_loc.oloc, dxpl_id, old_attr_name, new_attr_name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTRENAME, FAIL, "can't rename attribute")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5A_rename_by_name() */
diff --git a/src/H5Amodule.h b/src/H5Amodule.h
new file mode 100644
index 0000000..8ed056b
--- /dev/null
+++ b/src/H5Amodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5A package. Including this header means that the source file
+ * is part of the H5A package.
+ */
+#ifndef _H5Amodule_H
+#define _H5Amodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5A_MODULE
+#define H5_MY_PKG H5A
+#define H5_MY_PKG_ERR H5E_ATTR
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Amodule_H */
+
diff --git a/src/H5Apkg.h b/src/H5Apkg.h
new file mode 100644
index 0000000..6d5a83a
--- /dev/null
+++ b/src/H5Apkg.h
@@ -0,0 +1,275 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol
+ * Monday, Apr 20
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5A package. Source files outside the H5A package should
+ * include H5Aprivate.h instead.
+ */
+#if !(defined H5A_FRIEND || defined H5A_MODULE)
+#error "Do not include this file outside the H5A package!"
+#endif
+
+#ifndef _H5Apkg_H
+#define _H5Apkg_H
+
+/*
+ * Define this to enable debugging.
+ */
+#ifdef NDEBUG
+# undef H5A_DEBUG
+#endif
+
+/* Get package's private header */
+#include "H5Aprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5B2private.h" /* v2 B-trees */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5HFprivate.h" /* Fractal heaps */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspace */
+#include "H5Tprivate.h" /* Datatype functions */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* This is the initial version, which does not have support for shared datatypes */
+#define H5O_ATTR_VERSION_1 1
+
+/* This version allows support for shared datatypes & dataspaces by adding a
+ * 'flag' byte indicating when those components are shared. This version
+ * also dropped the alignment on all the components.
+ */
+#define H5O_ATTR_VERSION_2 2
+
+/* Add support for different character encodings of attribute names */
+#define H5O_ATTR_VERSION_3 3
+
+/* The latest version of the format. Look through the 'encode', 'decode'
+ * and 'size' message callbacks for places to change when updating this.
+ */
+#define H5O_ATTR_VERSION_LATEST H5O_ATTR_VERSION_3
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+/* Define the shared attribute structure */
+typedef struct H5A_shared_t {
+ uint8_t version; /* Version to encode attribute with */
+
+ char *name; /* Attribute's name */
+ H5T_cset_t encoding; /* Character encoding of attribute name */
+
+ H5T_t *dt; /* Attribute's datatype */
+ size_t dt_size; /* Size of datatype on disk */
+
+ H5S_t *ds; /* Attribute's dataspace */
+ size_t ds_size; /* Size of dataspace on disk */
+
+ void *data; /* Attribute data (on a temporary basis) */
+ size_t data_size; /* Size of data on disk */
+ H5O_msg_crt_idx_t crt_idx; /* Attribute's creation index in the object header */
+ unsigned nrefs; /* Ref count for times this object is refered */
+} H5A_shared_t;
+
+/* Define the main attribute structure */
+struct H5A_t {
+ H5O_shared_t sh_loc; /* Shared message info (must be first) */
+ H5O_loc_t oloc; /* Object location for object attribute is on */
+ hbool_t obj_opened; /* Object header entry opened? */
+ H5G_name_t path; /* Group hierarchy path */
+ H5A_shared_t *shared; /* Shared attribute information */
+};
+
+/* Typedefs for "dense" attribute storage */
+/* (fractal heap & v2 B-tree info) */
+
+/* Typedef for native 'name' field index records in the v2 B-tree */
+/* (Keep 'id' field first so generic record handling in callbacks works) */
+typedef struct H5A_dense_bt2_name_rec_t {
+ H5O_fheap_id_t id; /* Heap ID for attribute */
+ uint8_t flags; /* Object header message flags for attribute */
+ H5O_msg_crt_idx_t corder; /* 'creation order' field value */
+ uint32_t hash; /* Hash of 'name' field value */
+} H5A_dense_bt2_name_rec_t;
+
+/* Typedef for native 'creation order' field index records in the v2 B-tree */
+/* (Keep 'id' field first so generic record handling in callbacks works) */
+typedef struct H5A_dense_bt2_corder_rec_t {
+ H5O_fheap_id_t id; /* Heap ID for attribute */
+ uint8_t flags; /* Object header message flags for attribute */
+ H5O_msg_crt_idx_t corder; /* 'creation order' field value */
+} H5A_dense_bt2_corder_rec_t;
+
+/* Define the 'found' callback function pointer for matching an attribute record in a v2 B-tree */
+typedef herr_t (*H5A_bt2_found_t)(const H5A_t *attr, hbool_t *took_ownership, void *op_data);
+
+/*
+ * Common data exchange structure for dense attribute storage. This structure
+ * is passed through the v2 B-tree layer to the methods for the objects
+ * to which the v2 B-tree points.
+ */
+typedef struct H5A_bt2_ud_common_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */
+ const char *name; /* Name of attribute to compare */
+ uint32_t name_hash; /* Hash of name of attribute to compare */
+ uint8_t flags; /* Flags for attribute storage location */
+ H5O_msg_crt_idx_t corder; /* Creation order value of attribute to compare */
+ H5A_bt2_found_t found_op; /* Callback when correct attribute is found */
+ void *found_op_data; /* Callback data when correct attribute is found */
+} H5A_bt2_ud_common_t;
+
+/*
+ * Data exchange structure for dense attribute storage. This structure is
+ * passed through the v2 B-tree layer when inserting attributes.
+ */
+typedef struct H5A_bt2_ud_ins_t {
+ /* downward */
+ H5A_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */
+ H5O_fheap_id_t id; /* Heap ID of attribute to insert */
+} H5A_bt2_ud_ins_t;
+
+/* Data structure to hold table of attributes for an object */
+typedef struct {
+ size_t nattrs; /* # of attributes in table */
+ H5A_t **attrs; /* Pointer to array of attribute pointers */
+} H5A_attr_table_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare extern the free list for H5A_t's */
+H5FL_EXTERN(H5A_t);
+
+/* Declare the external free lists for H5A_shared_t's */
+H5FL_EXTERN(H5A_shared_t);
+
+/* Declare extern a free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(attr_buf);
+
+/* The v2 B-tree class for indexing 'name' field on attributes */
+H5_DLLVAR const H5B2_class_t H5A_BT2_NAME[1];
+
+/* The v2 B-tree class for indexing 'creation order' field on attributes */
+H5_DLLVAR const H5B2_class_t H5A_BT2_CORDER[1];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Function prototypes for H5A package scope */
+H5_DLL H5A_t *H5A_create(const H5G_loc_t *loc, const char *name,
+ const H5T_t *type, const H5S_t *space, hid_t acpl_id, hid_t dxpl_id);
+H5_DLL H5A_t *H5A_open_by_name(const H5G_loc_t *loc, const char *obj_name,
+ const char *attr_name, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL H5A_t *H5A_open_by_idx(const H5G_loc_t *loc, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5A__open_common(const H5G_loc_t *loc, H5A_t *attr);
+H5_DLL H5A_t *H5A_copy(H5A_t *new_attr, const H5A_t *old_attr);
+H5_DLL herr_t H5A__get_info(const H5A_t *attr, H5A_info_t *ainfo);
+H5_DLL hid_t H5A_get_create_plist(H5A_t* attr);
+H5_DLL herr_t H5A_free(H5A_t *attr);
+H5_DLL herr_t H5A_close(H5A_t *attr);
+H5_DLL htri_t H5A_get_ainfo(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_ainfo_t *ainfo);
+H5_DLL herr_t H5A_set_version(const H5F_t *f, H5A_t *attr);
+H5_DLL herr_t H5A_rename_by_name(H5G_loc_t loc, const char *obj_name, const char *old_attr_name,
+ const char *new_attr_name, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL htri_t H5A_exists_by_name(H5G_loc_t loc, const char *obj_name, const char *attr_name,
+ hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5A__write(H5A_t *attr, const H5T_t *mem_type, const void *buf, hid_t dxpl_id);
+H5_DLL herr_t H5A__read(const H5A_t *attr, const H5T_t *mem_type, void *buf, hid_t dxpl_id);
+H5_DLL ssize_t H5A__get_name(H5A_t *attr, size_t buf_size, char *buf);
+
+/* Attribute "dense" storage routines */
+H5_DLL herr_t H5A_dense_create(H5F_t *f, hid_t dxpl_id, H5O_ainfo_t *ainfo);
+H5_DLL H5A_t *H5A_dense_open(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ const char *name);
+H5_DLL herr_t H5A_dense_insert(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ H5A_t *attr);
+H5_DLL herr_t H5A_dense_write(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ H5A_t *attr);
+H5_DLL herr_t H5A_dense_rename(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ const char *old_name, const char *new_name);
+H5_DLL herr_t H5A_dense_iterate(H5F_t *f, hid_t dxpl_id, hid_t loc_id,
+ const H5O_ainfo_t *ainfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t skip, hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op,
+ void *op_data);
+H5_DLL herr_t H5A_dense_remove(H5F_t *f, hid_t dxpl_id,
+ const H5O_ainfo_t *ainfo, const char *name);
+H5_DLL herr_t H5A_dense_remove_by_idx(H5F_t *f, hid_t dxpl_id,
+ const H5O_ainfo_t *ainfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t n);
+H5_DLL htri_t H5A_dense_exists(H5F_t *f, hid_t dxpl_id, const H5O_ainfo_t *ainfo,
+ const char *name);
+H5_DLL herr_t H5A_dense_delete(H5F_t *f, hid_t dxpl_id, H5O_ainfo_t *ainfo);
+
+/* Attribute table operations */
+H5_DLL herr_t H5A_compact_build_table(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ H5_index_t idx_type, H5_iter_order_t order, H5A_attr_table_t *atable);
+H5_DLL herr_t H5A_dense_build_table(H5F_t *f, hid_t dxpl_id,
+ const H5O_ainfo_t *ainfo, H5_index_t idx_type, H5_iter_order_t order,
+ H5A_attr_table_t *atable);
+H5_DLL herr_t H5A_attr_iterate_table(const H5A_attr_table_t *atable,
+ hsize_t skip, hsize_t *last_attr, hid_t loc_id,
+ const H5A_attr_iter_op_t *attr_op, void *op_data);
+H5_DLL herr_t H5A_attr_release_table(H5A_attr_table_t *atable);
+
+/* Attribute operations */
+H5_DLL herr_t H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr);
+H5_DLL H5A_t *H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name,
+ hid_t dxpl_id);
+H5_DLL H5A_t *H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t dxpl_id);
+H5_DLL herr_t H5O_attr_update_shared(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ H5A_t *attr, H5O_shared_t *sh_mesg);
+H5_DLL herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id,
+ H5A_t *attr);
+H5_DLL herr_t H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id,
+ const char *old_name, const char *new_name);
+H5_DLL herr_t H5O_attr_remove(const H5O_loc_t *loc, const char *name,
+ hid_t dxpl_id);
+H5_DLL herr_t H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t dxpl_id);
+H5_DLL htri_t H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL int H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+H5_DLL H5A_t *H5A_attr_copy_file(const H5A_t *attr_src, H5F_t *file_dst, hbool_t *recompute_size,
+ H5O_copy_t *cpy_info, hid_t dxpl_id);
+H5_DLL herr_t H5A_attr_post_copy_file(const H5O_loc_t *src_oloc, const H5A_t *mesg_src,
+ H5O_loc_t *dst_oloc, const H5A_t *mesg_dst, hid_t dxpl_id, H5O_copy_t *cpy_info);
+H5_DLL herr_t H5A_dense_post_copy_file_all(const H5O_loc_t *src_oloc, const H5O_ainfo_t * ainfo_src,
+ H5O_loc_t *dst_oloc, H5O_ainfo_t *ainfo_dst, hid_t dxpl_id, H5O_copy_t *cpy_info);
+
+/* Testing functions */
+#ifdef H5A_TESTING
+H5_DLL htri_t H5A_is_shared_test(hid_t aid);
+H5_DLL herr_t H5A_get_shared_rc_test(hid_t attr_id, hsize_t *ref_count);
+#endif /* H5A_TESTING */
+
+#endif /* _H5Apkg_H */
+
diff --git a/src/H5Aprivate.h b/src/H5Aprivate.h
new file mode 100644
index 0000000..b285920
--- /dev/null
+++ b/src/H5Aprivate.h
@@ -0,0 +1,89 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5D module
+ */
+#ifndef _H5Aprivate_H
+#define _H5Aprivate_H
+
+/* Include package's public header */
+#include "H5Apublic.h"
+
+/* Private headers needed by this file */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspace */
+#include "H5Tprivate.h" /* Datatypes */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Forward references of package typedefs */
+typedef struct H5A_t H5A_t;
+
+/* Attribute iteration operator for internal library callbacks */
+typedef herr_t (*H5A_lib_iterate_t)(const H5A_t *attr, void *op_data);
+
+/* Describe kind of callback to make for each attribute */
+typedef enum H5A_attr_iter_op_type_t {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ H5A_ATTR_OP_APP, /* Application callback */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ H5A_ATTR_OP_APP2, /* Revised application callback */
+ H5A_ATTR_OP_LIB /* Library internal callback */
+} H5A_attr_iter_op_type_t;
+
+typedef struct H5A_attr_iter_op_t {
+ H5A_attr_iter_op_type_t op_type;
+ union {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ H5A_operator1_t app_op; /* Application callback for each attribute */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ H5A_operator2_t app_op2; /* Revised application callback for each attribute */
+ H5A_lib_iterate_t lib_op; /* Library internal callback for each attribute */
+ } u;
+} H5A_attr_iter_op_t;
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General attribute routines */
+H5_DLL struct H5O_loc_t *H5A_oloc(H5A_t *attr);
+H5_DLL H5G_name_t *H5A_nameof(H5A_t *attr);
+H5_DLL H5T_t *H5A_type(const H5A_t *attr);
+H5_DLL H5T_t *H5A_get_type(H5A_t *attr);
+H5_DLL H5S_t *H5A_get_space(H5A_t *attr);
+H5_DLL herr_t H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc,
+ hid_t dxpl_id, H5_index_t idx_type, H5_iter_order_t order, hsize_t skip,
+ hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data);
+H5_DLL herr_t H5O_attr_iterate(hid_t loc_id, hid_t dxpl_id, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t skip, hsize_t *last_attr,
+ const H5A_attr_iter_op_t *op, void *op_data);
+
+#endif /* _H5Aprivate_H */
+
diff --git a/src/H5Apublic.h b/src/H5Apublic.h
new file mode 100644
index 0000000..586940b
--- /dev/null
+++ b/src/H5Apublic.h
@@ -0,0 +1,118 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5A module.
+ */
+#ifndef _H5Apublic_H
+#define _H5Apublic_H
+
+/* Public headers needed by this file */
+#include "H5Ipublic.h" /* IDs */
+#include "H5Opublic.h" /* Object Headers */
+#include "H5Tpublic.h" /* Datatypes */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Information struct for attribute (for H5Aget_info/H5Aget_info_by_idx) */
+typedef struct {
+ hbool_t corder_valid; /* Indicate if creation order is valid */
+ H5O_msg_crt_idx_t corder; /* Creation order */
+ H5T_cset_t cset; /* Character set of attribute name */
+ hsize_t data_size; /* Size of raw data */
+} H5A_info_t;
+
+/* Typedef for H5Aiterate2() callbacks */
+typedef herr_t (*H5A_operator2_t)(hid_t location_id/*in*/,
+ const char *attr_name/*in*/, const H5A_info_t *ainfo/*in*/, void *op_data/*in,out*/);
+
+/* Public function prototypes */
+H5_DLL hid_t H5Acreate2(hid_t loc_id, const char *attr_name, hid_t type_id,
+ hid_t space_id, hid_t acpl_id, hid_t aapl_id);
+H5_DLL hid_t H5Acreate_by_name(hid_t loc_id, const char *obj_name, const char *attr_name,
+ hid_t type_id, hid_t space_id, hid_t acpl_id, hid_t aapl_id, hid_t lapl_id);
+H5_DLL hid_t H5Aopen(hid_t obj_id, const char *attr_name, hid_t aapl_id);
+H5_DLL hid_t H5Aopen_by_name(hid_t loc_id, const char *obj_name,
+ const char *attr_name, hid_t aapl_id, hid_t lapl_id);
+H5_DLL hid_t H5Aopen_by_idx(hid_t loc_id, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t aapl_id,
+ hid_t lapl_id);
+H5_DLL herr_t H5Awrite(hid_t attr_id, hid_t type_id, const void *buf);
+H5_DLL herr_t H5Aread(hid_t attr_id, hid_t type_id, void *buf);
+H5_DLL herr_t H5Aclose(hid_t attr_id);
+H5_DLL hid_t H5Aget_space(hid_t attr_id);
+H5_DLL hid_t H5Aget_type(hid_t attr_id);
+H5_DLL hid_t H5Aget_create_plist(hid_t attr_id);
+H5_DLL ssize_t H5Aget_name(hid_t attr_id, size_t buf_size, char *buf);
+H5_DLL ssize_t H5Aget_name_by_idx(hid_t loc_id, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ char *name /*out*/, size_t size, hid_t lapl_id);
+H5_DLL hsize_t H5Aget_storage_size(hid_t attr_id);
+H5_DLL herr_t H5Aget_info(hid_t attr_id, H5A_info_t *ainfo /*out*/);
+H5_DLL herr_t H5Aget_info_by_name(hid_t loc_id, const char *obj_name,
+ const char *attr_name, H5A_info_t *ainfo /*out*/, hid_t lapl_id);
+H5_DLL herr_t H5Aget_info_by_idx(hid_t loc_id, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ H5A_info_t *ainfo /*out*/, hid_t lapl_id);
+H5_DLL herr_t H5Arename(hid_t loc_id, const char *old_name, const char *new_name);
+H5_DLL herr_t H5Arename_by_name(hid_t loc_id, const char *obj_name,
+ const char *old_attr_name, const char *new_attr_name, hid_t lapl_id);
+H5_DLL herr_t H5Aiterate2(hid_t loc_id, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t *idx, H5A_operator2_t op, void *op_data);
+H5_DLL herr_t H5Aiterate_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t *idx, H5A_operator2_t op, void *op_data,
+ hid_t lapd_id);
+H5_DLL herr_t H5Adelete(hid_t loc_id, const char *name);
+H5_DLL herr_t H5Adelete_by_name(hid_t loc_id, const char *obj_name,
+ const char *attr_name, hid_t lapl_id);
+H5_DLL herr_t H5Adelete_by_idx(hid_t loc_id, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id);
+H5_DLL htri_t H5Aexists(hid_t obj_id, const char *attr_name);
+H5_DLL htri_t H5Aexists_by_name(hid_t obj_id, const char *obj_name,
+ const char *attr_name, hid_t lapl_id);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+
+/* Typedefs */
+
+/* Typedef for H5Aiterate1() callbacks */
+typedef herr_t (*H5A_operator1_t)(hid_t location_id/*in*/,
+ const char *attr_name/*in*/, void *operator_data/*in,out*/);
+
+
+/* Function prototypes */
+H5_DLL hid_t H5Acreate1(hid_t loc_id, const char *name, hid_t type_id,
+ hid_t space_id, hid_t acpl_id);
+H5_DLL hid_t H5Aopen_name(hid_t loc_id, const char *name);
+H5_DLL hid_t H5Aopen_idx(hid_t loc_id, unsigned idx);
+H5_DLL int H5Aget_num_attrs(hid_t loc_id);
+H5_DLL herr_t H5Aiterate1(hid_t loc_id, unsigned *attr_num, H5A_operator1_t op,
+ void *op_data);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5Apublic_H */
+
diff --git a/src/H5Atest.c b/src/H5Atest.c
new file mode 100644
index 0000000..b923637
--- /dev/null
+++ b/src/H5Atest.c
@@ -0,0 +1,148 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Atest.c
+ * Dec 18 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Attribute testing routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Amodule.h" /* This source code file is part of the H5A module */
+#define H5A_TESTING /*suppress warning about H5A testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5SMprivate.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_is_shared_test
+ *
+ * Purpose: Check if an attribute is shared
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5A_is_shared_test(hid_t attr_id)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ /* Check if attribute is shared */
+ ret_value = H5O_msg_is_shared(H5O_ATTR_ID, attr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_is_shared_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5A_get_shared_rc_test
+ *
+ * Purpose: Retrieve the refcount for a shared attribute
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5A_get_shared_rc_test(hid_t attr_id, hsize_t *ref_count)
+{
+ H5A_t *attr; /* Attribute object for ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (attr = (H5A_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute")
+
+ /* Sanity check */
+ HDassert(H5O_msg_is_shared(H5O_ATTR_ID, attr));
+
+ /* Retrieve ref count for shared or shareable attribute */
+ if(H5SM_get_refcount(attr->oloc.file, H5AC_ind_read_dxpl_id, H5O_ATTR_ID,
+ &attr->sh_loc, ref_count) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5A_get_shared_rc_test() */
+
diff --git a/src/H5B.c b/src/H5B.c
new file mode 100644
index 0000000..e64a695
--- /dev/null
+++ b/src/H5B.c
@@ -0,0 +1,2107 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B.c
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Implements balanced, sibling-linked, N-ary trees
+ * capable of storing any type of data with unique key
+ * values.
+ *
+ * A B-link-tree is a balanced tree where each node has
+ * a pointer to its left and right siblings. A
+ * B-link-tree is a rooted tree having the following
+ * properties:
+ *
+ * 1. Every node, x, has the following fields:
+ *
+ * a. level[x], the level in the tree at which node
+ * x appears. Leaf nodes are at level zero.
+ *
+ * b. n[x], the number of children pointed to by the
+ * node. Internal nodes point to subtrees while
+ * leaf nodes point to arbitrary data.
+ *
+ * c. The child pointers themselves, child[x,i] such
+ * that 0 <= i < n[x].
+ *
+ * d. n[x]+1 key values stored in increasing
+ * order:
+ *
+ * key[x,0] < key[x,1] < ... < key[x,n[x]].
+ *
+ * e. left[x] is a pointer to the node's left sibling
+ * or the null pointer if this is the left-most
+ * node at this level in the tree.
+ *
+ * f. right[x] is a pointer to the node's right
+ * sibling or the null pointer if this is the
+ * right-most node at this level in the tree.
+ *
+ * 3. The keys key[x,i] partition the key spaces of the
+ * children of x:
+ *
+ * key[x,i] <= key[child[x,i],j] <= key[x,i+1]
+ *
+ * for any valid combination of i and j.
+ *
+ * 4. There are lower and upper bounds on the number of
+ * child pointers a node can contain. These bounds
+ * can be expressed in terms of a fixed integer k>=2
+ * called the `minimum degree' of the B-tree.
+ *
+ * a. Every node other than the root must have at least
+ * k child pointers and k+1 keys. If the tree is
+ * nonempty, the root must have at least one child
+ * pointer and two keys.
+ *
+ * b. Every node can contain at most 2k child pointers
+ * and 2k+1 keys. A node is `full' if it contains
+ * exactly 2k child pointers and 2k+1 keys.
+ *
+ * 5. When searching for a particular value, V, and
+ * key[V] = key[x,i] for some node x and entry i,
+ * then:
+ *
+ * a. If i=0 the child[0] is followed.
+ *
+ * b. If i=n[x] the child[n[x]-1] is followed.
+ *
+ * c. Otherwise, the child that is followed
+ * (either child[x,i-1] or child[x,i]) is
+ * determined by the type of object to which the
+ * leaf nodes of the tree point and is controlled
+ * by the key comparison function registered for
+ * that type of B-tree.
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Bmodule.h" /* This source code file is part of the H5B module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Bpkg.h" /* B-link trees */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#define H5B_SIZEOF_HDR(F) \
+ (H5_SIZEOF_MAGIC + /*magic number */ \
+ 4 + /*type, level, num entries */ \
+ 2*H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses */
+
+/* Default initializer for H5B_ins_ud_t */
+#define H5B_INS_UD_T_NULL {NULL, HADDR_UNDEF, H5AC__NO_FLAGS_SET}
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* "user data" for iterating over B-tree (collects B-tree metadata size) */
+typedef struct H5B_iter_ud_t {
+ H5B_info_t *bt_info; /* Information about B-tree */
+ void *udata; /* Node type's 'udata' for loading & iterator callback */
+} H5B_info_ud_t;
+
+/* Convenience struct for the arguments needed to unprotect a b-tree after a
+ * call to H5B__iterate_helper() or H5B__split() */
+typedef struct H5B_ins_ud_t {
+ H5B_t *bt; /* B-tree */
+ haddr_t addr; /* B-tree address */
+ unsigned cache_flags; /* Cache flags for H5AC_unprotect() */
+} H5B_ins_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static H5B_ins_t H5B__insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
+ const H5B_class_t *type,
+ uint8_t *lt_key,
+ hbool_t *lt_key_changed,
+ uint8_t *md_key, void *udata,
+ uint8_t *rt_key,
+ hbool_t *rt_key_changed,
+ H5B_ins_ud_t *split_bt_ud/*out*/);
+static herr_t H5B__insert_child(H5B_t *bt, unsigned *bt_flags,
+ unsigned idx, haddr_t child,
+ H5B_ins_t anchor, const void *md_key);
+static herr_t H5B__split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
+ unsigned idx, void *udata,
+ H5B_ins_ud_t *split_bt_ud/*out*/);
+static H5B_t * H5B__copy(const H5B_t *old_bt);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the haddr_t sequence information */
+H5FL_SEQ_DEFINE(haddr_t);
+
+/* Declare a PQ free list to manage the native block information */
+H5FL_BLK_DEFINE(native_block);
+
+/* Declare a free list to manage the H5B_t struct */
+H5FL_DEFINE(H5B_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5B_shared_t struct */
+H5FL_DEFINE_STATIC(H5B_shared_t);
+
+/* Declare a free list to manage the raw page information */
+H5FL_BLK_DEFINE_STATIC(page);
+
+/* Declare a free list to manage the native key offset sequence information */
+H5FL_SEQ_DEFINE_STATIC(size_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_create
+ *
+ * Purpose: Creates a new empty B-tree leaf node. The UDATA pointer is
+ * passed as an argument to the sizeof_rkey() method for the
+ * B-tree.
+ *
+ * Return: Success: Non-negative, and the address of new node is
+ * returned through the ADDR_P argument.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_create(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, void *udata,
+ haddr_t *addr_p/*out*/)
+{
+ H5B_t *bt = NULL;
+ H5B_shared_t *shared=NULL; /* Pointer to shared B-tree info */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(addr_p);
+
+ /*
+ * Allocate file and memory data structures.
+ */
+ if(NULL == (bt = H5FL_MALLOC(H5B_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for B-tree root node")
+ HDmemset(&bt->cache_info, 0, sizeof(H5AC_info_t));
+ bt->level = 0;
+ bt->left = HADDR_UNDEF;
+ bt->right = HADDR_UNDEF;
+ bt->nchildren = 0;
+ if(NULL == (bt->rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree node buffer")
+ H5UC_INC(bt->rc_shared);
+ shared=(H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+ if(NULL == (bt->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)) ||
+ NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for B-tree root node")
+ if(HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "file allocation failed for B-tree root node")
+
+ /*
+ * Cache the new B-tree node.
+ */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_BT, *addr_p, bt, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree root node to cache")
+#ifdef H5B_DEBUG
+ H5B__assert(f, dxpl_id, *addr_p, shared->type, udata);
+#endif
+
+done:
+ if(ret_value < 0) {
+ if(shared && shared->sizeof_rnode>0) {
+ H5_CHECK_OVERFLOW(shared->sizeof_rnode,size_t,hsize_t);
+ (void)H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, *addr_p, (hsize_t)shared->sizeof_rnode);
+ } /* end if */
+ if(bt)
+ /* Destroy B-tree node */
+ if(H5B__node_dest(bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_create() */ /*lint !e818 Can't make udata a pointer to const */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_find
+ *
+ * Purpose: Locate the specified information in a B-tree and return
+ * that information by filling in fields of the caller-supplied
+ * UDATA pointer depending on the type of leaf node
+ * requested. The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * Note: This function does not follow the left/right sibling
+ * pointers since it assumes that all nodes can be reached
+ * from the parent node.
+ *
+ * Return: Non-negative (TRUE/FALSE) on success (if found, values returned
+ * through the UDATA argument). Negative on failure (if not found,
+ * UDATA is undefined).
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+{
+ H5B_t *bt = NULL;
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned idx = 0, lt = 0, rt; /* Final, left & right key indices */
+ int cmp = 1; /* Key comparison value */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(type->found);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Perform a binary search to locate the child which contains
+ * the thing for which we're searching.
+ */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ rt = bt->nchildren;
+ while(lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+ /* compare */
+ if((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, (idx + 1)))) < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+ /* Check if not found */
+ if(cmp)
+ HGOTO_DONE(FALSE)
+
+ /*
+ * Follow the link to the subtree or to the data node.
+ */
+ HDassert(idx < bt->nchildren);
+
+ if(bt->level > 0) {
+ if((ret_value = H5B_find(f, dxpl_id, type, bt->child[idx], udata)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in subtree")
+ } /* end if */
+ else {
+ if((ret_value = (type->found)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx), udata)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in leaf node")
+ } /* end else */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__split
+ *
+ * Purpose: Split a single node into two nodes. The old node will
+ * contain the left children and the new node will contain the
+ * right children.
+ *
+ * The UDATA pointer is passed to the sizeof_rkey() method but is
+ * otherwise unused.
+ *
+ * The BT_UD argument is a pointer to a protected B-tree
+ * node.
+ *
+ * Return: Non-negative on success (The address of the new node is
+ * returned through the NEW_ADDR argument). Negative on failure.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 3 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx,
+ void *udata, H5B_ins_ud_t *split_bt_ud/*out*/)
+{
+ H5P_genplist_t *dx_plist; /* Data transfer property list */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned nleft, nright; /* Number of keys in left & right halves */
+ double split_ratios[3]; /* B-tree split ratios */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(bt_ud);
+ HDassert(bt_ud->bt);
+ HDassert(H5F_addr_defined(bt_ud->addr));
+ HDassert(split_bt_ud);
+ HDassert(!split_bt_ud->bt);
+
+ /*
+ * Initialize variables.
+ */
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt_ud->bt->rc_shared);
+ HDassert(shared);
+ HDassert(bt_ud->bt->nchildren == shared->two_k);
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Get B-tree split ratios */
+ if(H5P_get(dx_plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &split_ratios[0]) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree split ratios")
+
+#ifdef H5B_DEBUG
+ if(H5DEBUG(B)) {
+ const char *side;
+
+ if(!H5F_addr_defined(bt_ud->bt->left) && !H5F_addr_defined(bt_ud->bt->right))
+ side = "ONLY";
+ else if(!H5F_addr_defined(bt_ud->bt->right))
+ side = "RIGHT";
+ else if(!H5F_addr_defined(bt_ud->bt->left))
+ side = "LEFT";
+ else
+ side = "MIDDLE";
+ fprintf(H5DEBUG(B), "H5B__split: %3u {%5.3f,%5.3f,%5.3f} %6s",
+ shared->two_k, split_ratios[0], split_ratios[1], split_ratios[2], side);
+ }
+#endif
+
+ /*
+ * Decide how to split the children of the old node among the old node
+ * and the new node.
+ */
+ if(!H5F_addr_defined(bt_ud->bt->right))
+ nleft = (unsigned)((double)shared->two_k * split_ratios[2]); /*right*/
+ else if(!H5F_addr_defined(bt_ud->bt->left))
+ nleft = (unsigned)((double)shared->two_k * split_ratios[0]); /*left*/
+ else
+ nleft = (unsigned)((double)shared->two_k * split_ratios[1]); /*middle*/
+
+ /*
+ * Keep the new child in the same node as the child that split. This can
+ * result in nodes that have an unused child when data is written
+ * sequentially, but it simplifies stuff below.
+ */
+ if(idx < nleft && nleft == shared->two_k)
+ --nleft;
+ else if(idx >= nleft && 0 == nleft)
+ nleft++;
+ nright = shared->two_k - nleft;
+#ifdef H5B_DEBUG
+ if(H5DEBUG(B))
+ fprintf(H5DEBUG(B), " split %3d/%-3d\n", nleft, nright);
+#endif
+
+ /*
+ * Create the new B-tree node.
+ */
+ if(H5B_create(f, dxpl_id, shared->type, udata, &split_bt_ud->addr/*out*/) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create B-tree")
+ cache_udata.f = f;
+ cache_udata.type = shared->type;
+ cache_udata.rc_shared = bt_ud->bt->rc_shared;
+ if(NULL == (split_bt_ud->bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree")
+ split_bt_ud->bt->level = bt_ud->bt->level;
+
+ /*
+ * Copy data from the old node to the new node.
+ */
+
+ split_bt_ud->cache_flags = H5AC__DIRTIED_FLAG;
+ HDmemcpy(split_bt_ud->bt->native,
+ bt_ud->bt->native + nleft * shared->type->sizeof_nkey,
+ (nright + 1) * shared->type->sizeof_nkey);
+ HDmemcpy(split_bt_ud->bt->child,
+ &bt_ud->bt->child[nleft],
+ nright * sizeof(haddr_t));
+
+ split_bt_ud->bt->nchildren = nright;
+
+ /*
+ * Truncate the old node.
+ */
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ bt_ud->bt->nchildren = nleft;
+
+ /*
+ * Update other sibling pointers.
+ */
+ split_bt_ud->bt->left = bt_ud->addr;
+ split_bt_ud->bt->right = bt_ud->bt->right;
+
+ if(H5F_addr_defined(bt_ud->bt->right)) {
+ H5B_t *tmp_bt;
+
+ if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling")
+
+ tmp_bt->left = split_bt_ud->addr;
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, tmp_bt, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end if */
+
+ bt_ud->bt->right = split_bt_ud->addr;
+ HDassert(bt_ud->cache_flags & H5AC__DIRTIED_FLAG);
+
+done:
+ if(ret_value < 0) {
+ if(split_bt_ud->bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, split_bt_ud->addr, split_bt_ud->bt, split_bt_ud->cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ split_bt_ud->bt = NULL;
+ split_bt_ud->addr = HADDR_UNDEF;
+ split_bt_ud->cache_flags = H5AC__NO_FLAGS_SET;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__split() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_insert
+ *
+ * Purpose: Adds a new item to the B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+{
+ /*
+ * These are defined this way to satisfy alignment constraints.
+ */
+ uint64_t _lt_key[128], _md_key[128], _rt_key[128];
+ uint8_t *lt_key=(uint8_t*)_lt_key;
+ uint8_t *md_key=(uint8_t*)_md_key;
+ uint8_t *rt_key=(uint8_t*)_rt_key;
+
+ hbool_t lt_key_changed = FALSE, rt_key_changed = FALSE;
+ haddr_t old_root_addr = HADDR_UNDEF;
+ unsigned level;
+ H5B_ins_ud_t bt_ud = H5B_INS_UD_T_NULL; /* (Old) root node */
+ H5B_ins_ud_t split_bt_ud = H5B_INS_UD_T_NULL; /* Split B-tree node */
+ H5B_t *new_root_bt = NULL; /* New root node */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ H5B_ins_t my_ins = H5B_INS_ERROR;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->sizeof_nkey <= sizeof _lt_key);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /* Protect the root node */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ bt_ud.addr = addr;
+ if(NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to locate root of B-tree")
+
+ /* Insert the object */
+ if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &bt_ud, type, lt_key,
+ &lt_key_changed, md_key, udata, rt_key, &rt_key_changed,
+ &split_bt_ud/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to insert key")
+
+ /* Check if the root node split */
+ if(H5B_INS_NOOP == my_ins) {
+ /* The root node did not split - just return */
+ HDassert(!split_bt_ud.bt);
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+ HDassert(H5B_INS_RIGHT == my_ins);
+ HDassert(split_bt_ud.bt);
+ HDassert(H5F_addr_defined(split_bt_ud.addr));
+
+ /* Get level of old root */
+ level = bt_ud.bt->level;
+
+ /* update left and right keys */
+ if(!lt_key_changed)
+ HDmemcpy(lt_key, H5B_NKEY(bt_ud.bt,shared,0), type->sizeof_nkey);
+ if(!rt_key_changed)
+ HDmemcpy(rt_key, H5B_NKEY(split_bt_ud.bt,shared,split_bt_ud.bt->nchildren), type->sizeof_nkey);
+
+ /*
+ * Copy the old root node to some other file location and make the new root
+ * at the old root's previous address. This prevents the B-tree from
+ * "moving".
+ */
+ H5_CHECK_OVERFLOW(shared->sizeof_rnode,size_t,hsize_t);
+ if(HADDR_UNDEF == (old_root_addr = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)shared->sizeof_rnode)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move root")
+
+ /*
+ * Move the node to the new location
+ */
+
+ /* Make a copy of the old root information */
+ if(NULL == (new_root_bt = H5B__copy(bt_ud.bt)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to copy old root")
+
+ /* Unprotect the old root so we can move it. Also force it to be marked
+ * dirty so it is written to the new location. */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release old root")
+ bt_ud.bt = NULL; /* Make certain future references will be caught */
+
+ /* Move the location of the old root on the disk */
+ if(H5AC_move_entry(f, H5AC_BT, bt_ud.addr, old_root_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to move B-tree root node")
+ bt_ud.addr = old_root_addr;
+
+ /* Update the split b-tree's left pointer to point to the new location */
+ split_bt_ud.bt->left = bt_ud.addr;
+ split_bt_ud.cache_flags |= H5AC__DIRTIED_FLAG;
+
+ /* clear the old root info at the old address (we already copied it) */
+ new_root_bt->left = HADDR_UNDEF;
+ new_root_bt->right = HADDR_UNDEF;
+
+ /* Set the new information for the copy */
+ new_root_bt->level = level + 1;
+ new_root_bt->nchildren = 2;
+
+ new_root_bt->child[0] = bt_ud.addr;
+ HDmemcpy(H5B_NKEY(new_root_bt, shared, 0), lt_key, shared->type->sizeof_nkey);
+
+ new_root_bt->child[1] = split_bt_ud.addr;
+ HDmemcpy(H5B_NKEY(new_root_bt, shared, 1), md_key, shared->type->sizeof_nkey);
+ HDmemcpy(H5B_NKEY(new_root_bt, shared, 2), rt_key, shared->type->sizeof_nkey);
+
+ /* Insert the modified copy of the old root into the file again */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_BT, addr, new_root_bt, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to add old B-tree root node to cache")
+
+done:
+ if(ret_value < 0)
+ if(new_root_bt && H5B__node_dest(new_root_bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to free B-tree root node");
+
+ if(bt_ud.bt)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt_ud.addr, bt_ud.bt, bt_ud.cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect old root")
+
+ if(split_bt_ud.bt)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, split_bt_ud.addr, split_bt_ud.bt, split_bt_ud.cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect new child")
+
+#ifdef H5B_DEBUG
+ if(ret_value >= 0)
+ H5B__assert(f, dxpl_id, addr, type, udata);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__insert_child
+ *
+ * Purpose: Insert a child to the left or right of child[IDX] depending
+ * on whether ANCHOR is H5B_INS_LEFT or H5B_INS_RIGHT. The BT
+ * argument is a pointer to a protected B-tree node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 8 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__insert_child(H5B_t *bt, unsigned *bt_flags, unsigned idx,
+ haddr_t child, H5B_ins_t anchor, const void *md_key)
+{
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ uint8_t *base; /* Base offset for move */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(bt);
+ HDassert(bt_flags);
+ HDassert(H5F_addr_defined(child));
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+ HDassert(bt->nchildren < shared->two_k);
+
+ /* Check for inserting right-most key into node (common when just appending
+ * records to an unlimited dimension chunked dataset)
+ */
+ base = H5B_NKEY(bt, shared, (idx + 1));
+ if((idx + 1) == bt->nchildren) {
+ /* Make room for the new key */
+ HDmemcpy(base + shared->type->sizeof_nkey, base,
+ shared->type->sizeof_nkey); /* No overlap possible - memcpy() OK */
+ HDmemcpy(base, md_key, shared->type->sizeof_nkey);
+
+ /* The MD_KEY is the left key of the new node */
+ if(H5B_INS_RIGHT == anchor)
+ idx++; /* Don't have to memmove() child addresses down, just add new child */
+ else
+ /* Make room for the new child address */
+ bt->child[idx + 1] = bt->child[idx];
+ } /* end if */
+ else {
+ /* Make room for the new key */
+ HDmemmove(base + shared->type->sizeof_nkey, base,
+ (bt->nchildren - idx) * shared->type->sizeof_nkey);
+ HDmemcpy(base, md_key, shared->type->sizeof_nkey);
+
+ /* The MD_KEY is the left key of the new node */
+ if(H5B_INS_RIGHT == anchor)
+ idx++;
+
+ /* Make room for the new child address */
+ HDmemmove(bt->child + idx + 1, bt->child + idx,
+ (bt->nchildren - idx) * sizeof(haddr_t));
+ } /* end if */
+
+ bt->child[idx] = child;
+ bt->nchildren += 1;
+
+ /* Mark node as dirty */
+ *bt_flags |= H5AC__DIRTIED_FLAG;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B_insert_child() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__insert_helper
+ *
+ * Purpose: Inserts the item UDATA into the tree rooted at ADDR and having
+ * the specified type.
+ *
+ * On return, if LT_KEY_CHANGED is non-zero, then LT_KEY is
+ * the new native left key. Similarily for RT_KEY_CHANGED
+ * and RT_KEY.
+ *
+ * If the node splits, then MD_KEY contains the key that
+ * was split between the two nodes (that is, the key that
+ * appears as the max key in the left node and the min key
+ * in the right node).
+ *
+ * Return: Success: A B-tree operation. The address of the new
+ * node, if the node splits, is returned through
+ * the NEW_NODE_P argument. The new node is always
+ * to the right of the previous node. This
+ * function is called recursively and the return
+ * value influences the behavior of the caller.
+ * See also, declaration of H5B_ins_t.
+ *
+ * Failure: H5B_INS_ERROR
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 9 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5B__insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud,
+ const H5B_class_t *type,
+ uint8_t *lt_key, hbool_t *lt_key_changed,
+ uint8_t *md_key, void *udata,
+ uint8_t *rt_key, hbool_t *rt_key_changed,
+ H5B_ins_ud_t *split_bt_ud/*out*/)
+{
+ H5B_t *bt; /* Convenience pointer to B-tree */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned lt = 0, idx = 0, rt; /* Left, final & right index values */
+ int cmp = -1; /* Key comparison value */
+ H5B_ins_ud_t child_bt_ud = H5B_INS_UD_T_NULL; /* Child B-tree */
+ H5B_ins_ud_t new_child_bt_ud = H5B_INS_UD_T_NULL; /* Newly split child B-tree */
+ H5B_ins_t my_ins = H5B_INS_ERROR;
+ H5B_ins_t ret_value = H5B_INS_ERROR; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments
+ */
+ HDassert(f);
+ HDassert(bt_ud);
+ HDassert(bt_ud->bt);
+ HDassert(H5F_addr_defined(bt_ud->addr));
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(type->new_node);
+ HDassert(lt_key);
+ HDassert(lt_key_changed);
+ HDassert(rt_key);
+ HDassert(rt_key_changed);
+ HDassert(split_bt_ud);
+ HDassert(!split_bt_ud->bt);
+ HDassert(!H5F_addr_defined(split_bt_ud->addr));
+ HDassert(split_bt_ud->cache_flags == H5AC__NO_FLAGS_SET);
+
+ bt = bt_ud->bt;
+
+ *lt_key_changed = FALSE;
+ *rt_key_changed = FALSE;
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, H5B_INS_ERROR, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Use a binary search to find the child that will receive the new
+ * data. When the search completes IDX points to the child that
+ * should get the new data.
+ */
+ rt = bt->nchildren;
+
+ while(lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+ if((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, idx + 1))) < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+
+ /* Set up user data for cache callbacks */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+
+ if(0 == bt->nchildren) {
+ /*
+ * The value being inserted will be the only value in this tree. We
+ * must necessarily be at level zero.
+ */
+ HDassert(0 == bt->level);
+ if((type->new_node)(f, dxpl_id, H5B_INS_FIRST, H5B_NKEY(bt, shared, 0), udata,
+ H5B_NKEY(bt, shared, 1), bt->child + 0/*out*/) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, H5B_INS_ERROR, "unable to create leaf node")
+ bt->nchildren = 1;
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ idx = 0;
+
+ if(type->follow_min) {
+ if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx),
+ lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
+ rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "unable to insert first leaf node")
+ } /* end if */
+ else
+ my_ins = H5B_INS_NOOP;
+ } else if(cmp < 0 && idx == 0) {
+ if(bt->level > 0) {
+ /*
+ * The value being inserted is less than any value in this tree.
+ * Follow the minimum branch out of this node to a subtree.
+ */
+ child_bt_ud.addr = bt->child[idx];
+ if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node")
+
+ if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type,
+ H5B_NKEY(bt,shared,idx), lt_key_changed, md_key,
+ udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
+ &new_child_bt_ud/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum subtree")
+ } else if(type->follow_min) {
+ /*
+ * The value being inserted is less than any leaf node out of this
+ * current node. Follow the minimum branch to a leaf node and let
+ * the subclass handle the problem.
+ */
+ if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx),
+ lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
+ rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node")
+ } else {
+ /*
+ * The value being inserted is less than any leaf node out of the
+ * current node. Create a new minimum leaf node out of this B-tree
+ * node. This node is not empty (handled above).
+ */
+ my_ins = H5B_INS_LEFT;
+ HDmemcpy(md_key, H5B_NKEY(bt,shared,idx), type->sizeof_nkey);
+ if((type->new_node)(f, dxpl_id, H5B_INS_LEFT, H5B_NKEY(bt, shared, idx), udata,
+ md_key, &new_child_bt_ud.addr/*out*/) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert minimum leaf node")
+ *lt_key_changed = TRUE;
+ } /* end else */
+
+#ifdef H5_STRICT_FORMAT_CHECKS
+ /* Since we are to the left of the leftmost key there must not be a left
+ * sibling */
+ if(H5F_addr_defined(bt->left))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "internal error: likely corrupt key values")
+#endif /* H5_STRICT_FORMAT_CHECKS */
+ } else if(cmp > 0 && idx + 1 >= bt->nchildren) {
+ if (bt->level > 0) {
+ /*
+ * The value being inserted is larger than any value in this tree.
+ * Follow the maximum branch out of this node to a subtree.
+ */
+ idx = bt->nchildren - 1;
+ child_bt_ud.addr = bt->child[idx];
+ if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node")
+
+ if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type,
+ H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata,
+ H5B_NKEY(bt, shared, idx + 1), rt_key_changed,
+ &new_child_bt_ud/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum subtree")
+ } else if(type->follow_max) {
+ /*
+ * The value being inserted is larger than any leaf node out of the
+ * current node. Follow the maximum branch to a leaf node and let
+ * the subclass handle the problem.
+ */
+ idx = bt->nchildren - 1;
+ if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx),
+ lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
+ rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node")
+ } else {
+ /*
+ * The value being inserted is larger than any leaf node out of the
+ * current node. Create a new maximum leaf node out of this B-tree
+ * node.
+ */
+ idx = bt->nchildren - 1;
+ my_ins = H5B_INS_RIGHT;
+ HDmemcpy(md_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
+ if((type->new_node)(f, dxpl_id, H5B_INS_RIGHT, md_key, udata,
+ H5B_NKEY(bt, shared, idx + 1), &new_child_bt_ud.addr/*out*/) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert maximum leaf node")
+ *rt_key_changed = TRUE;
+ } /* end else */
+
+#ifdef H5_STRICT_FORMAT_CHECKS
+ /* Since we are to the right of the rightmost key there must not be a
+ * right sibling */
+ if(H5F_addr_defined(bt->right))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "internal error: likely corrupt key values")
+#endif /* H5_STRICT_FORMAT_CHECKS */
+ } else if(cmp) {
+ /*
+ * We couldn't figure out which branch to follow out of this node. THIS
+ * IS A MAJOR PROBLEM THAT NEEDS TO BE FIXED --rpm.
+ */
+ HDassert("INTERNAL HDF5 ERROR (contact rpm)" && 0);
+#ifdef NDEBUG
+ HDabort();
+#endif /* NDEBUG */
+ } else if(bt->level > 0) {
+ /*
+ * Follow a branch out of this node to another subtree.
+ */
+ HDassert(idx < bt->nchildren);
+ child_bt_ud.addr = bt->child[idx];
+ if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node")
+
+ if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type,
+ H5B_NKEY(bt, shared, idx), lt_key_changed, md_key, udata,
+ H5B_NKEY(bt, shared, idx + 1), rt_key_changed, &new_child_bt_ud/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert subtree")
+ } else {
+ /*
+ * Follow a branch out of this node to a leaf node of some other type.
+ */
+ HDassert(idx < bt->nchildren);
+ if((int)(my_ins = (type->insert)(f, dxpl_id, bt->child[idx], H5B_NKEY(bt, shared, idx),
+ lt_key_changed, md_key, udata, H5B_NKEY(bt, shared, idx + 1),
+ rt_key_changed, &new_child_bt_ud.addr/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert leaf node")
+ }
+ HDassert((int)my_ins >= 0);
+
+ /*
+ * Update the left and right keys of the current node.
+ */
+ if(*lt_key_changed) {
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ if(idx > 0) {
+ HDassert(type->critical_key == H5B_LEFT);
+ HDassert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins));
+ *lt_key_changed = FALSE;
+ } /* end if */
+ else
+ HDmemcpy(lt_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey);
+ } /* end if */
+ if(*rt_key_changed) {
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ if(idx + 1 < bt->nchildren) {
+ HDassert(type->critical_key == H5B_RIGHT);
+ HDassert(!(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins));
+ *rt_key_changed = FALSE;
+ } /* end if */
+ else
+ HDmemcpy(rt_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
+ } /* end if */
+
+ /*
+ * Handle changes/additions to children
+ */
+ HDassert(!(bt->level == 0) != !(child_bt_ud.bt));
+ if(H5B_INS_CHANGE == my_ins) {
+ /*
+ * The insertion simply changed the address for the child.
+ */
+ HDassert(!child_bt_ud.bt);
+ HDassert(bt->level == 0);
+ bt->child[idx] = new_child_bt_ud.addr;
+ bt_ud->cache_flags |= H5AC__DIRTIED_FLAG;
+ } else if(H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins) {
+ unsigned *tmp_bt_flags_ptr = NULL;
+ H5B_t *tmp_bt;
+
+ /*
+ * If this node is full then split it before inserting the new child.
+ */
+ if(bt->nchildren == shared->two_k) {
+ if(H5B__split(f, dxpl_id, bt_ud, idx, udata, split_bt_ud/*out*/) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, H5B_INS_ERROR, "unable to split node")
+ if(idx < bt->nchildren) {
+ tmp_bt = bt;
+ tmp_bt_flags_ptr = &bt_ud->cache_flags;
+ } else {
+ idx -= bt->nchildren;
+ tmp_bt = split_bt_ud->bt;
+ tmp_bt_flags_ptr = &split_bt_ud->cache_flags;
+ }
+ } /* end if */
+ else {
+ tmp_bt = bt;
+ tmp_bt_flags_ptr = &bt_ud->cache_flags;
+ } /* end else */
+
+ /* Insert the child */
+ if(H5B__insert_child(tmp_bt, tmp_bt_flags_ptr, idx, new_child_bt_ud.addr, my_ins, md_key) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, "can't insert child")
+ } /* end else-if */
+
+ /*
+ * If this node split, return the mid key (the one that is shared
+ * by the left and right node).
+ */
+ if(split_bt_ud->bt) {
+ HDmemcpy(md_key, H5B_NKEY(split_bt_ud->bt, shared, 0), type->sizeof_nkey);
+ ret_value = H5B_INS_RIGHT;
+#ifdef H5B_DEBUG
+ /*
+ * The max key in the original left node must be equal to the min key
+ * in the new node.
+ */
+ cmp = (type->cmp2)(H5B_NKEY(bt, shared, bt->nchildren), udata,
+ H5B_NKEY(split_bt_ud->bt, shared, 0));
+ HDassert(0 == cmp);
+#endif
+ } /* end if */
+ else
+ ret_value = H5B_INS_NOOP;
+
+done:
+ if(child_bt_ud.bt)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, child_bt_ud.bt, child_bt_ud.cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect child")
+
+ if(new_child_bt_ud.bt)
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, new_child_bt_ud.addr, new_child_bt_ud.bt, new_child_bt_ud.cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to unprotect new child")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_insert_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__iterate_helper
+ *
+ * Purpose: Calls the list callback for each leaf node of the
+ * B-tree, passing it the caller's UDATA structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__iterate_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ H5B_operator_t op, void *udata)
+{
+ H5B_t *bt = NULL; /* Pointer to current B-tree node */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(op);
+ HDassert(udata);
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /* Protect the initial/current node */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node")
+
+ /* Iterate over node's children */
+ for(u = 0; u < bt->nchildren && ret_value == H5_ITER_CONT; u++) {
+ if(bt->level > 0)
+ ret_value = H5B__iterate_helper(f, dxpl_id, type, bt->child[u], op, udata);
+ else
+ ret_value = (*op)(f, dxpl_id, H5B_NKEY(bt, shared, u), bt->child[u], H5B_NKEY(bt, shared, u + 1), udata);
+ if(ret_value < 0)
+ HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
+ } /* end for */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__iterate_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_iterate
+ *
+ * Purpose: Calls the list callback for each leaf node of the
+ * B-tree, passing it the UDATA structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_iterate(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ H5B_operator_t op, void *udata)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(op);
+ HDassert(udata);
+
+ /* Iterate over the B-tree records */
+ if((ret_value = H5B__iterate_helper(f, dxpl_id, type, addr, op, udata)) < 0)
+ HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__remove_helper
+ *
+ * Purpose: The recursive part of removing an item from a B-tree. The
+ * sub B-tree that is being considered is located at ADDR and
+ * the item to remove is described by UDATA. If the removed
+ * item falls at the left or right end of the current level then
+ * it might be necessary to adjust the left and/or right keys
+ * (LT_KEY and/or RT_KEY) to to indicate that they changed by
+ * setting LT_KEY_CHANGED and/or RT_KEY_CHANGED.
+ *
+ * Return: Success: A B-tree operation, see comments for
+ * H5B_ins_t declaration. This function is
+ * called recursively and the return value
+ * influences the actions of the caller. It is
+ * also called by H5B_remove().
+ *
+ * Failure: H5B_INS_ERROR, a negative value.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type,
+ int level, uint8_t *lt_key/*out*/,
+ hbool_t *lt_key_changed/*out*/, void *udata,
+ uint8_t *rt_key/*out*/, hbool_t *rt_key_changed/*out*/)
+{
+ H5B_t *bt = NULL, *sibling = NULL;
+ unsigned bt_flags = H5AC__NO_FLAGS_SET;
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned idx = 0, lt = 0, rt; /* Final, left & right indices */
+ int cmp = 1; /* Key comparison value */
+ H5B_ins_t ret_value = H5B_INS_ERROR;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(type);
+ HDassert(type->decode);
+ HDassert(type->cmp3);
+ HDassert(lt_key && lt_key_changed);
+ HDassert(udata);
+ HDassert(rt_key && rt_key_changed);
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, H5B_INS_ERROR, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Perform a binary search to locate the child which contains the thing
+ * for which we're searching.
+ */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node")
+
+ rt = bt->nchildren;
+ while(lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+ if((cmp = (type->cmp3)(H5B_NKEY(bt, shared, idx), udata, H5B_NKEY(bt, shared, idx + 1))) < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+ if(cmp)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "B-tree key not found")
+
+ /*
+ * Follow the link to the subtree or to the data node. The return value
+ * will be one of H5B_INS_ERROR, H5B_INS_NOOP, or H5B_INS_REMOVE.
+ */
+ HDassert(idx < bt->nchildren);
+ if(bt->level > 0) {
+ /* We're at an internal node -- call recursively */
+ if((int)(ret_value = H5B__remove_helper(f, dxpl_id,
+ bt->child[idx], type, level + 1, H5B_NKEY(bt, shared, idx)/*out*/,
+ lt_key_changed/*out*/, udata, H5B_NKEY(bt, shared, idx + 1)/*out*/,
+ rt_key_changed/*out*/)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "key not found in subtree")
+ } else if(type->remove) {
+ /*
+ * We're at a leaf node but the leaf node points to an object that
+ * has a removal method. Pass the removal request to the pointed-to
+ * object and let it decide how to progress.
+ */
+ if((int)(ret_value = (type->remove)(f, dxpl_id,
+ bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, udata,
+ H5B_NKEY(bt, shared, idx + 1), rt_key_changed)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "key not found in leaf node")
+ } else {
+ /*
+ * We're at a leaf node which points to an object that has no removal
+ * method. The best we can do is to leave the object alone but
+ * remove the B-tree reference to the object.
+ */
+ *lt_key_changed = FALSE;
+ *rt_key_changed = FALSE;
+ ret_value = H5B_INS_REMOVE;
+ }
+
+ /*
+ * Update left and right key dirty bits if the subtree indicates that they
+ * have changed. If the subtree's left key changed and the subtree is the
+ * left-most child of the current node then we must update the key in our
+ * parent and indicate that it changed. Similarly, if the right subtree
+ * key changed and it's the right most key of this node we must update
+ * our right key and indicate that it changed.
+ */
+ if(*lt_key_changed) {
+ HDassert(type->critical_key == H5B_LEFT);
+ bt_flags |= H5AC__DIRTIED_FLAG;
+
+ if(idx > 0)
+ /* Don't propagate change out of this B-tree node */
+ *lt_key_changed = FALSE;
+ else
+ HDmemcpy(lt_key, H5B_NKEY(bt, shared, idx), type->sizeof_nkey);
+ } /* end if */
+ if(*rt_key_changed) {
+ HDassert(type->critical_key == H5B_RIGHT);
+ bt_flags |= H5AC__DIRTIED_FLAG;
+ if(idx + 1 < bt->nchildren)
+ /* Don't propagate change out of this B-tree node */
+ *rt_key_changed = FALSE;
+ else
+ HDmemcpy(rt_key, H5B_NKEY(bt, shared, idx + 1), type->sizeof_nkey);
+ } /* end if */
+
+ /*
+ * If the subtree returned H5B_INS_REMOVE then we should remove the
+ * subtree entry from the current node. There are four cases:
+ */
+ if(H5B_INS_REMOVE == ret_value) {
+ /* Clients should not change keys when a node is removed. This function
+ * will handle it as appropriate, based on the value of bt->critical_key
+ */
+ HDassert(!(*lt_key_changed));
+ HDassert(!(*rt_key_changed));
+
+ if(1 == bt->nchildren) {
+ /*
+ * The subtree is the only child of this node. Discard both
+ * keys and the subtree pointer. Free this node (unless it's the
+ * root node) and return H5B_INS_REMOVE.
+ */
+ /* Only delete the node if it is not the root node. Note that this
+ * "level" is the opposite of bt->level */
+ if(level > 0) {
+ /* Fix siblings, making sure that the keys remain consistent
+ * between siblings. Overwrite the key that that is not
+ * "critical" for any child in its node to maintain this
+ * consistency (and avoid breaking key/child consistency) */
+ if(H5F_addr_defined(bt->left)) {
+ if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node from tree")
+
+ /* Copy right-most key from deleted node to right-most key
+ * in its left neighbor, but only if it is not the critical
+ * key for the right-most child of the left neighbor */
+ if(type->critical_key == H5B_LEFT)
+ HDmemcpy(H5B_NKEY(sibling, shared, sibling->nchildren),
+ H5B_NKEY(bt, shared, 1), type->sizeof_nkey);
+
+ sibling->right = bt->right;
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt->left, sibling, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree")
+ sibling = NULL; /* Make certain future references will be caught */
+ } /* end if */
+ if(H5F_addr_defined(bt->right)) {
+ if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to unlink node from tree")
+
+ /* Copy left-most key from deleted node to left-most key in
+ * its right neighbor, but only if it is not the critical
+ * key for the left-most child of the right neighbor */
+ if(type->critical_key == H5B_RIGHT)
+ HDmemcpy(H5B_NKEY(sibling, shared, 0),
+ H5B_NKEY(bt, shared, 0), type->sizeof_nkey);
+
+ sibling->left = bt->left;
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt->right, sibling, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree")
+ sibling = NULL; /* Make certain future references will be caught */
+ } /* end if */
+
+ /* Update bt struct */
+ bt->left = HADDR_UNDEF;
+ bt->right = HADDR_UNDEF;
+ bt->nchildren = 0;
+
+ /* Delete the node from disk (via the metadata cache) */
+ bt_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+ H5_CHECK_OVERFLOW(shared->sizeof_rnode, size_t, hsize_t);
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, bt_flags | H5AC__DELETED_FLAG) < 0) {
+ bt = NULL;
+ bt_flags = H5AC__NO_FLAGS_SET;
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to free B-tree node")
+ } /* end if */
+ bt = NULL;
+ bt_flags = H5AC__NO_FLAGS_SET;
+ } else {
+ /* We removed the last child in the root node, set the level
+ * back to 0 (as well as nchildren) */
+ bt->nchildren = 0;
+ bt->level = 0;
+ bt_flags |= H5AC__DIRTIED_FLAG;
+ } /* end else */
+ } else if(0 == idx) {
+ /*
+ * The subtree is the left-most child of this node. We update the
+ * key and child arrays and lt_key as appropriate, depending on the
+ * status of bt->critical_key. Return H5B_INS_NOOP.
+ */
+ if(type->critical_key == H5B_LEFT) {
+ /* Slide all keys down 1, update lt_key */
+ HDmemmove(H5B_NKEY(bt, shared, 0), H5B_NKEY(bt, shared, 1),
+ bt->nchildren * type->sizeof_nkey);
+ HDmemcpy(lt_key, H5B_NKEY(bt, shared, 0), type->sizeof_nkey);
+ *lt_key_changed = TRUE;
+ } else
+ /* Slide all but the leftmost 2 keys down, leaving the leftmost
+ * key intact (the right key of the leftmost child is
+ * overwritten) */
+ HDmemmove(H5B_NKEY(bt, shared, 1), H5B_NKEY(bt, shared, 2),
+ (bt->nchildren - 1) * type->sizeof_nkey);
+
+ HDmemmove(bt->child,
+ bt->child + 1,
+ (bt->nchildren - 1) * sizeof(haddr_t));
+
+ bt->nchildren -= 1;
+ bt_flags |= H5AC__DIRTIED_FLAG;
+ ret_value = H5B_INS_NOOP;
+ } else if(idx + 1 == bt->nchildren) {
+ /*
+ * The subtree is the right-most child of this node. We update the
+ * key and child arrays and rt_key as appropriate, depending on the
+ * status of bt->critical_key. Return H5B_INS_NOOP.
+ */
+ if(type->critical_key == H5B_LEFT)
+ /* Slide the rightmost key down one, overwriting the left key of
+ * the deleted (righmost) child */
+ HDmemmove(H5B_NKEY(bt, shared, bt->nchildren - 1),
+ H5B_NKEY(bt, shared, bt->nchildren), type->sizeof_nkey);
+ else {
+ /* Just update rt_key */
+ HDmemcpy(rt_key, H5B_NKEY(bt, shared, bt->nchildren - 1),
+ type->sizeof_nkey);
+ *rt_key_changed = TRUE;
+ } /* end else */
+
+ bt->nchildren -= 1;
+ bt_flags |= H5AC__DIRTIED_FLAG;
+ ret_value = H5B_INS_NOOP;
+ } else {
+ /*
+ * There are subtrees out of this node to both the left and right of
+ * the subtree being removed. The subtree and its critical key are
+ * removed from this node and all keys and nodes to the right are
+ * shifted left by one place. The subtree has already been freed.
+ * Return H5B_INS_NOOP.
+ */
+ if(type->critical_key == H5B_LEFT)
+ HDmemmove(H5B_NKEY(bt, shared, idx),
+ H5B_NKEY(bt, shared, idx + 1),
+ (bt->nchildren - idx) * type->sizeof_nkey);
+ else
+ HDmemmove(H5B_NKEY(bt, shared, idx + 1),
+ H5B_NKEY(bt, shared, idx + 2),
+ (bt->nchildren - 1 - idx) * type->sizeof_nkey);
+
+ HDmemmove(bt->child + idx,
+ bt->child + idx + 1,
+ (bt->nchildren - 1 - idx) * sizeof(haddr_t));
+
+ bt->nchildren -= 1;
+ bt_flags |= H5AC__DIRTIED_FLAG;
+ ret_value = H5B_INS_NOOP;
+ } /* end else */
+ } else /* H5B_INS_REMOVE != ret_value */
+ ret_value = H5B_INS_NOOP;
+
+ /* Patch keys in neighboring trees if necessary */
+ if(*lt_key_changed && H5F_addr_defined(bt->left)) {
+ HDassert(type->critical_key == H5B_LEFT);
+ HDassert(level > 0);
+
+ /* Update the rightmost key in the left sibling */
+ if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node")
+
+ HDmemcpy(H5B_NKEY(sibling, shared, sibling->nchildren),
+ H5B_NKEY(bt, shared, 0), type->sizeof_nkey);
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt->left, sibling, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree")
+ sibling = NULL; /* Make certain future references will be caught */
+ } /* end if */
+ else if(*rt_key_changed && H5F_addr_defined(bt->right)) {
+ HDassert(type->critical_key == H5B_RIGHT);
+ HDassert(level > 0);
+
+ /* Update the lefttmost key in the right sibling */
+ if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node")
+
+ HDmemcpy(H5B_NKEY(sibling, shared, 0),
+ H5B_NKEY(bt, shared, bt->nchildren), type->sizeof_nkey);
+
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, bt->right, sibling, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node from tree")
+ sibling = NULL; /* Make certain future references will be caught */
+ } /* end else */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, bt_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__remove_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_remove
+ *
+ * Purpose: Removes an item from a B-tree.
+ *
+ * Note: The current version does not attempt to rebalance the tree.
+ * (Read the paper Yao & Lehman paper for details on why)
+ *
+ * Return: Non-negative on success/Negative on failure (failure includes
+ * not being able to find the object which is to be removed).
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+{
+ /* These are defined this way to satisfy alignment constraints */
+ uint64_t _lt_key[128], _rt_key[128];
+ uint8_t *lt_key = (uint8_t*)_lt_key; /*left key*/
+ uint8_t *rt_key = (uint8_t*)_rt_key; /*right key*/
+ hbool_t lt_key_changed = FALSE; /*left key changed?*/
+ hbool_t rt_key_changed = FALSE; /*right key changed?*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(type);
+ HDassert(type->sizeof_nkey <= sizeof _lt_key);
+ HDassert(H5F_addr_defined(addr));
+
+ /* The actual removal */
+ if(H5B__remove_helper(f, dxpl_id, addr, type, 0, lt_key, &lt_key_changed,
+ udata, rt_key, &rt_key_changed) == H5B_INS_ERROR)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to remove entry from B-tree")
+
+#ifdef H5B_DEBUG
+ H5B__assert(f, dxpl_id, addr, type, udata);
+#endif
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_delete
+ *
+ * Purpose: Deletes an entire B-tree from the file, calling the 'remove'
+ * callbacks for each node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *udata)
+{
+ H5B_t *bt = NULL; /* B-tree node being operated on */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /* Lock this B-tree node into memory for now */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ /* Iterate over all children in tree, deleting them */
+ if(bt->level > 0) {
+ /* Iterate over all children in node, deleting them */
+ for(u = 0; u < bt->nchildren; u++)
+ if(H5B_delete(f, dxpl_id, type, bt->child[u], udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to delete B-tree node")
+
+ } /* end if */
+ else {
+ hbool_t lt_key_changed, rt_key_changed; /* Whether key changed (unused here, just for callback) */
+
+ /* Check for removal callback */
+ if(type->remove) {
+ /* Iterate over all entries in node, calling callback */
+ for(u = 0; u < bt->nchildren; u++) {
+ /* Call user's callback for each entry */
+ if((type->remove)(f, dxpl_id,
+ bt->child[u], H5B_NKEY(bt, shared, u), &lt_key_changed, udata,
+ H5B_NKEY(bt, shared, u + 1), &rt_key_changed) < H5B_INS_NOOP)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't remove B-tree node")
+ } /* end for */
+ } /* end if */
+ } /* end else */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node in cache")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_shared_new
+ *
+ * Purpose: Allocates & constructs a shared v1 B-tree struct for client.
+ *
+ * Return: Success: non-NULL pointer to struct allocated
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 27 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B_shared_t *
+H5B_shared_new(const H5F_t *f, const H5B_class_t *type, size_t sizeof_rkey)
+{
+ H5B_shared_t *shared = NULL; /* New shared B-tree struct */
+ size_t u; /* Local index variable */
+ H5B_shared_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(type);
+
+ /* Allocate space for the shared structure */
+ if(NULL == (shared = H5FL_CALLOC(H5B_shared_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for shared B-tree info")
+
+ /* Set up the "global" information for this file's groups */
+ shared->type = type;
+ shared->two_k = 2 * H5F_KVALUE(f, type);
+ shared->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ shared->sizeof_len = H5F_SIZEOF_SIZE(f);
+ shared->sizeof_rkey = sizeof_rkey;
+ HDassert(shared->sizeof_rkey);
+ shared->sizeof_keys = (shared->two_k + 1) * type->sizeof_nkey;
+ shared->sizeof_rnode = ((size_t)H5B_SIZEOF_HDR(f) + /*node header */
+ shared->two_k * H5F_SIZEOF_ADDR(f) + /*child pointers */
+ (shared->two_k + 1) * shared->sizeof_rkey); /*keys */
+ HDassert(shared->sizeof_rnode);
+
+ /* Allocate and clear shared buffers */
+ if(NULL == (shared->page = H5FL_BLK_MALLOC(page, shared->sizeof_rnode)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree page")
+ HDmemset(shared->page, 0, shared->sizeof_rnode);
+
+ if(NULL == (shared->nkey = H5FL_SEQ_MALLOC(size_t, (size_t)(shared->two_k + 1))))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree native keys")
+
+ /* Initialize the offsets into the native key buffer */
+ for(u = 0; u < (shared->two_k + 1); u++)
+ shared->nkey[u] = u * type->sizeof_nkey;
+
+ /* Set return value */
+ ret_value = shared;
+
+done:
+ if(NULL == ret_value)
+ if(shared) {
+ if(shared->page)
+ shared->page = H5FL_BLK_FREE(page, shared->page);
+ if(shared->nkey)
+ shared->nkey = H5FL_SEQ_FREE(size_t, shared->nkey);
+ shared = H5FL_FREE(H5B_shared_t, shared);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_shared_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_shared_free
+ *
+ * Purpose: Free B-tree shared info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 27, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_shared_free(void *_shared)
+{
+ H5B_shared_t *shared = (H5B_shared_t *)_shared;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Free the raw B-tree node buffer */
+ shared->page = H5FL_BLK_FREE(page, shared->page);
+
+ /* Free the B-tree native key offsets buffer */
+ shared->nkey = H5FL_SEQ_FREE(size_t, shared->nkey);
+
+ /* Free the shared B-tree info */
+ shared = H5FL_FREE(H5B_shared_t, shared);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B_shared_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__copy
+ *
+ * Purpose: Deep copies an existing H5B_t node.
+ *
+ * Return: Success: Pointer to H5B_t object.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 18 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_t *
+H5B__copy(const H5B_t *old_bt)
+{
+ H5B_t *new_node = NULL;
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(old_bt);
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(old_bt->rc_shared);
+ HDassert(shared);
+
+ /* Allocate memory for the new H5B_t object */
+ if(NULL == (new_node = H5FL_MALLOC(H5B_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree root node")
+
+ /* Copy the main structure */
+ HDmemcpy(new_node, old_bt, sizeof(H5B_t));
+
+ /* Reset cache info */
+ HDmemset(&new_node->cache_info, 0, sizeof(H5AC_info_t));
+
+ if(NULL == (new_node->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)) ||
+ NULL == (new_node->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree root node")
+
+ /* Copy the other structures */
+ HDmemcpy(new_node->native, old_bt->native, shared->sizeof_keys);
+ HDmemcpy(new_node->child, old_bt->child, (sizeof(haddr_t) * shared->two_k));
+
+ /* Increment the ref-count on the raw page */
+ H5UC_INC(new_node->rc_shared);
+
+ /* Set return value */
+ ret_value = new_node;
+
+done:
+ if(NULL == ret_value) {
+ if(new_node) {
+ new_node->native = H5FL_BLK_FREE(native_block, new_node->native);
+ new_node->child = H5FL_SEQ_FREE(haddr_t, new_node->child);
+ new_node = H5FL_FREE(H5B_t, new_node);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__get_info_helper
+ *
+ * Purpose: Walks the B-tree nodes, getting information for all of them.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 3 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ const H5B_info_ud_t *info_udata)
+{
+ H5B_t *bt = NULL; /* Pointer to current B-tree node */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned level; /* Node level */
+ size_t sizeof_rnode; /* Size of raw (disk) node */
+ haddr_t next_addr; /* Address of next node to the right */
+ haddr_t left_child; /* Address of left-most child in node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(info_udata);
+ HDassert(info_udata->bt_info);
+ HDassert(info_udata->udata);
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, info_udata->udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /* Get the raw node size for iteration */
+ sizeof_rnode = shared->sizeof_rnode;
+
+ /* Protect the initial/current node */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ /* Cache information from this node */
+ left_child = bt->child[0];
+ next_addr = bt->right;
+ level = bt->level;
+
+ /* Update B-tree info */
+ info_udata->bt_info->size += sizeof_rnode;
+ info_udata->bt_info->num_nodes++;
+
+ /* Release current node */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ bt = NULL;
+
+ /*
+ * Follow the right-sibling pointer from node to node until we've
+ * processed all nodes.
+ */
+ while(H5F_addr_defined(next_addr)) {
+ /* Protect the next node to the right */
+ addr = next_addr;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "B-tree node")
+
+ /* Cache information from this node */
+ next_addr = bt->right;
+
+ /* Update B-tree info */
+ info_udata->bt_info->size += sizeof_rnode;
+ info_udata->bt_info->num_nodes++;
+
+ /* Unprotect node */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ bt = NULL;
+ } /* end while */
+
+ /* Check for another "row" of B-tree nodes to iterate over */
+ if(level > 0) {
+ /* Keep following the left-most child until we reach a leaf node. */
+ if(H5B__get_info_helper(f, dxpl_id, type, left_child, info_udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to list B-tree node")
+ } /* end if */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__get_info_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_get_info
+ *
+ * Purpose: Return the amount of storage used for the btree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * June 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_get_info(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr,
+ H5B_info_t *bt_info, H5B_operator_t op, void *udata)
+{
+ H5B_info_ud_t info_udata; /* User-data for B-tree size iteration */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+ HDassert(bt_info);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+
+ /* Portably initialize B-tree info struct */
+ HDmemset(bt_info, 0, sizeof(*bt_info));
+
+ /* Set up internal user-data for the B-tree 'get info' helper routine */
+ info_udata.bt_info = bt_info;
+ info_udata.udata = udata;
+
+ /* Iterate over the B-tree nodes */
+ if(H5B__get_info_helper(f, dxpl_id, type, addr, &info_udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADITER, FAIL, "B-tree iteration failed")
+
+ /* Iterate over the B-tree records, making any "leaf" callbacks */
+ /* (Only if operator defined) */
+ if(op)
+ if((ret_value = H5B__iterate_helper(f, dxpl_id, type, addr, op, udata)) < 0)
+ HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_valid
+ *
+ * Purpose: Attempt to load a B-tree node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * March 17, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr)
+{
+ H5B_t *bt = NULL; /* The B-tree */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ htri_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(type);
+
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "address is undefined")
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, NULL)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Load the tree node.
+ */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node")
+
+done:
+ /* Release the node */
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__node_dest
+ *
+ * Purpose: Destroy/release a B-tree node
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 26, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B__node_dest(H5B_t *bt)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* check arguments */
+ HDassert(bt);
+ HDassert(bt->rc_shared);
+
+ bt->child = H5FL_SEQ_FREE(haddr_t, bt->child);
+ bt->native = H5FL_BLK_FREE(native_block, bt->native);
+ H5UC_DEC(bt->rc_shared);
+ bt = H5FL_FREE(H5B_t, bt);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B__node_dest() */
+
diff --git a/src/H5B2.c b/src/H5B2.c
new file mode 100644
index 0000000..7e679cd
--- /dev/null
+++ b/src/H5B2.c
@@ -0,0 +1,1632 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2.c
+ * Jan 31 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Implements a B-tree, with several modifications from
+ * the "standard" methods.
+ *
+ * Please see the documentation in:
+ * doc/html/TechNotes/Btrees.html for a full description
+ * of how they work, etc.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* v2 B-tree client ID to class mapping */
+
+/* Remember to add client ID to H5B2_subid_t in H5B2private.h when adding a new
+ * client class..
+ */
+extern const H5B2_class_t H5B2_TEST[1];
+extern const H5B2_class_t H5HF_HUGE_BT2_INDIR[1];
+extern const H5B2_class_t H5HF_HUGE_BT2_FILT_INDIR[1];
+extern const H5B2_class_t H5HF_HUGE_BT2_DIR[1];
+extern const H5B2_class_t H5HF_HUGE_BT2_FILT_DIR[1];
+extern const H5B2_class_t H5G_BT2_NAME[1];
+extern const H5B2_class_t H5G_BT2_CORDER[1];
+extern const H5B2_class_t H5SM_INDEX[1];
+extern const H5B2_class_t H5A_BT2_NAME[1];
+extern const H5B2_class_t H5A_BT2_CORDER[1];
+extern const H5B2_class_t H5D_BT2[1];
+extern const H5B2_class_t H5D_BT2_FILT[1];
+extern const H5B2_class_t H5B2_TEST2[1];
+
+const H5B2_class_t *const H5B2_client_class_g[] = {
+ H5B2_TEST, /* 0 - H5B2_TEST_ID */
+ H5HF_HUGE_BT2_INDIR, /* 1 - H5B2_FHEAP_HUGE_INDIR_ID */
+ H5HF_HUGE_BT2_FILT_INDIR, /* 2 - H5B2_FHEAP_HUGE_FILT_INDIR_ID */
+ H5HF_HUGE_BT2_DIR, /* 3 - H5B2_FHEAP_HUGE_DIR_ID */
+ H5HF_HUGE_BT2_FILT_DIR, /* 4 - H5B2_FHEAP_HUGE_FILT_DIR_ID */
+ H5G_BT2_NAME, /* 5 - H5B2_GRP_DENSE_NAME_ID */
+ H5G_BT2_CORDER, /* 6 - H5B2_GRP_DENSE_CORDER_ID */
+ H5SM_INDEX, /* 7 - H5B2_SOHM_INDEX_ID */
+ H5A_BT2_NAME, /* 8 - H5B2_ATTR_DENSE_NAME_ID */
+ H5A_BT2_CORDER, /* 9 - H5B2_ATTR_DENSE_CORDER_ID */
+ H5D_BT2, /* 10 - H5B2_CDSET_ID */
+ H5D_BT2_FILT, /* 11 - H5B2_CDSET_FILT_ID */
+ H5B2_TEST2 /* 12 - H5B2_TEST_ID */
+};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5B2_t struct */
+H5FL_DEFINE_STATIC(H5B2_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_create
+ *
+ * Purpose: Creates a new empty B-tree in the file.
+ *
+ * Return: Non-negative on success (with address of new B-tree
+ * filled in), negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 31 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_t *
+H5B2_create(H5F_t *f, hid_t dxpl_id, const H5B2_create_t *cparam, void *ctx_udata)
+{
+ H5B2_t *bt2 = NULL; /* Pointer to the B-tree */
+ H5B2_hdr_t *hdr = NULL; /* Pointer to the B-tree header */
+ haddr_t hdr_addr; /* B-tree header address */
+ H5B2_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+ /* H5B2 interface sanity check */
+ HDcompile_assert(H5B2_NUM_BTREE_ID == NELMTS(H5B2_client_class_g));
+
+ /* Create shared v2 B-tree header */
+ if(HADDR_UNDEF == (hdr_addr = H5B2__hdr_create(f, dxpl_id, cparam, ctx_udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't create v2 B-tree header")
+
+ /* Create v2 B-tree wrapper */
+ if(NULL == (bt2 = H5FL_MALLOC(H5B2_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for v2 B-tree info")
+
+ /* Look up the B-tree header */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, hdr_addr, ctx_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect v2 B-tree header")
+
+ /* Point v2 B-tree wrapper at header and bump it's ref count */
+ bt2->hdr = hdr;
+ if(H5B2__hdr_incr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment reference count on shared v2 B-tree header")
+
+ /* Increment # of files using this v2 B-tree header */
+ if(H5B2__hdr_fuse_incr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment file reference count on shared v2 B-tree header")
+
+ /* Set file pointer for this v2 B-tree open context */
+ bt2->f = f;
+
+ /* Set the return value */
+ ret_value = bt2;
+
+done:
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to release v2 B-tree header")
+ if(!ret_value && bt2)
+ if(H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCLOSEOBJ, NULL, "unable to close v2 B-tree")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_open
+ *
+ * Purpose: Opens an existing v2 B-tree in the file.
+ *
+ * Return: Pointer to v2 B-tree wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 15 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_t *
+H5B2_open(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *ctx_udata)
+{
+ H5B2_t *bt2 = NULL; /* Pointer to the B-tree */
+ H5B2_hdr_t *hdr = NULL; /* Pointer to the B-tree header */
+ H5B2_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Look up the B-tree header */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, addr, ctx_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect v2 B-tree header")
+
+ /* Check for pending heap deletion */
+ if(hdr->pending_delete)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTOPENOBJ, NULL, "can't open v2 B-tree pending deletion")
+
+ /* Create v2 B-tree info */
+ if(NULL == (bt2 = H5FL_MALLOC(H5B2_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for v2 B-tree info")
+
+ /* Point v2 B-tree wrapper at header */
+ bt2->hdr = hdr;
+ if(H5B2__hdr_incr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment reference count on shared v2 B-tree header")
+
+ /* Increment # of files using this v2 B-tree header */
+ if(H5B2__hdr_fuse_incr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment file reference count on shared v2 B-tree header")
+
+ /* Set file pointer for this v2 B-tree open context */
+ bt2->f = f;
+
+ /* Set the return value */
+ ret_value = bt2;
+
+done:
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to release v2 B-tree header")
+ if(!ret_value && bt2)
+ if(H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCLOSEOBJ, NULL, "unable to close v2 B-tree")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_insert
+ *
+ * Purpose: Adds a new record to the B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_insert(H5B2_t *bt2, hid_t dxpl_id, void *udata)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(udata);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Insert the record */
+ if(H5B2__insert(hdr, dxpl_id, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_update
+ *
+ * Purpose: Insert or modify a record to the B-tree.
+ * If the record exists already, it is modified as if H5B2_modify
+ * was called). If it doesn't exist, it is inserted as if
+ * H5B2_insert was called.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 23 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_update(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_modify_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ H5B2_update_status_t status = H5B2_UPDATE_UNKNOWN; /* Whether the record was inserted/modified */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(udata);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Check if the root node is allocated yet */
+ if(!H5F_addr_defined(hdr->root.addr)) {
+ /* Create root node as leaf node in B-tree */
+ if(H5B2__create_leaf(hdr, dxpl_id, hdr, &(hdr->root)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create root node")
+ } /* end if */
+
+ /* Attempt to insert record into B-tree */
+ if(hdr->depth > 0) {
+ if(H5B2__update_internal(hdr, dxpl_id, hdr->depth, NULL, &hdr->root, &status, H5B2_POS_ROOT, hdr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__update_leaf(hdr, dxpl_id, &hdr->root, &status, H5B2_POS_ROOT, hdr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in B-tree leaf node")
+ } /* end else */
+
+ /* Sanity check */
+ HDassert(H5B2_UPDATE_UNKNOWN != status);
+
+ /* Use insert algorithm if nodes to leaf full */
+ if(H5B2_UPDATE_INSERT_CHILD_FULL == status) {
+ if(H5B2__insert(hdr, dxpl_id, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree")
+ } /* end if */
+ else if(H5B2_UPDATE_SHADOW_DONE == status || H5B2_UPDATE_INSERT_DONE == status) {
+ /* Mark B-tree header as dirty */
+ if(H5B2__hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty")
+ } /* end else-if */
+ else {
+ /* Sanity check */
+ HDassert(H5B2_UPDATE_MODIFY_DONE == status);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_update() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_get_addr
+ *
+ * Purpose: Get the address of a v2 B-tree
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 5 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_get_addr(const H5B2_t *bt2, haddr_t *addr_p)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(bt2);
+ HDassert(addr_p);
+
+ /* Retrieve the header address for this v2 B-tree */
+ *addr_p = bt2->hdr->addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_iterate
+ *
+ * Purpose: Iterate over all the records in the B-tree, in "in-order"
+ * order, making a callback for each record.
+ *
+ * If the callback returns non-zero, the iteration breaks out
+ * without finishing all the records.
+ *
+ * Return: Value from callback: non-negative on success, negative on error
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 11 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_iterate(H5B2_t *bt2, hid_t dxpl_id, H5B2_operator_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(op);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Iterate through records */
+ if(hdr->root.node_nrec > 0) {
+ /* Iterate through nodes */
+ if((ret_value = H5B2__iterate_node(hdr, dxpl_id, hdr->depth, &hdr->root, hdr, op, op_data)) < 0)
+ HERROR(H5E_BTREE, H5E_CANTLIST, "node iteration failed");
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_find
+ *
+ * Purpose: Locate the specified information in a B-tree and return
+ * that information by calling the provided 'OP' routine with an
+ * OP_DATA pointer. The UDATA parameter points to data passed
+ * to the key comparison function.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to return information about
+ * the record.
+ *
+ * If 'OP' is NULL, then this routine just returns "TRUE" when
+ * a record is present in the B-tree.
+ *
+ * Return: Non-negative (TRUE/FALSE) on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5B2_find(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_found_t op,
+ void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ H5B2_node_ptr_t curr_node_ptr; /* Node pointer info for current node */
+ void *parent = NULL; /* Parent of current node */
+ uint16_t depth; /* Current depth of the tree */
+ int cmp; /* Comparison value of records */
+ unsigned idx; /* Location of record which matches key */
+ H5B2_nodepos_t curr_pos; /* Position of the current node */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Make copy of the root node pointer to start search with */
+ curr_node_ptr = hdr->root;
+
+ /* Check for empty tree */
+ if(curr_node_ptr.node_nrec == 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check record against min & max records in tree, to attempt to quickly
+ * find candidates or avoid further searching.
+ */
+ if(hdr->min_native_rec != NULL) {
+ if((hdr->cls->compare)(udata, hdr->min_native_rec, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp < 0)
+ HGOTO_DONE(FALSE) /* Less than the least record--not found */
+ else if(cmp == 0) { /* Record is found */
+ if(op && (op)(hdr->min_native_rec, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+ if(hdr->max_native_rec != NULL) {
+ if((hdr->cls->compare)(udata, hdr->max_native_rec, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp > 0)
+ HGOTO_DONE(FALSE) /* Less than the least record--not found */
+ else if(cmp == 0) { /* Record is found */
+ if(op && (op)(hdr->max_native_rec, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+
+ /* Current depth of the tree */
+ depth = hdr->depth;
+
+ /* Set initial parent, if doing swmr writes */
+ if(hdr->swmr_write)
+ parent = hdr;
+
+ /* Walk down B-tree to find record or leaf node where record is located */
+ cmp = -1;
+ curr_pos = H5B2_POS_ROOT;
+ while(depth > 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node in B-tree */
+ H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */
+
+ /* Lock B-tree current node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, &curr_node_ptr, depth, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0) {
+ /* Unlock current node before failing */
+ H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET);
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ } /* end if */
+
+ if(cmp > 0)
+ idx++;
+ if(cmp != 0) {
+ /* Get node pointer for next node to search */
+ next_node_ptr=internal->node_ptrs[idx];
+
+ /* Set the position of the next node */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ curr_pos = H5B2_POS_LEFT;
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ curr_pos = H5B2_POS_RIGHT;
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Keep track of parent if necessary */
+ if(hdr->swmr_write)
+ parent = internal;
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+ } /* end if */
+ else {
+ /* Make callback for current record */
+ if(op && (op)(H5B2_INT_NREC(internal, hdr, idx), op_data) < 0) {
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Indicate record found */
+ HGOTO_DONE(TRUE)
+ } /* end else */
+
+ /* Decrement depth we're at in B-tree */
+ depth--;
+ } /* end while */
+
+ {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
+
+ /* Lock B-tree leaf node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, &curr_node_ptr, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) {
+ /* Unlock current node before failing */
+ H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET);
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ } /* end if */
+
+ if(cmp != 0) {
+ /* Unlock leaf node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Record not found */
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else {
+ /* Make callback for current record */
+ if(op && (op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) {
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Check for record being the min or max for the tree */
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec == NULL)
+ if(NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree min record info")
+ HDmemcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec == NULL)
+ if(NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree max record info")
+ HDmemcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end block */
+
+done:
+ if(parent) {
+ HDassert(ret_value < 0);
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_index
+ *
+ * Purpose: Locate the IDX'th record in a B-tree according to the
+ * ordering used by the B-tree. The IDX values are 0-based.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to return information about
+ * the record.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_index(H5B2_t *bt2, hid_t dxpl_id, H5_iter_order_t order, hsize_t idx,
+ H5B2_found_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ H5B2_node_ptr_t curr_node_ptr; /* Node pointer info for current node */
+ void *parent = NULL; /* Parent of current node */
+ uint16_t depth; /* Current depth of the tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(op);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Make copy of the root node pointer to start search with */
+ curr_node_ptr = hdr->root;
+
+ /* Check for empty tree */
+ if(curr_node_ptr.node_nrec == 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
+
+ /* Check for index greater than the number of records in the tree */
+ if(idx >= curr_node_ptr.all_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records")
+
+ /* Current depth of the tree */
+ depth = hdr->depth;
+
+ /* Set initial parent, if doing swmr writes */
+ if(hdr->swmr_write)
+ parent = hdr;
+
+ /* Check for reverse indexing and map requested index to appropriate forward index */
+ if(order == H5_ITER_DEC)
+ idx = curr_node_ptr.all_nrec - (idx + 1);
+
+ /* Walk down B-tree to find record or leaf node where record is located */
+ while(depth > 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node in B-tree */
+ H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */
+ unsigned u; /* Local index variable */
+
+ /* Lock B-tree current node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, &curr_node_ptr, depth, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Search for record with correct index */
+ for(u = 0; u < internal->nrec; u++) {
+ /* Check if record is in child node */
+ if(internal->node_ptrs[u].all_nrec > idx) {
+ /* Get node pointer for next node to search */
+ next_node_ptr = internal->node_ptrs[u];
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Keep track of parent if necessary */
+ if(hdr->swmr_write)
+ parent = internal;
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+
+ /* Break out of for loop */
+ break;
+ } /* end if */
+
+ /* Check if record is in this node */
+ if(internal->node_ptrs[u].all_nrec == idx) {
+ /* Make callback for current record */
+ if((op)(H5B2_INT_NREC(internal, hdr, u), op_data) < 0) {
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /* Decrement index we are looking for to account for the node we
+ * just advanced past.
+ */
+ idx -= (internal->node_ptrs[u].all_nrec + 1);
+ } /* end for */
+
+ /* Check last node pointer */
+ if(u == internal->nrec) {
+ /* Check if record is in child node */
+ if(internal->node_ptrs[u].all_nrec > idx) {
+ /* Get node pointer for next node to search */
+ next_node_ptr = internal->node_ptrs[u];
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Keep track of parent if necessary */
+ if(hdr->swmr_write)
+ parent = internal;
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+ } /* end if */
+ else
+ /* Index that is greater than the number of records in the tree? */
+ HDassert(0 && "Index off end of tree??");
+ } /* end if */
+
+ /* Decrement depth we're at in B-tree */
+ depth--;
+ } /* end while */
+
+ {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
+
+ /* Lock B-tree leaf node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, &curr_node_ptr, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Sanity check index */
+ HDassert(idx < leaf->nrec);
+
+ /* Make callback for correct record */
+ if((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) {
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end block */
+
+done:
+ if(parent) {
+ HDassert(ret_value < 0);
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_remove
+ *
+ * Purpose: Removes a record from a B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 25 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_remove(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_remove_t op,
+ void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Check for empty B-tree */
+ if(0 == hdr->root.all_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree")
+
+ /* Attempt to remove record from B-tree */
+ if(hdr->depth > 0) {
+ hbool_t depth_decreased = FALSE; /* Flag to indicate whether the depth of the B-tree decreased */
+
+ if(H5B2__remove_internal(hdr, dxpl_id, &depth_decreased, NULL, NULL,
+ hdr->depth, &(hdr->cache_info), NULL, H5B2_POS_ROOT, &hdr->root,
+ udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
+
+ /* Check for decreasing the depth of the B-tree */
+ if(depth_decreased) {
+ /* Destroy free list factories for previous depth */
+ if(hdr->node_info[hdr->depth].nat_rec_fac)
+ if(H5FL_fac_term(hdr->node_info[hdr->depth].nat_rec_fac) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's native record block factory")
+ if(hdr->node_info[hdr->depth].node_ptr_fac)
+ if(H5FL_fac_term(hdr->node_info[hdr->depth].node_ptr_fac) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's node pointer block factory")
+
+ HDassert((uint16_t)(hdr->depth - depth_decreased) < hdr->depth);
+ hdr->depth = (uint16_t)(hdr->depth - depth_decreased);
+ } /* end for */
+ } /* end if */
+ else {
+ if(H5B2__remove_leaf(hdr, dxpl_id, &hdr->root, H5B2_POS_ROOT, hdr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
+ } /* end else */
+
+ /* Decrement # of records in B-tree */
+ hdr->root.all_nrec--;
+
+ /* Mark B-tree header as dirty */
+ if(H5B2__hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_remove_by_idx
+ *
+ * Purpose: Removes the n'th record from a B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_remove_by_idx(H5B2_t *bt2, hid_t dxpl_id, H5_iter_order_t order,
+ hsize_t idx, H5B2_remove_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Check for empty B-tree */
+ if(0 == hdr->root.all_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree")
+
+ /* Check for index greater than the number of records in the tree */
+ if(idx >= hdr->root.all_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree doesn't have that many records")
+
+ /* Check for reverse indexing and map requested index to appropriate forward index */
+ if(H5_ITER_DEC == order)
+ idx = hdr->root.all_nrec - (idx + 1);
+
+ /* Attempt to remove record from B-tree */
+ if(hdr->depth > 0) {
+ hbool_t depth_decreased = FALSE; /* Flag to indicate whether the depth of the B-tree decreased */
+
+ if(H5B2__remove_internal_by_idx(hdr, dxpl_id, &depth_decreased, NULL, NULL,
+ hdr->depth, &(hdr->cache_info), NULL, &hdr->root, H5B2_POS_ROOT,
+ idx, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
+
+ /* Check for decreasing the depth of the B-tree */
+ if(depth_decreased) {
+ /* Destroy free list factories for previous depth */
+ if(hdr->node_info[hdr->depth].nat_rec_fac)
+ if(H5FL_fac_term(hdr->node_info[hdr->depth].nat_rec_fac) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's native record block factory")
+ if(hdr->node_info[hdr->depth].node_ptr_fac)
+ if(H5FL_fac_term(hdr->node_info[hdr->depth].node_ptr_fac) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy node's node pointer block factory")
+
+ HDassert((uint16_t)(hdr->depth - depth_decreased) < hdr->depth);
+ hdr->depth = (uint16_t)(hdr->depth - depth_decreased);
+ } /* end for */
+ } /* end if */
+ else {
+ if(H5B2__remove_leaf_by_idx(hdr, dxpl_id, &hdr->root, H5B2_POS_ROOT, hdr, (unsigned)idx, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
+ } /* end else */
+
+ /* Decrement # of records in B-tree */
+ hdr->root.all_nrec--;
+
+ /* Mark B-tree header as dirty */
+ if(H5B2__hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_get_nrec
+ *
+ * Purpose: Retrieves the number of records in a B-tree
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 25 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_get_nrec(const H5B2_t *bt2, hsize_t *nrec)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(nrec);
+
+ /* Get B-tree number of records */
+ *nrec = bt2->hdr->root.all_nrec;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2_get_nrec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_neighbor
+ *
+ * Purpose: Locate a record relative to the specified information in a
+ * B-tree and return that information by filling in fields of the
+ * caller-supplied UDATA pointer depending on the type of leaf node
+ * requested. The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to return information about
+ * the record.
+ *
+ * The RANGE indicates whether to search for records less than or
+ * equal to, or greater than or equal to the information passed
+ * in with UDATA.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 8 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_neighbor(H5B2_t *bt2, hid_t dxpl_id, H5B2_compare_t range, void *udata,
+ H5B2_found_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(op);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Check for empty tree */
+ if(!H5F_addr_defined(hdr->root.addr))
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
+
+ /* Attempt to find neighbor record in B-tree */
+ if(hdr->depth > 0) {
+ if(H5B2__neighbor_internal(hdr, dxpl_id, hdr->depth, &hdr->root, NULL, range, hdr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__neighbor_leaf(hdr, dxpl_id, &hdr->root, NULL, range, hdr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree leaf node")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_neighbor() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_modify
+ *
+ * Purpose: Locate the specified information in a B-tree and modify it.
+ * The UDATA points to additional data passed
+ * to the key comparison function for locating the record to
+ * modify.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to modify information about
+ * the record.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 10 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_modify(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_modify_t op,
+ void *op_data)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ H5B2_node_ptr_t curr_node_ptr; /* Node pointer info for current node */
+ void *parent = NULL; /* Parent of current node */
+ H5B2_nodepos_t curr_pos; /* Position of current node */
+ uint16_t depth; /* Current depth of the tree */
+ int cmp; /* Comparison value of records */
+ unsigned idx; /* Location of record which matches key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(op);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Make copy of the root node pointer to start search with */
+ curr_node_ptr = hdr->root;
+
+ /* Check for empty tree */
+ if(0 == curr_node_ptr.node_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
+
+ /* Current depth of the tree */
+ depth = hdr->depth;
+
+ /* Set initial parent, if doing swmr writes */
+ if(hdr->swmr_write)
+ parent = hdr;
+
+ /* Walk down B-tree to find record or leaf node where record is located */
+ cmp = -1;
+ curr_pos = H5B2_POS_ROOT;
+ while(depth > 0) {
+ unsigned internal_flags = H5AC__NO_FLAGS_SET;
+ H5B2_internal_t *internal; /* Pointer to internal node in B-tree */
+ H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */
+
+ /* Lock B-tree current node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, &curr_node_ptr, depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0) {
+ /* Unlock current node before failing */
+ H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET);
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ } /* end if */
+
+ if(cmp > 0)
+ idx++;
+
+ if(cmp != 0) {
+ /* Get node pointer for next node to search */
+ next_node_ptr = internal->node_ptrs[idx];
+
+ /* Set the position of the next node */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ curr_pos = H5B2_POS_LEFT;
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ curr_pos = H5B2_POS_RIGHT;
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+ else
+ curr_pos = H5B2_POS_MIDDLE;
+ } /* end if */
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Keep track of parent if necessary */
+ if(hdr->swmr_write)
+ parent = internal;
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+ } /* end if */
+ else {
+ hbool_t changed; /* Whether the 'modify' callback changed the record */
+
+ /* Make callback for current record */
+ if((op)(H5B2_INT_NREC(internal, hdr, idx), op_data, &changed) < 0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed == FALSE);
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL, "'modify' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Mark the node as dirty if it changed */
+ internal_flags |= changed ? H5AC__DIRTIED_FLAG : 0;
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, internal_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_DONE(SUCCEED);
+ } /* end else */
+
+ /* Decrement depth we're at in B-tree */
+ depth--;
+ } /* end while */
+
+ {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
+ unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
+ hbool_t changed = FALSE;/* Whether the 'modify' callback changed the record */
+
+ /* Lock B-tree leaf node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, &curr_node_ptr, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) {
+ /* Unlock current node before failing */
+ H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET);
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ } /* end if */
+
+ if(cmp != 0) {
+ /* Unlock leaf node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Note: don't push error on stack, leave that to next higher level,
+ * since many times the B-tree is searched in order to determine
+ * if an object exists in the B-tree or not. -QAK
+ */
+#ifdef OLD_WAY
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "key not found in leaf node")
+#else /* OLD_WAY */
+ HGOTO_DONE(FAIL)
+#endif /* OLD_WAY */
+ } /* end if */
+ else {
+ /* Make callback for current record */
+ if((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data, &changed) < 0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed == FALSE);
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL, "'modify' callback failed for B-tree find operation")
+ } /* end if */
+
+ /* Check for modified record being the min or max for the tree */
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec == NULL)
+ if(NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree min record info")
+ HDmemcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec == NULL)
+ if(NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree max record info")
+ HDmemcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Mark the node as dirty if it changed */
+ leaf_flags |= (changed ? H5AC__DIRTIED_FLAG : 0);
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, leaf_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ } /* end block */
+
+done:
+ if(parent) {
+ HDassert(ret_value < 0);
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_modify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_close
+ *
+ * Purpose: Close a v2 B-tree
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 15 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_close(H5B2_t *bt2, hid_t dxpl_id)
+{
+ haddr_t bt2_addr = HADDR_UNDEF; /* Address of v2 B-tree (for deletion) */
+ hbool_t pending_delete = FALSE; /* Whether the v2 B-tree is pending deletion */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(bt2->f);
+
+ /* Decrement file reference & check if this is the last open v2 B-tree using the shared B-tree header */
+ if(0 == H5B2__hdr_fuse_decr(bt2->hdr)) {
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Check for pending B-tree deletion */
+ if(bt2->hdr->pending_delete) {
+ /* Set local info, so B-tree deletion can occur after decrementing the
+ * header's ref count
+ */
+ pending_delete = TRUE;
+ bt2_addr = bt2->hdr->addr;
+ } /* end if */
+ } /* end if */
+
+ /* Check for pending v2 B-tree deletion */
+ if(pending_delete) {
+ H5B2_hdr_t *hdr; /* Another pointer to v2 B-tree header */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(bt2_addr));
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Header's status in the metadata cache */
+
+ /* Check the header's status in the metadata cache */
+ if(H5AC_get_entry_status(bt2->f, bt2_addr, &hdr_status) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "unable to check metadata cache status for v2 B-tree header, address = %llu", (unsigned long long)bt2_addr)
+
+ /* Sanity checks on header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PINNED);
+ HDassert(!(hdr_status & H5AC_ES__IS_PROTECTED));
+}
+#endif /* NDEBUG */
+
+ /* Lock the v2 B-tree header into memory */
+ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */
+ if(NULL == (hdr = H5B2__hdr_protect(bt2->f, dxpl_id, bt2_addr, NULL, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header")
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ hdr->f = bt2->f;
+
+ /* Decrement the reference count on the B-tree header */
+ /* (don't put in H5B2__hdr_fuse_decr() as the B-tree header may be evicted
+ * immediately -QAK)
+ */
+ if(H5B2__hdr_decr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement reference count on shared v2 B-tree header")
+
+ /* Delete v2 B-tree, starting with header (unprotects header) */
+ if(H5B2__hdr_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree")
+ } /* end if */
+ else {
+ /* Decrement the reference count on the B-tree header */
+ /* (don't put in H5B2__hdr_fuse_decr() as the B-tree header may be evicted
+ * immediately -QAK)
+ */
+ if(H5B2__hdr_decr(bt2->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement reference count on shared v2 B-tree header")
+
+ } /* end else */
+
+ /* Release the v2 B-tree wrapper */
+ bt2 = H5FL_FREE(H5B2_t, bt2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_delete
+ *
+ * Purpose: Delete an entire B-tree from a file.
+ *
+ * The 'OP' routine is called for each record and the
+ * OP_DATA pointer, to allow caller to perform an operation as
+ * each record is removed from the B-tree.
+ *
+ * If 'OP' is NULL, the records are just removed in the process
+ * of deleting the B-tree.
+ *
+ * Note: The records are _not_ guaranteed to be visited in order.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *ctx_udata,
+ H5B2_remove_t op, void *op_data)
+{
+ H5B2_hdr_t *hdr = NULL; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Lock the v2 B-tree header into memory */
+#ifdef QAK
+HDfprintf(stderr, "%s: addr = %a\n", FUNC, addr);
+#endif /* QAK */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, addr, ctx_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header")
+
+ /* Remember the callback & context for later */
+ hdr->remove_op = op;
+ hdr->remove_op_data = op_data;
+
+ /* Check for files using shared v2 B-tree header */
+ if(hdr->file_rc)
+ hdr->pending_delete = TRUE;
+ else {
+ /* Set the shared v2 B-tree header's file context for this operation */
+ hdr->f = f;
+
+ /* Delete v2 B-tree now, starting with header (unprotects header) */
+ if(H5B2__hdr_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree")
+ hdr = NULL;
+ } /* end if */
+
+done:
+ /* Unprotect the header, if an error occurred */
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release v2 B-tree header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_depend
+ *
+ * Purpose: Make a child flush dependency between the v2 B-tree's
+ * header and another piece of metadata in the file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_depend(H5B2_t *bt2, hid_t dxpl_id, H5AC_proxy_entry_t *parent)
+{
+ /* Local variables */
+ H5B2_hdr_t *hdr = bt2->hdr; /* Header for B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(SUCCEED)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(bt2);
+ HDassert(hdr);
+ HDassert(parent);
+ HDassert(hdr->parent == NULL || hdr->parent == parent);
+
+ /*
+ * Check to see if the flush dependency between the parent
+ * and the v2 B-tree header has already been setup. If it hasn't, then
+ * set it up.
+ */
+ if(NULL == hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ hdr->f = bt2->f;
+
+ /* Add the v2 B-tree as a child of the parent (proxy) */
+ if(H5AC_proxy_entry_add_child(parent, hdr->f, dxpl_id, hdr->top_proxy) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree as child of proxy")
+ hdr->parent = parent;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_patch_file
+ *
+ * Purpose: Patch the top-level file pointer contained in bt2
+ * to point to idx_info->f if they are different.
+ * This is possible because the file pointer in bt2 can be
+ * closed out if bt2 remains open.
+ *
+ * Return: SUCCEED
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_patch_file(H5B2_t *bt2, H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(bt2);
+ HDassert(f);
+
+ if(bt2->f != f || bt2->hdr->f != f)
+ bt2->f = bt2->hdr->f = f;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2_patch_file() */
+
diff --git a/src/H5B2cache.c b/src/H5B2cache.c
new file mode 100644
index 0000000..2e1d37b
--- /dev/null
+++ b/src/H5B2cache.c
@@ -0,0 +1,1362 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2cache.c
+ * Jan 31 2005
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement v2 B-tree metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* B-tree format version #'s */
+#define H5B2_HDR_VERSION 0 /* Header */
+#define H5B2_INT_VERSION 0 /* Internal node */
+#define H5B2_LEAF_VERSION 0 /* Leaf node */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+static herr_t H5B2__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_hdr_free_icr(void *thing);
+
+static herr_t H5B2__cache_int_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_int_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_int_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_int_free_icr(void *thing);
+
+static herr_t H5B2__cache_leaf_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_leaf_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_leaf_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_leaf_free_icr(void *thing);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_HDR[1] = {{
+ H5AC_BT2_HDR_ID, /* Metadata client ID */
+ "v2 B-tree header", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5B2__cache_hdr_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_hdr_serialize, /* 'serialize' callback */
+ H5B2__cache_hdr_notify, /* 'notify' callback */
+ H5B2__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_INT[1] = {{
+ H5AC_BT2_INT_ID, /* Metadata client ID */
+ "v2 B-tree internal node", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_int_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_int_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_int_deserialize, /* 'deserialize' callback */
+ H5B2__cache_int_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_int_serialize, /* 'serialize' callback */
+ H5B2__cache_int_notify, /* 'notify' callback */
+ H5B2__cache_int_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_LEAF[1] = {{
+ H5AC_BT2_LEAF_ID, /* Metadata client ID */
+ "v2 B-tree leaf node", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_leaf_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_leaf_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_leaf_deserialize, /* 'deserialize' callback */
+ H5B2__cache_leaf_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_leaf_serialize, /* 'serialize' callback */
+ H5B2__cache_leaf_notify, /* 'notify' callback */
+ H5B2__cache_leaf_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = H5B2_HEADER_SIZE_FILE(udata->f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_deserialize
+ *
+ * Purpose: Loads a B-tree header from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 1 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_hdr_t *hdr = NULL; /* B-tree header */
+ H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata;
+ H5B2_create_t cparam; /* B-tree creation parameters */
+ H5B2_subid_t id; /* ID of B-tree class, as found in file */
+ uint16_t depth; /* Depth of B-tree */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new B-tree header and reset cache info */
+ if(NULL == (hdr = H5B2__hdr_alloc(udata->f)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "allocation failed for B-tree header")
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_HDR_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree header version")
+
+ /* B-tree class */
+ id = (H5B2_subid_t)*image++;
+ if(id >= H5B2_NUM_BTREE_ID)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Node size (in bytes) */
+ UINT32DECODE(image, cparam.node_size);
+
+ /* Raw key size (in bytes) */
+ UINT16DECODE(image, cparam.rrec_size);
+
+ /* Depth of tree */
+ UINT16DECODE(image, depth);
+
+ /* Split & merge %s */
+ cparam.split_percent = *image++;
+ cparam.merge_percent = *image++;
+
+ /* Root node pointer */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(hdr->root.addr));
+ UINT16DECODE(image, hdr->root.node_nrec);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size);
+
+ /* Initialize B-tree header info */
+ cparam.cls = H5B2_client_class_g[id];
+ if(H5B2__hdr_init(hdr, &cparam, udata->ctx_udata, depth) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't initialize B-tree header info")
+
+ /* Set the B-tree header's address */
+ hdr->addr = udata->addr;
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = hdr;
+
+done:
+ if(!ret_value && hdr)
+ if(H5B2__hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, NULL, "can't release v2 B-tree header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_hdr_t *hdr = (const H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = hdr->hdr_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_serialize
+ *
+ * Purpose: Flushes a dirty B-tree header to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 1 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5B2_HDR_VERSION;
+
+ /* B-tree type */
+ *image++ = hdr->cls->id;
+
+ /* Node size (in bytes) */
+ UINT32ENCODE(image, hdr->node_size);
+
+ /* Raw key size (in bytes) */
+ UINT16ENCODE(image, hdr->rrec_size);
+
+ /* Depth of tree */
+ UINT16ENCODE(image, hdr->depth);
+
+ /* Split & merge %s */
+ H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t);
+ *image++ = (uint8_t)hdr->split_percent;
+ H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t);
+ *image++ = (uint8_t)hdr->merge_percent;
+
+ /* Root node pointer */
+ H5F_addr_encode(f, &image, hdr->root.addr);
+ UINT16ENCODE(image, hdr->root.node_nrec);
+ H5F_ENCODE_LENGTH(f, image, hdr->root.all_nrec);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 24 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* Increment the shadow epoch, forcing new modifications to
+ * internal and leaf nodes to create new shadow copies */
+ hdr->shadow_epoch++;
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* If hdr->parent != NULL, hdr->parent is used to destroy
+ * the flush dependency before the header is evicted.
+ */
+ if(hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Destroy flush dependency on object header proxy */
+ if(H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent, (void *)hdr->top_proxy) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between v2 B-tree and proxy")
+ hdr->parent = NULL;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between header and v2 B-tree 'top' proxy")
+ /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == hdr->parent);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_free_icr(void *thing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Destroy v2 B-tree header */
+ if(H5B2__hdr_free((H5B2_hdr_t *)thing) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_int_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ size_t chk_size; /* Exact size of the node with checksum at the end */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */
+ chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth));
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_int_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_deserialize
+ *
+ * Purpose: Deserialize a B-tree internal node from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree internal node.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ H5B2_internal_t *internal = NULL; /* Internal node read */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native record info */
+ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned u; /* Local index variable */
+ H5B2_internal_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new internal node and reset cache info */
+ if(NULL == (internal = H5FL_CALLOC(H5B2_internal_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(udata->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree information */
+ internal->hdr = udata->hdr;
+ internal->parent = udata->parent;
+ internal->shadow_epoch = udata->hdr->shadow_epoch;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_INT_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node version")
+
+ /* B-tree type */
+ if(*image++ != (uint8_t)udata->hdr->cls->id)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (internal->int_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].nat_rec_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for B-tree internal native keys")
+
+ /* Allocate space for the node pointers in memory */
+ if(NULL == (internal->node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].node_ptr_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for B-tree internal node pointers")
+
+ /* Set the number of records in the leaf & it's depth */
+ internal->nrec = udata->nrec;
+ internal->depth = udata->depth;
+
+ /* Deserialize records for internal node */
+ native = internal->int_native;
+ for(u = 0; u < internal->nrec; u++) {
+ /* Decode record */
+ if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode B-tree record")
+
+ /* Move to next record */
+ image += udata->hdr->rrec_size;
+ native += udata->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Deserialize node pointers for internal node */
+ int_node_ptr = internal->node_ptrs;
+ for(u = 0; u < (unsigned)(internal->nrec + 1); u++) {
+ /* Decode node pointer */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(int_node_ptr->addr));
+ UINT64DECODE_VAR(image, int_node_ptr->node_nrec, udata->hdr->max_nrec_size);
+ if(udata->depth > 1)
+ UINT64DECODE_VAR(image, int_node_ptr->all_nrec, udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size)
+ else
+ int_node_ptr->all_nrec = int_node_ptr->node_nrec;
+
+ /* Move to next node pointer */
+ int_node_ptr++;
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check parsing */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = internal;
+
+done:
+ if(!ret_value && internal)
+ if(H5B2__internal_free(internal) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree internal node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_internal_t *internal = (const H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(internal);
+ HDassert(internal->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = internal->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_int_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_serialize
+ *
+ * Purpose: Serializes a B-tree internal node for writing to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native record info */
+ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(internal);
+ HDassert(internal->hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5B2_INT_VERSION;
+
+ /* B-tree type */
+ *image++ = internal->hdr->cls->id;
+ HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
+
+ /* Serialize records for internal node */
+ native = internal->int_native;
+ for(u = 0; u < internal->nrec; u++) {
+ /* Encode record */
+ if((internal->hdr->cls->encode)(image, native, internal->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record")
+
+ /* Move to next record */
+ image += internal->hdr->rrec_size;
+ native += internal->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Serialize node pointers for internal node */
+ int_node_ptr = internal->node_ptrs;
+ for(u = 0; u < (unsigned)(internal->nrec + 1); u++) {
+ /* Encode node pointer */
+ H5F_addr_encode(f, &image, int_node_ptr->addr);
+ UINT64ENCODE_VAR(image, int_node_ptr->node_nrec, internal->hdr->max_nrec_size);
+ if(internal->depth > 1)
+ UINT64ENCODE_VAR(image, int_node_ptr->all_nrec, internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size);
+
+ /* Move to next node pointer */
+ int_node_ptr++;
+ } /* end for */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of internal node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 25 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(internal);
+ HDassert(internal->hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(internal->hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5B2__create_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5B2__destroy_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* Detach from 'top' proxy for v2 B-tree */
+ if(internal->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(internal->top_proxy, internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between internal node and v2 B-tree 'top' proxy")
+ internal->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == internal->top_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_int_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_free_icr(void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(internal);
+
+ /* Release v2 B-tree internal node */
+ if(H5B2__internal_free(internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_leaf_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ size_t chk_size; /* Exact size of the node with checksum at the end */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Leaf node prefix header + records: size with checksum at the end */
+ chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_leaf_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_deserialize
+ *
+ * Purpose: Deserialize a B-tree leaf from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree leaf node.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata;
+ H5B2_leaf_t *leaf = NULL; /* Pointer to lead node loaded */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native keys */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned u; /* Local index variable */
+ H5B2_leaf_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new leaf node and reset cache info */
+ if(NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(udata->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree header information */
+ leaf->hdr = udata->hdr;
+ leaf->parent = udata->parent;
+ leaf->shadow_epoch = udata->hdr->shadow_epoch;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree leaf node signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_LEAF_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree leaf node version")
+
+ /* B-tree type */
+ if(*image++ != (uint8_t)udata->hdr->cls->id)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[0].nat_rec_fac)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree leaf native keys")
+
+ /* Set the number of records in the leaf */
+ leaf->nrec = udata->nrec;
+
+ /* Deserialize records for leaf node */
+ native = leaf->leaf_native;
+ for(u = 0; u < leaf->nrec; u++) {
+ /* Decode record */
+ if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, NULL, "unable to decode B-tree record")
+
+ /* Move to next record */
+ image += udata->hdr->rrec_size;
+ native += udata->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check parsing */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = leaf;
+
+done:
+ if(!ret_value && leaf)
+ if(H5B2__leaf_free(leaf) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree leaf node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_leaf_t *leaf = (const H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = leaf->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_leaf_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_serialize
+ *
+ * Purpose: Serializes a B-tree leaf node for writing to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_serialize(const H5F_t H5_ATTR_UNUSED *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native keys */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+
+ /* magic number */
+ HDmemcpy(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* version # */
+ *image++ = H5B2_LEAF_VERSION;
+
+ /* B-tree type */
+ *image++ = leaf->hdr->cls->id;
+ HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
+
+ /* Serialize records for leaf node */
+ native = leaf->leaf_native;
+ for(u = 0; u < leaf->nrec; u++) {
+ /* Encode record */
+ if((leaf->hdr->cls->encode)(image, native, leaf->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record")
+
+ /* Move to next record */
+ image += leaf->hdr->rrec_size;
+ native += leaf->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)((const uint8_t *)image - (const uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of leaf node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 25 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(leaf->hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5B2__create_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5B2__destroy_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* Detach from 'top' proxy for v2 B-tree */
+ if(leaf->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy")
+ leaf->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == leaf->top_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_leaf_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_free_icr(void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(leaf);
+
+ /* Destroy v2 B-tree leaf node */
+ if(H5B2__leaf_free(leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_free_icr() */
+
diff --git a/src/H5B2dbg.c b/src/H5B2dbg.c
new file mode 100644
index 0000000..3890ae0
--- /dev/null
+++ b/src/H5B2dbg.c
@@ -0,0 +1,376 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2dbg.c
+ * Feb 2 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Dump debugging information about a v2 B-tree.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_debug
+ *
+ * Purpose: Prints debugging info about a B-tree header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth,
+ const H5B2_class_t *type, haddr_t obj_addr)
+{
+ H5B2_hdr_t *hdr = NULL; /* B-tree header info */
+ unsigned u; /* Local index variable */
+ char temp_str[128]; /* Temporary string, for formatting */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(type);
+
+ /* Load the B-tree header */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree header")
+
+ /* Set file pointer for this B-tree operation */
+ hdr->f = f;
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sv2 B-tree Header...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Tree type ID:", hdr->cls->name, (unsigned)hdr->cls->id);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of node:",
+ (unsigned)hdr->node_size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of raw (disk) record:",
+ (unsigned)hdr->rrec_size);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Dirty flag:",
+ hdr->cache_info.is_dirty ? "True" : "False");
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Depth:",
+ hdr->depth);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of records in tree:",
+ hdr->root.all_nrec);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of records in root node:",
+ hdr->root.node_nrec);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of root node:",
+ hdr->root.addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Split percent:",
+ hdr->split_percent);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Merge percent:",
+ hdr->merge_percent);
+
+ /* Print relevant node info */
+ HDfprintf(stream, "%*sNode Info: (max_nrec/split_nrec/merge_nrec)\n", indent, "");
+ for(u = 0; u < (unsigned)(hdr->depth + 1); u++) {
+ HDsnprintf(temp_str, sizeof(temp_str), "Depth %u:", u);
+ HDfprintf(stream, "%*s%-*s (%u/%u/%u)\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str,
+ hdr->node_info[u].max_nrec, hdr->node_info[u].split_nrec, hdr->node_info[u].merge_nrec);
+ } /* end for */
+
+done:
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release v2 B-tree header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__int_debug
+ *
+ * Purpose: Prints debugging info about a B-tree internal node
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 4 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__int_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth,
+ const H5B2_class_t *type, haddr_t hdr_addr, unsigned nrec, unsigned depth, haddr_t obj_addr)
+{
+ H5B2_hdr_t *hdr = NULL; /* B-tree header */
+ H5B2_internal_t *internal = NULL; /* B-tree internal node */
+ H5B2_node_ptr_t node_ptr; /* Fake node pointer for protect */
+ unsigned u; /* Local index variable */
+ char temp_str[128]; /* Temporary string, for formatting */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(type);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(nrec > 0);
+
+ /* Load the B-tree header */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, hdr_addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load v2 B-tree header")
+
+ /* Set file pointer for this B-tree operation */
+ hdr->f = f;
+
+ /*
+ * Load the B-tree internal node
+ */
+ H5_CHECK_OVERFLOW(depth, unsigned, uint16_t);
+ node_ptr.addr = addr;
+ H5_CHECKED_ASSIGN(node_ptr.node_nrec, unsigned, nrec, uint16_t)
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, NULL, &node_ptr, (uint16_t)depth, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree internal node")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sv2 B-tree Internal Node...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Tree type ID:", hdr->cls->name, (unsigned)hdr->cls->id);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of node:",
+ (unsigned)hdr->node_size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of raw (disk) record:",
+ (unsigned)hdr->rrec_size);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Dirty flag:",
+ internal->cache_info.is_dirty ? "True" : "False");
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of records in node:",
+ internal->nrec);
+
+ /* Print all node pointers and records */
+ for(u = 0; u < internal->nrec; u++) {
+ /* Print node pointer */
+ HDsnprintf(temp_str, sizeof(temp_str), "Node pointer #%u: (all/node/addr)", u);
+ HDfprintf(stream, "%*s%-*s (%Hu/%u/%a)\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str,
+ internal->node_ptrs[u].all_nrec,
+ internal->node_ptrs[u].node_nrec,
+ internal->node_ptrs[u].addr);
+
+ /* Print record */
+ HDsnprintf(temp_str, sizeof(temp_str), "Record #%u:", u);
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str);
+ HDassert(H5B2_INT_NREC(internal, hdr, u));
+ (void)(type->debug)(stream, indent + 6, MAX (0, fwidth-6), H5B2_INT_NREC(internal, hdr, u), hdr->cb_ctx);
+ } /* end for */
+
+ /* Print final node pointer */
+ HDsnprintf(temp_str, sizeof(temp_str), "Node pointer #%u: (all/node/addr)", u);
+ HDfprintf(stream, "%*s%-*s (%Hu/%u/%a)\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str,
+ internal->node_ptrs[u].all_nrec,
+ internal->node_ptrs[u].node_nrec,
+ internal->node_ptrs[u].addr);
+
+done:
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release v2 B-tree header")
+ if(internal && H5AC_unprotect(f, dxpl_id, H5AC_BT2_INT, addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree internal node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__int_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__leaf_debug
+ *
+ * Purpose: Prints debugging info about a B-tree leaf node
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 7 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__leaf_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth,
+ const H5B2_class_t *type, haddr_t hdr_addr, unsigned nrec, haddr_t obj_addr)
+{
+ H5B2_hdr_t *hdr = NULL; /* B-tree header */
+ H5B2_leaf_t *leaf = NULL; /* B-tree leaf node */
+ H5B2_node_ptr_t node_ptr; /* Fake node pointer for protect */
+ unsigned u; /* Local index variable */
+ char temp_str[128]; /* Temporary string, for formatting */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(type);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(nrec > 0);
+
+ /* Load the B-tree header */
+ if(NULL == (hdr = H5B2__hdr_protect(f, dxpl_id, hdr_addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header")
+
+ /* Set file pointer for this B-tree operation */
+ hdr->f = f;
+
+ /*
+ * Load the B-tree leaf node
+ */
+ H5_CHECK_OVERFLOW(nrec, unsigned, uint16_t);
+ node_ptr.addr = addr;
+ H5_CHECKED_ASSIGN(node_ptr.node_nrec, unsigned, nrec, uint16_t)
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, NULL, &node_ptr, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sv2 B-tree Leaf Node...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Tree type ID:", hdr->cls->name, (unsigned)hdr->cls->id);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of node:",
+ (unsigned)hdr->node_size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of raw (disk) record:",
+ (unsigned)hdr->rrec_size);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Dirty flag:",
+ leaf->cache_info.is_dirty ? "True" : "False");
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of records in node:",
+ leaf->nrec);
+
+ /* Print all node pointers and records */
+ for(u = 0; u < leaf->nrec; u++) {
+ /* Print record */
+ HDsnprintf(temp_str, sizeof(temp_str), "Record #%u:", u);
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str);
+ HDassert(H5B2_LEAF_NREC(leaf, hdr, u));
+ (void)(type->debug)(stream, indent + 6, MAX (0, fwidth-6), H5B2_LEAF_NREC(leaf, hdr, u), hdr->cb_ctx);
+ } /* end for */
+
+done:
+ if(hdr && H5B2__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree header")
+ if(leaf && H5AC_unprotect(f, dxpl_id, H5AC_BT2_LEAF, addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, "unable to release B-tree leaf node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__leaf_debug() */
+
diff --git a/src/H5B2hdr.c b/src/H5B2hdr.c
new file mode 100644
index 0000000..ab017c6
--- /dev/null
+++ b/src/H5B2hdr.c
@@ -0,0 +1,741 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2int.c
+ * Feb 27 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Internal routines for managing v2 B-trees.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Number of records that fit into leaf node */
+#define H5B2_NUM_LEAF_REC(n, r) \
+ (((n) - H5B2_LEAF_PREFIX_SIZE) / (r))
+
+/* Uncomment this macro to enable extra sanity checking */
+/* #define H5B2_DEBUG */
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5B2_hdr_t struct */
+H5FL_DEFINE_STATIC(H5B2_hdr_t);
+
+/* Declare a free list to manage B-tree node pages to/from disk */
+H5FL_BLK_DEFINE_STATIC(node_page);
+
+/* Declare a free list to manage the 'size_t' sequence information */
+H5FL_SEQ_DEFINE_STATIC(size_t);
+
+/* Declare a free list to manage the 'H5B2_node_info_t' sequence information */
+H5FL_SEQ_DEFINE(H5B2_node_info_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_init
+ *
+ * Purpose: Allocate & initialize B-tree header info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_init(H5B2_hdr_t *hdr, const H5B2_create_t *cparam, void *ctx_udata,
+ uint16_t depth)
+{
+ size_t sz_max_nrec; /* Temporary variable for range checking */
+ unsigned u_max_nrec_size; /* Temporary variable for range checking */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(cparam);
+ HDassert(cparam->cls);
+ HDassert((cparam->cls->crt_context && cparam->cls->dst_context) ||
+ (NULL == cparam->cls->crt_context && NULL == cparam->cls->dst_context));
+ HDassert(cparam->node_size > 0);
+ HDassert(cparam->rrec_size > 0);
+ HDassert(cparam->merge_percent > 0 && cparam->merge_percent <= 100);
+ HDassert(cparam->split_percent > 0 && cparam->split_percent <= 100);
+ HDassert(cparam->merge_percent < (cparam->split_percent / 2));
+
+ /* Assign dynamic information */
+ hdr->depth = depth;
+
+ /* Assign user's information */
+ hdr->split_percent = cparam->split_percent;
+ hdr->merge_percent = cparam->merge_percent;
+ hdr->node_size = cparam->node_size;
+ hdr->rrec_size = cparam->rrec_size;
+
+ /* Assign common type information */
+ hdr->cls = cparam->cls;
+
+ /* Allocate "page" for node I/O */
+ if(NULL == (hdr->page = H5FL_BLK_MALLOC(node_page, hdr->node_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDmemset(hdr->page, 0, hdr->node_size);
+
+ /* Allocate array of node info structs */
+ if(NULL == (hdr->node_info = H5FL_SEQ_MALLOC(H5B2_node_info_t, (size_t)(hdr->depth + 1))))
+ HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize leaf node info */
+ sz_max_nrec = H5B2_NUM_LEAF_REC(hdr->node_size, hdr->rrec_size);
+ H5_CHECKED_ASSIGN(hdr->node_info[0].max_nrec, unsigned, sz_max_nrec, size_t)
+ hdr->node_info[0].split_nrec = (hdr->node_info[0].max_nrec * hdr->split_percent) / 100;
+ hdr->node_info[0].merge_nrec = (hdr->node_info[0].max_nrec * hdr->merge_percent) / 100;
+ hdr->node_info[0].cum_max_nrec = hdr->node_info[0].max_nrec;
+ hdr->node_info[0].cum_max_nrec_size = 0;
+ if(NULL == (hdr->node_info[0].nat_rec_fac = H5FL_fac_init(hdr->cls->nrec_size * hdr->node_info[0].max_nrec)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't create node native key block factory")
+ hdr->node_info[0].node_ptr_fac = NULL;
+
+ /* Allocate array of pointers to internal node native keys */
+ /* (uses leaf # of records because its the largest) */
+ if(NULL == (hdr->nat_off = H5FL_SEQ_MALLOC(size_t, (size_t)hdr->node_info[0].max_nrec)))
+ HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize offsets in native key block */
+ /* (uses leaf # of records because its the largest) */
+ for(u = 0; u < hdr->node_info[0].max_nrec; u++)
+ hdr->nat_off[u] = hdr->cls->nrec_size * u;
+
+ /* Compute size to store # of records in each node */
+ /* (uses leaf # of records because its the largest) */
+ u_max_nrec_size = H5VM_limit_enc_size((uint64_t)hdr->node_info[0].max_nrec);
+ H5_CHECKED_ASSIGN(hdr->max_nrec_size, uint8_t, u_max_nrec_size, unsigned)
+ HDassert(hdr->max_nrec_size <= H5B2_SIZEOF_RECORDS_PER_NODE);
+
+ /* Initialize internal node info */
+ if(depth > 0) {
+ for(u = 1; u < (unsigned)(depth + 1); u++) {
+ sz_max_nrec = H5B2_NUM_INT_REC(hdr, u);
+ H5_CHECKED_ASSIGN(hdr->node_info[u].max_nrec, unsigned, sz_max_nrec, size_t)
+ HDassert(hdr->node_info[u].max_nrec <= hdr->node_info[u - 1].max_nrec);
+
+ hdr->node_info[u].split_nrec = (hdr->node_info[u].max_nrec * hdr->split_percent) / 100;
+ hdr->node_info[u].merge_nrec = (hdr->node_info[u].max_nrec * hdr->merge_percent) / 100;
+
+ hdr->node_info[u].cum_max_nrec = ((hdr->node_info[u].max_nrec + 1) *
+ hdr->node_info[u - 1].cum_max_nrec) + hdr->node_info[u].max_nrec;
+ u_max_nrec_size = H5VM_limit_enc_size((uint64_t)hdr->node_info[u].cum_max_nrec);
+ H5_CHECKED_ASSIGN(hdr->node_info[u].cum_max_nrec_size, uint8_t, u_max_nrec_size, unsigned)
+
+ if(NULL == (hdr->node_info[u].nat_rec_fac = H5FL_fac_init(hdr->cls->nrec_size * hdr->node_info[u].max_nrec)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't create node native key block factory")
+ if(NULL == (hdr->node_info[u].node_ptr_fac = H5FL_fac_init(sizeof(H5B2_node_ptr_t) * (hdr->node_info[u].max_nrec + 1))))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't create internal 'branch' node node pointer block factory")
+ } /* end for */
+ } /* end if */
+
+ /* Determine if we are doing SWMR writes. Only enable for data chunks for now. */
+ hdr->swmr_write = (H5F_INTENT(hdr->f) & H5F_ACC_SWMR_WRITE) > 0
+ && (hdr->cls->id == H5B2_CDSET_ID || hdr->cls->id == H5B2_CDSET_FILT_ID);
+
+ /* Reset the shadow epoch */
+ hdr->shadow_epoch = 0;
+
+ /* Create the callback context, if the callback exists */
+ if(hdr->cls->crt_context)
+ if(NULL == (hdr->cb_ctx = (*hdr->cls->crt_context)(ctx_udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, FAIL, "unable to create v2 B-tree client callback context")
+
+done:
+ if(ret_value < 0)
+ if(H5B2__hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free shared v2 B-tree info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_alloc
+ *
+ * Purpose: Allocate B-tree header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 27 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_hdr_t *
+H5B2__hdr_alloc(H5F_t *f)
+{
+ H5B2_hdr_t *hdr = NULL; /* v2 B-tree header */
+ H5B2_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5FL_CALLOC(H5B2_hdr_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree header")
+
+ /* Assign non-zero information */
+ hdr->f = f;
+ hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
+ hdr->hdr_size = H5B2_HEADER_SIZE_HDR(hdr);
+ hdr->root.addr = HADDR_UNDEF;
+
+ /* Set return value */
+ ret_value = hdr;
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_create
+ *
+ * Purpose: Create new fractal heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5B2__hdr_create(H5F_t *f, hid_t dxpl_id, const H5B2_create_t *cparam,
+ void *ctx_udata)
+{
+ H5B2_hdr_t *hdr = NULL; /* The new v2 B-tree header information */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+ /* Allocate v2 B-tree header */
+ if(NULL == (hdr = H5B2__hdr_alloc(f)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed for B-tree header")
+
+ /* Initialize shared B-tree info */
+ if(H5B2__hdr_init(hdr, cparam, ctx_udata, (uint16_t)0) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, HADDR_UNDEF, "can't create shared B-tree info")
+
+ /* Allocate space for the header on disk */
+ if(HADDR_UNDEF == (hdr->addr = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)hdr->hdr_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, HADDR_UNDEF, "file allocation failed for B-tree header")
+
+ /* Create 'top' proxy for extensible array entries */
+ if(hdr->swmr_write)
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, HADDR_UNDEF, "can't create v2 B-tree proxy")
+
+ /* Cache the new B-tree node */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_BT2_HDR, hdr->addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, HADDR_UNDEF, "can't add B-tree header to cache")
+ inserted = TRUE;
+
+ /* Add header as child of 'top' proxy */
+ if(hdr->top_proxy)
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, HADDR_UNDEF, "unable to add v2 B-tree header as child of array proxy")
+
+ /* Set address of v2 B-tree header to return */
+ ret_value = hdr->addr;
+
+done:
+ if(!H5F_addr_defined(ret_value))
+ if(hdr) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(hdr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, HADDR_UNDEF, "unable to remove v2 B-tree header from cache")
+
+ /* Release header's disk space */
+ if(H5F_addr_defined(hdr->addr) && H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, hdr->addr, (hsize_t)hdr->hdr_size) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, HADDR_UNDEF, "unable to free v2 B-tree header")
+
+ /* Destroy header */
+ if(H5B2__hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, HADDR_UNDEF, "unable to release v2 B-tree header")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_incr
+ *
+ * Purpose: Increment reference count on B-tree header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 13 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_incr(H5B2_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(hdr);
+
+ /* Mark header as un-evictable when a B-tree node is depending on it */
+ if(hdr->rc == 0)
+ if(H5AC_pin_protected_entry(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPIN, FAIL, "unable to pin v2 B-tree header")
+
+ /* Increment reference count on B-tree header */
+ hdr->rc++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_decr
+ *
+ * Purpose: Decrement reference count on B-tree header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 13 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_decr(H5B2_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->rc > 0);
+
+ /* Decrement reference count on B-tree header */
+ hdr->rc--;
+
+ /* Mark header as evictable again when no nodes depend on it */
+ if(hdr->rc == 0)
+ if(H5AC_unpin_entry(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin v2 B-tree header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_fuse_incr
+ *
+ * Purpose: Increment file reference count on shared v2 B-tree header
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 27 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_fuse_incr(H5B2_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Increment file reference count on shared header */
+ hdr->file_rc++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__hdr_fuse_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_fuse_decr
+ *
+ * Purpose: Decrement file reference count on shared v2 B-tree header
+ *
+ * Return: The file's reference count after the decrement. (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 27 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5B2__hdr_fuse_decr(H5B2_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->file_rc);
+
+ /* Decrement file reference count on shared header */
+ hdr->file_rc--;
+
+ FUNC_LEAVE_NOAPI(hdr->file_rc)
+} /* end H5B2__hdr_fuse_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_dirty
+ *
+ * Purpose: Mark B-tree header as dirty
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 13 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_dirty(H5B2_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Mark B-tree header as dirty in cache */
+ if(H5AC_mark_entry_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark v2 B-tree header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_protect
+ *
+ * Purpose: Convenience wrapper around protecting v2 B-tree header
+ *
+ * Return: Non-NULL pointer to header on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_hdr_t *
+H5B2__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t hdr_addr, void *ctx_udata,
+ unsigned flags)
+{
+ H5B2_hdr_cache_ud_t udata; /* User data for cache callbacks */
+ H5B2_hdr_t *hdr = NULL; /* v2 B-tree header */
+ H5B2_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(hdr_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data for cache callbacks */
+ udata.f = f;
+ udata.addr = hdr_addr;
+ udata.ctx_udata = ctx_udata;
+
+ /* Protect the header */
+ if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &udata, flags)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to load v2 B-tree header, address = %llu", (unsigned long long)hdr_addr)
+ hdr->f = f; /* (Must be set again here, in case the header was already in the cache -QAK) */
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->swmr_write && NULL == hdr->top_proxy) {
+ /* Create 'top' proxy for v2 B-tree entries */
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, NULL, "can't create v2 B-tree proxy")
+
+ /* Add header as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree header as child of proxy")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = hdr;
+
+done:
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the header, if it was protected */
+ if(hdr && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_HDR, hdr_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to unprotect v2 B-tree header, address = %llu", (unsigned long long)hdr_addr)
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting v2 B-tree header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_unprotect(H5B2_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Unprotect the header */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_HDR, hdr->addr, hdr, cache_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to unprotect v2 B-tree header, address = %llu", (unsigned long long)hdr->addr)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_free
+ *
+ * Purpose: Free B-tree header info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_free(H5B2_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Destroy the callback context */
+ if(hdr->cb_ctx) {
+ if((*hdr->cls->dst_context)(hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "can't destroy v2 B-tree client callback context")
+ hdr->cb_ctx = NULL;
+ } /* end if */
+
+ /* Free the B-tree node buffer */
+ if(hdr->page)
+ hdr->page = H5FL_BLK_FREE(node_page, hdr->page);
+
+ /* Free the array of offsets into the native key block */
+ if(hdr->nat_off)
+ hdr->nat_off = H5FL_SEQ_FREE(size_t, hdr->nat_off);
+
+ /* Release the node info */
+ if(hdr->node_info) {
+ unsigned u; /* Local index variable */
+
+ /* Destroy free list factories */
+ for(u = 0; u < (unsigned)(hdr->depth + 1); u++) {
+ if(hdr->node_info[u].nat_rec_fac)
+ if(H5FL_fac_term(hdr->node_info[u].nat_rec_fac) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "can't destroy node's native record block factory")
+ if(hdr->node_info[u].node_ptr_fac)
+ if(H5FL_fac_term(hdr->node_info[u].node_ptr_fac) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "can't destroy node's node pointer block factory")
+ } /* end for */
+
+ /* Free the array of node info structs */
+ hdr->node_info = H5FL_SEQ_FREE(H5B2_node_info_t, hdr->node_info);
+ } /* end if */
+
+ /* Release the min & max record info, if set */
+ if(hdr->min_native_rec)
+ hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
+ if(hdr->max_native_rec)
+ hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
+
+ /* Destroy the 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_dest(hdr->top_proxy) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to destroy v2 B-tree 'top' proxy")
+ hdr->top_proxy = NULL;
+ } /* end if */
+
+ /* Free B-tree header info */
+ hdr = H5FL_FREE(H5B2_hdr_t, hdr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__hdr_delete
+ *
+ * Purpose: Delete a v2 B-tree, starting with the header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 15 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__hdr_delete(H5B2_hdr_t *hdr, hid_t dxpl_id)
+{
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting v2 B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(hdr);
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* v2 B-tree header's status in the metadata cache */
+
+ /* Check the v2 B-tree header's status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, hdr->addr, &hdr_status) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "unable to check metadata cache status for v2 B-tree header")
+
+ /* Sanity checks on v2 B-tree header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PROTECTED);
+} /* end block */
+#endif /* NDEBUG */
+
+ /* Delete all nodes in B-tree */
+ if(H5F_addr_defined(hdr->root.addr))
+ if(H5B2__delete_node(hdr, dxpl_id, hdr->depth, &hdr->root, hdr, hdr->remove_op, hdr->remove_op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete B-tree nodes")
+
+ /* Indicate that the heap header should be deleted & file space freed */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+done:
+ /* Unprotect the header with appropriate flags */
+ if(H5B2__hdr_unprotect(hdr, dxpl_id, cache_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release v2 B-tree header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__hdr_delete() */
+
diff --git a/src/H5B2int.c b/src/H5B2int.c
new file mode 100644
index 0000000..c72bc98
--- /dev/null
+++ b/src/H5B2int.c
@@ -0,0 +1,1948 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2int.c
+ * Feb 27 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Internal routines for managing v2 B-trees.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5B2__update_child_flush_depends(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ unsigned depth, const H5B2_node_ptr_t *node_ptrs, unsigned start_idx,
+ unsigned end_idx, void *old_parent, void *new_parent);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the 'H5B2_node_info_t' sequence information */
+H5FL_SEQ_EXTERN(H5B2_node_info_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__locate_record
+ *
+ * Purpose: Performs a binary search to locate a record in a sorted
+ * array of records.
+ *
+ * Sets *IDX to location of record greater than or equal to
+ * record to locate.
+ *
+ * Return: Comparison value for insertion location. Negative for record
+ * to locate being less than value in *IDX. Zero for record to
+ * locate equal to value in *IDX. Positive for record to locate
+ * being greater than value in *IDX (which should only happen when
+ * record to locate is greater than all records to search).
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__locate_record(const H5B2_class_t *type, unsigned nrec, size_t *rec_off,
+ const uint8_t *native, const void *udata, unsigned *idx, int *cmp)
+{
+ unsigned lo = 0, hi; /* Low & high index values */
+ unsigned my_idx = 0; /* Final index value */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ *cmp = -1;
+
+ hi = nrec;
+ while(lo < hi && *cmp) {
+ my_idx = (lo + hi) / 2;
+ if((type->compare)(udata, native + rec_off[my_idx], cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(*cmp < 0)
+ hi = my_idx;
+ else
+ lo = my_idx + 1;
+ } /* end while */
+
+ *idx = my_idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__locate_record */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__split1
+ *
+ * Purpose: Perform a 1->2 node split
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 28 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t left_addr, right_addr; /* Addresses of left & right child nodes */
+ void *left_child = NULL, *right_child = NULL; /* Pointers to child nodes */
+ uint16_t *left_nrec, *right_nrec; /* Pointers to child # of records */
+ uint8_t *left_native, *right_native;/* Pointers to childs' native records */
+ H5B2_node_ptr_t *left_node_ptrs = NULL, *right_node_ptrs = NULL;/* Pointers to childs' node pointer info */
+ uint16_t mid_record; /* Index of "middle" record in current node */
+ uint16_t old_node_nrec; /* Number of records in internal node split */
+ unsigned left_child_flags = H5AC__NO_FLAGS_SET, right_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(internal);
+ HDassert(internal_flags_ptr);
+
+ /* Slide records in parent node up one space, to make room for promoted record */
+ if(idx < internal->nrec) {
+ HDmemmove(H5B2_INT_NREC(internal, hdr, idx + 1), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size * (internal->nrec - idx));
+ HDmemmove(&(internal->node_ptrs[idx + 2]), &(internal->node_ptrs[idx + 1]), sizeof(H5B2_node_ptr_t) * (internal->nrec - idx));
+ } /* end if */
+
+ /* Check for the kind of B-tree node to split */
+ if(depth > 1) {
+ H5B2_internal_t *left_int = NULL, *right_int = NULL; /* Pointers to old & new internal nodes */
+
+ /* Create new internal node */
+ internal->node_ptrs[idx + 1].all_nrec = internal->node_ptrs[idx + 1].node_nrec = 0;
+ if(H5B2__create_internal(hdr, dxpl_id, internal, &(internal->node_ptrs[idx + 1]), (uint16_t)(depth - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new internal node")
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_INT;
+
+ /* Protect both leaves */
+ /* (Shadow left node if doing SWMR writes) */
+ if(NULL == (left_int = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_int = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], (uint16_t)(depth - 1), FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_int;
+ right_child = right_int;
+ left_nrec = &(left_int->nrec);
+ right_nrec = &(right_int->nrec);
+ left_native = left_int->int_native;
+ right_native = right_int->int_native;
+ left_node_ptrs = left_int->node_ptrs;
+ right_node_ptrs = right_int->node_ptrs;
+ } /* end if */
+ else {
+ H5B2_leaf_t *left_leaf = NULL, *right_leaf = NULL; /* Pointers to old & new leaf nodes */
+
+ /* Create new leaf node */
+ internal->node_ptrs[idx + 1].all_nrec = internal->node_ptrs[idx + 1].node_nrec = 0;
+ if(H5B2__create_leaf(hdr, dxpl_id, internal, &(internal->node_ptrs[idx + 1])) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new leaf node")
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Protect both leaves */
+ /* (Shadow the left node if doing SWMR writes) */
+ if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_leaf;
+ right_child = right_leaf;
+ left_nrec = &(left_leaf->nrec);
+ right_nrec = &(right_leaf->nrec);
+ left_native = left_leaf->leaf_native;
+ right_native = right_leaf->leaf_native;
+ } /* end if */
+
+ /* Get the number of records in node to split */
+ old_node_nrec = internal->node_ptrs[idx].node_nrec;
+
+ /* Determine "middle" record to promote to internal node */
+ mid_record = old_node_nrec / 2;
+
+ /* Copy "upper half" of records to new child */
+ HDmemcpy(H5B2_NAT_NREC(right_native, hdr, 0),
+ H5B2_NAT_NREC(left_native, hdr, mid_record + (unsigned)1),
+ hdr->cls->nrec_size * (old_node_nrec - (mid_record + (unsigned)1)));
+
+ /* Copy "upper half" of node pointers, if the node is an internal node */
+ if(depth > 1)
+ HDmemcpy(&(right_node_ptrs[0]), &(left_node_ptrs[mid_record + (unsigned)1]),
+ sizeof(H5B2_node_ptr_t) * (size_t)(old_node_nrec - mid_record));
+
+ /* Copy "middle" record to internal node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx), H5B2_NAT_NREC(left_native, hdr, mid_record), hdr->cls->nrec_size);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Update record counts in child nodes */
+ internal->node_ptrs[idx].node_nrec = *left_nrec = mid_record;
+ internal->node_ptrs[idx + 1].node_nrec = *right_nrec = (uint16_t)(old_node_nrec - (mid_record + 1));
+
+ /* Determine total number of records in new child nodes */
+ if(depth > 1) {
+ unsigned u; /* Local index variable */
+ hsize_t new_left_all_nrec; /* New total number of records in left child */
+ hsize_t new_right_all_nrec; /* New total number of records in right child */
+
+ /* Compute total of all records in each child node */
+ new_left_all_nrec = internal->node_ptrs[idx].node_nrec;
+ for(u = 0; u < (*left_nrec + (unsigned)1); u++)
+ new_left_all_nrec += left_node_ptrs[u].all_nrec;
+
+ new_right_all_nrec = internal->node_ptrs[idx + 1].node_nrec;
+ for(u = 0; u < (*right_nrec + (unsigned)1); u++)
+ new_right_all_nrec += right_node_ptrs[u].all_nrec;
+
+ internal->node_ptrs[idx].all_nrec = new_left_all_nrec;
+ internal->node_ptrs[idx + 1].all_nrec = new_right_all_nrec;
+ } /* end if */
+ else {
+ internal->node_ptrs[idx].all_nrec = internal->node_ptrs[idx].node_nrec;
+ internal->node_ptrs[idx + 1].all_nrec = internal->node_ptrs[idx + 1].node_nrec;
+ } /* end else */
+
+ /* Update # of records in parent node */
+ internal->nrec++;
+
+ /* Mark parent as dirty */
+ *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+ /* Update grandparent info */
+ curr_node_ptr->node_nrec++;
+
+ /* Mark grandparent as dirty, if given */
+ if(parent_cache_info_flags_ptr)
+ *parent_cache_info_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, right_node_ptrs,
+ 0, (unsigned)(*right_nrec + 1), left_child, right_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1) {
+ H5B2__assert_internal2(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)left_child, (H5B2_internal_t *)right_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx + 1].all_nrec, hdr, (H5B2_internal_t *)right_child, (H5B2_internal_t *)left_child);
+ } /* end if */
+ else {
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)left_child, (H5B2_leaf_t *)right_child);
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)right_child);
+ } /* end else */
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Release child nodes (marked as dirty) */
+ if(left_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, left_addr, left_child, left_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree leaf node")
+ if(right_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, right_addr, right_child, right_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree leaf node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__split1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__split_root
+ *
+ * Purpose: Split the root node
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__split_root(H5B2_hdr_t *hdr, hid_t dxpl_id)
+{
+ H5B2_internal_t *new_root = NULL; /* Pointer to new root node */
+ unsigned new_root_flags = H5AC__NO_FLAGS_SET; /* Cache flags for new root node */
+ H5B2_node_ptr_t old_root_ptr; /* Old node pointer to root node in B-tree */
+ size_t sz_max_nrec; /* Temporary variable for range checking */
+ unsigned u_max_nrec_size; /* Temporary variable for range checking */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+
+ /* Update depth of B-tree */
+ hdr->depth++;
+
+ /* Re-allocate array of node info structs */
+ if(NULL == (hdr->node_info = H5FL_SEQ_REALLOC(H5B2_node_info_t, hdr->node_info, (size_t)(hdr->depth + 1))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Update node info for new depth of tree */
+ sz_max_nrec = H5B2_NUM_INT_REC(hdr, hdr->depth);
+ H5_CHECKED_ASSIGN(hdr->node_info[hdr->depth].max_nrec, unsigned, sz_max_nrec, size_t)
+ hdr->node_info[hdr->depth].split_nrec = (hdr->node_info[hdr->depth].max_nrec * hdr->split_percent) / 100;
+ hdr->node_info[hdr->depth].merge_nrec = (hdr->node_info[hdr->depth].max_nrec * hdr->merge_percent) / 100;
+ hdr->node_info[hdr->depth].cum_max_nrec = ((hdr->node_info[hdr->depth].max_nrec + 1) *
+ hdr->node_info[hdr->depth - 1].cum_max_nrec) + hdr->node_info[hdr->depth].max_nrec;
+ u_max_nrec_size = H5VM_limit_enc_size((uint64_t)hdr->node_info[hdr->depth].cum_max_nrec);
+ H5_CHECKED_ASSIGN(hdr->node_info[hdr->depth].cum_max_nrec_size, uint8_t, u_max_nrec_size, unsigned)
+ if(NULL == (hdr->node_info[hdr->depth].nat_rec_fac = H5FL_fac_init(hdr->cls->nrec_size * hdr->node_info[hdr->depth].max_nrec)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create node native key block factory")
+ if(NULL == (hdr->node_info[hdr->depth].node_ptr_fac = H5FL_fac_init(sizeof(H5B2_node_ptr_t) * (hdr->node_info[hdr->depth].max_nrec + 1))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create internal 'branch' node node pointer block factory")
+
+ /* Keep old root node pointer info */
+ old_root_ptr = hdr->root;
+
+ /* Create new internal node to use as root */
+ hdr->root.node_nrec = 0;
+ if(H5B2__create_internal(hdr, dxpl_id, hdr, &(hdr->root), hdr->depth) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new internal node")
+
+ /* Protect new root node */
+ if(NULL == (new_root = H5B2__protect_internal(hdr, dxpl_id, hdr, &hdr->root, hdr->depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Set first node pointer in root node to old root node pointer info */
+ new_root->node_ptrs[0] = old_root_ptr;
+
+ /* Split original root node */
+ if(H5B2__split1(hdr, dxpl_id, hdr->depth, &(hdr->root), NULL, new_root, &new_root_flags, 0) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split old root node")
+
+done:
+ /* Release new root node (marked as dirty) */
+ if(new_root && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, hdr->root.addr, new_root, new_root_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree internal node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__split_root() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__redistribute2
+ *
+ * Purpose: Redistribute records between two nodes
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned idx)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t left_addr, right_addr; /* Addresses of left & right child nodes */
+ void *left_child = NULL, *right_child = NULL; /* Pointers to child nodes */
+ uint16_t *left_nrec, *right_nrec; /* Pointers to child # of records */
+ uint8_t *left_native, *right_native; /* Pointers to childs' native records */
+ H5B2_node_ptr_t *left_node_ptrs = NULL, *right_node_ptrs = NULL;/* Pointers to childs' node pointer info */
+ hssize_t left_moved_nrec = 0, right_moved_nrec = 0; /* Number of records moved, for internal redistrib */
+ unsigned left_child_flags = H5AC__NO_FLAGS_SET, right_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(internal);
+
+ /* Check for the kind of B-tree node to redistribute */
+ if(depth > 1) {
+ H5B2_internal_t *left_internal; /* Pointer to left internal node */
+ H5B2_internal_t *right_internal; /* Pointer to right internal node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_INT;
+
+ /* Lock left & right B-tree child nodes */
+ /* (Shadow both nodes if doing SWMR writes) */
+ if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_internal;
+ right_child = right_internal;
+ left_nrec = &(left_internal->nrec);
+ right_nrec = &(right_internal->nrec);
+ left_native = left_internal->int_native;
+ right_native = right_internal->int_native;
+ left_node_ptrs = left_internal->node_ptrs;
+ right_node_ptrs = right_internal->node_ptrs;
+ } /* end if */
+ else {
+ H5B2_leaf_t *left_leaf; /* Pointer to left leaf node */
+ H5B2_leaf_t *right_leaf; /* Pointer to right leaf node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Lock left & right B-tree child nodes */
+ /* (Shadow both nodes if doing SWMR writes) */
+ if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_leaf;
+ right_child = right_leaf;
+ left_nrec = &(left_leaf->nrec);
+ right_nrec = &(right_leaf->nrec);
+ left_native = left_leaf->leaf_native;
+ right_native = right_leaf->leaf_native;
+ } /* end else */
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1) {
+ H5B2__assert_internal2(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)left_child, (H5B2_internal_t *)right_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx + 1].all_nrec, hdr, (H5B2_internal_t *)right_child, (H5B2_internal_t *)left_child);
+ } /* end if */
+ else {
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)left_child, (H5B2_leaf_t *)right_child);
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)right_child);
+ } /* end else */
+#endif /* H5B2_DEBUG */
+
+ /* Determine whether to shuffle records left or right */
+ if(*left_nrec < *right_nrec) {
+ /* Moving record from right node to left */
+
+ uint16_t new_right_nrec = (uint16_t)(*left_nrec + *right_nrec) / 2; /* New number of records for right child */
+ uint16_t move_nrec = (uint16_t)(*right_nrec - new_right_nrec); /* Number of records to move from right node to left */
+
+ /* Copy record from parent node down into left child */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* See if we need to move records from right node */
+ if(move_nrec > 1)
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, (*left_nrec + 1)), H5B2_NAT_NREC(right_native, hdr, 0), hdr->cls->nrec_size * (size_t)(move_nrec - 1));
+
+ /* Move record from right node into parent node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx), H5B2_NAT_NREC(right_native, hdr, (move_nrec - 1)), hdr->cls->nrec_size);
+
+ /* Slide records in right node down */
+ HDmemmove(H5B2_NAT_NREC(right_native, hdr, 0), H5B2_NAT_NREC(right_native, hdr, move_nrec), hdr->cls->nrec_size * new_right_nrec);
+
+ /* Handle node pointers, if we have an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec = move_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned u; /* Local index variable */
+
+ /* Count the number of records being moved */
+ for(u = 0; u < move_nrec; u++)
+ moved_nrec += right_node_ptrs[u].all_nrec;
+ H5_CHECKED_ASSIGN(left_moved_nrec, hssize_t, moved_nrec, hsize_t)
+ right_moved_nrec -= (hssize_t)moved_nrec;
+
+ /* Copy node pointers from right node to left */
+ HDmemcpy(&(left_node_ptrs[*left_nrec + 1]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * move_nrec);
+
+ /* Slide node pointers in right node down */
+ HDmemmove(&(right_node_ptrs[0]), &(right_node_ptrs[move_nrec]), sizeof(H5B2_node_ptr_t) * (new_right_nrec + (unsigned)1));
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, left_node_ptrs,
+ (unsigned)(*left_nrec + 1), (unsigned)(*left_nrec + move_nrec + 1), right_child, left_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update number of records in child nodes */
+ *left_nrec = (uint16_t)(*left_nrec + move_nrec);
+ *right_nrec = new_right_nrec;
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else {
+ /* Moving record from left node to right */
+
+ uint16_t new_left_nrec = (uint16_t)(*left_nrec + *right_nrec) / 2; /* New number of records for left child */
+ uint16_t move_nrec = (uint16_t)(*left_nrec - new_left_nrec); /* Number of records to move from left node to right */
+
+ /* Sanity check */
+ HDassert(*left_nrec > *right_nrec);
+
+ /* Slide records in right node up */
+ HDmemmove(H5B2_NAT_NREC(right_native, hdr, move_nrec),
+ H5B2_NAT_NREC(right_native, hdr, 0),
+ hdr->cls->nrec_size * (*right_nrec));
+
+ /* Copy record from parent node down into right child */
+ HDmemcpy(H5B2_NAT_NREC(right_native, hdr, (move_nrec - 1)), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* See if we need to move records from left node */
+ if(move_nrec > 1)
+ HDmemcpy(H5B2_NAT_NREC(right_native, hdr, 0), H5B2_NAT_NREC(left_native, hdr, ((*left_nrec - move_nrec) + 1)), hdr->cls->nrec_size * (size_t)(move_nrec - 1));
+
+ /* Move record from left node into parent node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx), H5B2_NAT_NREC(left_native, hdr, (*left_nrec - move_nrec)), hdr->cls->nrec_size);
+
+ /* Handle node pointers, if we have an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec = move_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned u; /* Local index variable */
+
+ /* Slide node pointers in right node up */
+ HDmemmove(&(right_node_ptrs[move_nrec]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * (size_t)(*right_nrec + 1));
+
+ /* Copy node pointers from left node to right */
+ HDmemcpy(&(right_node_ptrs[0]), &(left_node_ptrs[new_left_nrec + 1]), sizeof(H5B2_node_ptr_t) * move_nrec);
+
+ /* Count the number of records being moved */
+ for(u = 0; u < move_nrec; u++)
+ moved_nrec += right_node_ptrs[u].all_nrec;
+ left_moved_nrec -= (hssize_t)moved_nrec;
+ H5_CHECKED_ASSIGN(right_moved_nrec, hssize_t, moved_nrec, hsize_t)
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, right_node_ptrs,
+ 0, (unsigned)move_nrec, left_child, right_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update number of records in child nodes */
+ *left_nrec = new_left_nrec;
+ *right_nrec = (uint16_t)(*right_nrec + move_nrec);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end else */
+
+ /* Update # of records in child nodes */
+ internal->node_ptrs[idx].node_nrec = *left_nrec;
+ internal->node_ptrs[idx + 1].node_nrec = *right_nrec;
+
+ /* Update total # of records in child B-trees */
+ if(depth > 1) {
+ internal->node_ptrs[idx].all_nrec = (hsize_t)((hssize_t)internal->node_ptrs[idx].all_nrec + left_moved_nrec);
+ internal->node_ptrs[idx + 1].all_nrec = (hsize_t)((hssize_t)internal->node_ptrs[idx + 1].all_nrec + right_moved_nrec);
+ } /* end if */
+ else {
+ internal->node_ptrs[idx].all_nrec = internal->node_ptrs[idx].node_nrec;
+ internal->node_ptrs[idx + 1].all_nrec = internal->node_ptrs[idx + 1].node_nrec;
+ } /* end else */
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1) {
+ H5B2__assert_internal2(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)left_child, (H5B2_internal_t *)right_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx + 1].all_nrec, hdr, (H5B2_internal_t *)right_child, (H5B2_internal_t *)left_child);
+ } /* end if */
+ else {
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)left_child, (H5B2_leaf_t *)right_child);
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)right_child);
+ } /* end else */
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Release child nodes (marked as dirty) */
+ if(left_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, left_addr, left_child, left_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+ if(right_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, right_addr, right_child, right_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__redistribute2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__redistribute3
+ *
+ * Purpose: Redistribute records between three nodes
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx)
+{
+ H5B2_node_ptr_t *left_node_ptrs = NULL, *right_node_ptrs = NULL; /* Pointers to childs' node pointer info */
+ H5B2_node_ptr_t *middle_node_ptrs = NULL; /* Pointers to childs' node pointer info */
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t left_addr, right_addr; /* Addresses of left & right child nodes */
+ haddr_t middle_addr; /* Address of middle child node */
+ void *left_child = NULL, *right_child = NULL; /* Pointers to child nodes */
+ void *middle_child = NULL; /* Pointers to middle child node */
+ uint16_t *left_nrec, *right_nrec; /* Pointers to child # of records */
+ uint16_t *middle_nrec; /* Pointers to middle child # of records */
+ uint8_t *left_native, *right_native; /* Pointers to childs' native records */
+ uint8_t *middle_native; /* Pointers to middle child's native records */
+ hssize_t left_moved_nrec = 0, right_moved_nrec = 0; /* Number of records moved, for internal split */
+ hssize_t middle_moved_nrec = 0; /* Number of records moved, for internal split */
+ unsigned left_child_flags = H5AC__NO_FLAGS_SET, right_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ unsigned middle_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(internal);
+ HDassert(internal_flags_ptr);
+
+ /* Check for the kind of B-tree node to redistribute */
+ if(depth > 1) {
+ H5B2_internal_t *left_internal; /* Pointer to left internal node */
+ H5B2_internal_t *middle_internal; /* Pointer to middle internal node */
+ H5B2_internal_t *right_internal; /* Pointer to right internal node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_INT;
+
+ /* Lock B-tree child nodes */
+ /* (Shadow all nodes if doing SWMR writes) */
+ if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx - 1], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ left_addr = internal->node_ptrs[idx - 1].addr;
+ if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ middle_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_internal;
+ middle_child = middle_internal;
+ right_child = right_internal;
+ left_nrec = &(left_internal->nrec);
+ middle_nrec = &(middle_internal->nrec);
+ right_nrec = &(right_internal->nrec);
+ left_native = left_internal->int_native;
+ middle_native = middle_internal->int_native;
+ right_native = right_internal->int_native;
+ left_node_ptrs = left_internal->node_ptrs;
+ middle_node_ptrs = middle_internal->node_ptrs;
+ right_node_ptrs = right_internal->node_ptrs;
+ } /* end if */
+ else {
+ H5B2_leaf_t *left_leaf; /* Pointer to left leaf node */
+ H5B2_leaf_t *middle_leaf; /* Pointer to middle leaf node */
+ H5B2_leaf_t *right_leaf; /* Pointer to right leaf node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Lock B-tree child nodes */
+ /* (Shadow all nodes if doing SWMR writes) */
+ if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx - 1], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx - 1].addr;
+ if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ middle_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for child nodes */
+ left_child = left_leaf;
+ middle_child = middle_leaf;
+ right_child = right_leaf;
+ left_nrec = &(left_leaf->nrec);
+ middle_nrec = &(middle_leaf->nrec);
+ right_nrec = &(right_leaf->nrec);
+ left_native = left_leaf->leaf_native;
+ middle_native = middle_leaf->leaf_native;
+ right_native = right_leaf->leaf_native;
+ } /* end else */
+
+ /* Redistribute records */
+ {
+ /* Compute new # of records in each node */
+ unsigned total_nrec = (unsigned)(*left_nrec + *middle_nrec + *right_nrec + 2);
+ uint16_t new_middle_nrec = (uint16_t)(total_nrec - 2) / 3;
+ uint16_t new_left_nrec = (uint16_t)((total_nrec - 2) - new_middle_nrec) / 2;
+ uint16_t new_right_nrec = (uint16_t)((total_nrec - 2) - (unsigned)(new_left_nrec + new_middle_nrec));
+ uint16_t curr_middle_nrec = *middle_nrec;
+
+ /* Sanity check rounding */
+ HDassert(new_middle_nrec <= new_left_nrec);
+ HDassert(new_middle_nrec <= new_right_nrec);
+
+ /* Move records into left node */
+ if(new_left_nrec > *left_nrec) {
+ uint16_t moved_middle_nrec = 0; /* Number of records moved into left node */
+
+ /* Move left parent record down to left node */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec), H5B2_INT_NREC(internal, hdr, idx - 1), hdr->cls->nrec_size);
+
+ /* Move records from middle node into left node */
+ if((new_left_nrec - 1) > *left_nrec) {
+ moved_middle_nrec = (uint16_t)(new_left_nrec - (*left_nrec + 1));
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec + 1), H5B2_NAT_NREC(middle_native, hdr, 0), hdr->cls->nrec_size * moved_middle_nrec);
+ } /* end if */
+
+ /* Move record from middle node up to parent node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx - 1), H5B2_NAT_NREC(middle_native, hdr, moved_middle_nrec), hdr->cls->nrec_size);
+ moved_middle_nrec++;
+
+ /* Slide records in middle node down */
+ HDmemmove(H5B2_NAT_NREC(middle_native, hdr, 0), H5B2_NAT_NREC(middle_native, hdr, moved_middle_nrec), hdr->cls->nrec_size * (size_t)(*middle_nrec - moved_middle_nrec));
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned move_nptrs; /* Number of node pointers to move */
+ unsigned u; /* Local index variable */
+
+ /* Move middle node pointers into left node */
+ move_nptrs = (unsigned)(new_left_nrec - *left_nrec);
+ HDmemcpy(&(left_node_ptrs[*left_nrec + 1]), &(middle_node_ptrs[0]), sizeof(H5B2_node_ptr_t)*move_nptrs);
+
+ /* Count the number of records being moved into the left node */
+ for(u = 0, moved_nrec = 0; u < move_nptrs; u++)
+ moved_nrec += middle_node_ptrs[u].all_nrec;
+ left_moved_nrec = (hssize_t)(moved_nrec + move_nptrs);
+ middle_moved_nrec -= (hssize_t)(moved_nrec + move_nptrs);
+
+ /* Slide the node pointers in middle node down */
+ HDmemmove(&(middle_node_ptrs[0]), &(middle_node_ptrs[move_nptrs]), sizeof(H5B2_node_ptr_t) * ((*middle_nrec - move_nptrs) + 1));
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, left_node_ptrs,
+ (unsigned)(*left_nrec + 1), (unsigned)(*left_nrec + moved_middle_nrec + 1), middle_child, left_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update the current number of records in middle node */
+ curr_middle_nrec = (uint16_t)(curr_middle_nrec - moved_middle_nrec);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Move records into right node */
+ if(new_right_nrec > *right_nrec) {
+ unsigned right_nrec_move = (unsigned)(new_right_nrec - *right_nrec); /* Number of records to move out of right node */
+
+ /* Slide records in right node up */
+ HDmemmove(H5B2_NAT_NREC(right_native, hdr, right_nrec_move), H5B2_NAT_NREC(right_native, hdr, 0), hdr->cls->nrec_size * (*right_nrec));
+
+ /* Move right parent record down to right node */
+ HDmemcpy(H5B2_NAT_NREC(right_native, hdr, right_nrec_move - 1), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* Move records from middle node into right node */
+ if(right_nrec_move > 1)
+ HDmemcpy(H5B2_NAT_NREC(right_native, hdr, 0), H5B2_NAT_NREC(middle_native, hdr, ((curr_middle_nrec - right_nrec_move) + 1)), hdr->cls->nrec_size * (right_nrec_move - 1));
+
+ /* Move record from middle node up to parent node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx), H5B2_NAT_NREC(middle_native, hdr, (curr_middle_nrec - right_nrec_move)), hdr->cls->nrec_size);
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned u; /* Local index variable */
+
+ /* Slide the node pointers in right node up */
+ HDmemmove(&(right_node_ptrs[right_nrec_move]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * (size_t)(*right_nrec + 1));
+
+ /* Move middle node pointers into right node */
+ HDmemcpy(&(right_node_ptrs[0]), &(middle_node_ptrs[(curr_middle_nrec - right_nrec_move) + 1]), sizeof(H5B2_node_ptr_t) * right_nrec_move);
+
+ /* Count the number of records being moved into the right node */
+ for(u = 0, moved_nrec = 0; u < right_nrec_move; u++)
+ moved_nrec += right_node_ptrs[u].all_nrec;
+ right_moved_nrec = (hssize_t)(moved_nrec + right_nrec_move);
+ middle_moved_nrec -= (hssize_t)(moved_nrec + right_nrec_move);
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, right_node_ptrs,
+ 0, (unsigned)right_nrec_move, middle_child, right_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update the current number of records in middle node */
+ curr_middle_nrec = (uint16_t)(curr_middle_nrec - right_nrec_move);
+
+ /* Mark nodes as dirty */
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Move records out of left node */
+ if(new_left_nrec < *left_nrec) {
+ unsigned left_nrec_move = (unsigned)(*left_nrec - new_left_nrec); /* Number of records to move out of left node */
+
+ /* Slide middle records up */
+ HDmemmove(H5B2_NAT_NREC(middle_native, hdr, left_nrec_move), H5B2_NAT_NREC(middle_native, hdr, 0), hdr->cls->nrec_size * curr_middle_nrec);
+
+ /* Move left parent record down to middle node */
+ HDmemcpy(H5B2_NAT_NREC(middle_native, hdr, left_nrec_move - 1), H5B2_INT_NREC(internal, hdr, idx - 1), hdr->cls->nrec_size);
+
+ /* Move left records to middle node */
+ if(left_nrec_move > 1)
+ HDmemmove(H5B2_NAT_NREC(middle_native, hdr, 0), H5B2_NAT_NREC(left_native, hdr, new_left_nrec + 1), hdr->cls->nrec_size * (left_nrec_move - 1));
+
+ /* Move left parent record up from left node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx - 1), H5B2_NAT_NREC(left_native, hdr, new_left_nrec), hdr->cls->nrec_size);
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned u; /* Local index variable */
+
+ /* Slide the node pointers in middle node up */
+ HDmemmove(&(middle_node_ptrs[left_nrec_move]), &(middle_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * (size_t)(curr_middle_nrec + 1));
+
+ /* Move left node pointers into middle node */
+ HDmemcpy(&(middle_node_ptrs[0]), &(left_node_ptrs[new_left_nrec + 1]), sizeof(H5B2_node_ptr_t) * left_nrec_move);
+
+ /* Count the number of records being moved into the left node */
+ for(u = 0, moved_nrec = 0; u < left_nrec_move; u++)
+ moved_nrec += middle_node_ptrs[u].all_nrec;
+ left_moved_nrec -= (hssize_t)(moved_nrec + left_nrec_move);
+ middle_moved_nrec += (hssize_t)(moved_nrec + left_nrec_move);
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, middle_node_ptrs,
+ 0, (unsigned)left_nrec_move, left_child, middle_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update the current number of records in middle node */
+ curr_middle_nrec = (uint16_t)(curr_middle_nrec + left_nrec_move);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Move records out of right node */
+ if(new_right_nrec < *right_nrec) {
+ unsigned right_nrec_move = (unsigned)(*right_nrec - new_right_nrec); /* Number of records to move out of right node */
+
+ /* Move right parent record down to middle node */
+ HDmemcpy(H5B2_NAT_NREC(middle_native, hdr, curr_middle_nrec), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* Move right records to middle node */
+ HDmemmove(H5B2_NAT_NREC(middle_native, hdr, (curr_middle_nrec + 1)), H5B2_NAT_NREC(right_native, hdr, 0), hdr->cls->nrec_size * (right_nrec_move - 1));
+
+ /* Move right parent record up from right node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx), H5B2_NAT_NREC(right_native, hdr, right_nrec_move - 1), hdr->cls->nrec_size);
+
+ /* Slide right records down */
+ HDmemmove(H5B2_NAT_NREC(right_native, hdr, 0), H5B2_NAT_NREC(right_native, hdr, right_nrec_move), hdr->cls->nrec_size * new_right_nrec);
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1) {
+ hsize_t moved_nrec; /* Total number of records moved, for internal redistrib */
+ unsigned u; /* Local index variable */
+
+ /* Move right node pointers into middle node */
+ HDmemcpy(&(middle_node_ptrs[curr_middle_nrec + 1]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * right_nrec_move);
+
+ /* Count the number of records being moved into the right node */
+ for(u = 0, moved_nrec = 0; u < right_nrec_move; u++)
+ moved_nrec += right_node_ptrs[u].all_nrec;
+ right_moved_nrec -= (hssize_t)(moved_nrec + right_nrec_move);
+ middle_moved_nrec += (hssize_t)(moved_nrec + right_nrec_move);
+
+ /* Slide the node pointers in right node down */
+ HDmemmove(&(right_node_ptrs[0]), &(right_node_ptrs[right_nrec_move]), sizeof(H5B2_node_ptr_t) * (size_t)(new_right_nrec + 1));
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, middle_node_ptrs,
+ (unsigned)(curr_middle_nrec + 1), (unsigned)(curr_middle_nrec + right_nrec_move + 1), right_child, middle_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Mark nodes as dirty */
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Update # of records in nodes */
+ *left_nrec = new_left_nrec;
+ *middle_nrec = new_middle_nrec;
+ *right_nrec = new_right_nrec;
+ } /* end block */
+
+ /* Update # of records in child nodes */
+ internal->node_ptrs[idx - 1].node_nrec = *left_nrec;
+ internal->node_ptrs[idx].node_nrec = *middle_nrec;
+ internal->node_ptrs[idx + 1].node_nrec = *right_nrec;
+
+ /* Update total # of records in child B-trees */
+ if(depth > 1) {
+ internal->node_ptrs[idx - 1].all_nrec = (hsize_t)((hssize_t)internal->node_ptrs[idx - 1].all_nrec + left_moved_nrec);
+ internal->node_ptrs[idx].all_nrec = (hsize_t)((hssize_t)internal->node_ptrs[idx].all_nrec + middle_moved_nrec);
+ internal->node_ptrs[idx + 1].all_nrec = (hsize_t)((hssize_t)internal->node_ptrs[idx + 1].all_nrec + right_moved_nrec);
+ } /* end if */
+ else {
+ internal->node_ptrs[idx - 1].all_nrec = internal->node_ptrs[idx - 1].node_nrec;
+ internal->node_ptrs[idx].all_nrec = internal->node_ptrs[idx].node_nrec;
+ internal->node_ptrs[idx + 1].all_nrec = internal->node_ptrs[idx + 1].node_nrec;
+ } /* end else */
+
+ /* Mark parent as dirty */
+ *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1) {
+ H5B2__assert_internal2(internal->node_ptrs[idx - 1].all_nrec, hdr, (H5B2_internal_t *)left_child, (H5B2_internal_t *)middle_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)middle_child, (H5B2_internal_t *)left_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)middle_child, (H5B2_internal_t *)right_child);
+ H5B2__assert_internal2(internal->node_ptrs[idx + 1].all_nrec, hdr, (H5B2_internal_t *)right_child, (H5B2_internal_t *)middle_child);
+ } /* end if */
+ else {
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)left_child, (H5B2_leaf_t *)middle_child);
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)middle_child, (H5B2_leaf_t *)right_child);
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)right_child);
+ } /* end else */
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Unlock child nodes (marked as dirty) */
+ if(left_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, left_addr, left_child, left_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+ if(middle_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, middle_addr, middle_child, middle_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+ if(right_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, right_addr, right_child, right_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__redistribute3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__merge2
+ *
+ * Purpose: Perform a 2->1 node merge
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 4 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t left_addr, right_addr; /* Addresses of left & right child nodes */
+ void *left_child = NULL, *right_child = NULL; /* Pointers to left & right child nodes */
+ uint16_t *left_nrec, *right_nrec; /* Pointers to left & right child # of records */
+ uint8_t *left_native, *right_native; /* Pointers to left & right children's native records */
+ H5B2_node_ptr_t *left_node_ptrs = NULL, *right_node_ptrs = NULL;/* Pointers to childs' node pointer info */
+ unsigned left_child_flags = H5AC__NO_FLAGS_SET, right_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(internal);
+ HDassert(internal_flags_ptr);
+
+ /* Check for the kind of B-tree node to split */
+ if(depth > 1) {
+ H5B2_internal_t *left_internal; /* Pointer to left internal node */
+ H5B2_internal_t *right_internal; /* Pointer to right internal node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_INT;
+
+ /* Lock left & right B-tree child nodes */
+ /* (Shadow the left node if doing SWMR writes) */
+ if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], (uint16_t)(depth - 1), FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for accessing child node information */
+ left_child = left_internal;
+ right_child = right_internal;
+ left_nrec = &(left_internal->nrec);
+ right_nrec = &(right_internal->nrec);
+ left_native = left_internal->int_native;
+ right_native = right_internal->int_native;
+ left_node_ptrs = left_internal->node_ptrs;
+ right_node_ptrs = right_internal->node_ptrs;
+ } /* end if */
+ else {
+ H5B2_leaf_t *left_leaf; /* Pointer to left leaf node */
+ H5B2_leaf_t *right_leaf; /* Pointer to right leaf node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Lock left & right B-tree child nodes */
+ /* (Shadow the left node if doing SWMR writes) */
+ if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for accessing child node information */
+ left_child = left_leaf;
+ right_child = right_leaf;
+ left_nrec = &(left_leaf->nrec);
+ right_nrec = &(right_leaf->nrec);
+ left_native = left_leaf->leaf_native;
+ right_native = right_leaf->leaf_native;
+ } /* end else */
+
+ /* Redistribute records into left node */
+ {
+ /* Copy record from parent node to proper location */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* Copy records from right node to left node */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec + 1), H5B2_NAT_NREC(right_native, hdr, 0), hdr->cls->nrec_size * (*right_nrec));
+
+ /* Copy node pointers from right node into left node */
+ if(depth > 1)
+ HDmemcpy(&(left_node_ptrs[*left_nrec + 1]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * (size_t)(*right_nrec + 1));
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, left_node_ptrs,
+ (unsigned)(*left_nrec + 1), (unsigned)(*left_nrec + *right_nrec + 2), right_child, left_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update # of records in left node */
+ *left_nrec = (uint16_t)(*left_nrec + *right_nrec + 1);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DELETED_FLAG;
+ if(!(hdr->swmr_write))
+ right_child_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+ } /* end block */
+
+ /* Update # of records in child nodes */
+ internal->node_ptrs[idx].node_nrec = *left_nrec;
+
+ /* Update total # of records in child B-trees */
+ internal->node_ptrs[idx].all_nrec += internal->node_ptrs[idx + 1].all_nrec + 1;
+
+ /* Slide records in parent node down, to eliminate demoted record */
+ if((idx + 1) < internal->nrec) {
+ HDmemmove(H5B2_INT_NREC(internal, hdr, idx), H5B2_INT_NREC(internal, hdr, idx + 1), hdr->cls->nrec_size * (internal->nrec - (idx + 1)));
+ HDmemmove(&(internal->node_ptrs[idx + 1]), &(internal->node_ptrs[idx + 2]), sizeof(H5B2_node_ptr_t) * (internal->nrec - (idx + 1)));
+ } /* end if */
+
+ /* Update # of records in parent node */
+ internal->nrec--;
+
+ /* Mark parent as dirty */
+ *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+ /* Update grandparent info */
+ curr_node_ptr->node_nrec--;
+
+ /* Mark grandparent as dirty, if given */
+ if(parent_cache_info_flags_ptr)
+ *parent_cache_info_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1)
+ H5B2__assert_internal(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)left_child);
+ else
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)left_child);
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Unlock left node (marked as dirty) */
+ if(left_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, left_addr, left_child, left_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ /* Delete right node & remove from cache (marked as dirty) */
+ if(right_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, right_addr, right_child, right_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__merge2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__merge3
+ *
+ * Purpose: Perform a 3->2 node merge
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 4 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t left_addr, right_addr; /* Addresses of left & right child nodes */
+ haddr_t middle_addr; /* Address of middle child node */
+ void *left_child = NULL, *right_child = NULL; /* Pointers to left & right child nodes */
+ void *middle_child = NULL; /* Pointer to middle child node */
+ uint16_t *left_nrec, *right_nrec; /* Pointers to left & right child # of records */
+ uint16_t *middle_nrec; /* Pointer to middle child # of records */
+ uint8_t *left_native, *right_native; /* Pointers to left & right children's native records */
+ uint8_t *middle_native; /* Pointer to middle child's native records */
+ H5B2_node_ptr_t *left_node_ptrs = NULL, *right_node_ptrs = NULL;/* Pointers to childs' node pointer info */
+ H5B2_node_ptr_t *middle_node_ptrs = NULL;/* Pointer to child's node pointer info */
+ hsize_t middle_moved_nrec; /* Number of records moved, for internal split */
+ unsigned left_child_flags = H5AC__NO_FLAGS_SET, right_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ unsigned middle_child_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting child nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(internal);
+ HDassert(internal_flags_ptr);
+
+ /* Check for the kind of B-tree node to split */
+ if(depth > 1) {
+ H5B2_internal_t *left_internal; /* Pointer to left internal node */
+ H5B2_internal_t *middle_internal; /* Pointer to middle internal node */
+ H5B2_internal_t *right_internal; /* Pointer to right internal node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_INT;
+
+ /* Lock B-tree child nodes */
+ /* (Shadow left and middle nodes if doing SWMR writes) */
+ if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx - 1], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ left_addr = internal->node_ptrs[idx - 1].addr;
+ if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ middle_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], (uint16_t)(depth - 1), FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for accessing child node information */
+ left_child = left_internal;
+ middle_child = middle_internal;
+ right_child = right_internal;
+ left_nrec = &(left_internal->nrec);
+ middle_nrec = &(middle_internal->nrec);
+ right_nrec = &(right_internal->nrec);
+ left_native = left_internal->int_native;
+ middle_native = middle_internal->int_native;
+ right_native = right_internal->int_native;
+ left_node_ptrs = left_internal->node_ptrs;
+ middle_node_ptrs = middle_internal->node_ptrs;
+ right_node_ptrs = right_internal->node_ptrs;
+ } /* end if */
+ else {
+ H5B2_leaf_t *left_leaf; /* Pointer to left leaf node */
+ H5B2_leaf_t *middle_leaf; /* Pointer to middle leaf node */
+ H5B2_leaf_t *right_leaf; /* Pointer to right leaf node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Lock B-tree child nodes */
+ /* (Shadow left and middle nodes if doing SWMR writes) */
+ if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx - 1], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ left_addr = internal->node_ptrs[idx - 1].addr;
+ if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], hdr->swmr_write, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ middle_addr = internal->node_ptrs[idx].addr;
+ if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx + 1], FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ right_addr = internal->node_ptrs[idx + 1].addr;
+
+ /* More setup for accessing child node information */
+ left_child = left_leaf;
+ middle_child = middle_leaf;
+ right_child = right_leaf;
+ left_nrec = &(left_leaf->nrec);
+ middle_nrec = &(middle_leaf->nrec);
+ right_nrec = &(right_leaf->nrec);
+ left_native = left_leaf->leaf_native;
+ middle_native = middle_leaf->leaf_native;
+ right_native = right_leaf->leaf_native;
+ } /* end else */
+
+ /* Redistribute records into left node */
+ {
+ unsigned total_nrec = (unsigned)(*left_nrec + *middle_nrec + *right_nrec + 2);
+ unsigned middle_nrec_move = ((total_nrec - 1) / 2) - *left_nrec;
+
+ /* Set the base number of records moved from middle node */
+ middle_moved_nrec = middle_nrec_move;
+
+ /* Copy record from parent node to proper location in left node */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec), H5B2_INT_NREC(internal, hdr, idx - 1), hdr->cls->nrec_size);
+
+ /* Copy records from middle node to left node */
+ HDmemcpy(H5B2_NAT_NREC(left_native, hdr, *left_nrec + 1), H5B2_NAT_NREC(middle_native, hdr, 0), hdr->cls->nrec_size * (middle_nrec_move - 1));
+
+ /* Copy record from middle node to proper location in parent node */
+ HDmemcpy(H5B2_INT_NREC(internal, hdr, idx - 1), H5B2_NAT_NREC(middle_native, hdr, (middle_nrec_move - 1)), hdr->cls->nrec_size);
+
+ /* Slide records in middle node down */
+ HDmemmove(H5B2_NAT_NREC(middle_native, hdr, 0), H5B2_NAT_NREC(middle_native, hdr, middle_nrec_move), hdr->cls->nrec_size * (*middle_nrec - middle_nrec_move));
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1) {
+ unsigned u; /* Local index variable */
+
+ /* Copy node pointers from middle node into left node */
+ HDmemcpy(&(left_node_ptrs[*left_nrec + 1]), &(middle_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * middle_nrec_move);
+
+ /* Count the number of records being moved into the left node */
+ for(u = 0; u < middle_nrec_move; u++)
+ middle_moved_nrec += middle_node_ptrs[u].all_nrec;
+
+ /* Slide the node pointers in middle node down */
+ HDmemmove(&(middle_node_ptrs[0]), &(middle_node_ptrs[middle_nrec_move]), sizeof(H5B2_node_ptr_t) * (size_t)((unsigned)(*middle_nrec + 1) - middle_nrec_move));
+ } /* end if */
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, left_node_ptrs,
+ (unsigned)(*left_nrec + 1), (unsigned)(*left_nrec + middle_nrec_move + 1), middle_child, left_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update # of records in left & middle nodes */
+ *left_nrec = (uint16_t)(*left_nrec + middle_nrec_move);
+ *middle_nrec = (uint16_t)(*middle_nrec - middle_nrec_move);
+
+ /* Mark nodes as dirty */
+ left_child_flags |= H5AC__DIRTIED_FLAG;
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ } /* end block */
+
+ /* Redistribute records into middle node */
+ {
+ /* Copy record from parent node to proper location in middle node */
+ HDmemcpy(H5B2_NAT_NREC(middle_native, hdr, *middle_nrec), H5B2_INT_NREC(internal, hdr, idx), hdr->cls->nrec_size);
+
+ /* Copy records from right node to middle node */
+ HDmemcpy(H5B2_NAT_NREC(middle_native, hdr, *middle_nrec + 1), H5B2_NAT_NREC(right_native, hdr, 0), hdr->cls->nrec_size * (*right_nrec));
+
+ /* Move node pointers also if this is an internal node */
+ if(depth > 1)
+ /* Copy node pointers from right node into middle node */
+ HDmemcpy(&(middle_node_ptrs[*middle_nrec + 1]), &(right_node_ptrs[0]), sizeof(H5B2_node_ptr_t) * (size_t)(*right_nrec + 1));
+
+ /* Update flush dependencies for grandchildren, if using SWMR */
+ if(hdr->swmr_write && depth > 1)
+ if(H5B2__update_child_flush_depends(hdr, dxpl_id, depth, middle_node_ptrs,
+ (unsigned)(*middle_nrec + 1), (unsigned)(*middle_nrec + *right_nrec + 2), right_child, middle_child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child nodes to new parent")
+
+ /* Update # of records in middle node */
+ *middle_nrec = (uint16_t)(*middle_nrec + (*right_nrec + 1));
+
+ /* Mark nodes as dirty */
+ middle_child_flags |= H5AC__DIRTIED_FLAG;
+ right_child_flags |= H5AC__DELETED_FLAG;
+ if(!(hdr->swmr_write))
+ right_child_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+ } /* end block */
+
+ /* Update # of records in child nodes */
+ internal->node_ptrs[idx - 1].node_nrec = *left_nrec;
+ internal->node_ptrs[idx].node_nrec = *middle_nrec;
+
+ /* Update total # of records in child B-trees */
+ internal->node_ptrs[idx - 1].all_nrec += middle_moved_nrec;
+ internal->node_ptrs[idx].all_nrec += (internal->node_ptrs[idx + 1].all_nrec + 1) - middle_moved_nrec;
+
+ /* Slide records in parent node down, to eliminate demoted record */
+ if((idx + 1) < internal->nrec) {
+ HDmemmove(H5B2_INT_NREC(internal, hdr, idx), H5B2_INT_NREC(internal, hdr, idx + 1), hdr->cls->nrec_size * (internal->nrec - (idx + 1)));
+ HDmemmove(&(internal->node_ptrs[idx + 1]), &(internal->node_ptrs[idx + 2]), sizeof(H5B2_node_ptr_t) * (internal->nrec - (idx + 1)));
+ } /* end if */
+
+ /* Update # of records in parent node */
+ internal->nrec--;
+
+ /* Mark parent as dirty */
+ *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+ /* Update grandparent info */
+ curr_node_ptr->node_nrec--;
+
+ /* Mark grandparent as dirty, if given */
+ if(parent_cache_info_flags_ptr)
+ *parent_cache_info_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1) {
+ H5B2__assert_internal2(internal->node_ptrs[idx - 1].all_nrec, hdr, (H5B2_internal_t *)left_child, (H5B2_internal_t *)middle_child);
+ H5B2__assert_internal(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)middle_child);
+ } /* end if */
+ else {
+ H5B2__assert_leaf2(hdr, (H5B2_leaf_t *)left_child, (H5B2_leaf_t *)middle_child);
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)middle_child);
+ } /* end else */
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Unlock left & middle nodes (marked as dirty) */
+ if(left_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, left_addr, left_child, left_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+ if(middle_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, middle_addr, middle_child, middle_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ /* Delete right node & remove from cache (marked as dirty) */
+ if(right_child && H5AC_unprotect(hdr->f, dxpl_id, child_class, right_addr, right_child, right_child_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__merge3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__insert
+ *
+ * Purpose: Adds a new record to the B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 23 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__insert(H5B2_hdr_t *hdr, hid_t dxpl_id, void *udata)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(udata);
+
+ /* Check if the root node is allocated yet */
+ if(!H5F_addr_defined(hdr->root.addr)) {
+ /* Create root node as leaf node in B-tree */
+ if(H5B2__create_leaf(hdr, dxpl_id, hdr, &(hdr->root)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create root node")
+ } /* end if */
+ /* Check if we need to split the root node (equiv. to a 1->2 node split) */
+ else if(hdr->root.node_nrec == hdr->node_info[hdr->depth].split_nrec) {
+ /* Split root node */
+ if(H5B2__split_root(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split root node")
+ } /* end if */
+
+ /* Attempt to insert record into B-tree */
+ if(hdr->depth > 0) {
+ if(H5B2__insert_internal(hdr, dxpl_id, hdr->depth, NULL, &hdr->root, H5B2_POS_ROOT, hdr, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__insert_leaf(hdr, dxpl_id, &hdr->root, H5B2_POS_ROOT, hdr, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree leaf node")
+ } /* end else */
+
+ /* Mark B-tree header as dirty */
+ if(H5B2__hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark B-tree header dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__iterate_node
+ *
+ * Purpose: Iterate over all the records from a B-tree node, in "in-order"
+ * order, making a callback for each record.
+ *
+ * If the callback returns non-zero, the iteration breaks out
+ * without finishing all the records.
+ *
+ * Return: Value from callback, non-negative on success, negative on error
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 11 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__iterate_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ const H5B2_node_ptr_t *curr_node, void *parent, H5B2_operator_t op,
+ void *op_data)
+{
+ const H5AC_class_t *curr_node_class = NULL; /* Pointer to current node's class info */
+ void *node = NULL; /* Pointers to current node */
+ uint8_t *node_native; /* Pointers to node's native records */
+ uint8_t *native = NULL; /* Pointers to copy of node's native records */
+ H5B2_node_ptr_t *node_ptrs = NULL; /* Pointers to node's node pointers */
+ hbool_t node_pinned = FALSE; /* Whether node is pinned */
+ unsigned u; /* Local index */
+ herr_t ret_value = H5_ITER_CONT; /* Iterator return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node);
+ HDassert(op);
+
+ /* Protect current node & set up variables */
+ if(depth > 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node */
+
+ /* Lock the current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, (H5B2_node_ptr_t *)curr_node, depth, FALSE, H5AC__READ_ONLY_FLAG))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Set up information about current node */
+ curr_node_class = H5AC_BT2_INT;
+ node = internal;
+ node_native = internal->int_native;
+
+ /* Allocate space for the node pointers in memory */
+ if(NULL == (node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(hdr->node_info[depth].node_ptr_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree internal node pointers")
+
+ /* Copy the node pointers */
+ HDmemcpy(node_ptrs, internal->node_ptrs, (sizeof(H5B2_node_ptr_t) * (size_t)(curr_node->node_nrec + 1)));
+ } /* end if */
+ else {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+
+ /* Lock the current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, (H5B2_node_ptr_t *)curr_node, FALSE, H5AC__READ_ONLY_FLAG))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Set up information about current node */
+ curr_node_class = H5AC_BT2_LEAF;
+ node = leaf;
+ node_native = leaf->leaf_native;
+ } /* end else */
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (native = (uint8_t *)H5FL_FAC_MALLOC(hdr->node_info[depth].nat_rec_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree internal native keys")
+
+ /* Copy the native keys */
+ HDmemcpy(native, node_native, (hdr->cls->nrec_size * curr_node->node_nrec));
+
+ /* Unlock the node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, curr_node_class, curr_node->addr, node, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+ if(hdr->swmr_write)
+ node_pinned = TRUE;
+ else
+ node = NULL;
+
+ /* Iterate through records, in order */
+ for(u = 0; u < curr_node->node_nrec && !ret_value; u++) {
+ /* Descend into child node, if current node is an internal node */
+ if(depth > 0) {
+ if((ret_value = H5B2__iterate_node(hdr, dxpl_id, (uint16_t)(depth - 1), &(node_ptrs[u]), node, op, op_data)) < 0)
+ HERROR(H5E_BTREE, H5E_CANTLIST, "node iteration failed");
+ } /* end if */
+
+ /* Make callback for current record */
+ if(!ret_value) {
+ if((ret_value = (op)(H5B2_NAT_NREC(native, hdr, u), op_data)) < 0)
+ HERROR(H5E_BTREE, H5E_CANTLIST, "iterator function failed");
+ } /* end if */
+ } /* end for */
+
+ /* Descend into last child node, if current node is an internal node */
+ if(!ret_value && depth > 0) {
+ if((ret_value = H5B2__iterate_node(hdr, dxpl_id, (uint16_t)(depth - 1), &(node_ptrs[u]), node, op, op_data)) < 0)
+ HERROR(H5E_BTREE, H5E_CANTLIST, "node iteration failed");
+ } /* end if */
+
+done:
+ /* Unpin the node if it was pinned */
+ if(node_pinned && H5AC_unpin_entry(node) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "can't unpin node")
+
+ /* Release the node pointers & native records, if they were copied */
+ if(node_ptrs)
+ node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_FREE(hdr->node_info[depth].node_ptr_fac, node_ptrs);
+ if(native)
+ native = (uint8_t *)H5FL_FAC_FREE(hdr->node_info[depth].nat_rec_fac, native);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__iterate_node() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__delete_node
+ *
+ * Purpose: Iterate over all the nodes in a B-tree node deleting them
+ * after they no longer have any children
+ *
+ * Return: Value from callback, non-negative on success, negative on error
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__delete_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ const H5B2_node_ptr_t *curr_node, void *parent, H5B2_remove_t op,
+ void *op_data)
+{
+ const H5AC_class_t *curr_node_class = NULL; /* Pointer to current node's class info */
+ void *node = NULL; /* Pointers to current node */
+ uint8_t *native; /* Pointers to node's native records */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node);
+
+ if(depth > 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node */
+ unsigned u; /* Local index */
+
+ /* Lock the current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, (H5B2_node_ptr_t *)curr_node, depth, FALSE, H5AC__NO_FLAGS_SET))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Set up information about current node */
+ curr_node_class = H5AC_BT2_INT;
+ node = internal;
+ native = internal->int_native;
+
+ /* Descend into children */
+ for(u = 0; u < internal->nrec + (unsigned)1; u++)
+ if(H5B2__delete_node(hdr, dxpl_id, (uint16_t)(depth - 1), &(internal->node_ptrs[u]), internal, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "node descent failed")
+ } /* end if */
+ else {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+
+ /* Lock the current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, (H5B2_node_ptr_t *)curr_node, FALSE, H5AC__NO_FLAGS_SET))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Set up information about current node */
+ curr_node_class = H5AC_BT2_LEAF;
+ node = leaf;
+ native = leaf->leaf_native;
+ } /* end else */
+
+ /* If there's a callback defined, iterate over the records in this node */
+ if(op) {
+ unsigned u; /* Local index */
+
+ /* Iterate through records in this node */
+ for(u = 0; u < curr_node->node_nrec; u++) {
+ /* Make callback for each record */
+ if((op)(H5B2_NAT_NREC(native, hdr, u), op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "iterator function failed")
+ } /* end for */
+ } /* end if */
+
+done:
+ /* Unlock & delete current node */
+ if(node && H5AC_unprotect(hdr->f, dxpl_id, curr_node_class, curr_node->addr, node, (unsigned)(H5AC__DELETED_FLAG | (hdr->swmr_write ? 0 : H5AC__FREE_FILE_SPACE_FLAG))) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__delete_node() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__node_size
+ *
+ * Purpose: Iterate over all the records from a B-tree node, collecting
+ * btree storage info.
+ *
+ * Return: non-negative on success, negative on error
+ *
+ * Programmer: Vailin Choi
+ * July 12 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__node_size(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ const H5B2_node_ptr_t *curr_node, void *parent, hsize_t *btree_size)
+{
+ H5B2_internal_t *internal = NULL; /* Pointer to internal node */
+ herr_t ret_value = SUCCEED; /* Iterator return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node);
+ HDassert(btree_size);
+ HDassert(depth > 0);
+
+ /* Lock the current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, (H5B2_node_ptr_t *)curr_node, depth, FALSE, H5AC__READ_ONLY_FLAG))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Recursively descend into child nodes, if we are above the "twig" level in the B-tree */
+ if(depth > 1) {
+ unsigned u; /* Local index */
+
+ /* Descend into children */
+ for(u = 0; u < internal->nrec + (unsigned)1; u++)
+ if(H5B2__node_size(hdr, dxpl_id, (uint16_t)(depth - 1), &(internal->node_ptrs[u]), internal, btree_size) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "node iteration failed")
+ } /* end if */
+ else /* depth is 1: count all the leaf nodes from this node */
+ *btree_size += (hsize_t)(internal->nrec + 1) * hdr->node_size;
+
+ /* Count this node */
+ *btree_size += hdr->node_size;
+
+done:
+ if(internal && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node->addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__node_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__create_flush_depend
+ *
+ * Purpose: Create a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__create_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Create a flush dependency between parent and child entry */
+ if(H5AC_create_flush_dependency(parent_entry, child_entry) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__create_flush_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__update_flush_depend
+ *
+ * Purpose: Update flush dependencies for children of a node
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Dec 1 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__update_flush_depend(H5B2_hdr_t *hdr, hid_t dxpl_id, unsigned depth,
+ const H5B2_node_ptr_t *node_ptr, void *old_parent, void *new_parent)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ void *child = NULL; /* Pointer to child node */
+ unsigned node_status = 0; /* Node's status in the metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(node_ptr);
+ HDassert(old_parent);
+ HDassert(new_parent);
+
+ /* Check the node's entry status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, node_ptr->addr, &node_status) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "unable to check status of B-tree node")
+
+ /* If the node is in the cache, check for retargeting its parent */
+ if(node_status & H5AC_ES__IN_CACHE) {
+ void **parent_ptr; /* Pointer to child node's parent */
+ hbool_t update_deps = FALSE; /* Whether to update flush dependencies */
+
+ /* Get child node pointer */
+ if(depth > 1) {
+ H5B2_internal_t *child_int;
+
+ /* Protect child */
+ if(NULL == (child_int = H5B2__protect_internal(hdr, dxpl_id, new_parent, (H5B2_node_ptr_t *)node_ptr, (uint16_t)(depth - 1), FALSE, H5AC__NO_FLAGS_SET))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ child_class = H5AC_BT2_INT;
+ child = child_int;
+
+ if(child_int->parent == old_parent) {
+ parent_ptr = &child_int->parent;
+ update_deps = TRUE;
+ } /* end if */
+ else
+ HDassert(child_int->parent == new_parent);
+ } /* end if */
+ else {
+ H5B2_leaf_t *child_leaf;
+
+ /* Protect child */
+ if(NULL == (child_leaf = H5B2__protect_leaf(hdr, dxpl_id, new_parent, (H5B2_node_ptr_t *)node_ptr, FALSE, H5AC__NO_FLAGS_SET))) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ child_class = H5AC_BT2_LEAF;
+ child = child_leaf;
+
+ if(child_leaf->parent == old_parent) {
+ parent_ptr = &child_leaf->parent;
+ update_deps = TRUE;
+ } /* end if */
+ else
+ HDassert(child_leaf->parent == new_parent);
+ } /* end else */
+
+ /* Update flush dependencies if necessary */
+ if(update_deps) {
+ /* Sanity check */
+ HDassert(parent_ptr);
+
+ /* Switch the flush dependency for the node */
+ if(H5B2__destroy_flush_depend((H5AC_info_t *)old_parent, (H5AC_info_t *)child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ *parent_ptr = new_parent;
+ if(H5B2__create_flush_depend((H5AC_info_t *)new_parent, (H5AC_info_t *)child) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Unprotect the child */
+ if(child)
+ if(H5AC_unprotect(hdr->f, dxpl_id, child_class, node_ptr->addr, child, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__update_flush_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__update_child_flush_depends
+ *
+ * Purpose: Update flush dependencies for children of a node
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Dec 1 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__update_child_flush_depends(H5B2_hdr_t *hdr, hid_t dxpl_id, unsigned depth,
+ const H5B2_node_ptr_t *node_ptrs, unsigned start_idx, unsigned end_idx,
+ void *old_parent, void *new_parent)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(hdr);
+ HDassert(depth > 1);
+ HDassert(node_ptrs);
+ HDassert(start_idx <= end_idx);
+ HDassert(old_parent);
+ HDassert(new_parent);
+
+ /* Loop over children */
+ for(u = start_idx; u < end_idx; u++)
+ /* Update parent for children */
+ if(H5B2__update_flush_depend(hdr, dxpl_id, depth - 1, &node_ptrs[u], old_parent, new_parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child node to new parent")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__update_child_flush_depends() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__destroy_flush_depend
+ *
+ * Purpose: Destroy a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__destroy_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Destroy a flush dependency between parent and child entry */
+ if(H5AC_destroy_flush_dependency(parent_entry, child_entry) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__destroy_flush_depend() */
+
diff --git a/src/H5B2internal.c b/src/H5B2internal.c
new file mode 100644
index 0000000..1716c44
--- /dev/null
+++ b/src/H5B2internal.c
@@ -0,0 +1,1441 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2internal.c
+ * Dec 01 2016
+ * Quincey Koziol <koziol@lbl.gov>
+ *
+ * Purpose: Routines for managing v2 B-tree internal ndoes.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5B2__shadow_internal(H5B2_internal_t *internal, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5B2_internal_t struct */
+H5FL_DEFINE(H5B2_internal_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__create_internal
+ *
+ * Purpose: Creates empty internal node of a B-tree and update node pointer
+ * to point to it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__create_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ H5B2_node_ptr_t *node_ptr, uint16_t depth)
+{
+ H5B2_internal_t *internal = NULL; /* Pointer to new internal node created */
+ hbool_t inserted = FALSE; /* Whether the internal node was inserted into cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(node_ptr);
+ HDassert(depth > 0);
+
+ /* Allocate memory for internal node information */
+ if(NULL == (internal = H5FL_CALLOC(H5B2_internal_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree internal info")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, FAIL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree header information */
+ internal->hdr = hdr;
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (internal->int_native = (uint8_t *)H5FL_FAC_MALLOC(hdr->node_info[depth].nat_rec_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree internal native keys")
+ HDmemset(internal->int_native, 0, hdr->cls->nrec_size * hdr->node_info[depth].max_nrec);
+
+ /* Allocate space for the node pointers in memory */
+ if(NULL == (internal->node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(hdr->node_info[depth].node_ptr_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree internal node pointers")
+ HDmemset(internal->node_ptrs, 0, sizeof(H5B2_node_ptr_t) * (hdr->node_info[depth].max_nrec + 1));
+
+ /* Set depth of the node */
+ internal->depth = depth;
+
+ /* Set parent */
+ internal->parent = parent;
+
+ /* Set shadowed epoch to header's epoch */
+ internal->shadow_epoch = hdr->shadow_epoch;
+
+ /* Allocate space on disk for the internal node */
+ if(HADDR_UNDEF == (node_ptr->addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)hdr->node_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for B-tree internal node")
+
+ /* Cache the new B-tree node */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_BT2_INT, node_ptr->addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree internal node to cache")
+ inserted = TRUE;
+
+ /* Add internal node as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree node as child of proxy")
+ internal->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+done:
+ if(ret_value < 0) {
+ if(internal) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(internal) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "unable to remove v2 B-tree internal node from cache")
+
+ /* Release internal node's disk space */
+ if(H5F_addr_defined(node_ptr->addr) && H5MF_xfree(hdr->f, H5FD_MEM_BTREE, dxpl_id, node_ptr->addr, (hsize_t)hdr->node_size) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release file space for v2 B-tree internal node")
+
+ /* Destroy internal node */
+ if(H5B2__internal_free(internal) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__create_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__protect_internal
+ *
+ * Purpose: "Protect" an internal node in the metadata cache
+ *
+ * Return: Pointer to internal node on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_internal_t *
+H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ H5B2_node_ptr_t *node_ptr, uint16_t depth, hbool_t shadow, unsigned flags)
+{
+ H5B2_internal_cache_ud_t udata; /* User data to pass through to cache 'deserialize' callback */
+ H5B2_internal_t *internal = NULL; /* v2 B-tree internal node */
+ H5B2_internal_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(node_ptr);
+ HDassert(H5F_addr_defined(node_ptr->addr));
+ HDassert(depth > 0);
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data for callback */
+ udata.f = hdr->f;
+ udata.hdr = hdr;
+ udata.parent = parent;
+ udata.nrec = node_ptr->node_nrec;
+ udata.depth = depth;
+
+ /* Protect the internal node */
+ if(NULL == (internal = (H5B2_internal_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_INT, node_ptr->addr, &udata, flags)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree internal node")
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == internal->top_proxy) {
+ /* Add internal node as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree internal node as child of proxy")
+ internal->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Shadow the node, if requested */
+ if(shadow)
+ if(H5B2__shadow_internal(internal, dxpl_id, node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, NULL, "unable to shadow internal node")
+
+ /* Set return value */
+ ret_value = internal;
+
+done:
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the internal node, if it was protected */
+ if(internal) {
+ /* Remove from v2 B-tree's proxy, if added */
+ if(internal->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(internal->top_proxy, internal) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, NULL, "unable to destroy flush dependency between internal node and v2 B-tree 'top' proxy")
+ internal->top_proxy = NULL;
+ } /* end if */
+
+ /* Unprotect internal node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, node_ptr->addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to unprotect v2 B-tree internal node, address = %llu", (unsigned long long)node_ptr->addr)
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__protect_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__neighbor_internal
+ *
+ * Purpose: Locate a record relative to the specified information in a
+ * B-tree internal node and return that information by filling in
+ * fields of the
+ * caller-supplied UDATA pointer depending on the type of leaf node
+ * requested. The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to return information about
+ * the record.
+ *
+ * The RANGE indicates whether to search for records less than or
+ * equal to, or greater than or equal to the information passed
+ * in with UDATA.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__neighbor_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, void *neighbor_loc, H5B2_compare_t comp,
+ void *parent, void *udata, H5B2_found_t op, void *op_data)
+{
+ H5B2_internal_t *internal; /* Pointer to internal node */
+ unsigned idx = 0; /* Location of record which matches key */
+ int cmp = 0; /* Comparison value of records */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+ HDassert(op);
+
+ /* Lock current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, curr_node_ptr, depth, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp > 0)
+ idx++;
+
+ /* Set the neighbor location, if appropriate */
+ if(comp == H5B2_COMPARE_LESS) {
+ if(idx > 0)
+ neighbor_loc = H5B2_INT_NREC(internal, hdr, idx - 1);
+ } /* end if */
+ else {
+ HDassert(comp == H5B2_COMPARE_GREATER);
+
+ if(idx < internal->nrec)
+ neighbor_loc = H5B2_INT_NREC(internal, hdr, idx);
+ } /* end else */
+
+ /* Attempt to find neighboring record */
+ if(depth > 1) {
+ if(H5B2__neighbor_internal(hdr, dxpl_id, (uint16_t)(depth - 1), &internal->node_ptrs[idx], neighbor_loc, comp, internal, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__neighbor_leaf(hdr, dxpl_id, &internal->node_ptrs[idx], neighbor_loc, comp, internal, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree leaf node")
+ } /* end else */
+
+done:
+ /* Release the B-tree internal node */
+ if(internal && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr->addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__neighbor_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__insert_internal
+ *
+ * Purpose: Adds a new record to a B-tree node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__insert_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ unsigned *parent_cache_info_flags_ptr, H5B2_node_ptr_t *curr_node_ptr,
+ H5B2_nodepos_t curr_pos, void *parent, void *udata)
+{
+ H5B2_internal_t *internal = NULL; /* Pointer to internal node */
+ unsigned internal_flags = H5AC__NO_FLAGS_SET;
+ unsigned idx = 0; /* Location of record which matches key */
+ H5B2_nodepos_t next_pos = H5B2_POS_MIDDLE; /* Position of node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, curr_node_ptr, depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Sanity check number of records */
+ HDassert(internal->nrec == curr_node_ptr->node_nrec);
+
+ /* Split or redistribute child node pointers, if necessary */
+ {
+ int cmp; /* Comparison value of records */
+ unsigned retries; /* Number of times to attempt redistribution */
+ size_t split_nrec; /* Number of records to split node at */
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native,
+ udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp == 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_EXISTS, FAIL, "record is already in B-tree")
+ if(cmp > 0)
+ idx++;
+
+ /* Set the number of redistribution retries */
+ /* This takes care of the case where a B-tree node needs to be
+ * redistributed, but redistributing the node causes the index
+ * for insertion to move to another node, which also needs to be
+ * redistributed. Now, we loop trying to redistribute and then
+ * eventually force a split */
+ retries = 2;
+
+ /* Determine the correct number of records to split child node at */
+ split_nrec = hdr->node_info[depth - 1].split_nrec;
+
+ /* Preemptively split/redistribute a node we will enter */
+ while(internal->node_ptrs[idx].node_nrec == split_nrec) {
+ /* Attempt to redistribute records among children */
+ if(idx == 0) { /* Left-most child */
+ if(retries > 0 && (internal->node_ptrs[idx + 1].node_nrec < split_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__split1(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split child node")
+ } /* end else */
+ } /* end if */
+ else if(idx == internal->nrec) { /* Right-most child */
+ if(retries > 0 && (internal->node_ptrs[idx - 1].node_nrec < split_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, (idx - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__split1(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split child node")
+ } /* end else */
+ } /* end if */
+ else { /* Middle child */
+ if(retries > 0 && ((internal->node_ptrs[idx + 1].node_nrec < split_nrec) ||
+ (internal->node_ptrs[idx - 1].node_nrec < split_nrec))) {
+ if(H5B2__redistribute3(hdr, dxpl_id, depth, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__split1(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to split child node")
+ } /* end else */
+ } /* end else */
+
+ /* Locate node pointer for child (after split/redistribute) */
+ /* Actually, this can be easily updated (for 2-node redistrib.) and shouldn't require re-searching */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native,
+ udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp == 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_EXISTS, FAIL, "record is already in B-tree")
+ if(cmp > 0)
+ idx++;
+
+ /* Decrement the number of redistribution retries left */
+ retries--;
+ } /* end while */
+ } /* end block */
+
+ /* Check if this node is left/right-most */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_LEFT;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_RIGHT;
+ } /* end else */
+ } /* end if */
+
+ /* Attempt to insert node */
+ if(depth > 1) {
+ if(H5B2__insert_internal(hdr, dxpl_id, (uint16_t)(depth - 1), &internal_flags, &internal->node_ptrs[idx], next_pos, internal, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__insert_leaf(hdr, dxpl_id, &internal->node_ptrs[idx], next_pos, internal, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into B-tree leaf node")
+ } /* end else */
+
+ /* Update record count for node pointer to current node */
+ curr_node_ptr->all_nrec++;
+
+ /* Mark node as dirty */
+ internal_flags |= H5AC__DIRTIED_FLAG;
+
+done:
+ /* Release the B-tree internal node */
+ if(internal) {
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write && (internal_flags & H5AC__DIRTIED_FLAG))
+ if(H5B2__shadow_internal(internal, dxpl_id, curr_node_ptr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow internal B-tree node")
+
+ /* Unprotect node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr->addr, internal, internal_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__insert_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__update_internal
+ *
+ * Purpose: Insert or modify a record in a B-tree internal node.
+ * If the record exists already, it is modified as if H5B2_modify
+ * was called). If it doesn't exist, it is inserted as if
+ * H5B2_insert was called.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 24 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__update_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ unsigned *parent_cache_info_flags_ptr, H5B2_node_ptr_t *curr_node_ptr,
+ H5B2_update_status_t *status, H5B2_nodepos_t curr_pos, void *parent,
+ void *udata, H5B2_modify_t op, void *op_data)
+{
+ H5B2_internal_t *internal = NULL; /* Pointer to internal node */
+ unsigned internal_flags = H5AC__NO_FLAGS_SET;
+ int cmp; /* Comparison value of records */
+ unsigned idx = 0; /* Location of record which matches key */
+ H5B2_nodepos_t next_pos = H5B2_POS_MIDDLE; /* Position of node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, curr_node_ptr, depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+
+ /* Sanity check number of records */
+ HDassert(internal->nrec == curr_node_ptr->node_nrec);
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ /* Check for modifying existing record */
+ if(0 == cmp) {
+ hbool_t changed = FALSE; /* Whether the 'modify' callback changed the record */
+
+ /* Make callback for current record */
+ if((op)(H5B2_INT_NREC(internal, hdr, idx), op_data, &changed) < 0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed == FALSE);
+
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL, "'modify' callback failed for B-tree update operation")
+ } /* end if */
+
+ /* Mark the node as dirty if it changed */
+ internal_flags |= (changed ? H5AC__DIRTIED_FLAG : 0);
+
+ /* Indicate that the record was modified */
+ *status = H5B2_UPDATE_MODIFY_DONE;
+ } /* end if */
+ else {
+ /* Adjust index to leave room for node to insert */
+ if(cmp > 0)
+ idx++;
+
+ /* Check if this node is left/right-most */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_LEFT;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_RIGHT;
+ } /* end else */
+ } /* end if */
+
+ /* Attempt to update record in child */
+ if(depth > 1) {
+ if(H5B2__update_internal(hdr, dxpl_id, (uint16_t)(depth - 1), &internal_flags, &internal->node_ptrs[idx], status, next_pos, internal, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in internal B-tree node")
+ } /* end if */
+ else {
+ if(H5B2__update_leaf(hdr, dxpl_id, &internal->node_ptrs[idx], status, next_pos, internal, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update record in leaf B-tree node")
+ } /* end else */
+
+ /* Take actions based on child's status report */
+ switch(*status) {
+ case H5B2_UPDATE_MODIFY_DONE:
+ /* No action */
+ break;
+
+ case H5B2_UPDATE_SHADOW_DONE:
+ /* If child node was shadowed (if SWMR is enabled), mark this node dirty */
+ if(hdr->swmr_write)
+ internal_flags |= H5AC__DIRTIED_FLAG;
+
+ /* No further modifications up the tree are necessary though, so downgrade to merely "modified" */
+ *status = H5B2_UPDATE_MODIFY_DONE;
+ break;
+
+ case H5B2_UPDATE_INSERT_DONE:
+ /* Mark node as dirty */
+ internal_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Update total record count for node pointer to current node */
+ curr_node_ptr->all_nrec++;
+ break;
+
+ case H5B2_UPDATE_INSERT_CHILD_FULL:
+ /* Split/redistribute this node */
+ if(internal->nrec == hdr->node_info[depth].split_nrec) {
+ hbool_t could_split = FALSE; /* Whether the child node could split */
+
+ if(idx == 0) { /* Left-most child */
+ /* Check for left-most child and its neighbor being close to full */
+ if((internal->node_ptrs[idx].node_nrec + internal->node_ptrs[idx + 1].node_nrec)
+ >= ((hdr->node_info[depth - 1].split_nrec * 2) - 1))
+ could_split = TRUE;
+ } /* end if */
+ else if(idx == internal->nrec) { /* Right-most child */
+ /* Check for right-most child and its neighbor being close to full */
+ if((internal->node_ptrs[idx - 1].node_nrec + internal->node_ptrs[idx].node_nrec)
+ >= ((hdr->node_info[depth - 1].split_nrec * 2) - 1))
+ could_split = TRUE;
+ } /* end else-if */
+ else { /* Middle child */
+ /* Check for middle child and its left neighbor being close to full */
+ if((internal->node_ptrs[idx - 1].node_nrec + internal->node_ptrs[idx].node_nrec)
+ >= ((hdr->node_info[depth - 1].split_nrec * 2) - 1))
+ could_split = TRUE;
+ /* Check for middle child and its right neighbor being close to full */
+ else if((internal->node_ptrs[idx].node_nrec + internal->node_ptrs[idx + 1].node_nrec)
+ >= ((hdr->node_info[depth - 1].split_nrec * 2) - 1))
+ could_split = TRUE;
+ } /* end if */
+
+ /* If this node is full and the child node insertion could
+ * cause a split, punt back up to caller, leaving the
+ * "insert child full" status.
+ */
+ if(could_split) {
+ /* Release the internal B-tree node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr->addr, internal, internal_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+ internal = NULL;
+
+ /* Punt back to caller */
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+ } /* end if */
+
+ /* Release the internal B-tree node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr->addr, internal, internal_flags) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+ internal = NULL;
+
+ /* Indicate that the record was inserted */
+ *status = H5B2_UPDATE_INSERT_DONE;
+
+ /* Dodge sideways into inserting a record into this node */
+ if(H5B2__insert_internal(hdr, dxpl_id, depth, parent_cache_info_flags_ptr, curr_node_ptr, curr_pos, parent, udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into internal B-tree node")
+ break;
+
+ case H5B2_UPDATE_UNKNOWN:
+ default:
+ HDassert(0 && "Invalid update status");
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "invalid update status")
+ } /* end switch */
+ } /* end else */
+
+done:
+ /* Release the internal B-tree node */
+ if(internal) {
+ /* Check if we should shadow this node */
+ if(hdr->swmr_write && (internal_flags & H5AC__DIRTIED_FLAG)) {
+ /* Attempt to shadow the node if doing SWMR writes */
+ if(H5B2__shadow_internal(internal, dxpl_id, curr_node_ptr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow internal B-tree node")
+
+ /* Change the state to "shadowed" if only modified currently */
+ /* (Triggers parent to be marked dirty) */
+ if(*status == H5B2_UPDATE_MODIFY_DONE)
+ *status = H5B2_UPDATE_SHADOW_DONE;
+ } /* end if */
+
+ /* Unprotect node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr->addr, internal, internal_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__update_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__shadow_internal
+ *
+ * Purpose: "Shadow" an internal node - copy it to a new location,
+ * leaving the data in the old location intact (for now).
+ * This is done when writing in SWMR mode to ensure that
+ * readers do not see nodes that are out of date with
+ * respect to each other and thereby inconsistent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Apr 27 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__shadow_internal(H5B2_internal_t *internal, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr)
+{
+ H5B2_hdr_t *hdr; /* B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(internal);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+ hdr = internal->hdr;
+ HDassert(hdr);
+ HDassert(hdr->swmr_write);
+
+ /* We only need to shadow the node if it has not been shadowed since the
+ * last time the header was flushed, as otherwise it will be unreachable by
+ * the readers so there will be no need to shadow. To check if it has been
+ * shadowed, compare the epoch of this node and the header. If this node's
+ * epoch is <= to the header's, it hasn't been shadowed yet. */
+ if(internal->shadow_epoch <= hdr->shadow_epoch) {
+ haddr_t new_node_addr; /* Address to move node to */
+
+ /*
+ * We must clone the old node so readers with an out-of-date version of
+ * the parent can still see the correct number of children, via the
+ * shadowed node. Remove it from cache but do not mark it free on disk.
+ */
+ /* Allocate space for the cloned node */
+ if(HADDR_UNDEF == (new_node_addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)hdr->node_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move B-tree node")
+
+ /* Move the location of the node on the disk */
+ if(H5AC_move_entry(hdr->f, H5AC_BT2_INT, curr_node_ptr->addr, new_node_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree node")
+ curr_node_ptr->addr = new_node_addr;
+
+ /* Should free the space in the file, but this is not supported by
+ * SWMR_WRITE code yet - QAK, 2016/12/01
+ */
+
+ /* Set shadow epoch for node ahead of header */
+ internal->shadow_epoch = hdr->shadow_epoch + 1;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__shadow_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__remove_internal
+ *
+ * Purpose: Removes a record from a B-tree node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__remove_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, hbool_t *depth_decreased,
+ void *swap_loc, void *swap_parent, uint16_t depth, H5AC_info_t *parent_cache_info,
+ unsigned *parent_cache_info_flags_ptr, H5B2_nodepos_t curr_pos,
+ H5B2_node_ptr_t *curr_node_ptr, void *udata, H5B2_remove_t op, void *op_data)
+{
+ H5AC_info_t *new_cache_info; /* Pointer to new cache info */
+ unsigned *new_cache_info_flags_ptr = NULL;
+ H5B2_node_ptr_t *new_node_ptr; /* Pointer to new node pointer */
+ H5B2_internal_t *internal; /* Pointer to internal node */
+ H5B2_nodepos_t next_pos = H5B2_POS_MIDDLE; /* Position of next node */
+ unsigned internal_flags = H5AC__NO_FLAGS_SET;
+ haddr_t internal_addr = HADDR_UNDEF; /* Address of internal node */
+ size_t merge_nrec; /* Number of records to merge node at */
+ hbool_t collapsed_root = FALSE; /* Whether the root was collapsed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(parent_cache_info);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent_cache_info, curr_node_ptr, depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ internal_addr = curr_node_ptr->addr;
+
+ /* Determine the correct number of records to merge at */
+ merge_nrec = hdr->node_info[depth - 1].merge_nrec;
+
+ /* Check for needing to collapse the root node */
+ /* (The root node is the only internal node allowed to have 1 record) */
+ if(internal->nrec == 1 &&
+ ((internal->node_ptrs[0].node_nrec + internal->node_ptrs[1].node_nrec) <= ((merge_nrec * 2) + 1))) {
+
+ /* Merge children of root node */
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, 0) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+
+ /* Let the cache know that the object is deleted */
+ internal_flags |= H5AC__DELETED_FLAG;
+ if(!hdr->swmr_write)
+ internal_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+ /* Reset information in header's root node pointer */
+ curr_node_ptr->addr = internal->node_ptrs[0].addr;
+ curr_node_ptr->node_nrec = internal->node_ptrs[0].node_nrec;
+
+ /* Update flush dependency for child, if using SWMR */
+ if(hdr->swmr_write)
+ if(H5B2__update_flush_depend(hdr, dxpl_id, depth, curr_node_ptr, internal, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child node to new parent")
+
+ /* Indicate that the level of the B-tree decreased */
+ *depth_decreased = TRUE;
+
+ /* Set pointers for advancing to child node */
+ new_cache_info = parent_cache_info;
+ new_cache_info_flags_ptr = parent_cache_info_flags_ptr;
+ new_node_ptr = curr_node_ptr;
+
+ /* Set flag to indicate root was collapsed */
+ collapsed_root = TRUE;
+
+ /* Indicate position of next node */
+ next_pos = H5B2_POS_ROOT;
+ } /* end if */
+ /* Merge or redistribute child node pointers, if necessary */
+ else {
+ unsigned idx = 0; /* Location of record which matches key */
+ int cmp = 0; /* Comparison value of records */
+ unsigned retries; /* Number of times to attempt redistribution */
+
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write) {
+ if(H5B2__shadow_internal(internal, dxpl_id, curr_node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow internal node")
+ internal_addr = curr_node_ptr->addr;
+ } /* end if */
+
+ /* Locate node pointer for child */
+ if(swap_loc)
+ idx = 0;
+ else {
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp >= 0)
+ idx++;
+ } /* end else */
+
+ /* Set the number of redistribution retries */
+ /* This takes care of the case where a B-tree node needs to be
+ * redistributed, but redistributing the node causes the index
+ * for removal to move to another node, which also needs to be
+ * redistributed. Now, we loop trying to redistribute and then
+ * eventually force a merge */
+ retries = 2;
+
+ /* Preemptively merge/redistribute a node we will enter */
+ while(internal->node_ptrs[idx].node_nrec == merge_nrec) {
+ /* Attempt to redistribute records among children */
+ /* (NOTE: These 2-node redistributions should actually get the
+ * record to promote from the node with more records. - QAK)
+ */
+ /* (NOTE: This code is the same in both H5B2__remove_internal() and
+ * H5B2__remove_internal_by_idx(), fix bugs in both places! - QAK)
+ */
+ if(idx == 0) { /* Left-most child */
+ if(retries > 0 && (internal->node_ptrs[idx + 1].node_nrec > merge_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end if */
+ else if(idx == internal->nrec) { /* Right-most child */
+ if(retries > 0 && (internal->node_ptrs[idx - 1].node_nrec > merge_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, (idx - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, (idx - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end if */
+ else { /* Middle child */
+ if(retries > 0 && ((internal->node_ptrs[idx + 1].node_nrec > merge_nrec) ||
+ (internal->node_ptrs[idx - 1].node_nrec > merge_nrec))) {
+ if(H5B2__redistribute3(hdr, dxpl_id, depth, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge3(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end else */
+
+ /* Locate node pointer for child (after merge/redistribute) */
+ if(swap_loc)
+ idx = 0;
+ else {
+/* Actually, this can be easily updated (for 2-node redistrib.) and shouldn't require re-searching */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp >= 0)
+ idx++;
+ } /* end else */
+
+ /* Decrement the number of redistribution retries left */
+ retries--;
+ } /* end while */
+
+ /* Handle deleting a record from an internal node */
+ if(!swap_loc && cmp == 0) {
+ swap_loc = H5B2_INT_NREC(internal, hdr, idx - 1);
+ swap_parent = internal;
+ } /* end if */
+
+ /* Swap record to delete with record from leaf, if we are the last internal node */
+ if(swap_loc && depth == 1)
+ if(H5B2__swap_leaf(hdr, dxpl_id, depth, internal, &internal_flags, idx, swap_loc) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSWAP, FAIL, "Can't swap records in B-tree")
+
+ /* Set pointers for advancing to child node */
+ new_cache_info_flags_ptr = &internal_flags;
+ new_cache_info = &internal->cache_info;
+ new_node_ptr = &internal->node_ptrs[idx];
+
+ /* Indicate position of next node */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_LEFT;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_RIGHT;
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Attempt to remove record from child node */
+ if(depth > 1) {
+ if(H5B2__remove_internal(hdr, dxpl_id, depth_decreased, swap_loc, swap_parent, (uint16_t)(depth - 1),
+ new_cache_info, new_cache_info_flags_ptr, next_pos, new_node_ptr, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__remove_leaf(hdr, dxpl_id, new_node_ptr, next_pos, new_cache_info, udata, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
+ } /* end else */
+
+ /* Update record count for node pointer to current node */
+ if(!collapsed_root)
+ new_node_ptr->all_nrec--;
+
+ /* Mark node as dirty */
+ if(!(hdr->swmr_write && collapsed_root))
+ internal_flags |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((!collapsed_root ? (curr_node_ptr->all_nrec - 1) : new_node_ptr->all_nrec), hdr, internal);
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Release the B-tree internal node */
+ if(internal && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, internal_addr, internal, internal_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__remove_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__remove_internal_by_idx
+ *
+ * Purpose: Removes a record from a B-tree node, according to the offset
+ * in the B-tree records
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__remove_internal_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t *depth_decreased, void *swap_loc, void *swap_parent, uint16_t depth,
+ H5AC_info_t *parent_cache_info, unsigned *parent_cache_info_flags_ptr,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, hsize_t n,
+ H5B2_remove_t op, void *op_data)
+{
+ H5AC_info_t *new_cache_info; /* Pointer to new cache info */
+ unsigned *new_cache_info_flags_ptr = NULL;
+ H5B2_node_ptr_t *new_node_ptr; /* Pointer to new node pointer */
+ H5B2_internal_t *internal; /* Pointer to internal node */
+ H5B2_nodepos_t next_pos = H5B2_POS_MIDDLE; /* Position of next node */
+ unsigned internal_flags = H5AC__NO_FLAGS_SET;
+ haddr_t internal_addr = HADDR_UNDEF; /* Address of internal node */
+ size_t merge_nrec; /* Number of records to merge node at */
+ hbool_t collapsed_root = FALSE; /* Whether the root was collapsed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(depth > 0);
+ HDassert(parent_cache_info);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent_cache_info, curr_node_ptr, depth, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ internal_addr = curr_node_ptr->addr;
+ HDassert(internal->nrec == curr_node_ptr->node_nrec);
+ HDassert(depth == hdr->depth || internal->nrec > 1);
+
+ /* Determine the correct number of records to merge at */
+ merge_nrec = hdr->node_info[depth - 1].merge_nrec;
+
+ /* Check for needing to collapse the root node */
+ /* (The root node is the only internal node allowed to have 1 record) */
+ if(internal->nrec == 1 &&
+ ((internal->node_ptrs[0].node_nrec + internal->node_ptrs[1].node_nrec) <= ((merge_nrec * 2) + 1))) {
+ HDassert(depth == hdr->depth);
+
+ /* Merge children of root node */
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, 0) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+
+ /* Let the cache know that the object is deleted */
+ internal_flags |= H5AC__DELETED_FLAG;
+ if(!hdr->swmr_write)
+ internal_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+ /* Reset information in header's root node pointer */
+ curr_node_ptr->addr = internal->node_ptrs[0].addr;
+ curr_node_ptr->node_nrec = internal->node_ptrs[0].node_nrec;
+
+ /* Update flush dependency for child, if using SWMR */
+ if(hdr->swmr_write)
+ if(H5B2__update_flush_depend(hdr, dxpl_id, depth, curr_node_ptr, internal, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUPDATE, FAIL, "unable to update child node to new parent")
+
+ /* Indicate that the level of the B-tree decreased */
+ *depth_decreased = TRUE;
+
+ /* Set pointers for advancing to child node */
+ new_cache_info = parent_cache_info;
+ new_cache_info_flags_ptr = parent_cache_info_flags_ptr;
+ new_node_ptr = curr_node_ptr;
+
+ /* Set flag to indicate root was collapsed */
+ collapsed_root = TRUE;
+
+ /* Indicate position of next node */
+ next_pos = H5B2_POS_ROOT;
+ } /* end if */
+ /* Merge or redistribute child node pointers, if necessary */
+ else {
+ hsize_t orig_n = n; /* Original index looked for */
+ unsigned idx; /* Location of record which matches key */
+ hbool_t found = FALSE; /* Comparison value of records */
+ unsigned retries; /* Number of times to attempt redistribution */
+
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write) {
+ if(H5B2__shadow_internal(internal, dxpl_id, curr_node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow internal node")
+ internal_addr = curr_node_ptr->addr;
+ } /* end if */
+
+ /* Locate node pointer for child */
+ if(swap_loc)
+ idx = 0;
+ else {
+ /* Search for record with correct index */
+ for(idx = 0; idx < internal->nrec; idx++) {
+ /* Check which child node contains indexed record */
+ if(internal->node_ptrs[idx].all_nrec >= n) {
+ /* Check if record is in this node */
+ if(internal->node_ptrs[idx].all_nrec == n) {
+ /* Indicate the record was found and that the index
+ * in child nodes is zero from now on
+ */
+ found = TRUE;
+ n = 0;
+
+ /* Increment to next record */
+ idx++;
+ } /* end if */
+
+ /* Break out of loop early */
+ break;
+ } /* end if */
+
+ /* Decrement index we are looking for to account for the node we
+ * just advanced past.
+ */
+ n -= (internal->node_ptrs[idx].all_nrec + 1);
+ } /* end for */
+ } /* end else */
+
+ /* Set the number of redistribution retries */
+ /* This takes care of the case where a B-tree node needs to be
+ * redistributed, but redistributing the node causes the index
+ * for removal to move to another node, which also needs to be
+ * redistributed. Now, we loop trying to redistribute and then
+ * eventually force a merge */
+ retries = 2;
+
+ /* Preemptively merge/redistribute a node we will enter */
+ while(internal->node_ptrs[idx].node_nrec == merge_nrec) {
+ /* Attempt to redistribute records among children */
+ /* (NOTE: These 2-node redistributions should actually get the
+ * record to promote from the node with more records. - QAK)
+ */
+ /* (NOTE: This code is the same in both H5B2__remove_internal() and
+ * H5B2__remove_internal_by_idx(), fix bugs in both places! - QAK)
+ */
+ if(idx == 0) { /* Left-most child */
+ if(retries > 0 && (internal->node_ptrs[idx + 1].node_nrec > merge_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end if */
+ else if(idx == internal->nrec) { /* Right-most child */
+ if(retries > 0 && (internal->node_ptrs[idx - 1].node_nrec > merge_nrec)) {
+ if(H5B2__redistribute2(hdr, dxpl_id, depth, internal, (idx - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge2(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, (idx - 1)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end if */
+ else { /* Middle child */
+ if(retries > 0 && ((internal->node_ptrs[idx + 1].node_nrec > merge_nrec) ||
+ (internal->node_ptrs[idx - 1].node_nrec > merge_nrec))) {
+ if(H5B2__redistribute3(hdr, dxpl_id, depth, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREDISTRIBUTE, FAIL, "unable to redistribute child node records")
+ } /* end if */
+ else {
+ if(H5B2__merge3(hdr, dxpl_id, depth, curr_node_ptr,
+ parent_cache_info_flags_ptr, internal, &internal_flags, idx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to merge child node")
+ } /* end else */
+ } /* end else */
+
+ /* Locate node pointer for child (after merge/redistribute) */
+ if(swap_loc)
+ idx = 0;
+ else {
+ /* Count from the orginal index value again */
+ n = orig_n;
+
+ /* Reset "found" flag - the record may have shifted during the
+ * redistribute/merge
+ */
+ found = FALSE;
+
+ /* Search for record with correct index */
+ for(idx = 0; idx < internal->nrec; idx++) {
+ /* Check which child node contains indexed record */
+ if(internal->node_ptrs[idx].all_nrec >= n) {
+ /* Check if record is in this node */
+ if(internal->node_ptrs[idx].all_nrec == n) {
+ /* Indicate the record was found and that the index
+ * in child nodes is zero from now on
+ */
+ found = TRUE;
+ n = 0;
+
+ /* Increment to next record */
+ idx++;
+ } /* end if */
+
+ /* Break out of loop early */
+ break;
+ } /* end if */
+
+ /* Decrement index we are looking for to account for the node we
+ * just advanced past.
+ */
+ n -= (internal->node_ptrs[idx].all_nrec + 1);
+ } /* end for */
+ } /* end else */
+
+ /* Decrement the number of redistribution retries left */
+ retries--;
+ } /* end while */
+
+ /* Handle deleting a record from an internal node */
+ if(!swap_loc && found) {
+ swap_loc = H5B2_INT_NREC(internal, hdr, idx - 1);
+ swap_parent = internal;
+ } /* end if */
+
+ /* Swap record to delete with record from leaf, if we are the last internal node */
+ if(swap_loc && depth == 1)
+ if(H5B2__swap_leaf(hdr, dxpl_id, depth, internal, &internal_flags, idx, swap_loc) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSWAP, FAIL, "can't swap records in B-tree")
+
+ /* Set pointers for advancing to child node */
+ new_cache_info_flags_ptr = &internal_flags;
+ new_cache_info = &internal->cache_info;
+ new_node_ptr = &internal->node_ptrs[idx];
+
+ /* Indicate position of next node */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_LEFT;
+ } /* end if */
+ else if(idx == internal->nrec) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos)
+ next_pos = H5B2_POS_RIGHT;
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Attempt to remove record from child node */
+ if(depth > 1) {
+ if(H5B2__remove_internal_by_idx(hdr, dxpl_id, depth_decreased, swap_loc, swap_parent, (uint16_t)(depth - 1),
+ new_cache_info, new_cache_info_flags_ptr, new_node_ptr, next_pos, n, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree internal node")
+ } /* end if */
+ else {
+ if(H5B2__remove_leaf_by_idx(hdr, dxpl_id, new_node_ptr, next_pos, new_cache_info, (unsigned)n, op, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record from B-tree leaf node")
+ } /* end else */
+
+ /* Update record count for node pointer to child node */
+ if(!collapsed_root)
+ new_node_ptr->all_nrec--;
+
+ /* Mark node as dirty */
+ if(!(hdr->swmr_write && collapsed_root))
+ internal_flags |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((!collapsed_root ? (curr_node_ptr->all_nrec - 1) : new_node_ptr->all_nrec), hdr, internal);
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Release the B-tree internal node */
+ if(internal && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, internal_addr, internal, internal_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release internal B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__remove_internal_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__internal_free
+ *
+ * Purpose: Destroys a B-tree internal node in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__internal_free(H5B2_internal_t *internal)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(internal);
+
+ /* Release internal node's native key buffer */
+ if(internal->int_native)
+ internal->int_native = (uint8_t *)H5FL_FAC_FREE(internal->hdr->node_info[internal->depth].nat_rec_fac, internal->int_native);
+
+ /* Release internal node's node pointer buffer */
+ if(internal->node_ptrs)
+ internal->node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_FREE(internal->hdr->node_info[internal->depth].node_ptr_fac, internal->node_ptrs);
+
+ /* Decrement ref. count on B-tree header */
+ if(H5B2__hdr_decr(internal->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement ref. count on B-tree header")
+
+ /* Sanity check */
+ HDassert(NULL == internal->top_proxy);
+
+ /* Free B-tree internal node info */
+ internal = H5FL_FREE(H5B2_internal_t, internal);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__internal_free() */
+
+#ifdef H5B2_DEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__assert_internal
+ *
+ * Purpose: Verify than an internal node is mostly sane
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 19 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE herr_t
+H5B2__assert_internal(hsize_t parent_all_nrec, const H5B2_hdr_t *hdr, const H5B2_internal_t *internal)
+{
+ hsize_t tot_all_nrec; /* Total number of records at or below this node */
+ uint16_t u, v; /* Local index variables */
+
+ /* General sanity checking on node */
+ HDassert(internal->nrec <= hdr->node_info->split_nrec);
+
+ /* Sanity checking on node pointers */
+ tot_all_nrec = internal->nrec;
+ for(u = 0; u < internal->nrec + 1; u++) {
+ tot_all_nrec += internal->node_ptrs[u].all_nrec;
+
+ HDassert(H5F_addr_defined(internal->node_ptrs[u].addr));
+ HDassert(internal->node_ptrs[u].addr > 0);
+ for(v = 0; v < u; v++)
+ HDassert(internal->node_ptrs[u].addr != internal->node_ptrs[v].addr);
+ } /* end for */
+
+ /* Sanity check all_nrec total in parent */
+ if(parent_all_nrec > 0)
+ HDassert(tot_all_nrec == parent_all_nrec);
+
+ return(0);
+} /* end H5B2__assert_internal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__assert_internal2
+ *
+ * Purpose: Verify than internal nodes are mostly sane
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 19 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE herr_t
+H5B2__assert_internal2(hsize_t parent_all_nrec, const H5B2_hdr_t *hdr, const H5B2_internal_t *internal, const H5B2_internal_t *internal2)
+{
+ hsize_t tot_all_nrec; /* Total number of records at or below this node */
+ uint16_t u, v; /* Local index variables */
+
+ /* General sanity checking on node */
+ HDassert(internal->nrec <= hdr->node_info->split_nrec);
+
+ /* Sanity checking on node pointers */
+ tot_all_nrec =internal->nrec;
+ for(u =0; u < internal->nrec + 1; u++) {
+ tot_all_nrec += internal->node_ptrs[u].all_nrec;
+
+ HDassert(H5F_addr_defined(internal->node_ptrs[u].addr));
+ HDassert(internal->node_ptrs[u].addr > 0);
+ for(v = 0; v < u; v++)
+ HDassert(internal->node_ptrs[u].addr != internal->node_ptrs[v].addr);
+ for(v = 0; v < internal2->nrec + 1; v++)
+ HDassert(internal->node_ptrs[u].addr != internal2->node_ptrs[v].addr);
+ } /* end for */
+
+ /* Sanity check all_nrec total in parent */
+ if(parent_all_nrec > 0)
+ HDassert(tot_all_nrec == parent_all_nrec);
+
+ return(0);
+} /* end H5B2__assert_internal2() */
+#endif /* H5B2_DEBUG */
+
diff --git a/src/H5B2leaf.c b/src/H5B2leaf.c
new file mode 100644
index 0000000..d900761
--- /dev/null
+++ b/src/H5B2leaf.c
@@ -0,0 +1,1063 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2leaf.c
+ * Dec 01 2016
+ * Quincey Koziol <koziol@lbl.gov>
+ *
+ * Purpose: Routines for managing v2 B-tree leaf ndoes.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5B2__shadow_leaf(H5B2_leaf_t *leaf, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5B2_leaf_t struct */
+H5FL_DEFINE(H5B2_leaf_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__create_leaf
+ *
+ * Purpose: Creates empty leaf node of a B-tree and update node pointer
+ * to point to it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__create_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent, H5B2_node_ptr_t *node_ptr)
+{
+ H5B2_leaf_t *leaf = NULL; /* Pointer to new leaf node created */
+ hbool_t inserted = FALSE; /* Whether the leaf node was inserted into cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(node_ptr);
+
+ /* Allocate memory for leaf information */
+ if(NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf info")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, FAIL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree header information */
+ leaf->hdr = hdr;
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(hdr->node_info[0].nat_rec_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf native keys")
+ HDmemset(leaf->leaf_native, 0, hdr->cls->nrec_size * hdr->node_info[0].max_nrec);
+
+ /* Set parent */
+ leaf->parent = parent;
+
+ /* Set shadowed epoch to header's epoch */
+ leaf->shadow_epoch = hdr->shadow_epoch;
+
+ /* Allocate space on disk for the leaf */
+ if(HADDR_UNDEF == (node_ptr->addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)hdr->node_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for B-tree leaf node")
+
+ /* Cache the new B-tree node */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree leaf to cache")
+ inserted = TRUE;
+
+ /* Add leaf node as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree node as child of proxy")
+ leaf->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+done:
+ if(ret_value < 0) {
+ if(leaf) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(leaf) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "unable to remove v2 B-tree leaf node from cache")
+
+ /* Release leaf node's disk space */
+ if(H5F_addr_defined(node_ptr->addr) && H5MF_xfree(hdr->f, H5FD_MEM_BTREE, dxpl_id, node_ptr->addr, (hsize_t)hdr->node_size) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release file space for v2 B-tree leaf node")
+
+ /* Destroy leaf node */
+ if(H5B2__leaf_free(leaf) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree leaf node")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__create_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__protect_leaf
+ *
+ * Purpose: "Protect" an leaf node in the metadata cache
+ *
+ * Return: Pointer to leaf node on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 5 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+H5B2_leaf_t *
+H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ H5B2_node_ptr_t *node_ptr, hbool_t shadow, unsigned flags)
+{
+ H5B2_leaf_cache_ud_t udata; /* User-data for callback */
+ H5B2_leaf_t *leaf; /* v2 B-tree leaf node */
+ H5B2_leaf_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(node_ptr);
+ HDassert(H5F_addr_defined(node_ptr->addr));
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data for callback */
+ udata.f = hdr->f;
+ udata.hdr = hdr;
+ udata.parent = parent;
+ udata.nrec = node_ptr->node_nrec;
+
+ /* Protect the leaf node */
+ if(NULL == (leaf = (H5B2_leaf_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_LEAF, node_ptr->addr, &udata, flags)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree leaf node")
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == leaf->top_proxy) {
+ /* Add leaf node as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree leaf node as child of proxy")
+ leaf->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Shadow the node, if requested */
+ if(shadow)
+ if(H5B2__shadow_leaf(leaf, dxpl_id, node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, NULL, "unable to shadow leaf node")
+
+ /* Set return value */
+ ret_value = leaf;
+
+done:
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the leaf node, if it was protected */
+ if(leaf) {
+ /* Remove from v2 B-tree's proxy, if added */
+ if(leaf->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, NULL, "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy")
+ leaf->top_proxy = NULL;
+ } /* end if */
+
+ /* Unprotect leaf node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, "unable to unprotect v2 B-tree leaf node, address = %llu", (unsigned long long)node_ptr->addr)
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__protect_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__neighbor_leaf
+ *
+ * Purpose: Locate a record relative to the specified information in a
+ * B-tree leaf node and return that information by filling in
+ * fields of the
+ * caller-supplied UDATA pointer depending on the type of leaf node
+ * requested. The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * The 'OP' routine is called with the record found and the
+ * OP_DATA pointer, to allow caller to return information about
+ * the record.
+ *
+ * The RANGE indicates whether to search for records less than or
+ * equal to, or greater than or equal to the information passed
+ * in with UDATA.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 9 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__neighbor_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr,
+ void *neighbor_loc, H5B2_compare_t comp, void *parent, void *udata, H5B2_found_t op,
+ void *op_data)
+{
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+ unsigned idx = 0; /* Location of record which matches key */
+ int cmp = 0; /* Comparison value of records */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+ HDassert(op);
+
+ /* Lock current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, curr_node_ptr, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp > 0)
+ idx++;
+ else
+ if(cmp == 0 && comp == H5B2_COMPARE_GREATER)
+ idx++;
+
+ /* Set the neighbor location, if appropriate */
+ if(comp == H5B2_COMPARE_LESS) {
+ if(idx > 0)
+ neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx - 1);
+ } /* end if */
+ else {
+ HDassert(comp == H5B2_COMPARE_GREATER);
+
+ if(idx < leaf->nrec)
+ neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx);
+ } /* end else */
+
+ /* Make callback if neighbor record has been found */
+ if(neighbor_loc) {
+ /* Make callback for current record */
+ if((op)(neighbor_loc, op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "'found' callback failed for B-tree neighbor operation")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree")
+
+done:
+ /* Release the B-tree leaf node */
+ if(leaf && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree leaf node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__neighbor_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__insert_leaf
+ *
+ * Purpose: Adds a new record to a B-tree leaf node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__insert_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr,
+ H5B2_nodepos_t curr_pos, void *parent, void *udata)
+{
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+ unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
+ int cmp; /* Comparison value of records */
+ unsigned idx = 0; /* Location of record which matches key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, curr_node_ptr, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Must have a leaf node with enough space to insert a record now */
+ HDassert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec);
+
+ /* Sanity check number of records */
+ HDassert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
+ HDassert(leaf->nrec == curr_node_ptr->node_nrec);
+
+ /* Check for inserting into empty leaf */
+ if(leaf->nrec == 0)
+ idx = 0;
+ else {
+ /* Find correct location to insert this record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp == 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_EXISTS, FAIL, "record is already in B-tree")
+ if(cmp > 0)
+ idx++;
+
+ /* Make room for new record */
+ if(idx < leaf->nrec)
+ HDmemmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size * (leaf->nrec - idx));
+ } /* end else */
+
+ /* Make callback to store record in native form */
+ if((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node")
+
+ /* Mark the node as dirty */
+ leaf_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Update record count for node pointer to current node */
+ curr_node_ptr->all_nrec++;
+ curr_node_ptr->node_nrec++;
+
+ /* Update record count for current node */
+ leaf->nrec++;
+
+ /* Check for new record being the min or max for the tree */
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec == NULL)
+ if(NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree min record info")
+ HDmemcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec == NULL)
+ if(NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree max record info")
+ HDmemcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the B-tree leaf node (marked as dirty) */
+ if(leaf) {
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG))
+ if(H5B2__shadow_leaf(leaf, dxpl_id, curr_node_ptr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node")
+
+ /* Unprotect leaf node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__insert_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__update_leaf
+ *
+ * Purpose: Insert or modify a record in a B-tree leaf node.
+ * If the record exists already, it is modified as if H5B2_modify
+ * was called). If it doesn't exist, it is inserted as if
+ * H5B2_insert was called.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 23 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__update_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr,
+ H5B2_update_status_t *status, H5B2_nodepos_t curr_pos, void *parent,
+ void *udata, H5B2_modify_t op, void *op_data)
+{
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+ unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */
+ int cmp = -1; /* Comparison value of records */
+ unsigned idx = 0; /* Location of record which matches key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, curr_node_ptr, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Sanity check number of records */
+ HDassert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
+ HDassert(leaf->nrec == curr_node_ptr->node_nrec);
+
+ /* Check for inserting into empty leaf */
+ if(leaf->nrec == 0)
+ idx = 0;
+ else {
+ /* Find correct location to insert this record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ /* Check for inserting a record */
+ if(0 != cmp) {
+ /* Check if the leaf node is full */
+ if(curr_node_ptr->node_nrec == hdr->node_info[0].split_nrec) {
+ /* Indicate that the leaf is full, but we need to insert */
+ *status = H5B2_UPDATE_INSERT_CHILD_FULL;
+
+ /* Let calling routine handle insertion */
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Adjust index to leave room for record to insert */
+ if(cmp > 0)
+ idx++;
+
+ /* Make room for new record */
+ if(idx < leaf->nrec)
+ HDmemmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size * (leaf->nrec - idx));
+ } /* end if */
+ } /* end else */
+
+ /* Check for modifying existing record */
+ if(0 == cmp) {
+ hbool_t changed = FALSE; /* Whether the 'modify' callback changed the record */
+
+ /* Make callback for current record */
+ if((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data, &changed) < 0) {
+ /* Make certain that the callback didn't modify the value if it failed */
+ HDassert(changed == FALSE);
+
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL, "'modify' callback failed for B-tree update operation")
+ } /* end if */
+
+ /* Mark the node as dirty if it changed */
+ leaf_flags |= (changed ? H5AC__DIRTIED_FLAG : 0);
+
+ /* Indicate that the record was modified */
+ *status = H5B2_UPDATE_MODIFY_DONE;
+ } /* end if */
+ else {
+ /* Must have a leaf node with enough space to insert a record now */
+ HDassert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec);
+
+ /* Make callback to store record in native form */
+ if((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node")
+
+ /* Mark the node as dirty */
+ leaf_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Indicate that the record was inserted */
+ *status = H5B2_UPDATE_INSERT_DONE;
+
+ /* Update record count for node pointer to current node */
+ curr_node_ptr->all_nrec++;
+ curr_node_ptr->node_nrec++;
+
+ /* Update record count for current node */
+ leaf->nrec++;
+ } /* end else */
+
+ /* Check for new record being the min or max for the tree */
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec == NULL)
+ if(NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree min record info")
+ HDmemcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec == NULL)
+ if(NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "memory allocation failed for v2 B-tree max record info")
+ HDmemcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the B-tree leaf node */
+ if(leaf) {
+ /* Check if we should shadow this node */
+ if(hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG)) {
+ /* Attempt to shadow the node if doing SWMR writes */
+ if(H5B2__shadow_leaf(leaf, dxpl_id, curr_node_ptr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node")
+
+ /* Change the state to "shadowed" if only modified currently */
+ /* (Triggers parent to be marked dirty) */
+ if(*status == H5B2_UPDATE_MODIFY_DONE)
+ *status = H5B2_UPDATE_SHADOW_DONE;
+ } /* end if */
+
+ /* Unprotect leaf node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__update_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__swap_leaf
+ *
+ * Purpose: Swap a record in a node with a record in a leaf node
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 4 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__swap_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr,
+ unsigned idx, void *swap_loc)
+{
+ const H5AC_class_t *child_class; /* Pointer to child node's class info */
+ haddr_t child_addr; /* Address of child node */
+ void *child = NULL; /* Pointer to child node */
+ uint8_t *child_native; /* Pointer to child's native records */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(internal);
+ HDassert(internal_flags_ptr);
+ HDassert(idx <= internal->nrec);
+
+ /* Check for the kind of B-tree node to swap */
+ if(depth > 1) {
+ H5B2_internal_t *child_internal; /* Pointer to internal node */
+
+ /* Setup information for unlocking child node */
+ child_class = H5AC_BT2_INT;
+
+ /* Lock B-tree child nodes */
+ if(NULL == (child_internal = H5B2__protect_internal(hdr, dxpl_id, internal, &internal->node_ptrs[idx], (uint16_t)(depth - 1), FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node")
+ child_addr = internal->node_ptrs[idx].addr;
+
+ /* More setup for accessing child node information */
+ child = child_internal;
+ child_native = child_internal->int_native;
+ } /* end if */
+ else {
+ H5B2_leaf_t *child_leaf; /* Pointer to leaf node */
+
+ /* Setup information for unlocking child nodes */
+ child_class = H5AC_BT2_LEAF;
+
+ /* Lock B-tree child node */
+ if(NULL == (child_leaf = H5B2__protect_leaf(hdr, dxpl_id, internal, &internal->node_ptrs[idx], FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ child_addr = internal->node_ptrs[idx].addr;
+
+ /* More setup for accessing child node information */
+ child = child_leaf;
+ child_native = child_leaf->leaf_native;
+ } /* end else */
+
+ /* Swap records (use disk page as temporary buffer) */
+ HDmemcpy(hdr->page, H5B2_NAT_NREC(child_native, hdr, 0), hdr->cls->nrec_size);
+ HDmemcpy(H5B2_NAT_NREC(child_native, hdr, 0), swap_loc, hdr->cls->nrec_size);
+ HDmemcpy(swap_loc, hdr->page, hdr->cls->nrec_size);
+
+ /* Mark parent as dirty */
+ *internal_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+#ifdef H5B2_DEBUG
+ H5B2__assert_internal((hsize_t)0, hdr, internal);
+ if(depth > 1)
+ H5B2__assert_internal(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)child);
+ else
+ H5B2__assert_leaf(hdr, (H5B2_leaf_t *)child);
+#endif /* H5B2_DEBUG */
+
+done:
+ /* Unlock child node */
+ if(child && H5AC_unprotect(hdr->f, dxpl_id, child_class, child_addr, child, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__swap_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__shadow_leaf
+ *
+ * Purpose: "Shadow" a leaf node - copy it to a new location, leaving
+ * the data in the old location intact (for now). This is
+ * done when writing in SWMR mode to ensure that readers do
+ * not see nodes that are out of date with respect to each
+ * other and thereby inconsistent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Apr 27 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__shadow_leaf(H5B2_leaf_t *leaf, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr)
+{
+ H5B2_hdr_t *hdr; /* B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(leaf);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+ hdr = leaf->hdr;
+ HDassert(hdr);
+ HDassert(hdr->swmr_write);
+
+ /* We only need to shadow the node if it has not been shadowed since the
+ * last time the header was flushed, as otherwise it will be unreachable by
+ * the readers so there will be no need to shadow. To check if it has been
+ * shadowed, compare the epoch of this node and the header. If this node's
+ * epoch is <= to the header's, it hasn't been shadowed yet. */
+ if(leaf->shadow_epoch <= hdr->shadow_epoch) {
+ haddr_t new_node_addr; /* Address to move node to */
+
+ /*
+ * We must clone the old node so readers with an out-of-date version of
+ * the parent can still see the correct number of children, via the
+ * shadowed node. Remove it from cache but do not mark it free on disk.
+ */
+ /* Allocate space for the cloned node */
+ if(HADDR_UNDEF == (new_node_addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)hdr->node_size)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move B-tree node")
+
+ /* Move the location of the old child on the disk */
+ if(H5AC_move_entry(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, new_node_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree node")
+ curr_node_ptr->addr = new_node_addr;
+
+ /* Should free the space in the file, but this is not supported by
+ * SWMR_WRITE code yet - QAK, 2016/12/01
+ */
+
+ /* Set shadow epoch for node ahead of header */
+ leaf->shadow_epoch = hdr->shadow_epoch + 1;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__shadow_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__remove_leaf
+ *
+ * Purpose: Removes a record from a B-tree leaf node.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__remove_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr,
+ H5B2_nodepos_t curr_pos, void *parent, void *udata, H5B2_remove_t op, void *op_data)
+{
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+ haddr_t leaf_addr = HADDR_UNDEF; /* Leaf address on disk */
+ unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */
+ unsigned idx = 0; /* Location of record which matches key */
+ int cmp; /* Comparison value of records */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock current B-tree node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, curr_node_ptr, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ leaf_addr = curr_node_ptr->addr;
+
+ /* Sanity check number of records */
+ HDassert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
+ HDassert(leaf->nrec == curr_node_ptr->node_nrec);
+
+ /* Find correct location to remove this record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ if(cmp != 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree")
+
+ /* Check for invalidating the min/max record for the tree */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec)
+ hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec)
+ hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Make 'remove' callback if there is one */
+ if(op)
+ if((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node")
+
+ /* Update number of records in node */
+ leaf->nrec--;
+
+ if(leaf->nrec > 0) {
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write) {
+ if(H5B2__shadow_leaf(leaf, dxpl_id, curr_node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node")
+ leaf_addr = curr_node_ptr->addr;
+ } /* end if */
+
+ /* Pack record out of leaf */
+ if(idx < leaf->nrec)
+ HDmemmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)), hdr->cls->nrec_size * (leaf->nrec - idx));
+
+ /* Mark leaf node as dirty also */
+ leaf_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else {
+ /* Let the cache know that the object is deleted */
+ leaf_flags |= H5AC__DELETED_FLAG;
+ if(!hdr->swmr_write)
+ leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+ /* Reset address of parent node pointer */
+ curr_node_ptr->addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Update record count for parent of leaf node */
+ curr_node_ptr->node_nrec--;
+
+done:
+ /* Release the B-tree leaf node */
+ if(leaf && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__remove_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__remove_leaf_by_idx
+ *
+ * Purpose: Removes a record from a B-tree leaf node, according to the
+ * offset in the B-tree records.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__remove_leaf_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent,
+ unsigned idx, H5B2_remove_t op, void *op_data)
+{
+ H5B2_leaf_t *leaf; /* Pointer to leaf node */
+ haddr_t leaf_addr = HADDR_UNDEF; /* Leaf address on disk */
+ unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(curr_node_ptr);
+ HDassert(H5F_addr_defined(curr_node_ptr->addr));
+
+ /* Lock B-tree leaf node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, curr_node_ptr, FALSE, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+ leaf_addr = curr_node_ptr->addr;
+
+ /* Sanity check number of records */
+ HDassert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec);
+ HDassert(leaf->nrec == curr_node_ptr->node_nrec);
+ HDassert(idx < leaf->nrec);
+
+ /* Check for invalidating the min/max record for the tree */
+ if(H5B2_POS_MIDDLE != curr_pos) {
+ /* (Don't use 'else' for the idx check, to allow for root leaf node) */
+ if(idx == 0) {
+ if(H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->min_native_rec)
+ hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
+ } /* end if */
+ } /* end if */
+ if(idx == (unsigned)(leaf->nrec - 1)) {
+ if(H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) {
+ if(hdr->max_native_rec)
+ hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Make 'remove' callback if there is one */
+ if(op)
+ if((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node")
+
+ /* Update number of records in node */
+ leaf->nrec--;
+
+ if(leaf->nrec > 0) {
+ /* Shadow the node if doing SWMR writes */
+ if(hdr->swmr_write) {
+ if(H5B2__shadow_leaf(leaf, dxpl_id, curr_node_ptr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node")
+ leaf_addr = curr_node_ptr->addr;
+ } /* end if */
+
+ /* Pack record out of leaf */
+ if(idx < leaf->nrec)
+ HDmemmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)), hdr->cls->nrec_size * (leaf->nrec - idx));
+
+ /* Mark leaf node as dirty also */
+ leaf_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else {
+ /* Let the cache know that the object is deleted */
+ leaf_flags |= H5AC__DELETED_FLAG;
+ if(!hdr->swmr_write)
+ leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+ /* Reset address of parent node pointer */
+ curr_node_ptr->addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Update record count for parent of leaf node */
+ curr_node_ptr->node_nrec--;
+
+done:
+ /* Release the B-tree leaf node */
+ if(leaf && H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__remove_leaf_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__leaf_free
+ *
+ * Purpose: Destroys a B-tree leaf node in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2__leaf_free(H5B2_leaf_t *leaf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(leaf);
+
+ /* Release leaf's native key buffer */
+ if(leaf->leaf_native)
+ leaf->leaf_native = (uint8_t *)H5FL_FAC_FREE(leaf->hdr->node_info[0].nat_rec_fac, leaf->leaf_native);
+
+ /* Decrement ref. count on B-tree header */
+ if(H5B2__hdr_decr(leaf->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement ref. count on B-tree header")
+
+ /* Sanity check */
+ HDassert(NULL == leaf->top_proxy);
+
+ /* Free B-tree leaf node info */
+ leaf = H5FL_FREE(H5B2_leaf_t, leaf);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__leaf_free() */
+
+#ifdef H5B2_DEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__assert_leaf
+ *
+ * Purpose: Verify than a leaf node is mostly sane
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 19 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE herr_t
+H5B2__assert_leaf(const H5B2_hdr_t *hdr, const H5B2_leaf_t *leaf)
+{
+ /* General sanity checking on node */
+ HDassert(leaf->nrec <= hdr->node_info->split_nrec);
+
+ return(0);
+} /* end H5B2__assert_leaf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__assert_leaf2
+ *
+ * Purpose: Verify than a leaf node is mostly sane
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 19 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE herr_t
+H5B2__assert_leaf2(const H5B2_hdr_t *hdr, const H5B2_leaf_t *leaf, const H5B2_leaf_t H5_ATTR_UNUSED *leaf2)
+{
+ /* General sanity checking on node */
+ HDassert(leaf->nrec <= hdr->node_info->split_nrec);
+
+ return(0);
+} /* end H5B2__assert_leaf2() */
+#endif /* H5B2_DEBUG */
+
diff --git a/src/H5B2module.h b/src/H5B2module.h
new file mode 100644
index 0000000..35c982c
--- /dev/null
+++ b/src/H5B2module.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5B2 package. Including this header means that the source file
+ * is part of the H5B2 package.
+ */
+#ifndef _H5B2module_H
+#define _H5B2module_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5B2_MODULE
+#define H5_MY_PKG H5B2
+#define H5_MY_PKG_ERR H5E_BTREE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5B2module_H */
+
+
diff --git a/src/H5B2pkg.h b/src/H5B2pkg.h
new file mode 100644
index 0000000..e24d2eb
--- /dev/null
+++ b/src/H5B2pkg.h
@@ -0,0 +1,487 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, January 31, 2005
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5B2 package. Source files outside the H5B2 package should
+ * include H5B2private.h instead.
+ */
+#if !(defined H5B2_FRIEND || defined H5B2_MODULE)
+#error "Do not include this file outside the H5B2 package!"
+#endif
+
+#ifndef _H5B2pkg_H
+#define _H5B2pkg_H
+
+/* Get package's private header */
+#include "H5B2private.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Size of storage for number of records per node (on disk) */
+#define H5B2_SIZEOF_RECORDS_PER_NODE (unsigned)2
+
+/* Size of a "tree pointer" (on disk) */
+/* (essentially, the largest internal pointer allowed) */
+#define H5B2_TREE_POINTER_SIZE(sizeof_addr, sizeof_size) ( \
+ (sizeof_addr) + \
+ H5B2_SIZEOF_RECORDS_PER_NODE + \
+ (sizeof_size) \
+ )
+
+/* Size of a internal node pointer (on disk) */
+#define H5B2_INT_POINTER_SIZE(h, d) ( \
+ (unsigned)(h)->sizeof_addr /* Address of child node */ \
+ + (h)->max_nrec_size /* # of records in child node */ \
+ + (h)->node_info[(d) - 1].cum_max_nrec_size /* Total # of records in child & below */ \
+ )
+
+/* Size of checksum information (on disk) */
+#define H5B2_SIZEOF_CHKSUM 4
+
+/* Format overhead for all v2 B-tree metadata in the file */
+#define H5B2_METADATA_PREFIX_SIZE ( \
+ (unsigned)H5_SIZEOF_MAGIC /* Signature */ \
+ + (unsigned)1 /* Version */ \
+ + (unsigned)1 /* Tree type */ \
+ + (unsigned)H5B2_SIZEOF_CHKSUM /* Metadata checksum */ \
+ )
+
+/* Size of the v2 B-tree header on disk */
+#define H5B2_HEADER_SIZE(sizeof_addr, sizeof_size) ( \
+ /* General metadata fields */ \
+ H5B2_METADATA_PREFIX_SIZE \
+ \
+ /* Header specific fields */ \
+ + (unsigned)4 /* Node size, in bytes */ \
+ + (unsigned)2 /* Record size, in bytes */ \
+ + (unsigned)2 /* Depth of tree */ \
+ + (unsigned)1 /* Split % of full (as integer, ie. "98" means 98%) */ \
+ + (unsigned)1 /* Merge % of full (as integer, ie. "98" means 98%) */ \
+ + H5B2_TREE_POINTER_SIZE(sizeof_addr, sizeof_size) /* Node pointer to root node in tree */ \
+ )
+
+/* Size of the v2 B-tree header on disk (via file pointer) */
+#define H5B2_HEADER_SIZE_FILE(f) ( \
+ H5B2_HEADER_SIZE(H5F_SIZEOF_ADDR(f), H5F_SIZEOF_SIZE(f)) \
+ )
+
+/* Size of the v2 B-tree header on disk (via v2 B-tree header) */
+#define H5B2_HEADER_SIZE_HDR(h) ( \
+ H5B2_HEADER_SIZE((h)->sizeof_addr, (h)->sizeof_size) \
+ )
+
+/* Size of the v2 B-tree internal node prefix */
+#define H5B2_INT_PREFIX_SIZE ( \
+ /* General metadata fields */ \
+ H5B2_METADATA_PREFIX_SIZE \
+ \
+ /* Header specific fields */ \
+ /* <none> */ \
+ )
+
+/* Size of the v2 B-tree leaf node prefix */
+#define H5B2_LEAF_PREFIX_SIZE ( \
+ /* General metadata fields */ \
+ H5B2_METADATA_PREFIX_SIZE \
+ \
+ /* Header specific fields */ \
+ /* <none> */ \
+ )
+
+/* Macro to retrieve pointer to i'th native record for native record buffer */
+#define H5B2_NAT_NREC(b, hdr, idx) ((b) + (hdr)->nat_off[(idx)])
+
+/* Macro to retrieve pointer to i'th native record for internal node */
+#define H5B2_INT_NREC(i, hdr, idx) H5B2_NAT_NREC((i)->int_native, (hdr), (idx))
+
+/* Macro to retrieve pointer to i'th native record for leaf node */
+#define H5B2_LEAF_NREC(l, hdr, idx) H5B2_NAT_NREC((l)->leaf_native, (hdr), (idx))
+
+/* Number of records that fit into internal node */
+/* (accounts for extra node pointer by counting it in with the prefix bytes) */
+#define H5B2_NUM_INT_REC(h, d) \
+ (((h)->node_size - (H5B2_INT_PREFIX_SIZE + H5B2_INT_POINTER_SIZE(h, d))) / ((h)->rrec_size + H5B2_INT_POINTER_SIZE(h, d)))
+
+/* Uncomment this macro to enable extra sanity checking */
+/* #define H5B2_DEBUG */
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* A "node pointer" to another B-tree node */
+typedef struct {
+ haddr_t addr; /* Address of other node */
+ uint16_t node_nrec; /* Number of records used in node pointed to */
+ hsize_t all_nrec; /* Number of records in node pointed to and all it's children */
+} H5B2_node_ptr_t;
+
+/* Information about a node at a given depth */
+typedef struct {
+ unsigned max_nrec; /* Max. number of records in node */
+ unsigned split_nrec; /* Number of records to split node at */
+ unsigned merge_nrec; /* Number of records to merge node at */
+ hsize_t cum_max_nrec; /* Cumulative max. # of records below this node's depth */
+ uint8_t cum_max_nrec_size; /* Size to store cumulative max. # of records for this node (in bytes) */
+ H5FL_fac_head_t *nat_rec_fac; /* Factory for native record blocks */
+ H5FL_fac_head_t *node_ptr_fac; /* Factory for node pointer blocks */
+} H5B2_node_info_t;
+
+/* The B-tree header information */
+typedef struct H5B2_hdr_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Internal B-tree information (stored) */
+ H5B2_node_ptr_t root; /* Node pointer to root node in B-tree */
+
+ /* Information set by user (stored) */
+ uint8_t split_percent; /* Percent full at which to split the node, when inserting */
+ uint8_t merge_percent; /* Percent full at which to merge the node, when deleting */
+ uint32_t node_size; /* Size of B-tree nodes, in bytes */
+ uint32_t rrec_size; /* Size of "raw" (on disk) record, in bytes */
+
+ /* Dynamic information (stored) */
+ uint16_t depth; /* B-tree's overall depth */
+
+ /* Derived information from user's information (not stored) */
+ uint8_t max_nrec_size; /* Size to store max. # of records in any node (in bytes) */
+
+ /* Shared internal data structures (not stored) */
+ H5F_t *f; /* Pointer to the file that the B-tree is in */
+ haddr_t addr; /* Address of B-tree header in the file */
+ size_t hdr_size; /* Size of the B-tree header on disk */
+ size_t rc; /* Reference count of nodes using this header */
+ size_t file_rc; /* Reference count of files using this header */
+ hbool_t pending_delete; /* B-tree is pending deletion */
+ uint8_t sizeof_size; /* Size of file sizes */
+ uint8_t sizeof_addr; /* Size of file addresses */
+ H5B2_remove_t remove_op; /* Callback operator for deleting B-tree */
+ void *remove_op_data;/* B-tree deletion callback's context */
+ uint8_t *page; /* Common disk page for I/O */
+ size_t *nat_off; /* Array of offsets of native records */
+ H5B2_node_info_t *node_info; /* Table of node info structs for current depth of B-tree */
+ void *min_native_rec; /* Pointer to minimum native record */
+ void *max_native_rec; /* Pointer to maximum native record */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t swmr_write; /* Whether we are doing SWMR writes */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all B-tree entries */
+ void *parent; /* Pointer to 'top' proxy flush dependency
+ * parent, if it exists, otherwise NULL.
+ * If the v2 B-tree is being used to index a
+ * chunked dataset and the dataset metadata is
+ * modified by a SWMR writer, this field will
+ * be set equal to the object header proxy
+ * that is the flush dependency parent
+ * of the v2 B-tree header.
+ *
+ * The field is used to avoid duplicate setups
+ * of the flush dependency relationship, and to
+ * allow the v2 B-tree header to destroy the
+ * flush dependency on receipt of an eviction
+ * notification from the metadata cache.
+ */
+ uint64_t shadow_epoch; /* Epoch of header, for making shadow copies */
+
+ /* Client information (not stored) */
+ const H5B2_class_t *cls; /* Class of B-tree client */
+ void *cb_ctx; /* Client callback context */
+} H5B2_hdr_t;
+
+/* B-tree leaf node information */
+typedef struct H5B2_leaf_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Internal B-tree information */
+ H5B2_hdr_t *hdr; /* Pointer to the [pinned] v2 B-tree header */
+ uint8_t *leaf_native; /* Pointer to native records */
+ uint16_t nrec; /* Number of records in node */
+
+ /* SWMR / Flush dependency information (not stored) */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all B-tree entries */
+ void *parent; /* Flush dependency parent for leaf */
+ uint64_t shadow_epoch; /* Epoch of node, for making shadow copies */
+} H5B2_leaf_t;
+
+/* B-tree internal node information */
+typedef struct H5B2_internal_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Internal B-tree information */
+ H5B2_hdr_t *hdr; /* Pointer to the [pinned] v2 B-tree header */
+ uint8_t *int_native; /* Pointer to native records */
+ H5B2_node_ptr_t *node_ptrs; /* Pointer to node pointers */
+ uint16_t nrec; /* Number of records in node */
+ uint16_t depth; /* Depth of this node in the B-tree */
+
+ /* SWMR / Flush dependency information (not stored) */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all B-tree entries */
+ void *parent; /* Flush dependency parent for internal node */
+ uint64_t shadow_epoch; /* Epoch of node, for making shadow copies */
+} H5B2_internal_t;
+
+/* v2 B-tree */
+struct H5B2_t {
+ H5B2_hdr_t *hdr; /* Pointer to internal v2 B-tree header info */
+ H5F_t *f; /* Pointer to file for v2 B-tree */
+};
+
+/* Node position, for min/max determination */
+typedef enum H5B2_nodepos_t {
+ H5B2_POS_ROOT, /* Node is root (i.e. both right & left-most in tree) */
+ H5B2_POS_RIGHT, /* Node is right-most in tree, at a given depth */
+ H5B2_POS_LEFT, /* Node is left-most in tree, at a given depth */
+ H5B2_POS_MIDDLE /* Node is neither right or left-most in tree */
+} H5B2_nodepos_t;
+
+/* Update status */
+typedef enum H5B2_update_status_t {
+ H5B2_UPDATE_UNKNOWN, /* Unknown update status (initial state) */
+ H5B2_UPDATE_MODIFY_DONE, /* Update successfully modified existing record */
+ H5B2_UPDATE_SHADOW_DONE, /* Update modified existing record and modified node was shadowed */
+ H5B2_UPDATE_INSERT_DONE, /* Update inserted record successfully */
+ H5B2_UPDATE_INSERT_CHILD_FULL /* Update will insert record, but child is full */
+} H5B2_update_status_t;
+
+/* Callback info for loading a v2 B-tree header into the cache */
+typedef struct H5B2_hdr_cache_ud_t {
+ H5F_t *f; /* File that v2 b-tree header is within */
+ haddr_t addr; /* Address of B-tree header in the file */
+ void *ctx_udata; /* User-data for protecting */
+} H5B2_hdr_cache_ud_t;
+
+/* Callback info for loading a v2 B-tree internal node into the cache */
+typedef struct H5B2_internal_cache_ud_t {
+ H5F_t *f; /* File that v2 b-tree header is within */
+ H5B2_hdr_t *hdr; /* v2 B-tree header */
+ void *parent; /* Flush dependency parent */
+ uint16_t nrec; /* Number of records in node to load */
+ uint16_t depth; /* Depth of node to load */
+} H5B2_internal_cache_ud_t;
+
+/* Callback info for loading a v2 B-tree leaf node into the cache */
+typedef struct H5B2_leaf_cache_ud_t {
+ H5F_t *f; /* File that v2 b-tree header is within */
+ H5B2_hdr_t *hdr; /* v2 B-tree header */
+ void *parent; /* Flush dependency parent */
+ uint16_t nrec; /* Number of records in node to load */
+} H5B2_leaf_cache_ud_t;
+
+#ifdef H5B2_TESTING
+/* Node information for testing */
+typedef struct H5B2_node_info_test_t {
+ uint16_t depth; /* Depth of node */
+ uint16_t nrec; /* Number of records in node */
+} H5B2_node_info_test_t;
+#endif /* H5B2_TESTING */
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare a free list to manage the H5B2_internal_t struct */
+H5FL_EXTERN(H5B2_internal_t);
+
+/* Declare a free list to manage the H5B2_leaf_t struct */
+H5FL_EXTERN(H5B2_leaf_t);
+
+/* Internal v2 B-tree testing class */
+#ifdef H5B2_TESTING
+H5_DLLVAR const H5B2_class_t H5B2_TEST[1];
+H5_DLLVAR const H5B2_class_t H5B2_TEST2[1];
+
+/* B-tree record for testing H5B2_TEST2 class */
+typedef struct H5B2_test_rec_t {
+ hsize_t key; /* Key for record */
+ hsize_t val; /* Value for record */
+} H5B2_test_rec_t;
+#endif /* H5B2_TESTING */
+
+/* Array of v2 B-tree client ID -> client class mappings */
+extern const H5B2_class_t *const H5B2_client_class_g[H5B2_NUM_BTREE_ID];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Generic routines */
+H5_DLL herr_t H5B2__create_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+H5_DLL herr_t H5B2__update_flush_depend(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ unsigned depth, const H5B2_node_ptr_t *node_ptr, void *old_parent,
+ void *new_parent);
+H5_DLL herr_t H5B2__destroy_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+
+/* Internal node management routines */
+H5_DLL herr_t H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx);
+H5_DLL herr_t H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned idx);
+H5_DLL herr_t H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx);
+H5_DLL herr_t H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx);
+H5_DLL herr_t H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_node_ptr_t *curr_node_ptr, unsigned *parent_cache_info_flags_ptr,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx);
+
+/* Routines for managing B-tree header info */
+H5_DLL H5B2_hdr_t *H5B2__hdr_alloc(H5F_t *f);
+H5_DLL haddr_t H5B2__hdr_create(H5F_t *f, hid_t dxpl_id,
+ const H5B2_create_t *cparam, void *ctx_udata);
+H5_DLL herr_t H5B2__hdr_init(H5B2_hdr_t *hdr, const H5B2_create_t *cparam,
+ void *ctx_udata, uint16_t depth);
+H5_DLL herr_t H5B2__hdr_incr(H5B2_hdr_t *hdr);
+H5_DLL herr_t H5B2__hdr_decr(H5B2_hdr_t *hdr);
+H5_DLL herr_t H5B2__hdr_fuse_incr(H5B2_hdr_t *hdr);
+H5_DLL size_t H5B2__hdr_fuse_decr(H5B2_hdr_t *hdr);
+H5_DLL herr_t H5B2__hdr_dirty(H5B2_hdr_t *hdr);
+H5_DLL H5B2_hdr_t *H5B2__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t hdr_addr,
+ void *ctx_udata, unsigned flags);
+H5_DLL herr_t H5B2__hdr_unprotect(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ unsigned cache_flags);
+H5_DLL herr_t H5B2__hdr_delete(H5B2_hdr_t *hdr, hid_t dxpl_id);
+
+/* Routines for operating on leaf nodes */
+H5_DLL H5B2_leaf_t * H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ void *parent, H5B2_node_ptr_t *node_ptr, hbool_t shadow, unsigned flags);
+H5_DLL herr_t H5B2__swap_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ H5B2_internal_t *internal, unsigned *internal_flags_ptr, unsigned idx,
+ void *swap_loc);
+
+/* Routines for operating on internal nodes */
+H5_DLL H5B2_internal_t *H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ void *parent, H5B2_node_ptr_t *node_ptr, uint16_t depth, hbool_t shadow,
+ unsigned flags);
+
+/* Routines for allocating nodes */
+H5_DLL herr_t H5B2__split_root(H5B2_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5B2__create_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ H5B2_node_ptr_t *node_ptr);
+H5_DLL herr_t H5B2__create_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ H5B2_node_ptr_t *node_ptr, uint16_t depth);
+
+/* Routines for releasing structures */
+H5_DLL herr_t H5B2__hdr_free(H5B2_hdr_t *hdr);
+H5_DLL herr_t H5B2__leaf_free(H5B2_leaf_t *l);
+H5_DLL herr_t H5B2__internal_free(H5B2_internal_t *i);
+
+/* Routines for inserting records */
+H5_DLL herr_t H5B2__insert(H5B2_hdr_t *hdr, hid_t dxpl_id, void *udata);
+H5_DLL herr_t H5B2__insert_internal(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ uint16_t depth, unsigned *parent_cache_info_flags_ptr,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent, void *udata);
+H5_DLL herr_t H5B2__insert_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent, void *udata);
+
+/* Routines for update records */
+H5_DLL herr_t H5B2__update_internal(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ uint16_t depth, unsigned *parent_cache_info_flags_ptr,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_update_status_t *status,
+ H5B2_nodepos_t curr_pos, void *parent, void *udata, H5B2_modify_t op,
+ void *op_data);
+H5_DLL herr_t H5B2__update_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_update_status_t *status,
+ H5B2_nodepos_t curr_pos, void *parent, void *udata, H5B2_modify_t op,
+ void *op_data);
+
+/* Routines for iterating over nodes/records */
+H5_DLL herr_t H5B2__iterate_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ const H5B2_node_ptr_t *curr_node, void *parent, H5B2_operator_t op, void *op_data);
+H5_DLL herr_t H5B2__node_size(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ uint16_t depth, const H5B2_node_ptr_t *curr_node, void *parent,
+ hsize_t *op_data);
+
+/* Routines for locating records */
+H5_DLL herr_t H5B2__locate_record(const H5B2_class_t *type, unsigned nrec,
+ size_t *rec_off, const uint8_t *native, const void *udata, unsigned *idx, int *result);
+H5_DLL herr_t H5B2__neighbor_internal(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ uint16_t depth, H5B2_node_ptr_t *curr_node_ptr, void *neighbor_loc,
+ H5B2_compare_t comp, void *parent, void *udata, H5B2_found_t op,
+ void *op_data);
+H5_DLL herr_t H5B2__neighbor_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, void *neighbor_loc, H5B2_compare_t comp,
+ void *parent, void *udata, H5B2_found_t op, void *op_data);
+
+/* Routines for removing records */
+H5_DLL herr_t H5B2__remove_internal(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t *depth_decreased, void *swap_loc, void *swap_parent, uint16_t depth,
+ H5AC_info_t *parent_cache_info, unsigned *parent_cache_info_flags_ptr,
+ H5B2_nodepos_t curr_pos, H5B2_node_ptr_t *curr_node_ptr, void *udata,
+ H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2__remove_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent,
+ void *udata, H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2__remove_internal_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t *depth_decreased, void *swap_loc, void *swap_parent, uint16_t depth,
+ H5AC_info_t *parent_cache_info, unsigned *parent_cache_info_flags_ptr,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, hsize_t n,
+ H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2__remove_leaf_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id,
+ H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent,
+ unsigned idx, H5B2_remove_t op, void *op_data);
+
+/* Routines for deleting nodes */
+H5_DLL herr_t H5B2__delete_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth,
+ const H5B2_node_ptr_t *curr_node, void *parent, H5B2_remove_t op,
+ void *op_data);
+
+/* Debugging routines for dumping file structures */
+H5_DLL herr_t H5B2__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5B2_class_t *type, haddr_t obj_addr);
+H5_DLL herr_t H5B2__int_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5B2_class_t *type,
+ haddr_t hdr_addr, unsigned nrec, unsigned depth, haddr_t obj_addr);
+H5_DLL herr_t H5B2__leaf_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5B2_class_t *type,
+ haddr_t hdr_addr, unsigned nrec, haddr_t obj_addr);
+
+/* Sanity checking routines */
+#ifdef H5B2_DEBUG
+/* Don't label these with H5_ATTR_PURE or you'll get even more warnings... */
+H5_DLL herr_t H5B2__assert_internal(hsize_t parent_all_nrec, const H5B2_hdr_t *hdr, const H5B2_internal_t *internal);
+H5_DLL herr_t H5B2__assert_internal2(hsize_t parent_all_nrec, const H5B2_hdr_t *hdr, const H5B2_internal_t *internal, const H5B2_internal_t *internal2);
+H5_DLL herr_t H5B2__assert_leaf(const H5B2_hdr_t *hdr, const H5B2_leaf_t *leaf);
+H5_DLL herr_t H5B2__assert_leaf2(const H5B2_hdr_t *hdr, const H5B2_leaf_t *leaf, const H5B2_leaf_t *leaf2);
+#endif /* H5B2_DEBUG */
+
+/* Testing routines */
+#ifdef H5B2_TESTING
+H5_DLL herr_t H5B2_get_root_addr_test(H5B2_t *bt2, haddr_t *root_addr);
+H5_DLL int H5B2_get_node_depth_test(H5B2_t *bt2, hid_t dxpl_id, void *udata);
+H5_DLL herr_t H5B2_get_node_info_test(H5B2_t *bt2, hid_t dxpl_id,
+ void *udata, H5B2_node_info_test_t *ninfo);
+#endif /* H5B2_TESTING */
+
+#endif /* _H5B2pkg_H */
+
diff --git a/src/H5B2private.h b/src/H5B2private.h
new file mode 100644
index 0000000..e4bbffa
--- /dev/null
+++ b/src/H5B2private.h
@@ -0,0 +1,162 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2private.h
+ * Jan 31 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Private header for library accessible B-tree routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5B2private_H
+#define _H5B2private_H
+
+/* Include package's public header */
+#include "H5B2public.h"
+
+/* Private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Fprivate.h" /* File access */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* B-tree IDs for various internal things. */
+typedef enum H5B2_subid_t {
+ H5B2_TEST_ID = 0, /* B-tree is for testing (do not use for actual data) */
+ H5B2_FHEAP_HUGE_INDIR_ID, /* B-tree is for fractal heap indirectly accessed, non-filtered 'huge' objects */
+ H5B2_FHEAP_HUGE_FILT_INDIR_ID, /* B-tree is for fractal heap indirectly accessed, filtered 'huge' objects */
+ H5B2_FHEAP_HUGE_DIR_ID, /* B-tree is for fractal heap directly accessed, non-filtered 'huge' objects */
+ H5B2_FHEAP_HUGE_FILT_DIR_ID, /* B-tree is for fractal heap directly accessed, filtered 'huge' objects */
+ H5B2_GRP_DENSE_NAME_ID, /* B-tree is for indexing 'name' field for "dense" link storage in groups */
+ H5B2_GRP_DENSE_CORDER_ID, /* B-tree is for indexing 'creation order' field for "dense" link storage in groups */
+ H5B2_SOHM_INDEX_ID, /* B-tree is an index for shared object header messages */
+ H5B2_ATTR_DENSE_NAME_ID, /* B-tree is for indexing 'name' field for "dense" attribute storage on objects */
+ H5B2_ATTR_DENSE_CORDER_ID, /* B-tree is for indexing 'creation order' field for "dense" attribute storage on objects */
+ H5B2_CDSET_ID, /* B-tree is for non-filtered chunked dataset storage w/ >1 unlim dims */
+ H5B2_CDSET_FILT_ID, /* B-tree is for filtered chunked dataset storage w/ >1 unlim dims */
+ H5B2_TEST2_ID, /* Another B-tree is for testing (do not use for actual data) */
+ H5B2_NUM_BTREE_ID /* Number of B-tree IDs (must be last) */
+} H5B2_subid_t;
+
+/* Define the operator callback function pointer for H5B2_iterate() */
+typedef int (*H5B2_operator_t)(const void *record, void *op_data);
+
+/* Define the 'found' callback function pointer for H5B2_find(), H5B2_neighbor() & H5B2_index() */
+typedef herr_t (*H5B2_found_t)(const void *record, void *op_data);
+
+/* Define the 'modify' callback function pointer for H5B2_modify() */
+typedef herr_t (*H5B2_modify_t)(void *record, void *op_data, hbool_t *changed);
+
+/* Define the 'remove' callback function pointer for H5B2_remove() & H5B2_delete() */
+typedef herr_t (*H5B2_remove_t)(const void *record, void *op_data);
+
+/* Comparisons for H5B2_neighbor() call */
+typedef enum H5B2_compare_t {
+ H5B2_COMPARE_LESS, /* Records with keys less than query value */
+ H5B2_COMPARE_GREATER /* Records with keys greater than query value */
+} H5B2_compare_t;
+
+/*
+ * Each class of object that can be pointed to by a B-tree has a
+ * variable of this type that contains class variables and methods.
+ */
+typedef struct H5B2_class_t H5B2_class_t;
+struct H5B2_class_t {
+ H5B2_subid_t id; /* ID of B-tree class, as found in file */
+ const char *name; /* Name of B-tree class, for debugging */
+ size_t nrec_size; /* Size of native (memory) record */
+
+ /* Extensible array client callback methods */
+ void *(*crt_context)(void *udata); /* Create context for other client callbacks */
+ herr_t (*dst_context)(void *ctx); /* Destroy client callback context */
+ herr_t (*store)(void *nrecord, const void *udata); /* Store application record in native record table */
+ herr_t (*compare)(const void *rec1, const void *rec2, int *result); /* Compare two native records */
+ herr_t (*encode)(uint8_t *raw, const void *record, void *ctx); /* Encode record from native form to disk storage form */
+ herr_t (*decode)(const uint8_t *raw, void *record, void *ctx); /* Decode record from disk storage form to native form */
+ herr_t (*debug)(FILE *stream, int indent, int fwidth, /* Print a record for debugging */
+ const void *record, const void *ctx);
+};
+
+/* v2 B-tree creation parameters */
+typedef struct H5B2_create_t {
+ const H5B2_class_t *cls; /* v2 B-tree client class */
+ uint32_t node_size; /* Size of each node (in bytes) */
+ uint32_t rrec_size; /* Size of raw record (in bytes) */
+ uint8_t split_percent; /* % full to split nodes */
+ uint8_t merge_percent; /* % full to merge nodes */
+} H5B2_create_t;
+
+/* v2 B-tree metadata statistics info */
+typedef struct H5B2_stat_t {
+ unsigned depth; /* Depth of B-tree */
+ hsize_t nrecords; /* Number of records */
+} H5B2_stat_t;
+
+/* v2 B-tree info (forward decl - defined in H5B2pkg.h) */
+typedef struct H5B2_t H5B2_t;
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+H5_DLL H5B2_t *H5B2_create(H5F_t *f, hid_t dxpl_id, const H5B2_create_t *cparam,
+ void *ctx_udata);
+H5_DLL H5B2_t *H5B2_open(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *ctx_udata);
+H5_DLL herr_t H5B2_get_addr(const H5B2_t *bt2, haddr_t *addr/*out*/);
+H5_DLL herr_t H5B2_insert(H5B2_t *bt2, hid_t dxpl_id, void *udata);
+H5_DLL herr_t H5B2_iterate(H5B2_t *bt2, hid_t dxpl_id, H5B2_operator_t op,
+ void *op_data);
+H5_DLL htri_t H5B2_find(H5B2_t *bt2, hid_t dxpl_id, void *udata,
+ H5B2_found_t op, void *op_data);
+H5_DLL herr_t H5B2_index(H5B2_t *bt2, hid_t dxpl_id, H5_iter_order_t order,
+ hsize_t idx, H5B2_found_t op, void *op_data);
+H5_DLL herr_t H5B2_neighbor(H5B2_t *bt2, hid_t dxpl_id, H5B2_compare_t range,
+ void *udata, H5B2_found_t op, void *op_data);
+H5_DLL herr_t H5B2_modify(H5B2_t *bt2, hid_t dxpl_id, void *udata,
+ H5B2_modify_t op, void *op_data);
+H5_DLL herr_t H5B2_update(H5B2_t *bt2, hid_t dxpl_id, void *udata,
+ H5B2_modify_t op, void *op_data);
+H5_DLL herr_t H5B2_remove(H5B2_t *b2, hid_t dxpl_id, void *udata,
+ H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2_remove_by_idx(H5B2_t *bt2, hid_t dxpl_id,
+ H5_iter_order_t order, hsize_t idx, H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2_get_nrec(const H5B2_t *bt2, hsize_t *nrec);
+H5_DLL herr_t H5B2_size(H5B2_t *bt2, hid_t dxpl_id,
+ hsize_t *btree_size);
+H5_DLL herr_t H5B2_close(H5B2_t *bt2, hid_t dxpl_id);
+H5_DLL herr_t H5B2_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ void *ctx_udata, H5B2_remove_t op, void *op_data);
+H5_DLL herr_t H5B2_depend(H5B2_t *bt2, hid_t dxpl_id, H5AC_proxy_entry_t *parent);
+H5_DLL herr_t H5B2_patch_file(H5B2_t *fa, H5F_t *f);
+
+/* Statistics routines */
+H5_DLL herr_t H5B2_stat_info(H5B2_t *bt2, H5B2_stat_t *info);
+
+#endif /* _H5B2private_H */
+
diff --git a/src/H5B2public.h b/src/H5B2public.h
new file mode 100644
index 0000000..6e0b964
--- /dev/null
+++ b/src/H5B2public.h
@@ -0,0 +1,52 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2public.h
+ * Jan 31 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Public declarations for the v2 B-tree package.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5B2public_H
+#define _H5B2public_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/**********************************/
+/* Public API Function Prototypes */
+/**********************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5B2public_H */
+
diff --git a/src/H5B2stat.c b/src/H5B2stat.c
new file mode 100644
index 0000000..df99ad5
--- /dev/null
+++ b/src/H5B2stat.c
@@ -0,0 +1,147 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Monday, March 6, 2006
+ *
+ * Purpose: v2 B-tree metadata statistics functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_stat_info
+ *
+ * Purpose: Retrieve metadata statistics for a v2 B-tree
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, March 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_stat_info(H5B2_t *bt2, H5B2_stat_t *info)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(info);
+
+ /* Get information about the B-tree */
+ info->depth = bt2->hdr->depth;
+ info->nrecords = bt2->hdr->root.all_nrec;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2_stat_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_size
+ *
+ * Purpose: Iterate over all the records in the B-tree, collecting
+ * storage info.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * June 19 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_size(H5B2_t *bt2, hid_t dxpl_id, hsize_t *btree_size)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(btree_size);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Add size of header to B-tree metadata total */
+ *btree_size += hdr->hdr_size;
+
+ /* Iterate through records */
+ if(hdr->root.node_nrec > 0) {
+ /* Check for root node being a leaf */
+ if(hdr->depth == 0)
+ *btree_size += hdr->node_size;
+ else
+ /* Iterate through nodes */
+ if(H5B2__node_size(hdr, dxpl_id, hdr->depth, &hdr->root, hdr, btree_size) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "node iteration failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_size() */
+
diff --git a/src/H5B2test.c b/src/H5B2test.c
new file mode 100644
index 0000000..c10e5a8
--- /dev/null
+++ b/src/H5B2test.c
@@ -0,0 +1,687 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, February 3, 2005
+ *
+ * Purpose: v2 B-tree testing functions.
+ *
+ */
+
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+#define H5B2_TESTING /*suppress warning about H5B2 testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* v2 B-tree client callback context */
+typedef struct H5B2_test_ctx_t {
+ uint8_t sizeof_size; /* Size of file sizes */
+} H5B2_test_ctx_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* v2 B-tree driver callbacks for 'test' B-trees */
+static void *H5B2__test_crt_context(void *udata);
+static herr_t H5B2__test_dst_context(void *ctx);
+static herr_t H5B2__test_store(void *nrecord, const void *udata);
+static herr_t H5B2__test_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5B2__test_encode(uint8_t *raw, const void *nrecord, void *ctx);
+static herr_t H5B2__test_decode(const uint8_t *raw, void *nrecord, void *ctx);
+static herr_t H5B2__test_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* v2 B-tree driver callbacks for 'test2' B-trees */
+static herr_t H5B2__test2_store(void *nrecord, const void *udata);
+static herr_t H5B2__test2_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5B2__test2_encode(uint8_t *raw, const void *nrecord, void *ctx);
+static herr_t H5B2__test2_decode(const uint8_t *raw, void *nrecord, void *ctx);
+static herr_t H5B2__test2_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Class structure for testing simple B-tree records */
+const H5B2_class_t H5B2_TEST[1]={{ /* B-tree class information */
+ H5B2_TEST_ID, /* Type of B-tree */
+ "H5B2_TEST_ID", /* Name of B-tree class */
+ sizeof(hsize_t), /* Size of native record */
+ H5B2__test_crt_context, /* Create client callback context */
+ H5B2__test_dst_context, /* Destroy client callback context */
+ H5B2__test_store, /* Record storage callback */
+ H5B2__test_compare, /* Record comparison callback */
+ H5B2__test_encode, /* Record encoding callback */
+ H5B2__test_decode, /* Record decoding callback */
+ H5B2__test_debug /* Record debugging callback */
+}};
+
+/* Class structure for testing key/value B-tree records */
+const H5B2_class_t H5B2_TEST2[1]={{ /* B-tree class information */
+ H5B2_TEST2_ID, /* Type of B-tree */
+ "H5B2_TEST2_ID", /* Name of B-tree class */
+ sizeof(H5B2_test_rec_t), /* Size of native record */
+ H5B2__test_crt_context, /* Create client callback context */
+ H5B2__test_dst_context, /* Destroy client callback context */
+ H5B2__test2_store, /* Record storage callback */
+ H5B2__test2_compare, /* Record comparison callback */
+ H5B2__test2_encode, /* Record encoding callback */
+ H5B2__test2_decode, /* Record decoding callback */
+ H5B2__test2_debug /* Record debugging callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/* Declare a free list to manage the H5B2_test_ctx_t struct */
+H5FL_DEFINE_STATIC(H5B2_test_ctx_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_crt_context
+ *
+ * Purpose: Create client callback context
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__test_crt_context(void *_f)
+{
+ H5F_t *f = (H5F_t *)_f; /* User data for building callback context */
+ H5B2_test_ctx_t *ctx; /* Callback context structure */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Allocate callback context */
+ if(NULL == (ctx = H5FL_MALLOC(H5B2_test_ctx_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate callback context")
+
+ /* Determine the size of lengths in the file */
+ ctx->sizeof_size = H5F_SIZEOF_SIZE(f);
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__test_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_dst_context
+ *
+ * Purpose: Destroy client callback context
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_dst_context(void *_ctx)
+{
+ H5B2_test_ctx_t *ctx = (H5B2_test_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Release callback context */
+ ctx = H5FL_FREE(H5B2_test_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_store
+ *
+ * Purpose: Store native information into record for B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(hsize_t *)nrecord = *(const hsize_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_compare(const void *rec1, const void *rec2, int *result)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *result = (int)(*(const hssize_t *)rec1 - *(const hssize_t *)rec2);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_encode(uint8_t *raw, const void *nrecord, void *_ctx)
+{
+ H5B2_test_ctx_t *ctx = (H5B2_test_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ H5F_ENCODE_LENGTH_LEN(raw, *(const hsize_t *)nrecord, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 4, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_decode(const uint8_t *raw, void *nrecord, void *_ctx)
+{
+ H5B2_test_ctx_t *ctx = (H5B2_test_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ H5F_DECODE_LENGTH_LEN(raw, *(hsize_t *)nrecord, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 4, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test_debug(FILE *stream, int indent, int fwidth, const void *record,
+ const void H5_ATTR_UNUSED *_udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(record);
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, "Record:",
+ *(const hsize_t *)record);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test2_store
+ *
+ * Purpose: Store native information into record for B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test2_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5B2_test_rec_t *)nrecord = *(const H5B2_test_rec_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test2_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test2_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test2_compare(const void *rec1, const void *rec2, int *result)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *result = (int)(((const H5B2_test_rec_t *)rec1)->key - ((const H5B2_test_rec_t *)rec2)->key);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test2_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test2_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test2_encode(uint8_t *raw, const void *nrecord, void *_ctx)
+{
+ H5B2_test_ctx_t *ctx = (H5B2_test_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ H5F_ENCODE_LENGTH_LEN(raw, ((const H5B2_test_rec_t *)nrecord)->key, ctx->sizeof_size);
+ H5F_ENCODE_LENGTH_LEN(raw, ((const H5B2_test_rec_t *)nrecord)->val, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test2_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test2_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test2_decode(const uint8_t *raw, void *nrecord, void *_ctx)
+{
+ H5B2_test_ctx_t *ctx = (H5B2_test_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ H5F_DECODE_LENGTH_LEN(raw, ((H5B2_test_rec_t *)nrecord)->key, ctx->sizeof_size);
+ H5F_DECODE_LENGTH_LEN(raw, ((H5B2_test_rec_t *)nrecord)->val, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test2_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__test2_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__test2_debug(FILE *stream, int indent, int fwidth, const void *record,
+ const void H5_ATTR_UNUSED *_udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(record);
+
+ HDfprintf(stream, "%*s%-*s (%Hu, %Hu)\n", indent, "", fwidth, "Record:",
+ ((const H5B2_test_rec_t *)record)->key,
+ ((const H5B2_test_rec_t *)record)->val);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__test2_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_get_root_addr_test
+ *
+ * Purpose: Retrieve the root node's address
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 26, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_get_root_addr_test(H5B2_t *bt2, haddr_t *root_addr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(bt2);
+ HDassert(root_addr);
+
+ /* Get B-tree root addr */
+ *root_addr = bt2->hdr->root.addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2_get_root_addr_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_get_node_info_test
+ *
+ * Purpose: Determine information about a node holding a record in the B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 31, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B2_get_node_info_test(H5B2_t *bt2, hid_t dxpl_id, void *udata,
+ H5B2_node_info_test_t *ninfo)
+{
+ H5B2_hdr_t *hdr; /* Pointer to the B-tree header */
+ H5B2_node_ptr_t curr_node_ptr; /* Node pointer info for current node */
+ void *parent = NULL; /* Parent of current node */
+ uint16_t depth; /* Current depth of the tree */
+ int cmp; /* Comparison value of records */
+ unsigned idx; /* Location of record which matches key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+
+ /* Set the shared v2 B-tree header's file context for this operation */
+ bt2->hdr->f = bt2->f;
+
+ /* Get the v2 B-tree header */
+ hdr = bt2->hdr;
+
+ /* Make copy of the root node pointer to start search with */
+ curr_node_ptr = hdr->root;
+
+ /* Set initial parent, if doing swmr writes */
+ if(hdr->swmr_write)
+ parent = hdr;
+
+ /* Current depth of the tree */
+ depth = hdr->depth;
+
+ /* Check for empty tree */
+ if(0 == curr_node_ptr.node_nrec)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree has no records")
+
+ /* Walk down B-tree to find record or leaf node where record is located */
+ cmp = -1;
+ while(depth > 0 && cmp != 0) {
+ H5B2_internal_t *internal; /* Pointer to internal node in B-tree */
+ H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */
+
+ /* Lock B-tree current node */
+ if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, parent, &curr_node_ptr, depth, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate node pointer for child */
+ if(H5B2__locate_record(hdr->cls, internal->nrec, hdr->nat_off, internal->int_native,
+ udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ if(cmp > 0)
+ idx++;
+
+ if(cmp != 0) {
+ /* Get node pointer for next node to search */
+ next_node_ptr = internal->node_ptrs[idx];
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, (unsigned)(hdr->swmr_write ? H5AC__PIN_ENTRY_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Keep track of parent if necessary */
+ if(hdr->swmr_write)
+ parent = internal;
+
+ /* Set pointer to next node to load */
+ curr_node_ptr = next_node_ptr;
+ } /* end if */
+ else {
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_INT, curr_node_ptr.addr, internal, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Fill in information about the node */
+ ninfo->depth = depth;
+ ninfo->nrec = curr_node_ptr.node_nrec;
+
+ /* Indicate success */
+ HGOTO_DONE(SUCCEED)
+ } /* end else */
+
+ /* Decrement depth we're at in B-tree */
+ depth--;
+ } /* end while */
+
+ {
+ H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */
+
+ /* Lock B-tree leaf node */
+ if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, parent, &curr_node_ptr, FALSE, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node")
+
+ /* Unpin parent if necessary */
+ if(parent) {
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ parent = NULL;
+ } /* end if */
+
+ /* Locate record */
+ if(H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native,
+ udata, &idx, &cmp) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ /* Unlock current node */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_BT2_LEAF, curr_node_ptr.addr, leaf, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ /* Indicate the depth that the record was found */
+ if(cmp != 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record not in B-tree")
+ } /* end block */
+
+ /* Fill in information about the leaf node */
+ ninfo->depth = depth;
+ ninfo->nrec = curr_node_ptr.node_nrec;
+
+done:
+ if(parent) {
+ HDassert(ret_value < 0);
+ if(parent != hdr && H5AC_unpin_entry(parent) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin parent entry")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_get_node_info_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2_get_node_depth_test
+ *
+ * Purpose: Determine the depth of a node holding a record in the B-tree
+ *
+ * Note: Just a simple wrapper around the H5B2__get_node_info_test() routine
+ *
+ * Return: Success: non-negative depth of the node where the record
+ * was found
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, August 26, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5B2_get_node_depth_test(H5B2_t *bt2, hid_t dxpl_id, void *udata)
+{
+ H5B2_node_info_test_t ninfo; /* Node information */
+ int ret_value = -1; /* Return information */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(bt2);
+
+ /* Get information abou the node */
+ if(H5B2_get_node_info_test(bt2, dxpl_id, udata, &ninfo) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "error looking up node info")
+
+ /* Set return value */
+ ret_value = (int)ninfo.depth;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2_get_node_depth_test() */
+
diff --git a/src/H5Bcache.c b/src/H5Bcache.c
new file mode 100644
index 0000000..a0a75c8
--- /dev/null
+++ b/src/H5Bcache.c
@@ -0,0 +1,387 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Bcache.c
+ * Oct 31 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Implement B-tree metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Bmodule.h" /* This source code file is part of the H5B module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Bpkg.h" /* B-link trees */
+#include "H5Eprivate.h" /* Error handling */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+static herr_t H5B__cache_get_initial_load_size(void *udata, size_t *image_len);
+static void *H5B__cache_deserialize(const void *image, size_t len, void *udata,
+ hbool_t *dirty);
+static herr_t H5B__cache_image_len(const void *thing, size_t *image_len);
+static herr_t H5B__cache_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B__cache_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5B inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT[1] = {{
+ H5AC_BT_ID, /* Metadata client ID */
+ "v1 B-tree", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B__cache_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5B__cache_deserialize, /* 'deserialize' callback */
+ H5B__cache_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B__cache_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5B__cache_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__cache_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__cache_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(image_len);
+
+ /* Get shared info for B-tree */
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(udata->rc_shared);
+ HDassert(shared);
+
+ /* Set the image length size */
+ *image_len = shared->sizeof_rnode;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B__cache_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__cache_deserialize
+ *
+ * Purpose: Deserialize the data structure from disk.
+ *
+ * Return: Success: Pointer to a new B-tree node.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 24, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B__cache_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B_t *bt = NULL; /* Pointer to the deserialized B-tree node */
+ H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into image buffer */
+ uint8_t *native; /* Pointer to native keys */
+ unsigned u; /* Local index variable */
+ H5B_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate the B-tree node in memory */
+ if(NULL == (bt = H5FL_MALLOC(H5B_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate B-tree struct")
+ HDmemset(&bt->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Set & increment the ref-counted "shared" B-tree information for the node */
+ bt->rc_shared = udata->rc_shared;
+ H5UC_INC(bt->rc_shared);
+
+ /* Get a pointer to the shared info, for convenience */
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+
+ /* Allocate space for the native keys and child addresses */
+ if(NULL == (bt->native = H5FL_BLK_MALLOC(native_block, shared->sizeof_keys)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate buffer for native keys")
+ if(NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate buffer for child addresses")
+
+ /* magic number */
+ if(HDmemcmp(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* node type and level */
+ if(*image++ != (uint8_t)udata->type->id)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "incorrect B-tree node type")
+ bt->level = *image++;
+
+ /* entries used */
+ UINT16DECODE(image, bt->nchildren);
+
+ /* Check if bt->nchildren is greater than two_k */
+ if(bt->nchildren > shared->two_k)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "number of children is greater than maximum")
+
+ /* sibling pointers */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->left));
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->right));
+
+ /* the child/key pairs */
+ native = bt->native;
+ for(u = 0; u < bt->nchildren; u++) {
+ /* Decode native key value */
+ if((udata->type->decode)(shared, image, native) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key")
+ image += shared->sizeof_rkey;
+ native += udata->type->sizeof_nkey;
+
+ /* Decode address value */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, bt->child + u);
+ } /* end for */
+
+ /* Decode final key */
+ if(bt->nchildren > 0) {
+ /* Decode native key value */
+ if((udata->type->decode)(shared, image, native) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key")
+ } /* end if */
+
+ /* Sanity check */
+ HDassert((size_t)((const uint8_t *)image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = bt;
+
+done:
+ if(!ret_value && bt)
+ if(H5B__node_dest(bt) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__cache_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__cache_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__cache_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B_t *bt = (const H5B_t *)_thing; /* Pointer to the B-tree node */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(bt);
+ HDassert(image_len);
+
+ /* Get shared info for B-tree */
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+
+ /* Set the image length size */
+ *image_len = shared->sizeof_rnode;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B__cache_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__cache_serialize
+ *
+ * Purpose: Serialize the data structure for writing to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 24, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__cache_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B_t *bt = (H5B_t *)_thing; /* Pointer to the B-tree node */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into image buffer */
+ uint8_t *native; /* Pointer to native keys */
+ unsigned u; /* Local index counter */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(image);
+ HDassert(bt);
+ HDassert(bt->rc_shared);
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+ HDassert(shared->type);
+ HDassert(shared->type->encode);
+
+ /* magic number */
+ HDmemcpy(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += 4;
+
+ /* node type and level */
+ *image++ = (uint8_t)shared->type->id;
+
+ /* 2^8 limit: only 1 byte is used to store node level */
+ if(bt->level >= HDpow(2, LEVEL_BITS))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode node level")
+
+ H5_CHECK_OVERFLOW(bt->level, unsigned, uint8_t);
+ *image++ = (uint8_t)bt->level;
+
+ /* entries used */
+ UINT16ENCODE(image, bt->nchildren);
+
+ /* sibling pointers */
+ H5F_addr_encode(f, &image, bt->left);
+ H5F_addr_encode(f, &image, bt->right);
+
+ /* child keys and pointers */
+ native = bt->native;
+ for(u = 0; u < bt->nchildren; ++u) {
+ /* encode the key */
+ if(shared->type->encode(shared, image, native) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key")
+ image += shared->sizeof_rkey;
+ native += shared->type->sizeof_nkey;
+
+ /* encode the child address */
+ H5F_addr_encode(f, &image, bt->child[u]);
+ } /* end for */
+ if(bt->nchildren > 0) {
+ /* Encode the final key */
+ if(shared->type->encode(shared, image, native) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key")
+ image += shared->sizeof_rkey;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__cache_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__cache_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 26, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B__cache_free_icr(void *thing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Destroy B-tree node */
+ if(H5B__node_dest((H5B_t *)thing) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__cache_free_icr() */
+
diff --git a/src/H5Bdbg.c b/src/H5Bdbg.c
new file mode 100644
index 0000000..3881b44
--- /dev/null
+++ b/src/H5Bdbg.c
@@ -0,0 +1,291 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Bdbg.c
+ * Dec 11 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Debugging routines for B-link tree package.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Bmodule.h" /* This source code file is part of the H5B module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Bpkg.h" /* B-link trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_debug
+ *
+ * Purpose: Prints debugging info about a B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 4 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth,
+ const H5B_class_t *type, void *udata)
+{
+ H5B_t *bt = NULL;
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(type);
+
+ /* Currently does not support SWMR access */
+ HDassert(!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE));
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /*
+ * Load the tree node.
+ */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node")
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Tree type ID:",
+ ((shared->type->id) == H5B_SNODE_ID ? "H5B_SNODE_ID" :
+ ((shared->type->id) == H5B_CHUNK_ID ? "H5B_CHUNK_ID" : "Unknown!")));
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Size of node:",
+ shared->sizeof_rnode);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Size of raw (disk) key:",
+ shared->sizeof_rkey);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Dirty flag:",
+ bt->cache_info.is_dirty ? "True" : "False");
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Level:",
+ bt->level);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of left sibling:",
+ bt->left);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of right sibling:",
+ bt->right);
+ HDfprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth,
+ "Number of children (max):",
+ bt->nchildren, shared->two_k);
+
+ /*
+ * Print the child addresses
+ */
+ for(u = 0; u < bt->nchildren; u++) {
+ HDfprintf(stream, "%*sChild %d...\n", indent, "", u);
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Address:", bt->child[u]);
+
+ /* If there is a key debugging routine, use it to display the left & right keys */
+ if(type->debug_key) {
+ /* Decode the 'left' key & print it */
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Left Key:");
+ HDassert(H5B_NKEY(bt,shared,u));
+ (void)(type->debug_key)(stream, indent + 6, MAX(0, fwidth - 6),
+ H5B_NKEY(bt, shared, u), udata);
+
+ /* Decode the 'right' key & print it */
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Right Key:");
+ HDassert(H5B_NKEY(bt, shared, u + 1));
+ (void)(type->debug_key)(stream, indent + 6, MAX (0, fwidth - 6),
+ H5B_NKEY(bt, shared, u + 1), udata);
+ } /* end if */
+ } /* end for */
+
+done:
+ if(bt && H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B__assert
+ *
+ * Purpose: Verifies that the tree is structured correctly.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: aborts if something is wrong.
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5B_DEBUG
+herr_t
+H5B__assert(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type, void *udata)
+{
+ H5B_t *bt = NULL;
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+ H5B_shared_t *shared; /* Pointer to shared B-tree info */
+ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ int ncell, cmp;
+ static int ncalls = 0;
+ herr_t status;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* A queue of child data */
+ struct child_t {
+ haddr_t addr;
+ unsigned level;
+ struct child_t *next;
+ } *head = NULL, *tail = NULL, *prev = NULL, *cur = NULL, *tmp = NULL;
+
+ FUNC_ENTER_PACKAGE
+
+ if(0 == ncalls++) {
+ if(H5DEBUG(B))
+ fprintf(H5DEBUG(B), "H5B: debugging B-trees (expensive)\n");
+ } /* end if */
+
+ /* Get shared info for B-tree */
+ if(NULL == (rc_shared = (type->get_shared)(f, udata)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object")
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared);
+ HDassert(shared);
+
+ /* Initialize the queue */
+ cache_udata.f = f;
+ cache_udata.type = type;
+ cache_udata.rc_shared = rc_shared;
+ bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG);
+ HDassert(bt);
+ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared);
+ HDassert(shared);
+ cur = (struct child_t *)H5MM_calloc(sizeof(struct child_t));
+ HDassert(cur);
+ cur->addr = addr;
+ cur->level = bt->level;
+ head = tail = cur;
+
+ status = H5AC_unprotect(f, dxpl_id, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET);
+ HDassert(status >= 0);
+ bt = NULL; /* Make certain future references will be caught */
+
+ /*
+ * Do a breadth-first search of the tree. New nodes are added to the end
+ * of the queue as the `cur' pointer is advanced toward the end. We don't
+ * remove any nodes from the queue because we need them in the uniqueness
+ * test.
+ */
+ for(ncell = 0; cur; ncell++) {
+ bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, cur->addr, &cache_udata, H5AC__READ_ONLY_FLAG);
+ HDassert(bt);
+
+ /* Check node header */
+ HDassert(bt->level == cur->level);
+ if(cur->next && cur->next->level == bt->level)
+ HDassert(H5F_addr_eq(bt->right, cur->next->addr));
+ else
+ HDassert(!H5F_addr_defined(bt->right));
+ if(prev && prev->level == bt->level)
+ HDassert(H5F_addr_eq(bt->left, prev->addr));
+ else
+ HDassert(!H5F_addr_defined(bt->left));
+
+ if(cur->level > 0) {
+ unsigned u;
+
+ for(u = 0; u < bt->nchildren; u++) {
+ /*
+ * Check that child nodes haven't already been seen. If they
+ * have then the tree has a cycle.
+ */
+ for(tmp = head; tmp; tmp = tmp->next)
+ HDassert(H5F_addr_ne(tmp->addr, bt->child[u]));
+
+ /* Add the child node to the end of the queue */
+ tmp = (struct child_t *)H5MM_calloc(sizeof(struct child_t));
+ HDassert(tmp);
+ tmp->addr = bt->child[u];
+ tmp->level = bt->level - 1;
+ tail->next = tmp;
+ tail = tmp;
+
+ /* Check that the keys are monotonically increasing */
+ cmp = (type->cmp2)(H5B_NKEY(bt, shared, u), udata, H5B_NKEY(bt, shared, u + 1));
+ HDassert(cmp < 0);
+ } /* end for */
+ } /* end if */
+
+ /* Release node */
+ status = H5AC_unprotect(f, dxpl_id, H5AC_BT, cur->addr, bt, H5AC__NO_FLAGS_SET);
+ HDassert(status >= 0);
+ bt = NULL; /* Make certain future references will be caught */
+
+ /* Advance current location in queue */
+ prev = cur;
+ cur = cur->next;
+ } /* end for */
+
+ /* Free all entries from queue */
+ while(head) {
+ tmp = head->next;
+ H5MM_xfree(head);
+ head = tmp;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B__assert() */
+#endif /* H5B_DEBUG */
+
diff --git a/src/H5Bmodule.h b/src/H5Bmodule.h
new file mode 100644
index 0000000..bc46752
--- /dev/null
+++ b/src/H5Bmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5B package. Including this header means that the source file
+ * is part of the H5B package.
+ */
+#ifndef _H5Bmodule_H
+#define _H5Bmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5B_MODULE
+#define H5_MY_PKG H5B
+#define H5_MY_PKG_ERR H5E_BTREE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5Bmodule_H */
+
diff --git a/src/H5Bpkg.h b/src/H5Bpkg.h
new file mode 100644
index 0000000..14dce4f
--- /dev/null
+++ b/src/H5Bpkg.h
@@ -0,0 +1,94 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, May 15, 2003
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5B package. Source files outside the H5B package should
+ * include H5Bprivate.h instead.
+ */
+#if !(defined H5B_FRIEND || defined H5B_MODULE)
+#error "Do not include this file outside the H5B package!"
+#endif
+
+#ifndef _H5Bpkg_H
+#define _H5Bpkg_H
+
+/* Get package's private header */
+#include "H5Bprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Get the native key at a given index */
+#define H5B_NKEY(b, shared, idx) ((b)->native + (shared)->nkey[(idx)])
+#define LEVEL_BITS 8 /* # of bits for node level: 1 byte */
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* The B-tree node as stored in memory... */
+typedef struct H5B_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions */
+ /* _must_ be first field in structure */
+ H5UC_t *rc_shared; /*ref-counted shared info */
+ unsigned level; /*node level */
+ unsigned nchildren; /*number of child pointers */
+ haddr_t left; /*address of left sibling */
+ haddr_t right; /*address of right sibling */
+ uint8_t *native; /*array of keys in native format */
+ haddr_t *child; /*2k child pointers */
+} H5B_t;
+
+/* Callback info for loading a B-tree node into the cache */
+typedef struct H5B_cache_ud_t {
+ H5F_t *f; /* File that B-tree node is within */
+ const struct H5B_class_t *type; /* Type of tree */
+ H5UC_t *rc_shared; /* Ref-counted shared info */
+} H5B_cache_ud_t;
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare a free list to manage the haddr_t sequence information */
+H5FL_SEQ_EXTERN(haddr_t);
+
+/* Declare a PQ free list to manage the native block information */
+H5FL_BLK_EXTERN(native_block);
+
+/* Declare a free list to manage the H5B_t struct */
+H5FL_EXTERN(H5B_t);
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+H5_DLL herr_t H5B__node_dest(H5B_t *bt);
+#ifdef H5B_DEBUG
+herr_t H5B__assert(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type,
+ void *udata);
+#endif
+
+#endif /*_H5Bpkg_H*/
+
diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h
new file mode 100644
index 0000000..cb038ec
--- /dev/null
+++ b/src/H5Bprivate.h
@@ -0,0 +1,180 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Bprivate.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Private non-prototype header.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5Bprivate_H
+#define _H5Bprivate_H
+
+#include "H5Bpublic.h" /*API prototypes */
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* File access */
+#include "H5UCprivate.h" /* Reference counted object functions */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/*
+ * Feature: Define this constant if you want to check B-tree consistency
+ * after each B-tree operation. Note that this slows down the
+ * library considerably! Debugging the B-tree depends on assert()
+ * being enabled.
+ */
+#ifdef NDEBUG
+# undef H5B_DEBUG
+#endif
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* B-tree IDs for various internal things. */
+/* Note - if more of these are added, any 'K' values (for internal or leaf
+ * nodes) they use will need to be stored in the file somewhere. -QAK
+ */
+typedef enum H5B_subid_t {
+ H5B_SNODE_ID = 0, /*B-tree is for symbol table nodes */
+ H5B_CHUNK_ID = 1, /*B-tree is for chunked dataset storage */
+ H5B_NUM_BTREE_ID /* Number of B-tree key IDs (must be last) */
+} H5B_subid_t;
+
+/* Define return values from B-tree insertion callbacks */
+typedef enum H5B_ins_t {
+ H5B_INS_ERROR = -1, /*error return value */
+ H5B_INS_NOOP = 0, /*insert made no changes */
+ H5B_INS_LEFT = 1, /*insert new node to left of cur node */
+ H5B_INS_RIGHT = 2, /*insert new node to right of cur node */
+ H5B_INS_CHANGE = 3, /*change child address for cur node */
+ H5B_INS_FIRST = 4, /*insert first node in (sub)tree */
+ H5B_INS_REMOVE = 5 /*remove current node */
+} H5B_ins_t;
+
+/* Enum for specifying the direction of the critical key in relation to the
+ * child */
+typedef enum H5B_dir_t {
+ H5B_LEFT = 0, /* Critical key is to the left */
+ H5B_RIGHT = 1 /* Critical key is to the right */
+} H5B_dir_t;
+
+/* Define the operator callback function pointer for H5B_iterate() */
+typedef int (*H5B_operator_t)(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+
+/* Each B-tree has certain information that can be shared across all
+ * the instances of nodes in that B-tree.
+ */
+typedef struct H5B_shared_t {
+ const struct H5B_class_t *type; /* Type of tree */
+ unsigned two_k; /* 2*"K" value for tree's nodes */
+ size_t sizeof_rkey; /* Size of raw (disk) key */
+ size_t sizeof_rnode; /* Size of raw (disk) node */
+ size_t sizeof_keys; /* Size of native (memory) key node */
+ size_t sizeof_addr; /* Size of file address (in bytes) */
+ size_t sizeof_len; /* Size of file lengths (in bytes) */
+ uint8_t *page; /* Disk page */
+ size_t *nkey; /* Offsets of each native key in native key buffer */
+ void *udata; /* 'Local' info for a B-tree */
+} H5B_shared_t;
+
+/*
+ * Each class of object that can be pointed to by a B-link tree has a
+ * variable of this type that contains class variables and methods. Each
+ * tree has a K (1/2 rank) value on a per-file basis. The file_create_parms
+ * has an array of K values indexed by the `id' class field below. The
+ * array is initialized with the HDF5_BTREE_K_DEFAULT macro.
+ */
+
+typedef struct H5B_class_t {
+ H5B_subid_t id; /*id as found in file*/
+ size_t sizeof_nkey; /*size of native (memory) key*/
+ H5UC_t * (*get_shared)(const H5F_t*, const void*); /*shared info for node */
+ herr_t (*new_node)(H5F_t*, hid_t, H5B_ins_t, void*, void*, void*, haddr_t*);
+ int (*cmp2)(void*, void*, void*); /*compare 2 keys */
+ int (*cmp3)(void*, void*, void*); /*compare 3 keys */
+ htri_t (*found)(H5F_t*, hid_t, haddr_t, const void*, void*);
+
+ /* insert new data */
+ H5B_ins_t (*insert)(H5F_t*, hid_t, haddr_t, void*, hbool_t*, void*, void*,
+ void*, hbool_t*, haddr_t*);
+
+ /* min insert uses min leaf, not new(), similarily for max insert */
+ hbool_t follow_min;
+ hbool_t follow_max;
+
+ /* The direction of the key that is intrinsically associated with each node */
+ H5B_dir_t critical_key;
+
+ /* remove existing data */
+ H5B_ins_t (*remove)(H5F_t*, hid_t, haddr_t, void*, hbool_t*, void*, void*,
+ hbool_t*);
+
+ /* encode, decode, debug key values */
+ herr_t (*decode)(const H5B_shared_t*, const uint8_t*, void*);
+ herr_t (*encode)(const H5B_shared_t*, uint8_t*, const void*);
+ herr_t (*debug_key)(FILE*, int, int, const void*, const void*);
+} H5B_class_t;
+
+/* Information about B-tree */
+typedef struct H5B_info_t {
+ hsize_t size; /* Size of B-tree nodes */
+ hsize_t num_nodes; /* Number of B-tree nodes */
+} H5B_info_t;
+
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+H5_DLL herr_t H5B_create(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ void *udata, haddr_t *addr_p/*out*/);
+H5_DLL herr_t H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata);
+H5_DLL herr_t H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata);
+H5_DLL herr_t H5B_iterate(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, H5B_operator_t op, void *udata);
+H5_DLL herr_t H5B_get_info(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, H5B_info_t *bt_info, H5B_operator_t op, void *udata);
+H5_DLL herr_t H5B_remove(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata);
+H5_DLL herr_t H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr, void *udata);
+H5_DLL H5B_shared_t *H5B_shared_new(const H5F_t *f, const H5B_class_t *type,
+ size_t sizeof_rkey);
+H5_DLL herr_t H5B_shared_free(void *_shared);
+H5_DLL herr_t H5B_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream,
+ int indent, int fwidth, const H5B_class_t *type, void *udata);
+H5_DLL htri_t H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type,
+ haddr_t addr);
+#endif /* _H5Bprivate_H */
+
diff --git a/src/H5Bpublic.h b/src/H5Bpublic.h
new file mode 100644
index 0000000..1764f61
--- /dev/null
+++ b/src/H5Bpublic.h
@@ -0,0 +1,39 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Bproto.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public declarations for the H5B package.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Bpublic_H
+#define _H5Bpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/H5C.c b/src/H5C.c
new file mode 100644
index 0000000..e6770ec
--- /dev/null
+++ b/src/H5C.c
@@ -0,0 +1,8952 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5C.c
+ * June 1 2004
+ * John Mainzer
+ *
+ * Purpose: Functions in this file implement a generic cache for
+ * things which exist on disk, and which may be
+ * unambiguously referenced by their disk addresses.
+ *
+ * The code in this module was initially written in
+ * support of a complete re-write of the metadata cache
+ * in H5AC.c However, other uses for the cache code
+ * suggested themselves, and thus this file was created
+ * in an attempt to support re-use.
+ *
+ * For a detailed overview of the cache, please see the
+ * header comment for H5C_t in H5Cpkg.h.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**************************************************************************
+ *
+ * To Do:
+ *
+ * Code Changes:
+ *
+ * - Remove extra functionality in H5C__flush_single_entry()?
+ *
+ * - Change protect/unprotect to lock/unlock.
+ *
+ * - Flush entries in increasing address order in
+ * H5C__make_space_in_cache().
+ *
+ * - Also in H5C__make_space_in_cache(), use high and low water marks
+ * to reduce the number of I/O calls.
+ *
+ * - When flushing, attempt to combine contiguous entries to reduce
+ * I/O overhead. Can't do this just yet as some entries are not
+ * contiguous. Do this in parallel only or in serial as well?
+ *
+ * - Create MPI type for dirty objects when flushing in parallel.
+ *
+ * - Now that TBBT routines aren't used, fix nodes in memory to
+ * point directly to the skip list node from the LRU list, eliminating
+ * skip list lookups when evicting objects from the cache.
+ *
+ * Tests:
+ *
+ * - Trim execution time. (This is no longer a major issue with the
+ * shift from the TBBT to a hash table for indexing.)
+ *
+ * - Add random tests.
+ *
+ **************************************************************************/
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5F_FRIEND /* suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#if H5C_DO_MEMORY_SANITY_CHECKS
+#define H5C_IMAGE_EXTRA_SPACE 8
+#define H5C_IMAGE_SANITY_VALUE "DeadBeef"
+#else /* H5C_DO_MEMORY_SANITY_CHECKS */
+#define H5C_IMAGE_EXTRA_SPACE 0
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5C__auto_adjust_cache_size(H5F_t * f,
+ hid_t dxpl_id,
+ hbool_t write_permitted);
+
+static herr_t H5C__autoadjust__ageout(H5F_t * f,
+ hid_t dxpl_id,
+ double hit_rate,
+ enum H5C_resize_status * status_ptr,
+ size_t * new_max_cache_size_ptr,
+ hbool_t write_permitted);
+
+static herr_t H5C__autoadjust__ageout__cycle_epoch_marker(H5C_t * cache_ptr);
+
+static herr_t H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f,
+ hid_t dxpl_id,
+ hbool_t write_permitted);
+
+static herr_t H5C__autoadjust__ageout__insert_new_marker(H5C_t * cache_ptr);
+
+static herr_t H5C__autoadjust__ageout__remove_all_markers(H5C_t * cache_ptr);
+
+static herr_t H5C__autoadjust__ageout__remove_excess_markers(H5C_t * cache_ptr);
+
+static herr_t H5C__flash_increase_cache_size(H5C_t * cache_ptr,
+ size_t old_entry_size, size_t new_entry_size);
+
+static herr_t H5C_flush_invalidate_cache(H5F_t *f, hid_t dxpl_id, unsigned flags);
+
+static herr_t H5C_flush_invalidate_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring,
+ unsigned flags);
+
+static herr_t H5C_flush_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring,
+ unsigned flags);
+
+static void * H5C_load_entry(H5F_t * f,
+ hid_t dxpl_id,
+#ifdef H5_HAVE_PARALLEL
+ hbool_t coll_access,
+#endif /* H5_HAVE_PARALLEL */
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * udata);
+
+static herr_t H5C__mark_flush_dep_dirty(H5C_cache_entry_t * entry);
+
+static herr_t H5C__mark_flush_dep_clean(H5C_cache_entry_t * entry);
+
+static herr_t H5C__serialize_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring);
+static herr_t H5C__serialize_single_entry(H5F_t *f, hid_t dxpl_id,
+ H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr);
+
+static herr_t H5C__verify_len_eoa(H5F_t *f, const H5C_class_t * type,
+ haddr_t addr, size_t *len, hbool_t actual);
+
+#if H5C_DO_SLIST_SANITY_CHECKS
+static hbool_t H5C_entry_in_skip_list(H5C_t * cache_ptr,
+ H5C_cache_entry_t *target_ptr);
+#endif /* H5C_DO_SLIST_SANITY_CHECKS */
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+static herr_t H5C_validate_lru_list(H5C_t * cache_ptr);
+static herr_t H5C_validate_pinned_entry_list(H5C_t * cache_ptr);
+static herr_t H5C_validate_protected_entry_list(H5C_t * cache_ptr);
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+#ifndef NDEBUG
+static void H5C__assert_flush_dep_nocycle(const H5C_cache_entry_t * entry,
+ const H5C_cache_entry_t * base_entry);
+#endif /* NDEBUG */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the tag info struct */
+H5FL_DEFINE(H5C_tag_info_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5C_t struct */
+H5FL_DEFINE_STATIC(H5C_t);
+
+/* Declare a free list to manage flush dependency arrays */
+H5FL_BLK_DEFINE_STATIC(parent);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_create
+ *
+ * Purpose: Allocate, initialize, and return the address of a new
+ * instance of H5C_t.
+ *
+ * In general, the max_cache_size parameter must be positive,
+ * and the min_clean_size parameter must lie in the closed
+ * interval [0, max_cache_size].
+ *
+ * The check_write_permitted parameter must either be NULL,
+ * or point to a function of type H5C_write_permitted_func_t.
+ * If it is NULL, the cache will use the write_permitted
+ * flag to determine whether writes are permitted.
+ *
+ * Return: Success: Pointer to the new instance.
+ *
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+H5C_t *
+H5C_create(size_t max_cache_size,
+ size_t min_clean_size,
+ int max_type_id,
+ const H5C_class_t * const * class_table_ptr,
+ H5C_write_permitted_func_t check_write_permitted,
+ hbool_t write_permitted,
+ H5C_log_flush_func_t log_flush,
+ void * aux_ptr)
+{
+ int i;
+ H5C_t * cache_ptr = NULL;
+ H5C_t * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert( max_cache_size >= H5C__MIN_MAX_CACHE_SIZE );
+ HDassert( max_cache_size <= H5C__MAX_MAX_CACHE_SIZE );
+ HDassert( min_clean_size <= max_cache_size );
+
+ HDassert( max_type_id >= 0 );
+ HDassert( max_type_id < H5C__MAX_NUM_TYPE_IDS );
+ HDassert( class_table_ptr );
+
+ for ( i = 0; i <= max_type_id; i++ ) {
+ HDassert( (class_table_ptr)[i] );
+ HDassert(HDstrlen((class_table_ptr)[i]->name) > 0);
+ } /* end for */
+
+ if(NULL == (cache_ptr = H5FL_CALLOC(H5C_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ if(NULL == (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list")
+
+ if(NULL == (cache_ptr->tag_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list for tagged entry addresses")
+
+ /* If we get this far, we should succeed. Go ahead and initialize all
+ * the fields.
+ */
+
+ cache_ptr->magic = H5C__H5C_T_MAGIC;
+
+ cache_ptr->flush_in_progress = FALSE;
+
+ cache_ptr->logging_enabled = FALSE;
+
+ cache_ptr->currently_logging = FALSE;
+
+ cache_ptr->log_file_ptr = NULL;
+
+ cache_ptr->trace_file_ptr = NULL;
+
+ cache_ptr->aux_ptr = aux_ptr;
+
+ cache_ptr->max_type_id = max_type_id;
+
+ cache_ptr->class_table_ptr = class_table_ptr;
+
+ cache_ptr->max_cache_size = max_cache_size;
+ cache_ptr->min_clean_size = min_clean_size;
+
+ cache_ptr->check_write_permitted = check_write_permitted;
+ cache_ptr->write_permitted = write_permitted;
+
+ cache_ptr->log_flush = log_flush;
+
+ cache_ptr->evictions_enabled = TRUE;
+ cache_ptr->close_warning_received = FALSE;
+
+ cache_ptr->index_len = 0;
+ cache_ptr->index_size = (size_t)0;
+ cache_ptr->clean_index_size = (size_t)0;
+ cache_ptr->dirty_index_size = (size_t)0;
+
+ for(i = 0; i < H5C_RING_NTYPES; i++) {
+ cache_ptr->index_ring_len[i] = 0;
+ cache_ptr->index_ring_size[i] = (size_t)0;
+ cache_ptr->clean_index_ring_size[i] = (size_t)0;
+ cache_ptr->dirty_index_ring_size[i] = (size_t)0;
+
+ cache_ptr->slist_ring_len[i] = 0;
+ cache_ptr->slist_ring_size[i] = (size_t)0;
+ } /* end for */
+
+ for(i = 0; i < H5C__HASH_TABLE_LEN; i++)
+ (cache_ptr->index)[i] = NULL;
+
+ cache_ptr->il_len = 0;
+ cache_ptr->il_size = (size_t)0;
+ cache_ptr->il_head = NULL;
+ cache_ptr->il_tail = NULL;
+
+ /* Tagging Field Initializations */
+ cache_ptr->ignore_tags = FALSE;
+
+ cache_ptr->slist_changed = FALSE;
+ cache_ptr->slist_len = 0;
+ cache_ptr->slist_size = (size_t)0;
+
+#if H5C_DO_SANITY_CHECKS
+ cache_ptr->slist_len_increase = 0;
+ cache_ptr->slist_size_increase = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ cache_ptr->entries_removed_counter = 0;
+ cache_ptr->last_entry_removed_ptr = NULL;
+ cache_ptr->entry_watched_for_removal = NULL;
+
+ cache_ptr->pl_len = 0;
+ cache_ptr->pl_size = (size_t)0;
+ cache_ptr->pl_head_ptr = NULL;
+ cache_ptr->pl_tail_ptr = NULL;
+
+ cache_ptr->pel_len = 0;
+ cache_ptr->pel_size = (size_t)0;
+ cache_ptr->pel_head_ptr = NULL;
+ cache_ptr->pel_tail_ptr = NULL;
+
+ cache_ptr->LRU_list_len = 0;
+ cache_ptr->LRU_list_size = (size_t)0;
+ cache_ptr->LRU_head_ptr = NULL;
+ cache_ptr->LRU_tail_ptr = NULL;
+
+#ifdef H5_HAVE_PARALLEL
+ cache_ptr->coll_list_len = 0;
+ cache_ptr->coll_list_size = (size_t)0;
+ cache_ptr->coll_head_ptr = NULL;
+ cache_ptr->coll_tail_ptr = NULL;
+ cache_ptr->coll_write_list = NULL;
+#endif /* H5_HAVE_PARALLEL */
+
+ cache_ptr->cLRU_list_len = 0;
+ cache_ptr->cLRU_list_size = (size_t)0;
+ cache_ptr->cLRU_head_ptr = NULL;
+ cache_ptr->cLRU_tail_ptr = NULL;
+
+ cache_ptr->dLRU_list_len = 0;
+ cache_ptr->dLRU_list_size = (size_t)0;
+ cache_ptr->dLRU_head_ptr = NULL;
+ cache_ptr->dLRU_tail_ptr = NULL;
+
+ cache_ptr->size_increase_possible = FALSE;
+ cache_ptr->flash_size_increase_possible = FALSE;
+ cache_ptr->flash_size_increase_threshold = 0;
+ cache_ptr->size_decrease_possible = FALSE;
+ cache_ptr->resize_enabled = FALSE;
+ cache_ptr->cache_full = FALSE;
+ cache_ptr->size_decreased = FALSE;
+ cache_ptr->resize_in_progress = FALSE;
+ cache_ptr->msic_in_progress = FALSE;
+
+ (cache_ptr->resize_ctl).version = H5C__CURR_AUTO_SIZE_CTL_VER;
+ (cache_ptr->resize_ctl).rpt_fcn = NULL;
+ (cache_ptr->resize_ctl).set_initial_size = FALSE;
+ (cache_ptr->resize_ctl).initial_size = H5C__DEF_AR_INIT_SIZE;
+ (cache_ptr->resize_ctl).min_clean_fraction = H5C__DEF_AR_MIN_CLEAN_FRAC;
+ (cache_ptr->resize_ctl).max_size = H5C__DEF_AR_MAX_SIZE;
+ (cache_ptr->resize_ctl).min_size = H5C__DEF_AR_MIN_SIZE;
+ (cache_ptr->resize_ctl).epoch_length = H5C__DEF_AR_EPOCH_LENGTH;
+
+ (cache_ptr->resize_ctl).incr_mode = H5C_incr__off;
+ (cache_ptr->resize_ctl).lower_hr_threshold = H5C__DEF_AR_LOWER_THRESHHOLD;
+ (cache_ptr->resize_ctl).increment = H5C__DEF_AR_INCREMENT;
+ (cache_ptr->resize_ctl).apply_max_increment = TRUE;
+ (cache_ptr->resize_ctl).max_increment = H5C__DEF_AR_MAX_INCREMENT;
+
+ (cache_ptr->resize_ctl).flash_incr_mode = H5C_flash_incr__off;
+ (cache_ptr->resize_ctl).flash_multiple = 1.0f;
+ (cache_ptr->resize_ctl).flash_threshold = 0.25f;
+
+ (cache_ptr->resize_ctl).decr_mode = H5C_decr__off;
+ (cache_ptr->resize_ctl).upper_hr_threshold = H5C__DEF_AR_UPPER_THRESHHOLD;
+ (cache_ptr->resize_ctl).decrement = H5C__DEF_AR_DECREMENT;
+ (cache_ptr->resize_ctl).apply_max_decrement = TRUE;
+ (cache_ptr->resize_ctl).max_decrement = H5C__DEF_AR_MAX_DECREMENT;
+ (cache_ptr->resize_ctl).epochs_before_eviction = H5C__DEF_AR_EPCHS_B4_EVICT;
+ (cache_ptr->resize_ctl).apply_empty_reserve = TRUE;
+ (cache_ptr->resize_ctl).empty_reserve = H5C__DEF_AR_EMPTY_RESERVE;
+
+ cache_ptr->epoch_markers_active = 0;
+
+ /* no need to initialize the ring buffer itself */
+ cache_ptr->epoch_marker_ringbuf_first = 1;
+ cache_ptr->epoch_marker_ringbuf_last = 0;
+ cache_ptr->epoch_marker_ringbuf_size = 0;
+
+ /* Initialize all epoch marker entries' fields to zero/FALSE/NULL */
+ HDmemset(cache_ptr->epoch_markers, 0, sizeof(cache_ptr->epoch_markers));
+
+ /* Set non-zero/FALSE/NULL fields for epoch markers */
+ for ( i = 0; i < H5C__MAX_EPOCH_MARKERS; i++ )
+ {
+ ((cache_ptr->epoch_markers)[i]).magic =
+ H5C__H5C_CACHE_ENTRY_T_MAGIC;
+ ((cache_ptr->epoch_markers)[i]).addr = (haddr_t)i;
+ ((cache_ptr->epoch_markers)[i]).type = H5AC_EPOCH_MARKER;
+ }
+
+ /* Initialize cache image generation on file close related fields.
+ * Initial value of image_ctl must match H5C__DEFAULT_CACHE_IMAGE_CTL
+ * in H5Cprivate.h.
+ */
+ cache_ptr->image_ctl.version = H5C__CURR_CACHE_IMAGE_CTL_VER;
+ cache_ptr->image_ctl.generate_image = FALSE;
+ cache_ptr->image_ctl.save_resize_status = FALSE;
+ cache_ptr->image_ctl.entry_ageout = -1;
+ cache_ptr->image_ctl.flags = H5C_CI__ALL_FLAGS;
+
+ cache_ptr->serialization_in_progress= FALSE;
+ cache_ptr->load_image = FALSE;
+ cache_ptr->image_loaded = FALSE;
+ cache_ptr->delete_image = FALSE;
+ cache_ptr->image_addr = HADDR_UNDEF;
+ cache_ptr->image_len = 0;
+ cache_ptr->image_data_len = 0;
+
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+ cache_ptr->entry_fd_height_change_counter = 0;
+
+ cache_ptr->num_entries_in_image = 0;
+ cache_ptr->image_entries = NULL;
+ cache_ptr->image_buffer = NULL;
+
+ /* initialize free space manager related fields: */
+ cache_ptr->rdfsm_settled = FALSE;
+ cache_ptr->mdfsm_settled = FALSE;
+
+ if(H5C_reset_cache_hit_rate_stats(cache_ptr) < 0)
+ /* this should be impossible... */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "H5C_reset_cache_hit_rate_stats failed")
+
+ H5C_stats__reset(cache_ptr);
+
+ cache_ptr->prefix[0] = '\0'; /* empty string */
+
+#ifndef NDEBUG
+ cache_ptr->get_entry_ptr_from_addr_counter = 0;
+#endif /* NDEBUG */
+
+ /* Set return value */
+ ret_value = cache_ptr;
+
+done:
+ if(NULL == ret_value) {
+ if(cache_ptr != NULL) {
+ if(cache_ptr->slist_ptr != NULL)
+ H5SL_close(cache_ptr->slist_ptr);
+
+ if(cache_ptr->tag_list != NULL)
+ H5SL_close(cache_ptr->tag_list);
+
+ cache_ptr->magic = 0;
+ cache_ptr = H5FL_FREE(H5C_t, cache_ptr);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_def_auto_resize_rpt_fcn
+ *
+ * Purpose: Print results of a automatic cache resize.
+ *
+ * This function should only be used where HDprintf() behaves
+ * well -- i.e. not on Windows.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 10/27/04
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5C_def_auto_resize_rpt_fcn(H5C_t * cache_ptr,
+#ifndef NDEBUG
+ int32_t version,
+#else /* NDEBUG */
+ int32_t H5_ATTR_UNUSED version,
+#endif /* NDEBUG */
+ double hit_rate,
+ enum H5C_resize_status status,
+ size_t old_max_cache_size,
+ size_t new_max_cache_size,
+ size_t old_min_clean_size,
+ size_t new_min_clean_size)
+{
+ HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( version == H5C__CURR_AUTO_RESIZE_RPT_FCN_VER );
+
+ switch ( status )
+ {
+ case in_spec:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- no change. (hit rate = %lf)\n",
+ cache_ptr->prefix, hit_rate);
+ break;
+
+ case increase:
+ HDassert( hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold );
+ HDassert( old_max_cache_size < new_max_cache_size );
+
+ HDfprintf(stdout,
+ "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n",
+ cache_ptr->prefix, hit_rate,
+ (cache_ptr->resize_ctl).lower_hr_threshold);
+
+ HDfprintf(stdout,
+ "%s cache size increased from (%Zu/%Zu) to (%Zu/%Zu).\n",
+ cache_ptr->prefix,
+ old_max_cache_size,
+ old_min_clean_size,
+ new_max_cache_size,
+ new_min_clean_size);
+ break;
+
+ case flash_increase:
+ HDassert( old_max_cache_size < new_max_cache_size );
+
+ HDfprintf(stdout,
+ "%sflash cache resize(%d) -- size threshold = %Zu.\n",
+ cache_ptr->prefix,
+ (int)((cache_ptr->resize_ctl).flash_incr_mode),
+ cache_ptr->flash_size_increase_threshold);
+
+ HDfprintf(stdout,
+ "%s cache size increased from (%Zu/%Zu) to (%Zu/%Zu).\n",
+ cache_ptr->prefix,
+ old_max_cache_size,
+ old_min_clean_size,
+ new_max_cache_size,
+ new_min_clean_size);
+ break;
+
+ case decrease:
+ HDassert( old_max_cache_size > new_max_cache_size );
+
+ switch ( (cache_ptr->resize_ctl).decr_mode )
+ {
+ case H5C_decr__off:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease off. HR = %lf\n",
+ cache_ptr->prefix, hit_rate);
+ break;
+
+ case H5C_decr__threshold:
+ HDassert( hit_rate >
+ (cache_ptr->resize_ctl).upper_hr_threshold );
+
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease by threshold. HR = %lf > %6.5lf\n",
+ cache_ptr->prefix, hit_rate,
+ (cache_ptr->resize_ctl).upper_hr_threshold);
+
+ HDfprintf(stdout, "%sout of bounds high (%6.5lf).\n",
+ cache_ptr->prefix,
+ (cache_ptr->resize_ctl).upper_hr_threshold);
+ break;
+
+ case H5C_decr__age_out:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease by ageout. HR = %lf\n",
+ cache_ptr->prefix, hit_rate);
+ break;
+
+ case H5C_decr__age_out_with_threshold:
+ HDassert( hit_rate >
+ (cache_ptr->resize_ctl).upper_hr_threshold );
+
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease by ageout with threshold. HR = %lf > %6.5lf\n",
+ cache_ptr->prefix, hit_rate,
+ (cache_ptr->resize_ctl).upper_hr_threshold);
+ break;
+
+ default:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease by unknown mode. HR = %lf\n",
+ cache_ptr->prefix, hit_rate);
+ }
+
+ HDfprintf(stdout,
+ "%s cache size decreased from (%Zu/%Zu) to (%Zu/%Zu).\n",
+ cache_ptr->prefix,
+ old_max_cache_size,
+ old_min_clean_size,
+ new_max_cache_size,
+ new_min_clean_size);
+ break;
+
+ case at_max_size:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n",
+ cache_ptr->prefix, hit_rate,
+ (cache_ptr->resize_ctl).lower_hr_threshold);
+ HDfprintf(stdout,
+ "%s cache already at maximum size so no change.\n",
+ cache_ptr->prefix);
+ break;
+
+ case at_min_size:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- hit rate (%lf) -- can't decrease.\n",
+ cache_ptr->prefix, hit_rate);
+ HDfprintf(stdout, "%s cache already at minimum size.\n",
+ cache_ptr->prefix);
+ break;
+
+ case increase_disabled:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- increase disabled -- HR = %lf.",
+ cache_ptr->prefix, hit_rate);
+ break;
+
+ case decrease_disabled:
+ HDfprintf(stdout,
+ "%sAuto cache resize -- decrease disabled -- HR = %lf.\n",
+ cache_ptr->prefix, hit_rate);
+ break;
+
+ case not_full:
+ HDassert( hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold );
+
+ HDfprintf(stdout,
+ "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n",
+ cache_ptr->prefix, hit_rate,
+ (cache_ptr->resize_ctl).lower_hr_threshold);
+ HDfprintf(stdout,
+ "%s cache not full so no increase in size.\n",
+ cache_ptr->prefix);
+ break;
+
+ default:
+ HDfprintf(stdout, "%sAuto cache resize -- unknown status code.\n",
+ cache_ptr->prefix);
+ break;
+ }
+
+ return;
+
+} /* H5C_def_auto_resize_rpt_fcn() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_free_tag_list_cb
+ *
+ * Purpose: Callback function to free tag nodes from the skip list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * January 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C_free_tag_list_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *op_data)
+{
+ H5C_tag_info_t *tag_info = (H5C_tag_info_t *)_item;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(tag_info);
+
+ /* Release the item */
+ tag_info = H5FL_FREE(H5C_tag_info_t, tag_info);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5C_free_tag_list_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_prep_for_file_close
+ *
+ * Purpose: This function should be called just prior to the cache
+ * flushes at file close. There should be no protected
+ * entries in the cache at this point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/3/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_prep_for_file_close(H5F_t *f, hid_t dxpl_id)
+{
+ H5C_t * cache_ptr;
+ hbool_t image_generated = FALSE; /* Whether a cache image was generated */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* For now at least, it is possible to receive the
+ * close warning more than once -- the following
+ * if statement handles this.
+ */
+ if(cache_ptr->close_warning_received)
+ HGOTO_DONE(SUCCEED)
+ cache_ptr->close_warning_received = TRUE;
+
+ /* Make certain there aren't any protected entries */
+ HDassert(cache_ptr->pl_len == 0);
+
+ /* Prepare cache image */
+ if(H5C__prep_image_for_file_close(f, dxpl_id, &image_generated) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cache image")
+
+#ifdef H5_HAVE_PARALLEL
+ if ( ( H5F_INTENT(f) & H5F_ACC_RDWR ) &&
+ ( ! image_generated ) &&
+ ( cache_ptr->aux_ptr != NULL ) &&
+ ( f->shared->fs_persist ) ) {
+ /* If persistent free space managers are enabled, flushing the
+ * metadata cache may result in the deletion, insertion, and/or
+ * dirtying of entries.
+ *
+ * This is a problem in PHDF5, as it breaks two invariants of
+ * our management of the metadata cache across all processes:
+ *
+ * 1) Entries will not be dirtied, deleted, inserted, or moved
+ * during flush in the parallel case.
+ *
+ * 2) All processes contain the same set of dirty metadata
+ * entries on entry to a sync point.
+ *
+ * To solve this problem for the persistent free space managers,
+ * serialize the metadata cache on all processes prior to the
+ * first sync point on file shutdown. The shutdown warning is
+ * a convenient location for this call.
+ *
+ * This is sufficient since:
+ *
+ * 1) FSM settle routines are only invoked on file close. Since
+ * serialization make the same settle calls as flush on file
+ * close, and since the close warning is issued after all
+ * non FSM related space allocations and just before the
+ * first sync point on close, this call will leave the caches
+ * in a consistant state across the processes if they were
+ * consistant before.
+ *
+ * 2) Since the FSM settle routines are only invoked once during
+ * file close, invoking them now will prevent their invocation
+ * during a flush, and thus avoid any resulting entrie dirties,
+ * deletions, insertion, or moves during the flush.
+ */
+ if(H5C__serialize_cache(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "serialization of the cache failed")
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_prep_for_file_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dest
+ *
+ * Purpose: Flush all data to disk and destroy the cache.
+ *
+ * This function fails if any object are protected since the
+ * resulting file might not be consistent.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the destroy (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the metadata
+ * cache, but may not be needed elsewhere. If so, just use the
+ * same dxpl_id for both parameters.
+ *
+ * Note that *cache_ptr has been freed upon successful return.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_dest(H5F_t * f, hid_t dxpl_id)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+
+#if H5AC_DUMP_IMAGE_STATS_ON_CLOSE
+ if(H5C_image_stats(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't display cache image stats")
+#endif /* H5AC_DUMP_IMAGE_STATS_ON_CLOSE */
+
+ /* Flush and invalidate all cache entries */
+ if(H5C_flush_invalidate_cache(f, dxpl_id, H5C__NO_FLAGS_SET) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
+
+ /* Generate & write cache image if requested */
+ if(cache_ptr->image_ctl.generate_image)
+ if(H5C__generate_cache_image(f, dxpl_id, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "Can't generate metadata cache image")
+
+ if(cache_ptr->slist_ptr != NULL) {
+ H5SL_close(cache_ptr->slist_ptr);
+ cache_ptr->slist_ptr = NULL;
+ } /* end if */
+
+ if(cache_ptr->tag_list != NULL) {
+ H5SL_destroy(cache_ptr->tag_list, H5C_free_tag_list_cb, NULL);
+ cache_ptr->tag_list = NULL;
+ } /* end if */
+
+#ifndef NDEBUG
+#if H5C_DO_SANITY_CHECKS
+ if(cache_ptr->get_entry_ptr_from_addr_counter > 0)
+ HDfprintf(stdout, "*** %ld calls to H5C_get_entry_ptr_from_add(). ***\n",
+ cache_ptr->get_entry_ptr_from_addr_counter);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ cache_ptr->magic = 0;
+#endif /* NDEBUG */
+
+ cache_ptr = H5FL_FREE(H5C_t, cache_ptr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_evict
+ *
+ * Purpose: Evict all except pinned entries in the cache
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_evict(H5F_t * f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Flush and invalidate all cache entries except the pinned entries */
+ if(H5C_flush_invalidate_cache(f, dxpl_id, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_evict() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_expunge_entry
+ *
+ * Purpose: Use this function to tell the cache to expunge an entry
+ * from the cache without writing it to disk even if it is
+ * dirty. The entry may not be either pinned or protected.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/29/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type,
+ haddr_t addr, unsigned flags)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ unsigned flush_flags = (H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_lru_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "LRU extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ /* Look for entry in cache */
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+ if((entry_ptr == NULL) || (entry_ptr->type != type))
+ /* the target doesn't exist in the cache, so we are done. */
+ HGOTO_DONE(SUCCEED)
+
+ HDassert(entry_ptr->addr == addr);
+ HDassert(entry_ptr->type == type);
+
+ /* Check for entry being pinned or protected */
+ if(entry_ptr->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "Target entry is protected")
+ if(entry_ptr->is_pinned)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "Target entry is pinned")
+
+ /* If we get this far, call H5C__flush_single_entry() with the
+ * H5C__FLUSH_INVALIDATE_FLAG and the H5C__FLUSH_CLEAR_ONLY_FLAG.
+ * This will clear the entry, and then delete it from the cache.
+ */
+
+ /* Pass along 'free file space' flag */
+ flush_flags |= (flags & H5C__FREE_FILE_SPACE_FLAG);
+
+ /* Delete the entry from the skip list on destroy */
+ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, flush_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "can't flush entry")
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_lru_list(cache_ptr) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "LRU extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_expunge_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_cache
+ *
+ * Purpose: Flush (and possibly destroy) the entries contained in the
+ * specified cache.
+ *
+ * If the cache contains protected entries, the function will
+ * fail, as protected entries cannot be flushed. However
+ * all unprotected entries should be flushed before the
+ * function returns failure.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Changes: Modified function to test for slist chamges in
+ * pre_serialize and serialize callbacks, and re-start
+ * scans through the slist when such changes occur.
+ *
+ * This has been a potential problem for some time,
+ * and there has been code in this function to deal
+ * with elements of this issue. However the shift
+ * to the V3 cache in combination with the activities
+ * of some of the cache clients (in particular the
+ * free space manager and the fractal heap) have
+ * made this re-work necessary.
+ *
+ * JRM -- 12/13/14
+ *
+ * Modified function to support rings. Basic idea is that
+ * every entry in the cache is assigned to a ring. Entries
+ * in the outermost ring are flushed first, followed by
+ * those in the next outermost ring, and so on until the
+ * innermost ring is flushed. See header comment on
+ * H5C_ring_t in H5Cprivate.h for a more detailed
+ * discussion.
+ *
+ * JRM -- 8/30/15
+ *
+ * Modified function to call the free space manager
+ * settling functions.
+ * JRM -- 6/9/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags)
+{
+#if H5C_DO_SANITY_CHECKS
+ int i;
+ uint32_t index_len = 0;
+ size_t index_size = (size_t)0;
+ size_t clean_index_size = (size_t)0;
+ size_t dirty_index_size = (size_t)0;
+ size_t slist_size = (size_t)0;
+ uint32_t slist_len = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+ H5C_ring_t ring;
+ H5C_t * cache_ptr;
+ hbool_t destroy;
+ hbool_t ignore_protected;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+
+ for(i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) {
+ index_len += cache_ptr->index_ring_len[i];
+ index_size += cache_ptr->index_ring_size[i];
+ clean_index_size += cache_ptr->clean_index_ring_size[i];
+ dirty_index_size += cache_ptr->dirty_index_ring_size[i];
+
+ slist_len += cache_ptr->slist_ring_len[i];
+ slist_size += cache_ptr->slist_ring_size[i];
+ } /* end for */
+
+ HDassert(cache_ptr->index_len == index_len);
+ HDassert(cache_ptr->index_size == index_size);
+ HDassert(cache_ptr->clean_index_size == clean_index_size);
+ HDassert(cache_ptr->dirty_index_size == dirty_index_size);
+ HDassert(cache_ptr->slist_len == slist_len);
+ HDassert(cache_ptr->slist_size == slist_size);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ ignore_protected = ( (flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0 );
+ destroy = ( (flags & H5C__FLUSH_INVALIDATE_FLAG) != 0 );
+ HDassert( ! ( destroy && ignore_protected ) );
+ HDassert( ! ( cache_ptr->flush_in_progress ) );
+
+ cache_ptr->flush_in_progress = TRUE;
+
+ if(destroy) {
+ if(H5C_flush_invalidate_cache(f, dxpl_id, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate failed")
+ } /* end if */
+ else {
+ /* flush each ring, starting from the outermost ring and
+ * working inward.
+ */
+ ring = H5C_RING_USER;
+ while(ring < H5C_RING_NTYPES) {
+
+ /* Only call the free space manager settle routines when close
+ * warning has been received.
+ */
+ if(cache_ptr->close_warning_received) {
+ switch(ring) {
+ case H5C_RING_USER:
+ break;
+
+ case H5C_RING_RDFSM:
+ /* Settle raw data FSM */
+ if(!cache_ptr->rdfsm_settled)
+ if(H5MF_settle_raw_data_fsm(f, dxpl_id, &cache_ptr->rdfsm_settled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "RD FSM settle failed")
+ break;
+
+ case H5C_RING_MDFSM:
+ /* Settle metadata FSM */
+ if(!cache_ptr->mdfsm_settled)
+ if(H5MF_settle_meta_data_fsm(f, dxpl_id, &cache_ptr->mdfsm_settled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "MD FSM settle failed")
+ break;
+
+ case H5C_RING_SBE:
+ case H5C_RING_SB:
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown ring?!?!")
+ break;
+ } /* end switch */
+ } /* end if */
+
+ if(H5C_flush_ring(f, dxpl_id, ring, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush ring failed")
+ ring++;
+ } /* end while */
+ } /* end else */
+
+done:
+ cache_ptr->flush_in_progress = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_to_min_clean
+ *
+ * Purpose: Flush dirty entries until the caches min clean size is
+ * attained.
+ *
+ * This function is used in the implementation of the
+ * metadata cache in PHDF5. To avoid "messages from the
+ * future", the cache on process 0 can't be allowed to
+ * flush entries until the other processes have reached
+ * the same point in the calculation. If this constraint
+ * is not met, it is possible that the other processes will
+ * read metadata generated at a future point in the
+ * computation.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure or if
+ * write is not permitted.
+ *
+ * Programmer: John Mainzer
+ * 9/16/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_flush_to_min_clean(H5F_t * f,
+ hid_t dxpl_id)
+{
+ H5C_t * cache_ptr;
+ hbool_t write_permitted;
+#if 0 /* modified code -- commented out for now */ /* JRM */
+ int i;
+ int flushed_entries_count = 0;
+ size_t flushed_entries_size = 0;
+ size_t space_needed = 0;
+ haddr_t * flushed_entries_list = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+#endif /* JRM */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if(cache_ptr->check_write_permitted != NULL) {
+ if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't get write_permitted")
+ } /* end if */
+ else
+ write_permitted = cache_ptr->write_permitted;
+
+ if(!write_permitted)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cache write is not permitted!?!")
+
+#if 1 /* original code */
+ if(H5C__make_space_in_cache(f, dxpl_id, (size_t)0, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C__make_space_in_cache failed")
+#else /* modified code -- commented out for now */
+ if ( cache_ptr->max_cache_size > cache_ptr->index_size ) {
+
+ if ( ((cache_ptr->max_cache_size - cache_ptr->index_size) +
+ cache_ptr->cLRU_list_size) >= cache_ptr->min_clean_size ) {
+
+ space_needed = 0;
+
+ } else {
+
+ space_needed = cache_ptr->min_clean_size -
+ ((cache_ptr->max_cache_size - cache_ptr->index_size) +
+ cache_ptr->cLRU_list_size);
+ }
+ } else {
+
+ if ( cache_ptr->min_clean_size <= cache_ptr->cLRU_list_size ) {
+
+ space_needed = 0;
+
+ } else {
+
+ space_needed = cache_ptr->min_clean_size -
+ cache_ptr->cLRU_list_size;
+ }
+ }
+
+ if ( space_needed > 0 ) { /* we have work to do */
+
+ HDassert( cache_ptr->slist_len > 0 );
+
+ /* allocate an array to keep a list of the entries that we
+ * mark for flush. We need this list to touch up the LRU
+ * list after the flush.
+ */
+ flushed_entries_list = (haddr_t *)H5MM_malloc(sizeof(haddr_t) *
+ (size_t)(cache_ptr->slist_len));
+ if(flushed_entries_list == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flushed entries list")
+
+ /* Scan the dirty LRU list from tail forward and mark sufficient
+ * entries to free up the necessary space. Keep a list of the
+ * entries marked in the order in which they are encountered.
+ */
+ entry_ptr = cache_ptr->dLRU_tail_ptr;
+
+ while ( ( flushed_entries_size < space_needed ) &&
+ ( flushed_entries_count < cache_ptr->slist_len ) &&
+ ( entry_ptr != NULL ) )
+ {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( entry_ptr->ro_ref_count == 0 );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_slist );
+
+ entry_ptr->flush_marker = TRUE;
+ flushed_entries_size += entry_ptr->size;
+ flushed_entries_list[flushed_entries_count] = entry_ptr->addr;
+ flushed_entries_count++;
+ entry_ptr = entry_ptr->aux_prev;
+ }
+
+ HDassert( flushed_entries_count <= cache_ptr->slist_len );
+ HDassert( flushed_entries_size >= space_needed );
+
+
+ /* Flush the marked entries */
+ if(H5C_flush_cache(f, primary_dxpl_id, secondary_dxpl_id, H5C__FLUSH_MARKED_ENTRIES_FLAG | H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_flush_cache failed")
+
+ /* Now touch up the LRU list so as to place the flushed entries in
+ * the order they they would be in if we had flushed them in the
+ * order we encountered them in.
+ */
+
+ i = 0;
+ while ( i < flushed_entries_count )
+ {
+ H5C__SEARCH_INDEX_NO_STATS(cache_ptr, flushed_entries_list[i], \
+ entry_ptr, FAIL)
+
+ /* At present, the above search must always succeed. However,
+ * that may change. Write the code so we need only remove the
+ * following assert in that event.
+ */
+ HDassert( entry_ptr != NULL );
+ H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, FAIL)
+ i++;
+ }
+ } /* if ( space_needed > 0 ) */
+#endif /* end modified code -- commented out for now */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_to_min_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_insert_entry
+ *
+ * Purpose: Adds the specified thing to the cache. The thing need not
+ * exist on disk yet, but it must have an address and disk
+ * space reserved.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the insertion (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the
+ * metadata cache, but may not be needed elsewhere. If so,
+ * just use the same dxpl_id for both parameters.
+ *
+ * The primary_dxpl_id is the dxpl_id passed to the
+ * check_write_permitted function if such a function has been
+ * provided.
+ *
+ * Observe that this function cannot occasion a read.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_insert_entry(H5F_t * f,
+ hid_t dxpl_id,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * thing,
+ unsigned int flags)
+{
+ H5C_t *cache_ptr;
+ H5P_genplist_t *dxpl;
+ H5AC_ring_t ring = H5C_RING_UNDEFINED;
+ hbool_t insert_pinned;
+ hbool_t flush_last;
+#ifdef H5_HAVE_PARALLEL
+ hbool_t coll_access = FALSE; /* whether access to the cache entry is done collectively */
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t set_flush_marker;
+ hbool_t write_permitted = TRUE;
+ size_t empty_space;
+ H5C_cache_entry_t *entry_ptr = NULL;
+ H5C_cache_entry_t *test_entry_ptr;
+ hbool_t entry_tagged = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( type );
+ HDassert( type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type );
+ HDassert( type->image_len );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( thing );
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ /* no need to verify that entry is not already in the index as */
+ /* we already make that check below. */
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ set_flush_marker = ( (flags & H5C__SET_FLUSH_MARKER_FLAG) != 0 );
+ insert_pinned = ( (flags & H5C__PIN_ENTRY_FLAG) != 0 );
+ flush_last = ( (flags & H5C__FLUSH_LAST_FLAG) != 0 );
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the ring type from the DXPL */
+ if((H5P_get(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "unable to query ring value")
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ /* verify that the new entry isn't already in the hash table -- scream
+ * and die if it is.
+ */
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL)
+
+ if(test_entry_ptr != NULL) {
+ if(test_entry_ptr == entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "entry already in cache")
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "duplicate entry in cache")
+ } /* end if */
+
+ entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC;
+ entry_ptr->cache_ptr = cache_ptr;
+ entry_ptr->addr = addr;
+ entry_ptr->type = type;
+
+ entry_ptr->image_ptr = NULL;
+ entry_ptr->image_up_to_date = FALSE;
+
+ entry_ptr->is_protected = FALSE;
+ entry_ptr->is_read_only = FALSE;
+ entry_ptr->ro_ref_count = 0;
+
+ entry_ptr->is_pinned = insert_pinned;
+ entry_ptr->pinned_from_client = insert_pinned;
+ entry_ptr->pinned_from_cache = FALSE;
+ entry_ptr->flush_me_last = flush_last;
+
+ /* newly inserted entries are assumed to be dirty */
+ entry_ptr->is_dirty = TRUE;
+
+ /* not protected, so can't be dirtied */
+ entry_ptr->dirtied = FALSE;
+
+ /* Retrieve the size of the thing */
+ if((type->image_len)(thing, &(entry_ptr->size)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGETSIZE, FAIL, "can't get size of thing")
+ HDassert(entry_ptr->size > 0 && entry_ptr->size < H5C_MAX_ENTRY_SIZE);
+
+ entry_ptr->in_slist = FALSE;
+
+#ifdef H5_HAVE_PARALLEL
+ entry_ptr->clear_on_unprotect = FALSE;
+ entry_ptr->flush_immediately = FALSE;
+#endif /* H5_HAVE_PARALLEL */
+
+ entry_ptr->flush_in_progress = FALSE;
+ entry_ptr->destroy_in_progress = FALSE;
+
+ entry_ptr->ring = ring;
+
+ /* Initialize flush dependency fields */
+ entry_ptr->flush_dep_parent = NULL;
+ entry_ptr->flush_dep_nparents = 0;
+ entry_ptr->flush_dep_parent_nalloc = 0;
+ entry_ptr->flush_dep_nchildren = 0;
+ entry_ptr->flush_dep_ndirty_children = 0;
+ entry_ptr->flush_dep_nunser_children = 0;
+
+ entry_ptr->ht_next = NULL;
+ entry_ptr->ht_prev = NULL;
+ entry_ptr->il_next = NULL;
+ entry_ptr->il_prev = NULL;
+
+ entry_ptr->next = NULL;
+ entry_ptr->prev = NULL;
+
+ entry_ptr->aux_next = NULL;
+ entry_ptr->aux_prev = NULL;
+
+#ifdef H5_HAVE_PARALLEL
+ entry_ptr->coll_next = NULL;
+ entry_ptr->coll_prev = NULL;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* initialize cache image related fields */
+ entry_ptr->include_in_image = FALSE;
+ entry_ptr->lru_rank = 0;
+ entry_ptr->image_dirty = FALSE;
+ entry_ptr->fd_parent_count = 0;
+ entry_ptr->fd_parent_addrs = NULL;
+ entry_ptr->fd_child_count = 0;
+ entry_ptr->fd_dirty_child_count = 0;
+ entry_ptr->image_fd_height = 0;
+ entry_ptr->prefetched = FALSE;
+ entry_ptr->prefetch_type_id = 0;
+ entry_ptr->age = 0;
+ entry_ptr->prefetched_dirty = FALSE;
+#ifndef NDEBUG /* debugging field */
+ entry_ptr->serialization_count = 0;
+#endif /* NDEBUG */
+
+ entry_ptr->tl_next = NULL;
+ entry_ptr->tl_prev = NULL;
+ entry_ptr->tag_info = NULL;
+
+ /* Apply tag to newly inserted entry */
+ if(H5C__tag_entry(cache_ptr, entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot tag metadata entry")
+ entry_tagged = TRUE;
+
+ H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+
+ if(cache_ptr->flash_size_increase_possible &&
+ (entry_ptr->size > cache_ptr->flash_size_increase_threshold))
+ if(H5C__flash_increase_cache_size(cache_ptr, 0, entry_ptr->size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C__flash_increase_cache_size failed")
+
+ if(cache_ptr->index_size >= cache_ptr->max_cache_size)
+ empty_space = 0;
+ else
+ empty_space = cache_ptr->max_cache_size - cache_ptr->index_size;
+
+ if(cache_ptr->evictions_enabled &&
+ (((cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size)
+ ||
+ (((empty_space + cache_ptr->clean_index_size) < cache_ptr->min_clean_size)))) {
+ size_t space_needed;
+
+ if(empty_space <= entry_ptr->size)
+ cache_ptr->cache_full = TRUE;
+
+ if(cache_ptr->check_write_permitted != NULL) {
+ if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "Can't get write_permitted")
+ } /* end if */
+ else
+ write_permitted = cache_ptr->write_permitted;
+
+ HDassert(entry_ptr->size <= H5C_MAX_ENTRY_SIZE);
+ space_needed = entry_ptr->size;
+ if(space_needed > cache_ptr->max_cache_size)
+ space_needed = cache_ptr->max_cache_size;
+
+ /* Note that space_needed is just the amount of space that
+ * needed to insert the new entry without exceeding the cache
+ * size limit. The subsequent call to H5C__make_space_in_cache()
+ * may evict the entries required to free more or less space
+ * depending on conditions. It MAY be less if the cache is
+ * currently undersized, or more if the cache is oversized.
+ *
+ * The cache can exceed its maximum size limit via the following
+ * mechanisms:
+ *
+ * First, it is possible for the cache to grow without
+ * bound as long as entries are protected and not unprotected.
+ *
+ * Second, when writes are not permitted it is also possible
+ * for the cache to grow without bound.
+ *
+ * Finally, we usually don't check to see if the cache is
+ * oversized at the end of an unprotect. As a result, it is
+ * possible to have a vastly oversized cache with no protected
+ * entries as long as all the protects preceed the unprotects.
+ *
+ * Since items 1 and 2 are not changing any time soon, I see
+ * no point in worrying about the third.
+ */
+
+ if(H5C__make_space_in_cache(f, dxpl_id, space_needed, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C__make_space_in_cache failed")
+ } /* end if */
+
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ /* New entries are presumed to be dirty */
+ HDassert(entry_ptr->is_dirty);
+ entry_ptr->flush_marker = set_flush_marker;
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL)
+ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL)
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed just before done")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ /* If the entry's type has a 'notify' callback send a 'after insertion'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_INSERT, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry inserted into cache")
+
+ H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)
+
+#ifdef H5_HAVE_PARALLEL
+ /* Get the dataset transfer property list */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ coll_access = (H5P_USER_TRUE == f->coll_md_read ? TRUE : FALSE);
+
+ if(!coll_access && H5P_FORCE_FALSE != f->coll_md_read) {
+ H5P_coll_md_read_flag_t prop_value;
+
+ /* Get the property value */
+ if(H5P_get(dxpl, H5_COLL_MD_READ_FLAG_NAME, &prop_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't get collective metadata access flag")
+ coll_access = (H5P_USER_TRUE == prop_value ? TRUE : FALSE);
+ } /* end if */
+ } /* end if */
+
+ entry_ptr->coll_access = coll_access;
+ if(coll_access) {
+ H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, FAIL)
+
+ /* Make sure the size of the collective entries in the cache remain in check */
+ if(H5P_USER_TRUE == f->coll_md_read) {
+ if(cache_ptr->max_cache_size * 80 < cache_ptr->coll_list_size * 100) {
+ if(H5C_clear_coll_entries(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear collective metadata entries")
+ } /* end if */
+ } /* end if */
+ else {
+ if(cache_ptr->max_cache_size * 40 < cache_ptr->coll_list_size * 100) {
+ if(H5C_clear_coll_entries(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear collective metadata entries")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+#endif
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ if(ret_value < 0 && entry_tagged)
+ if(H5C__untag_entry(cache_ptr, entry_ptr) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_mark_entry_dirty
+ *
+ * Purpose: Mark a pinned or protected entry as dirty. The target entry
+ * MUST be either pinned or protected, and MAY be both.
+ *
+ * In the protected case, this call is the functional
+ * equivalent of setting the H5C__DIRTIED_FLAG on an unprotect
+ * call.
+ *
+ * In the pinned but not protected case, if the entry is not
+ * already dirty, the function places function marks the entry
+ * dirty and places it on the skip list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/15/06
+ *
+ * JRM -- 11/5/08
+ * Added call to H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY() to
+ * update the new clean_index_size and dirty_index_size
+ * fields of H5C_t in the case that the entry was clean
+ * prior to this call, and is pinned and not protected.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_mark_entry_dirty(void *thing)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(H5F_addr_defined(entry_ptr->addr));
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ if ( entry_ptr->is_protected ) {
+ HDassert( ! ((entry_ptr)->is_read_only) );
+
+ /* set the dirtied flag */
+ entry_ptr->dirtied = TRUE;
+
+ /* reset image_up_to_date */
+ if(entry_ptr->image_up_to_date) {
+ entry_ptr->image_up_to_date = FALSE;
+
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+ }/* end if */
+ } /* end if */
+ else if ( entry_ptr->is_pinned ) {
+ hbool_t was_clean; /* Whether the entry was previously clean */
+ hbool_t image_was_up_to_date;
+
+ /* Remember previous dirty status */
+ was_clean = !entry_ptr->is_dirty;
+
+ /* Check if image is up to date */
+ image_was_up_to_date = entry_ptr->image_up_to_date;
+
+ /* Mark the entry as dirty if it isn't already */
+ entry_ptr->is_dirty = TRUE;
+ entry_ptr->image_up_to_date = FALSE;
+
+ /* Modify cache data structures */
+ if(was_clean)
+ H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr)
+ if(!entry_ptr->in_slist)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL)
+
+ /* Update stats for entry being marked dirty */
+ H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr)
+
+ /* Check for entry changing status and do notifications, etc. */
+ if(was_clean) {
+ /* If the entry's type has a 'notify' callback send a 'entry dirtied'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set")
+
+ /* Propagate the dirty flag up the flush dependency chain if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_dirty(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag")
+ } /* end if */
+ if(image_was_up_to_date)
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Entry is neither pinned nor protected??")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_mark_entry_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_mark_entry_clean
+ *
+ * Purpose: Mark a pinned entry as clean. The target entry MUST be pinned.
+ *
+ * If the entry is not
+ * already clean, the function places function marks the entry
+ * clean and removes it from the skip list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 7/23/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_mark_entry_clean(void *_thing)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(H5F_addr_defined(entry_ptr->addr));
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Operate on pinned entry */
+ if(entry_ptr->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "entry is protected")
+ else if(entry_ptr->is_pinned) {
+ hbool_t was_dirty; /* Whether the entry was previously dirty */
+
+ /* Remember previous dirty status */
+ was_dirty = entry_ptr->is_dirty;
+
+ /* Mark the entry as clean if it isn't already */
+ entry_ptr->is_dirty = FALSE;
+
+ /* Also reset the 'flush_marker' flag, since the entry shouldn't be flushed now */
+ entry_ptr->flush_marker = FALSE;
+
+ /* Modify cache data structures */
+ if(was_dirty)
+ H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr)
+ if(entry_ptr->in_slist)
+ H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE)
+
+ /* Update stats for entry being marked clean */
+ H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
+
+ /* Check for entry changing status and do notifications, etc. */
+ if(was_dirty) {
+ /* If the entry's type has a 'notify' callback send a 'entry cleaned'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared")
+
+ /* Propagate the clean up the flush dependency chain, if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_clean(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "Can't propagate flush dep clean")
+ } /* end if */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "Entry is not pinned??")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_mark_entry_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_mark_entry_unserialized
+ *
+ * Purpose: Mark a pinned or protected entry as unserialized. The target
+ * entry MUST be either pinned or protected, and MAY be both.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 12/23/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_mark_entry_unserialized(void *thing)
+{
+ H5C_cache_entry_t *entry = (H5C_cache_entry_t *)thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+ HDassert(H5F_addr_defined(entry->addr));
+
+ if(entry->is_protected || entry->is_pinned) {
+ HDassert(!entry->is_read_only);
+
+ /* Reset image_up_to_date */
+ if(entry->image_up_to_date) {
+ entry->image_up_to_date = FALSE;
+
+ if(entry->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "Can't propagate serialization status to fd parents")
+ }/* end if */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKUNSERIALIZED, FAIL, "Entry to unserialize is neither pinned nor protected??")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_mark_entry_unserialized() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_mark_entry_serialized
+ *
+ * Purpose: Mark a pinned entry as serialized. The target entry MUST be
+ * pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 12/23/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_mark_entry_serialized(void *_thing)
+{
+ H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+ HDassert(H5F_addr_defined(entry->addr));
+
+ /* Operate on pinned entry */
+ if(entry->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "entry is protected")
+ else if(entry->is_pinned) {
+ /* Check for entry changing status and do notifications, etc. */
+ if(!entry->image_up_to_date) {
+ /* Set the image_up_to_date flag */
+ entry->image_up_to_date = TRUE;
+
+ /* Propagate the serialize up the flush dependency chain, if appropriate */
+ if(entry->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_serialized(entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "Can't propagate flush dep serialize")
+ } /* end if */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "Entry is not pinned??")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_mark_entry_serialized() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_move_entry
+ *
+ * Purpose: Use this function to notify the cache that an entry's
+ * file address changed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_move_entry(H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t old_addr,
+ haddr_t new_addr)
+{
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5C_cache_entry_t * test_entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(type);
+ HDassert(H5F_addr_defined(old_addr));
+ HDassert(H5F_addr_defined(new_addr));
+ HDassert(H5F_addr_ne(old_addr, new_addr));
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL)
+
+ if(entry_ptr == NULL || entry_ptr->type != type)
+ /* the old item doesn't exist in the cache, so we are done. */
+ HGOTO_DONE(SUCCEED)
+
+ HDassert(entry_ptr->addr == old_addr);
+ HDassert(entry_ptr->type == type);
+
+ /* Check for R/W status, otherwise error */
+ /* (Moving a R/O entry would mark it dirty, which shouldn't
+ * happen. QAK - 2016/12/02)
+ */
+ if(entry_ptr->is_read_only)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "can't move R/O entry")
+
+ H5C__SEARCH_INDEX(cache_ptr, new_addr, test_entry_ptr, FAIL)
+
+ if(test_entry_ptr != NULL) { /* we are hosed */
+ if(test_entry_ptr->type == type)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "target already moved & reinserted???")
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "new address already in use?")
+ } /* end if */
+
+ /* If we get this far we have work to do. Remove *entry_ptr from
+ * the hash table (and skip list if necessary), change its address to the
+ * new address, mark it as dirty (if it isn't already) and then re-insert.
+ *
+ * Update the replacement policy for a hit to avoid an eviction before
+ * the moved entry is touched. Update stats for a move.
+ *
+ * Note that we do not check the size of the cache, or evict anything.
+ * Since this is a simple re-name, cache size should be unaffected.
+ *
+ * Check to see if the target entry is in the process of being destroyed
+ * before we delete from the index, etc. If it is, all we do is
+ * change the addr. If the entry is only in the process of being flushed,
+ * don't mark it as dirty either, lest we confuse the flush call back.
+ */
+ if(!entry_ptr->destroy_in_progress) {
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ if(entry_ptr->in_slist) {
+ HDassert(cache_ptr->slist_ptr);
+ H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE)
+ } /* end if */
+ } /* end if */
+
+ entry_ptr->addr = new_addr;
+
+ if(!entry_ptr->destroy_in_progress) {
+ hbool_t was_dirty; /* Whether the entry was previously dirty */
+
+ /* Remember previous dirty status */
+ was_dirty = entry_ptr->is_dirty;
+
+ /* Mark the entry as dirty if it isn't already */
+ entry_ptr->is_dirty = TRUE;
+
+ /* This shouldn't be needed, but it keeps the test code happy */
+ if(entry_ptr->image_up_to_date) {
+ entry_ptr->image_up_to_date = FALSE;
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+ } /* end if */
+
+ /* Modify cache data structures */
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL)
+
+ /* Skip some actions if we're in the middle of flushing the entry */
+ if(!entry_ptr->flush_in_progress) {
+ /* Update the replacement policy for the entry */
+ H5C__UPDATE_RP_FOR_MOVE(cache_ptr, entry_ptr, was_dirty, FAIL)
+
+ /* Check for entry changing status and do notifications, etc. */
+ if(!was_dirty) {
+ /* If the entry's type has a 'notify' callback send a 'entry dirtied'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set")
+
+ /* Propagate the dirty flag up the flush dependency chain if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_dirty(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr)
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_move_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_resize_entry
+ *
+ * Purpose: Resize a pinned or protected entry.
+ *
+ * Resizing an entry dirties it, so if the entry is not
+ * already dirty, the function places the entry on the
+ * skip list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/5/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_resize_entry(void *thing, size_t new_size)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(H5F_addr_defined(entry_ptr->addr));
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Check for usage errors */
+ if(new_size <= 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "New size is non-positive")
+ if(!(entry_ptr->is_pinned || entry_ptr->is_protected))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "Entry isn't pinned or protected??")
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ /* update for change in entry size if necessary */
+ if ( entry_ptr->size != new_size ) {
+ hbool_t was_clean;
+
+ /* make note of whether the entry was clean to begin with */
+ was_clean = !entry_ptr->is_dirty;
+
+ /* mark the entry as dirty if it isn't already */
+ entry_ptr->is_dirty = TRUE;
+
+ /* Reset the image up-to-date status */
+ if(entry_ptr->image_up_to_date) {
+ entry_ptr->image_up_to_date = FALSE;
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+ } /* end if */
+
+ /* Release the current image */
+ if(entry_ptr->image_ptr)
+ entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr);
+
+ /* do a flash cache size increase if appropriate */
+ if ( cache_ptr->flash_size_increase_possible ) {
+
+ if ( new_size > entry_ptr->size ) {
+ size_t size_increase;
+
+ size_increase = new_size - entry_ptr->size;
+
+ if(size_increase >= cache_ptr->flash_size_increase_threshold) {
+ if(H5C__flash_increase_cache_size(cache_ptr, entry_ptr->size, new_size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, "flash cache increase failed")
+ }
+ }
+ }
+
+ /* update the pinned and/or protected entry list */
+ if(entry_ptr->is_pinned) {
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pel_len), \
+ (cache_ptr->pel_size), \
+ (entry_ptr->size), (new_size))
+ } /* end if */
+ if(entry_ptr->is_protected) {
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pl_len), \
+ (cache_ptr->pl_size), \
+ (entry_ptr->size), (new_size))
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ if(entry_ptr->coll_access) {
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->coll_list_len), \
+ (cache_ptr->coll_list_size), \
+ (entry_ptr->size), (new_size))
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* update statistics just before changing the entry size */
+ H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size);
+
+ /* update the hash table */
+ H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, \
+ new_size, entry_ptr, was_clean);
+
+ /* if the entry is in the skip list, update that too */
+ if(entry_ptr->in_slist)
+ H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_size);
+
+ /* finally, update the entry size proper */
+ entry_ptr->size = new_size;
+
+ if(!entry_ptr->in_slist)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL)
+
+ if(entry_ptr->is_pinned)
+ H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr)
+
+ /* Check for entry changing status and do notifications, etc. */
+ if(was_clean) {
+ /* If the entry's type has a 'notify' callback send a 'entry dirtied'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set")
+
+ /* Propagate the dirty flag up the flush dependency chain if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_dirty(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag")
+ } /* end if */
+ } /* end if */
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_resize_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_pin_entry_from_client()
+ *
+ * Purpose: Internal routine to pin a cache entry from a client action.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/26/09
+ *
+ * Changes: Added sanity checks to clarify the circumstances under
+ * which an entry can be pinned. JRM -- 4/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5C_pin_entry_from_client(H5C_t * cache_ptr,
+ H5C_cache_entry_t * entry_ptr)
+#else
+static herr_t
+H5C_pin_entry_from_client(H5C_t H5_ATTR_UNUSED * cache_ptr,
+ H5C_cache_entry_t * entry_ptr)
+#endif
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert( cache_ptr );
+ HDassert( entry_ptr );
+ HDassert( entry_ptr->is_protected );
+
+ /* Check if the entry is already pinned */
+ if(entry_ptr->is_pinned) {
+ /* Check if the entry was pinned through an explicit pin from a client */
+ if(entry_ptr->pinned_from_client)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Entry is already pinned")
+ } /* end if */
+ else {
+ entry_ptr->is_pinned = TRUE;
+
+ H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr)
+ } /* end else */
+
+ /* Mark that the entry was pinned through an explicit pin from a client */
+ entry_ptr->pinned_from_client = TRUE;
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_pin_entry_from_client() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_pin_protected_entry()
+ *
+ * Purpose: Pin a protected cache entry. The entry must be protected
+ * at the time of call, and must be unpinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/26/06
+ *
+ * Changes: Added extreme sanity checks on entry and exit.
+ * JRM -- 4/26/14
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_pin_protected_entry(void *thing)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)thing; /* Pointer to entry to pin */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(H5F_addr_defined(entry_ptr->addr));
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+ /* Only protected entries can be pinned */
+ if(!entry_ptr->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Entry isn't protected")
+
+ /* Pin the entry from a client */
+ if(H5C_pin_entry_from_client(cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client")
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_pin_protected_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_protect
+ *
+ * Purpose: If the target entry is not in the cache, load it. If
+ * necessary, attempt to evict one or more entries to keep
+ * the cache within its maximum size.
+ *
+ * Mark the target entry as protected, and return its address
+ * to the caller. The caller must call H5C_unprotect() when
+ * finished with the entry.
+ *
+ * While it is protected, the entry may not be either evicted
+ * or flushed -- nor may it be accessed by another call to
+ * H5C_protect. Any attempt to do so will result in a failure.
+ *
+ * Return: Success: Ptr to the desired entry
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer - 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5C_protect(H5F_t * f,
+ hid_t dxpl_id,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * udata,
+ unsigned flags)
+{
+ H5C_t * cache_ptr;
+ H5AC_ring_t ring = H5C_RING_UNDEFINED;
+ hbool_t hit;
+ hbool_t have_write_permitted = FALSE;
+ hbool_t read_only = FALSE;
+ hbool_t flush_last;
+#ifdef H5_HAVE_PARALLEL
+ hbool_t coll_access = FALSE; /* whether access to the cache entry is done collectively */
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t write_permitted;
+ hbool_t was_loaded = FALSE; /* Whether the entry was loaded as a result of the protect */
+ size_t empty_space;
+ void * thing;
+ H5C_cache_entry_t * entry_ptr;
+ H5P_genplist_t * dxpl; /* dataset transfer property list */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( type );
+ HDassert( type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type );
+ HDassert( H5F_addr_defined(addr) );
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ /* Load the cache image, if requested */
+ if(cache_ptr->load_image) {
+ cache_ptr->load_image = FALSE;
+ if(H5C__load_cache_image(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't load cache image")
+ } /* end if */
+
+ read_only = ( (flags & H5C__READ_ONLY_FLAG) != 0 );
+ flush_last = ( (flags & H5C__FLUSH_LAST_FLAG) != 0 );
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, NULL, "not a property list")
+
+ /* Get the ring type from the DXPL */
+ if((H5P_get(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "unable to query ring value")
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ coll_access = (H5P_USER_TRUE == f->coll_md_read ? TRUE : FALSE);
+
+ if(!coll_access && H5P_FORCE_FALSE != f->coll_md_read) {
+ H5P_coll_md_read_flag_t prop_value;
+
+ /* get the property value */
+ if(H5P_get(dxpl, H5_COLL_MD_READ_FLAG_NAME, &prop_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "Can't get collective metadata access flag")
+ coll_access = (H5P_USER_TRUE == prop_value ? TRUE : FALSE);
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* first check to see if the target is in cache */
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, NULL)
+
+ if(entry_ptr != NULL) {
+ if(entry_ptr->ring != ring)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "ring type mismatch occured for cache entry")
+
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ if(entry_ptr->prefetched) {
+ /* This call removes the prefetched entry from the cache,
+ * and replaces it with an entry deserialized from the
+ * image of the prefetched entry.
+ */
+ if(H5C__deserialize_prefetched_entry(f, dxpl_id, cache_ptr, &entry_ptr, type, addr, udata) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't deserialize prefetched entry")
+
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(!entry_ptr->prefetched);
+ HDassert(entry_ptr->addr == addr);
+ } /* end if */
+
+ /* Check for trying to load the wrong type of entry from an address */
+ if(entry_ptr->type != type)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, NULL, "incorrect cache entry type")
+
+ /* if this is a collective metadata read, the entry is not
+ marked as collective, and is clean, it is possible that
+ other processes will not have it in its cache and will
+ expect a bcast of the entry from process 0. So process 0
+ will bcast the entry to all other ranks. Ranks that _do_ have
+ the entry in their cache still have to participate in the
+ bcast. */
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI) && coll_access) {
+ if(!(entry_ptr->is_dirty) && !(entry_ptr->coll_access)) {
+ MPI_Comm comm; /* File MPI Communicator */
+ int mpi_code; /* MPI error code */
+ int buf_size;
+
+ if(MPI_COMM_NULL == (comm = H5F_mpi_get_comm(f)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "get_comm request failed")
+
+ if(entry_ptr->image_ptr == NULL) {
+ int mpi_rank;
+
+ if((mpi_rank = H5F_mpi_get_rank(f)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "Can't get MPI rank")
+
+ if(NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+ if(0 == mpi_rank)
+ if(H5C__generate_image(f, cache_ptr, entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't generate entry's image")
+ } /* end if */
+ HDassert(entry_ptr->image_ptr);
+
+ H5_CHECKED_ASSIGN(buf_size, int, entry_ptr->size, size_t);
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(entry_ptr->image_ptr, buf_size, MPI_BYTE, 0, comm)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code)
+
+ /* Mark the entry as collective and insert into the collective list */
+ entry_ptr->coll_access = TRUE;
+ H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, NULL)
+ } /* end if */
+ else if(entry_ptr->coll_access) {
+ H5C__MOVE_TO_TOP_IN_COLL_LIST(cache_ptr, entry_ptr, NULL)
+ } /* end else-if */
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+#if H5C_DO_TAGGING_SANITY_CHECKS
+{
+ /* Verify tag value */
+ if(cache_ptr->ignore_tags != TRUE) {
+ haddr_t tag; /* Tag value */
+
+ /* The entry is already in the cache, but make sure that the tag value
+ being passed in via dxpl is still legal. This will ensure that had
+ the entry NOT been in the cache, tagging was still set up correctly
+ and it would have received a legal tag value after getting loaded
+ from disk. */
+
+ /* Get the tag from the DXPL */
+ if((H5P_get(dxpl, H5AC_TAG_NAME, &tag)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to query property value")
+
+ if(H5C_verify_tag(entry_ptr->type->id, tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "tag verification failed")
+ } /* end if */
+}
+#endif
+
+ hit = TRUE;
+ thing = (void *)entry_ptr;
+
+ } else {
+
+ /* must try to load the entry from disk. */
+
+ hit = FALSE;
+
+ if(NULL == (thing = H5C_load_entry(f, dxpl_id,
+#ifdef H5_HAVE_PARALLEL
+ coll_access,
+#endif /* H5_HAVE_PARALLEL */
+ type, addr, udata)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't load entry")
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+ cache_ptr->entries_loaded_counter++;
+
+ entry_ptr->ring = ring;
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI) && entry_ptr->coll_access)
+ H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, NULL)
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Apply tag to newly protected entry */
+ if(H5C__tag_entry(cache_ptr, entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Cannot tag metadata entry")
+
+ /* If the entry is very large, and we are configured to allow it,
+ * we may wish to perform a flash cache size increase.
+ */
+ if ( ( cache_ptr->flash_size_increase_possible ) &&
+ ( entry_ptr->size > cache_ptr->flash_size_increase_threshold ) ) {
+
+ if(H5C__flash_increase_cache_size(cache_ptr, 0, entry_ptr->size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__flash_increase_cache_size failed")
+ }
+
+ if(cache_ptr->index_size >= cache_ptr->max_cache_size)
+ empty_space = 0;
+ else
+ empty_space = cache_ptr->max_cache_size - cache_ptr->index_size;
+
+ /* try to free up if necceary and if evictions are permitted. Note
+ * that if evictions are enabled, we will call H5C__make_space_in_cache()
+ * regardless if the min_free_space requirement is not met.
+ */
+ if ( ( cache_ptr->evictions_enabled ) &&
+ ( ( (cache_ptr->index_size + entry_ptr->size) >
+ cache_ptr->max_cache_size)
+ ||
+ ( ( empty_space + cache_ptr->clean_index_size ) <
+ cache_ptr->min_clean_size )
+ )
+ ) {
+
+ size_t space_needed;
+
+ if(empty_space <= entry_ptr->size)
+ cache_ptr->cache_full = TRUE;
+
+ if(cache_ptr->check_write_permitted != NULL) {
+ if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Can't get write_permitted 1")
+ else
+ have_write_permitted = TRUE;
+ } /* end if */
+ else {
+ write_permitted = cache_ptr->write_permitted;
+ have_write_permitted = TRUE;
+ } /* end else */
+
+ HDassert(entry_ptr->size <= H5C_MAX_ENTRY_SIZE);
+ space_needed = entry_ptr->size;
+ if(space_needed > cache_ptr->max_cache_size)
+ space_needed = cache_ptr->max_cache_size;
+
+ /* Note that space_needed is just the amount of space that
+ * needed to insert the new entry without exceeding the cache
+ * size limit. The subsequent call to H5C__make_space_in_cache()
+ * may evict the entries required to free more or less space
+ * depending on conditions. It MAY be less if the cache is
+ * currently undersized, or more if the cache is oversized.
+ *
+ * The cache can exceed its maximum size limit via the following
+ * mechanisms:
+ *
+ * First, it is possible for the cache to grow without
+ * bound as long as entries are protected and not unprotected.
+ *
+ * Second, when writes are not permitted it is also possible
+ * for the cache to grow without bound.
+ *
+ * Third, the user may choose to disable evictions -- causing
+ * the cache to grow without bound until evictions are
+ * re-enabled.
+ *
+ * Finally, we usually don't check to see if the cache is
+ * oversized at the end of an unprotect. As a result, it is
+ * possible to have a vastly oversized cache with no protected
+ * entries as long as all the protects preceed the unprotects.
+ *
+ * Since items 1, 2, and 3 are not changing any time soon, I
+ * see no point in worrying about the fourth.
+ */
+
+ if(H5C__make_space_in_cache(f, dxpl_id, space_needed, write_permitted) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__make_space_in_cache failed")
+ } /* end if */
+
+ /* Insert the entry in the hash table. It can't be dirty yet, so
+ * we don't even check to see if it should go in the skip list.
+ *
+ * This is no longer true -- due to a bug fix, we may modify
+ * data on load to repair a file.
+ *
+ * *******************************************
+ *
+ * Set the flush_last field
+ * of the newly loaded entry before inserting it into the
+ * index. Must do this, as the index tracked the number of
+ * entries with the flush_last field set, but assumes that
+ * the field will not change after insertion into the index.
+ *
+ * Note that this means that the H5C__FLUSH_LAST_FLAG flag
+ * is ignored if the entry is already in cache.
+ */
+ entry_ptr->flush_me_last = flush_last;
+
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, NULL)
+
+ if ( ( entry_ptr->is_dirty ) && ( ! (entry_ptr->in_slist) ) ) {
+
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, NULL)
+ }
+
+ /* insert the entry in the data structures used by the replacement
+ * policy. We are just going to take it out again when we update
+ * the replacement policy for a protect, but this simplifies the
+ * code. If we do this often enough, we may want to optimize this.
+ */
+ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, NULL)
+
+ /* Record that the entry was loaded, to trigger a notify callback later */
+ /* (After the entry is fully added to the cache) */
+ was_loaded = TRUE;
+ } /* end else */
+
+ HDassert(entry_ptr->addr == addr);
+ HDassert(entry_ptr->type == type);
+
+ if(entry_ptr->is_protected) {
+ if(read_only && entry_ptr->is_read_only) {
+ HDassert(entry_ptr->ro_ref_count > 0);
+ (entry_ptr->ro_ref_count)++;
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Target already protected & not read only?!?")
+ } /* end if */
+ else {
+ H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, NULL)
+
+ entry_ptr->is_protected = TRUE;
+
+ if ( read_only ) {
+ entry_ptr->is_read_only = TRUE;
+ entry_ptr->ro_ref_count = 1;
+ } /* end if */
+
+ entry_ptr->dirtied = FALSE;
+ } /* end else */
+
+ H5C__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit)
+
+ H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)
+
+ ret_value = thing;
+
+ if ( ( cache_ptr->evictions_enabled ) &&
+ ( ( cache_ptr->size_decreased ) ||
+ ( ( cache_ptr->resize_enabled ) &&
+ ( cache_ptr->cache_accesses >=
+ (cache_ptr->resize_ctl).epoch_length ) ) ) ) {
+
+ if ( ! have_write_permitted ) {
+
+ if ( cache_ptr->check_write_permitted != NULL ) {
+ if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Can't get write_permitted")
+ else
+ have_write_permitted = TRUE;
+ } else {
+
+ write_permitted = cache_ptr->write_permitted;
+
+ have_write_permitted = TRUE;
+
+ }
+ }
+
+ if(cache_ptr->resize_enabled &&
+ (cache_ptr->cache_accesses >= (cache_ptr->resize_ctl).epoch_length)) {
+
+ if(H5C__auto_adjust_cache_size(f, dxpl_id, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Cache auto-resize failed")
+ } /* end if */
+
+ if(cache_ptr->size_decreased) {
+ cache_ptr->size_decreased = FALSE;
+
+ /* check to see if the cache is now oversized due to the cache
+ * size reduction. If it is, try to evict enough entries to
+ * bring the cache size down to the current maximum cache size.
+ *
+ * Also, if the min_clean_size requirement is not met, we
+ * should also call H5C__make_space_in_cache() to bring us
+ * into complience.
+ */
+
+ if(cache_ptr->index_size >= cache_ptr->max_cache_size)
+ empty_space = 0;
+ else
+ empty_space = cache_ptr->max_cache_size - cache_ptr->index_size;
+
+ if ( ( cache_ptr->index_size > cache_ptr->max_cache_size )
+ ||
+ ( ( empty_space + cache_ptr->clean_index_size ) <
+ cache_ptr->min_clean_size) ) {
+
+ if(cache_ptr->index_size > cache_ptr->max_cache_size)
+ cache_ptr->cache_full = TRUE;
+
+ if(H5C__make_space_in_cache(f, dxpl_id, (size_t)0, write_permitted) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__make_space_in_cache failed")
+ }
+ } /* end if */
+ }
+
+ /* If we loaded the entry and the entry's type has a 'notify' callback, send
+ * an 'after load' notice now that the entry is fully integrated into
+ * the cache and protected. We must wait until it is protected so it is not
+ * evicted during the notify callback.
+ */
+ if(was_loaded) {
+ /* If the entry's type has a 'notify' callback send a 'after load'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, NULL, "can't notify client about entry inserted into cache")
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ /* Make sure the size of the collective entries in the cache remain in check */
+ if(coll_access) {
+ if(H5P_USER_TRUE == f->coll_md_read) {
+ if(cache_ptr->max_cache_size * 80 < cache_ptr->coll_list_size * 100)
+ if(H5C_clear_coll_entries(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "can't clear collective metadata entries")
+ } /* end if */
+ else {
+ if(cache_ptr->max_cache_size * 40 < cache_ptr->coll_list_size * 100)
+ if(H5C_clear_coll_entries(cache_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "can't clear collective metadata entries")
+ } /* end else */
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_protect() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_reset_cache_hit_rate_stats()
+ *
+ * Purpose: Reset the cache hit rate computation fields.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer, 10/5/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_reset_cache_hit_rate_stats(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry")
+
+ cache_ptr->cache_hits = 0;
+ cache_ptr->cache_accesses = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_reset_cache_hit_rate_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_cache_auto_resize_config
+ *
+ * Purpose: Set the cache automatic resize configuration to the
+ * provided values if they are in range, and fail if they
+ * are not.
+ *
+ * If the new configuration enables automatic cache resizing,
+ * coerce the cache max size and min clean size into agreement
+ * with the new policy and re-set the full cache hit rate
+ * stats.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 10/8/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_cache_auto_resize_config(H5C_t *cache_ptr,
+ H5C_auto_size_ctl_t *config_ptr)
+{
+ size_t new_max_cache_size;
+ size_t new_min_clean_size;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry")
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry")
+ if(config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown config version")
+
+ /* check general configuration section of the config: */
+ if(H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_GENERAL) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in general configuration fields of new config")
+
+ /* check size increase control fields of the config: */
+ if(H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INCREMENT) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size increase control fields of new config")
+
+ /* check size decrease control fields of the config: */
+ if(H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_DECREMENT) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size decrease control fields of new config")
+
+ /* check for conflicts between size increase and size decrease controls: */
+ if(H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "conflicting threshold fields in new config")
+
+ /* will set the increase possible fields to FALSE later if needed */
+ cache_ptr->size_increase_possible = TRUE;
+ cache_ptr->flash_size_increase_possible = TRUE;
+ cache_ptr->size_decrease_possible = TRUE;
+
+ switch(config_ptr->incr_mode) {
+ case H5C_incr__off:
+ cache_ptr->size_increase_possible = FALSE;
+ break;
+
+ case H5C_incr__threshold:
+ if((config_ptr->lower_hr_threshold <= (double)0.0f) ||
+ (config_ptr->increment <= (double)1.0f) ||
+ ((config_ptr->apply_max_increment) && (config_ptr->max_increment <= 0)))
+ cache_ptr->size_increase_possible = FALSE;
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown incr_mode?!?!?")
+ } /* end switch */
+
+ /* logically, this is were configuration for flash cache size increases
+ * should go. However, this configuration depends on max_cache_size, so
+ * we wait until the end of the function, when this field is set.
+ */
+
+ switch(config_ptr->decr_mode) {
+ case H5C_decr__off:
+ cache_ptr->size_decrease_possible = FALSE;
+ break;
+
+ case H5C_decr__threshold:
+ if((config_ptr->upper_hr_threshold >= (double)1.0f) ||
+ (config_ptr->decrement >= (double)1.0f) ||
+ ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0)))
+ cache_ptr->size_decrease_possible = FALSE;
+ break;
+
+ case H5C_decr__age_out:
+ if(((config_ptr->apply_empty_reserve) && (config_ptr->empty_reserve >= (double)1.0f)) ||
+ ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0)))
+ cache_ptr->size_decrease_possible = FALSE;
+ break;
+
+ case H5C_decr__age_out_with_threshold:
+ if(((config_ptr->apply_empty_reserve) && (config_ptr->empty_reserve >= (double)1.0f)) ||
+ ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0)) ||
+ (config_ptr->upper_hr_threshold >= (double)1.0f))
+ cache_ptr->size_decrease_possible = FALSE;
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown decr_mode?!?!?")
+ } /* end switch */
+
+ if(config_ptr->max_size == config_ptr->min_size) {
+ cache_ptr->size_increase_possible = FALSE;
+ cache_ptr->flash_size_increase_possible = FALSE;
+ cache_ptr->size_decrease_possible = FALSE;
+ } /* end if */
+
+ /* flash_size_increase_possible is intentionally omitted from the
+ * following:
+ */
+ cache_ptr->resize_enabled = cache_ptr->size_increase_possible ||
+ cache_ptr->size_decrease_possible;
+
+ cache_ptr->resize_ctl = *config_ptr;
+
+ /* Resize the cache to the supplied initial value if requested, or as
+ * necessary to force it within the bounds of the current automatic
+ * cache resizing configuration.
+ *
+ * Note that the min_clean_fraction may have changed, so we
+ * go through the exercise even if the current size is within
+ * range and an initial size has not been provided.
+ */
+ if(cache_ptr->resize_ctl.set_initial_size)
+ new_max_cache_size = cache_ptr->resize_ctl.initial_size;
+ else if(cache_ptr->max_cache_size > cache_ptr->resize_ctl.max_size)
+ new_max_cache_size = cache_ptr->resize_ctl.max_size;
+ else if(cache_ptr->max_cache_size < cache_ptr->resize_ctl.min_size)
+ new_max_cache_size = cache_ptr->resize_ctl.min_size;
+ else
+ new_max_cache_size = cache_ptr->max_cache_size;
+
+ new_min_clean_size = (size_t)((double)new_max_cache_size *
+ ((cache_ptr->resize_ctl).min_clean_fraction));
+
+
+ /* since new_min_clean_size is of type size_t, we have
+ *
+ * ( 0 <= new_min_clean_size )
+ *
+ * by definition.
+ */
+ HDassert(new_min_clean_size <= new_max_cache_size);
+ HDassert(cache_ptr->resize_ctl.min_size <= new_max_cache_size);
+ HDassert(new_max_cache_size <= cache_ptr->resize_ctl.max_size);
+
+ if(new_max_cache_size < cache_ptr->max_cache_size)
+ cache_ptr->size_decreased = TRUE;
+
+ cache_ptr->max_cache_size = new_max_cache_size;
+ cache_ptr->min_clean_size = new_min_clean_size;
+
+ if(H5C_reset_cache_hit_rate_stats(cache_ptr) < 0)
+ /* this should be impossible... */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed")
+
+ /* remove excess epoch markers if any */
+ if((config_ptr->decr_mode == H5C_decr__age_out_with_threshold) ||
+ (config_ptr->decr_mode == H5C_decr__age_out)) {
+ if(cache_ptr->epoch_markers_active > cache_ptr->resize_ctl.epochs_before_eviction)
+ if(H5C__autoadjust__ageout__remove_excess_markers(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't remove excess epoch markers")
+ } /* end if */
+ else if(cache_ptr->epoch_markers_active > 0) {
+ if(H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error removing all epoch markers")
+ }
+
+ /* configure flash size increase facility. We wait until the
+ * end of the function, as we need the max_cache_size set before
+ * we start to keep things simple.
+ *
+ * If we haven't already ruled out flash cache size increases above,
+ * go ahead and configure it.
+ */
+
+ if(cache_ptr->flash_size_increase_possible) {
+ switch(config_ptr->flash_incr_mode) {
+ case H5C_flash_incr__off:
+ cache_ptr->flash_size_increase_possible = FALSE;
+ break;
+
+ case H5C_flash_incr__add_space:
+ cache_ptr->flash_size_increase_possible = TRUE;
+ cache_ptr->flash_size_increase_threshold = (size_t)(((double)(cache_ptr->max_cache_size)) *
+ ((cache_ptr->resize_ctl).flash_threshold));
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?")
+ break;
+ } /* end switch */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_cache_auto_resize_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_evictions_enabled()
+ *
+ * Purpose: Set cache_ptr->evictions_enabled to the value of the
+ * evictions enabled parameter.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 7/27/07
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_evictions_enabled(H5C_t *cache_ptr, hbool_t evictions_enabled)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry")
+
+ /* There is no fundamental reason why we should not permit
+ * evictions to be disabled while automatic resize is enabled.
+ * However, I can't think of any good reason why one would
+ * want to, and allowing it would greatly complicate testing
+ * the feature. Hence the following:
+ */
+ if((evictions_enabled != TRUE) &&
+ ((cache_ptr->resize_ctl.incr_mode != H5C_incr__off) ||
+ (cache_ptr->resize_ctl.decr_mode != H5C_decr__off)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't disable evictions when auto resize enabled")
+
+ cache_ptr->evictions_enabled = evictions_enabled;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_evictions_enabled() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_unpin_entry_from_client()
+ *
+ * Purpose: Internal routine to unpin a cache entry from a client action.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/24/09
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C_unpin_entry_from_client(H5C_t * cache_ptr,
+ H5C_cache_entry_t * entry_ptr,
+ hbool_t update_rp)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checking */
+ HDassert( cache_ptr );
+ HDassert( entry_ptr );
+
+ /* Error checking (should be sanity checks?) */
+ if(!entry_ptr->is_pinned)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Entry isn't pinned")
+ if(!entry_ptr->pinned_from_client)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Entry wasn't pinned by cache client")
+
+ /* Check if the entry is not pinned from a flush dependency */
+ if(!entry_ptr->pinned_from_cache) {
+ /* If requested, update the replacement policy if the entry is not protected */
+ if(update_rp && !entry_ptr->is_protected)
+ H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, FAIL)
+
+ /* Unpin the entry now */
+ entry_ptr->is_pinned = FALSE;
+
+ /* Update the stats for an unpin operation */
+ H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr)
+ } /* end if */
+
+ /* Mark the entry as explicitly unpinned by the client */
+ entry_ptr->pinned_from_client = FALSE;
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_unpin_entry_from_client() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_unpin_entry()
+ *
+ * Purpose: Unpin a cache entry. The entry can be either protected or
+ * unprotected at the time of call, but must be pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 3/22/06
+ *
+ * Changes: Added extreme sanity checks on entry and exit.
+ JRM -- 4/26/14
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_unpin_entry(void *_entry_ptr)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)_entry_ptr; /* Pointer to entry to unpin */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(entry_ptr);
+ cache_ptr = entry_ptr->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+ /* Unpin the entry */
+ if(H5C_unpin_entry_from_client(cache_ptr, entry_ptr, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry from client")
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_unpin_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_unprotect
+ *
+ * Purpose: Undo an H5C_protect() call -- specifically, mark the
+ * entry as unprotected, remove it from the protected list,
+ * and give it back to the replacement policy.
+ *
+ * The TYPE and ADDR arguments must be the same as those in
+ * the corresponding call to H5C_protect() and the THING
+ * argument must be the value returned by that call to
+ * H5C_protect().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * If the deleted flag is TRUE, simply remove the target entry
+ * from the cache, clear it, and free it without writing it to
+ * disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_unprotect(H5F_t * f,
+ hid_t dxpl_id,
+ haddr_t addr,
+ void * thing,
+ unsigned int flags)
+{
+ H5C_t * cache_ptr;
+ hbool_t deleted;
+ hbool_t dirtied;
+ hbool_t set_flush_marker;
+ hbool_t pin_entry;
+ hbool_t unpin_entry;
+ hbool_t free_file_space;
+ hbool_t take_ownership;
+ hbool_t was_clean;
+#ifdef H5_HAVE_PARALLEL
+ hbool_t clear_entry = FALSE;
+#endif /* H5_HAVE_PARALLEL */
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * test_entry_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ deleted = ((flags & H5C__DELETED_FLAG) != 0);
+ dirtied = ((flags & H5C__DIRTIED_FLAG) != 0);
+ set_flush_marker = ((flags & H5C__SET_FLUSH_MARKER_FLAG) != 0);
+ pin_entry = ((flags & H5C__PIN_ENTRY_FLAG) != 0);
+ unpin_entry = ((flags & H5C__UNPIN_ENTRY_FLAG) != 0);
+ free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0);
+ take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0);
+
+ HDassert( f );
+ HDassert( f->shared );
+
+ cache_ptr = f->shared->cache;
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( thing );
+ HDassert( ! ( pin_entry && unpin_entry ) );
+ HDassert( ( ! free_file_space ) || ( deleted ) ); /* deleted flag must accompany free_file_space */
+ HDassert( ( ! take_ownership ) || ( deleted ) ); /* deleted flag must accompany take_ownership */
+ HDassert( ! ( free_file_space && take_ownership ) ); /* can't have both free_file_space & take_ownership */
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ HDassert( entry_ptr->addr == addr );
+
+ /* also set the dirtied variable if the dirtied field is set in
+ * the entry.
+ */
+ dirtied |= entry_ptr->dirtied;
+ was_clean = ! ( entry_ptr->is_dirty );
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ /* if the entry has multiple read only protects, just decrement
+ * the ro_ref_counter. Don't actually unprotect until the ref count
+ * drops to zero.
+ */
+ if(entry_ptr->ro_ref_count > 1) {
+ /* Sanity check */
+ HDassert(entry_ptr->is_protected);
+ HDassert(entry_ptr->is_read_only);
+
+ if(dirtied)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??")
+
+ /* Reduce the RO ref count */
+ (entry_ptr->ro_ref_count)--;
+
+ /* Pin or unpin the entry as requested. */
+ if(pin_entry) {
+ /* Pin the entry from a client */
+ if(H5C_pin_entry_from_client(cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client")
+ } else if(unpin_entry) {
+ /* Unpin the entry from a client */
+ if(H5C_unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client")
+ } /* end if */
+ } else {
+ if(entry_ptr->is_read_only) {
+ /* Sanity check */
+ HDassert(entry_ptr->ro_ref_count == 1);
+
+ if(dirtied)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??")
+
+ entry_ptr->is_read_only = FALSE;
+ entry_ptr->ro_ref_count = 0;
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ /* When the H5C code is used to implement the metadata cache in the
+ * PHDF5 case, only the cache on process 0 is allowed to write to file.
+ * All the other metadata caches must hold dirty entries until they
+ * are told that the entries are clean.
+ *
+ * The clear_on_unprotect flag in the H5C_cache_entry_t structure
+ * exists to deal with the case in which an entry is protected when
+ * its cache receives word that the entry is now clean. In this case,
+ * the clear_on_unprotect flag is set, and the entry is flushed with
+ * the H5C__FLUSH_CLEAR_ONLY_FLAG.
+ *
+ * All this is a bit awkward, but until the metadata cache entries
+ * are contiguous, with only one dirty flag, we have to let the supplied
+ * functions deal with the reseting the is_dirty flag.
+ */
+ if(entry_ptr->clear_on_unprotect) {
+ /* Sanity check */
+ HDassert(entry_ptr->is_dirty);
+
+ entry_ptr->clear_on_unprotect = FALSE;
+ if(!dirtied)
+ clear_entry = TRUE;
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ if(!entry_ptr->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Entry already unprotected??")
+
+ /* Mark the entry as dirty if appropriate */
+ entry_ptr->is_dirty = (entry_ptr->is_dirty || dirtied);
+
+ if(dirtied)
+ if(entry_ptr->image_up_to_date) {
+ entry_ptr->image_up_to_date = FALSE;
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+ } /* end if */
+
+ /* Check for newly dirtied entry */
+ if(was_clean && entry_ptr->is_dirty) {
+ /* Update index for newly dirtied entry */
+ H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr)
+
+ /* If the entry's type has a 'notify' callback send a 'entry dirtied'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set")
+
+ /* Propagate the flush dep dirty flag up the flush dependency chain
+ * if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_dirty(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag")
+ } /* end if */
+ /* Check for newly clean entry */
+ else if(!was_clean && !entry_ptr->is_dirty) {
+ /* If the entry's type has a 'notify' callback send a 'entry cleaned'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared")
+
+ /* Propagate the flush dep clean flag up the flush dependency chain
+ * if appropriate */
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_clean(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag")
+ } /* end else-if */
+
+ /* Pin or unpin the entry as requested. */
+ if(pin_entry) {
+ /* Pin the entry from a client */
+ if(H5C_pin_entry_from_client(cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client")
+ } else if(unpin_entry) {
+ /* Unpin the entry from a client */
+ if(H5C_unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client")
+ } /* end if */
+
+ /* H5C__UPDATE_RP_FOR_UNPROTECT will place the unprotected entry on
+ * the pinned entry list if entry_ptr->is_pinned is TRUE.
+ */
+ H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, FAIL)
+
+ entry_ptr->is_protected = FALSE;
+
+ /* if the entry is dirty, 'or' its flush_marker with the set flush flag,
+ * and then add it to the skip list if it isn't there already.
+ */
+ if(entry_ptr->is_dirty) {
+ entry_ptr->flush_marker |= set_flush_marker;
+ if(!entry_ptr->in_slist)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL)
+ } /* end if */
+
+ /* this implementation of the "deleted" option is a bit inefficient, as
+ * we re-insert the entry to be deleted into the replacement policy
+ * data structures, only to remove them again. Depending on how often
+ * we do this, we may want to optimize a bit.
+ *
+ * On the other hand, this implementation is reasonably clean, and
+ * makes good use of existing code.
+ * JRM - 5/19/04
+ */
+ if(deleted) {
+ unsigned flush_flags = (H5C__FLUSH_CLEAR_ONLY_FLAG |
+ H5C__FLUSH_INVALIDATE_FLAG);
+
+ /* verify that the target entry is in the cache. */
+ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL)
+ if(test_entry_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?")
+ else if(test_entry_ptr != entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?")
+
+ /* Set the 'free file space' flag for the flush, if needed */
+ if(free_file_space)
+ flush_flags |= H5C__FREE_FILE_SPACE_FLAG;
+
+ /* Set the "take ownership" flag for the flush, if needed */
+ if(take_ownership)
+ flush_flags |= H5C__TAKE_OWNERSHIP_FLAG;
+
+ /* Delete the entry from the skip list on destroy */
+ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG;
+
+ HDassert(((!was_clean) || dirtied) == entry_ptr->in_slist);
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, flush_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush entry")
+ } /* end if */
+#ifdef H5_HAVE_PARALLEL
+ else if(clear_entry) {
+
+ /* verify that the target entry is in the cache. */
+ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL)
+ if(test_entry_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?")
+ else if(test_entry_ptr != entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?")
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't clear entry")
+ } /* end else if */
+#endif /* H5_HAVE_PARALLEL */
+ }
+
+ H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0)) {
+ HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_unsettle_entry_ring
+ *
+ * Purpose: Advise the metadata cache that the specified entry's free space
+ * manager ring is no longer settled (if it was on entry).
+ *
+ * If the target free space manager ring is already
+ * unsettled, do nothing, and return SUCCEED.
+ *
+ * If the target free space manager ring is settled, and
+ * we are not in the process of a file shutdown, mark
+ * the ring as unsettled, and return SUCCEED.
+ *
+ * If the target free space manager is settled, and we
+ * are in the process of a file shutdown, post an error
+ * message, and return FAIL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * January 3, 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_unsettle_entry_ring(void *_entry)
+{
+ H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_entry; /* Entry whose ring to unsettle */
+ H5C_t *cache; /* Cache for file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+ HDassert(entry->ring != H5C_RING_UNDEFINED);
+ HDassert((H5C_RING_USER == entry->ring) || (H5C_RING_RDFSM == entry->ring) || (H5C_RING_MDFSM == entry->ring));
+ cache = entry->cache_ptr;
+ HDassert(cache);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ switch(entry->ring) {
+ case H5C_RING_USER:
+ /* Do nothing */
+ break;
+
+ case H5C_RING_RDFSM:
+ if(cache->rdfsm_settled) {
+ if(cache->flush_in_progress || cache->close_warning_received)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected rdfsm ring unsettle")
+ cache->rdfsm_settled = FALSE;
+ } /* end if */
+ break;
+
+ case H5C_RING_MDFSM:
+ if(cache->mdfsm_settled) {
+ if(cache->flush_in_progress || cache->close_warning_received)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected mdfsm ring unsettle")
+ cache->mdfsm_settled = FALSE;
+ } /* end if */
+ break;
+
+ default:
+ HDassert(FALSE); /* this should be un-reachable */
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_unsettle_entry_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_unsettle_ring()
+ *
+ * Purpose: Advise the metadata cache that the specified free space
+ * manager ring is no longer settled (if it was on entry).
+ *
+ * If the target free space manager ring is already
+ * unsettled, do nothing, and return SUCCEED.
+ *
+ * If the target free space manager ring is settled, and
+ * we are not in the process of a file shutdown, mark
+ * the ring as unsettled, and return SUCCEED.
+ *
+ * If the target free space manager is settled, and we
+ * are in the process of a file shutdown, post an error
+ * message, and return FAIL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 10/15/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_unsettle_ring(H5F_t * f, H5C_ring_t ring)
+{
+ H5C_t * cache_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert((H5C_RING_RDFSM == ring) || (H5C_RING_MDFSM == ring));
+ cache_ptr = f->shared->cache;
+ HDassert(H5C__H5C_T_MAGIC == cache_ptr->magic);
+
+ switch(ring) {
+ case H5C_RING_RDFSM:
+ if(cache_ptr->rdfsm_settled) {
+ if(cache_ptr->close_warning_received)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected rdfsm ring unsettle")
+ cache_ptr->rdfsm_settled = FALSE;
+ } /* end if */
+ break;
+
+ case H5C_RING_MDFSM:
+ if(cache_ptr->mdfsm_settled) {
+ if(cache_ptr->close_warning_received)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected mdfsm ring unsettle")
+ cache_ptr->mdfsm_settled = FALSE;
+ } /* end if */
+ break;
+
+ default:
+ HDassert(FALSE); /* this should be un-reachable */
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_unsettle_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_validate_resize_config()
+ *
+ * Purpose: Run a sanity check on the specified sections of the
+ * provided instance of struct H5C_auto_size_ctl_t.
+ *
+ * Do nothing and return SUCCEED if no errors are detected,
+ * and flag an error and return FAIL otherwise.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 3/23/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_validate_resize_config(H5C_auto_size_ctl_t * config_ptr,
+ unsigned int tests)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry")
+
+ if(config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown config version")
+
+ if((tests & H5C_RESIZE_CFG__VALIDATE_GENERAL) != 0) {
+
+ if(config_ptr->max_size > H5C__MAX_MAX_CACHE_SIZE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "max_size too big")
+
+ if(config_ptr->min_size < H5C__MIN_MAX_CACHE_SIZE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size too small")
+
+ if(config_ptr->min_size > config_ptr->max_size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size > max_size")
+
+ if(config_ptr->set_initial_size &&
+ ((config_ptr->initial_size < config_ptr->min_size) ||
+ (config_ptr->initial_size > config_ptr->max_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "initial_size must be in the interval [min_size, max_size]")
+
+ if((config_ptr->min_clean_fraction < (double)0.0f) ||
+ (config_ptr->min_clean_fraction > (double)1.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_clean_fraction must be in the interval [0.0, 1.0]")
+
+ if(config_ptr->epoch_length < H5C__MIN_AR_EPOCH_LENGTH)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too small")
+
+ if(config_ptr->epoch_length > H5C__MAX_AR_EPOCH_LENGTH)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too big")
+ } /* H5C_RESIZE_CFG__VALIDATE_GENERAL */
+
+
+ if((tests & H5C_RESIZE_CFG__VALIDATE_INCREMENT) != 0) {
+ if((config_ptr->incr_mode != H5C_incr__off) &&
+ (config_ptr->incr_mode != H5C_incr__threshold))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid incr_mode")
+
+ if(config_ptr->incr_mode == H5C_incr__threshold) {
+ if((config_ptr->lower_hr_threshold < (double)0.0f) ||
+ (config_ptr->lower_hr_threshold > (double)1.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "lower_hr_threshold must be in the range [0.0, 1.0]")
+
+ if(config_ptr->increment < (double)1.0f)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "increment must be greater than or equal to 1.0")
+
+ /* no need to check max_increment, as it is a size_t,
+ * and thus must be non-negative.
+ */
+ } /* H5C_incr__threshold */
+
+ switch(config_ptr->flash_incr_mode) {
+ case H5C_flash_incr__off:
+ /* nothing to do here */
+ break;
+
+ case H5C_flash_incr__add_space:
+ if((config_ptr->flash_multiple < (double)0.1f) ||
+ (config_ptr->flash_multiple > (double)10.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "flash_multiple must be in the range [0.1, 10.0]")
+ if((config_ptr->flash_threshold < (double)0.1f) ||
+ (config_ptr->flash_threshold > (double)1.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "flash_threshold must be in the range [0.1, 1.0]")
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid flash_incr_mode")
+ break;
+ } /* end switch */
+ } /* H5C_RESIZE_CFG__VALIDATE_INCREMENT */
+
+
+ if ( (tests & H5C_RESIZE_CFG__VALIDATE_DECREMENT) != 0 ) {
+
+ if ( ( config_ptr->decr_mode != H5C_decr__off ) &&
+ ( config_ptr->decr_mode != H5C_decr__threshold ) &&
+ ( config_ptr->decr_mode != H5C_decr__age_out ) &&
+ ( config_ptr->decr_mode != H5C_decr__age_out_with_threshold )
+ ) {
+
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid decr_mode")
+ }
+
+ if ( config_ptr->decr_mode == H5C_decr__threshold ) {
+ if(config_ptr->upper_hr_threshold > (double)1.0f)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "upper_hr_threshold must be <= 1.0")
+
+ if((config_ptr->decrement > (double)1.0f) ||
+ (config_ptr->decrement < (double)0.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "decrement must be in the interval [0.0, 1.0]")
+
+ /* no need to check max_decrement as it is a size_t
+ * and thus must be non-negative.
+ */
+ } /* H5C_decr__threshold */
+
+ if((config_ptr->decr_mode == H5C_decr__age_out) ||
+ (config_ptr->decr_mode == H5C_decr__age_out_with_threshold)) {
+
+ if(config_ptr->epochs_before_eviction < 1)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction must be positive")
+ if(config_ptr->epochs_before_eviction > H5C__MAX_EPOCH_MARKERS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction too big")
+
+ if((config_ptr->apply_empty_reserve) &&
+ ((config_ptr->empty_reserve > (double)1.0f) ||
+ (config_ptr->empty_reserve < (double)0.0f)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "empty_reserve must be in the interval [0.0, 1.0]")
+
+ /* no need to check max_decrement as it is a size_t
+ * and thus must be non-negative.
+ */
+ } /* H5C_decr__age_out || H5C_decr__age_out_with_threshold */
+
+ if(config_ptr->decr_mode == H5C_decr__age_out_with_threshold) {
+ if((config_ptr->upper_hr_threshold > (double)1.0f) ||
+ (config_ptr->upper_hr_threshold < (double)0.0f))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "upper_hr_threshold must be in the interval [0.0, 1.0]")
+ } /* H5C_decr__age_out_with_threshold */
+ } /* H5C_RESIZE_CFG__VALIDATE_DECREMENT */
+
+
+ if ( (tests & H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) != 0 ) {
+ if((config_ptr->incr_mode == H5C_incr__threshold)
+ && ((config_ptr->decr_mode == H5C_decr__threshold) ||
+ (config_ptr->decr_mode == H5C_decr__age_out_with_threshold))
+ && (config_ptr->lower_hr_threshold >= config_ptr->upper_hr_threshold))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "conflicting threshold fields in config")
+ } /* H5C_RESIZE_CFG__VALIDATE_INTERACTIONS */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_validate_resize_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_create_flush_dependency()
+ *
+ * Purpose: Initiates a parent<->child entry flush dependency. The parent
+ * entry must be pinned or protected at the time of call, and must
+ * have all dependencies removed before the cache can shut down.
+ *
+ * Note: Flush dependencies in the cache indicate that a child entry
+ * must be flushed to the file before its parent. (This is
+ * currently used to implement Single-Writer/Multiple-Reader (SWMR)
+ * I/O access for data structures in the file).
+ *
+ * Creating a flush dependency between two entries will also pin
+ * the parent entry.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/05/09
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_create_flush_dependency(void * parent_thing, void * child_thing)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * parent_entry = (H5C_cache_entry_t *)parent_thing; /* Ptr to parent thing's entry */
+ H5C_cache_entry_t * child_entry = (H5C_cache_entry_t *)child_thing; /* Ptr to child thing's entry */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(parent_entry);
+ HDassert(parent_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(H5F_addr_defined(parent_entry->addr));
+ HDassert(child_entry);
+ HDassert(child_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(H5F_addr_defined(child_entry->addr));
+ cache_ptr = parent_entry->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr == child_entry->cache_ptr);
+#ifndef NDEBUG
+ /* Make sure the parent is not already a parent */
+ {
+ unsigned u;
+
+ for(u = 0; u < child_entry->flush_dep_nparents; u++)
+ HDassert(child_entry->flush_dep_parent[u] != parent_entry);
+ } /* end block */
+#endif /* NDEBUG */
+
+ /* More sanity checks */
+ if(child_entry == parent_entry)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Child entry flush dependency parent can't be itself")
+ if(!(parent_entry->is_protected || parent_entry->is_pinned))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Parent entry isn't pinned or protected")
+
+ /* Check for parent not pinned */
+ if(!parent_entry->is_pinned) {
+ /* Sanity check */
+ HDassert(parent_entry->flush_dep_nchildren == 0);
+ HDassert(!parent_entry->pinned_from_client);
+ HDassert(!parent_entry->pinned_from_cache);
+
+ /* Pin the parent entry */
+ parent_entry->is_pinned = TRUE;
+ H5C__UPDATE_STATS_FOR_PIN(cache_ptr, parent_entry)
+ } /* end else */
+
+ /* Mark the entry as pinned from the cache's action (possibly redundantly) */
+ parent_entry->pinned_from_cache = TRUE;
+
+ /* Check if we need to resize the child's parent array */
+ if(child_entry->flush_dep_nparents >= child_entry->flush_dep_parent_nalloc) {
+ if(child_entry->flush_dep_parent_nalloc == 0) {
+ /* Array does not exist yet, allocate it */
+ HDassert(!child_entry->flush_dep_parent);
+
+ if(NULL == (child_entry->flush_dep_parent = (H5C_cache_entry_t **)H5FL_BLK_MALLOC(parent, H5C_FLUSH_DEP_PARENT_INIT * sizeof(H5C_cache_entry_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list")
+ child_entry->flush_dep_parent_nalloc = H5C_FLUSH_DEP_PARENT_INIT;
+ } /* end if */
+ else {
+ /* Resize existing array */
+ HDassert(child_entry->flush_dep_parent);
+
+ if(NULL == (child_entry->flush_dep_parent = (H5C_cache_entry_t **)H5FL_BLK_REALLOC(parent, child_entry->flush_dep_parent, 2 * child_entry->flush_dep_parent_nalloc * sizeof(H5C_cache_entry_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list")
+ child_entry->flush_dep_parent_nalloc *= 2;
+ } /* end else */
+ cache_ptr->entry_fd_height_change_counter++;
+ } /* end if */
+
+ /* Add the dependency to the child's parent array */
+ child_entry->flush_dep_parent[child_entry->flush_dep_nparents] = parent_entry;
+ child_entry->flush_dep_nparents++;
+
+ /* Increment parent's number of children */
+ parent_entry->flush_dep_nchildren++;
+
+ /* Adjust the number of dirty children */
+ if(child_entry->is_dirty) {
+ /* Sanity check */
+ HDassert(parent_entry->flush_dep_ndirty_children < parent_entry->flush_dep_nchildren);
+
+ parent_entry->flush_dep_ndirty_children++;
+
+ /* If the parent has a 'notify' callback, send a 'child entry dirtied' notice */
+ if(parent_entry->type->notify &&
+ (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_DIRTIED, parent_entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag set")
+ } /* end if */
+
+ /* adjust the parent's number of unserialized children. Note
+ * that it is possible for and entry to be clean and unserialized.
+ */
+ if(!child_entry->image_up_to_date) {
+ HDassert(parent_entry->flush_dep_nunser_children < parent_entry->flush_dep_nchildren);
+
+ parent_entry->flush_dep_nunser_children++;
+
+ /* If the parent has a 'notify' callback, send a 'child entry unserialized' notice */
+ if(parent_entry->type->notify &&
+ (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED, parent_entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag reset")
+ } /* end if */
+
+ /* Post-conditions, for successful operation */
+ HDassert(parent_entry->is_pinned);
+ HDassert(parent_entry->flush_dep_nchildren > 0);
+ HDassert(child_entry->flush_dep_parent);
+ HDassert(child_entry->flush_dep_nparents > 0);
+ HDassert(child_entry->flush_dep_parent_nalloc > 0);
+#ifndef NDEBUG
+ H5C__assert_flush_dep_nocycle(parent_entry, child_entry);
+#endif /* NDEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_create_flush_dependency() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_destroy_flush_dependency()
+ *
+ * Purpose: Terminates a parent<-> child entry flush dependency. The
+ * parent entry must be pinned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 3/05/09
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_destroy_flush_dependency(void *parent_thing, void * child_thing)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * parent_entry = (H5C_cache_entry_t *)parent_thing; /* Ptr to parent entry */
+ H5C_cache_entry_t * child_entry = (H5C_cache_entry_t *)child_thing; /* Ptr to child entry */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(parent_entry);
+ HDassert(parent_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(H5F_addr_defined(parent_entry->addr));
+ HDassert(child_entry);
+ HDassert(child_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(H5F_addr_defined(child_entry->addr));
+ cache_ptr = parent_entry->cache_ptr;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr == child_entry->cache_ptr);
+
+ /* Usage checks */
+ if(!parent_entry->is_pinned)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't pinned")
+ if(NULL == child_entry->flush_dep_parent)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Child entry doesn't have a flush dependency parent array")
+ if(0 == parent_entry->flush_dep_nchildren)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry flush dependency ref. count has no child dependencies")
+
+ /* Search for parent in child's parent array. This is a linear search
+ * because we do not expect large numbers of parents. If this changes, we
+ * may wish to change the parent array to a skip list */
+ for(u = 0; u < child_entry->flush_dep_nparents; u++)
+ if(child_entry->flush_dep_parent[u] == parent_entry)
+ break;
+ if(u == child_entry->flush_dep_nparents)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't a flush dependency parent for child entry")
+
+ /* Remove parent entry from child's parent array */
+ if(u < (child_entry->flush_dep_nparents - 1))
+ HDmemmove(&child_entry->flush_dep_parent[u],
+ &child_entry->flush_dep_parent[u + 1],
+ (child_entry->flush_dep_nparents - u - 1) * sizeof(child_entry->flush_dep_parent[0]));
+ child_entry->flush_dep_nparents--;
+
+ /* Adjust parent entry's nchildren and unpin parent if it goes to zero */
+ parent_entry->flush_dep_nchildren--;
+ if(0 == parent_entry->flush_dep_nchildren) {
+ /* Sanity check */
+ HDassert(parent_entry->pinned_from_cache);
+
+ /* Check if we should unpin parent entry now */
+ if(!parent_entry->pinned_from_client) {
+ /* Update the replacement policy if the entry is not protected */
+ if(!parent_entry->is_protected)
+ H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, parent_entry, FAIL)
+
+ /* Unpin the entry now */
+ parent_entry->is_pinned = FALSE;
+
+ /* Update the stats for an unpin operation */
+ H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, parent_entry)
+ } /* end if */
+
+ /* Mark the entry as unpinned from the cache's action */
+ parent_entry->pinned_from_cache = FALSE;
+ } /* end if */
+
+ /* Adjust parent entry's ndirty_children */
+ if(child_entry->is_dirty) {
+ /* Sanity check */
+ HDassert(parent_entry->flush_dep_ndirty_children > 0);
+
+ parent_entry->flush_dep_ndirty_children--;
+
+ /* If the parent has a 'notify' callback, send a 'child entry cleaned' notice */
+ if(parent_entry->type->notify &&
+ (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_CLEANED, parent_entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag reset")
+ } /* end if */
+
+ /* adjust parent entry's number of unserialized children */
+ if(!child_entry->image_up_to_date) {
+ HDassert(parent_entry->flush_dep_nunser_children > 0);
+
+ parent_entry->flush_dep_nunser_children--;
+
+ /* If the parent has a 'notify' callback, send a 'child entry serialized' notice */
+ if(parent_entry->type->notify &&
+ (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_SERIALIZED, parent_entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag set")
+ } /* end if */
+
+ /* Shrink or free the parent array if apporpriate */
+ if(child_entry->flush_dep_nparents == 0) {
+ child_entry->flush_dep_parent = (H5C_cache_entry_t **)H5FL_BLK_FREE(parent, child_entry->flush_dep_parent);
+ child_entry->flush_dep_parent_nalloc = 0;
+ } /* end if */
+ else if(child_entry->flush_dep_parent_nalloc > H5C_FLUSH_DEP_PARENT_INIT
+ && child_entry->flush_dep_nparents
+ <= (child_entry->flush_dep_parent_nalloc / 4)) {
+ if(NULL == (child_entry->flush_dep_parent = (H5C_cache_entry_t **)H5FL_BLK_REALLOC(parent, child_entry->flush_dep_parent, (child_entry->flush_dep_parent_nalloc / 4) * sizeof(H5C_cache_entry_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list")
+ child_entry->flush_dep_parent_nalloc /= 4;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_destroy_flush_dependency() */
+
+
+/*************************************************************************/
+/**************************** Private Functions: *************************/
+/*************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__auto_adjust_cache_size
+ *
+ * Purpose: Obtain the current full cache hit rate, and compare it
+ * with the hit rate thresholds for modifying cache size.
+ * If one of the thresholds has been crossed, adjusts the
+ * size of the cache accordingly.
+ *
+ * The function then resets the full cache hit rate
+ * statistics, and exits.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * an attempt to flush a protected item.
+ *
+ *
+ * Programmer: John Mainzer, 10/7/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__auto_adjust_cache_size(H5F_t * f,
+ hid_t dxpl_id,
+ hbool_t write_permitted)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+ hbool_t reentrant_call = FALSE;
+ hbool_t inserted_epoch_marker = FALSE;
+ size_t new_max_cache_size = 0;
+ size_t old_max_cache_size = 0;
+ size_t new_min_clean_size = 0;
+ size_t old_min_clean_size = 0;
+ double hit_rate;
+ enum H5C_resize_status status = in_spec; /* will change if needed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( f );
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->cache_accesses >=
+ (cache_ptr->resize_ctl).epoch_length );
+ HDassert( (double)0.0f <= (cache_ptr->resize_ctl).min_clean_fraction );
+ HDassert( (cache_ptr->resize_ctl).min_clean_fraction <= (double)100.0f );
+
+ /* check to see if cache_ptr->resize_in_progress is TRUE. If it, this
+ * is a re-entrant call via a client callback called in the resize
+ * process. To avoid an infinite recursion, set reentrant_call to
+ * TRUE, and goto done.
+ */
+ if(cache_ptr->resize_in_progress) {
+ reentrant_call = TRUE;
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ cache_ptr->resize_in_progress = TRUE;
+
+ if(!cache_ptr->resize_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Auto cache resize disabled")
+
+ HDassert(((cache_ptr->resize_ctl).incr_mode != H5C_incr__off) || \
+ ((cache_ptr->resize_ctl).decr_mode != H5C_decr__off));
+
+ if(H5C_get_cache_hit_rate(cache_ptr, &hit_rate) != SUCCEED)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get hit rate")
+
+ HDassert( ( (double)0.0f <= hit_rate ) && ( hit_rate <= (double)1.0f ) );
+
+ switch((cache_ptr->resize_ctl).incr_mode) {
+ case H5C_incr__off:
+ if(cache_ptr->size_increase_possible)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "size_increase_possible but H5C_incr__off?!?!?")
+ break;
+
+ case H5C_incr__threshold:
+ if ( hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold ) {
+
+ if ( ! cache_ptr->size_increase_possible ) {
+
+ status = increase_disabled;
+
+ } else if ( cache_ptr->max_cache_size >=
+ (cache_ptr->resize_ctl).max_size ) {
+
+ HDassert( cache_ptr->max_cache_size == \
+ (cache_ptr->resize_ctl).max_size );
+ status = at_max_size;
+
+ } else if ( ! cache_ptr->cache_full ) {
+
+ status = not_full;
+
+ } else {
+
+ new_max_cache_size = (size_t)
+ (((double)(cache_ptr->max_cache_size)) *
+ (cache_ptr->resize_ctl).increment);
+
+ /* clip to max size if necessary */
+ if ( new_max_cache_size >
+ (cache_ptr->resize_ctl).max_size ) {
+
+ new_max_cache_size = (cache_ptr->resize_ctl).max_size;
+ }
+
+ /* clip to max increment if necessary */
+ if ( ( (cache_ptr->resize_ctl).apply_max_increment ) &&
+ ( (cache_ptr->max_cache_size +
+ (cache_ptr->resize_ctl).max_increment) <
+ new_max_cache_size ) ) {
+
+ new_max_cache_size = cache_ptr->max_cache_size +
+ (cache_ptr->resize_ctl).max_increment;
+ }
+
+ status = increase;
+ }
+ }
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown incr_mode")
+ }
+
+ /* If the decr_mode is either age out or age out with threshold, we
+ * must run the marker maintenance code, whether we run the size
+ * reduction code or not. We do this in two places -- here we
+ * insert a new marker if the number of active epoch markers is
+ * is less than the the current epochs before eviction, and after
+ * the ageout call, we cycle the markers.
+ *
+ * However, we can't call the ageout code or cycle the markers
+ * unless there was a full complement of markers in place on
+ * entry. The inserted_epoch_marker flag is used to track this.
+ */
+
+ if ( ( ( (cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out )
+ ||
+ ( (cache_ptr->resize_ctl).decr_mode ==
+ H5C_decr__age_out_with_threshold
+ )
+ )
+ &&
+ ( cache_ptr->epoch_markers_active <
+ (cache_ptr->resize_ctl).epochs_before_eviction
+ )
+ ) {
+
+ if(H5C__autoadjust__ageout__insert_new_marker(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't insert new epoch marker")
+
+ inserted_epoch_marker = TRUE;
+ }
+
+ /* don't run the cache size decrease code unless the cache size
+ * increase code is disabled, or the size increase code sees no need
+ * for action. In either case, status == in_spec at this point.
+ */
+
+ if ( status == in_spec ) {
+
+ switch ( (cache_ptr->resize_ctl).decr_mode )
+ {
+ case H5C_decr__off:
+ break;
+
+ case H5C_decr__threshold:
+ if ( hit_rate > (cache_ptr->resize_ctl).upper_hr_threshold ) {
+
+ if ( ! cache_ptr->size_decrease_possible ) {
+
+ status = decrease_disabled;
+
+ } else if ( cache_ptr->max_cache_size <=
+ (cache_ptr->resize_ctl).min_size ) {
+
+ HDassert( cache_ptr->max_cache_size ==
+ (cache_ptr->resize_ctl).min_size );
+ status = at_min_size;
+
+ } else {
+
+ new_max_cache_size = (size_t)
+ (((double)(cache_ptr->max_cache_size)) *
+ (cache_ptr->resize_ctl).decrement);
+
+ /* clip to min size if necessary */
+ if ( new_max_cache_size <
+ (cache_ptr->resize_ctl).min_size ) {
+
+ new_max_cache_size =
+ (cache_ptr->resize_ctl).min_size;
+ }
+
+ /* clip to max decrement if necessary */
+ if ( ( (cache_ptr->resize_ctl).apply_max_decrement ) &&
+ ( ((cache_ptr->resize_ctl).max_decrement +
+ new_max_cache_size) <
+ cache_ptr->max_cache_size ) ) {
+
+ new_max_cache_size = cache_ptr->max_cache_size -
+ (cache_ptr->resize_ctl).max_decrement;
+ }
+
+ status = decrease;
+ }
+ }
+ break;
+
+ case H5C_decr__age_out_with_threshold:
+ case H5C_decr__age_out:
+ if(!inserted_epoch_marker) {
+ if(!cache_ptr->size_decrease_possible)
+ status = decrease_disabled;
+ else {
+ if(H5C__autoadjust__ageout(f, dxpl_id, hit_rate, &status, &new_max_cache_size, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ageout code failed")
+ } /* end else */
+ } /* end if */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown incr_mode")
+ }
+ }
+
+ /* cycle the epoch markers here if appropriate */
+ if ( ( ( (cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out )
+ ||
+ ( (cache_ptr->resize_ctl).decr_mode ==
+ H5C_decr__age_out_with_threshold
+ )
+ )
+ &&
+ ( ! inserted_epoch_marker )
+ ) {
+
+ /* move last epoch marker to the head of the LRU list */
+ if(H5C__autoadjust__ageout__cycle_epoch_marker(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error cycling epoch marker")
+ }
+
+ if ( ( status == increase ) || ( status == decrease ) ) {
+
+ old_max_cache_size = cache_ptr->max_cache_size;
+ old_min_clean_size = cache_ptr->min_clean_size;
+
+ new_min_clean_size = (size_t)
+ ((double)new_max_cache_size *
+ ((cache_ptr->resize_ctl).min_clean_fraction));
+
+ /* new_min_clean_size is of size_t, and thus must be non-negative.
+ * Hence we have
+ *
+ * ( 0 <= new_min_clean_size ).
+ *
+ * by definition.
+ */
+ HDassert( new_min_clean_size <= new_max_cache_size );
+ HDassert( (cache_ptr->resize_ctl).min_size <= new_max_cache_size );
+ HDassert( new_max_cache_size <= (cache_ptr->resize_ctl).max_size );
+
+ cache_ptr->max_cache_size = new_max_cache_size;
+ cache_ptr->min_clean_size = new_min_clean_size;
+
+ if ( status == increase ) {
+
+ cache_ptr->cache_full = FALSE;
+
+ } else if ( status == decrease ) {
+
+ cache_ptr->size_decreased = TRUE;
+ }
+
+ /* update flash cache size increase fields as appropriate */
+ if ( cache_ptr->flash_size_increase_possible ) {
+
+ switch ( (cache_ptr->resize_ctl).flash_incr_mode )
+ {
+ case H5C_flash_incr__off:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flash_size_increase_possible but H5C_flash_incr__off?!")
+ break;
+
+ case H5C_flash_incr__add_space:
+ cache_ptr->flash_size_increase_threshold =
+ (size_t)
+ (((double)(cache_ptr->max_cache_size)) *
+ ((cache_ptr->resize_ctl).flash_threshold));
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?")
+ break;
+ }
+ }
+ }
+
+ if ( (cache_ptr->resize_ctl).rpt_fcn != NULL ) {
+ (*((cache_ptr->resize_ctl).rpt_fcn))
+ (cache_ptr,
+ H5C__CURR_AUTO_RESIZE_RPT_FCN_VER,
+ hit_rate,
+ status,
+ old_max_cache_size,
+ new_max_cache_size,
+ old_min_clean_size,
+ new_min_clean_size);
+ }
+
+ if(H5C_reset_cache_hit_rate_stats(cache_ptr) < 0)
+ /* this should be impossible... */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed")
+
+done:
+ /* Sanity checks */
+ HDassert(cache_ptr->resize_in_progress);
+ if(!reentrant_call)
+ cache_ptr->resize_in_progress = FALSE;
+ HDassert((!reentrant_call) || (cache_ptr->resize_in_progress));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__auto_adjust_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout
+ *
+ * Purpose: Implement the ageout automatic cache size decrement
+ * algorithm. Note that while this code evicts aged out
+ * entries, the code does not change the maximum cache size.
+ * Instead, the function simply computes the new value (if
+ * any change is indicated) and reports this value in
+ * *new_max_cache_size_ptr.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * an attempt to flush a protected item.
+ *
+ *
+ * Programmer: John Mainzer, 11/18/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout(H5F_t * f,
+ hid_t dxpl_id,
+ double hit_rate,
+ enum H5C_resize_status * status_ptr,
+ size_t * new_max_cache_size_ptr,
+ hbool_t write_permitted)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+ size_t test_size;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( f );
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( ( status_ptr ) && ( *status_ptr == in_spec ) );
+ HDassert( ( new_max_cache_size_ptr ) && ( *new_max_cache_size_ptr == 0 ) );
+
+ /* remove excess epoch markers if any */
+ if(cache_ptr->epoch_markers_active > (cache_ptr->resize_ctl).epochs_before_eviction)
+ if(H5C__autoadjust__ageout__remove_excess_markers(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't remove excess epoch markers")
+
+ if ( ( (cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out )
+ ||
+ ( ( (cache_ptr->resize_ctl).decr_mode ==
+ H5C_decr__age_out_with_threshold
+ )
+ &&
+ ( hit_rate >= (cache_ptr->resize_ctl).upper_hr_threshold )
+ )
+ ) {
+
+ if ( cache_ptr->max_cache_size > (cache_ptr->resize_ctl).min_size ){
+
+ /* evict aged out cache entries if appropriate... */
+ if(H5C__autoadjust__ageout__evict_aged_out_entries(f, dxpl_id, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error flushing aged out entries")
+
+ /* ... and then reduce cache size if appropriate */
+ if ( cache_ptr->index_size < cache_ptr->max_cache_size ) {
+
+ if ( (cache_ptr->resize_ctl).apply_empty_reserve ) {
+
+ test_size = (size_t)(((double)cache_ptr->index_size) /
+ (1 - (cache_ptr->resize_ctl).empty_reserve));
+
+ if ( test_size < cache_ptr->max_cache_size ) {
+
+ *status_ptr = decrease;
+ *new_max_cache_size_ptr = test_size;
+ }
+ } else {
+
+ *status_ptr = decrease;
+ *new_max_cache_size_ptr = cache_ptr->index_size;
+ }
+
+ if ( *status_ptr == decrease ) {
+
+ /* clip to min size if necessary */
+ if ( *new_max_cache_size_ptr <
+ (cache_ptr->resize_ctl).min_size ) {
+
+ *new_max_cache_size_ptr =
+ (cache_ptr->resize_ctl).min_size;
+ }
+
+ /* clip to max decrement if necessary */
+ if ( ( (cache_ptr->resize_ctl).apply_max_decrement ) &&
+ ( ((cache_ptr->resize_ctl).max_decrement +
+ *new_max_cache_size_ptr) <
+ cache_ptr->max_cache_size ) ) {
+
+ *new_max_cache_size_ptr = cache_ptr->max_cache_size -
+ (cache_ptr->resize_ctl).max_decrement;
+ }
+ }
+ }
+ } else {
+
+ *status_ptr = at_min_size;
+ }
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__autoadjust__ageout() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout__cycle_epoch_marker
+ *
+ * Purpose: Remove the oldest epoch marker from the LRU list,
+ * and reinsert it at the head of the LRU list. Also
+ * remove the epoch marker's index from the head of the
+ * ring buffer, and re-insert it at the tail of the ring
+ * buffer.
+ *
+ * Return: SUCCEED on success/FAIL on failure.
+ *
+ * Programmer: John Mainzer, 11/22/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout__cycle_epoch_marker(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if(cache_ptr->epoch_markers_active <= 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "No active epoch markers on entry?!?!?")
+
+ /* remove the last marker from both the ring buffer and the LRU list */
+
+ i = cache_ptr->epoch_marker_ringbuf[cache_ptr->epoch_marker_ringbuf_first];
+
+ cache_ptr->epoch_marker_ringbuf_first =
+ (cache_ptr->epoch_marker_ringbuf_first + 1) %
+ (H5C__MAX_EPOCH_MARKERS + 1);
+
+ cache_ptr->epoch_marker_ringbuf_size -= 1;
+
+ if(cache_ptr->epoch_marker_ringbuf_size < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer underflow")
+ if((cache_ptr->epoch_marker_active)[i] != TRUE)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unused marker in LRU?!?")
+
+ H5C__DLL_REMOVE((&((cache_ptr->epoch_markers)[i])), \
+ (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (FAIL))
+
+ /* now, re-insert it at the head of the LRU list, and at the tail of
+ * the ring buffer.
+ */
+
+ HDassert(((cache_ptr->epoch_markers)[i]).addr == (haddr_t)i);
+ HDassert(((cache_ptr->epoch_markers)[i]).next == NULL);
+ HDassert(((cache_ptr->epoch_markers)[i]).prev == NULL);
+
+ cache_ptr->epoch_marker_ringbuf_last =
+ (cache_ptr->epoch_marker_ringbuf_last + 1) %
+ (H5C__MAX_EPOCH_MARKERS + 1);
+
+ (cache_ptr->epoch_marker_ringbuf)[cache_ptr->epoch_marker_ringbuf_last] = i;
+
+ cache_ptr->epoch_marker_ringbuf_size += 1;
+
+ if(cache_ptr->epoch_marker_ringbuf_size > H5C__MAX_EPOCH_MARKERS)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer overflow")
+
+ H5C__DLL_PREPEND((&((cache_ptr->epoch_markers)[i])), \
+ (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (FAIL))
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__autoadjust__ageout__cycle_epoch_marker() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout__evict_aged_out_entries
+ *
+ * Purpose: Evict clean entries in the cache that haven't
+ * been accessed for at least
+ * (cache_ptr->resize_ctl).epochs_before_eviction epochs,
+ * and flush dirty entries that haven't been accessed for
+ * that amount of time.
+ *
+ * Depending on configuration, the function will either
+ * flush or evict all such entries, or all such entries it
+ * encounters until it has freed the maximum amount of space
+ * allowed under the maximum decrement.
+ *
+ * If we are running in parallel mode, writes may not be
+ * permitted. If so, the function simply skips any dirty
+ * entries it may encounter.
+ *
+ * The function makes no attempt to maintain the minimum
+ * clean size, as there is no guarantee that the cache size
+ * will be changed.
+ *
+ * If there is no cache size change, the minimum clean size
+ * constraint will be met through a combination of clean
+ * entries and free space in the cache.
+ *
+ * If there is a cache size reduction, the minimum clean size
+ * will be re-calculated, and will be enforced the next time
+ * we have to make space in the cache.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used depending on the value of
+ * *first_flush_ptr. The idea is to use the primary_dxpl_id
+ * on the first write in a sequence of writes, and to use
+ * the secondary_dxpl_id on all subsequent writes.
+ *
+ * This is useful in the metadata cache, but may not be
+ * needed elsewhere. If so, just use the same dxpl_id for
+ * both parameters.
+ *
+ * Observe that this function cannot occasion a read.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 11/22/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f,
+ hid_t dxpl_id,
+ hbool_t write_permitted)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+ size_t eviction_size_limit;
+ size_t bytes_evicted = 0;
+ hbool_t prev_is_dirty = FALSE;
+ hbool_t restart_scan;
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * next_ptr;
+ H5C_cache_entry_t * prev_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( f );
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ /* if there is a limit on the amount that the cache size can be decrease
+ * in any one round of the cache size reduction algorithm, load that
+ * limit into eviction_size_limit. Otherwise, set eviction_size_limit
+ * to the equivalent of infinity. The current size of the index will
+ * do nicely.
+ */
+ if ( (cache_ptr->resize_ctl).apply_max_decrement ) {
+
+ eviction_size_limit = (cache_ptr->resize_ctl).max_decrement;
+
+ } else {
+
+ eviction_size_limit = cache_ptr->index_size; /* i.e. infinity */
+ }
+
+ if ( write_permitted ) {
+
+ restart_scan = FALSE;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+
+ while ( ( entry_ptr != NULL ) &&
+ ( (entry_ptr->type)->id != H5AC_EPOCH_MARKER_ID ) &&
+ ( bytes_evicted < eviction_size_limit ) )
+ {
+ hbool_t skipping_entry = FALSE;
+
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( (entry_ptr->ro_ref_count) == 0 );
+
+ next_ptr = entry_ptr->next;
+ prev_ptr = entry_ptr->prev;
+
+ if(prev_ptr != NULL)
+ prev_is_dirty = prev_ptr->is_dirty;
+
+ if(entry_ptr->is_dirty ) {
+ HDassert(!entry_ptr->prefetched_dirty);
+
+ /* dirty corked entry is skipped */
+ if(entry_ptr->tag_info && entry_ptr->tag_info->corked)
+ skipping_entry = TRUE;
+ else {
+ /* reset entries_removed_counter and
+ * last_entry_removed_ptr prior to the call to
+ * H5C__flush_single_entry() so that we can spot
+ * unexpected removals of entries from the cache,
+ * and set the restart_scan flag if proceeding
+ * would be likely to cause us to scan an entry
+ * that is no longer in the cache.
+ */
+ cache_ptr->entries_removed_counter = 0;
+ cache_ptr->last_entry_removed_ptr = NULL;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry")
+
+ if(cache_ptr->entries_removed_counter > 1 || cache_ptr->last_entry_removed_ptr == prev_ptr)
+ restart_scan = TRUE;
+ } /* end else */
+ } /* end if */
+ else if(!entry_ptr->prefetched_dirty) {
+
+ bytes_evicted += entry_ptr->size;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry")
+ } /* end else-if */
+ else {
+ HDassert(!entry_ptr->is_dirty);
+ HDassert(entry_ptr->prefetched_dirty);
+
+ skipping_entry = TRUE;
+ } /* end else */
+
+ if(prev_ptr != NULL) {
+ if(skipping_entry)
+ entry_ptr = prev_ptr;
+ else if(restart_scan || (prev_ptr->is_dirty != prev_is_dirty)
+ || (prev_ptr->next != next_ptr)
+ || (prev_ptr->is_protected)
+ || (prev_ptr->is_pinned)) {
+ /* Something has happened to the LRU -- start over
+ * from the tail.
+ */
+ restart_scan = FALSE;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+
+ H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr)
+ } /* end else-if */
+ else
+ entry_ptr = prev_ptr;
+ } /* end if */
+ else
+ entry_ptr = NULL;
+ } /* end while */
+
+ /* for now at least, don't bother to maintain the minimum clean size,
+ * as the cache should now be less than its maximum size. Due to
+ * the vaguries of the cache size reduction algorthim, we may not
+ * reduce the size of the cache.
+ *
+ * If we do, we will calculate a new minimum clean size, which will
+ * be enforced the next time we try to make space in the cache.
+ *
+ * If we don't, no action is necessary, as we have just evicted and/or
+ * or flushed a bunch of entries and therefore the sum of the clean
+ * and free space in the cache must be greater than or equal to the
+ * min clean space requirement (assuming that requirement was met on
+ * entry).
+ */
+
+ } /* end if */
+ else /* ! write_permitted */ {
+ /* Since we are not allowed to write, all we can do is evict
+ * any clean entries that we may encounter before we either
+ * hit the eviction size limit, or encounter the epoch marker.
+ *
+ * If we are operating read only, this isn't an issue, as there
+ * will not be any dirty entries.
+ *
+ * If we are operating in R/W mode, all the dirty entries we
+ * skip will be flushed the next time we attempt to make space
+ * when writes are permitted. This may have some local
+ * performance implications, but it shouldn't cause any net
+ * slowdown.
+ */
+ HDassert(H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS);
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+ while(entry_ptr != NULL &&
+ ((entry_ptr->type)->id != H5AC_EPOCH_MARKER_ID) &&
+ (bytes_evicted < eviction_size_limit)) {
+ HDassert(!(entry_ptr->is_protected));
+
+ prev_ptr = entry_ptr->prev;
+
+ if(!(entry_ptr->is_dirty) && !(entry_ptr->prefetched_dirty))
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush clean entry")
+
+ /* just skip the entry if it is dirty, as we can't do
+ * anything with it now since we can't write.
+ *
+ * Since all entries are clean, serialize() will not be called,
+ * and thus we needn't test to see if the LRU has been changed
+ * out from under us.
+ */
+ entry_ptr = prev_ptr;
+ } /* end while */
+ } /* end else */
+
+ if(cache_ptr->index_size < cache_ptr->max_cache_size)
+ cache_ptr->cache_full = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__autoadjust__ageout__evict_aged_out_entries() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout__insert_new_marker
+ *
+ * Purpose: Find an unused marker cache entry, mark it as used, and
+ * insert it at the head of the LRU list. Also add the
+ * marker's index in the epoch_markers array.
+ *
+ * Return: SUCCEED on success/FAIL on failure.
+ *
+ * Programmer: John Mainzer, 11/19/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout__insert_new_marker(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if(cache_ptr->epoch_markers_active >= (cache_ptr->resize_ctl).epochs_before_eviction)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Already have a full complement of markers")
+
+ /* find an unused marker */
+ i = 0;
+ while((cache_ptr->epoch_marker_active)[i] && i < H5C__MAX_EPOCH_MARKERS)
+ i++;
+
+ if(i >= H5C__MAX_EPOCH_MARKERS)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't find unused marker")
+
+ HDassert( ((cache_ptr->epoch_markers)[i]).addr == (haddr_t)i );
+ HDassert( ((cache_ptr->epoch_markers)[i]).next == NULL );
+ HDassert( ((cache_ptr->epoch_markers)[i]).prev == NULL );
+
+ (cache_ptr->epoch_marker_active)[i] = TRUE;
+
+ cache_ptr->epoch_marker_ringbuf_last =
+ (cache_ptr->epoch_marker_ringbuf_last + 1) %
+ (H5C__MAX_EPOCH_MARKERS + 1);
+
+ (cache_ptr->epoch_marker_ringbuf)[cache_ptr->epoch_marker_ringbuf_last] = i;
+
+ cache_ptr->epoch_marker_ringbuf_size += 1;
+
+ if ( cache_ptr->epoch_marker_ringbuf_size > H5C__MAX_EPOCH_MARKERS ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer overflow")
+ }
+
+ H5C__DLL_PREPEND((&((cache_ptr->epoch_markers)[i])), \
+ (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (FAIL))
+
+ cache_ptr->epoch_markers_active += 1;
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__autoadjust__ageout__insert_new_marker() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout__remove_all_markers
+ *
+ * Purpose: Remove all epoch markers from the LRU list and mark them
+ * as inactive.
+ *
+ * Return: SUCCEED on success/FAIL on failure.
+ *
+ * Programmer: John Mainzer, 11/22/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout__remove_all_markers(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+ int ring_buf_index;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ while ( cache_ptr->epoch_markers_active > 0 )
+ {
+ /* get the index of the last epoch marker in the LRU list
+ * and remove it from the ring buffer.
+ */
+
+ ring_buf_index = cache_ptr->epoch_marker_ringbuf_first;
+ i = (cache_ptr->epoch_marker_ringbuf)[ring_buf_index];
+
+ cache_ptr->epoch_marker_ringbuf_first =
+ (cache_ptr->epoch_marker_ringbuf_first + 1) %
+ (H5C__MAX_EPOCH_MARKERS + 1);
+
+ cache_ptr->epoch_marker_ringbuf_size -= 1;
+
+ if(cache_ptr->epoch_marker_ringbuf_size < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer underflow")
+
+ if((cache_ptr->epoch_marker_active)[i] != TRUE)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unused marker in LRU?!?")
+
+ /* remove the epoch marker from the LRU list */
+ H5C__DLL_REMOVE((&((cache_ptr->epoch_markers)[i])), \
+ (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (FAIL))
+
+ /* mark the epoch marker as unused. */
+ (cache_ptr->epoch_marker_active)[i] = FALSE;
+
+ HDassert( ((cache_ptr->epoch_markers)[i]).addr == (haddr_t)i );
+ HDassert( ((cache_ptr->epoch_markers)[i]).next == NULL );
+ HDassert( ((cache_ptr->epoch_markers)[i]).prev == NULL );
+
+ /* decrement the number of active epoch markers */
+ cache_ptr->epoch_markers_active -= 1;
+
+ HDassert( cache_ptr->epoch_markers_active == \
+ cache_ptr->epoch_marker_ringbuf_size );
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__autoadjust__ageout__remove_all_markers() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__autoadjust__ageout__remove_excess_markers
+ *
+ * Purpose: Remove epoch markers from the end of the LRU list and
+ * mark them as inactive until the number of active markers
+ * equals the the current value of
+ * (cache_ptr->resize_ctl).epochs_before_eviction.
+ *
+ * Return: SUCCEED on success/FAIL on failure.
+ *
+ * Programmer: John Mainzer, 11/19/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__autoadjust__ageout__remove_excess_markers(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+ int ring_buf_index;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if(cache_ptr->epoch_markers_active <= (cache_ptr->resize_ctl).epochs_before_eviction)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "no excess markers on entry")
+
+ while(cache_ptr->epoch_markers_active > (cache_ptr->resize_ctl).epochs_before_eviction) {
+ /* get the index of the last epoch marker in the LRU list
+ * and remove it from the ring buffer.
+ */
+
+ ring_buf_index = cache_ptr->epoch_marker_ringbuf_first;
+ i = (cache_ptr->epoch_marker_ringbuf)[ring_buf_index];
+
+ cache_ptr->epoch_marker_ringbuf_first =
+ (cache_ptr->epoch_marker_ringbuf_first + 1) %
+ (H5C__MAX_EPOCH_MARKERS + 1);
+
+ cache_ptr->epoch_marker_ringbuf_size -= 1;
+
+ if(cache_ptr->epoch_marker_ringbuf_size < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer underflow")
+ if((cache_ptr->epoch_marker_active)[i] != TRUE)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unused marker in LRU?!?")
+
+ /* remove the epoch marker from the LRU list */
+ H5C__DLL_REMOVE((&((cache_ptr->epoch_markers)[i])), \
+ (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (FAIL))
+
+ /* mark the epoch marker as unused. */
+ (cache_ptr->epoch_marker_active)[i] = FALSE;
+
+ HDassert( ((cache_ptr->epoch_markers)[i]).addr == (haddr_t)i );
+ HDassert( ((cache_ptr->epoch_markers)[i]).next == NULL );
+ HDassert( ((cache_ptr->epoch_markers)[i]).prev == NULL );
+
+ /* decrement the number of active epoch markers */
+ cache_ptr->epoch_markers_active -= 1;
+
+ HDassert( cache_ptr->epoch_markers_active == \
+ cache_ptr->epoch_marker_ringbuf_size );
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__autoadjust__ageout__remove_excess_markers() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__flash_increase_cache_size
+ *
+ * Purpose: If there is not at least new_entry_size - old_entry_size
+ * bytes of free space in the cache and the current
+ * max_cache_size is less than (cache_ptr->resize_ctl).max_size,
+ * perform a flash increase in the cache size and then reset
+ * the full cache hit rate statistics, and exit.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 12/31/07
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__flash_increase_cache_size(H5C_t * cache_ptr,
+ size_t old_entry_size,
+ size_t new_entry_size)
+{
+ size_t new_max_cache_size = 0;
+ size_t old_max_cache_size = 0;
+ size_t new_min_clean_size = 0;
+ size_t old_min_clean_size = 0;
+ size_t space_needed;
+ enum H5C_resize_status status = flash_increase; /* may change */
+ double hit_rate;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->flash_size_increase_possible );
+ HDassert( new_entry_size > cache_ptr->flash_size_increase_threshold );
+ HDassert( old_entry_size < new_entry_size );
+
+ if(old_entry_size >= new_entry_size)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "old_entry_size >= new_entry_size")
+
+ space_needed = new_entry_size - old_entry_size;
+
+ if ( ( (cache_ptr->index_size + space_needed) >
+ cache_ptr->max_cache_size ) &&
+ ( cache_ptr->max_cache_size < (cache_ptr->resize_ctl).max_size ) ) {
+
+ /* we have work to do */
+
+ switch ( (cache_ptr->resize_ctl).flash_incr_mode )
+ {
+ case H5C_flash_incr__off:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flash_size_increase_possible but H5C_flash_incr__off?!")
+ break;
+
+ case H5C_flash_incr__add_space:
+ if ( cache_ptr->index_size < cache_ptr->max_cache_size ) {
+
+ HDassert( (cache_ptr->max_cache_size - cache_ptr->index_size)
+ < space_needed );
+ space_needed -= cache_ptr->max_cache_size -
+ cache_ptr->index_size;
+ }
+ space_needed =
+ (size_t)(((double)space_needed) *
+ (cache_ptr->resize_ctl).flash_multiple);
+
+ new_max_cache_size = cache_ptr->max_cache_size + space_needed;
+
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?")
+ break;
+ }
+
+ if ( new_max_cache_size > (cache_ptr->resize_ctl).max_size ) {
+
+ new_max_cache_size = (cache_ptr->resize_ctl).max_size;
+ }
+
+ HDassert( new_max_cache_size > cache_ptr->max_cache_size );
+
+ new_min_clean_size = (size_t)
+ ((double)new_max_cache_size *
+ ((cache_ptr->resize_ctl).min_clean_fraction));
+
+ HDassert( new_min_clean_size <= new_max_cache_size );
+
+ old_max_cache_size = cache_ptr->max_cache_size;
+ old_min_clean_size = cache_ptr->min_clean_size;
+
+ cache_ptr->max_cache_size = new_max_cache_size;
+ cache_ptr->min_clean_size = new_min_clean_size;
+
+ /* update flash cache size increase fields as appropriate */
+ HDassert ( cache_ptr->flash_size_increase_possible );
+
+ switch ( (cache_ptr->resize_ctl).flash_incr_mode )
+ {
+ case H5C_flash_incr__off:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flash_size_increase_possible but H5C_flash_incr__off?!")
+ break;
+
+ case H5C_flash_incr__add_space:
+ cache_ptr->flash_size_increase_threshold =
+ (size_t)
+ (((double)(cache_ptr->max_cache_size)) *
+ ((cache_ptr->resize_ctl).flash_threshold));
+ break;
+
+ default: /* should be unreachable */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?")
+ break;
+ }
+
+ /* note that we don't cycle the epoch markers. We can
+ * argue either way as to whether we should, but for now
+ * we don't.
+ */
+
+ if ( (cache_ptr->resize_ctl).rpt_fcn != NULL ) {
+
+ /* get the hit rate for the reporting function. Should still
+ * be good as we havent reset the hit rate statistics.
+ */
+ if(H5C_get_cache_hit_rate(cache_ptr, &hit_rate) != SUCCEED)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get hit rate")
+
+ (*((cache_ptr->resize_ctl).rpt_fcn))
+ (cache_ptr,
+ H5C__CURR_AUTO_RESIZE_RPT_FCN_VER,
+ hit_rate,
+ status,
+ old_max_cache_size,
+ new_max_cache_size,
+ old_min_clean_size,
+ new_min_clean_size);
+ }
+
+ if(H5C_reset_cache_hit_rate_stats(cache_ptr) < 0)
+ /* this should be impossible... */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed")
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__flash_increase_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_invalidate_cache
+ *
+ * Purpose: Flush and destroy the entries contained in the target
+ * cache.
+ *
+ * If the cache contains protected entries, the function will
+ * fail, as protected entries cannot be either flushed or
+ * destroyed. However all unprotected entries should be
+ * flushed and destroyed before the function returns failure.
+ *
+ * While pinned entries can usually be flushed, they cannot
+ * be destroyed. However, they should be unpinned when all
+ * the entries that reference them have been destroyed (thus
+ * reduding the pinned entry's reference count to 0, allowing
+ * it to be unpinned).
+ *
+ * If pinned entries are present, the function makes repeated
+ * passes through the cache, flushing all dirty entries
+ * (including the pinned dirty entries where permitted) and
+ * destroying all unpinned entries. This process is repeated
+ * until either the cache is empty, or the number of pinned
+ * entries stops decreasing on each pass.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the flush (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id).
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 3/24/065
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C_flush_invalidate_cache(H5F_t *f, hid_t dxpl_id, unsigned flags)
+{
+ H5C_t * cache_ptr;
+ H5C_ring_t ring;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+
+#if H5C_DO_SANITY_CHECKS
+{
+ int32_t i;
+ uint32_t index_len = 0;
+ uint32_t slist_len = 0;
+ size_t index_size = (size_t)0;
+ size_t clean_index_size = (size_t)0;
+ size_t dirty_index_size = (size_t)0;
+ size_t slist_size = (size_t)0;
+
+ HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+
+ for(i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) {
+ index_len += cache_ptr->index_ring_len[i];
+ index_size += cache_ptr->index_ring_size[i];
+ clean_index_size += cache_ptr->clean_index_ring_size[i];
+ dirty_index_size += cache_ptr->dirty_index_ring_size[i];
+
+ slist_len += cache_ptr->slist_ring_len[i];
+ slist_size += cache_ptr->slist_ring_size[i];
+ } /* end for */
+
+ HDassert(cache_ptr->index_len == index_len);
+ HDassert(cache_ptr->index_size == index_size);
+ HDassert(cache_ptr->clean_index_size == clean_index_size);
+ HDassert(cache_ptr->dirty_index_size == dirty_index_size);
+ HDassert(cache_ptr->slist_len == slist_len);
+ HDassert(cache_ptr->slist_size == slist_size);
+}
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* remove ageout markers if present */
+ if(cache_ptr->epoch_markers_active > 0)
+ if(H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error removing all epoch markers")
+
+ /* flush invalidate each ring, starting from the outermost ring and
+ * working inward.
+ */
+ ring = H5C_RING_USER;
+ while(ring < H5C_RING_NTYPES) {
+ if(H5C_flush_invalidate_ring(f, dxpl_id, ring, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate ring failed")
+ ring++;
+ } /* end while */
+
+ /* Invariants, after destroying all entries in the hash table */
+ if(!(flags & H5C__EVICT_ALLOW_LAST_PINS_FLAG)) {
+ HDassert(cache_ptr->index_size == 0);
+ HDassert(cache_ptr->clean_index_size == 0);
+ HDassert(cache_ptr->pel_len == 0);
+ HDassert(cache_ptr->pel_size == 0);
+ } /* end if */
+ else {
+ H5C_cache_entry_t *entry_ptr; /* Cache entry */
+ unsigned u; /* Local index variable */
+
+ /* All rings except ring 4 should be empty now */
+ /* (Ring 4 has the superblock) */
+ for(u = H5C_RING_USER; u < H5C_RING_SB; u++) {
+ HDassert(cache_ptr->index_ring_len[u] == 0);
+ HDassert(cache_ptr->index_ring_size[u] == 0);
+ HDassert(cache_ptr->clean_index_ring_size[u] == 0);
+ } /* end for */
+
+ /* Check that any remaining pinned entries are in the superblock ring */
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while(entry_ptr) {
+ /* Check ring */
+ HDassert(entry_ptr->ring == H5C_RING_SB);
+
+ /* Advance to next entry in pinned entry list */
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+ } /* end else */
+ HDassert(cache_ptr->dirty_index_size == 0);
+ HDassert(cache_ptr->slist_len == 0);
+ HDassert(cache_ptr->slist_size == 0);
+ HDassert(cache_ptr->pl_len == 0);
+ HDassert(cache_ptr->pl_size == 0);
+ HDassert(cache_ptr->LRU_list_len == 0);
+ HDassert(cache_ptr->LRU_list_size == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_invalidate_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_invalidate_ring
+ *
+ * Purpose: Flush and destroy the entries contained in the target
+ * cache and ring.
+ *
+ * If the ring contains protected entries, the function will
+ * fail, as protected entries cannot be either flushed or
+ * destroyed. However all unprotected entries should be
+ * flushed and destroyed before the function returns failure.
+ *
+ * While pinned entries can usually be flushed, they cannot
+ * be destroyed. However, they should be unpinned when all
+ * the entries that reference them have been destroyed (thus
+ * reduding the pinned entry's reference count to 0, allowing
+ * it to be unpinned).
+ *
+ * If pinned entries are present, the function makes repeated
+ * passes through the cache, flushing all dirty entries
+ * (including the pinned dirty entries where permitted) and
+ * destroying all unpinned entries. This process is repeated
+ * until either the cache is empty, or the number of pinned
+ * entries stops decreasing on each pass.
+ *
+ * If flush dependencies appear in the target ring, the
+ * function makes repeated passes through the cache flushing
+ * entries in flush dependency order.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 9/1/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C_flush_invalidate_ring(H5F_t * f, hid_t dxpl_id, H5C_ring_t ring,
+ unsigned flags)
+{
+ H5C_t *cache_ptr;
+ hbool_t restart_slist_scan;
+ uint32_t protected_entries = 0;
+ int32_t i;
+ int32_t cur_ring_pel_len;
+ int32_t old_ring_pel_len;
+ unsigned cooked_flags;
+ unsigned evict_flags;
+ H5SL_node_t *node_ptr = NULL;
+ H5C_cache_entry_t *entry_ptr = NULL;
+ H5C_cache_entry_t *next_entry_ptr = NULL;
+#if H5C_DO_SANITY_CHECKS
+ uint32_t initial_slist_len = 0;
+ size_t initial_slist_size = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+ HDassert(ring > H5C_RING_UNDEFINED);
+ HDassert(ring < H5C_RING_NTYPES);
+
+ HDassert(cache_ptr->epoch_markers_active == 0);
+
+ /* Filter out the flags that are not relevant to the flush/invalidate.
+ */
+ cooked_flags = flags & H5C__FLUSH_CLEAR_ONLY_FLAG;
+ evict_flags = flags & H5C__EVICT_ALLOW_LAST_PINS_FLAG;
+
+ /* The flush proceedure here is a bit strange.
+ *
+ * In the outer while loop we make at least one pass through the
+ * cache, and then repeat until either all the pinned entries in
+ * the ring unpin themselves, or until the number of pinned entries
+ * in the ring stops declining. In this later case, we scream and die.
+ *
+ * Since the fractal heap can dirty, resize, and/or move entries
+ * in is flush callback, it is possible that the cache will still
+ * contain dirty entries at this point. If so, we must make more
+ * passes through the skip list to allow it to empty.
+ *
+ * Further, since clean entries can be dirtied, resized, and/or moved
+ * as the result of a flush call back (either the entries own, or that
+ * for some other cache entry), we can no longer promise to flush
+ * the cache entries in increasing address order.
+ *
+ * Instead, we just do the best we can -- making a pass through
+ * the skip list, and then a pass through the "clean" entries, and
+ * then repeating as needed. Thus it is quite possible that an
+ * entry will be evicted from the cache only to be re-loaded later
+ * in the flush process (From what Quincey tells me, the pin
+ * mechanism makes this impossible, but even it it is true now,
+ * we shouldn't count on it in the future.)
+ *
+ * The bottom line is that entries will probably be flushed in close
+ * to increasing address order, but there are no guarantees.
+ */
+
+ /* compute the number of pinned entries in this ring */
+ entry_ptr = cache_ptr->pel_head_ptr;
+ cur_ring_pel_len = 0;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring >= ring);
+ if(entry_ptr->ring == ring)
+ cur_ring_pel_len++;
+
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+
+ old_ring_pel_len = cur_ring_pel_len;
+ while(cache_ptr->index_ring_len[ring] > 0) {
+ /* first, try to flush-destroy any dirty entries. Do this by
+ * making a scan through the slist. Note that new dirty entries
+ * may be created by the flush call backs. Thus it is possible
+ * that the slist will not be empty after we finish the scan.
+ */
+
+#if H5C_DO_SANITY_CHECKS
+ /* Depending on circumstances, H5C__flush_single_entry() will
+ * remove dirty entries from the slist as it flushes them.
+ * Thus for sanity checks we must make note of the initial
+ * slist length and size before we do any flushes.
+ */
+ initial_slist_len = cache_ptr->slist_len;
+ initial_slist_size = cache_ptr->slist_size;
+
+ /* There is also the possibility that entries will be
+ * dirtied, resized, moved, and/or removed from the cache
+ * as the result of calls to the flush callbacks. We use
+ * the slist_len_increase and slist_size_increase increase
+ * fields in struct H5C_t to track these changes for purpose
+ * of sanity checking.
+ *
+ * To this end, we must zero these fields before we start
+ * the pass through the slist.
+ */
+ cache_ptr->slist_len_increase = 0;
+ cache_ptr->slist_size_increase = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* Set the cache_ptr->slist_changed to false.
+ *
+ * This flag is set to TRUE by H5C__flush_single_entry if the slist
+ * is modified by a pre_serialize, serialize, or notify callback.
+ *
+ * H5C_flush_invalidate_ring() uses this flag to detect any
+ * modifications to the slist that might corrupt the scan of
+ * the slist -- and restart the scan in this event.
+ */
+ cache_ptr->slist_changed = FALSE;
+
+ /* this done, start the scan of the slist */
+ restart_slist_scan = TRUE;
+ while(restart_slist_scan || (node_ptr != NULL)) {
+ if(restart_slist_scan) {
+ restart_slist_scan = FALSE;
+
+ /* Start at beginning of skip list */
+ node_ptr = H5SL_first(cache_ptr->slist_ptr);
+ if(node_ptr == NULL)
+ /* the slist is empty -- break out of inner loop */
+ break;
+
+ /* Get cache entry for this node */
+ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+ if(NULL == next_entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
+
+ HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(next_entry_ptr->is_dirty);
+ HDassert(next_entry_ptr->in_slist);
+ HDassert(next_entry_ptr->ring >= ring);
+ } /* end if */
+
+ entry_ptr = next_entry_ptr;
+
+ /* It is possible that entries will be dirtied, resized,
+ * flushed, or removed from the cache via the take ownership
+ * flag as the result of pre_serialize or serialized callbacks.
+ *
+ * This in turn can corrupt the scan through the slist.
+ *
+ * We test for slist modifications in the pre_serialize
+ * and serialize callbacks, and restart the scan of the
+ * slist if we find them. However, best we do some extra
+ * sanity checking just in case.
+ */
+ HDassert(entry_ptr != NULL);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->in_slist);
+ HDassert(entry_ptr->is_dirty);
+ HDassert(entry_ptr->ring >= ring);
+
+ /* increment node pointer now, before we delete its target
+ * from the slist.
+ */
+ node_ptr = H5SL_next(node_ptr);
+ if(node_ptr != NULL) {
+ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+ if(NULL == next_entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
+ HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(next_entry_ptr->is_dirty);
+ HDassert(next_entry_ptr->in_slist);
+ HDassert(next_entry_ptr->ring >= ring);
+ HDassert(entry_ptr != next_entry_ptr);
+ } /* end if */
+ else
+ next_entry_ptr = NULL;
+
+ /* Note that we now remove nodes from the slist as we flush
+ * the associated entries, instead of leaving them there
+ * until we are done, and then destroying all nodes in
+ * the slist.
+ *
+ * While this optimization used to be easy, with the possibility
+ * of new entries being added to the slist in the midst of the
+ * flush, we must keep the slist in cannonical form at all
+ * times.
+ */
+ if(((!entry_ptr->flush_me_last) ||
+ ((entry_ptr->flush_me_last) &&
+ (cache_ptr->num_last_entries >= cache_ptr->slist_len))) &&
+ (entry_ptr->flush_dep_nchildren == 0) &&
+ (entry_ptr->ring == ring)) {
+ if(entry_ptr->is_protected) {
+ /* we have major problems -- but lets flush
+ * everything we can before we flag an error.
+ */
+ protected_entries++;
+ } /* end if */
+ else if(entry_ptr->is_pinned) {
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__DURING_FLUSH_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty pinned entry flush failed")
+
+ if(cache_ptr->slist_changed) {
+ /* The slist has been modified by something
+ * other than the simple removal of the
+ * of the flushed entry after the flush.
+ *
+ * This has the potential to corrupt the
+ * scan through the slist, so restart it.
+ */
+ restart_slist_scan = TRUE;
+ cache_ptr->slist_changed = FALSE;
+ H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr);
+ } /* end if */
+ } /* end else-if */
+ else {
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry flush destroy failed")
+
+ if(cache_ptr->slist_changed) {
+ /* The slist has been modified by something
+ * other than the simple removal of the
+ * of the flushed entry after the flush.
+ *
+ * This has the potential to corrupt the
+ * scan through the slist, so restart it.
+ */
+ restart_slist_scan = TRUE;
+ cache_ptr->slist_changed = FALSE;
+ H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr)
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ } /* end while loop scanning skip list */
+
+#if H5C_DO_SANITY_CHECKS
+ /* It is possible that entries were added to the slist during
+ * the scan, either before or after scan pointer. The following
+ * asserts take this into account.
+ *
+ * Don't bother with the sanity checks if node_ptr != NULL, as
+ * in this case we broke out of the loop because it got changed
+ * out from under us.
+ */
+
+ if(node_ptr == NULL) {
+ HDassert(cache_ptr->slist_len == (uint32_t)((int32_t)initial_slist_len + cache_ptr->slist_len_increase));
+ HDassert(cache_ptr->slist_size == (size_t)((ssize_t)initial_slist_size + cache_ptr->slist_size_increase));
+ } /* end if */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* Since we are doing a destroy, we must make a pass through
+ * the hash table and try to flush - destroy all entries that
+ * remain.
+ *
+ * It used to be that all entries remaining in the cache at
+ * this point had to be clean, but with the fractal heap mods
+ * this may not be the case. If so, we will flush entries out
+ * in increasing address order.
+ *
+ * Writes to disk are possible here.
+ */
+
+ /* reset the counters so that we can detect insertions, loads,
+ * and moves caused by the pre_serialize and serialize calls.
+ */
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ next_entry_ptr = cache_ptr->il_head;
+ while(next_entry_ptr != NULL) {
+ entry_ptr = next_entry_ptr;
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring >= ring);
+
+ next_entry_ptr = entry_ptr->il_next;
+ HDassert((next_entry_ptr == NULL) ||
+ (next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC));
+
+ if((!entry_ptr->flush_me_last || (entry_ptr->flush_me_last && cache_ptr->num_last_entries >= cache_ptr->slist_len))
+ && entry_ptr->flush_dep_nchildren == 0 && entry_ptr->ring == ring) {
+ if(entry_ptr->is_protected) {
+ /* we have major problems -- but lets flush and
+ * destroy everything we can before we flag an
+ * error.
+ */
+ protected_entries++;
+ if(!entry_ptr->in_slist)
+ HDassert(!(entry_ptr->is_dirty));
+ } /* end if */
+ else if(!(entry_ptr->is_pinned)) {
+ /* if *entry_ptr is dirty, it is possible
+ * that one or more other entries may be
+ * either removed from the cache, loaded
+ * into the cache, or moved to a new location
+ * in the file as a side effect of the flush.
+ *
+ * It's also possible that removing a clean
+ * entry will remove the last child of a proxy
+ * entry, allowing it to be removed also and
+ * invalidating the next_entry_ptr.
+ *
+ * If either of these happen, and one of the target
+ * or proxy entries happens to be the next entry in
+ * the hash bucket, we could either find ourselves
+ * either scanning a non-existant entry, scanning
+ * through a different bucket, or skipping an entry.
+ *
+ * Neither of these are good, so restart the
+ * the scan at the head of the hash bucket
+ * after the flush if we detect that the next_entry_ptr
+ * becomes invalid.
+ *
+ * This is not as inefficient at it might seem,
+ * as hash buckets typically have at most two
+ * or three entries.
+ */
+ cache_ptr->entry_watched_for_removal = next_entry_ptr;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Entry flush destroy failed")
+
+ /* Restart the index list scan if necessary. Must
+ * do this if the next entry is evicted, and also if
+ * one or more entries are inserted, loaded, or moved
+ * as these operations can result in part of the scan
+ * being skipped -- which can cause a spurious failure
+ * if this results in the size of the pinned entry
+ * failing to decline during the pass.
+ */
+ if((NULL != next_entry_ptr && NULL == cache_ptr->entry_watched_for_removal)
+ || (cache_ptr->entries_loaded_counter > 0)
+ || (cache_ptr->entries_inserted_counter > 0)
+ || (cache_ptr->entries_relocated_counter > 0)) {
+
+ next_entry_ptr = cache_ptr->il_head;
+
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr)
+ } /* end if */
+ else
+ cache_ptr->entry_watched_for_removal = NULL;
+ } /* end if */
+ } /* end if */
+ } /* end for loop scanning hash table */
+
+ /* We can't do anything if entries are pinned. The
+ * hope is that the entries will be unpinned as the
+ * result of destroys of entries that reference them.
+ *
+ * We detect this by noting the change in the number
+ * of pinned entries from pass to pass. If it stops
+ * shrinking before it hits zero, we scream and die.
+ */
+ old_ring_pel_len = cur_ring_pel_len;
+ entry_ptr = cache_ptr->pel_head_ptr;
+ cur_ring_pel_len = 0;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring >= ring);
+
+ if(entry_ptr->ring == ring)
+ cur_ring_pel_len++;
+
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+
+ /* Check if the number of pinned entries in the ring is positive, and
+ * it is not declining. Scream and die if so.
+ */
+ if(cur_ring_pel_len > 0 && cur_ring_pel_len >= old_ring_pel_len) {
+ /* Don't error if allowed to have pinned entries remaining */
+ if(evict_flags)
+ HGOTO_DONE(TRUE)
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entry count not decreasing, cur_ring_pel_len = %d, old_ring_pel_len = %d, ring = %d", (int)cur_ring_pel_len, (int)old_ring_pel_len, (int)ring)
+ } /* end if */
+
+ HDassert(protected_entries == cache_ptr->pl_len);
+
+ if(protected_entries > 0 && protected_entries == cache_ptr->index_len)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Only protected entries left in cache, protected_entries = %d", (int)protected_entries)
+ } /* main while loop */
+
+ /* Invariants, after destroying all entries in the ring */
+ for(i = (int)H5C_RING_UNDEFINED; i <= (int)ring; i++) {
+ HDassert(cache_ptr->index_ring_len[i] == 0);
+ HDassert(cache_ptr->index_ring_size[i] == (size_t)0);
+ HDassert(cache_ptr->clean_index_ring_size[i] == (size_t)0);
+ HDassert(cache_ptr->dirty_index_ring_size[i] == (size_t)0);
+
+ HDassert(cache_ptr->slist_ring_len[i] == 0);
+ HDassert(cache_ptr->slist_ring_size[i] == (size_t)0);
+ } /* end for */
+
+ HDassert(protected_entries <= cache_ptr->pl_len);
+
+ if(protected_entries > 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cache has protected entries")
+ else if(cur_ring_pel_len > 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't unpin all pinned entries in ring")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_invalidate_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_ring
+ *
+ * Purpose: Flush the entries contained in the specified cache and
+ * ring. All entries in rings outside the specified ring
+ * must have been flushed on entry.
+ *
+ * If the cache contains protected entries in the specified
+ * ring, the function will fail, as protected entries cannot
+ * be flushed. However all unprotected entries in the target
+ * ring should be flushed before the function returns failure.
+ *
+ * If flush dependencies appear in the target ring, the
+ * function makes repeated passes through the slist flushing
+ * entries in flush dependency order.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 9/1/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_flush_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring, unsigned flags)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+ hbool_t flushed_entries_last_pass;
+ hbool_t flush_marked_entries;
+ hbool_t ignore_protected;
+ hbool_t tried_to_flush_protected_entry = FALSE;
+ hbool_t restart_slist_scan;
+ uint32_t protected_entries = 0;
+ H5SL_node_t * node_ptr = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5C_cache_entry_t * next_entry_ptr = NULL;
+#if H5C_DO_SANITY_CHECKS
+ uint32_t initial_slist_len = 0;
+ size_t initial_slist_size = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+ int i;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+ HDassert((flags & H5C__FLUSH_INVALIDATE_FLAG) == 0);
+ HDassert(ring > H5C_RING_UNDEFINED);
+ HDassert(ring < H5C_RING_NTYPES);
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ ignore_protected = ( (flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0 );
+ flush_marked_entries = ( (flags & H5C__FLUSH_MARKED_ENTRIES_FLAG) != 0 );
+
+ if(!flush_marked_entries)
+ for(i = (int)H5C_RING_UNDEFINED; i < (int)ring; i++)
+ HDassert(cache_ptr->slist_ring_len[i] == 0);
+
+ HDassert(cache_ptr->flush_in_progress);
+
+ /* When we are only flushing marked entries, the slist will usually
+ * still contain entries when we have flushed everything we should.
+ * Thus we track whether we have flushed any entries in the last
+ * pass, and terminate if we haven't.
+ */
+ flushed_entries_last_pass = TRUE;
+
+ /* Set the cache_ptr->slist_changed to false.
+ *
+ * This flag is set to TRUE by H5C__flush_single_entry if the
+ * slist is modified by a pre_serialize, serialize, or notify callback.
+ * H5C_flush_cache uses this flag to detect any modifications
+ * to the slist that might corrupt the scan of the slist -- and
+ * restart the scan in this event.
+ */
+ cache_ptr->slist_changed = FALSE;
+
+ while((cache_ptr->slist_ring_len[ring] > 0) &&
+ (protected_entries == 0) &&
+ (flushed_entries_last_pass)) {
+ flushed_entries_last_pass = FALSE;
+
+#if H5C_DO_SANITY_CHECKS
+ /* For sanity checking, try to verify that the skip list has
+ * the expected size and number of entries at the end of each
+ * internal while loop (see below).
+ *
+ * Doing this get a bit tricky, as depending on flags, we may
+ * or may not flush all the entries in the slist.
+ *
+ * To make things more entertaining, with the advent of the
+ * fractal heap, the entry serialize callback can cause entries
+ * to be dirtied, resized, and/or moved. Also, the
+ * pre_serialize callback can result in an entry being
+ * removed from the cache via the take ownership flag.
+ *
+ * To deal with this, we first make note of the initial
+ * skip list length and size:
+ */
+ initial_slist_len = cache_ptr->slist_len;
+ initial_slist_size = cache_ptr->slist_size;
+
+ /* As mentioned above, there is the possibility that
+ * entries will be dirtied, resized, flushed, or removed
+ * from the cache via the take ownership flag during
+ * our pass through the skip list. To capture the number
+ * of entries added, and the skip list size delta,
+ * zero the slist_len_increase and slist_size_increase of
+ * the cache's instance of H5C_t. These fields will be
+ * updated elsewhere to account for slist insertions and/or
+ * dirty entry size changes.
+ */
+ cache_ptr->slist_len_increase = 0;
+ cache_ptr->slist_size_increase = 0;
+
+ /* at the end of the loop, use these values to compute the
+ * expected slist length and size and compare this with the
+ * value recorded in the cache's instance of H5C_t.
+ */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ restart_slist_scan = TRUE;
+
+ while((restart_slist_scan ) || (node_ptr != NULL)) {
+ if(restart_slist_scan) {
+ restart_slist_scan = FALSE;
+
+ /* Start at beginning of skip list */
+ node_ptr = H5SL_first(cache_ptr->slist_ptr);
+
+ if(node_ptr == NULL)
+ /* the slist is empty -- break out of inner loop */
+ break;
+
+ /* Get cache entry for this node */
+ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+
+ if(NULL == next_entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
+
+ HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(next_entry_ptr->is_dirty);
+ HDassert(next_entry_ptr->in_slist);
+ } /* end if */
+
+ entry_ptr = next_entry_ptr;
+
+ /* With the advent of the fractal heap, the free space
+ * manager, and the version 3 cache, it is possible
+ * that the pre-serialize or serialize callback will
+ * dirty, resize, or take ownership of other entries
+ * in the cache.
+ *
+ * To deal with this, I have inserted code to detect any
+ * change in the skip list not directly under the control
+ * of this function. If such modifications are detected,
+ * we must re-start the scan of the skip list to avoid
+ * the possibility that the target of the next_entry_ptr
+ * may have been flushed or deleted from the cache.
+ *
+ * To verify that all such possibilities have been dealt
+ * with, we do a bit of extra sanity checking on
+ * entry_ptr.
+ */
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->in_slist);
+ HDassert(entry_ptr->is_dirty);
+ if(!flush_marked_entries || entry_ptr->flush_marker)
+ HDassert(entry_ptr->ring >= ring);
+
+ /* Advance node pointer now, before we delete its target
+ * from the slist.
+ */
+ node_ptr = H5SL_next(node_ptr);
+ if(node_ptr != NULL) {
+ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+ if(NULL == next_entry_ptr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
+
+ HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(next_entry_ptr->is_dirty);
+ HDassert(next_entry_ptr->in_slist);
+
+ if(!flush_marked_entries || next_entry_ptr->flush_marker)
+ HDassert(next_entry_ptr->ring >= ring);
+
+ HDassert(entry_ptr != next_entry_ptr);
+ } /* end if */
+ else
+ next_entry_ptr = NULL;
+
+ if((!flush_marked_entries || entry_ptr->flush_marker)
+ && (!entry_ptr->flush_me_last ||
+ (entry_ptr->flush_me_last
+ && (cache_ptr->num_last_entries >= cache_ptr->slist_len
+ || (flush_marked_entries && entry_ptr->flush_marker))))
+ && (entry_ptr->flush_dep_nchildren == 0
+ || entry_ptr->flush_dep_ndirty_children == 0)
+ && entry_ptr->ring == ring) {
+
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+
+ if(entry_ptr->is_protected) {
+ /* we probably have major problems -- but lets
+ * flush everything we can before we decide
+ * whether to flag an error.
+ */
+ tried_to_flush_protected_entry = TRUE;
+ protected_entries++;
+ } /* end if */
+ else {
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, (flags | H5C__DURING_FLUSH_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush entry")
+
+ if(cache_ptr->slist_changed) {
+ /* The slist has been modified by something
+ * other than the simple removal of the
+ * of the flushed entry after the flush.
+ *
+ * This has the potential to corrupt the
+ * scan through the slist, so restart it.
+ */
+ restart_slist_scan = TRUE;
+ cache_ptr->slist_changed = FALSE;
+ H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr)
+ } /* end if */
+
+ flushed_entries_last_pass = TRUE;
+ } /* end else */
+ } /* end if */
+ } /* while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) */
+
+#if H5C_DO_SANITY_CHECKS
+ /* Verify that the slist size and length are as expected. */
+ HDassert((uint32_t)((int32_t)initial_slist_len + cache_ptr->slist_len_increase) == cache_ptr->slist_len);
+ HDassert((size_t)((ssize_t)initial_slist_size + cache_ptr->slist_size_increase) == cache_ptr->slist_size);
+#endif /* H5C_DO_SANITY_CHECKS */
+ } /* while */
+
+ HDassert(protected_entries <= cache_ptr->pl_len);
+
+ if(((cache_ptr->pl_len > 0) && (!ignore_protected)) || (tried_to_flush_protected_entry))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "cache has protected items")
+
+#if H5C_DO_SANITY_CHECKS
+ if(!flush_marked_entries) {
+ HDassert(cache_ptr->slist_ring_len[ring] == 0);
+ HDassert(cache_ptr->slist_ring_size[ring] == 0);
+ } /* end if */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_ring() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__flush_single_entry
+ *
+ * Purpose: Flush or clear (and evict if requested) the cache entry
+ * with the specified address and type. If the type is NULL,
+ * any unprotected entry at the specified address will be
+ * flushed (and possibly evicted).
+ *
+ * Attempts to flush a protected entry will result in an
+ * error.
+ *
+ * If the H5C__FLUSH_INVALIDATE_FLAG flag is set, the entry will
+ * be cleared and not flushed, and the call can't be part of a
+ * sequence of flushes.
+ *
+ * If the caller knows the address of the skip list node at
+ * which the target entry resides, it can avoid a lookup
+ * by supplying that address in the tgt_node_ptr parameter.
+ * If this parameter is NULL, the function will do a skip list
+ * search for the entry instead.
+ *
+ * The function does nothing silently if there is no entry
+ * at the supplied address, or if the entry found has the
+ * wrong type.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * an attempt to flush a protected item.
+ *
+ * Programmer: John Mainzer, 5/5/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__flush_single_entry(H5F_t *f, hid_t dxpl_id, H5C_cache_entry_t *entry_ptr,
+ unsigned flags)
+{
+ H5C_t * cache_ptr; /* Cache for file */
+ hbool_t destroy; /* external flag */
+ hbool_t clear_only; /* external flag */
+ hbool_t free_file_space; /* external flag */
+ hbool_t take_ownership; /* external flag */
+ hbool_t del_from_slist_on_destroy; /* external flag */
+ hbool_t during_flush; /* external flag */
+ hbool_t write_entry; /* internal flag */
+ hbool_t destroy_entry; /* internal flag */
+ hbool_t generate_image; /* internal flag */
+ hbool_t update_page_buffer; /* internal flag */
+ hbool_t was_dirty;
+ hbool_t suppress_image_entry_writes = FALSE;
+ hbool_t suppress_image_entry_frees = FALSE;
+ haddr_t entry_addr = HADDR_UNDEF;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(f);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring != H5C_RING_UNDEFINED);
+ HDassert(entry_ptr->type);
+
+ /* setup external flags from the flags parameter */
+ destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0);
+ clear_only = ((flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0);
+ free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0);
+ take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0);
+ del_from_slist_on_destroy = ((flags & H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) != 0);
+ during_flush = ((flags & H5C__DURING_FLUSH_FLAG) != 0);
+ generate_image = ((flags & H5C__GENERATE_IMAGE_FLAG) != 0);
+ update_page_buffer = ((flags & H5C__UPDATE_PAGE_BUFFER_FLAG) != 0);
+
+ /* Set the flag for destroying the entry, based on the 'take ownership'
+ * and 'destroy' flags
+ */
+ if(take_ownership)
+ destroy_entry = FALSE;
+ else
+ destroy_entry = destroy;
+
+ /* we will write the entry to disk if it exists, is dirty, and if the
+ * clear only flag is not set.
+ */
+ if(entry_ptr->is_dirty && !clear_only)
+ write_entry = TRUE;
+ else
+ write_entry = FALSE;
+
+ /* if we have received close warning, and we have been instructed to
+ * generate a metadata cache image, and we have actually constructed
+ * the entry images, set suppress_image_entry_frees to TRUE.
+ *
+ * Set suppress_image_entry_writes to TRUE if indicated by the
+ * image_ctl flags.
+ */
+ if(cache_ptr->close_warning_received && cache_ptr->image_ctl.generate_image
+ && cache_ptr->num_entries_in_image > 0 && cache_ptr->image_entries) {
+ /* Sanity checks */
+ HDassert(entry_ptr->image_up_to_date || !(entry_ptr->include_in_image));
+ HDassert(entry_ptr->image_ptr || !(entry_ptr->include_in_image));
+ HDassert((!clear_only) || !(entry_ptr->include_in_image));
+ HDassert((!take_ownership) || !(entry_ptr->include_in_image));
+ HDassert((!free_file_space) || !(entry_ptr->include_in_image));
+
+ suppress_image_entry_frees = TRUE;
+
+ if(cache_ptr->image_ctl.flags & H5C_CI__SUPRESS_ENTRY_WRITES)
+ suppress_image_entry_writes = TRUE;
+ } /* end if */
+
+ /* run initial sanity checks */
+#if H5C_DO_SANITY_CHECKS
+ if(entry_ptr->in_slist) {
+ HDassert(entry_ptr->is_dirty);
+
+ if((entry_ptr->flush_marker) && (!entry_ptr->is_dirty))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry in slist failed sanity checks")
+ } /* end if */
+ else {
+ HDassert(!entry_ptr->is_dirty);
+ HDassert(!entry_ptr->flush_marker);
+
+ if((entry_ptr->is_dirty) || (entry_ptr->flush_marker))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry failed sanity checks")
+ } /* end else */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ if(entry_ptr->is_protected) {
+ HDassert(!entry_ptr->is_protected);
+
+ /* Attempt to flush a protected entry -- scream and die. */
+ HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, "Attempt to flush a protected entry")
+ } /* end if */
+
+ /* Set entry_ptr->flush_in_progress = TRUE and set
+ * entry_ptr->flush_marker = FALSE
+ *
+ * We will set flush_in_progress back to FALSE at the end if the
+ * entry still exists at that point.
+ */
+ entry_ptr->flush_in_progress = TRUE;
+ entry_ptr->flush_marker = FALSE;
+
+ /* Preserve current dirty state for later */
+ was_dirty = entry_ptr->is_dirty;
+
+ /* The entry is dirty, and we are doing a flush, a flush destroy or have
+ * been requested to generate an image. In those cases, serialize the
+ * entry.
+ */
+ if(write_entry || generate_image) {
+ HDassert(entry_ptr->is_dirty);
+
+ if(NULL == entry_ptr->image_ptr) {
+ if(NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+ } /* end if */
+
+ if(!(entry_ptr->image_up_to_date)) {
+ /* Sanity check */
+ HDassert(!entry_ptr->prefetched);
+
+ /* Generate the entry's image */
+ if(H5C__generate_image(f, cache_ptr, entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't generate entry's image")
+ } /* end if ( ! (entry_ptr->image_up_to_date) ) */
+ } /* end if */
+
+ /* Finally, write the image to disk.
+ *
+ * Note that if the H5AC__CLASS_SKIP_WRITES flag is set in the
+ * in the entry's type, we silently skip the write. This
+ * flag should only be used in test code.
+ */
+ if(write_entry) {
+ HDassert(entry_ptr->is_dirty);
+
+#if H5C_DO_SANITY_CHECKS
+ if(cache_ptr->check_write_permitted && !(cache_ptr->write_permitted))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Write when writes are always forbidden!?!?!")
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* Write the image to disk unless the write is suppressed.
+ *
+ * This happens if both suppress_image_entry_writes and
+ * entry_ptr->include_in_image are TRUE, or if the
+ * H5AC__CLASS_SKIP_WRITES is set in the entry's type. This
+ * flag should only be used in test code
+ */
+ if((!suppress_image_entry_writes || !entry_ptr->include_in_image)
+ && (((entry_ptr->type->flags) & H5C__CLASS_SKIP_WRITES) == 0)) {
+ H5FD_mem_t mem_type = H5FD_MEM_DEFAULT;
+
+#ifdef H5_HAVE_PARALLEL
+ if(cache_ptr->coll_write_list) {
+ if(H5SL_insert(cache_ptr->coll_write_list, entry_ptr, &entry_ptr->addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "unable to insert skip list item")
+ } /* end if */
+ else
+#endif /* H5_HAVE_PARALLEL */
+
+ if(entry_ptr->prefetched) {
+ HDassert(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID);
+ mem_type = cache_ptr->class_table_ptr[entry_ptr->prefetch_type_id]->mem_type;
+ } /* end if */
+ else
+ mem_type = entry_ptr->type->mem_type;
+
+ if(H5F_block_write(f, mem_type, entry_ptr->addr, entry_ptr->size, dxpl_id, entry_ptr->image_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't write image to file")
+ } /* end if */
+
+ /* if the entry has a notify callback, notify it that we have
+ * just flushed the entry.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_FLUSH, entry_ptr) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client of entry flush")
+ } /* if ( write_entry ) */
+
+ /* At this point, all pre-serialize and serialize calls have been
+ * made if it was appropriate to make them. Similarly, the entry
+ * has been written to disk if desired.
+ *
+ * Thus it is now safe to update the cache data structures for the
+ * flush.
+ */
+
+ /* start by updating the statistics */
+ if(clear_only) {
+ /* only log a clear if the entry was dirty */
+ if(was_dirty) {
+ H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
+ } /* end if */
+ } else if(write_entry) {
+ HDassert(was_dirty);
+
+ /* only log a flush if we actually wrote to disk */
+ H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)
+ } /* end else if */
+
+ /* Note that the algorithm below is (very) similar to the set of operations
+ * in H5C_remove_entry() and should be kept in sync with changes
+ * to that code. - QAK, 2016/11/30
+ */
+
+ /* Update the cache internal data structures. */
+ if(destroy) {
+ /* Sanity checks */
+ if(take_ownership)
+ HDassert(!destroy_entry);
+ else
+ HDassert(destroy_entry);
+ HDassert(!entry_ptr->is_pinned);
+
+ /* Update stats, while entry is still in the cache */
+ H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership)
+
+ /* If the entry's type has a 'notify' callback and the entry is about
+ * to be removed from the cache, send a 'before eviction' notice while
+ * the entry is still fully integrated in the cache.
+ */
+ if(entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry to evict")
+
+ /* Update the cache internal data structures as appropriate
+ * for a destroy. Specifically:
+ *
+ * 1) Delete it from the index
+ *
+ * 2) Delete it from the skip list if requested.
+ *
+ * 3) Delete it from the collective read access list.
+ *
+ * 4) Update the replacement policy for eviction
+ *
+ * 5) Remove it from the tag list for this object
+ *
+ * Finally, if the destroy_entry flag is set, discard the
+ * entry.
+ */
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ if(entry_ptr->in_slist && del_from_slist_on_destroy)
+ H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush)
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check for collective read access flag */
+ if(entry_ptr->coll_access) {
+ entry_ptr->coll_access = FALSE;
+ H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, FAIL)
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL)
+
+ /* Remove entry from tag list */
+ if(H5C__untag_entry(cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list")
+
+ /* verify that the entry is no longer part of any flush dependencies */
+ HDassert(entry_ptr->flush_dep_nparents == 0);
+ HDassert(entry_ptr->flush_dep_nchildren == 0);
+ } /* end if */
+ else {
+ HDassert(clear_only || write_entry);
+ HDassert(entry_ptr->is_dirty);
+ HDassert(entry_ptr->in_slist);
+
+ /* We are either doing a flush or a clear.
+ *
+ * A clear and a flush are the same from the point of
+ * view of the replacement policy and the slist.
+ * Hence no differentiation between them.
+ *
+ * JRM -- 7/7/07
+ */
+
+ H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, FAIL)
+
+ H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush)
+
+ /* mark the entry as clean and update the index for
+ * entry clean. Also, call the clear callback
+ * if defined.
+ */
+ entry_ptr->is_dirty = FALSE;
+
+ H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr);
+
+ /* Check for entry changing status and do notifications, etc. */
+ if(was_dirty) {
+ /* If the entry's type has a 'notify' callback send a 'entry cleaned'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared")
+
+ /* Propagate the clean flag up the flush dependency chain if appropriate */
+ if(entry_ptr->flush_dep_ndirty_children != 0)
+ HDassert(entry_ptr->flush_dep_ndirty_children == 0);
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_clean(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep clean flag")
+ } /* end if */
+ } /* end else */
+
+ /* reset the flush_in progress flag */
+ entry_ptr->flush_in_progress = FALSE;
+
+ /* capture the cache entry address for the log_flush call at the
+ end before the entry_ptr gets freed */
+ entry_addr = entry_ptr->addr;
+
+ /* Internal cache data structures should now be up to date, and
+ * consistant with the status of the entry.
+ *
+ * Now discard the entry if appropriate.
+ */
+ if(destroy) {
+ /* Sanity check */
+ HDassert(0 == entry_ptr->flush_dep_nparents);
+
+ /* if both suppress_image_entry_frees and entry_ptr->include_in_image
+ * are true, simply set entry_ptr->image_ptr to NULL, as we have
+ * another pointer to the buffer in an instance of H5C_image_entry_t
+ * in cache_ptr->image_entries.
+ *
+ * Otherwise, free the buffer if it exists.
+ */
+ if(suppress_image_entry_frees && entry_ptr->include_in_image)
+ entry_ptr->image_ptr = NULL;
+ else if(entry_ptr->image_ptr != NULL)
+ entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr);
+
+ /* If the entry is not a prefetched entry, verify that the flush
+ * dependency parents addresses array has been transfered.
+ *
+ * If the entry is prefetched, the free_isr routine will dispose of
+ * the flush dependency parents adresses array if necessary.
+ */
+ if(!entry_ptr->prefetched) {
+ HDassert(0 == entry_ptr->fd_parent_count);
+ HDassert(NULL == entry_ptr->fd_parent_addrs);
+ } /* end if */
+
+ /* Check whether we should free the space in the file that
+ * the entry occupies
+ */
+ if(free_file_space) {
+ size_t fsf_size;
+
+ /* Sanity checks */
+ HDassert(H5F_addr_defined(entry_ptr->addr));
+ HDassert(!H5F_IS_TMP_ADDR(f, entry_ptr->addr));
+#ifndef NDEBUG
+ {
+ size_t curr_len;
+
+ /* Get the actual image size for the thing again */
+ entry_ptr->type->image_len((void *)entry_ptr, &curr_len);
+ HDassert(curr_len == entry_ptr->size);
+ }
+#endif /* NDEBUG */
+
+ /* If the file space free size callback is defined, use
+ * it to get the size of the block of file space to free.
+ * Otherwise use entry_ptr->size.
+ */
+ if(entry_ptr->type->fsf_size) {
+ if((entry_ptr->type->fsf_size)((void *)entry_ptr, &fsf_size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to get file space free size")
+ } /* end if */
+ else /* no file space free size callback -- use entry size */
+ fsf_size = entry_ptr->size;
+
+ /* Release the space on disk */
+ if(H5MF_xfree(f, entry_ptr->type->mem_type, dxpl_id, entry_ptr->addr, (hsize_t)fsf_size) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to free file space for cache entry")
+ } /* end if ( free_file_space ) */
+
+ /* Reset the pointer to the cache the entry is within. -QAK */
+ entry_ptr->cache_ptr = NULL;
+
+ /* increment entries_removed_counter and set
+ * last_entry_removed_ptr. As we are likely abuut to
+ * free the entry, recall that last_entry_removed_ptr
+ * must NEVER be dereferenced.
+ *
+ * Recall that these fields are maintained to allow functions
+ * that perform scans of lists of entries to detect the
+ * unexpected removal of entries (via expunge, eviction,
+ * or take ownership at present), so that they can re-start
+ * their scans if necessary.
+ *
+ * Also check if the entry we are watching for removal is being
+ * removed (usually the 'next' entry for an iteration) and reset
+ * it to indicate that it was removed.
+ */
+ cache_ptr->entries_removed_counter++;
+ cache_ptr->last_entry_removed_ptr = entry_ptr;
+ if(entry_ptr == cache_ptr->entry_watched_for_removal)
+ cache_ptr->entry_watched_for_removal = NULL;
+
+ /* Check for actually destroying the entry in memory */
+ /* (As opposed to taking ownership of it) */
+ if(destroy_entry) {
+ if(entry_ptr->is_dirty) {
+ /* Reset dirty flag */
+ entry_ptr->is_dirty = FALSE;
+
+ /* If the entry's type has a 'notify' callback send a 'entry cleaned'
+ * notice now that the entry is fully integrated into the cache.
+ */
+ if(entry_ptr->type->notify &&
+ (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared")
+ } /* end if */
+
+ /* we are about to discard the in core representation --
+ * set the magic field to bad magic so we can detect a
+ * freed entry if we see one.
+ */
+ entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC;
+
+ /* verify that the image has been freed */
+ HDassert(entry_ptr->image_ptr == NULL);
+
+ if(entry_ptr->type->free_icr((void *)entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed")
+ } /* end if */
+ else {
+ HDassert(take_ownership);
+
+ /* client is taking ownership of the entry.
+ * set bad magic here too so the cache will choke
+ * unless the entry is re-inserted properly
+ */
+ entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC;
+ } /* end else */
+ } /* if (destroy) */
+
+ /* Check if we have to update the page buffer with cleared entries
+ * so it doesn't go out of date
+ */
+ if(update_page_buffer) {
+ /* Sanity check */
+ HDassert(!destroy);
+ HDassert(entry_ptr->image_ptr);
+
+ if(f->shared->page_buf && f->shared->page_buf->page_size >= entry_ptr->size)
+ if(H5PB_update_entry(f->shared->page_buf, entry_ptr->addr, entry_ptr->size, entry_ptr->image_ptr) > 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Failed to update PB with metadata cache")
+ } /* end if */
+
+ if(cache_ptr->log_flush)
+ if((cache_ptr->log_flush)(cache_ptr, entry_addr, was_dirty, flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "log_flush callback failed")
+
+done:
+ HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) ||
+ ( ! entry_ptr->flush_in_progress ) );
+ HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) ||
+ ( take_ownership ) || ( ! entry_ptr->is_dirty ) );
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__flush_single_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__verify_len_eoa
+ *
+ * Purpose: Verify that 'len' does not exceed eoa when 'actual' is
+ * false i.e. 'len" is the initial speculative length from
+ * get_load_size callback with null image pointer.
+ * If exceed, adjust 'len' accordingly.
+ *
+ * Verify that 'len' should not exceed eoa when 'actual' is
+ * true i.e. 'len' is the actual length from get_load_size
+ * callback with non-null image pointer.
+ * If exceed, return error.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Vailin Choi
+ * 9/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__verify_len_eoa(H5F_t *f, const H5C_class_t *type, haddr_t addr,
+ size_t *len, hbool_t actual)
+{
+ H5FD_mem_t cooked_type; /* Modified type, accounting for switching global heaps */
+ haddr_t eoa; /* End-of-allocation in the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces
+ * type to H5FD_MEM_DRAW via its call to H5F__accum_read().
+ * Thus we do the same for purposes of computing the EOA
+ * for sanity checks.
+ */
+ cooked_type = (type->mem_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type->mem_type;
+
+ /* Get the file's end-of-allocation value */
+ eoa = H5F_get_eoa(f, cooked_type);
+ if(!H5F_addr_defined(eoa))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid EOA address for file")
+
+ /* Check for bad address in general */
+ if(H5F_addr_gt(addr, eoa))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "address of object past end of allocation")
+
+ /* Check if the amount of data to read will be past the EOA */
+ if(H5F_addr_gt((addr + *len), eoa)) {
+ if(actual)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "actual len exceeds EOA")
+ else
+ /* Trim down the length of the metadata */
+ *len = (size_t)(eoa - addr);
+ } /* end if */
+
+ if(*len <= 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "len not positive after adjustment for EOA")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__verify_len_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_load_entry
+ *
+ * Purpose: Attempt to load the entry at the specified disk address
+ * and with the specified type into memory. If successful.
+ * return the in memory address of the entry. Return NULL
+ * on failure.
+ *
+ * Note that this function simply loads the entry into
+ * core. It does not insert it into the cache.
+ *
+ * Return: Non-NULL on success / NULL on failure.
+ *
+ * Programmer: John Mainzer, 5/18/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5C_load_entry(H5F_t * f,
+ hid_t dxpl_id,
+#ifdef H5_HAVE_PARALLEL
+ hbool_t coll_access,
+#endif /* H5_HAVE_PARALLEL */
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * udata)
+{
+ hbool_t dirty = FALSE; /* Flag indicating whether thing was dirtied during deserialize */
+ uint8_t * image = NULL; /* Buffer for disk image */
+ void * thing = NULL; /* Pointer to thing loaded */
+ H5C_cache_entry_t *entry = NULL; /* Alias for thing loaded, as cache entry */
+ size_t len; /* Size of image in file */
+#ifdef H5_HAVE_PARALLEL
+ int mpi_rank = 0; /* MPI process rank */
+ MPI_Comm comm = MPI_COMM_NULL; /* File MPI Communicator */
+ int mpi_code; /* MPI error code */
+#endif /* H5_HAVE_PARALLEL */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(type);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(type->get_initial_load_size);
+ if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG)
+ HDassert(type->get_final_load_size);
+ else
+ HDassert(NULL == type->get_final_load_size);
+ HDassert(type->deserialize);
+
+ /* Can't see how skip reads could be usefully combined with
+ * the speculative read flag. Hence disallow.
+ */
+ HDassert(!((type->flags & H5C__CLASS_SKIP_READS) &&
+ (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG)));
+
+ /* Call the get_initial_load_size callback, to retrieve the initial size of image */
+ if(type->get_initial_load_size(udata, &len) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't retrieve image size")
+ HDassert(len > 0);
+
+ /* Check for possible speculative read off the end of the file */
+ if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG)
+ if(H5C__verify_len_eoa(f, type, addr, &len, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid len with respect to EOA")
+
+ /* Allocate the buffer for reading the on-disk entry image */
+ if(NULL == (image = (uint8_t *)H5MM_malloc(len + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ if((mpi_rank = H5F_mpi_get_rank(f)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "Can't get MPI rank")
+ if((comm = H5F_mpi_get_comm(f)) == MPI_COMM_NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "get_comm request failed")
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Get the on-disk entry image */
+ if(0 == (type->flags & H5C__CLASS_SKIP_READS)) {
+ unsigned tries, max_tries; /* The # of read attempts */
+ unsigned retries; /* The # of retries */
+ htri_t chk_ret; /* return from verify_chksum callback */
+ size_t actual_len = len; /* The actual length, after speculative reads have been resolved */
+ uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */
+ void *new_image; /* Pointer to image */
+ hbool_t len_changed = TRUE; /* Whether to re-check speculative entries */
+
+ /* Get the # of read attempts */
+ max_tries = tries = H5F_GET_READ_ATTEMPTS(f);
+
+ /*
+ * This do/while loop performs the following till the metadata checksum
+ * is correct or the file's number of allowed read attempts are reached.
+ * --read the metadata
+ * --determine the actual size of the metadata
+ * --perform checksum verification
+ */
+ do {
+ if(actual_len != len) {
+ if(NULL == (new_image = H5MM_realloc(image, len + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()")
+ image = (uint8_t *)new_image;
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ if(!coll_access || 0 == mpi_rank) {
+#endif /* H5_HAVE_PARALLEL */
+ if(H5F_block_read(f, type->mem_type, addr, len, dxpl_id, image) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "Can't read image*")
+#ifdef H5_HAVE_PARALLEL
+ } /* end if */
+ /* if the collective metadata read optimization is turned on,
+ * bcast the metadata read from process 0 to all ranks in the file
+ * communicator
+ */
+ if(coll_access) {
+ int buf_size;
+
+ H5_CHECKED_ASSIGN(buf_size, int, len, size_t);
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image, buf_size, MPI_BYTE, 0, comm)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code)
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* If the entry could be read speculatively and the length is still
+ * changing, check for updating the actual size
+ */
+ if((type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) && len_changed) {
+ /* Retrieve the actual length */
+ actual_len = len;
+ if(type->get_final_load_size(image, len, udata, &actual_len) < 0)
+ continue; /* Transfer control to while() and count towards retries */
+
+ /* Check for the length changing */
+ if(actual_len != len) {
+ /* Verify that the length isn't past the EOA for the file */
+ if(H5C__verify_len_eoa(f, type, addr, &actual_len, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "actual_len exceeds EOA")
+
+ /* Expand buffer to new size */
+ if(NULL == (new_image = H5MM_realloc(image, actual_len + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()")
+ image = (uint8_t *)new_image;
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(image + actual_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+ if(actual_len > len) {
+#ifdef H5_HAVE_PARALLEL
+ if(!coll_access || 0 == mpi_rank) {
+#endif /* H5_HAVE_PARALLEL */
+ /* If the thing's image needs to be bigger for a speculatively
+ * loaded thing, go get the on-disk image again (the extra portion).
+ */
+ if(H5F_block_read(f, type->mem_type, addr + len, actual_len - len, dxpl_id, image + len) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't read image")
+#ifdef H5_HAVE_PARALLEL
+ }
+ /* If the collective metadata read optimization is turned on,
+ * Bcast the metadata read from process 0 to all ranks in the file
+ * communicator */
+ if(coll_access) {
+ int buf_size;
+
+ H5_CHECKED_ASSIGN(buf_size, int, actual_len - len, size_t);
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image + len, buf_size, MPI_BYTE, 0, comm)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code)
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+ } /* end if */
+ } /* end if (actual_len != len) */
+ else {
+ /* The length has stabilized */
+ len_changed = FALSE;
+
+ /* Set the final length */
+ len = actual_len;
+ } /* else */
+ } /* end if */
+
+ /* If there's no way to verify the checksum for a piece of metadata
+ * (usually because there's no checksum in the file), leave now
+ */
+ if(type->verify_chksum == NULL)
+ break;
+
+ /* Verify the checksum for the metadata image */
+ if((chk_ret = type->verify_chksum(image, actual_len, udata)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "failure from verify_chksum callback")
+ if(chk_ret == TRUE)
+ break;
+
+ /* Sleep for some time */
+ H5_nanosleep(nanosec);
+ nanosec *= 2; /* Double the sleep time next time */
+ } while(--tries);
+
+ /* Check for too many tries */
+ if(tries == 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "incorrect metadatda checksum after all read attempts")
+
+ /* Calculate and track the # of retries */
+ retries = max_tries - tries;
+ if(retries) /* Does not track 0 retry */
+ if(H5F_track_metadata_read_retries(f, (unsigned)type->mem_type, retries) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "cannot track read tries = %u ", retries)
+
+ /* Set the final length (in case it wasn't set earlier) */
+ len = actual_len;
+ } /* end if !H5C__CLASS_SKIP_READS */
+
+ /* Deserialize the on-disk image into the native memory form */
+ if(NULL == (thing = type->deserialize(image, len, udata, &dirty)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't deserialize image")
+
+ entry = (H5C_cache_entry_t *)thing;
+
+ /* In general, an entry should be clean just after it is loaded.
+ *
+ * However, when this code is used in the metadata cache, it is
+ * possible that object headers will be dirty at this point, as
+ * the deserialize function will alter object headers if necessary to
+ * fix an old bug.
+ *
+ * In the following assert:
+ *
+ * HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6 ) );
+ *
+ * note that type ids 5 & 6 are associated with object headers in the
+ * metadata cache.
+ *
+ * When we get to using H5C for other purposes, we may wish to
+ * tighten up the assert so that the loophole only applies to the
+ * metadata cache.
+ */
+
+ HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6) );
+
+ entry->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC;
+ entry->cache_ptr = f->shared->cache;
+ entry->addr = addr;
+ entry->size = len;
+ HDassert(entry->size < H5C_MAX_ENTRY_SIZE);
+ entry->image_ptr = image;
+ entry->image_up_to_date = !dirty;
+ entry->type = type;
+ entry->is_dirty = dirty;
+ entry->dirtied = FALSE;
+ entry->is_protected = FALSE;
+ entry->is_read_only = FALSE;
+ entry->ro_ref_count = 0;
+ entry->is_pinned = FALSE;
+ entry->in_slist = FALSE;
+ entry->flush_marker = FALSE;
+#ifdef H5_HAVE_PARALLEL
+ entry->clear_on_unprotect = FALSE;
+ entry->flush_immediately = FALSE;
+ entry->coll_access = coll_access;
+#endif /* H5_HAVE_PARALLEL */
+ entry->flush_in_progress = FALSE;
+ entry->destroy_in_progress = FALSE;
+
+ entry->ring = H5C_RING_UNDEFINED;
+
+ /* Initialize flush dependency fields */
+ entry->flush_dep_parent = NULL;
+ entry->flush_dep_nparents = 0;
+ entry->flush_dep_parent_nalloc = 0;
+ entry->flush_dep_nchildren = 0;
+ entry->flush_dep_ndirty_children = 0;
+ entry->flush_dep_nunser_children = 0;
+ entry->ht_next = NULL;
+ entry->ht_prev = NULL;
+ entry->il_next = NULL;
+ entry->il_prev = NULL;
+
+ entry->next = NULL;
+ entry->prev = NULL;
+
+ entry->aux_next = NULL;
+ entry->aux_prev = NULL;
+
+#ifdef H5_HAVE_PARALLEL
+ entry->coll_next = NULL;
+ entry->coll_prev = NULL;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* initialize cache image related fields */
+ entry->include_in_image = FALSE;
+ entry->lru_rank = 0;
+ entry->image_dirty = FALSE;
+ entry->fd_parent_count = 0;
+ entry->fd_parent_addrs = NULL;
+ entry->fd_child_count = 0;
+ entry->fd_dirty_child_count = 0;
+ entry->image_fd_height = 0;
+ entry->prefetched = FALSE;
+ entry->prefetch_type_id = 0;
+ entry->age = 0;
+ entry->prefetched_dirty = FALSE;
+#ifndef NDEBUG /* debugging field */
+ entry->serialization_count = 0;
+#endif /* NDEBUG */
+
+ entry->tl_next = NULL;
+ entry->tl_prev = NULL;
+ entry->tag_info = NULL;
+
+ H5C__RESET_CACHE_ENTRY_STATS(entry);
+
+ ret_value = thing;
+
+done:
+ /* Cleanup on error */
+ if(NULL == ret_value) {
+ /* Release resources */
+ if(thing && type->free_icr(thing) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "free_icr callback failed")
+ if(image)
+ image = (uint8_t *)H5MM_xfree(image);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_load_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__make_space_in_cache
+ *
+ * Purpose: Attempt to evict cache entries until the index_size
+ * is at least needed_space below max_cache_size.
+ *
+ * In passing, also attempt to bring cLRU_list_size to a
+ * value greater than min_clean_size.
+ *
+ * Depending on circumstances, both of these goals may
+ * be impossible, as in parallel mode, we must avoid generating
+ * a write as part of a read (to avoid deadlock in collective
+ * I/O), and in all cases, it is possible (though hopefully
+ * highly unlikely) that the protected list may exceed the
+ * maximum size of the cache.
+ *
+ * Thus the function simply does its best, returning success
+ * unless an error is encountered.
+ *
+ * Observe that this function cannot occasion a read.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/14/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__make_space_in_cache(H5F_t *f, hid_t dxpl_id, size_t space_needed,
+ hbool_t write_permitted)
+{
+ H5C_t * cache_ptr = f->shared->cache;
+#if H5C_COLLECT_CACHE_STATS
+ int32_t clean_entries_skipped = 0;
+ int32_t dirty_pf_entries_skipped = 0;
+ int32_t total_entries_scanned = 0;
+#endif /* H5C_COLLECT_CACHE_STATS */
+ uint32_t entries_examined = 0;
+ uint32_t initial_list_len;
+ size_t empty_space;
+ hbool_t reentrant_call = FALSE;
+ hbool_t prev_is_dirty = FALSE;
+ hbool_t didnt_flush_entry = FALSE;
+ hbool_t restart_scan;
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * prev_ptr;
+ H5C_cache_entry_t * next_ptr;
+ uint32_t num_corked_entries = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->index_size == (cache_ptr->clean_index_size + cache_ptr->dirty_index_size));
+
+ /* check to see if cache_ptr->msic_in_progress is TRUE. If it, this
+ * is a re-entrant call via a client callback called in the make
+ * space in cache process. To avoid an infinite recursion, set
+ * reentrant_call to TRUE, and goto done.
+ */
+ if(cache_ptr->msic_in_progress) {
+ reentrant_call = TRUE;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ cache_ptr->msic_in_progress = TRUE;
+
+ if ( write_permitted ) {
+ restart_scan = FALSE;
+ initial_list_len = cache_ptr->LRU_list_len;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+
+ if(cache_ptr->index_size >= cache_ptr->max_cache_size)
+ empty_space = 0;
+ else
+ empty_space = cache_ptr->max_cache_size - cache_ptr->index_size;
+
+ while ( ( ( (cache_ptr->index_size + space_needed)
+ >
+ cache_ptr->max_cache_size
+ )
+ ||
+ (
+ ( empty_space + cache_ptr->clean_index_size )
+ <
+ ( cache_ptr->min_clean_size )
+ )
+ )
+ &&
+ ( entries_examined <= (2 * initial_list_len) )
+ &&
+ ( entry_ptr != NULL )
+ )
+ {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert( !(entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( (entry_ptr->ro_ref_count) == 0 );
+
+ next_ptr = entry_ptr->next;
+ prev_ptr = entry_ptr->prev;
+
+ if(prev_ptr != NULL)
+ prev_is_dirty = prev_ptr->is_dirty;
+
+ if(entry_ptr->is_dirty &&
+ (entry_ptr->tag_info && entry_ptr->tag_info->corked)) {
+
+ /* Skip "dirty" corked entries. */
+ ++num_corked_entries;
+ didnt_flush_entry = TRUE;
+
+ } else if ( ( (entry_ptr->type)->id != H5AC_EPOCH_MARKER_ID ) &&
+ ( ! entry_ptr->flush_in_progress ) &&
+ ( ! entry_ptr->prefetched_dirty ) ) {
+
+ didnt_flush_entry = FALSE;
+
+ if ( entry_ptr->is_dirty ) {
+
+#if H5C_COLLECT_CACHE_STATS
+ if ( (cache_ptr->index_size + space_needed)
+ >
+ cache_ptr->max_cache_size ) {
+
+ cache_ptr->entries_scanned_to_make_space++;
+ }
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ /* reset entries_removed_counter and
+ * last_entry_removed_ptr prior to the call to
+ * H5C__flush_single_entry() so that we can spot
+ * unexpected removals of entries from the cache,
+ * and set the restart_scan flag if proceeding
+ * would be likely to cause us to scan an entry
+ * that is no longer in the cache.
+ */
+ cache_ptr->entries_removed_counter = 0;
+ cache_ptr->last_entry_removed_ptr = NULL;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry")
+
+ if ( ( cache_ptr->entries_removed_counter > 1 ) ||
+ ( cache_ptr->last_entry_removed_ptr == prev_ptr ) )
+
+ restart_scan = TRUE;
+
+ } else if ( (cache_ptr->index_size + space_needed) > cache_ptr->max_cache_size
+#ifdef H5_HAVE_PARALLEL
+ && !(entry_ptr->coll_access)
+#endif /* H5_HAVE_PARALLEL */
+ ) {
+#if H5C_COLLECT_CACHE_STATS
+ cache_ptr->entries_scanned_to_make_space++;
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry")
+ } else {
+ /* We have enough space so don't flush clean entry. */
+#if H5C_COLLECT_CACHE_STATS
+ clean_entries_skipped++;
+#endif /* H5C_COLLECT_CACHE_STATS */
+ didnt_flush_entry = TRUE;
+ }
+
+#if H5C_COLLECT_CACHE_STATS
+ total_entries_scanned++;
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ } else {
+
+ /* Skip epoch markers, entries that are in the process
+ * of being flushed, and entries marked as prefetched_dirty
+ * (occurs in the R/O case only).
+ */
+ didnt_flush_entry = TRUE;
+
+#if H5C_COLLECT_CACHE_STATS
+ if(entry_ptr->prefetched_dirty)
+ dirty_pf_entries_skipped++;
+#endif /* H5C_COLLECT_CACHE_STATS */
+ }
+
+ if ( prev_ptr != NULL ) {
+
+ if ( didnt_flush_entry ) {
+
+ /* epoch markers don't get flushed, and we don't touch
+ * entries that are in the process of being flushed.
+ * Hence no need for sanity checks, as we haven't
+ * flushed anything. Thus just set entry_ptr to prev_ptr
+ * and go on.
+ */
+ entry_ptr = prev_ptr;
+
+ } else if ( ( restart_scan )
+ ||
+ ( prev_ptr->is_dirty != prev_is_dirty )
+ ||
+ ( prev_ptr->next != next_ptr )
+ ||
+ ( prev_ptr->is_protected )
+ ||
+ ( prev_ptr->is_pinned ) ) {
+
+ /* something has happened to the LRU -- start over
+ * from the tail.
+ */
+ restart_scan = FALSE;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+ H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr)
+
+ } else {
+
+ entry_ptr = prev_ptr;
+
+ }
+ } else {
+
+ entry_ptr = NULL;
+
+ }
+
+ entries_examined++;
+
+ if ( cache_ptr->index_size >= cache_ptr->max_cache_size ) {
+
+ empty_space = 0;
+
+ } else {
+
+ empty_space = cache_ptr->max_cache_size - cache_ptr->index_size;
+
+ }
+
+ HDassert( cache_ptr->index_size ==
+ (cache_ptr->clean_index_size +
+ cache_ptr->dirty_index_size) );
+
+ }
+
+#if H5C_COLLECT_CACHE_STATS
+ cache_ptr->calls_to_msic++;
+
+ cache_ptr->total_entries_skipped_in_msic += clean_entries_skipped;
+ cache_ptr->total_dirty_pf_entries_skipped_in_msic += dirty_pf_entries_skipped;
+ cache_ptr->total_entries_scanned_in_msic += total_entries_scanned;
+
+ if ( clean_entries_skipped > cache_ptr->max_entries_skipped_in_msic ) {
+
+ cache_ptr->max_entries_skipped_in_msic = clean_entries_skipped;
+ }
+
+ if(dirty_pf_entries_skipped > cache_ptr->max_dirty_pf_entries_skipped_in_msic)
+ cache_ptr->max_dirty_pf_entries_skipped_in_msic = dirty_pf_entries_skipped;
+
+ if ( total_entries_scanned > cache_ptr->max_entries_scanned_in_msic ) {
+
+ cache_ptr->max_entries_scanned_in_msic = total_entries_scanned;
+ }
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+
+ /* NEED: work on a better assert for corked entries */
+ HDassert( ( entries_examined > (2 * initial_list_len) ) ||
+ ( (cache_ptr->pl_size + cache_ptr->pel_size + cache_ptr->min_clean_size) >
+ cache_ptr->max_cache_size ) ||
+ ( ( cache_ptr->clean_index_size + empty_space )
+ >= cache_ptr->min_clean_size ) ||
+ ( ( num_corked_entries )));
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+ HDassert( ( entries_examined > (2 * initial_list_len) ) ||
+ ( cache_ptr->cLRU_list_size <= cache_ptr->clean_index_size ) );
+ HDassert( ( entries_examined > (2 * initial_list_len) ) ||
+ ( cache_ptr->dLRU_list_size <= cache_ptr->dirty_index_size ) );
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+ } else {
+
+ HDassert( H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS );
+
+ initial_list_len = cache_ptr->cLRU_list_len;
+ entry_ptr = cache_ptr->cLRU_tail_ptr;
+
+ while ( ( (cache_ptr->index_size + space_needed)
+ >
+ cache_ptr->max_cache_size
+ )
+ &&
+ ( entries_examined <= initial_list_len )
+ &&
+ ( entry_ptr != NULL )
+ )
+ {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( (entry_ptr->ro_ref_count) == 0 );
+ HDassert( ! (entry_ptr->is_dirty) );
+
+ prev_ptr = entry_ptr->aux_prev;
+
+ if ( ( !(entry_ptr->prefetched_dirty) )
+#ifdef H5_HAVE_PARALLEL
+ && ( ! (entry_ptr->coll_access) )
+#endif /* H5_HAVE_PARALLEL */
+ ) {
+
+ if ( H5C__flush_single_entry(f, dxpl_id, entry_ptr,
+ H5C__FLUSH_INVALIDATE_FLAG |
+ H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0 )
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to flush entry")
+
+ } /* end if */
+
+ /* we are scanning the clean LRU, so the serialize function
+ * will not be called on any entry -- thus there is no
+ * concern about the list being modified out from under
+ * this function.
+ */
+
+ entry_ptr = prev_ptr;
+ entries_examined++;
+ }
+ }
+
+done:
+ /* Sanity checks */
+ HDassert(cache_ptr->msic_in_progress);
+ if(!reentrant_call)
+ cache_ptr->msic_in_progress = FALSE;
+ HDassert((!reentrant_call) || (cache_ptr->msic_in_progress));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__make_space_in_cache() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_validate_lru_list
+ *
+ * Purpose: Debugging function that scans the LRU list for errors.
+ *
+ * If an error is detected, the function generates a
+ * diagnostic and returns FAIL. If no error is detected,
+ * the function returns SUCCEED.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 7/14/05
+ *
+ * Changes:
+ *
+ * Added code to verify that the LRU contains no pinned
+ * entries. JRM -- 4/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5C_DO_EXTREME_SANITY_CHECKS
+
+static herr_t
+H5C_validate_lru_list(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int32_t len = 0;
+ size_t size = 0;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if ( ( ( cache_ptr->LRU_head_ptr == NULL )
+ ||
+ ( cache_ptr->LRU_tail_ptr == NULL )
+ )
+ &&
+ ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed")
+ }
+
+ if(cache_ptr->LRU_list_len < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed")
+
+ if ( ( cache_ptr->LRU_list_len == 1 )
+ &&
+ ( ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr )
+ ||
+ ( cache_ptr->LRU_head_ptr == NULL )
+ ||
+ ( cache_ptr->LRU_head_ptr->size != cache_ptr->LRU_list_size )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed")
+ }
+
+ if ( ( cache_ptr->LRU_list_len >= 1 )
+ &&
+ ( ( cache_ptr->LRU_head_ptr == NULL )
+ ||
+ ( cache_ptr->LRU_head_ptr->prev != NULL )
+ ||
+ ( cache_ptr->LRU_tail_ptr == NULL )
+ ||
+ ( cache_ptr->LRU_tail_ptr->next != NULL )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed")
+ }
+
+ entry_ptr = cache_ptr->LRU_head_ptr;
+ while ( entry_ptr != NULL )
+ {
+
+ if ( ( entry_ptr != cache_ptr->LRU_head_ptr ) &&
+ ( ( entry_ptr->prev == NULL ) ||
+ ( entry_ptr->prev->next != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed")
+ }
+
+ if ( ( entry_ptr != cache_ptr->LRU_tail_ptr ) &&
+ ( ( entry_ptr->next == NULL ) ||
+ ( entry_ptr->next->prev != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
+ }
+
+ if ( ( entry_ptr->is_pinned ) ||
+ ( entry_ptr->pinned_from_client ) ||
+ ( entry_ptr->pinned_from_cache ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ }
+
+ len++;
+ size += entry_ptr->size;
+ entry_ptr = entry_ptr->next;
+ }
+
+ if ( ( cache_ptr->LRU_list_len != len ) ||
+ ( cache_ptr->LRU_list_size != size ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
+ }
+
+done:
+
+ if ( ret_value != SUCCEED ) {
+
+ HDassert(0);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_validate_lru_list() */
+
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_validate_pinned_entry_list
+ *
+ * Purpose: Debugging function that scans the pinned entry list for
+ * errors.
+ *
+ * If an error is detected, the function generates a
+ * diagnostic and returns FAIL. If no error is detected,
+ * the function returns SUCCEED.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 4/25/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5C_DO_EXTREME_SANITY_CHECKS
+
+static herr_t
+H5C_validate_pinned_entry_list(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int32_t len = 0;
+ size_t size = 0;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if ( ( ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr == NULL )
+ )
+ &&
+ ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed")
+ }
+
+ if(cache_ptr->pel_len < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed")
+
+ if ( ( cache_ptr->pel_len == 1 )
+ &&
+ ( ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr )
+ ||
+ ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_head_ptr->size != cache_ptr->pel_size )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed")
+ }
+
+ if ( ( cache_ptr->pel_len >= 1 )
+ &&
+ ( ( cache_ptr->pel_head_ptr == NULL )
+ ||
+ ( cache_ptr->pel_head_ptr->prev != NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr == NULL )
+ ||
+ ( cache_ptr->pel_tail_ptr->next != NULL )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed")
+ }
+
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while ( entry_ptr != NULL )
+ {
+
+ if ( ( entry_ptr != cache_ptr->pel_head_ptr ) &&
+ ( ( entry_ptr->prev == NULL ) ||
+ ( entry_ptr->prev->next != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed")
+ }
+
+ if ( ( entry_ptr != cache_ptr->pel_tail_ptr ) &&
+ ( ( entry_ptr->next == NULL ) ||
+ ( entry_ptr->next->prev != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
+ }
+
+ if ( ! entry_ptr->is_pinned ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ }
+
+ if ( ! ( ( entry_ptr->pinned_from_client ) ||
+ ( entry_ptr->pinned_from_cache ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
+ }
+
+ len++;
+ size += entry_ptr->size;
+ entry_ptr = entry_ptr->next;
+ }
+
+ if ( ( cache_ptr->pel_len != len ) ||
+ ( cache_ptr->pel_size != size ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed")
+ }
+
+done:
+
+ if ( ret_value != SUCCEED ) {
+
+ HDassert(0);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_validate_pinned_entry_list() */
+
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_validate_protected_entry_list
+ *
+ * Purpose: Debugging function that scans the protected entry list for
+ * errors.
+ *
+ * If an error is detected, the function generates a
+ * diagnostic and returns FAIL. If no error is detected,
+ * the function returns SUCCEED.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 4/25/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5C_DO_EXTREME_SANITY_CHECKS
+
+static herr_t
+H5C_validate_protected_entry_list(H5C_t * cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int32_t len = 0;
+ size_t size = 0;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if(((cache_ptr->pl_head_ptr == NULL) || (cache_ptr->pl_tail_ptr == NULL))
+ && (cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed")
+
+ if(cache_ptr->pl_len < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed")
+
+ if ( ( cache_ptr->pl_len == 1 )
+ &&
+ ( ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr )
+ ||
+ ( cache_ptr->pl_head_ptr == NULL )
+ ||
+ ( cache_ptr->pl_head_ptr->size != cache_ptr->pl_size )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed")
+ }
+
+ if ( ( cache_ptr->pl_len >= 1 )
+ &&
+ ( ( cache_ptr->pl_head_ptr == NULL )
+ ||
+ ( cache_ptr->pl_head_ptr->prev != NULL )
+ ||
+ ( cache_ptr->pl_tail_ptr == NULL )
+ ||
+ ( cache_ptr->pl_tail_ptr->next != NULL )
+ )
+ ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed")
+ }
+
+ entry_ptr = cache_ptr->pl_head_ptr;
+ while ( entry_ptr != NULL )
+ {
+
+ if ( ( entry_ptr != cache_ptr->pl_head_ptr ) &&
+ ( ( entry_ptr->prev == NULL ) ||
+ ( entry_ptr->prev->next != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed")
+ }
+
+ if ( ( entry_ptr != cache_ptr->pl_tail_ptr ) &&
+ ( ( entry_ptr->next == NULL ) ||
+ ( entry_ptr->next->prev != entry_ptr ) ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed")
+ }
+
+ if ( ! entry_ptr->is_protected ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed")
+ }
+
+ if ( ( entry_ptr->is_read_only ) &&
+ ( entry_ptr->ro_ref_count <= 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed")
+ }
+
+ len++;
+ size += entry_ptr->size;
+ entry_ptr = entry_ptr->next;
+ }
+
+ if ( ( cache_ptr->pl_len != len ) ||
+ ( cache_ptr->pl_size != size ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed")
+ }
+
+done:
+
+ if ( ret_value != SUCCEED ) {
+
+ HDassert(0);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_validate_protected_entry_list() */
+
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_entry_in_skip_list
+ *
+ * Purpose: Debugging function that scans skip list to see if it
+ * is in present. We need this, as it is possible for
+ * an entry to be in the skip list twice.
+ *
+ * Return: FALSE if the entry is not in the skip list, and TRUE
+ * if it is.
+ *
+ * Programmer: John Mainzer, 11/1/14
+ *
+ * Changes:
+ *
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5C_DO_SLIST_SANITY_CHECKS
+
+static hbool_t
+H5C_entry_in_skip_list(H5C_t * cache_ptr, H5C_cache_entry_t *target_ptr)
+{
+ hbool_t in_slist = FALSE;
+ H5SL_node_t * node_ptr = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->slist_ptr );
+
+ node_ptr = H5SL_first(cache_ptr->slist_ptr);
+
+ while ( ( node_ptr != NULL ) && ( ! in_slist ) )
+ {
+ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+
+ HDassert( entry_ptr );
+ HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_slist );
+
+ if ( entry_ptr == target_ptr ) {
+
+ in_slist = TRUE;
+
+ } else {
+
+ node_ptr = H5SL_next(node_ptr);
+ }
+ }
+
+ return(in_slist);
+
+} /* H5C_entry_in_skip_list() */
+#endif /* H5C_DO_SLIST_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__flush_marked_entries
+ *
+ * Purpose: Flushes all marked entries in the cache.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * November 3, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__flush_marked_entries(H5F_t * f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /* Assertions */
+ HDassert(f != NULL);
+
+ /* Flush all marked entries */
+ if(H5C_flush_cache(f, dxpl_id, H5C__FLUSH_MARKED_ENTRIES_FLAG | H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__flush_marked_entries */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_cork
+ *
+ * Purpose: To cork/uncork/get cork status of an object depending on "action":
+ * H5C__SET_CORK:
+ * To cork the object
+ * Return error if the object is already corked
+ * H5C__UNCORK:
+ * To uncork the obejct
+ * Return error if the object is not corked
+ * H5C__GET_CORKED:
+ * To retrieve the cork status of an object in
+ * the parameter "corked"
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * January 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked)
+{
+ H5C_tag_info_t *tag_info; /* Points to a tag info struct */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Assertions */
+ HDassert(cache_ptr != NULL);
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(action == H5C__SET_CORK || action == H5C__UNCORK || action == H5C__GET_CORKED);
+
+ /* Search the list of corked object addresses in the cache */
+ tag_info = (H5C_tag_info_t *)H5SL_search(cache_ptr->tag_list, &obj_addr);
+
+ if(H5C__GET_CORKED == action) {
+ HDassert(corked);
+ if(tag_info != NULL && tag_info->corked)
+ *corked = TRUE;
+ else
+ *corked = FALSE;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5C__SET_CORK == action || H5C__UNCORK == action);
+
+ /* Perform appropriate action */
+ if(H5C__SET_CORK == action) {
+ /* Check if this is the first entry for this tagged object */
+ if(NULL == tag_info) {
+ /* Allocate new tag info struct */
+ if(NULL == (tag_info = H5FL_CALLOC(H5C_tag_info_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "can't allocate tag info for cache entry")
+
+ /* Set the tag for all entries */
+ tag_info->tag = obj_addr;
+
+ /* Insert tag info into skip list */
+ if(H5SL_insert(cache_ptr->tag_list, tag_info, &(tag_info->tag)) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert tag info in skip list")
+ } /* end if */
+ else {
+ /* Check for object already corked */
+ if(tag_info->corked)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCORK, FAIL, "object already corked")
+ HDassert(tag_info->entry_cnt > 0 && tag_info->head);
+ } /* end else */
+
+ /* Set the corked status for the entire object */
+ tag_info->corked = TRUE;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(tag_info);
+
+ /* Check for already uncorked */
+ if(!tag_info->corked)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNCORK, FAIL, "object already uncorked")
+
+ /* Set the corked status for the entire object */
+ tag_info->corked = FALSE;
+
+ /* Remove the tag info from the tag list, if there's no more entries with this tag */
+ if(0 == tag_info->entry_cnt) {
+ /* Sanity check */
+ HDassert(NULL == tag_info->head);
+
+ if(H5SL_remove(cache_ptr->tag_list, &(tag_info->tag)) != tag_info)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove tag info from list")
+
+ /* Release the tag info */
+ tag_info = H5FL_FREE(H5C_tag_info_t, tag_info);
+ } /* end if */
+ else
+ HDassert(NULL != tag_info->head);
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_cork() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__mark_flush_dep_dirty()
+ *
+ * Purpose: Recursively propagate the flush_dep_ndirty_children flag
+ * up the dependency chain in response to entry either
+ * becoming dirty or having its flush_dep_ndirty_children
+ * increased from 0.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 11/13/12
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__mark_flush_dep_dirty(H5C_cache_entry_t * entry)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry);
+
+ /* Iterate over the parent entries, if any */
+ for(u = 0; u < entry->flush_dep_nparents; u++) {
+ /* Sanity check */
+ HDassert(entry->flush_dep_parent[u]->flush_dep_ndirty_children < entry->flush_dep_parent[u]->flush_dep_nchildren);
+
+ /* Adjust the parent's number of dirty children */
+ entry->flush_dep_parent[u]->flush_dep_ndirty_children++;
+
+ /* If the parent has a 'notify' callback, send a 'child entry dirtied' notice */
+ if(entry->flush_dep_parent[u]->type->notify &&
+ (entry->flush_dep_parent[u]->type->notify)(H5C_NOTIFY_ACTION_CHILD_DIRTIED, entry->flush_dep_parent[u]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag set")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__mark_flush_dep_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__mark_flush_dep_clean()
+ *
+ * Purpose: Recursively propagate the flush_dep_ndirty_children flag
+ * up the dependency chain in response to entry either
+ * becoming clean or having its flush_dep_ndirty_children
+ * reduced to 0.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 11/13/12
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__mark_flush_dep_clean(H5C_cache_entry_t * entry)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry);
+
+ /* Iterate over the parent entries, if any */
+ for(u = 0; u < entry->flush_dep_nparents; u++) {
+ /* Sanity check */
+ HDassert(entry->flush_dep_parent[u]->flush_dep_ndirty_children > 0);
+
+ /* Adjust the parent's number of dirty children */
+ entry->flush_dep_parent[u]->flush_dep_ndirty_children--;
+
+ /* If the parent has a 'notify' callback, send a 'child entry cleaned' notice */
+ if(entry->flush_dep_parent[u]->type->notify &&
+ (entry->flush_dep_parent[u]->type->notify)(H5C_NOTIFY_ACTION_CHILD_CLEANED, entry->flush_dep_parent[u]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag reset")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__mark_flush_dep_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__mark_flush_dep_serialized()
+ *
+ * Purpose: Decrement the flush_dep_nunser_children fields of all the
+ * target entry's flush dependency parents in response to
+ * the target entry becoming serialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/30/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__mark_flush_dep_serialized(H5C_cache_entry_t * entry_ptr)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+
+ /* Iterate over the parent entries, if any */
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++) {
+
+ HDassert(entry_ptr->flush_dep_parent);
+ HDassert(entry_ptr->flush_dep_parent[u]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children > 0);
+
+ /* decrement the parents number of unserialized children */
+ entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children--;
+
+ /* If the parent has a 'notify' callback, send a 'child entry serialized' notice */
+ if(entry_ptr->flush_dep_parent[u]->type->notify &&
+ (entry_ptr->flush_dep_parent[u]->type->notify)(H5C_NOTIFY_ACTION_CHILD_SERIALIZED, entry_ptr->flush_dep_parent[u]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag set")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__mark_flush_dep_serialized() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__mark_flush_dep_unserialized()
+ *
+ * Purpose: Decrement the flush_dep_nunser_children fields of all the
+ * target entry's flush dependency parents in response to
+ * the target entry becoming unserialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/30/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__mark_flush_dep_unserialized(H5C_cache_entry_t * entry_ptr)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+
+ /* Iterate over the parent entries, if any */
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++) {
+ /* Sanity check */
+ HDassert(entry_ptr->flush_dep_parent);
+ HDassert(entry_ptr->flush_dep_parent[u]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children <
+ entry_ptr->flush_dep_parent[u]->flush_dep_nchildren);
+
+ /* increment parents number of usserialized children */
+ entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children++;
+
+ /* If the parent has a 'notify' callback, send a 'child entry unserialized' notice */
+ if(entry_ptr->flush_dep_parent[u]->type->notify &&
+ (entry_ptr->flush_dep_parent[u]->type->notify)(H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED, entry_ptr->flush_dep_parent[u]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag reset")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__mark_flush_dep_unserialized() */
+
+
+#ifndef NDEBUG
+/*-------------------------------------------------------------------------
+ * Function: H5C__assert_flush_dep_nocycle()
+ *
+ * Purpose: Assert recursively that base_entry is not the same as
+ * entry, and perform the same assertion on all of entry's
+ * flush dependency parents. This is used to detect cycles
+ * created by flush dependencies.
+ *
+ * Return: void
+ *
+ * Programmer: Neil Fortner
+ * 12/10/12
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5C__assert_flush_dep_nocycle(const H5C_cache_entry_t * entry,
+ const H5C_cache_entry_t * base_entry)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(entry);
+ HDassert(base_entry);
+
+ /* Make sure the entries are not the same */
+ HDassert(base_entry != entry);
+
+ /* Iterate over entry's parents (if any) */
+ for(u = 0; u < entry->flush_dep_nparents; u++)
+ H5C__assert_flush_dep_nocycle(entry->flush_dep_parent[u], base_entry);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5C__assert_flush_dep_nocycle() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__serialize_cache
+ *
+ * Purpose: Serialize (i.e. construct an on disk image) for all entries
+ * in the metadata cache including clean entries.
+ *
+ * Note that flush dependencies and "flush me last" flags
+ * must be observed in the serialization process.
+ *
+ * Note also that entries may be loaded, flushed, evicted,
+ * expunged, relocated, resized, or removed from the cache
+ * during this process, just as these actions may occur during
+ * a regular flush.
+ *
+ * However, we are given that the cache will contain no protected
+ * entries on entry to this routine (although entries may be
+ * briefly protected and then unprotected during the serialize
+ * process).
+ *
+ * The objective of this routine is serialize all entries and
+ * to force all entries into their actual locations on disk.
+ *
+ * The initial need for this routine is to settle all entries
+ * in the cache prior to construction of the metadata cache
+ * image so that the size of the cache image can be calculated.
+ * However, I gather that other uses for the routine are
+ * under consideration.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 7/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__serialize_cache(H5F_t *f, hid_t dxpl_id)
+{
+#if H5C_DO_SANITY_CHECKS
+ int i;
+ uint32_t index_len = 0;
+ size_t index_size = (size_t)0;
+ size_t clean_index_size = (size_t)0;
+ size_t dirty_index_size = (size_t)0;
+ size_t slist_size = (size_t)0;
+ uint32_t slist_len = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+ H5C_ring_t ring;
+ H5C_t * cache_ptr;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+
+ for(i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) {
+ index_len += cache_ptr->index_ring_len[i];
+ index_size += cache_ptr->index_ring_size[i];
+ clean_index_size += cache_ptr->clean_index_ring_size[i];
+ dirty_index_size += cache_ptr->dirty_index_ring_size[i];
+
+ slist_len += cache_ptr->slist_ring_len[i];
+ slist_size += cache_ptr->slist_ring_size[i];
+ } /* end for */
+
+ HDassert(cache_ptr->index_len == index_len);
+ HDassert(cache_ptr->index_size == index_size);
+ HDassert(cache_ptr->clean_index_size == clean_index_size);
+ HDassert(cache_ptr->dirty_index_size == dirty_index_size);
+ HDassert(cache_ptr->slist_len == slist_len);
+ HDassert(cache_ptr->slist_size == slist_size);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+#ifndef NDEBUG
+ /* if this is a debug build, set the serialization_count field of
+ * each entry in the cache to zero before we start the serialization.
+ * This allows us to detect the case in which any entry is serialized
+ * more than once (a performance issues), and more importantly, the
+ * case is which any flush depencency parent is serializes more than
+ * once (a correctness issue).
+ */
+ {
+ H5C_cache_entry_t * scan_ptr = NULL;
+
+ scan_ptr = cache_ptr->il_head;
+ while(scan_ptr != NULL) {
+ HDassert(scan_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ scan_ptr->serialization_count = 0;
+ scan_ptr = scan_ptr->il_next;
+ } /* end while */
+ } /* end block */
+#endif /* NDEBUG */
+
+ /* set cache_ptr->serialization_in_progress to TRUE, and back
+ * to FALSE at the end of the function. Must maintain this flag
+ * to support H5C_get_serialization_in_progress(), which is in
+ * turn required to support sanity checking in some cache
+ * clients.
+ */
+ HDassert(!cache_ptr->serialization_in_progress);
+ cache_ptr->serialization_in_progress = TRUE;
+
+ /* Serialize each ring, starting from the outermost ring and
+ * working inward.
+ */
+ ring = H5C_RING_USER;
+ while(ring < H5C_RING_NTYPES) {
+ HDassert(cache_ptr->close_warning_received);
+ switch(ring) {
+ case H5C_RING_USER:
+ break;
+
+ case H5C_RING_RDFSM:
+ /* Settle raw data FSM */
+ if(!cache_ptr->rdfsm_settled)
+ if(H5MF_settle_raw_data_fsm(f, dxpl_id, &cache_ptr->rdfsm_settled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "RD FSM settle failed")
+ break;
+
+ case H5C_RING_MDFSM:
+ /* Settle metadata FSM */
+ if(!cache_ptr->mdfsm_settled)
+ if(H5MF_settle_meta_data_fsm(f, dxpl_id, &cache_ptr->mdfsm_settled) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "MD FSM settle failed")
+ break;
+
+ case H5C_RING_SBE:
+ case H5C_RING_SB:
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown ring?!?!")
+ break;
+ } /* end switch */
+
+ if(H5C__serialize_ring(f, dxpl_id, ring) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "serialize ring failed")
+
+ ring++;
+ } /* end while */
+
+#ifndef NDEBUG
+ /* Verify that no entry has been serialized more than once.
+ * FD parents with multiple serializations should have been caught
+ * elsewhere, so no specific check for them here.
+ */
+ {
+ H5C_cache_entry_t * scan_ptr = NULL;
+
+ scan_ptr = cache_ptr->il_head;
+ while(scan_ptr != NULL) {
+ HDassert(scan_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(scan_ptr->serialization_count <= 1);
+
+ scan_ptr = scan_ptr->il_next;
+ } /* end while */
+ } /* end block */
+#endif /* NDEBUG */
+
+done:
+ cache_ptr->serialization_in_progress = FALSE;
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__serialize_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__serialize_ring
+ *
+ * Purpose: Serialize the entries contained in the specified cache and
+ * ring. All entries in rings outside the specified ring
+ * must have been serialized on entry.
+ *
+ * If the cache contains protected entries in the specified
+ * ring, the function will fail, as protected entries cannot
+ * be serialized. However all unprotected entries in the
+ * target ring should be serialized before the function
+ * returns failure.
+ *
+ * If flush dependencies appear in the target ring, the
+ * function makes repeated passes through the index list
+ * serializing entries in flush dependency order.
+ *
+ * All entries outside the H5C_RING_SBE are marked for
+ * inclusion in the cache image. Entries in H5C_RING_SBE
+ * and below are marked for exclusion from the image.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 9/11/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__serialize_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring)
+{
+ hbool_t done = FALSE;
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(ring > H5C_RING_UNDEFINED);
+ HDassert(ring < H5C_RING_NTYPES);
+
+ HDassert(cache_ptr->serialization_in_progress);
+
+ /* The objective here is to serialize all entries in the cache ring
+ * in flush dependency order.
+ *
+ * The basic algorithm is to scan the cache index list looking for
+ * unserialized entries that are either not in a flush dependency
+ * relationship, or which have no unserialized children. Any such
+ * entry is serialized and its flush dependency parents (if any) are
+ * informed -- allowing them to decrement their userialized child counts.
+ *
+ * However, this algorithm is complicated by the ability
+ * of client serialization callbacks to perform operations on
+ * on the cache which can result in the insertion, deletion,
+ * relocation, resize, dirty, flush, eviction, or removal (via the
+ * take ownership flag) of entries. Changes in the flush dependency
+ * structure are also possible.
+ *
+ * On the other hand, the algorithm is simplified by the fact that
+ * we are serializing, not flushing. Thus, as long as all entries
+ * are serialized correctly, it doesn't matter if we have to go back
+ * and serialize an entry a second time.
+ *
+ * These possible actions result in the following modfications to
+ * tha basic algorithm:
+ *
+ * 1) In the event of an entry expunge, eviction or removal, we must
+ * restart the scan as it is possible that the next entry in our
+ * scan is no longer in the cache. Were we to examine this entry,
+ * we would be accessing deallocated memory.
+ *
+ * 2) A resize, dirty, or insertion of an entry may result in the
+ * the increment of a flush dependency parent's dirty and/or
+ * unserialized child count. In the context of serializing the
+ * the cache, this is a non-issue, as even if we have already
+ * serialized the parent, it will be marked dirty and its image
+ * marked out of date if appropriate when the child is serialized.
+ *
+ * However, this is a major issue for a flush, as were this to happen
+ * in a flush, it would violate the invariant that the flush dependency
+ * feature is intended to enforce. As the metadata cache has no
+ * control over the behavior of cache clients, it has no way of
+ * preventing this behaviour. However, it should detect it if at all
+ * possible.
+ *
+ * Do this by maintaining a count of the number of times each entry is
+ * serialized during a cache serialization. If any flush dependency
+ * parent is serialized more than once, throw an assertion failure.
+ *
+ * 3) An entry relocation will typically change the location of the
+ * entry in the index list. This shouldn't cause problems as we
+ * will scan the index list until we make a complete pass without
+ * finding anything to serialize -- making relocations of either
+ * the current or next entries irrelevant.
+ *
+ * Note that since a relocation may result in our skipping part of
+ * the index list, we must always do at least one more pass through
+ * the index list after an entry relocation.
+ *
+ * 4) Changes in the flush dependency structure are possible on
+ * entry insertion, load, expunge, evict, or remove. Destruction
+ * of a flush dependency has no effect, as it can only relax the
+ * flush dependencies. Creation of a flush dependency can create
+ * an unserialized child of a flush dependency parent where all
+ * flush dependency children were previously serialized. Should
+ * this child dirty the flush dependency parent when it is serialized,
+ * the parent will be re-serialized.
+ *
+ * Per the discussion of 2) above, this is a non issue for cache
+ * serialization, and a major problem for cache flush. Using the
+ * same detection mechanism, throw an assertion failure if this
+ * condition appears.
+ *
+ * Observe that either eviction or removal of entries as a result of
+ * a serialization is not a problem as long as the flush depencency
+ * tree does not change beyond the removal of a leaf.
+ */
+ while(!done) {
+ /* Reset the counters so that we can detect insertions, loads,
+ * moves, and flush dependency height changes caused by the pre_serialize
+ * and serialize callbacks.
+ */
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ done = TRUE; /* set to FALSE if any activity in inner loop */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Verify that either the entry is already serialized, or
+ * that it is assigned to either the target or an inner
+ * ring.
+ */
+ HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date));
+
+ /* Skip flush me last entries or inner ring entries */
+ if(!entry_ptr->flush_me_last && entry_ptr->ring == ring) {
+
+ /* if we encounter an unserialized entry in the current
+ * ring that is not marked flush me last, we are not done.
+ */
+ if(!entry_ptr->image_up_to_date)
+ done = FALSE;
+
+ /* Serialize the entry if its image is not up to date
+ * and it has no unserialized flush dependency children.
+ */
+ if(!entry_ptr->image_up_to_date && entry_ptr->flush_dep_nunser_children == 0) {
+ HDassert(entry_ptr->serialization_count == 0);
+
+ /* Serialize the entry */
+ if(H5C__serialize_single_entry(f, dxpl_id, cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "entry serialization failed")
+
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+ HDassert(entry_ptr->serialization_count == 0);
+
+#ifndef NDEBUG
+ /* Increment serialization counter (to detect multiple serializations) */
+ entry_ptr->serialization_count++;
+#endif /* NDEBUG */
+ } /* end if */
+ } /* end if */
+
+ /* Check for the cache being perturbed during the entry serialize */
+ if((cache_ptr->entries_loaded_counter > 0) ||
+ (cache_ptr->entries_inserted_counter > 0) ||
+ (cache_ptr->entries_relocated_counter > 0)) {
+
+#if H5C_COLLECT_CACHE_STATS
+ H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr);
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ /* Reset the counters */
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ /* Restart scan */
+ entry_ptr = cache_ptr->il_head;
+ } /* end if */
+ else
+ /* Advance to next entry */
+ entry_ptr = entry_ptr->il_next;
+ } /* while ( entry_ptr != NULL ) */
+ } /* while ( ! done ) */
+
+
+ /* Reset the counters so that we can detect insertions, loads,
+ * moves, and flush dependency height changes caused by the pre_serialize
+ * and serialize callbacks.
+ */
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ /* At this point, all entries not marked "flush me last" and in
+ * the current ring or outside it should be serialized and have up
+ * to date images. Scan the index list again to serialize the
+ * "flush me last" entries (if they are in the current ring) and to
+ * verify that all other entries have up to date images.
+ */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring > H5C_RING_UNDEFINED);
+ HDassert(entry_ptr->ring < H5C_RING_NTYPES);
+ HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date));
+
+ if(entry_ptr->ring == ring) {
+ if(entry_ptr->flush_me_last) {
+ if(!entry_ptr->image_up_to_date) {
+ HDassert(entry_ptr->serialization_count == 0);
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+
+ /* Serialize the entry */
+ if(H5C__serialize_single_entry(f, dxpl_id, cache_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "entry serialization failed")
+
+ /* Check for the cache changing */
+ if((cache_ptr->entries_loaded_counter > 0) ||
+ (cache_ptr->entries_inserted_counter > 0) ||
+ (cache_ptr->entries_relocated_counter > 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flush_me_last entry serialization triggered restart")
+
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+ HDassert(entry_ptr->serialization_count == 0);
+#ifndef NDEBUG
+ /* Increment serialization counter (to detect multiple serializations) */
+ entry_ptr->serialization_count++;
+#endif /* NDEBUG */
+ } /* end if */
+ } /* end if */
+ else {
+ HDassert(entry_ptr->image_up_to_date);
+ HDassert(entry_ptr->serialization_count <= 1);
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+ } /* end else */
+ } /* if ( entry_ptr->ring == ring ) */
+
+ entry_ptr = entry_ptr->il_next;
+ } /* while ( entry_ptr != NULL ) */
+
+done:
+ HDassert(cache_ptr->serialization_in_progress);
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__serialize_ring() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__serialize_single_entry
+ *
+ * Purpose: Serialize the cache entry pointed to by the entry_ptr
+ * parameter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer, 7/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__serialize_single_entry(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr,
+ H5C_cache_entry_t *entry_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(!entry_ptr->prefetched);
+ HDassert(!entry_ptr->image_up_to_date);
+ HDassert(entry_ptr->is_dirty);
+ HDassert(!entry_ptr->is_protected);
+ HDassert(!entry_ptr->flush_in_progress);
+ HDassert(entry_ptr->type);
+
+ /* Set entry_ptr->flush_in_progress to TRUE so the the target entry
+ * will not be evicted out from under us. Must set it back to FALSE
+ * when we are done.
+ */
+ entry_ptr->flush_in_progress = TRUE;
+
+ /* Allocate buffer for the entry image if required. */
+ if(NULL == entry_ptr->image_ptr) {
+ HDassert(entry_ptr->size > 0);
+ if(NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE)) )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + image_size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+ } /* end if */
+
+ /* Generate image for entry */
+ if(H5C__generate_image(f, cache_ptr, entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "Can't generate image for cache entry")
+
+ /* Reset the flush_in progress flag */
+ entry_ptr->flush_in_progress = FALSE;
+
+done:
+ HDassert((ret_value != SUCCEED) || (!entry_ptr->flush_in_progress));
+ HDassert((ret_value != SUCCEED) || (entry_ptr->image_up_to_date));
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__serialize_single_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__generate_image
+ *
+ * Purpose: Serialize an entry and generate its image.
+ *
+ * Note: This may cause the entry to be re-sized and/or moved in
+ * the cache.
+ *
+ * As we will not update the metadata cache's data structures
+ * until we we finish the write, we must touch up these
+ * data structures for size and location changes even if we
+ * are about to delete the entry from the cache (i.e. on a
+ * flush destroy).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * 2/10/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr,
+ hid_t dxpl_id)
+{
+ haddr_t new_addr = HADDR_UNDEF;
+ haddr_t old_addr = HADDR_UNDEF;
+ size_t new_len = 0;
+ unsigned serialize_flags = H5C__SERIALIZE_NO_FLAGS_SET;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(!entry_ptr->image_up_to_date);
+ HDassert(entry_ptr->is_dirty);
+ HDassert(!entry_ptr->is_protected);
+ HDassert(entry_ptr->type);
+
+ /* make note of the entry's current address */
+ old_addr = entry_ptr->addr;
+
+ /* Call client's pre-serialize callback, if there's one */
+ if(entry_ptr->type->pre_serialize &&
+ (entry_ptr->type->pre_serialize)(f, dxpl_id, (void *)entry_ptr,
+ entry_ptr->addr, entry_ptr->size, &new_addr, &new_len, &serialize_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to pre-serialize entry")
+
+ /* Check for any flags set in the pre-serialize callback */
+ if(serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET) {
+ /* Check for unexpected flags from serialize callback */
+ if(serialize_flags & ~(H5C__SERIALIZE_RESIZED_FLAG | H5C__SERIALIZE_MOVED_FLAG))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unknown serialize flag(s)")
+
+#ifdef H5_HAVE_PARALLEL
+ /* In the parallel case, resizes and moves in
+ * the serialize operation can cause problems.
+ * If they occur, scream and die.
+ *
+ * At present, in the parallel case, the aux_ptr
+ * will only be set if there is more than one
+ * process. Thus we can use this to detect
+ * the parallel case.
+ *
+ * This works for now, but if we start using the
+ * aux_ptr for other purposes, we will have to
+ * change this test accordingly.
+ *
+ * NB: While this test detects entryies that attempt
+ * to resize or move themselves during a flush
+ * in the parallel case, it will not detect an
+ * entry that dirties, resizes, and/or moves
+ * other entries during its flush.
+ *
+ * From what Quincey tells me, this test is
+ * sufficient for now, as any flush routine that
+ * does the latter will also do the former.
+ *
+ * If that ceases to be the case, further
+ * tests will be necessary.
+ */
+ if(cache_ptr->aux_ptr != NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "resize/move in serialize occured in parallel case")
+#endif
+
+ /* If required, resize the buffer and update the entry and the cache
+ * data structures */
+ if(serialize_flags & H5C__SERIALIZE_RESIZED_FLAG) {
+ /* Sanity check */
+ HDassert(new_len > 0);
+
+ /* Allocate a new image buffer */
+ if(NULL == (entry_ptr->image_ptr = H5MM_realloc(entry_ptr->image_ptr, new_len + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + new_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+ /* Update statistics for resizing the entry */
+ H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_len);
+
+ /* Update the hash table for the size change */
+ H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len, entry_ptr, !(entry_ptr->is_dirty));
+
+ /* The entry can't be protected since we are in the process of
+ * flushing it. Thus we must update the replacement policy data
+ * structures for the size change. The macro deals with the pinned
+ * case.
+ */
+ H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_len);
+
+ /* As we haven't updated the cache data structures for
+ * for the flush or flush destroy yet, the entry should
+ * be in the slist. Thus update it for the size change.
+ */
+ HDassert(entry_ptr->is_dirty);
+ HDassert(entry_ptr->in_slist);
+ H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len);
+
+ /* Finally, update the entry for its new size */
+ entry_ptr->size = new_len;
+ } /* end if */
+
+ /* If required, udate the entry and the cache data structures
+ * for a move
+ */
+ if(serialize_flags & H5C__SERIALIZE_MOVED_FLAG) {
+ /* Update stats and entries relocated counter */
+ H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr)
+
+ /* We must update cache data structures for the change in address */
+ if(entry_ptr->addr == old_addr) {
+ /* Delete the entry from the hash table and the slist */
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL);
+ H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE);
+
+ /* Update the entry for its new address */
+ entry_ptr->addr = new_addr;
+
+ /* And then reinsert in the index and slist */
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL);
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL);
+ } /* end if */
+ else /* move is already done for us -- just do sanity checks */
+ HDassert(entry_ptr->addr == new_addr);
+ } /* end if */
+ } /* end if(serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET) */
+
+ /* Serialize object into buffer */
+ if(entry_ptr->type->serialize(f, entry_ptr->image_ptr, entry_ptr->size, (void *)entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to serialize entry")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDassert(0 == HDmemcmp(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE));
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+ entry_ptr->image_up_to_date = TRUE;
+
+ /* Propagate the fact that the entry is serialized up the
+ * flush dependency chain if appropriate. Since the image must
+ * have been out of date for this function to have been called
+ * (see assertion on entry), no need to check that -- only check
+ * for flush dependency parents.
+ */
+ HDassert(entry_ptr->flush_dep_nunser_children == 0);
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_serialized(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__generate_image */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_remove_entry
+ *
+ * Purpose: Remove an entry from the cache. Must be not protected, pinned,
+ * dirty, involved in flush dependencies, etc.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_remove_entry(void *_entry)
+{
+ H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_entry; /* Entry to remove */
+ H5C_t *cache; /* Cache for file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(entry);
+ HDassert(entry->ring != H5C_RING_UNDEFINED);
+ cache = entry->cache_ptr;
+ HDassert(cache);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Check for error conditions */
+ if(entry->is_dirty)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove dirty entry from cache")
+ if(entry->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove protected entry from cache")
+ if(entry->is_pinned)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove pinned entry from cache")
+ if(entry->flush_dep_nparents > 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry with flush dependency parents from cache")
+ if(entry->flush_dep_nchildren > 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry with flush dependency children from cache")
+
+ /* Additional internal cache consistency checks */
+ HDassert(!entry->in_slist);
+ HDassert(!entry->flush_marker);
+ HDassert(!entry->flush_in_progress);
+
+ /* Note that the algorithm below is (very) similar to the set of operations
+ * in H5C__flush_single_entry() and should be kept in sync with changes
+ * to that code. - QAK, 2016/11/30
+ */
+
+ /* Update stats, as if we are "destroying" and taking ownership of the entry */
+ H5C__UPDATE_STATS_FOR_EVICTION(cache, entry, TRUE)
+
+ /* If the entry's type has a 'notify' callback, send a 'before eviction'
+ * notice while the entry is still fully integrated in the cache.
+ */
+ if(entry->type->notify && (entry->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry to evict")
+
+ /* Update the cache internal data structures as appropriate for a destroy.
+ * Specifically:
+ * 1) Delete it from the index
+ * 2) Delete it from the collective read access list
+ * 3) Update the replacement policy for eviction
+ * 4) Remove it from the tag list for this object
+ */
+
+ H5C__DELETE_FROM_INDEX(cache, entry, FAIL)
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check for collective read access flag */
+ if(entry->coll_access) {
+ entry->coll_access = FALSE;
+ H5C__REMOVE_FROM_COLL_LIST(cache, entry, FAIL)
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ H5C__UPDATE_RP_FOR_EVICTION(cache, entry, FAIL)
+
+ /* Remove entry from tag list */
+ if(H5C__untag_entry(cache, entry) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list")
+
+ /* Increment entries_removed_counter and set last_entry_removed_ptr.
+ * As we me be about to free the entry, recall that last_entry_removed_ptr
+ * must NEVER be dereferenced.
+ *
+ * Recall that these fields are maintained to allow functions that perform
+ * scans of lists of entries to detect the unexpected removal of entries
+ * (via expunge, eviction, or take ownership at present), so that they can
+ * re-start their scans if necessary.
+ *
+ * Also check if the entry we are watching for removal is being
+ * removed (usually the 'next' entry for an iteration) and reset
+ * it to indicate that it was removed.
+ */
+ cache->entries_removed_counter++;
+ cache->last_entry_removed_ptr = entry;
+ if(entry == cache->entry_watched_for_removal)
+ cache->entry_watched_for_removal = NULL;
+
+ /* Internal cache data structures should now be up to date, and
+ * consistant with the status of the entry.
+ *
+ * Now clean up internal cache fields if appropriate.
+ */
+
+ /* Free the buffer for the on disk image */
+ if(entry->image_ptr != NULL)
+ entry->image_ptr = H5MM_xfree(entry->image_ptr);
+
+ /* Reset the pointer to the cache the entry is within */
+ entry->cache_ptr = NULL;
+
+ /* Client is taking ownership of the entry. Set bad magic here so the
+ * cache will choke unless the entry is re-inserted properly
+ */
+ entry->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__remove_entry() */
+
diff --git a/src/H5CS.c b/src/H5CS.c
new file mode 100644
index 0000000..0a3dcce
--- /dev/null
+++ b/src/H5CS.c
@@ -0,0 +1,330 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Provides internal function tracing in the form of a stack.
+ * The FUNC_ENTER() macro adds the function name to the function
+ * stack whenever a function is entered.
+ * As the functions return with FUNC_LEAVE,
+ * entries are removed from the stack.
+ *
+ * A function stack has a fixed maximum size. If this size is
+ * exceeded then the stack will be truncated and only the
+ * first called functions will have entries on the stack. This is
+ * expected to be a rare condition.
+ *
+ */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5CSprivate.h" /* Function stack */
+#include "H5Eprivate.h" /* Error handling */
+
+#ifdef H5_HAVE_CODESTACK
+
+#define H5CS_MIN_NSLOTS 16 /* Minimum number of records in an function stack */
+
+/* A function stack */
+typedef struct H5CS_t {
+ unsigned nused; /* Number of records currently used in stack */
+ unsigned nalloc; /* Number of records current allocated for stack */
+ const char **rec; /* Array of function records */
+} H5CS_t;
+
+#ifdef H5_HAVE_THREADSAFE
+/*
+ * The per-thread function stack. pthread_once() initializes a special
+ * key that will be used by all threads to create a stack specific to
+ * each thread individually. The association of stacks to threads will
+ * be handled by the pthread library.
+ *
+ * In order for this macro to work, H5CS_get_my_stack() must be preceeded
+ * by "H5CS_t *fstack =".
+ */
+static H5CS_t *H5CS__get_stack(void);
+#define H5CS_get_my_stack() H5CS__get_stack()
+#else /* H5_HAVE_THREADSAFE */
+/*
+ * The function stack. Eventually we'll have some sort of global table so each
+ * thread has it's own stack. The stacks will be created on demand when the
+ * thread first calls H5CS_push(). */
+H5CS_t H5CS_stack_g[1];
+#define H5CS_get_my_stack() (H5CS_stack_g+0)
+#endif /* H5_HAVE_THREADSAFE */
+
+
+#ifdef H5_HAVE_THREADSAFE
+/*-------------------------------------------------------------------------
+ * Function: H5CS__get_stack
+ *
+ * Purpose: Support function for H5CS_get_my_stack() to initialize and
+ * acquire per-thread function stack.
+ *
+ * Return: Success: function stack (H5CS_t *)
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5CS_t *
+H5CS__get_stack(void)
+{
+ H5CS_t *fstack;
+
+ FUNC_ENTER_STATIC_NOERR_NOFS
+
+ fstack = H5TS_get_thread_local_value(H5TS_funcstk_key_g);
+ if(!fstack) {
+ /* No associated value with current thread - create one */
+#ifdef H5_HAVE_WIN_THREADS
+ fstack = (H5CS_t *)LocalAlloc(LPTR, sizeof(H5CS_t)); /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */
+#else
+ fstack = (H5CS_t *)HDmalloc(sizeof(H5CS_t)); /* Don't use H5MM_malloc() here, it causes infinite recursion */
+#endif /* H5_HAVE_WIN_THREADS */
+ HDassert(fstack);
+
+ /* Set the thread-specific info */
+ fstack->nused = 0;
+ fstack->nalloc = 0;
+ fstack->rec = NULL;
+
+ /* (It's not necessary to release this in this API, it is
+ * released by the "key destructor" set up in the H5TS
+ * routines. See calls to pthread_key_create() in H5TS.c -QAK)
+ */
+ H5TS_set_thread_local_value(H5TS_funcstk_key_g, (void *)fstack);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_NOFS(fstack)
+} /* end H5CS__get_stack() */
+#endif /* H5_HAVE_THREADSAFE */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5CS_print_stack
+ *
+ * Purpose: Prints a function stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 6, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5CS_print_stack(const H5CS_t *fstack, FILE *stream)
+{
+ const int indent = 2; /* Indention level */
+ int i; /* Local index ariable */
+
+ /* Don't push this function on the function stack... :-) */
+ FUNC_ENTER_NOAPI_NOERR_NOFS
+
+ /* Sanity check */
+ HDassert(fstack);
+
+ /* Default to outputting information to stderr */
+ if(!stream)
+ stream = stderr;
+
+ HDfprintf(stream, "HDF5-DIAG: Function stack from %s ", H5_lib_vers_info_g);
+ /* try show the process or thread id in multiple processes cases*/
+#ifdef H5_HAVE_THREADSAFE
+ HDfprintf(stream, "thread %lu.", HDpthread_self_ulong());
+#else /* H5_HAVE_THREADSAFE */
+ HDfprintf(stream, "thread 0.");
+#endif /* H5_HAVE_THREADSAFE */
+ if(fstack && fstack->nused>0)
+ HDfprintf(stream, " Back trace follows.");
+ HDfputc('\n', stream);
+
+ for(i = fstack->nused - 1; i >= 0; --i)
+ HDfprintf(stream, "%*s#%03d: Routine: %s\n", indent, "", i, fstack->rec[i]);
+
+ FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
+} /* end H5CS_print_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5CS_push
+ *
+ * Purpose: Pushes a new record onto function stack for the current
+ * thread.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5CS_push(const char *func_name)
+{
+ H5CS_t *fstack = H5CS_get_my_stack(); /* Current function stack for library */
+
+ /* Don't push this function on the function stack... :-) */
+ FUNC_ENTER_NOAPI_NOERR_NOFS
+
+ /* Sanity check */
+ HDassert(fstack);
+ HDassert(fstack->nused <= fstack->nalloc);
+ HDassert(func_name);
+
+ /* Check if we need to expand the stack of records */
+ if(fstack->nused == fstack->nalloc) {
+ size_t na = MAX((fstack->nalloc * 2), H5CS_MIN_NSLOTS);
+
+ /* Don't use H5MM_realloc here */
+ const char **x = (const char **)HDrealloc(fstack->rec, na * sizeof(const char *));
+
+ /* (Avoid returning an error from this routine, currently -QAK) */
+ HDassert(x);
+ fstack->rec = x;
+ fstack->nalloc = na;
+ } /* end if */
+
+ /* Push the function name */
+ fstack->rec[fstack->nused] = func_name;
+ fstack->nused++;
+
+ FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
+} /* end H5CS_push() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5CS_pop
+ *
+ * Purpose: Pops a record off function stack for the current thread.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 6, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5CS_pop(void)
+{
+ H5CS_t *fstack = H5CS_get_my_stack();
+
+ /* Don't push this function on the function stack... :-) */
+ FUNC_ENTER_NOAPI_NOERR_NOFS
+
+ /* Sanity check */
+ HDassert(fstack);
+ HDassert(fstack->nused > 0);
+
+ /* Pop the function. */
+ fstack->nused--;
+
+ FUNC_LEAVE_NOAPI_NOFS(SUCCEED);
+} /* end H5CS_pop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5CS_copy_stack
+ *
+ * Purpose: Makes a copy of the current stack
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 9, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5CS_t *
+H5CS_copy_stack(void)
+{
+ H5CS_t *old_stack = H5CS_get_my_stack(); /* Existing function stack for library */
+ H5CS_t *new_stack; /* New function stack, for copy */
+ unsigned u; /* Local index variable */
+ H5CS_t *ret_value = NULL; /* Return value */
+
+ /* Don't push this function on the function stack... :-) */
+ FUNC_ENTER_NOAPI_NOFS
+
+ /* Sanity check */
+ HDassert(old_stack);
+
+ /* Allocate a new stack */
+ /* (Don't use library allocate code, since this code stack supports it) */
+ if(NULL == (new_stack = HDcalloc(1, sizeof(H5CS_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate function stack")
+ if(NULL == (new_stack->rec = HDcalloc(old_stack->nused, sizeof(const char *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate function stack records")
+
+ /* Copy old stack to new one, duplicating the strings */
+ for(u = 0; u < old_stack->nused; u++)
+ new_stack->rec[u] = HDstrdup(old_stack->rec[u]);
+ new_stack->nused = new_stack->nalloc = old_stack->nused;
+
+ /* Set the return value */
+ ret_value = new_stack;
+
+done:
+ FUNC_LEAVE_NOAPI_NOFS(ret_value)
+} /* end H5CS_copy_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5CS_close_stack
+ *
+ * Purpose: Closes and frees a copy of a stack
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 9, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5CS_close_stack(H5CS_t *stack)
+{
+ unsigned u; /* Local index variable */
+
+ /* Don't push this function on the function stack... :-) */
+ FUNC_ENTER_NOAPI_NOERR_NOFS
+
+ /* Sanity check */
+ HDassert(stack);
+
+ /* Free stack */
+ for(u = 0; u < stack->nused; u++) {
+ if(stack->rec[u])
+ HDfree((void *)stack->rec[u]);
+ stack->rec[u] = NULL;
+ } /* end for */
+ if(stack->rec) {
+ HDfree(stack->rec);
+ stack->rec = NULL;
+ } /* end if */
+ if(stack)
+ HDfree(stack);
+
+ FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
+} /* end H5CS_close_stack() */
+
+#endif /* H5_HAVE_CODESTACK */
+
diff --git a/src/H5CSprivate.h b/src/H5CSprivate.h
new file mode 100644
index 0000000..467dd9d
--- /dev/null
+++ b/src/H5CSprivate.h
@@ -0,0 +1,36 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Header file for function stacks, etc.
+ */
+#ifndef _H5CSprivate_H
+#define _H5CSprivate_H
+
+#ifdef NOT_YET
+#include "H5CSpublic.h"
+#endif /* NOT_YET */
+
+/* Private headers needed by this file */
+#include "H5private.h"
+
+/* Forward declarations for structure fields */
+struct H5CS_t;
+H5_DLL herr_t H5CS_push(const char *func_name);
+H5_DLL herr_t H5CS_pop(void);
+H5_DLL herr_t H5CS_print_stack(const struct H5CS_t *stack, FILE *stream);
+H5_DLL struct H5CS_t *H5CS_copy_stack(void);
+H5_DLL herr_t H5CS_close_stack(struct H5CS_t *stack);
+
+#endif /* _H5CSprivate_H */
+
diff --git a/src/H5Cdbg.c b/src/H5Cdbg.c
new file mode 100644
index 0000000..4a08d9b
--- /dev/null
+++ b/src/H5Cdbg.c
@@ -0,0 +1,1597 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cdbg.c
+ * July 8 2016
+ * Quincey Koziol
+ *
+ * Purpose: Debugging Routines for the generic cache structure or entries.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+
+#define H5AC_FRIEND
+
+
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACpkg.h" /* Metadata Cache */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error Handling */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef NDEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dump_cache
+ *
+ * Purpose: Print a summary of the contents of the metadata cache for
+ * debugging purposes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 10/10/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_dump_cache(H5C_t * cache_ptr, const char * cache_name)
+{
+ H5C_cache_entry_t * entry_ptr;
+ H5SL_t * slist_ptr = NULL;
+ int i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_name != NULL );
+
+ /* First, create a skip list */
+ if(NULL == (slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create skip list")
+
+ /* Next, scan the index, and insert all entries in the skip list.
+ * Do this, as we want to display cache entries in increasing address
+ * order.
+ */
+ for(i = 0; i < H5C__HASH_TABLE_LEN; i++) {
+ entry_ptr = cache_ptr->index[i];
+
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ if(H5SL_insert(slist_ptr, entry_ptr, &(entry_ptr->addr)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "can't insert entry in skip list")
+
+ entry_ptr = entry_ptr->ht_next;
+ } /* end while */
+ } /* end for */
+
+ /* If we get this far, all entries in the cache are listed in the
+ * skip list -- scan the skip list generating the desired output.
+ */
+
+ HDfprintf(stdout, "\n\nDump of metadata cache \"%s\"\n", cache_name);
+
+ /* Print header */
+ HDfprintf(stdout, "Entry ");
+ HDfprintf(stdout, "| Address ");
+ HDfprintf(stdout, "| Tag ");
+ HDfprintf(stdout, "| Size ");
+ HDfprintf(stdout, "| Ring ");
+ HDfprintf(stdout, "| Type ");
+ HDfprintf(stdout, "| Prot/Pin/Dirty");
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout, "----------------------------------------------------------------------------------------------------------------\n");
+
+ i = 0;
+ entry_ptr = (H5C_cache_entry_t *)H5SL_remove_first(slist_ptr);
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Print entry */
+ HDfprintf(stdout, "%s%5d ", cache_ptr->prefix, i);
+ HDfprintf(stdout, " 0x%16llx ", (long long)(entry_ptr->addr));
+ if(NULL == entry_ptr->tag_info)
+ HDfprintf(stdout, " %16s ", "N/A");
+ else
+ HDfprintf(stdout, " 0x%16llx ", (long long)(entry_ptr->tag_info->tag));
+ HDfprintf(stdout, " %5lld ", (long long)(entry_ptr->size));
+ HDfprintf(stdout, " %d ", (int)(entry_ptr->ring));
+ HDfprintf(stdout, " %2d %-32s ", (int)(entry_ptr->type->id), (entry_ptr->type->name));
+ HDfprintf(stdout, " %d", (int)(entry_ptr->is_protected));
+ HDfprintf(stdout, " %d", (int)(entry_ptr->is_pinned));
+ HDfprintf(stdout, " %d", (int)(entry_ptr->is_dirty));
+ HDfprintf(stdout, "\n");
+
+ /* remove the next (first) item in the skip list */
+ entry_ptr = (H5C_cache_entry_t *)H5SL_remove_first(slist_ptr);
+
+ i++;
+ } /* end while */
+
+ HDfprintf(stdout, "\n\n");
+
+ /* Verify that all the entries were removed from the skip list */
+ HDassert(H5SL_count(slist_ptr) == 0);
+
+done:
+ /* Discard the skip list */
+ if(slist_ptr)
+ H5SL_close(slist_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_dump_cache() */
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dump_cache_LRU
+ *
+ * Purpose: Print a summary of the contents of the metadata cache
+ * LRU for debugging purposes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 10/10/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_dump_cache_LRU(H5C_t *cache_ptr, const char *cache_name)
+{
+ H5C_cache_entry_t * entry_ptr;
+ int i = 0;
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity check */
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_name != NULL );
+
+ HDfprintf(stdout, "\n\nDump of metadata cache LRU \"%s\"\n", cache_name);
+ HDfprintf(stdout, "LRU len = %d, LRU size = %d\n",
+ cache_ptr->LRU_list_len, (int)(cache_ptr->LRU_list_size));
+ HDfprintf(stdout, "index_size = %d, max_cache_size = %d, delta = %d\n\n",
+ (int)(cache_ptr->index_size), (int)(cache_ptr->max_cache_size),
+ (int)(cache_ptr->max_cache_size) - (int)(cache_ptr->index_size));
+
+ /* Print header */
+ HDfprintf(stdout, "Entry ");
+ HDfprintf(stdout, "| Address ");
+ HDfprintf(stdout, "| Tag ");
+ HDfprintf(stdout, "| Size ");
+ HDfprintf(stdout, "| Ring ");
+ HDfprintf(stdout, "| Type ");
+ HDfprintf(stdout, "| Dirty");
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout, "----------------------------------------------------------------------------------------------------------------\n");
+
+ entry_ptr = cache_ptr->LRU_head_ptr;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Print entry */
+ HDfprintf(stdout, "%s%5d ", cache_ptr->prefix, i);
+ HDfprintf(stdout, " 0x%16llx ", (long long)(entry_ptr->addr));
+
+ if(NULL == entry_ptr->tag_info)
+ HDfprintf(stdout, " %16s ", "N/A");
+ else
+ HDfprintf(stdout, " 0x%16llx ",
+ (long long)(entry_ptr->tag_info->tag));
+
+ HDfprintf(stdout, " %5lld ", (long long)(entry_ptr->size));
+ HDfprintf(stdout, " %d ", (int)(entry_ptr->ring));
+ HDfprintf(stdout, " %2d %-32s ", (int)(entry_ptr->type->id),
+ (entry_ptr->type->name));
+ HDfprintf(stdout, " %d", (int)(entry_ptr->is_dirty));
+ HDfprintf(stdout, "\n");
+
+ i++;
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+
+ HDfprintf(stdout, "----------------------------------------------------------------------------------------------------------------\n");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C_dump_cache_LRU() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dump_cache_skip_list
+ *
+ * Purpose: Debugging routine that prints a summary of the contents of
+ * the skip list used by the metadata cache metadata cache to
+ * maintain an address sorted list of dirty entries.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 11/15/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_dump_cache_skip_list(H5C_t * cache_ptr, char * calling_fcn)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5SL_node_t * node_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(calling_fcn != NULL);
+
+ HDfprintf(stdout, "\n\nDumping metadata cache skip list from %s.\n", calling_fcn);
+ HDfprintf(stdout, " slist len = %u.\n", cache_ptr->slist_len);
+ HDfprintf(stdout, " slist size = %lld.\n", (long long)(cache_ptr->slist_size));
+
+ if(cache_ptr->slist_len > 0) {
+ /* If we get this far, all entries in the cache are listed in the
+ * skip list -- scan the skip list generating the desired output.
+ */
+ HDfprintf(stdout,
+ "Num: Addr: Len: Prot/Pind: Dirty: Type:\n");
+
+ i = 0;
+ node_ptr = H5SL_first(cache_ptr->slist_ptr);
+ if(node_ptr != NULL)
+ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+ else
+ entry_ptr = NULL;
+
+ while(entry_ptr != NULL) {
+ HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC );
+
+ HDfprintf(stdout,
+ "%s%d 0x%016llx %4lld %d/%d %d %s\n",
+ cache_ptr->prefix, i,
+ (long long)(entry_ptr->addr),
+ (long long)(entry_ptr->size),
+ (int)(entry_ptr->is_protected),
+ (int)(entry_ptr->is_pinned),
+ (int)(entry_ptr->is_dirty),
+ entry_ptr->type->name);
+
+ HDfprintf(stdout, " node_ptr = 0x%llx, item = %p\n",
+ (unsigned long long)node_ptr,
+ H5SL_item(node_ptr));
+
+ /* increment node_ptr before we delete its target */
+ node_ptr = H5SL_next(node_ptr);
+ if(node_ptr != NULL)
+ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+ else
+ entry_ptr = NULL;
+
+ i++;
+ } /* end while */
+ } /* end if */
+
+ HDfprintf(stdout, "\n\n");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_dump_cache_skip_list() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dump_coll_write_list
+ *
+ * Purpose: Debugging routine that prints a summary of the contents of
+ * the collective write skip list used by the metadata cache
+ * in the parallel case to maintain a list of entries to write
+ * collectively at a sync point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 4/1/17
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5_HAVE_PARALLEL
+#ifndef NDEBUG
+herr_t
+H5C_dump_coll_write_list(H5C_t * cache_ptr, char * calling_fcn)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ int i;
+ int list_len;
+ H5AC_aux_t * aux_ptr = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5SL_node_t * node_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->aux_ptr);
+
+ aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
+
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+
+ HDassert(calling_fcn != NULL);
+
+ list_len = (int)H5SL_count(cache_ptr->coll_write_list);
+
+ HDfprintf(stdout, "\n\nDumping MDC coll write list from %d:%s.\n",
+ aux_ptr->mpi_rank, calling_fcn);
+ HDfprintf(stdout, " slist len = %u.\n", cache_ptr->slist_len);
+
+ if ( list_len > 0 ) {
+
+ /* scan the collective write list generating the desired output */
+ HDfprintf(stdout,
+ "Num: Addr: Len: Prot/Pind: Dirty: Type:\n");
+
+ i = 0;
+
+ node_ptr = H5SL_first(cache_ptr->coll_write_list);
+
+ if ( node_ptr != NULL )
+
+ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+
+ else
+
+ entry_ptr = NULL;
+
+ while ( entry_ptr != NULL ) {
+
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ HDfprintf(stdout,
+ "%s%d 0x%016llx %4lld %d/%d %d %s\n",
+ cache_ptr->prefix, i,
+ (long long)(entry_ptr->addr),
+ (long long)(entry_ptr->size),
+ (int)(entry_ptr->is_protected),
+ (int)(entry_ptr->is_pinned),
+ (int)(entry_ptr->is_dirty),
+ entry_ptr->type->name);
+
+ node_ptr = H5SL_next(node_ptr);
+
+ if ( node_ptr != NULL )
+
+ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
+
+ else
+
+ entry_ptr = NULL;
+
+ i++;
+
+ } /* end while */
+ } /* end if */
+
+ HDfprintf(stdout, "\n\n");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_dump_coll_write_list() */
+#endif /* NDEBUG */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_prefix
+ *
+ * Purpose: Set the values of the prefix field of H5C_t. This
+ * filed is used to label some debugging output.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 1/20/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_prefix(H5C_t * cache_ptr, char * prefix)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC) ||
+ (prefix == NULL) || (HDstrlen(prefix) >= H5C__PREFIX_LEN))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad param(s) on entry")
+
+ HDstrncpy(&(cache_ptr->prefix[0]), prefix, (size_t)(H5C__PREFIX_LEN));
+
+ cache_ptr->prefix[H5C__PREFIX_LEN - 1] = '\0';
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_prefix() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_trace_file_ptr
+ *
+ * Purpose: Set the trace_file_ptr field for the cache.
+ *
+ * This field must either be NULL (which turns of trace
+ * file logging), or be a pointer to an open file to which
+ * trace file data is to be written.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 1/20/06
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_trace_file_ptr(H5C_t * cache_ptr, FILE * trace_file_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* This would normally be an assert, but we need to use an HGOTO_ERROR
+ * call to shut up the compiler.
+ */
+ if((NULL == cache_ptr) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr")
+
+ cache_ptr->trace_file_ptr = trace_file_ptr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_trace_file_ptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_stats
+ *
+ * Purpose: Prints statistics about the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_stats(H5C_t * cache_ptr,
+ const char * cache_name,
+ hbool_t
+#if !H5C_COLLECT_CACHE_STATS
+ H5_ATTR_UNUSED
+#endif /* H5C_COLLECT_CACHE_STATS */
+ display_detailed_stats)
+{
+#if H5C_COLLECT_CACHE_STATS
+ int i;
+ int64_t total_hits = 0;
+ int64_t total_misses = 0;
+ int64_t total_write_protects = 0;
+ int64_t total_read_protects = 0;
+ int64_t max_read_protects = 0;
+ int64_t total_insertions = 0;
+ int64_t total_pinned_insertions = 0;
+ int64_t total_clears = 0;
+ int64_t total_flushes = 0;
+ int64_t total_evictions = 0;
+ int64_t total_take_ownerships = 0;
+ int64_t total_moves = 0;
+ int64_t total_entry_flush_moves = 0;
+ int64_t total_cache_flush_moves = 0;
+ int64_t total_size_increases = 0;
+ int64_t total_size_decreases = 0;
+ int64_t total_entry_flush_size_changes = 0;
+ int64_t total_cache_flush_size_changes = 0;
+ int64_t total_pins = 0;
+ int64_t total_unpins = 0;
+ int64_t total_dirty_pins = 0;
+ int64_t total_pinned_flushes = 0;
+ int64_t total_pinned_clears = 0;
+ int32_t aggregate_max_accesses = 0;
+ int32_t aggregate_min_accesses = 1000000;
+ int32_t aggregate_max_clears = 0;
+ int32_t aggregate_max_flushes = 0;
+ size_t aggregate_max_size = 0;
+ int32_t aggregate_max_pins = 0;
+ double hit_rate;
+ double prefetch_use_rate;
+ double average_successful_search_depth = 0.0f;
+ double average_failed_search_depth = 0.0f;
+ double average_entries_skipped_per_calls_to_msic = 0.0f;
+ double average_dirty_pf_entries_skipped_per_call_to_msic = 0.0f;
+ double average_entries_scanned_per_calls_to_msic = 0.0f;
+#endif /* H5C_COLLECT_CACHE_STATS */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ /* This would normally be an assert, but we need to use an HGOTO_ERROR
+ * call to shut up the compiler.
+ */
+ if((NULL == cache_ptr) || (cache_ptr->magic != H5C__H5C_T_MAGIC) ||
+ (NULL == cache_name))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr or cache_name")
+
+#if H5C_COLLECT_CACHE_STATS
+ for(i = 0; i <= cache_ptr->max_type_id; i++ ) {
+ total_hits += cache_ptr->hits[i];
+ total_misses += cache_ptr->misses[i];
+ total_write_protects += cache_ptr->write_protects[i];
+ total_read_protects += cache_ptr->read_protects[i];
+ if(max_read_protects < cache_ptr->max_read_protects[i])
+ max_read_protects = cache_ptr->max_read_protects[i];
+ total_insertions += cache_ptr->insertions[i];
+ total_pinned_insertions += cache_ptr->pinned_insertions[i];
+ total_clears += cache_ptr->clears[i];
+ total_flushes += cache_ptr->flushes[i];
+ total_evictions += cache_ptr->evictions[i];
+ total_take_ownerships += cache_ptr->take_ownerships[i];
+ total_moves += cache_ptr->moves[i];
+ total_entry_flush_moves += cache_ptr->entry_flush_moves[i];
+ total_cache_flush_moves += cache_ptr->cache_flush_moves[i];
+ total_size_increases += cache_ptr->size_increases[i];
+ total_size_decreases += cache_ptr->size_decreases[i];
+ total_entry_flush_size_changes
+ += cache_ptr->entry_flush_size_changes[i];
+ total_cache_flush_size_changes
+ += cache_ptr->cache_flush_size_changes[i];
+ total_pins += cache_ptr->pins[i];
+ total_unpins += cache_ptr->unpins[i];
+ total_dirty_pins += cache_ptr->dirty_pins[i];
+ total_pinned_flushes += cache_ptr->pinned_flushes[i];
+ total_pinned_clears += cache_ptr->pinned_clears[i];
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+ if(aggregate_max_accesses < cache_ptr->max_accesses[i])
+ aggregate_max_accesses = cache_ptr->max_accesses[i];
+ if(aggregate_min_accesses > aggregate_max_accesses)
+ aggregate_min_accesses = aggregate_max_accesses;
+ if(aggregate_min_accesses > cache_ptr->min_accesses[i])
+ aggregate_min_accesses = cache_ptr->min_accesses[i];
+ if(aggregate_max_clears < cache_ptr->max_clears[i])
+ aggregate_max_clears = cache_ptr->max_clears[i];
+ if(aggregate_max_flushes < cache_ptr->max_flushes[i])
+ aggregate_max_flushes = cache_ptr->max_flushes[i];
+ if(aggregate_max_size < cache_ptr->max_size[i])
+ aggregate_max_size = cache_ptr->max_size[i];
+ if(aggregate_max_pins < cache_ptr->max_pins[i])
+ aggregate_max_pins = cache_ptr->max_pins[i];
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+ } /* end for */
+
+ if((total_hits > 0) || (total_misses > 0))
+ hit_rate = (double)100.0f * ((double)(total_hits)) /
+ ((double)(total_hits + total_misses));
+ else
+ hit_rate = 0.0f;
+
+ if(cache_ptr->successful_ht_searches > 0)
+ average_successful_search_depth =
+ ((double)(cache_ptr->total_successful_ht_search_depth)) /
+ ((double)(cache_ptr->successful_ht_searches));
+
+ if(cache_ptr->failed_ht_searches > 0)
+ average_failed_search_depth =
+ ((double)(cache_ptr->total_failed_ht_search_depth)) /
+ ((double)(cache_ptr->failed_ht_searches));
+
+
+ HDfprintf(stdout, "\n%sH5C: cache statistics for %s\n",
+ cache_ptr->prefix, cache_name);
+
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout,
+ "%s hash table insertion / deletions = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->total_ht_insertions),
+ (long)(cache_ptr->total_ht_deletions));
+
+ HDfprintf(stdout,
+ "%s HT successful / failed searches = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->successful_ht_searches),
+ (long)(cache_ptr->failed_ht_searches));
+
+ HDfprintf(stdout,
+ "%s Av. HT suc / failed search depth = %f / %f\n",
+ cache_ptr->prefix,
+ average_successful_search_depth,
+ average_failed_search_depth);
+
+ HDfprintf(stdout,
+ "%s current (max) index size / length = %ld (%ld) / %lu (%lu)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->index_size),
+ (long)(cache_ptr->max_index_size),
+ (unsigned long)(cache_ptr->index_len),
+ (unsigned long)(cache_ptr->max_index_len));
+
+ HDfprintf(stdout,
+ "%s current (max) clean/dirty idx size = %ld (%ld) / %ld (%ld)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->clean_index_size),
+ (long)(cache_ptr->max_clean_index_size),
+ (long)(cache_ptr->dirty_index_size),
+ (long)(cache_ptr->max_dirty_index_size));
+
+ HDfprintf(stdout,
+ "%s current (max) slist size / length = %ld (%ld) / %lu (%lu)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->slist_size),
+ (long)(cache_ptr->max_slist_size),
+ (unsigned long)(cache_ptr->slist_len),
+ (unsigned long)(cache_ptr->max_slist_len));
+
+ HDfprintf(stdout,
+ "%s current (max) PL size / length = %ld (%ld) / %lu (%lu)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->pl_size),
+ (long)(cache_ptr->max_pl_size),
+ (unsigned long)(cache_ptr->pl_len),
+ (unsigned long)(cache_ptr->max_pl_len));
+
+ HDfprintf(stdout,
+ "%s current (max) PEL size / length = %ld (%ld) / %lu (%lu)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->pel_size),
+ (long)(cache_ptr->max_pel_size),
+ (unsigned long)(cache_ptr->pel_len),
+ (unsigned long)(cache_ptr->max_pel_len));
+
+ HDfprintf(stdout,
+ "%s current LRU list size / length = %ld / %lu\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->LRU_list_size),
+ (unsigned long)(cache_ptr->LRU_list_len));
+
+ HDfprintf(stdout,
+ "%s current clean LRU size / length = %ld / %lu\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->cLRU_list_size),
+ (unsigned long)(cache_ptr->cLRU_list_len));
+
+ HDfprintf(stdout,
+ "%s current dirty LRU size / length = %ld / %lu\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->dLRU_list_size),
+ (unsigned long)(cache_ptr->dLRU_list_len));
+
+ HDfprintf(stdout,
+ "%s Total hits / misses / hit_rate = %ld / %ld / %f\n",
+ cache_ptr->prefix,
+ (long)total_hits,
+ (long)total_misses,
+ hit_rate);
+
+ HDfprintf(stdout,
+ "%s Total write / read (max) protects = %ld / %ld (%ld)\n",
+ cache_ptr->prefix,
+ (long)total_write_protects,
+ (long)total_read_protects,
+ (long)max_read_protects);
+
+ HDfprintf(stdout,
+ "%s Total clears / flushes = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_clears,
+ (long)total_flushes);
+
+ HDfprintf(stdout,
+ "%s Total evictions / take ownerships = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_evictions,
+ (long)total_take_ownerships);
+
+ HDfprintf(stdout,
+ "%s Total insertions(pinned) / moves = %ld(%ld) / %ld\n",
+ cache_ptr->prefix,
+ (long)total_insertions,
+ (long)total_pinned_insertions,
+ (long)total_moves);
+
+ HDfprintf(stdout,
+ "%s Total entry / cache flush moves = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_entry_flush_moves,
+ (long)total_cache_flush_moves);
+
+ HDfprintf(stdout, "%s Total entry size incrs / decrs = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_size_increases,
+ (long)total_size_decreases);
+
+ HDfprintf(stdout, "%s Ttl entry/cache flush size changes = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_entry_flush_size_changes,
+ (long)total_cache_flush_size_changes);
+
+ HDfprintf(stdout,
+ "%s Total entry pins (dirty) / unpins = %ld (%ld) / %ld\n",
+ cache_ptr->prefix,
+ (long)total_pins,
+ (long)total_dirty_pins,
+ (long)total_unpins);
+
+ HDfprintf(stdout, "%s Total pinned flushes / clears = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)total_pinned_flushes,
+ (long)total_pinned_clears);
+
+ HDfprintf(stdout, "%s MSIC: (make space in cache) calls = %lld\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->calls_to_msic));
+
+ if (cache_ptr->calls_to_msic > 0)
+ average_entries_skipped_per_calls_to_msic =
+ (((double)(cache_ptr->total_entries_skipped_in_msic)) /
+ ((double)(cache_ptr->calls_to_msic)));
+
+ HDfprintf(stdout, "%s MSIC: Average/max entries skipped = %lf / %ld\n",
+ cache_ptr->prefix,
+ (double)average_entries_skipped_per_calls_to_msic,
+ (long)(cache_ptr->max_entries_skipped_in_msic));
+
+ if(cache_ptr->calls_to_msic > 0)
+ average_dirty_pf_entries_skipped_per_call_to_msic =
+ (((double)(cache_ptr->total_dirty_pf_entries_skipped_in_msic)) /
+ ((double)(cache_ptr->calls_to_msic)));
+
+ HDfprintf(stdout,
+ "%s MSIC: Average/max dirty pf entries skipped = %lf / %ld\n",
+ cache_ptr->prefix,
+ average_dirty_pf_entries_skipped_per_call_to_msic,
+ (long)(cache_ptr->max_dirty_pf_entries_skipped_in_msic));
+
+ if(cache_ptr->calls_to_msic > 0)
+ average_entries_scanned_per_calls_to_msic =
+ (((double)(cache_ptr->total_entries_scanned_in_msic)) /
+ ((double)(cache_ptr->calls_to_msic)));
+
+ HDfprintf(stdout, "%s MSIC: Average/max entries scanned = %lf / %ld\n",
+ cache_ptr->prefix,
+ (double)average_entries_scanned_per_calls_to_msic,
+ (long)(cache_ptr->max_entries_scanned_in_msic));
+
+ HDfprintf(stdout, "%s MSIC: Scanned to make space(evict) = %lld\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->entries_scanned_to_make_space));
+
+ HDfprintf(stdout, "%s MSIC: Scanned to satisfy min_clean = %lld\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->total_entries_scanned_in_msic -
+ cache_ptr->entries_scanned_to_make_space));
+
+ HDfprintf(stdout,
+ "%s slist/LRU/index scan restarts = %lld / %lld / %lld.\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->slist_scan_restarts),
+ (long long)(cache_ptr->LRU_scan_restarts),
+ (long long)(cache_ptr->index_scan_restarts));
+
+ HDfprintf(stdout,
+ "%s cache image creations/reads/loads/size = %d / %d /%d / %Hu\n",
+ cache_ptr->prefix,
+ cache_ptr->images_created,
+ cache_ptr->images_read,
+ cache_ptr->images_loaded,
+ cache_ptr->last_image_size);
+
+ HDfprintf(stdout,
+ "%s prefetches / dirty prefetches = %lld / %lld\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->prefetches),
+ (long long)(cache_ptr->dirty_prefetches));
+
+ HDfprintf(stdout,
+ "%s prefetch hits/flushes/evictions = %lld / %lld / %lld\n",
+ cache_ptr->prefix,
+ (long long)(cache_ptr->prefetch_hits),
+ (long long)(cache_ptr->flushes[H5AC_PREFETCHED_ENTRY_ID]),
+ (long long)(cache_ptr->evictions[H5AC_PREFETCHED_ENTRY_ID]));
+
+ if(cache_ptr->prefetches > 0)
+ prefetch_use_rate =
+ (double)100.0f * ((double)(cache_ptr->prefetch_hits)) /
+ ((double)(cache_ptr->prefetches));
+ else
+ prefetch_use_rate = 0.0f;
+
+ HDfprintf(stdout,
+ "%s prefetched entry use rate = %lf\n",
+ cache_ptr->prefix,
+ prefetch_use_rate);
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ HDfprintf(stdout, "%s aggregate max / min accesses = %d / %d\n",
+ cache_ptr->prefix,
+ (int)aggregate_max_accesses,
+ (int)aggregate_min_accesses);
+
+ HDfprintf(stdout, "%s aggregate max_clears / max_flushes = %d / %d\n",
+ cache_ptr->prefix,
+ (int)aggregate_max_clears,
+ (int)aggregate_max_flushes);
+
+ HDfprintf(stdout, "%s aggregate max_size / max_pins = %d / %d\n",
+ cache_ptr->prefix,
+ (int)aggregate_max_size,
+ (int)aggregate_max_pins);
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+ if(display_detailed_stats) {
+ for(i = 0; i <= cache_ptr->max_type_id; i++) {
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout, "%s Stats on %s:\n",
+ cache_ptr->prefix,
+ ((cache_ptr->class_table_ptr))[i]->name);
+
+ if((cache_ptr->hits[i] > 0) || (cache_ptr->misses[i] > 0))
+ hit_rate = (double)100.0f * ((double)(cache_ptr->hits[i])) /
+ ((double)(cache_ptr->hits[i] + cache_ptr->misses[i]));
+ else
+ hit_rate = 0.0f;
+
+ HDfprintf(stdout,
+ "%s hits / misses / hit_rate = %ld / %ld / %f\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->hits[i]),
+ (long)(cache_ptr->misses[i]),
+ hit_rate);
+
+ HDfprintf(stdout,
+ "%s write / read (max) protects = %ld / %ld (%d)\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->write_protects[i]),
+ (long)(cache_ptr->read_protects[i]),
+ (int)(cache_ptr->max_read_protects[i]));
+
+ HDfprintf(stdout,
+ "%s clears / flushes = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->clears[i]),
+ (long)(cache_ptr->flushes[i]));
+
+ HDfprintf(stdout,
+ "%s evictions / take ownerships = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->evictions[i]),
+ (long)(cache_ptr->take_ownerships[i]));
+
+ HDfprintf(stdout,
+ "%s insertions(pinned) / moves = %ld(%ld) / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->insertions[i]),
+ (long)(cache_ptr->pinned_insertions[i]),
+ (long)(cache_ptr->moves[i]));
+
+ HDfprintf(stdout,
+ "%s entry / cache flush moves = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->entry_flush_moves[i]),
+ (long)(cache_ptr->cache_flush_moves[i]));
+
+ HDfprintf(stdout,
+ "%s size increases / decreases = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->size_increases[i]),
+ (long)(cache_ptr->size_decreases[i]));
+
+ HDfprintf(stdout,
+ "%s entry/cache flush size changes = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->entry_flush_size_changes[i]),
+ (long)(cache_ptr->cache_flush_size_changes[i]));
+
+
+ HDfprintf(stdout,
+ "%s entry pins / unpins = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->pins[i]),
+ (long)(cache_ptr->unpins[i]));
+
+ HDfprintf(stdout,
+ "%s entry dirty pins/pin'd flushes = %ld / %ld\n",
+ cache_ptr->prefix,
+ (long)(cache_ptr->dirty_pins[i]),
+ (long)(cache_ptr->pinned_flushes[i]));
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ HDfprintf(stdout,
+ "%s entry max / min accesses = %d / %d\n",
+ cache_ptr->prefix,
+ cache_ptr->max_accesses[i],
+ cache_ptr->min_accesses[i]);
+
+ HDfprintf(stdout,
+ "%s entry max_clears / max_flushes = %d / %d\n",
+ cache_ptr->prefix,
+ cache_ptr->max_clears[i],
+ cache_ptr->max_flushes[i]);
+
+ HDfprintf(stdout,
+ "%s entry max_size / max_pins = %d / %d\n",
+ cache_ptr->prefix,
+ (int)(cache_ptr->max_size[i]),
+ (int)(cache_ptr->max_pins[i]));
+
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+ } /* end for */
+ } /* end if */
+
+ HDfprintf(stdout, "\n");
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_stats() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_stats__reset
+ *
+ * Purpose: Reset the stats fields to their initial values.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer, 4/28/04
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+#ifndef NDEBUG
+H5C_stats__reset(H5C_t * cache_ptr)
+#else /* NDEBUG */
+#if H5C_COLLECT_CACHE_STATS
+H5C_stats__reset(H5C_t * cache_ptr)
+#else /* H5C_COLLECT_CACHE_STATS */
+H5C_stats__reset(H5C_t H5_ATTR_UNUSED * cache_ptr)
+#endif /* H5C_COLLECT_CACHE_STATS */
+#endif /* NDEBUG */
+{
+#if H5C_COLLECT_CACHE_STATS
+ int i;
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+#if H5C_COLLECT_CACHE_STATS
+ for(i = 0; i <= cache_ptr->max_type_id; i++) {
+ cache_ptr->hits[i] = 0;
+ cache_ptr->misses[i] = 0;
+ cache_ptr->write_protects[i] = 0;
+ cache_ptr->read_protects[i] = 0;
+ cache_ptr->max_read_protects[i] = 0;
+ cache_ptr->insertions[i] = 0;
+ cache_ptr->pinned_insertions[i] = 0;
+ cache_ptr->clears[i] = 0;
+ cache_ptr->flushes[i] = 0;
+ cache_ptr->evictions[i] = 0;
+ cache_ptr->take_ownerships[i] = 0;
+ cache_ptr->moves[i] = 0;
+ cache_ptr->entry_flush_moves[i] = 0;
+ cache_ptr->cache_flush_moves[i] = 0;
+ cache_ptr->pins[i] = 0;
+ cache_ptr->unpins[i] = 0;
+ cache_ptr->dirty_pins[i] = 0;
+ cache_ptr->pinned_flushes[i] = 0;
+ cache_ptr->pinned_clears[i] = 0;
+ cache_ptr->size_increases[i] = 0;
+ cache_ptr->size_decreases[i] = 0;
+ cache_ptr->entry_flush_size_changes[i] = 0;
+ cache_ptr->cache_flush_size_changes[i] = 0;
+ } /* end for */
+
+ cache_ptr->total_ht_insertions = 0;
+ cache_ptr->total_ht_deletions = 0;
+ cache_ptr->successful_ht_searches = 0;
+ cache_ptr->total_successful_ht_search_depth = 0;
+ cache_ptr->failed_ht_searches = 0;
+ cache_ptr->total_failed_ht_search_depth = 0;
+
+ cache_ptr->max_index_len = 0;
+ cache_ptr->max_index_size = (size_t)0;
+ cache_ptr->max_clean_index_size = (size_t)0;
+ cache_ptr->max_dirty_index_size = (size_t)0;
+
+ cache_ptr->max_slist_len = 0;
+ cache_ptr->max_slist_size = (size_t)0;
+
+ cache_ptr->max_pl_len = 0;
+ cache_ptr->max_pl_size = (size_t)0;
+
+ cache_ptr->max_pel_len = 0;
+ cache_ptr->max_pel_size = (size_t)0;
+
+ cache_ptr->calls_to_msic = 0;
+ cache_ptr->total_entries_skipped_in_msic = 0;
+ cache_ptr->total_dirty_pf_entries_skipped_in_msic = 0;
+ cache_ptr->total_entries_scanned_in_msic = 0;
+ cache_ptr->max_entries_skipped_in_msic = 0;
+ cache_ptr->max_dirty_pf_entries_skipped_in_msic = 0;
+ cache_ptr->max_entries_scanned_in_msic = 0;
+ cache_ptr->entries_scanned_to_make_space = 0;
+
+ cache_ptr->slist_scan_restarts = 0;
+ cache_ptr->LRU_scan_restarts = 0;
+ cache_ptr->index_scan_restarts = 0;
+
+ cache_ptr->images_created = 0;
+ cache_ptr->images_read = 0;
+ cache_ptr->images_loaded = 0;
+ cache_ptr->last_image_size = (hsize_t)0;
+
+ cache_ptr->prefetches = 0;
+ cache_ptr->dirty_prefetches = 0;
+ cache_ptr->prefetch_hits = 0;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+ for(i = 0; i <= cache_ptr->max_type_id; i++) {
+ cache_ptr->max_accesses[i] = 0;
+ cache_ptr->min_accesses[i] = 1000000;
+ cache_ptr->max_clears[i] = 0;
+ cache_ptr->max_flushes[i] = 0;
+ cache_ptr->max_size[i] = (size_t)0;
+ cache_ptr->max_pins[i] = 0;
+ } /* end for */
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ return;
+} /* H5C_stats__reset() */
+
+extern void
+H5C__dump_entry(H5C_t *cache_ptr, const H5C_cache_entry_t *entry_ptr,
+ hbool_t dump_parents, const char *prefix, int indent);
+
+static void
+H5C__dump_parents(H5C_t *cache_ptr, const H5C_cache_entry_t *entry_ptr, const char *prefix, int indent)
+{
+ unsigned u;
+
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++)
+ H5C__dump_entry(cache_ptr, entry_ptr->flush_dep_parent[u], TRUE, prefix, indent + 2);
+}
+
+typedef struct H5C__dump_child_ctx_t {
+ H5C_t *cache_ptr;
+ const H5C_cache_entry_t *parent;
+ hbool_t dump_parents;
+ const char *prefix;
+ int indent;
+} H5C__dump_child_ctx_t;
+
+static int
+H5C__dump_children_cb(H5C_cache_entry_t *entry_ptr, void *_ctx)
+{
+ H5C__dump_child_ctx_t *ctx = (H5C__dump_child_ctx_t *)_ctx;
+
+ if(entry_ptr->tag_info->tag != entry_ptr->addr) {
+ unsigned u;
+
+ HDassert(entry_ptr->flush_dep_nparents);
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++)
+ if(ctx->parent == entry_ptr->flush_dep_parent[u])
+ H5C__dump_entry(ctx->cache_ptr, entry_ptr, ctx->dump_parents, ctx->prefix, ctx->indent + 2);
+ } /* end if */
+
+ return(H5_ITER_CONT);
+} /* end H5C__dump_children_cb() */
+
+static void
+H5C__dump_children(H5C_t *cache_ptr, const H5C_cache_entry_t *entry_ptr,
+ hbool_t dump_parents, const char *prefix, int indent)
+{
+ H5C__dump_child_ctx_t ctx;
+
+ HDassert(entry_ptr->tag_info);
+
+ ctx.cache_ptr = cache_ptr;
+ ctx.parent = entry_ptr;
+ ctx.dump_parents = dump_parents;
+ ctx.prefix = prefix;
+ ctx.indent = indent;
+ H5C__iter_tagged_entries(cache_ptr, entry_ptr->tag_info->tag, FALSE, H5C__dump_children_cb, &ctx);
+} /* end H5C__dump_children() */
+
+void
+H5C__dump_entry(H5C_t *cache_ptr, const H5C_cache_entry_t *entry_ptr,
+ hbool_t dump_parents, const char *prefix, int indent)
+{
+ HDassert(cache_ptr);
+ HDassert(entry_ptr);
+
+ HDfprintf(stderr, "%*s%s: entry_ptr = (%a, '%s', %a, %t, %u, %u/%u)\n", indent, "", prefix, entry_ptr->addr, entry_ptr->type->name, entry_ptr->tag_info ? entry_ptr->tag_info->tag : HADDR_UNDEF, entry_ptr->is_dirty, entry_ptr->flush_dep_nparents, entry_ptr->flush_dep_nchildren, entry_ptr->flush_dep_ndirty_children);
+ if(dump_parents && entry_ptr->flush_dep_nparents)
+ H5C__dump_parents(cache_ptr, entry_ptr, "Parent", indent);
+ if(entry_ptr->flush_dep_nchildren)
+ H5C__dump_children(cache_ptr, entry_ptr, FALSE, "Child", indent);
+} /* end H5C__dump_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_dependency_exists()
+ *
+ * Purpose: Test to see if a flush dependency relationship exists
+ * between the supplied parent and child. Both parties
+ * are indicated by addresses so as to avoid the necessity
+ * of protect / unprotect calls prior to this call.
+ *
+ * If either the parent or the child is not in the metadata
+ * cache, the function sets *fd_exists_ptr to FALSE.
+ *
+ * If both are in the cache, the childs list of parents is
+ * searched for the proposed parent. If the proposed parent
+ * is found in the childs parent list, the function sets
+ * *fd_exists_ptr to TRUE. In all other non-error cases,
+ * the function sets *fd_exists_ptr FALSE.
+ *
+ * Return: SUCCEED on success/FAIL on failure. Note that
+ * *fd_exists_ptr is undefined on failure.
+ *
+ * Programmer: John Mainzer
+ * 9/28/16
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_flush_dependency_exists(H5C_t *cache_ptr, haddr_t parent_addr, haddr_t child_addr,
+ hbool_t *fd_exists_ptr)
+{
+ hbool_t fd_exists = FALSE; /* whether flush dependency exists */
+ H5C_cache_entry_t * parent_ptr; /* Ptr to parent entry */
+ H5C_cache_entry_t * child_ptr; /* Ptr to child entry */
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(H5F_addr_defined(parent_addr));
+ HDassert(H5F_addr_defined(child_addr));
+ HDassert(fd_exists_ptr);
+
+ H5C__SEARCH_INDEX(cache_ptr, parent_addr, parent_ptr, FAIL)
+ H5C__SEARCH_INDEX(cache_ptr, child_addr, child_ptr, FAIL)
+
+ if(parent_ptr && child_ptr) {
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(child_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ if(child_ptr->flush_dep_nparents > 0) {
+ unsigned u; /* Local index variable */
+
+ HDassert(child_ptr->flush_dep_parent);
+ HDassert(child_ptr->flush_dep_parent_nalloc >= child_ptr->flush_dep_nparents);
+
+ for(u = 0; u < child_ptr->flush_dep_nparents; u++) {
+ if(child_ptr->flush_dep_parent[u] == parent_ptr) {
+ fd_exists = TRUE;
+ HDassert(parent_ptr->flush_dep_nchildren > 0);
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ } /* end if */
+
+ *fd_exists_ptr = fd_exists;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_dependency_exists() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_validate_index_list
+ *
+ * Purpose: Debugging function that scans the index list for errors.
+ *
+ * If an error is detected, the function generates a
+ * diagnostic and returns FAIL. If no error is detected,
+ * the function returns SUCCEED.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 9/16/16
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_validate_index_list(H5C_t *cache_ptr)
+{
+ H5C_cache_entry_t * entry_ptr = NULL;
+ uint32_t len = 0;
+ int32_t index_ring_len[H5C_RING_NTYPES];
+ size_t size = 0;
+ size_t clean_size = 0;
+ size_t dirty_size = 0;
+ size_t index_ring_size[H5C_RING_NTYPES];
+ size_t clean_index_ring_size[H5C_RING_NTYPES];
+ size_t dirty_index_ring_size[H5C_RING_NTYPES];
+ int i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ for(i = 0; i < H5C_RING_NTYPES; i++) {
+ index_ring_len[i] = 0;
+ index_ring_size[i] = 0;
+ clean_index_ring_size[i] = 0;
+ dirty_index_ring_size[i] = 0;
+ } /* end if */
+
+ if(((cache_ptr->il_head == NULL) || (cache_ptr->il_tail == NULL))
+ && (cache_ptr->il_head != cache_ptr->il_tail))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index list pointer validation failed")
+
+ if((cache_ptr->index_len == 1) && ((cache_ptr->il_head != cache_ptr->il_tail)
+ || (cache_ptr->il_head == NULL) || (cache_ptr->il_head->size != cache_ptr->index_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index list pointer sanity checks failed")
+
+ if((cache_ptr->index_len >= 1)
+ && ((cache_ptr->il_head == NULL)
+ || (cache_ptr->il_head->il_prev != NULL)
+ || (cache_ptr->il_tail == NULL)
+ || (cache_ptr->il_tail->il_next != NULL)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index list length sanity checks failed")
+
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ if((entry_ptr != cache_ptr->il_head)
+ && ((entry_ptr->il_prev == NULL) || (entry_ptr->il_prev->il_next != entry_ptr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index list pointers for entry are invalid")
+
+ if((entry_ptr != cache_ptr->il_tail)
+ && ((entry_ptr->il_next == NULL) || (entry_ptr->il_next->il_prev != entry_ptr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index list pointers for entry are invalid")
+
+ HDassert(entry_ptr->ring > 0);
+ HDassert(entry_ptr->ring < H5C_RING_NTYPES);
+
+ len++;
+ index_ring_len[entry_ptr->ring] += 1;
+
+ size += entry_ptr->size;
+ index_ring_size[entry_ptr->ring] += entry_ptr->size;
+
+ if(entry_ptr->is_dirty) {
+ dirty_size += entry_ptr->size;
+ dirty_index_ring_size[entry_ptr->ring] += entry_ptr->size;
+ } /* end if */
+ else {
+ clean_size += entry_ptr->size;
+ clean_index_ring_size[entry_ptr->ring] += entry_ptr->size;
+ } /* end else */
+
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+
+ if((cache_ptr->index_len != len) || (cache_ptr->il_len != len)
+ || (cache_ptr->index_size != size) || (cache_ptr->il_size != size)
+ || (cache_ptr->clean_index_size != clean_size)
+ || (cache_ptr->dirty_index_size != dirty_size)
+ || (clean_size + dirty_size != size))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index, clean and dirty sizes for cache are invalid")
+
+ size = 0;
+ clean_size = 0;
+ dirty_size = 0;
+ for(i = 0; i < H5C_RING_NTYPES; i++) {
+ size += clean_index_ring_size[i] + dirty_index_ring_size[i];
+ clean_size += clean_index_ring_size[i];
+ dirty_size += dirty_index_ring_size[i];
+ } /* end for */
+
+ if((cache_ptr->index_size != size)
+ || (cache_ptr->clean_index_size != clean_size)
+ || (cache_ptr->dirty_index_size != dirty_size))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Index, clean and dirty sizes for cache are invalid")
+
+done:
+ if(ret_value != SUCCEED)
+ HDassert(0);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_validate_index_list() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_get_entry_ptr_from_addr()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, returns a pointer
+ * to the entry in *entry_ptr_ptr. If the entry is not in the
+ * cache, *entry_ptr_ptr is set to NULL.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * As heavy use of this function is almost certainly a
+ * bad idea, the metadata cache tracks the number of
+ * successful calls to this function, and (if
+ * H5C_DO_SANITY_CHECKS is defined) displays any
+ * non-zero count on cache shutdown.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_get_entry_ptr_from_addr(H5C_t *cache_ptr, haddr_t addr, void **entry_ptr_ptr)
+{
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(entry_ptr_ptr);
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if(entry_ptr == NULL)
+ /* the entry doesn't exist in the cache -- report this
+ * and quit.
+ */
+ *entry_ptr_ptr = NULL;
+ else {
+ *entry_ptr_ptr = entry_ptr;
+
+ /* increment call counter */
+ (cache_ptr->get_entry_ptr_from_addr_counter)++;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_entry_ptr_from_addr() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_serialization_in_progress
+ *
+ * Purpose: Return the current value of
+ * cache_ptr->serialization_in_progress.
+ *
+ * Return: Current value of cache_ptr->serialization_in_progress.
+ *
+ * Programmer: John Mainzer
+ * 8/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+hbool_t
+H5C_get_serialization_in_progress(const H5C_t *cache_ptr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ FUNC_LEAVE_NOAPI(cache_ptr->serialization_in_progress)
+} /* H5C_get_serialization_in_progress() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_cache_is_clean()
+ *
+ * Purpose: Debugging function that verifies that all rings in the
+ * metadata cache are clean from the outermost ring, inwards
+ * to the inner ring specified.
+ *
+ * Returns TRUE if all specified rings are clean, and FALSE
+ * if not. Throws an assertion failure on error.
+ *
+ * Return: TRUE if the indicated ring(s) are clean, and FALSE otherwise.
+ *
+ * Programmer: John Mainzer, 6/18/16
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+hbool_t
+H5C_cache_is_clean(const H5C_t *cache_ptr, H5C_ring_t inner_ring)
+{
+ H5C_ring_t ring = H5C_RING_USER;
+ hbool_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(inner_ring >= H5C_RING_USER);
+ HDassert(inner_ring <= H5C_RING_SB);
+
+ while(ring <= inner_ring) {
+ if(cache_ptr->dirty_index_ring_size[ring] > 0)
+ HGOTO_DONE(FALSE)
+
+ ring++;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_cache_is_clean() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_verify_entry_type()
+ *
+ * Purpose: Debugging function that attempts to look up an entry in the
+ * cache by its file address, and if found, test to see if its
+ * type field contains the expted value.
+ *
+ * If the specified entry is in cache, *in_cache_ptr is set
+ * to TRUE, and *type_ok_ptr is set to TRUE or FALSE depending
+ * on whether the entries type field matches the expected_type
+ * parameter.
+ *
+ * If the target entry is not in cache, *in_cache_ptr is
+ * set to FALSE, and *type_ok_ptr is undefined.
+ *
+ * Note that this function is only defined if NDEBUG
+ * is not defined.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: John Mainzer, 5/30/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+herr_t
+H5C_verify_entry_type(H5C_t *cache_ptr, haddr_t addr,
+ const H5C_class_t *expected_type, hbool_t *in_cache_ptr,
+ hbool_t *type_ok_ptr)
+{
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(expected_type);
+ HDassert(in_cache_ptr);
+ HDassert(type_ok_ptr);
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if(entry_ptr == NULL)
+ /* the entry doesn't exist in the cache -- report this
+ * and quit.
+ */
+ *in_cache_ptr = FALSE;
+ else {
+ *in_cache_ptr = TRUE;
+
+ if(entry_ptr->prefetched)
+ *type_ok_ptr = (expected_type->id == entry_ptr->prefetch_type_id);
+ else
+ *type_ok_ptr = (expected_type == entry_ptr->type);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_verify_entry_type() */
+#endif /* NDEBUG */
+
diff --git a/src/H5Cepoch.c b/src/H5Cepoch.c
new file mode 100644
index 0000000..f8507a9
--- /dev/null
+++ b/src/H5Cepoch.c
@@ -0,0 +1,240 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cepoch.c
+ * June 5 2004
+ * Quincey Koziol
+ *
+ * Purpose: Metadata cache epoch callbacks.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/****************************************************************************
+ *
+ * declarations for epoch marker cache entries.
+ *
+ * As a strategy for automatic cache size reduction, the cache may insert
+ * marker entries in the LRU list at the end of each epoch. These markers
+ * are then used to identify entries that have not been accessed for n
+ * epochs so that they can be evicted from the cache.
+ *
+ ****************************************************************************/
+static herr_t H5C__epoch_marker_get_initial_load_size(void *udata_ptr,
+ size_t *image_len_ptr);
+static herr_t H5C__epoch_marker_get_final_load_size(const void *image_ptr,
+ size_t image_len_ptr, void *udata_ptr, size_t *actual_len);
+static htri_t H5C__epoch_marker_verify_chksum(const void *image_ptr,
+ size_t len, void *udata_ptr);
+static void * H5C__epoch_marker_deserialize(const void * image_ptr,
+ size_t len, void * udata, hbool_t * dirty_ptr);
+static herr_t H5C__epoch_marker_image_len(const void * thing,
+ size_t *image_len_ptr);
+static herr_t H5C__epoch_marker_pre_serialize(H5F_t *f,
+ hid_t dxpl_id, void * thing, haddr_t addr, size_t len,
+ haddr_t * new_addr_ptr, size_t * new_len_ptr, unsigned * flags_ptr);
+static herr_t H5C__epoch_marker_serialize(const H5F_t *f,
+ void * image_ptr, size_t len, void * thing);
+static herr_t H5C__epoch_marker_notify(H5C_notify_action_t action, void *thing);
+static herr_t H5C__epoch_marker_free_icr(void * thing);
+static herr_t H5C__epoch_marker_fsf_size(const void H5_ATTR_UNUSED * thing,
+ size_t H5_ATTR_UNUSED * fsf_size_ptr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+const H5AC_class_t H5AC_EPOCH_MARKER[1] = {{
+ /* id = */ H5AC_EPOCH_MARKER_ID,
+ /* name = */ "epoch marker",
+ /* mem_type = */ H5FD_MEM_DEFAULT, /* value doesn't matter */
+ /* flags = */ H5AC__CLASS_NO_FLAGS_SET,
+ /* get_initial_load_size = */ H5C__epoch_marker_get_initial_load_size,
+ /* get_final_load_size = */ H5C__epoch_marker_get_final_load_size,
+ /* verify_chksum = */ H5C__epoch_marker_verify_chksum,
+ /* deserialize = */ H5C__epoch_marker_deserialize,
+ /* image_len = */ H5C__epoch_marker_image_len,
+ /* pre_serialize = */ H5C__epoch_marker_pre_serialize,
+ /* serialize = */ H5C__epoch_marker_serialize,
+ /* notify = */ H5C__epoch_marker_notify,
+ /* free_icr = */ H5C__epoch_marker_free_icr,
+ /* fsf_size = */ H5C__epoch_marker_fsf_size,
+}};
+
+
+/***************************************************************************
+ * Class functions for H5C__EPOCH_MAKER_TYPE:
+ *
+ * None of these functions should ever be called, so there is no point in
+ * documenting them separately.
+ * JRM - 11/16/04
+ *
+ ***************************************************************************/
+
+
+static herr_t
+H5C__epoch_marker_get_initial_load_size(void H5_ATTR_UNUSED *udata_ptr,
+ size_t H5_ATTR_UNUSED *image_len_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_get_initial_load_size() */
+
+
+static herr_t
+H5C__epoch_marker_get_final_load_size(const void H5_ATTR_UNUSED *image_ptr,
+ size_t H5_ATTR_UNUSED image_len, void H5_ATTR_UNUSED *udata_ptr,
+ size_t H5_ATTR_UNUSED *actual_len)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_final_get_load_size() */
+
+
+static htri_t
+H5C__epoch_marker_verify_chksum(const void H5_ATTR_UNUSED *image_ptr, size_t H5_ATTR_UNUSED len,
+ void H5_ATTR_UNUSED *udata_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FALSE)
+} /* end H5C__epoch_marker_verify_chksum() */
+
+
+static void *
+H5C__epoch_marker_deserialize(const void H5_ATTR_UNUSED * image_ptr, size_t H5_ATTR_UNUSED len,
+ void H5_ATTR_UNUSED * udata, hbool_t H5_ATTR_UNUSED * dirty_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5C__epoch_marker_deserialize() */
+
+
+static herr_t
+H5C__epoch_marker_image_len(const void H5_ATTR_UNUSED *thing,
+ size_t H5_ATTR_UNUSED *image_len_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_image_len() */
+
+
+static herr_t
+H5C__epoch_marker_pre_serialize(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ void H5_ATTR_UNUSED *thing, haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED len,
+ haddr_t H5_ATTR_UNUSED *new_addr_ptr, size_t H5_ATTR_UNUSED *new_len_ptr,
+ unsigned H5_ATTR_UNUSED *flags_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_pre_serialize() */
+
+
+static herr_t
+H5C__epoch_marker_serialize(const H5F_t H5_ATTR_UNUSED *f, void H5_ATTR_UNUSED *image_ptr,
+ size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *thing)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_serialize() */
+
+
+static herr_t
+H5C__epoch_marker_notify(H5C_notify_action_t H5_ATTR_UNUSED action,
+ void H5_ATTR_UNUSED * thing)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_notify() */
+
+
+static herr_t
+H5C__epoch_marker_free_icr(void H5_ATTR_UNUSED * thing)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_free_icr() */
+
+
+static herr_t
+H5C__epoch_marker_fsf_size(const void H5_ATTR_UNUSED * thing, size_t H5_ATTR_UNUSED *fsf_size_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__epoch_marker_fsf_size() */
+
diff --git a/src/H5Cimage.c b/src/H5Cimage.c
new file mode 100644
index 0000000..debd30c
--- /dev/null
+++ b/src/H5Cimage.c
@@ -0,0 +1,3569 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cimage.c
+ * July 20, 2015
+ * John Mainzer
+ *
+ * Purpose: Functions in this file are specific to the implementation
+ * of the metadata cache image feature.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#ifdef H5_HAVE_PARALLEL
+#define H5AC_FRIEND /*suppress error about including H5ACpkg */
+#include "H5ACpkg.h" /* Metadata cache */
+#endif /* H5_HAVE_PARALLEL */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#if H5C_DO_MEMORY_SANITY_CHECKS
+#define H5C_IMAGE_EXTRA_SPACE 8
+#define H5C_IMAGE_SANITY_VALUE "DeadBeef"
+#else /* H5C_DO_MEMORY_SANITY_CHECKS */
+#define H5C_IMAGE_EXTRA_SPACE 0
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+/* Cache image buffer components, on disk */
+#define H5C__MDCI_BLOCK_SIGNATURE "MDCI"
+#define H5C__MDCI_BLOCK_SIGNATURE_LEN 4
+#define H5C__MDCI_BLOCK_VERSION_0 0
+
+/* Metadata cache image header flags -- max 8 bits */
+#define H5C__MDCI_HEADER_HAVE_RESIZE_STATUS 0x01
+
+/* Metadata cache image entry flags -- max 8 bits */
+#define H5C__MDCI_ENTRY_DIRTY_FLAG 0x01
+#define H5C__MDCI_ENTRY_IN_LRU_FLAG 0x02
+#define H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG 0x04
+#define H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG 0x08
+
+/* Limits on flush dependency values, stored in 16-bit values on disk */
+#define H5C__MDCI_MAX_FD_CHILDREN USHRT_MAX
+#define H5C__MDCI_MAX_FD_PARENTS USHRT_MAX
+
+/* Values for image entry magic field */
+#define H5C_IMAGE_ENTRY_T_MAGIC 0x005CAC08
+#define H5C_IMAGE_ENTRY_T_BAD_MAGIC 0xBeefDead
+
+/* Maximum ring allowed in image */
+#define H5C_MAX_RING_IN_IMAGE H5C_RING_MDFSM
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Helper routines */
+static size_t H5C__cache_image_block_entry_header_size(const H5F_t *f);
+static size_t H5C__cache_image_block_header_size(const H5F_t *f);
+static herr_t H5C__decode_cache_image_header(const H5F_t *f,
+ H5C_t *cache_ptr, const uint8_t **buf);
+#ifndef NDEBUG /* only used in assertions */
+static herr_t H5C__decode_cache_image_entry(const H5F_t *f,
+ const H5C_t *cache_ptr, const uint8_t **buf, unsigned entry_num);
+#endif /* NDEBUG */ /* only used in assertions */
+static herr_t H5C__destroy_pf_entry_child_flush_deps(H5C_t *cache_ptr,
+ H5C_cache_entry_t *pf_entry_ptr, H5C_cache_entry_t **fd_children);
+static herr_t H5C__encode_cache_image_header(const H5F_t *f,
+ const H5C_t *cache_ptr, uint8_t **buf);
+static herr_t H5C__encode_cache_image_entry(H5F_t *f, H5C_t *cache_ptr,
+ uint8_t **buf, unsigned entry_num);
+static herr_t H5C__prep_for_file_close__compute_fd_heights(const H5C_t *cache_ptr);
+static void H5C__prep_for_file_close__compute_fd_heights_real(
+ H5C_cache_entry_t *entry_ptr, uint32_t fd_height);
+static herr_t H5C__prep_for_file_close__setup_image_entries_array(H5C_t *cache_ptr);
+static herr_t H5C__prep_for_file_close__scan_entries(const H5F_t *f,
+ H5C_t *cache_ptr);
+static herr_t H5C__reconstruct_cache_contents(H5F_t *f, hid_t dxpl_id,
+ H5C_t *cache_ptr);
+static H5C_cache_entry_t *H5C__reconstruct_cache_entry(const H5F_t *f,
+ H5C_t *cache_ptr, const uint8_t **buf);
+static herr_t H5C__write_cache_image_superblock_msg(H5F_t *f, hid_t dxpl_id,
+ hbool_t create);
+static herr_t H5C__read_cache_image(H5F_t * f, hid_t dxpl_id, H5C_t *cache_ptr);
+static herr_t H5C__write_cache_image(H5F_t *f, hid_t dxpl_id, const H5C_t *cache_ptr);
+static herr_t H5C__construct_cache_image_buffer(H5F_t *f, H5C_t *cache_ptr);
+static herr_t H5C__free_image_entries_array(H5C_t *cache_ptr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage H5C_cache_entry_t objects */
+H5FL_DEFINE(H5C_cache_entry_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_cache_image_pending()
+ *
+ * Purpose: Tests to see if the load of a metadata cache image
+ * load is pending (i.e. will be executed on the next
+ * protect or insert)
+ *
+ * Returns TRUE if a cache image load is pending, and FALSE
+ * if not. Throws an assertion failure on error.
+ *
+ * Return: TRUE if a cache image load is pending, and FALSE otherwise.
+ *
+ * Programmer: John Mainzer, 6/18/16
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5C_cache_image_pending(const H5C_t *cache_ptr)
+{
+ hbool_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ ret_value = (cache_ptr->load_image && !cache_ptr->image_loaded);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_cache_image_pending() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_cache_image_status()
+ *
+ * Purpose: Examine the metadata cache associated with the supplied
+ * instance of H5F_t to determine whether the load of a
+ * cache image has either been queued or executed, and if
+ * construction of a cache image has been requested.
+ *
+ * This done, it set *load_ci_ptr to TRUE if a cache image
+ * has either been loaded or a load has been requested, and
+ * to FALSE otherwise.
+ *
+ * Similarly, set *write_ci_ptr to TRUE if construction of
+ * a cache image has been requested, and to FALSE otherwise.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 12/29/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_cache_image_status(H5F_t * f, hbool_t *load_ci_ptr, hbool_t *write_ci_ptr)
+{
+ H5C_t * cache_ptr;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(load_ci_ptr);
+ HDassert(write_ci_ptr);
+
+ *load_ci_ptr = cache_ptr->load_image || cache_ptr->image_loaded;
+ *write_ci_ptr = cache_ptr->image_ctl.generate_image;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C_cache_image_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__construct_cache_image_buffer()
+ *
+ * Purpose: Allocate a buffer of size cache_ptr->image_len, and
+ * load it with an image of the metadata cache image block.
+ *
+ * Note that by the time this function is called, the cache
+ * should have removed all entries from its data structures.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 8/5/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__construct_cache_image_buffer(H5F_t * f, H5C_t *cache_ptr)
+{
+ uint8_t * p; /* Pointer into image buffer */
+ uint32_t chksum;
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(cache_ptr == f->shared->cache);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->image_ctl.generate_image);
+ HDassert(cache_ptr->num_entries_in_image > 0);
+ HDassert(cache_ptr->index_len == 0);
+ HDassert(cache_ptr->image_data_len > 0);
+ HDassert(cache_ptr->image_data_len <= cache_ptr->image_len);
+
+ /* Allocate the buffer in which to construct the cache image block */
+ if(NULL == (cache_ptr->image_buffer = H5MM_malloc(cache_ptr->image_len + 1)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for cache image buffer")
+
+ /* Construct the cache image block header image */
+ p = (uint8_t *)cache_ptr->image_buffer;
+ if(H5C__encode_cache_image_header(f, cache_ptr, &p) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTENCODE, FAIL, "header image construction failed")
+ HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_data_len);
+
+ /* Construct the cache entry images */
+ for(u = 0; u < cache_ptr->num_entries_in_image; u++)
+ if(H5C__encode_cache_image_entry(f, cache_ptr, &p, u) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTENCODE, FAIL, "entry image construction failed")
+ HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_data_len);
+
+ /* Construct the adaptive resize status image -- not yet */
+
+ /* Compute the checksum and encode */
+ chksum = H5_checksum_metadata(cache_ptr->image_buffer, (size_t)(cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM), 0);
+ UINT32ENCODE(p, chksum);
+ HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) == cache_ptr->image_data_len);
+ HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) <= cache_ptr->image_len);
+
+#ifndef NDEBUG
+ /* validate the metadata cache image we just constructed by decoding it
+ * and comparing the result with the original data.
+ */
+ {
+ uint32_t old_chksum;
+ const uint8_t * q;
+ H5C_t * fake_cache_ptr = NULL;
+ unsigned v;
+ herr_t status; /* Status from decoding */
+
+ fake_cache_ptr = (H5C_t *)H5MM_malloc(sizeof(H5C_t));
+ HDassert(fake_cache_ptr);
+ fake_cache_ptr->magic = H5C__H5C_T_MAGIC;
+
+ /* needed for sanity checks */
+ fake_cache_ptr->image_len = cache_ptr->image_len;
+ q = (const uint8_t *)cache_ptr->image_buffer;
+ status = H5C__decode_cache_image_header(f, fake_cache_ptr, &q);
+ HDassert(status >= 0);
+
+ HDassert(NULL != p);
+ HDassert(fake_cache_ptr->num_entries_in_image == cache_ptr->num_entries_in_image);
+
+ fake_cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_malloc(sizeof(H5C_image_entry_t) *
+ (size_t)(fake_cache_ptr->num_entries_in_image + 1));
+ HDassert(fake_cache_ptr->image_entries);
+
+ for(u = 0; u < fake_cache_ptr->num_entries_in_image; u++) {
+ (fake_cache_ptr->image_entries)[u].magic = H5C_IMAGE_ENTRY_T_MAGIC;
+ (fake_cache_ptr->image_entries)[u].image_ptr = NULL;
+
+ /* touch up f->shared->cache to satisfy sanity checks... */
+ f->shared->cache = fake_cache_ptr;
+ status = H5C__decode_cache_image_entry(f, fake_cache_ptr, &q, u);
+ HDassert(status >= 0);
+
+ /* ...and then return f->shared->cache to its correct value */
+ f->shared->cache = cache_ptr;
+
+ /* verify expected contents */
+ HDassert((cache_ptr->image_entries)[u].addr == (fake_cache_ptr->image_entries)[u].addr);
+ HDassert((cache_ptr->image_entries)[u].size == (fake_cache_ptr->image_entries)[u].size);
+ HDassert((cache_ptr->image_entries)[u].type_id == (fake_cache_ptr->image_entries)[u].type_id);
+ HDassert((cache_ptr->image_entries)[u].lru_rank == (fake_cache_ptr->image_entries)[u].lru_rank);
+ HDassert((cache_ptr->image_entries)[u].is_dirty == (fake_cache_ptr->image_entries)[u].is_dirty);
+ /* don't check image_fd_height as it is not stored in
+ * the metadata cache image block.
+ */
+ HDassert((cache_ptr->image_entries)[u].fd_child_count == (fake_cache_ptr->image_entries)[u].fd_child_count);
+ HDassert((cache_ptr->image_entries)[u].fd_dirty_child_count == (fake_cache_ptr->image_entries)[u].fd_dirty_child_count);
+ HDassert((cache_ptr->image_entries)[u].fd_parent_count == (fake_cache_ptr->image_entries)[u].fd_parent_count);
+
+ for(v = 0; v < (cache_ptr->image_entries)[u].fd_parent_count; v++)
+ HDassert((cache_ptr->image_entries)[u].fd_parent_addrs[v] == (fake_cache_ptr->image_entries)[u].fd_parent_addrs[v]);
+
+ /* free the fd_parent_addrs array if it exists */
+ if((fake_cache_ptr->image_entries)[u].fd_parent_addrs) {
+ HDassert((fake_cache_ptr->image_entries)[u].fd_parent_count > 0);
+ (fake_cache_ptr->image_entries)[u].fd_parent_addrs = (haddr_t *)H5MM_xfree((fake_cache_ptr->image_entries)[u].fd_parent_addrs);
+ (fake_cache_ptr->image_entries)[u].fd_parent_count = 0;
+ } /* end if */
+ else
+ HDassert((fake_cache_ptr->image_entries)[u].fd_parent_count == 0);
+
+ HDassert((cache_ptr->image_entries)[u].image_ptr);
+ HDassert((fake_cache_ptr->image_entries)[u].image_ptr);
+ HDassert(!HDmemcmp((cache_ptr->image_entries)[u].image_ptr,
+ (fake_cache_ptr->image_entries)[u].image_ptr,
+ (cache_ptr->image_entries)[u].size));
+
+ (fake_cache_ptr->image_entries)[u].image_ptr = H5MM_xfree((fake_cache_ptr->image_entries)[u].image_ptr);
+ } /* end for */
+
+ HDassert((size_t)(q - (const uint8_t *)cache_ptr->image_buffer) == cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM);
+
+ /* compute the checksum */
+ old_chksum = chksum;
+ chksum = H5_checksum_metadata(cache_ptr->image_buffer, (size_t)(cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM), 0);
+ HDassert(chksum == old_chksum);
+
+ fake_cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_xfree(fake_cache_ptr->image_entries);
+ fake_cache_ptr = (H5C_t *)H5MM_xfree(fake_cache_ptr);
+ } /* end block */
+#endif /* NDEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__construct_cache_image_buffer() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__generate_cache_image()
+ *
+ * Purpose: Generate the cache image and write it to the file, if
+ * directed.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: Quincey Koziol
+ * 1/26/17
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__generate_cache_image(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(cache_ptr == f->shared->cache);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Construct cache image */
+ if(H5C__construct_cache_image_buffer(f, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't create metadata cache image")
+
+ /* Free image entries array */
+ if(H5C__free_image_entries_array(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't free image entries array")
+
+ /* Write cache image block if so configured */
+ if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK) {
+ if(H5C__write_cache_image(f, dxpl_id, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't write metadata cache image block to file")
+
+ H5C__UPDATE_STATS_FOR_CACHE_IMAGE_CREATE(cache_ptr);
+ } /* end if */
+
+ /* Free cache image buffer */
+ HDassert(cache_ptr->image_buffer);
+ cache_ptr->image_buffer = H5MM_xfree(cache_ptr->image_buffer);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__generate_cache_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__deserialize_prefetched_entry()
+ *
+ * Purpose: Deserialize the supplied prefetched entry entry, and return
+ * a pointer to the deserialized entry in *entry_ptr_ptr.
+ * If successful, remove the prefetched entry from the cache,
+ * and free it. Insert the deserialized entry into the cache.
+ *
+ * Note that the on disk image of the entry is not freed --
+ * a pointer to it is stored in the deserialized entries'
+ * image_ptr field, and its image_up_to_date field is set to
+ * TRUE unless the entry is dirtied by the deserialize call.
+ *
+ * If the prefetched entry is a flush dependency child,
+ * destroy that flush dependency prior to calling the
+ * deserialize callback. If appropriate, the flush dependency
+ * relationship will be recreated by the cache client.
+ *
+ * If the prefetched entry is a flush dependency parent,
+ * destroy the flush dependency relationship with all its
+ * children. As all these children must be prefetched entries,
+ * recreate these flush dependency relationships with
+ * deserialized entry after it is inserted in the cache.
+ *
+ * Since deserializing a prefetched entry is semantically
+ * equivalent to a load, issue an entry loaded nofification
+ * if the notify callback is defined.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Note that *entry_ptr_ptr is undefined on failure.
+ *
+ * Programmer: John Mainzer, 8/10/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__deserialize_prefetched_entry(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr,
+ H5C_cache_entry_t **entry_ptr_ptr, const H5C_class_t *type,
+ haddr_t addr, void *udata)
+{
+ hbool_t dirty = FALSE; /* Flag indicating whether thing was
+ * dirtied during deserialize
+ */
+ size_t len; /* Size of image in file */
+ void * thing = NULL; /* Pointer to thing loaded */
+ H5C_cache_entry_t * pf_entry_ptr; /* pointer to the prefetched entry */
+ /* supplied in *entry_ptr_ptr. */
+ H5C_cache_entry_t * ds_entry_ptr; /* Alias for thing loaded, as cache
+ * entry
+ */
+ H5C_cache_entry_t** fd_children = NULL; /* Pointer to a dynamically */
+ /* allocated array of pointers to */
+ /* the flush dependency children of */
+ /* the prefetched entry, or NULL if */
+ /* that array does not exist. */
+ unsigned flush_flags = (H5C__FLUSH_INVALIDATE_FLAG |
+ H5C__FLUSH_CLEAR_ONLY_FLAG);
+ int i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ HDassert(f->shared->cache == cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(entry_ptr_ptr);
+ HDassert(*entry_ptr_ptr);
+ pf_entry_ptr = *entry_ptr_ptr;
+ HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(pf_entry_ptr->type);
+ HDassert(pf_entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID);
+ HDassert(pf_entry_ptr->prefetched);
+ HDassert(pf_entry_ptr->image_up_to_date);
+ HDassert(pf_entry_ptr->image_ptr);
+ HDassert(pf_entry_ptr->size > 0);
+ HDassert(pf_entry_ptr->addr == addr);
+ HDassert(type);
+ HDassert(type->id == pf_entry_ptr->prefetch_type_id);
+ HDassert(type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type);
+
+ /* verify absence of prohibited or unsupported type flag combinations */
+ HDassert(!(type->flags & H5C__CLASS_SKIP_READS));
+
+ /* Can't see how skip reads could be usefully combined with
+ * either the speculative read flag. Hence disallow.
+ */
+ HDassert(!((type->flags & H5C__CLASS_SKIP_READS) &&
+ (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG)));
+ HDassert(H5F_addr_defined(addr));
+ HDassert(type->get_initial_load_size);
+ HDassert(type->deserialize);
+
+ /* if *pf_entry_ptr is a flush dependency child, destroy all such
+ * relationships now. The client will restore the relationship(s) with
+ * the deserialized entry if appropriate.
+ */
+ HDassert(pf_entry_ptr->fd_parent_count == pf_entry_ptr->flush_dep_nparents);
+ for(i = (int)(pf_entry_ptr->fd_parent_count) - 1; i >= 0; i--) {
+ HDassert(pf_entry_ptr->flush_dep_parent);
+ HDassert(pf_entry_ptr->flush_dep_parent[i]);
+ HDassert(pf_entry_ptr->flush_dep_parent[i]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(pf_entry_ptr->flush_dep_parent[i]->flush_dep_nchildren > 0);
+ HDassert(pf_entry_ptr->fd_parent_addrs);
+ HDassert(pf_entry_ptr->flush_dep_parent[i]->addr == pf_entry_ptr->fd_parent_addrs[i]);
+
+ if(H5C_destroy_flush_dependency(pf_entry_ptr->flush_dep_parent[i], pf_entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry parent flush dependency")
+
+ pf_entry_ptr->fd_parent_addrs[i] = HADDR_UNDEF;
+ } /* end for */
+ HDassert(pf_entry_ptr->flush_dep_nparents == 0);
+
+ /* If *pf_entry_ptr is a flush dependency parent, destroy its flush
+ * dependency relationships with all its children (which must be
+ * prefetched entries as well).
+ *
+ * These flush dependency relationships will have to be restored
+ * after the deserialized entry is inserted into the cache in order
+ * to transfer these relationships to the new entry. Hence save the
+ * pointers to the flush dependency children of *pf_enty_ptr for later
+ * use.
+ */
+ if(pf_entry_ptr->fd_child_count > 0) {
+ if(NULL == (fd_children = (H5C_cache_entry_t **)H5MM_calloc(sizeof(H5C_cache_entry_t **) * (size_t)(pf_entry_ptr->fd_child_count + 1))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd child ptr array")
+
+ if(H5C__destroy_pf_entry_child_flush_deps(cache_ptr, pf_entry_ptr, fd_children) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry child flush dependency(s).")
+ } /* end if */
+
+ /* Since the size of the on disk image is known exactly, there is
+ * no need for either a call to the get_initial_load_size() callback,
+ * or retries if the H5C__CLASS_SPECULATIVE_LOAD_FLAG flag is set.
+ * Similarly, there is no need to clamp possible reads beyond
+ * EOF.
+ */
+ len = pf_entry_ptr->size;
+
+ /* Deserialize the prefetched on-disk image of the entry into the
+ * native memory form
+ */
+ if(NULL == (thing = type->deserialize(pf_entry_ptr->image_ptr, len, udata, &dirty)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "Can't deserialize image")
+ ds_entry_ptr = (H5C_cache_entry_t *)thing;
+
+ /* In general, an entry should be clean just after it is loaded.
+ *
+ * However, when this code is used in the metadata cache, it is
+ * possible that object headers will be dirty at this point, as
+ * the deserialize function will alter object headers if necessary to
+ * fix an old bug.
+ *
+ * In the following assert:
+ *
+ * HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6 ) );
+ *
+ * note that type ids 5 & 6 are associated with object headers in the
+ * metadata cache.
+ *
+ * When we get to using H5C for other purposes, we may wish to
+ * tighten up the assert so that the loophole only applies to the
+ * metadata cache.
+ *
+ * Note that at present, dirty can't be set to true with prefetched
+ * entries. However this may change, so include this functionality
+ * against that posibility.
+ *
+ * Also, note that it is possible for a prefetched entry to be dirty --
+ * hence the value assigned to ds_entry_ptr->is_dirty below.
+ */
+
+ HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6) );
+
+ ds_entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC;
+ ds_entry_ptr->cache_ptr = f->shared->cache;
+ ds_entry_ptr->addr = addr;
+ ds_entry_ptr->size = len;
+ HDassert(ds_entry_ptr->size < H5C_MAX_ENTRY_SIZE);
+ ds_entry_ptr->image_ptr = pf_entry_ptr->image_ptr;
+ ds_entry_ptr->image_up_to_date = !dirty;
+ ds_entry_ptr->type = type;
+ ds_entry_ptr->is_dirty = dirty | pf_entry_ptr->is_dirty;
+ ds_entry_ptr->dirtied = FALSE;
+ ds_entry_ptr->is_protected = FALSE;
+ ds_entry_ptr->is_read_only = FALSE;
+ ds_entry_ptr->ro_ref_count = 0;
+ ds_entry_ptr->is_pinned = FALSE;
+ ds_entry_ptr->in_slist = FALSE;
+ ds_entry_ptr->flush_marker = FALSE;
+#ifdef H5_HAVE_PARALLEL
+ ds_entry_ptr->clear_on_unprotect = FALSE;
+ ds_entry_ptr->flush_immediately = FALSE;
+ ds_entry_ptr->coll_access = FALSE;
+#endif /* H5_HAVE_PARALLEL */
+ ds_entry_ptr->flush_in_progress = FALSE;
+ ds_entry_ptr->destroy_in_progress = FALSE;
+
+ ds_entry_ptr->ring = pf_entry_ptr->ring;
+
+ /* Initialize flush dependency height fields */
+ ds_entry_ptr->flush_dep_parent = NULL;
+ ds_entry_ptr->flush_dep_nparents = 0;
+ ds_entry_ptr->flush_dep_parent_nalloc = 0;
+ ds_entry_ptr->flush_dep_nchildren = 0;
+ ds_entry_ptr->flush_dep_ndirty_children = 0;
+ ds_entry_ptr->flush_dep_nunser_children = 0;
+
+ /* Initialize fields supporting the hash table: */
+ ds_entry_ptr->ht_next = NULL;
+ ds_entry_ptr->ht_prev = NULL;
+ ds_entry_ptr->il_next = NULL;
+ ds_entry_ptr->il_prev = NULL;
+
+ /* Initialize fields supporting replacement policies: */
+ ds_entry_ptr->next = NULL;
+ ds_entry_ptr->prev = NULL;
+ ds_entry_ptr->aux_next = NULL;
+ ds_entry_ptr->aux_prev = NULL;
+#ifdef H5_HAVE_PARALLEL
+ pf_entry_ptr->coll_next = NULL;
+ pf_entry_ptr->coll_prev = NULL;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Initialize cache image related fields */
+ ds_entry_ptr->include_in_image = FALSE;
+ ds_entry_ptr->lru_rank = 0;
+ ds_entry_ptr->image_dirty = FALSE;
+ ds_entry_ptr->fd_parent_count = 0;
+ ds_entry_ptr->fd_parent_addrs = NULL;
+ ds_entry_ptr->fd_child_count = pf_entry_ptr->fd_child_count;
+ ds_entry_ptr->fd_dirty_child_count = 0;
+ ds_entry_ptr->image_fd_height = 0;
+ ds_entry_ptr->prefetched = FALSE;
+ ds_entry_ptr->prefetch_type_id = 0;
+ ds_entry_ptr->age = 0;
+ ds_entry_ptr->prefetched_dirty = pf_entry_ptr->prefetched_dirty;
+#ifndef NDEBUG /* debugging field */
+ ds_entry_ptr->serialization_count = 0;
+#endif /* NDEBUG */
+
+ H5C__RESET_CACHE_ENTRY_STATS(ds_entry_ptr);
+
+ /* Apply to to the newly deserialized entry */
+ if(H5C__tag_entry(cache_ptr, ds_entry_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot tag metadata entry")
+
+ /* We have successfully deserialized the prefetched entry.
+ *
+ * Before we return a pointer to the deserialized entry, we must remove
+ * the prefetched entry from the cache, discard it, and replace it with
+ * the deserialized entry. Note that we do not free the prefetched
+ * entries image, as that has been transferred to the deserialized
+ * entry.
+ *
+ * Also note that we have not yet restored any flush dependencies. This
+ * must wait until the deserialized entry is inserted in the cache.
+ *
+ * To delete the prefetched entry from the cache:
+ *
+ * 1) Set pf_entry_ptr->image_ptr to NULL. Since we have already
+ * transferred the buffer containing the image to *ds_entry_ptr,
+ * this is not a memory leak.
+ *
+ * 2) Call H5C__flush_single_entry() with the H5C__FLUSH_INVALIDATE_FLAG
+ * and H5C__FLUSH_CLEAR_ONLY_FLAG flags set.
+ */
+ pf_entry_ptr->image_ptr = NULL;
+ if(pf_entry_ptr->is_dirty) {
+ HDassert(pf_entry_ptr->in_slist);
+ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG;
+ } /* end if */
+
+ if(H5C__flush_single_entry(f, dxpl_id, pf_entry_ptr, flush_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "can't expunge prefetched entry")
+
+#ifndef NDEGUG /* verify deletion */
+ H5C__SEARCH_INDEX(cache_ptr, addr, pf_entry_ptr, FAIL);
+
+ HDassert(NULL == pf_entry_ptr);
+#endif /* NDEBUG */
+
+ /* Insert the deserialized entry into the cache. */
+ H5C__INSERT_IN_INDEX(cache_ptr, ds_entry_ptr, FAIL)
+
+ HDassert(!ds_entry_ptr->in_slist);
+ if(ds_entry_ptr->is_dirty)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, ds_entry_ptr, FAIL)
+
+ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, ds_entry_ptr, FAIL)
+
+ /* Deserializing a prefetched entry is the conceptual equivalent of
+ * loading it from file. If the deserialized entry has a notify callback,
+ * send an "after load" notice now that the deserialized entry is fully
+ * integrated into the cache.
+ */
+ if(ds_entry_ptr->type->notify &&
+ (ds_entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, ds_entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry loaded into cache")
+
+ /* Restore flush dependencies with the flush dependency children of
+ * of the prefetched entry. Note that we must protect *ds_entry_ptr
+ * before the call to avoid triggering sanity check failures, and
+ * then unprotect it afterwards.
+ */
+ i = 0;
+ if(fd_children != NULL) {
+ H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, ds_entry_ptr, FAIL)
+ ds_entry_ptr->is_protected = TRUE;
+ while(fd_children[i] != NULL) {
+ /* Sanity checks */
+ HDassert((fd_children[i])->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert((fd_children[i])->prefetched);
+ HDassert((fd_children[i])->fd_parent_count > 0);
+ HDassert((fd_children[i])->fd_parent_addrs);
+
+#ifndef NDEBUG
+ {
+ int j;
+ hbool_t found;
+
+ j = 0;
+ found = FALSE;
+ while((j < (int)((fd_children[i])->fd_parent_count)) && (!found)) {
+ if((fd_children[i])->fd_parent_addrs[j] == ds_entry_ptr->addr)
+ found = TRUE;
+
+ j++;
+ } /* end while */
+ HDassert(found);
+ }
+#endif /* NDEBUG */
+
+ if(H5C_create_flush_dependency(ds_entry_ptr, fd_children[i]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Can't restore child flush dependency")
+
+ i++;
+ } /* end while */
+
+ H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, ds_entry_ptr, FAIL);
+ ds_entry_ptr->is_protected = FALSE;
+ } /* end if ( fd_children != NULL ) */
+ HDassert((unsigned)i == ds_entry_ptr->fd_child_count);
+
+ ds_entry_ptr->fd_child_count = 0;
+ H5C__UPDATE_STATS_FOR_PREFETCH_HIT(cache_ptr)
+
+ /* finally, pass ds_entry_ptr back to the caller */
+ *entry_ptr_ptr = ds_entry_ptr;
+
+done:
+ if(fd_children)
+ fd_children = (H5C_cache_entry_t **)H5MM_xfree((void *)fd_children);
+
+ /* Release resources on error */
+ if(FAIL == ret_value)
+ if(thing && type->free_icr(thing) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__deserialize_prefetched_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__free_image_entries_array
+ *
+ * Purpose: If the image entries array exists, free the image
+ * associated with each entry, and then free the image
+ * entries array proper.
+ *
+ * Note that by the time this function is called, the cache
+ * should have removed all entries from its data structures.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 8/4/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__free_image_entries_array(H5C_t * cache_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->image_ctl.generate_image);
+ HDassert(cache_ptr->index_len == 0);
+
+ /* Check for entries to free */
+ if(cache_ptr->image_entries != NULL) {
+ unsigned u; /* Local index variable */
+
+ for(u = 0; u < cache_ptr->num_entries_in_image; u++) {
+ H5C_image_entry_t *ie_ptr; /* Image entry to release */
+
+ /* Get pointer to image entry */
+ ie_ptr = &((cache_ptr->image_entries)[u]);
+
+ /* Sanity checks */
+ HDassert(ie_ptr);
+ HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC);
+ HDassert(ie_ptr->image_ptr);
+
+ /* Free the parent addrs array if appropriate */
+ if(ie_ptr->fd_parent_addrs) {
+ HDassert(ie_ptr->fd_parent_count > 0);
+
+ ie_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(ie_ptr->fd_parent_addrs);
+ } /* end if */
+ else
+ HDassert(ie_ptr->fd_parent_count == 0);
+
+ /* Free the image */
+ ie_ptr->image_ptr = H5MM_xfree(ie_ptr->image_ptr);
+
+ /* Set magic field to bad magic so we can detect freed entries */
+ ie_ptr->magic = H5C_IMAGE_ENTRY_T_BAD_MAGIC;
+ } /* end for */
+
+ /* Free the image entries array */
+ cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_xfree(cache_ptr->image_entries);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C__free_image_entries_array() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_force_cache_image_load()
+ *
+ * Purpose: On rare occasions, it is necessary to run
+ * H5MF_tidy_self_referential_fsm_hack() prior to the first
+ * metadata cache access. This is a problem as if there is a
+ * cache image at the end of the file, that routine will
+ * discard it.
+ *
+ * We solve this issue by calling this function, which will
+ * load the cache image and then call
+ * H5MF_tidy_self_referential_fsm_hack() to discard it.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 1/11/17
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_force_cache_image_load(H5F_t *f, hid_t dxpl_id)
+{
+ H5C_t *cache_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->load_image);
+
+ /* Load the cache image, if requested */
+ if(cache_ptr->load_image) {
+ cache_ptr->load_image = FALSE;
+ if(H5C__load_cache_image(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "can't load cache image")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_force_cache_image_load() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_cache_image_config
+ *
+ * Purpose: Copy the current configuration for cache image generation
+ * on file close into the instance of H5C_cache_image_ctl_t
+ * pointed to by config_ptr.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 7/3/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_cache_image_config(const H5C_t * cache_ptr,
+ H5C_cache_image_ctl_t *config_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache_ptr on entry")
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad config_ptr on entry")
+
+ *config_ptr = cache_ptr->image_ctl;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_cache_image_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_image_stats
+ *
+ * Purpose: Prints statistics specific to the cache image.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 10/26/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+#if H5C_COLLECT_CACHE_STATS
+H5C_image_stats(H5C_t * cache_ptr, hbool_t print_header)
+#else /* H5C_COLLECT_CACHE_STATS */
+H5C_image_stats(H5C_t * cache_ptr, hbool_t H5_ATTR_UNUSED print_header)
+#endif /* H5C_COLLECT_CACHE_STATS */
+{
+#if H5C_COLLECT_CACHE_STATS
+ int i;
+ int64_t total_hits = 0;
+ int64_t total_misses = 0;
+ double hit_rate;
+ double prefetch_use_rate;
+#endif /* H5C_COLLECT_CACHE_STATS */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(!cache_ptr || cache_ptr->magic != H5C__H5C_T_MAGIC)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr")
+
+#if H5C_COLLECT_CACHE_STATS
+ for(i = 0; i <= cache_ptr->max_type_id; i++) {
+ total_hits += cache_ptr->hits[i];
+ total_misses += cache_ptr->misses[i];
+ } /* end for */
+
+ if((total_hits > 0) || (total_misses > 0))
+ hit_rate = (double)100.0f * ((double)(total_hits)) / ((double)(total_hits + total_misses));
+ else
+ hit_rate = 0.0f;
+
+ if(cache_ptr->prefetches > 0)
+ prefetch_use_rate = (double)100.0f * ((double)(cache_ptr->prefetch_hits)) /
+ ((double)(cache_ptr->prefetches));
+ else
+ prefetch_use_rate = 0.0f;
+
+ if(print_header) {
+ HDfprintf(stdout,
+ "\nhit prefetches prefetch image pf hit\n");
+ HDfprintf(stdout,
+ "rate: total: dirty: hits: flshs: evct: size: rate:\n");
+ } /* end if */
+
+ HDfprintf(stdout,
+ "%3.1lf %5lld %5lld %5lld %5lld %5lld %5lld %3.1lf\n",
+ hit_rate,
+ (long long)(cache_ptr->prefetches),
+ (long long)(cache_ptr->dirty_prefetches),
+ (long long)(cache_ptr->prefetch_hits),
+ (long long)(cache_ptr->flushes[H5AC_PREFETCHED_ENTRY_ID]),
+ (long long)(cache_ptr->evictions[H5AC_PREFETCHED_ENTRY_ID]),
+ (long long)(cache_ptr->last_image_size),
+ prefetch_use_rate);
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_image_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__read_cache_image
+ *
+ * Purpose: Load the metadata cache image from the specified location
+ * in the file, and return it in the supplied buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/16/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__read_cache_image(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(cache_ptr);
+ HDassert(H5F_addr_defined(cache_ptr->image_addr));
+ HDassert(cache_ptr->image_len > 0);
+ HDassert(cache_ptr->image_buffer);
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
+ int mpi_result;
+
+ if ( ( NULL == aux_ptr ) || ( aux_ptr->mpi_rank == 0 ) ) {
+
+ HDassert((NULL == aux_ptr) ||
+ (aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC));
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Read the buffer (if serial access, or rank 0 of parallel access) */
+ if ( H5F_block_read(f, H5FD_MEM_SUPER, cache_ptr->image_addr,
+ cache_ptr->image_len, dxpl_id,
+ cache_ptr->image_buffer) < 0)
+
+ HGOTO_ERROR(H5E_CACHE, H5E_READERROR, FAIL, \
+ "Can't read metadata cache image block")
+
+ H5C__UPDATE_STATS_FOR_CACHE_IMAGE_READ(cache_ptr)
+
+#ifdef H5_HAVE_PARALLEL
+ if ( aux_ptr ) {
+
+ /* Broadcast cache image */
+ if ( MPI_SUCCESS !=
+ (mpi_result = MPI_Bcast(cache_ptr->image_buffer,
+ (int)cache_ptr->image_len, MPI_BYTE,
+ 0, aux_ptr->mpi_comm)) )
+
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ } /* end if */
+ } /* end if */
+ else if ( aux_ptr ) {
+
+ /* Retrieve the contents of the metadata cache image from process 0 */
+ if ( MPI_SUCCESS !=
+ (mpi_result = MPI_Bcast(cache_ptr->image_buffer,
+ (int)cache_ptr->image_len, MPI_BYTE,
+ 0, aux_ptr->mpi_comm)) )
+
+ HMPI_GOTO_ERROR(FAIL, "can't receive cache image MPI_Bcast", \
+ mpi_result)
+ } /* end else-if */
+} /* end block */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C__read_cache_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__load_cache_image
+ *
+ * Purpose: Read the cache image superblock extension message and
+ * delete it if so directed.
+ *
+ * Then load the cache image block at the specified location,
+ * decode it, and insert its contents into the metadata
+ * cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__load_cache_image(H5F_t *f, hid_t dxpl_id)
+{
+ H5C_t * cache_ptr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* If the image address is defined, load the image, decode it,
+ * and insert its contents into the metadata cache.
+ *
+ * Note that under normal operating conditions, it is an error if the
+ * image address is HADDR_UNDEF. However, to facilitate testing,
+ * we allow this special value of the image address which means that
+ * no image exists, and that the load operation should be skipped
+ * silently.
+ */
+ if(H5F_addr_defined(cache_ptr->image_addr)) {
+ /* Sanity checks */
+ HDassert(cache_ptr->image_len > 0);
+ HDassert(cache_ptr->image_buffer == NULL);
+
+ /* Allocate space for the image */
+ if(NULL == (cache_ptr->image_buffer = H5MM_malloc(cache_ptr->image_len + 1)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for cache image buffer")
+
+ /* Load the image from file */
+ if(H5C__read_cache_image(f, dxpl_id, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_READERROR, FAIL, "Can't read metadata cache image block")
+
+ /* Reconstruct cache contents, from image */
+ if(H5C__reconstruct_cache_contents(f, dxpl_id, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "Can't reconstruct cache contents from image block")
+
+ /* Free the image buffer */
+ cache_ptr->image_buffer = H5MM_xfree(cache_ptr->image_buffer);
+
+ /* Update stats -- must do this now, as we are about
+ * to discard the size of the cache image.
+ */
+ H5C__UPDATE_STATS_FOR_CACHE_IMAGE_LOAD(cache_ptr)
+
+ cache_ptr->image_loaded = TRUE;
+ } /* end if */
+
+ /* If directed, free the on disk metadata cache image */
+ if(cache_ptr->delete_image) {
+ if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_MDCI_MSG_ID) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove metadata cache image message from superblock extension")
+
+ /* Reset image block values */
+ cache_ptr->image_len = 0;
+ cache_ptr->image_data_len = 0;
+ cache_ptr->image_addr = HADDR_UNDEF;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__load_cache_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_load_cache_image_on_next_protect()
+ *
+ * Purpose: Note the fact that a metadata cache image superblock
+ * extension message exists, along with the base address
+ * and length of the metadata cache image block.
+ *
+ * Once this notification is received the metadata cache
+ * image block must be read, decoded, and loaded into the
+ * cache on the next call to H5C_protect().
+ *
+ * Further, if the file is opened R/W, the metadata cache
+ * image superblock extension message must be deleted from
+ * the superblock extension and the image block freed
+ *
+ * Contrawise, if the file is openened R/O, the metadata
+ * cache image superblock extension message and image block
+ * must be left as is. Further, any dirty entries in the
+ * cache image block must be marked as clean to avoid
+ * attempts to write them on file close.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 7/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_load_cache_image_on_next_protect(H5F_t *f, haddr_t addr, hsize_t len,
+ hbool_t rw)
+{
+ H5C_t *cache_ptr;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Set information needed to load cache image */
+ cache_ptr->image_addr = addr,
+ cache_ptr->image_len = len;
+ cache_ptr->load_image = TRUE;
+ cache_ptr->delete_image = rw;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C_load_cache_image_on_next_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__image_entry_cmp
+ *
+ * Purpose: Comparison callback for qsort(3) on image entries.
+ * Entries are sorted first by flush dependency height,
+ * and then by LRU rank.
+ *
+ * Note: Entries with a _greater_ flush dependency height should
+ * be sorted earlier than entries with lower heights, since
+ * leafs in the flush dependency graph are at height 0, and their
+ * parents need to be earlier in the image, so that they can
+ * construct their flush dependencies when decoded.
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * first entry is considered to be respectively less than,
+ * equal to, or greater than the second.
+ *
+ * Programmer: Quincey Koziol
+ * 1/20/16
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__image_entry_cmp(const void *_entry1, const void *_entry2)
+{
+ const H5C_image_entry_t *entry1 = (const H5C_image_entry_t *)_entry1; /* Pointer to first image entry to compare */
+ const H5C_image_entry_t *entry2 = (const H5C_image_entry_t *)_entry2; /* Pointer to second image entry to compare */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(entry1);
+ HDassert(entry2);
+
+ if(entry1->image_fd_height > entry2->image_fd_height)
+ ret_value = -1;
+ else if(entry1->image_fd_height < entry2->image_fd_height)
+ ret_value = 1;
+ else {
+ /* Sanity check */
+ HDassert(entry1->lru_rank >= -1);
+ HDassert(entry2->lru_rank >= -1);
+
+ if(entry1->lru_rank < entry2->lru_rank)
+ ret_value = -1;
+ else if(entry1->lru_rank > entry2->lru_rank)
+ ret_value = 1;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__image_entry_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prep_image_for_file_close
+ *
+ * Purpose: The objective of the call is to allow the metadata cache
+ * to do any preparatory work prior to generation of a
+ * cache image.
+ *
+ * In particular, the cache must
+ *
+ * 1) serialize all its entries,
+ *
+ * 2) compute the size of the metadata cache image,
+ *
+ * 3) allocate space for the metadata cache image, and
+ *
+ * 4) setup the metadata cache image superblock extension
+ * message with the address and size of the metadata
+ * cache image.
+ *
+ * The parallel case is complicated by the fact that
+ * while all metadata caches must contain the same set of
+ * dirty entries, there is no such requirement for clean
+ * entries or the order that entries appear in the LRU.
+ *
+ * Thus, there is no requirement that different processes
+ * will construct cache images of the same size.
+ *
+ * This is not a major issue as long as all processes include
+ * the same set of dirty entries in the cache -- as they
+ * currently do (note that this will change when we implement
+ * the ageout feature). Since only the process zero cache
+ * writes the cache image, all that is necessary is to
+ * broadcast the process zero cache size for use in the
+ * superblock extension messages and cache image block
+ * allocations.
+ *
+ * Note: At present, cache image is disabled in the
+ * parallel case as the new collective metadata write
+ * code must be modified to support cache image.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/3/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__prep_image_for_file_close(H5F_t *f, hid_t dxpl_id, hbool_t *image_generated)
+{
+ H5C_t * cache_ptr = NULL;
+ haddr_t eoa_frag_addr = HADDR_UNDEF;
+ hsize_t eoa_frag_size = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(image_generated);
+
+ /* If the file is opened and closed without any access to
+ * any group or data set, it is possible that the cache image (if
+ * it exists) has not been read yet. Do this now if required.
+ */
+ if(cache_ptr->load_image) {
+ cache_ptr->load_image = FALSE;
+ if(H5C__load_cache_image(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "can't load cache image")
+ } /* end if */
+
+ /* Before we start to generate the cache image (if requested), verify
+ * that the superblock supports superblock extension messages, and
+ * silently cancel any request for a cache image if it does not.
+ *
+ * Ideally, we would do this when the cache image is requested,
+ * but the necessary information is not necessary available at that
+ * time -- hence this last minute check.
+ *
+ * Note that under some error conditions, the superblock will be
+ * undefined in this case as well -- if so, assume that the
+ * superblock does not support superblock extension messages.
+ */
+ if((NULL == f->shared->sblock) ||
+ (f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2)) {
+ H5C_cache_image_ctl_t default_image_ctl = H5C__DEFAULT_CACHE_IMAGE_CTL;
+
+ cache_ptr->image_ctl = default_image_ctl;
+ HDassert(!(cache_ptr->image_ctl.generate_image));
+ } /* end if */
+
+ /* Generate the cache image, if requested */
+ if(cache_ptr->image_ctl.generate_image) {
+ /* Create the cache image super block extension message.
+ *
+ * Note that the base address and length of the metadata cache
+ * image are undefined at this point, and thus will have to be
+ * updated later.
+ *
+ * Create the super block extension message now so that space
+ * is allocated for it (if necessary) before we allocate space
+ * for the cache image block.
+ *
+ * To simplify testing, do this only if the
+ * H5C_CI__GEN_MDCI_SBE_MESG bit is set in
+ * cache_ptr->image_ctl.flags.
+ */
+ if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDCI_SBE_MESG)
+ if(H5C__write_cache_image_superblock_msg(f, dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "creation of cache image SB mesg failed.")
+
+ /* Serialize the cache */
+ if(H5C__serialize_cache(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "serialization of the cache failed")
+
+ /* Scan the cache and record data needed to construct the
+ * cache image. In particular, for each entry we must record:
+ *
+ * 1) rank in LRU (if entry is in LRU)
+ *
+ * 2) Whether the entry is dirty prior to flush of
+ * cache just prior to close.
+ *
+ * 3) Addresses of flush dependency parents (if any).
+ *
+ * 4) Number of flush dependency children (if any).
+ *
+ * In passing, also compute the size of the metadata cache
+ * image. With the recent modifications of the free space
+ * manager code, this size should be correct.
+ */
+ if(H5C__prep_for_file_close__scan_entries(f, cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C__prep_for_file_close__scan_entries failed")
+ HDassert(HADDR_UNDEF == cache_ptr->image_addr);
+
+#ifdef H5_HAVE_PARALLEL
+ /* In the parallel case, overwrite the image_len with the
+ * value computed by process 0.
+ */
+ if(cache_ptr->aux_ptr) { /* we have multiple processes */
+ int mpi_result;
+ unsigned p0_image_len;
+ H5AC_aux_t * aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
+ if(aux_ptr->mpi_rank == 0) {
+ aux_ptr->p0_image_len = (unsigned)cache_ptr->image_data_len;
+ p0_image_len = aux_ptr->p0_image_len;
+
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&p0_image_len, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ HDassert(p0_image_len == aux_ptr->p0_image_len);
+ } /* end if */
+ else {
+ if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&p0_image_len, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result)
+
+ aux_ptr->p0_image_len = p0_image_len;
+ } /* end else */
+
+ /* Allocate space for a cache image of size equal to that
+ * computed by the process 0. This may be different from
+ * cache_ptr->image_data_len if mpi_rank != 0. However, since
+ * cache image write is suppressed on all processes other than
+ * process 0, this doesn't matter.
+ *
+ * Note that we allocate the cache image directly from the file
+ * driver so as to avoid unsettling the free space managers.
+ */
+ if(HADDR_UNDEF == (cache_ptr->image_addr = H5FD_alloc(f->shared->lf, dxpl_id, H5FD_MEM_SUPER, f,
+ (hsize_t)p0_image_len, &eoa_frag_addr, &eoa_frag_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_NOSPACE, FAIL, "can't allocate file space for metadata cache image")
+ } /* end if */
+ else
+#endif /* H5_HAVE_PARALLEL */
+ /* Allocate the cache image block. Note that we allocate this
+ * this space directly from the file driver so as to avoid
+ * unsettling the free space managers.
+ */
+ if(HADDR_UNDEF == (cache_ptr->image_addr = H5FD_alloc(f->shared->lf, dxpl_id, H5FD_MEM_SUPER, f,
+ (hsize_t)(cache_ptr->image_data_len), &eoa_frag_addr, &eoa_frag_size)))
+ HGOTO_ERROR(H5E_CACHE, H5E_NOSPACE, FAIL, "can't allocate file space for metadata cache image")
+
+ /* Make note of the eoa after allocation of the cache image
+ * block. This value is used for sanity checking when we
+ * shutdown the self referential free space managers after
+ * we destroy the metadata cache.
+ */
+ HDassert(HADDR_UNDEF == f->shared->eoa_post_mdci_fsalloc);
+ if(HADDR_UNDEF == (f->shared->eoa_post_mdci_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)) )
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* For now, drop any fragment left over from the allocation of the
+ * image block on the ground. A fragment should only be returned
+ * if the underlying file alignment is greater than 1.
+ *
+ * Clean this up eventually by extending the size of the cache
+ * image block to the next alignement boundary, and then setting
+ * the image_data_len to the actual size of the cache_image.
+ *
+ * On the off chance that there is some other way to get a
+ * a fragment on a cache image allocation, leave the following
+ * assertion in the code so we will find out.
+ */
+ HDassert((eoa_frag_size == 0) || (f->shared->alignment != 1));
+
+ /* Eventually it will be possible for the length of the cache image
+ * block on file to be greater than the size of the data it
+ * contains. However, for now they must be the same. Set
+ * cache_ptr->image_len accordingly.
+ */
+ cache_ptr->image_len = cache_ptr->image_data_len;
+
+ /* update the metadata cache image superblock extension
+ * message with the new cache image block base address and
+ * length.
+ *
+ * to simplify testing, do this only if the
+ * H5C_CI__GEN_MDC_IMAGE_BLK bit is set in
+ * cache_ptr->image_ctl.flags.
+ */
+ if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK)
+ if(H5C__write_cache_image_superblock_msg(f, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "update of cache image SB mesg failed")
+
+ /* At this point:
+ *
+ * 1) space in the file for the metadata cache image
+ * is allocated,
+ *
+ * 2) the metadata cache image superblock extension
+ * message exists and (if so configured) contains
+ * the correct data,
+ *
+ * 3) All entries in the cache that will appear in the
+ * cache image are serialized with up to date images.
+ *
+ * Since we just updated the cache image message,
+ * the super block extension message is dirty. However,
+ * since the superblock and the superblock extension
+ * can't be included in the cache image, this is a non-
+ * issue.
+ *
+ * 4) All entries in the cache that will be include in
+ * the cache are marked as such, and we have a count
+ * of same.
+ *
+ * 5) Flush dependency heights are calculated for all
+ * entries that will be included in the cache image.
+ *
+ * If there are any entries to be included in the metadata cache
+ * image, allocate, populate, and sort the image_entries array.
+ *
+ * If the metadata cache image will be empty, delete the
+ * metadata cache image superblock extension message, set
+ * cache_ptr->image_ctl.generate_image to FALSE. This will
+ * allow the file close to continue normally without the
+ * unecessary generation of the metadata cache image.
+ */
+ if(cache_ptr->num_entries_in_image > 0) {
+ if(H5C__prep_for_file_close__setup_image_entries_array(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINIT, FAIL, "can't setup image entries array.")
+
+ /* Sort the entries */
+ HDqsort(cache_ptr->image_entries, (size_t)cache_ptr->num_entries_in_image,
+ sizeof(H5C_image_entry_t), H5C__image_entry_cmp);
+ } /* end if */
+ else { /* cancel creation of metadata cache image */
+ HDassert(cache_ptr->image_entries == NULL);
+
+ /* To avoid breaking the control flow tests, only delete
+ * the mdci superblock extension message if the
+ * H5C_CI__GEN_MDC_IMAGE_BLK flag is set in
+ * cache_ptr->image_ctl.flags.
+ */
+ if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK)
+ if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_MDCI_MSG_ID) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove MDC image msg from superblock ext")
+
+ cache_ptr->image_ctl.generate_image = FALSE;
+ } /* end else */
+
+ /* Indicate that a cache image was generated */
+ *image_generated = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__prep_image_for_file_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_cache_image_config
+ *
+ * Purpose: If *config_ptr contains valid data, copy it into the
+ * image_ctl field of *cache_ptr. Make adjustments for
+ * changes in configuration as required.
+ *
+ * If the file is open read only, silently
+ * force the cache image configuration to its default
+ * (which disables construction of a cache image).
+ *
+ * Note that in addition to being inapplicable in the
+ * read only case, cache image is also inapplicable if
+ * the superblock does not support superblock extension
+ * messages. Unfortunately, this information need not
+ * be available at this point. Thus we check for this
+ * later, in H5C_prep_for_file_close() and cancel the
+ * cache image request if appropriate.
+ *
+ * Fail if the new configuration is invalid.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 7/3/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_cache_image_config(const H5F_t *f, H5C_t *cache_ptr,
+ H5C_cache_image_ctl_t *config_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache == f->shared->cache);
+
+ /* Check arguments */
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache_ptr on entry")
+
+ /* Validate the config: */
+ if(H5C_validate_cache_image_config(config_ptr) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid cache image configuration")
+
+#ifdef H5_HAVE_PARALLEL
+ /* The collective metadata write code is not currently compatible
+ * with cache image. Until this is fixed, suppress cache image silently
+ * if there is more than one process.
+ * JRM -- 11/8/16
+ */
+ if(cache_ptr->aux_ptr) {
+ H5C_cache_image_ctl_t default_image_ctl = H5C__DEFAULT_CACHE_IMAGE_CTL;
+
+ cache_ptr->image_ctl = default_image_ctl;
+ HDassert(!(cache_ptr->image_ctl.generate_image));
+ } /* end if */
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ /* A cache image can only be generated if the file is opened read / write
+ * and the superblock supports superblock extension messages.
+ *
+ * However, the superblock version is not available at this point --
+ * hence we can only check the former requirement now. Do the latter
+ * check just before we construct the image..
+ *
+ * If the file is opened read / write, apply the supplied configuration.
+ *
+ * If it is not, set the image configuration to the default, which has
+ * the effect of silently disabling the cache image if it was requested.
+ */
+ if(H5F_INTENT(f) & H5F_ACC_RDWR)
+ cache_ptr->image_ctl = *config_ptr;
+ else {
+ H5C_cache_image_ctl_t default_image_ctl = H5C__DEFAULT_CACHE_IMAGE_CTL;
+
+ cache_ptr->image_ctl = default_image_ctl;
+ HDassert(!(cache_ptr->image_ctl.generate_image));
+ } /* end else */
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_cache_image_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_validate_cache_image_config()
+ *
+ * Purpose: Run a sanity check on the provided instance of struct
+ * H5AC_cache_image_config_t.
+ *
+ * Do nothing and return SUCCEED if no errors are detected,
+ * and flag an error and return FAIL otherwise.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/15/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_validate_cache_image_config(H5C_cache_image_ctl_t * ctl_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(ctl_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL ctl_ptr on entry")
+ if(ctl_ptr->version != H5C__CURR_CACHE_IMAGE_CTL_VER)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown cache image control version")
+
+ /* At present, we do not support inclusion of the adaptive resize
+ * configuration in the cache image. Thus the save_resize_status
+ * field must be FALSE.
+ */
+ if(ctl_ptr->save_resize_status != FALSE)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unexpected value in save_resize_status field")
+
+ /* At present, we do not support prefetched entry ageouts. Thus
+ * the entry_ageout field must be set to
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE.
+ */
+ if(ctl_ptr->entry_ageout != H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unexpected value in entry_ageout field")
+
+ if((ctl_ptr->flags & ~H5C_CI__ALL_FLAGS) != 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown flag set")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_validate_cache_image_config() */
+
+
+/*************************************************************************/
+/**************************** Private Functions: *************************/
+/*************************************************************************/
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__cache_image_block_entry_header_size
+ *
+ * Purpose: Compute the size of the header of the metadata cache
+ * image block, and return the value.
+ *
+ * Return: Size of the header section of the metadata cache image
+ * block in bytes.
+ *
+ * Programmer: John Mainzer
+ * 7/27/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5C__cache_image_block_entry_header_size(const H5F_t * f)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)( 1 + /* type */
+ 1 + /* flags */
+ 1 + /* ring */
+ 1 + /* age */
+ 2 + /* dependency child count */
+ 2 + /* dirty dep child count */
+ 2 + /* dependency parent count */
+ 4 + /* index in LRU */
+ H5F_SIZEOF_ADDR(f) + /* entry offset */
+ H5F_SIZEOF_SIZE(f) ); /* entry length */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__cache_image_block_entry_header_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__cache_image_block_header_size
+ *
+ * Purpose: Compute the size of the header of the metadata cache
+ * image block, and return the value.
+ *
+ * Return: Size of the header section of the metadata cache image
+ * block in bytes.
+ *
+ * Programmer: John Mainzer
+ * 7/27/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5C__cache_image_block_header_size(const H5F_t * f)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)( 4 + /* signature */
+ 1 + /* version */
+ 1 + /* flags */
+ H5F_SIZEOF_SIZE(f) + /* image data length */
+ 4 ); /* num_entries */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__cache_image_block_header_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__decode_cache_image_header()
+ *
+ * Purpose: Decode the metadata cache image buffer header from the
+ * supplied buffer and load the data into the supplied instance
+ * of H5C_t. Advances the buffer pointer to the first byte
+ * after the header image, or unchanged on failure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__decode_cache_image_header(const H5F_t *f, H5C_t *cache_ptr,
+ const uint8_t **buf)
+{
+ uint8_t version;
+ uint8_t flags;
+ hbool_t have_resize_status = FALSE;
+ size_t actual_header_len;
+ size_t expected_header_len;
+ const uint8_t * p;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(buf);
+ HDassert(*buf);
+
+ /* Point to buffer to decode */
+ p = *buf;
+
+ /* Check signature */
+ if(HDmemcmp(p, H5C__MDCI_BLOCK_SIGNATURE, (size_t)H5C__MDCI_BLOCK_SIGNATURE_LEN))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image header signature")
+ p += H5C__MDCI_BLOCK_SIGNATURE_LEN;
+
+ /* Check version */
+ version = *p++;
+ if(version != (uint8_t)H5C__MDCI_BLOCK_VERSION_0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image version")
+
+ /* Decode flags */
+ flags = *p++;
+ if(flags & H5C__MDCI_HEADER_HAVE_RESIZE_STATUS)
+ have_resize_status = TRUE;
+ if(have_resize_status)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "MDC resize status not yet supported")
+
+ /* Read image data length */
+ H5F_DECODE_LENGTH(f, p, cache_ptr->image_data_len);
+
+ /* For now -- will become <= eventually */
+ if(cache_ptr->image_data_len != cache_ptr->image_len)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image data length")
+
+ /* Read num entries */
+ UINT32DECODE(p, cache_ptr->num_entries_in_image);
+ if(cache_ptr->num_entries_in_image == 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache entry count")
+
+ /* Verify expected length of header */
+ actual_header_len = (size_t)(p - *buf);
+ expected_header_len = H5C__cache_image_block_header_size(f);
+ if(actual_header_len != expected_header_len)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad header image len")
+
+ /* Update buffer pointer */
+ *buf = p;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__decode_cache_image_header() */
+
+#ifndef NDEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__decode_cache_image_entry()
+ *
+ * Purpose: Decode the metadata cache image entry from the supplied
+ * buffer into the supplied instance of H5C_image_entry_t.
+ * This includes allocating a buffer for the entry image,
+ * loading it, and seting ie_ptr->image_ptr to point to
+ * the buffer.
+ *
+ * Advances the buffer pointer to the first byte
+ * after the entry, or unchanged on failure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__decode_cache_image_entry(const H5F_t *f, const H5C_t *cache_ptr,
+ const uint8_t **buf, unsigned entry_num)
+{
+ hbool_t is_dirty = FALSE;
+ hbool_t in_lru = FALSE; /* Only used in assertions */
+ hbool_t is_fd_parent = FALSE; /* Only used in assertions */
+ hbool_t is_fd_child = FALSE; /* Only used in assertions */
+ haddr_t addr;
+ hsize_t size = 0;
+ void * image_ptr;
+ uint8_t flags = 0;
+ uint8_t type_id;
+ uint8_t ring;
+ uint8_t age;
+ uint16_t fd_child_count;
+ uint16_t fd_dirty_child_count;
+ uint16_t fd_parent_count;
+ haddr_t * fd_parent_addrs = NULL;
+ int32_t lru_rank;
+ H5C_image_entry_t * ie_ptr = NULL;
+ const uint8_t * p;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(cache_ptr == f->shared->cache);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(buf);
+ HDassert(*buf);
+ HDassert(entry_num < cache_ptr->num_entries_in_image);
+ ie_ptr = &((cache_ptr->image_entries)[entry_num]);
+ HDassert(ie_ptr);
+ HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC);
+
+ /* Get pointer to buffer */
+ p = *buf;
+
+ /* Decode type id */
+ type_id = *p++;
+
+ /* Decode flags */
+ flags = *p++;
+ if(flags & H5C__MDCI_ENTRY_DIRTY_FLAG)
+ is_dirty = TRUE;
+ if(flags & H5C__MDCI_ENTRY_IN_LRU_FLAG)
+ in_lru = TRUE;
+ if(flags & H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG)
+ is_fd_parent = TRUE;
+ if(flags & H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG)
+ is_fd_child = TRUE;
+
+ /* Decode ring */
+ ring = *p++;
+ HDassert(ring > (uint8_t)(H5C_RING_UNDEFINED));
+ HDassert(ring < (uint8_t)(H5C_RING_NTYPES));
+
+ /* Decode age */
+ age = *p++;
+
+ /* Decode dependency child count */
+ UINT16DECODE(p, fd_child_count);
+ HDassert((is_fd_parent && fd_child_count > 0) || (!is_fd_parent && fd_child_count == 0));
+
+ /* Decode dirty dependency child count */
+ UINT16DECODE(p, fd_dirty_child_count);
+ if(fd_dirty_child_count > fd_child_count)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid dirty flush dependency child count")
+
+ /* Decode dependency parent count */
+ UINT16DECODE(p, fd_parent_count);
+ HDassert((is_fd_child && fd_parent_count > 0) || (!is_fd_child && fd_parent_count == 0));
+
+ /* Decode index in LRU */
+ INT32DECODE(p, lru_rank);
+ HDassert((in_lru && lru_rank >= 0) || (!in_lru && lru_rank == -1));
+
+ /* Decode entry offset */
+ H5F_addr_decode(f, &p, &addr);
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid entry offset")
+
+ /* Decode entry length */
+ H5F_DECODE_LENGTH(f, p, size);
+ if(size == 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid entry size")
+
+ /* Verify expected length of entry image */
+ if((size_t)(p - *buf) != H5C__cache_image_block_entry_header_size(f))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, FAIL, "Bad entry image len")
+
+ /* If parent count greater than zero, allocate array for parent
+ * addresses, and decode addresses into the array.
+ */
+ if(fd_parent_count > 0) {
+ int i; /* Local index variable */
+
+ if(NULL == (fd_parent_addrs = (haddr_t *)H5MM_malloc((size_t)(fd_parent_count) * H5F_SIZEOF_ADDR(f))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addrs buffer")
+
+ for(i = 0; i < fd_parent_count; i++) {
+ H5F_addr_decode(f, &p, &(fd_parent_addrs[i]));
+ if(!H5F_addr_defined(fd_parent_addrs[i]))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid flush dependency parent offset")
+ } /* end for */
+ } /* end if */
+
+ /* Allocate buffer for entry image */
+ if(NULL == (image_ptr = H5MM_malloc(size + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer")
+
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)image_ptr) + size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+ /* Copy the entry image from the cache image block */
+ HDmemcpy(image_ptr, p, size);
+ p += size;
+
+ /* Copy data into target */
+ ie_ptr->addr = addr;
+ ie_ptr->size = size;
+ ie_ptr->ring = (H5C_ring_t)ring;
+ ie_ptr->age = (int32_t)age;
+ ie_ptr->type_id = (int32_t)type_id;
+ ie_ptr->lru_rank = lru_rank;
+ ie_ptr->is_dirty = is_dirty;
+ ie_ptr->fd_child_count = (uint64_t)fd_child_count;
+ ie_ptr->fd_dirty_child_count = (uint64_t)fd_dirty_child_count;
+ ie_ptr->fd_parent_count = (uint64_t)fd_parent_count;
+ ie_ptr->fd_parent_addrs = fd_parent_addrs;
+ ie_ptr->image_ptr = image_ptr;
+
+ /* Update buffer pointer */
+ *buf = p;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__decode_cache_image_entry() */
+#endif /* NDEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__destroy_pf_entry_child_flush_deps()
+ *
+ * Purpose: Destroy all flush dependencies in this the supplied
+ * prefetched entry is the parent. Note that the children
+ * in these flush dependencies must be prefetched entries as
+ * well.
+ *
+ * As this action is part of the process of transferring all
+ * such flush dependencies to the deserialized version of the
+ * prefetched entry, ensure that the data necessary to complete
+ * the transfer is retained.
+ *
+ * Note: The current implementation of this function is
+ * quite inefficient -- mostly due to the current
+ * implementation of flush dependencies. This should
+ * be fixed at some point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/11/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__destroy_pf_entry_child_flush_deps(H5C_t *cache_ptr,
+ H5C_cache_entry_t *pf_entry_ptr, H5C_cache_entry_t **fd_children)
+{
+ H5C_cache_entry_t * entry_ptr;
+ unsigned entries_visited = 0;
+ int fd_children_found = 0;
+ hbool_t found;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(pf_entry_ptr);
+ HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(pf_entry_ptr->type);
+ HDassert(pf_entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID);
+ HDassert(pf_entry_ptr->prefetched);
+ HDassert(pf_entry_ptr->fd_child_count > 0);
+ HDassert(fd_children);
+
+ /* Scan each entry on the index list */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Here we look at entry_ptr->flush_dep_nparents and not
+ * entry_ptr->fd_parent_count as it is possible that some
+ * or all of the prefetched flush dependency child relationships
+ * have already been destroyed.
+ */
+ if(entry_ptr->prefetched && (entry_ptr->flush_dep_nparents > 0)) {
+ unsigned u; /* Local index variable */
+
+ /* Re-init */
+ u = 0;
+ found = FALSE;
+
+ /* Sanity checks */
+ HDassert(entry_ptr->type);
+ HDassert(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID);
+ HDassert(entry_ptr->fd_parent_count >= entry_ptr->flush_dep_nparents);
+ HDassert(entry_ptr->fd_parent_addrs);
+ HDassert(entry_ptr->flush_dep_parent);
+
+ /* Look for correct entry */
+ while(!found && (u < entry_ptr->fd_parent_count)) {
+ /* Sanity check entry */
+ HDassert(entry_ptr->flush_dep_parent[u]);
+ HDassert(entry_ptr->flush_dep_parent[u]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Correct entry? */
+ if(pf_entry_ptr == entry_ptr->flush_dep_parent[u])
+ found = TRUE;
+
+ u++;
+ } /* end while */
+
+ if(found) {
+ HDassert(NULL == fd_children[fd_children_found]);
+
+ /* Remove flush dependency */
+ fd_children[fd_children_found] = entry_ptr;
+ fd_children_found++;
+ if(H5C_destroy_flush_dependency(pf_entry_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry child flush dependency")
+
+#ifndef NDEBUG
+ /* Sanity check -- verify that the address of the parent
+ * appears in entry_ptr->fd_parent_addrs. Must do a search,
+ * as with flush dependency creates and destroys,
+ * entry_ptr->fd_parent_addrs and entry_ptr->flush_dep_parent
+ * can list parents in different order.
+ */
+ found = FALSE;
+ u = 0;
+ while(!found && u < entry_ptr->fd_parent_count) {
+ if(pf_entry_ptr->addr == entry_ptr->fd_parent_addrs[u])
+ found = TRUE;
+ u++;
+ } /* end while */
+ HDassert(found);
+#endif /* NDEBUG */
+ } /* end if */
+ } /* end if */
+
+ entries_visited++;
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+
+ /* Post-op sanity checks */
+ HDassert(NULL == fd_children[fd_children_found]);
+ HDassert((unsigned)fd_children_found == pf_entry_ptr->fd_child_count);
+ HDassert(entries_visited == cache_ptr->index_len);
+ HDassert(!pf_entry_ptr->is_pinned);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__destroy_pf_entry_child_flush_deps() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__encode_cache_image_header()
+ *
+ * Purpose: Encode the metadata cache image buffer header in the
+ * supplied buffer. Updates buffer pointer to the first byte
+ * after the header image in the buffer, or unchanged on failure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__encode_cache_image_header(const H5F_t *f, const H5C_t *cache_ptr,
+ uint8_t **buf)
+{
+ size_t actual_header_len;
+ size_t expected_header_len;
+ uint8_t flags = 0;
+ uint8_t * p; /* Pointer into cache image buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->image_ctl.generate_image);
+ HDassert(cache_ptr->index_len == 0);
+ HDassert(cache_ptr->image_data_len > 0);
+ HDassert(cache_ptr->image_data_len <= cache_ptr->image_len);
+ HDassert(buf);
+ HDassert(*buf);
+
+ /* Set pointer into buffer */
+ p = *buf;
+
+ /* write signature */
+ HDmemcpy(p, H5C__MDCI_BLOCK_SIGNATURE, (size_t)H5C__MDCI_BLOCK_SIGNATURE_LEN);
+ p += H5C__MDCI_BLOCK_SIGNATURE_LEN;
+
+ /* write version */
+ *p++ = (uint8_t)H5C__MDCI_BLOCK_VERSION_0;
+
+ /* setup and write flags */
+
+ /* at present we don't support saving resize status */
+ HDassert(!cache_ptr->image_ctl.save_resize_status);
+ if(cache_ptr->image_ctl.save_resize_status)
+ flags |= H5C__MDCI_HEADER_HAVE_RESIZE_STATUS;
+
+ *p++ = flags;
+
+ /* Encode image data length */
+ /* this must be true at present */
+ HDassert(cache_ptr->image_len == cache_ptr->image_data_len);
+ H5F_ENCODE_LENGTH(f, p, cache_ptr->image_data_len);
+
+ /* write num entries */
+ UINT32ENCODE(p, cache_ptr->num_entries_in_image);
+
+ /* verify expected length of header */
+ actual_header_len = (size_t)(p - *buf);
+ expected_header_len = H5C__cache_image_block_header_size(f);
+ if(actual_header_len != expected_header_len)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad header image len")
+
+ /* Update buffer pointer */
+ *buf = p;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__encode_cache_image_header() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__encode_cache_image_entry()
+ *
+ * Purpose: Encode the metadata cache image buffer header in the
+ * supplied buffer. Updates buffer pointer to the first byte
+ * after the entry in the buffer, or unchanged on failure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/6/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__encode_cache_image_entry(H5F_t *f, H5C_t *cache_ptr, uint8_t **buf,
+ unsigned entry_num)
+{
+ H5C_image_entry_t * ie_ptr; /* Pointer to entry to encode */
+ uint8_t flags = 0; /* Flags for entry */
+ uint8_t * p; /* Pointer into cache image buffer */
+ unsigned u; /* Local index value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(cache_ptr == f->shared->cache);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->image_ctl.generate_image);
+ HDassert(cache_ptr->index_len == 0);
+ HDassert(buf);
+ HDassert(*buf);
+ HDassert(entry_num < cache_ptr->num_entries_in_image);
+ ie_ptr = &((cache_ptr->image_entries)[entry_num]);
+ HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC);
+
+ /* Get pointer to buffer to encode into */
+ p = *buf;
+
+ /* Encode type */
+ if((ie_ptr->type_id < 0) || (ie_ptr->type_id > 255))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "type_id out of range.")
+ *p++ = (uint8_t)(ie_ptr->type_id);
+
+ /* Compose and encode flags */
+ if(ie_ptr->is_dirty)
+ flags |= H5C__MDCI_ENTRY_DIRTY_FLAG;
+ if(ie_ptr->lru_rank > 0)
+ flags |= H5C__MDCI_ENTRY_IN_LRU_FLAG;
+ if(ie_ptr->fd_child_count > 0)
+ flags |= H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG;
+ if(ie_ptr->fd_parent_count > 0)
+ flags |= H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG;
+ *p++ = flags;
+
+ /* Encode ring */
+ *p++ = (uint8_t)(ie_ptr->ring);
+
+ /* Encode age */
+ *p++ = (uint8_t)(ie_ptr->age);
+
+ /* Validate and encode dependency child count */
+ if(ie_ptr->fd_child_count > H5C__MDCI_MAX_FD_CHILDREN)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_child_count out of range")
+ UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_child_count));
+
+ /* Validate and encode dirty dependency child count */
+ if(ie_ptr->fd_dirty_child_count > H5C__MDCI_MAX_FD_CHILDREN)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_dirty_child_count out of range")
+ UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_dirty_child_count));
+
+ /* Validate and encode dependency parent count */
+ if(ie_ptr->fd_parent_count > H5C__MDCI_MAX_FD_PARENTS)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_parent_count out of range")
+ UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_parent_count));
+
+ /* Encode index in LRU */
+ INT32ENCODE(p, ie_ptr->lru_rank);
+
+ /* Encode entry offset */
+ H5F_addr_encode(f, &p, ie_ptr->addr);
+
+ /* Encode entry length */
+ H5F_ENCODE_LENGTH(f, p, ie_ptr->size);
+
+ /* Verify expected length of entry image */
+ if((size_t)(p - *buf) != H5C__cache_image_block_entry_header_size(f))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad entry image len")
+
+ /* Encode dependency parent offsets -- if any */
+ for(u = 0; u < ie_ptr->fd_parent_count; u++)
+ H5F_addr_encode(f, &p, ie_ptr->fd_parent_addrs[u]);
+
+ /* Copy entry image */
+ HDmemcpy(p, ie_ptr->image_ptr, ie_ptr->size);
+ p += ie_ptr->size;
+
+ /* Update buffer pointer */
+ *buf = p;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__encode_cache_image_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prep_for_file_close__compute_fd_heights
+ *
+ * Purpose: Recent modifications to flush dependency support in the
+ * metadata cache have removed the notion of flush dependency
+ * height. This is a problem for the cache image feature,
+ * as flush dependency height is used to order entries in the
+ * cache image so that flush dependency parents appear before
+ * flush dependency children. (Recall that the flush dependency
+ * height of an entry in a flush dependency relationship is the
+ * length of the longest path from the entry to a leaf entry --
+ * that is an entry with flush dependency parents, but no
+ * flush dependency children. With the introduction of the
+ * possibility of multiple flush dependency parents, we have
+ * a flush partial dependency latice, not a flush dependency
+ * tree. But since the partial latice is acyclic, the concept
+ * of flush dependency height still makes sense.
+ *
+ * The purpose of this function is to compute the flush
+ * dependency height of all entries that appear in the cache
+ * image.
+ *
+ * At present, entries are included or excluded from the
+ * cache image depending upon the ring in which they reside.
+ * Thus there is no chance that one side of a flush dependency
+ * will be in the cache image, and the other side not.
+ *
+ * However, once we start placing a limit on the size of the
+ * cache image, or start excluding prefetched entries from
+ * the cache image if they haven't been accessed in some
+ * number of file close / open cycles, this will no longer
+ * be the case.
+ *
+ * In particular, if a flush dependency child is dirty, and
+ * one of its flush dependency parents is dirty and not in
+ * the cache image, then the flush dependency child cannot
+ * be in the cache image without violating flush ordering.
+ *
+ * Observe that a clean flush dependency child can be either
+ * in or out of the cache image without effect on flush
+ * dependencies.
+ *
+ * Similarly, a flush dependency parent can always be part
+ * of a cache image, regardless of whether it is clean or
+ * dirty -- but remember that a flush dependency parent can
+ * also be a flush dependency child.
+ *
+ * Finally, note that for purposes of the cache image, flush
+ * dependency height ends when a flush dependecy relation
+ * passes off the cache image.
+ *
+ * On exit, the flush dependency height of each entry in the
+ * cache image should be calculated and stored in the cache
+ * entry. Entries will be removed from the cache image if
+ * necessary to maintain flush ordering.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 9/6/16
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__prep_for_file_close__compute_fd_heights(const H5C_t *cache_ptr)
+{
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * parent_ptr;
+ unsigned entries_removed_from_image = 0;
+ unsigned external_parent_fd_refs_removed = 0;
+ unsigned external_child_fd_refs_removed = 0;
+ hbool_t done = FALSE;
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Remove from the cache image all dirty entries that are
+ * flush dependency children of dirty entries that are not in the
+ * cache image. Must do this, as if we fail to do so, the parent
+ * will be written to file before the child. Since it is possible
+ * that the child will have dirty children of its own, this may take
+ * multiple passes through the index list.
+ */
+ done = FALSE;
+ while(!done) {
+ done = TRUE;
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Should this entry be in the image */
+ if(entry_ptr->image_dirty && entry_ptr->include_in_image &&
+ (entry_ptr->fd_parent_count > 0)) {
+ HDassert(entry_ptr->flush_dep_parent != NULL);
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) {
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+
+ /* Sanity check parent */
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring == parent_ptr->ring);
+
+ if(parent_ptr->is_dirty && !parent_ptr->include_in_image &&
+ entry_ptr->include_in_image) {
+
+ /* Must remove child from image -- only do this once */
+ entries_removed_from_image++;
+ entry_ptr->include_in_image = FALSE;
+ } /* end if */
+ } /* for */
+ } /* end if */
+
+ entry_ptr = entry_ptr->il_next;
+ } /* while ( entry_ptr != NULL ) */
+ } /* while ( ! done ) */
+
+ /* at present, entries are included in the cache image if they reside
+ * in a specified set of rings. Thus it should be impossible for
+ * entries_removed_from_image to be positive. Assert that this is
+ * so. Note that this will change when we start aging entries out
+ * of the cache image.
+ */
+ HDassert(entries_removed_from_image == 0);
+
+ /* Next, remove from entries in the cache image, references to
+ * flush dependency parents or children that are not in the cache image.
+ */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ if(!entry_ptr->include_in_image && entry_ptr->flush_dep_nparents > 0) {
+ HDassert(entry_ptr->flush_dep_parent != NULL);
+
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) {
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+
+ /* Sanity check parent */
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring == parent_ptr->ring);
+
+ if(parent_ptr->include_in_image) {
+ /* Must remove reference to child */
+ HDassert(parent_ptr->fd_child_count > 0);
+ parent_ptr->fd_child_count--;
+
+ if(entry_ptr->is_dirty) {
+ HDassert(parent_ptr->fd_dirty_child_count > 0);
+ parent_ptr->fd_dirty_child_count--;
+ } /* end if */
+
+ external_child_fd_refs_removed++;
+ } /* end if */
+ } /* for */
+ } /* end if */
+ else if(entry_ptr->include_in_image && entry_ptr->flush_dep_nparents > 0) {
+ /* Sanity checks */
+ HDassert(entry_ptr->flush_dep_parent != NULL);
+ HDassert(entry_ptr->flush_dep_nparents == entry_ptr->fd_parent_count);
+ HDassert(entry_ptr->fd_parent_addrs);
+
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) {
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+
+ /* Sanity check parent */
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring == parent_ptr->ring);
+
+ if(!parent_ptr->include_in_image) {
+ /* Must remove reference to parent */
+ HDassert(entry_ptr->fd_parent_count > 0);
+ parent_ptr->fd_child_count--;
+
+ HDassert(parent_ptr->addr == entry_ptr->fd_parent_addrs[u]);
+
+ entry_ptr->fd_parent_addrs[u] = HADDR_UNDEF;
+ external_parent_fd_refs_removed++;
+ } /* end if */
+ } /* for */
+
+ /* Touch up fd_parent_addrs array if necessary */
+ if(entry_ptr->fd_parent_count == 0) {
+ H5MM_xfree(entry_ptr->fd_parent_addrs);
+ entry_ptr->fd_parent_addrs = NULL;
+ } /* end if */
+ else if(entry_ptr->flush_dep_nparents > entry_ptr->fd_parent_count) {
+ haddr_t * old_fd_parent_addrs = entry_ptr->fd_parent_addrs;
+ unsigned v;
+
+ if(NULL == (entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_calloc(sizeof(haddr_t) * (size_t)(entry_ptr->fd_parent_addrs))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addr array")
+
+ v = 0;
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++) {
+ if(old_fd_parent_addrs[u] != HADDR_UNDEF) {
+ entry_ptr->fd_parent_addrs[v] = old_fd_parent_addrs[u];
+ v++;
+ } /* end if */
+ } /* end for */
+
+ HDassert(v == entry_ptr->fd_parent_count);
+ } /* end else-if */
+ } /* end else-if */
+
+ entry_ptr = entry_ptr->il_next;
+ } /* while (entry_ptr != NULL) */
+
+ /* At present, no extenal parent or child flush dependency links
+ * should exist -- hence the following assertions. This will change
+ * if we support ageout of entries in the cache image.
+ */
+ HDassert(external_child_fd_refs_removed == 0);
+ HDassert(external_parent_fd_refs_removed == 0);
+
+ /* At this point we should have removed all flush dependencies that
+ * cross cache image boundaries. Now compute the flush dependency
+ * heights for all entries in the image.
+ *
+ * Until I can think of a better way, do this via a depth first
+ * search implemented via a recursive function call.
+ *
+ * Note that entry_ptr->image_fd_height has already been initialized to 0
+ * for all entries that may appear in the cache image.
+ */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ if(entry_ptr->include_in_image && entry_ptr->fd_child_count == 0 &&
+ entry_ptr->fd_parent_count > 0) {
+ for(u = 0; u < entry_ptr->fd_parent_count; u++) {
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ if(parent_ptr->include_in_image && parent_ptr->image_fd_height <= 0)
+ H5C__prep_for_file_close__compute_fd_heights_real(parent_ptr, 1);
+ } /* end for */
+ } /* end if */
+
+ entry_ptr = entry_ptr->il_next;
+ } /* while (entry_ptr != NULL) */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__prep_for_file_close__compute_fd_heights() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prep_for_file_close__compute_fd_heights_real
+ *
+ * Purpose: H5C__prep_for_file_close__compute_fd_heights() prepares
+ * for the computation of flush dependency heights of all
+ * entries in the cache image, this function actually does
+ * it.
+ *
+ * The basic observation behind this function is as follows:
+ *
+ * Suppose you have an entry E with a flush dependency
+ * height of X. Then the parents of E must all have
+ * flush dependency X + 1 or greater.
+ *
+ * Use this observation to compute flush dependency height
+ * of all entries in the cache image via the following
+ * recursive algorithm:
+ *
+ * 1) On entry, set the flush dependency height of the
+ * supplied cache entry to the supplied value.
+ *
+ * 2) Examine all the flush dependency parents of the
+ * supplied entry.
+ *
+ * If the parent is in the cache image, and has flush
+ * dependency height less than or equal to the flush
+ * dependency height of the current entry, call the
+ * recursive routine on the parent with flush dependency
+ * height equal to the flush dependency height of the
+ * child plus 1.
+ *
+ * Otherwise do nothing.
+ *
+ * Observe that if the flush dependency height of all entries
+ * in the image is initialized to zero, and if this recursive
+ * function is called with flush dependency height 0 on all
+ * entries in the cache image with FD parents in the image,
+ * but without FD children in the image, the correct flush
+ * dependency height should be set for all entries in the
+ * cache image.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 9/6/16
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5C__prep_for_file_close__compute_fd_heights_real(H5C_cache_entry_t *entry_ptr,
+ uint32_t fd_height)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->include_in_image);
+ HDassert((entry_ptr->image_fd_height == 0) || (entry_ptr->image_fd_height < fd_height));
+ HDassert(((fd_height == 0) && (entry_ptr->fd_child_count == 0)) || ((fd_height > 0) && (entry_ptr->fd_child_count > 0)));
+
+ entry_ptr->image_fd_height = fd_height;
+ if(entry_ptr->flush_dep_nparents > 0) {
+ unsigned u;
+
+ HDassert(entry_ptr->flush_dep_parent);
+ for(u = 0; u < entry_ptr->fd_parent_count; u++) {
+ H5C_cache_entry_t *parent_ptr;
+
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ if(parent_ptr->include_in_image && parent_ptr->image_fd_height <= fd_height)
+ H5C__prep_for_file_close__compute_fd_heights_real(parent_ptr, fd_height + 1);
+ } /* end for */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5C__prep_for_file_close__compute_fd_heights_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prep_for_file_close__setup_image_entries_array
+ *
+ * Purpose: Allocate space for the image_entries array, and load
+ * each instance of H5C_image_entry_t in the array with
+ * the data necessary to construct the metadata cache image.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/4/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__prep_for_file_close__setup_image_entries_array(H5C_t *cache_ptr)
+{
+ H5C_cache_entry_t * entry_ptr;
+ H5C_image_entry_t * image_entries = NULL;
+ uint32_t entries_visited = 0;
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->pl_len == 0);
+ HDassert(cache_ptr->num_entries_in_image > 0);
+ HDassert(cache_ptr->image_entries == NULL);
+
+ /* Allocate and initialize image_entries array */
+ if(NULL == (image_entries = (H5C_image_entry_t *)H5MM_calloc(sizeof(H5C_image_entry_t) * (size_t)(cache_ptr->num_entries_in_image + 1))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for image_entries")
+
+ /* Initialize (non-zero/NULL/FALSE) fields */
+ for(u = 0; u <= cache_ptr->num_entries_in_image; u++) {
+ image_entries[u].magic = H5C_IMAGE_ENTRY_T_MAGIC;
+ image_entries[u].addr = HADDR_UNDEF;
+ image_entries[u].ring = H5C_RING_UNDEFINED;
+ image_entries[u].type_id = -1;
+ } /* end for */
+
+ /* Scan each entry on the index list and populate the image_entries array */
+ u = 0;
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ if(entry_ptr->include_in_image) {
+ /* Since we have already serialized the cache, the following
+ * should hold.
+ */
+ HDassert(entry_ptr->image_up_to_date);
+ HDassert(entry_ptr->image_ptr);
+ HDassert(entry_ptr->type);
+
+ image_entries[u].addr = entry_ptr->addr;
+ image_entries[u].size = entry_ptr->size;
+ image_entries[u].ring = entry_ptr->ring;
+
+ /* When a prefetched entry is included in the image, store
+ * its underlying type id in the image entry, not
+ * H5AC_PREFETCHED_ENTRY_ID. In passing, also increment
+ * the age (up to H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX).
+ */
+ if(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID) {
+ image_entries[u].type_id = entry_ptr->prefetch_type_id;
+ image_entries[u].age = entry_ptr->age + 1;
+
+ if(image_entries[u].age > H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX)
+ image_entries[u].age = H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX;
+ } /* end if */
+ else {
+ image_entries[u].type_id = entry_ptr->type->id;
+ image_entries[u].age = 0;
+ } /* end else */
+
+ image_entries[u].lru_rank = entry_ptr->lru_rank;
+ image_entries[u].is_dirty = entry_ptr->is_dirty;
+ image_entries[u].image_fd_height = entry_ptr->image_fd_height;
+ image_entries[u].fd_parent_count = entry_ptr->fd_parent_count;
+ image_entries[u].fd_parent_addrs = entry_ptr->fd_parent_addrs;
+ image_entries[u].fd_child_count = entry_ptr->fd_child_count;
+ image_entries[u].fd_dirty_child_count =
+ entry_ptr->fd_dirty_child_count;
+ image_entries[u].image_ptr = entry_ptr->image_ptr;
+
+ /* Null out entry_ptr->fd_parent_addrs and set
+ * entry_ptr->fd_parent_count to zero so that ownership of the
+ * flush dependency parents address array is transferred to the
+ * image entry.
+ */
+ entry_ptr->fd_parent_count = 0;
+ entry_ptr->fd_parent_addrs = NULL;
+
+ u++;
+
+ HDassert(u <= cache_ptr->num_entries_in_image);
+ } /* end if */
+
+ entries_visited++;
+
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+
+ /* Sanity checks */
+ HDassert(entries_visited == cache_ptr->index_len);
+ HDassert(u == cache_ptr->num_entries_in_image);
+
+ HDassert(image_entries[u].fd_parent_addrs == NULL);
+ HDassert(image_entries[u].image_ptr == NULL);
+
+ cache_ptr->image_entries = image_entries;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__prep_for_file_close__setup_image_entries_array() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prep_for_file_close__scan_entries
+ *
+ * Purpose: Scan all entries in the metadata cache, and store all
+ * entry specific data required for construction of the
+ * metadata cache image block and likely to be discarded
+ * or modified during the cache flush on file close.
+ *
+ * In particular, make note of:
+ * entry rank in LRU
+ * whether the entry is dirty
+ * base address of entry flush dependency parent,
+ * if it exists.
+ * number of flush dependency children, if any.
+ *
+ * Also, determine which entries are to be included in the
+ * metadata cache image. At present, all entries other than
+ * the superblock, the superblock extension object header and
+ * its associated chunks (if any) are included.
+ *
+ * Finally, compute the size of the metadata cache image
+ * block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/21/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__prep_for_file_close__scan_entries(const H5F_t *f, H5C_t *cache_ptr)
+{
+ H5C_cache_entry_t * entry_ptr;
+ hbool_t include_in_image;
+ unsigned entries_visited = 0;
+ int lru_rank = 1;
+ uint32_t num_entries_tentatively_in_image = 0;
+ uint32_t num_entries_in_image = 0;
+ size_t image_len;
+ size_t entry_header_len;
+ size_t fd_parents_list_len;
+ int i;
+ unsigned j;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+ HDassert(cache_ptr->pl_len == 0);
+
+ /* Initialize image len to the size of the metadata cache image block
+ * header.
+ */
+ image_len = H5C__cache_image_block_header_size(f);
+ entry_header_len = H5C__cache_image_block_entry_header_size(f);
+
+ /* Scan each entry on the index list */
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ /* Since we have already serialized the cache, the following
+ * should hold.
+ */
+ HDassert(entry_ptr->image_up_to_date);
+ HDassert(entry_ptr->image_ptr);
+
+ /* Initially, we mark all entries in the rings included
+ * in the cache image as being included in the in the
+ * image. Depending on circumstances, we may exclude some
+ * of these entries later.
+ */
+ if(entry_ptr->ring > H5C_MAX_RING_IN_IMAGE)
+ include_in_image = FALSE;
+ else
+ include_in_image = TRUE;
+ entry_ptr->include_in_image = include_in_image;
+
+ if(include_in_image) {
+ entry_ptr->lru_rank = -1;
+ entry_ptr->image_dirty = entry_ptr->is_dirty;
+ entry_ptr->image_fd_height = 0; /* will compute this later */
+
+ /* Initially, include all flush dependency parents in the
+ * the list of flush dependencies to be stored in the
+ * image. We may remove some or all of these later.
+ */
+ if(entry_ptr->flush_dep_nparents > 0) {
+ /* The parents addresses array may already exist -- reallocate
+ * as needed.
+ */
+ if(entry_ptr->flush_dep_nparents == entry_ptr->fd_parent_count ) {
+ /* parent addresses array should already be allocated
+ * and of the correct size.
+ */
+ HDassert(entry_ptr->fd_parent_addrs);
+ } /* end if */
+ else if(entry_ptr->fd_parent_count > 0) {
+ HDassert(entry_ptr->fd_parent_addrs);
+ entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(entry_ptr->fd_parent_addrs);
+ } /* end else-if */
+ else {
+ HDassert(entry_ptr->fd_parent_count == 0);
+ HDassert(entry_ptr->fd_parent_addrs == NULL);
+ } /* end else */
+
+ entry_ptr->fd_parent_count = entry_ptr->flush_dep_nparents;
+ if(NULL == entry_ptr->fd_parent_addrs)
+ if(NULL == (entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)(entry_ptr->fd_parent_count))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addrs buffer")
+
+ for(i = 0; i < (int)(entry_ptr->fd_parent_count); i++) {
+ entry_ptr->fd_parent_addrs[i] = entry_ptr->flush_dep_parent[i]->addr;
+ HDassert(H5F_addr_defined(entry_ptr->fd_parent_addrs[i]));
+ } /* end for */
+ } /* end if */
+ else if(entry_ptr->fd_parent_count > 0) {
+ HDassert(entry_ptr->fd_parent_addrs);
+ entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(entry_ptr->fd_parent_addrs);
+ } /* end else-if */
+ else
+ HDassert(entry_ptr->fd_parent_addrs == NULL);
+
+ /* Initially, all flush dependency children are included int
+ * the count of flush dependency child relationships to be
+ * represented in the cache image. Some or all of these
+ * may be dropped from the image later.
+ */
+ if(entry_ptr->flush_dep_nchildren > 0) {
+ if(!entry_ptr->is_pinned)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "encountered unpinned fd parent?!?")
+
+ entry_ptr->fd_child_count = entry_ptr->flush_dep_nchildren;
+ entry_ptr->fd_dirty_child_count = entry_ptr->flush_dep_ndirty_children;
+ } /* end if */
+
+ num_entries_tentatively_in_image++;
+ } /* end if */
+
+ entries_visited++;
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+ HDassert(entries_visited == cache_ptr->index_len);
+
+ /* Now compute the flush dependency heights of all flush dependency
+ * relationships to be represented in the image.
+ *
+ * If all entries in the target rings are included in the
+ * image, the flush dependency heights are simply the heights
+ * of all flush dependencies in the target rings.
+ *
+ * However, if we restrict appearance in the cache image either
+ * by number of entries in the image, restrictions on the number
+ * of times a prefetched entry can appear in an image, or image
+ * size, it is possible that flush dependency parents or children
+ * of entries that are in the image may not be included in the
+ * the image. In this case, we must prune all flush dependency
+ * relationships that cross the image boundary, and all exclude
+ * from the image all dirty flush dependency children that have
+ * a dirty flush dependency parent that is not in the image.
+ * This is necessary to preserve the required flush ordering.
+ *
+ * These details are tended to by the following call to
+ * H5C__prep_for_file_close__compute_fd_heights(). Because the
+ * exact contents of the image cannot be known until after this
+ * call, computation of the image size is delayed.
+ */
+ if(H5C__prep_for_file_close__compute_fd_heights(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "computation of flush dependency heights failed?!?")
+
+ /* At this point, all entries that will appear in the cache
+ * image should be marked correctly. Compute the size of the
+ * cache image.
+ */
+ entries_visited = 0;
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+
+ if(entry_ptr->include_in_image) {
+ if(entry_ptr->fd_parent_count > 0)
+ fd_parents_list_len = (size_t)(H5F_SIZEOF_ADDR(f) * entry_ptr->fd_parent_count);
+ else
+ fd_parents_list_len = (size_t)0;
+
+ image_len += entry_header_len + fd_parents_list_len + entry_ptr->size;
+ num_entries_in_image++;
+ } /* end if */
+
+ entries_visited++;
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+ HDassert(entries_visited == cache_ptr->index_len);
+ HDassert(num_entries_in_image <= num_entries_tentatively_in_image);
+
+ j = 0;
+ for(i = H5C_MAX_RING_IN_IMAGE + 1; i <= H5C_RING_SB; i++)
+ j += cache_ptr->index_ring_len[i];
+
+ /* This will change */
+ HDassert(entries_visited == (num_entries_tentatively_in_image + j));
+
+ cache_ptr->num_entries_in_image = num_entries_in_image;
+ entries_visited = 0;
+
+ /* Now scan the LRU list to set the lru_rank fields of all entries
+ * on the LRU.
+ *
+ * Note that we start with rank 1, and increment by 1 with each
+ * entry on the LRU.
+ *
+ * Note that manually pinned entryies will have lru_rank -1,
+ * and no flush dependency. Putting these entries at the head of
+ * the reconstructed LRU should be appropriate.
+ */
+ entry_ptr = cache_ptr->LRU_head_ptr;
+ while(entry_ptr != NULL) {
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->type != NULL);
+
+ /* to avoid confusion, don't set lru_rank on epoch markers.
+ * Note that we still increment the lru_rank, so that the holes
+ * in the sequence of entries on the LRU will indicate the
+ * locations of epoch markers (if any) when we reconstruct
+ * the LRU.
+ *
+ * Do not set lru_rank or increment lru_rank for entries
+ * that will not be included in the cache image.
+ */
+ if(entry_ptr->type->id == H5AC_EPOCH_MARKER_ID)
+ lru_rank++;
+ else if(entry_ptr->include_in_image) {
+ entry_ptr->lru_rank = lru_rank;
+ lru_rank++;
+ } /* end else-if */
+
+ entries_visited++;
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+ HDassert(entries_visited == cache_ptr->LRU_list_len);
+
+ image_len += H5F_SIZEOF_CHKSUM;
+ cache_ptr->image_data_len = image_len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__prep_for_file_close__scan_entries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__reconstruct_cache_contents()
+ *
+ * Purpose: Scan the image buffer, and create a prefetched
+ * cache entry for every entry in the buffer. Insert the
+ * prefetched entries in the index and the LRU, and
+ * reconstruct any flush dependencies. Order the entries
+ * in the LRU as indicated by the stored lru_ranks.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 8/14/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__reconstruct_cache_contents(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr)
+{
+ H5C_cache_entry_t * pf_entry_ptr; /* Pointer to prefetched entry */
+ H5C_cache_entry_t * parent_ptr; /* Pointer to parent of prefetched entry */
+ const uint8_t * p; /* Pointer into image buffer */
+ unsigned u, v; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(cache_ptr == f->shared->cache);
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->image_buffer);
+ HDassert(cache_ptr->image_len > 0);
+
+ /* Decode metadata cache image header */
+ p = (uint8_t *)cache_ptr->image_buffer;
+ if(H5C__decode_cache_image_header(f, cache_ptr, &p) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "cache image header decode failed")
+ HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_len);
+
+ /* The image_data_len and # of entries should be defined now */
+ HDassert(cache_ptr->image_data_len > 0);
+ HDassert(cache_ptr->image_data_len <= cache_ptr->image_len);
+ HDassert(cache_ptr->num_entries_in_image > 0);
+
+ /* Reconstruct entries in image */
+ for(u = 0; u < cache_ptr->num_entries_in_image; u++) {
+ /* Create the prefetched entry described by the ith
+ * entry in cache_ptr->image_entrise.
+ */
+ if(NULL == (pf_entry_ptr = H5C__reconstruct_cache_entry(f, cache_ptr, &p)))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "reconstruction of cache entry failed")
+
+ /* Note that we make no checks on available cache space before
+ * inserting the reconstructed entry into the metadata cache.
+ *
+ * This is OK since the cache must be almost empty at the beginning
+ * of the process, and since we check cache size at the end of the
+ * reconstruction process.
+ */
+
+ /* Insert the prefetched entry in the index */
+ H5C__INSERT_IN_INDEX(cache_ptr, pf_entry_ptr, FAIL)
+
+ /* If dirty, insert the entry into the slist. */
+ if(pf_entry_ptr->is_dirty)
+ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, pf_entry_ptr, FAIL)
+
+ /* Append the entry to the LRU */
+ H5C__UPDATE_RP_FOR_INSERT_APPEND(cache_ptr, pf_entry_ptr, FAIL)
+
+ H5C__UPDATE_STATS_FOR_PREFETCH(cache_ptr, pf_entry_ptr->is_dirty)
+
+ /* If the prefetched entry is the child in one or more flush
+ * dependency relationships, recreate those flush dependencies.
+ */
+ for(v = 0; v < pf_entry_ptr->fd_parent_count; v++) {
+ /* Sanity checks */
+ HDassert(pf_entry_ptr->fd_parent_addrs);
+ HDassert(H5F_addr_defined(pf_entry_ptr->fd_parent_addrs[v]));
+
+ /* Find the parent entry */
+ parent_ptr = NULL;
+ H5C__SEARCH_INDEX(cache_ptr, pf_entry_ptr->fd_parent_addrs[v], parent_ptr, FAIL)
+ if(parent_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, "fd parent not in cache?!?")
+
+ /* Sanity checks */
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(parent_ptr->addr == pf_entry_ptr->fd_parent_addrs[v]);
+ HDassert(parent_ptr->lru_rank == -1);
+
+ /* Must protect parent entry to set up a flush dependency.
+ * Do this now, and then uprotect when done.
+ */
+ H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, parent_ptr, FAIL)
+ parent_ptr->is_protected = TRUE;
+
+ /* Setup the flush dependency */
+ if(H5C_create_flush_dependency(parent_ptr, pf_entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Can't restore flush dependency")
+
+ /* And now unprotect */
+ H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, parent_ptr, FAIL)
+ parent_ptr->is_protected = FALSE;
+ } /* end for */
+ } /* end for */
+
+#ifndef NDEBUG
+ /* Scan the cache entries, and verify that each entry has
+ * the expected flush dependency status.
+ */
+ pf_entry_ptr = cache_ptr->il_head;
+ while(pf_entry_ptr != NULL) {
+ HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert((pf_entry_ptr->prefetched && pf_entry_ptr->type == H5AC_PREFETCHED_ENTRY)
+ || (!pf_entry_ptr->prefetched && pf_entry_ptr->type != H5AC_PREFETCHED_ENTRY));
+ if(pf_entry_ptr->type == H5AC_PREFETCHED_ENTRY)
+ HDassert(pf_entry_ptr->fd_parent_count == pf_entry_ptr->flush_dep_nparents);
+
+ for(v = 0; v < pf_entry_ptr->fd_parent_count; v++) {
+ parent_ptr = pf_entry_ptr->flush_dep_parent[v];
+ HDassert(parent_ptr);
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(pf_entry_ptr->fd_parent_addrs);
+ HDassert(pf_entry_ptr->fd_parent_addrs[v] == parent_ptr->addr);
+ HDassert(parent_ptr->flush_dep_nchildren > 0);
+ } /* end for */
+
+ if(pf_entry_ptr->type == H5AC_PREFETCHED_ENTRY) {
+ HDassert(pf_entry_ptr->fd_child_count == pf_entry_ptr->flush_dep_nchildren);
+ HDassert(pf_entry_ptr->fd_dirty_child_count == pf_entry_ptr->flush_dep_ndirty_children);
+ } /* end if */
+
+ pf_entry_ptr = pf_entry_ptr->il_next;
+ } /* end while */
+
+ /* Scan the LRU, and verify the expected ordering of the
+ * prefetched entries.
+ */
+ {
+ int lru_rank_holes = 0;
+ H5C_cache_entry_t *entry_ptr;
+ int i; /* Local index variable */
+
+ i = -1;
+ entry_ptr = cache_ptr->LRU_head_ptr;
+
+ while(entry_ptr != NULL) {
+
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->type != NULL);
+
+ if ( entry_ptr->prefetched ) {
+
+ HDassert(entry_ptr->lru_rank != 0);
+ HDassert((entry_ptr->lru_rank == -1) ||
+ (entry_ptr->lru_rank > i));
+
+ if ( ( entry_ptr->lru_rank > 1 ) &&
+ ( entry_ptr->lru_rank > i + 1 ) )
+
+ lru_rank_holes += entry_ptr->lru_rank - (i + 1);
+
+ i = entry_ptr->lru_rank;
+
+ } /* end if */
+
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+
+ /* Holes in the sequences of LRU ranks can appear due to epoch
+ * markers. They are left in to allow re-insertion of the
+ * epoch markers on reconstruction of the cache -- thus
+ * the following sanity check will have to be revised when
+ * we add code to store and restore adaptive resize status.
+ */
+ HDassert(lru_rank_holes <= H5C__MAX_EPOCH_MARKERS);
+ } /* end block */
+#endif /* NDEBUG */
+
+ /* Check to see if the cache is oversize, and evict entries as
+ * necessary to remain within limits.
+ */
+ if(cache_ptr->index_size >= cache_ptr->max_cache_size) {
+ /* cache is oversized -- call H5C__make_space_in_cache() with zero
+ * space needed to repair the situation if possible.
+ */
+ hbool_t write_permitted = FALSE;
+
+ if(cache_ptr->check_write_permitted != NULL) {
+ if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "Can't get write_permitted")
+ } /* end if */
+ else
+ write_permitted = cache_ptr->write_permitted;
+
+ if(H5C__make_space_in_cache(f, dxpl_id, 0, write_permitted) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "H5C__make_space_in_cache failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__reconstruct_cache_contents() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__reconstruct_cache_entry()
+ *
+ * Purpose: Allocate a prefetched metadata cache entry and initialize
+ * it from image buffer.
+ *
+ * Return a pointer to the newly allocated cache entry,
+ * or NULL on failure.
+ *
+ * Return: Pointer to the new instance of H5C_cache_entry on success,
+ * or NULL on failure.
+ *
+ * Programmer: John Mainzer
+ * 8/14/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5C_cache_entry_t *
+H5C__reconstruct_cache_entry(const H5F_t *f, H5C_t *cache_ptr,
+ const uint8_t **buf)
+{
+ H5C_cache_entry_t *pf_entry_ptr = NULL; /* Reconstructed cache entry */
+ uint8_t flags = 0;
+ hbool_t is_dirty = FALSE;
+#ifndef NDEBUG /* only used in assertions */
+ hbool_t in_lru = FALSE;
+ hbool_t is_fd_parent = FALSE;
+ hbool_t is_fd_child = FALSE;
+#endif /* NDEBUG */ /* only used in assertions */
+ const uint8_t * p;
+ hbool_t file_is_rw;
+ H5C_cache_entry_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->num_entries_in_image > 0);
+ HDassert(buf && *buf);
+
+ /* Key R/W access off of whether the image will be deleted */
+ file_is_rw = cache_ptr->delete_image;
+
+ /* Allocate space for the prefetched cache entry */
+ if(NULL == (pf_entry_ptr = H5FL_CALLOC(H5C_cache_entry_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for prefetched cache entry")
+
+ /* Get pointer to buffer */
+ p = *buf;
+
+ /* Decode type id */
+ pf_entry_ptr->prefetch_type_id = *p++;
+
+ /* Decode flags */
+ flags = *p++;
+ if(flags & H5C__MDCI_ENTRY_DIRTY_FLAG)
+ is_dirty = TRUE;
+#ifndef NDEBUG /* only used in assertions */
+ if(flags & H5C__MDCI_ENTRY_IN_LRU_FLAG)
+ in_lru = TRUE;
+ if(flags & H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG)
+ is_fd_parent = TRUE;
+ if(flags & H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG)
+ is_fd_child = TRUE;
+#endif /* NDEBUG */ /* only used in assertions */
+
+ /* Force dirty entries to clean if the file read only -- must do
+ * this as otherwise the cache will attempt to write them on file
+ * close. Since the file is R/O, the metadata cache image superblock
+ * extension message and the cache image block will not be removed.
+ * Hence no danger in this for subsequent opens.
+ *
+ * However, if the dirty entry (marked clean for purposes of the R/O
+ * file open) is evicted and then referred to, the cache will read
+ * either invalid or obsolete data from the file. Handle this by
+ * setting the prefetched_dirty field, and hiding such entries from
+ * the eviction candidate selection algorithm.
+ */
+ pf_entry_ptr->is_dirty = (is_dirty && file_is_rw);
+
+ /* Decode ring */
+ pf_entry_ptr->ring = *p++;
+ HDassert(pf_entry_ptr->ring > (uint8_t)(H5C_RING_UNDEFINED));
+ HDassert(pf_entry_ptr->ring < (uint8_t)(H5C_RING_NTYPES));
+
+ /* Decode age */
+ pf_entry_ptr->age = *p++;
+
+ /* Decode dependency child count */
+ UINT16DECODE(p, pf_entry_ptr->fd_child_count);
+ HDassert((is_fd_parent && pf_entry_ptr->fd_child_count > 0) || (!is_fd_parent && pf_entry_ptr->fd_child_count == 0));
+
+ /* Decode dirty dependency child count */
+ UINT16DECODE(p, pf_entry_ptr->fd_dirty_child_count);
+ if(!file_is_rw)
+ pf_entry_ptr->fd_dirty_child_count = 0;
+ if(pf_entry_ptr->fd_dirty_child_count > pf_entry_ptr->fd_child_count)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid dirty flush dependency child count")
+
+ /* Decode dependency parent count */
+ UINT16DECODE(p, pf_entry_ptr->fd_parent_count);
+ HDassert((is_fd_child && pf_entry_ptr->fd_parent_count > 0) || (!is_fd_child && pf_entry_ptr->fd_parent_count == 0));
+
+ /* Decode index in LRU */
+ INT32DECODE(p, pf_entry_ptr->lru_rank);
+ HDassert((in_lru && pf_entry_ptr->lru_rank >= 0) || (!in_lru && pf_entry_ptr->lru_rank == -1));
+
+ /* Decode entry offset */
+ H5F_addr_decode(f, &p, &pf_entry_ptr->addr);
+ if(!H5F_addr_defined(pf_entry_ptr->addr))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid entry offset")
+
+ /* Decode entry length */
+ H5F_DECODE_LENGTH(f, p, pf_entry_ptr->size);
+ if(pf_entry_ptr->size == 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid entry size")
+
+ /* Verify expected length of entry image */
+ if((size_t)(p - *buf) != H5C__cache_image_block_entry_header_size(f))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, NULL, "Bad entry image len")
+
+ /* If parent count greater than zero, allocate array for parent
+ * addresses, and decode addresses into the array.
+ */
+ if(pf_entry_ptr->fd_parent_count > 0) {
+ unsigned u; /* Local index variable */
+
+ if(NULL == (pf_entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_malloc((size_t)(pf_entry_ptr->fd_parent_count) * H5F_SIZEOF_ADDR(f))))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for fd parent addrs buffer")
+
+ for(u = 0; u < pf_entry_ptr->fd_parent_count; u++) {
+ H5F_addr_decode(f, &p, &(pf_entry_ptr->fd_parent_addrs[u]));
+ if(!H5F_addr_defined(pf_entry_ptr->fd_parent_addrs[u]))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid flush dependency parent offset")
+ } /* end for */
+ } /* end if */
+
+ /* Allocate buffer for entry image */
+ if(NULL == (pf_entry_ptr->image_ptr = H5MM_malloc(pf_entry_ptr->size + H5C_IMAGE_EXTRA_SPACE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer")
+#if H5C_DO_MEMORY_SANITY_CHECKS
+ HDmemcpy(((uint8_t *)pf_entry_ptr->image_ptr) + size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE);
+#endif /* H5C_DO_MEMORY_SANITY_CHECKS */
+
+ /* Copy the entry image from the cache image block */
+ HDmemcpy(pf_entry_ptr->image_ptr, p, pf_entry_ptr->size);
+ p += pf_entry_ptr->size;
+
+ /* Initialize the rest of the fields in the prefetched entry */
+ /* (Only need to set non-zero/NULL/FALSE fields, due to calloc() above) */
+ pf_entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC;
+ pf_entry_ptr->cache_ptr = cache_ptr;
+ pf_entry_ptr->image_up_to_date = TRUE;
+ pf_entry_ptr->type = H5AC_PREFETCHED_ENTRY;
+ pf_entry_ptr->prefetched = TRUE;
+ pf_entry_ptr->prefetched_dirty = is_dirty && (!file_is_rw);
+
+ /* Sanity checks */
+ HDassert(pf_entry_ptr->size > 0 && pf_entry_ptr->size < H5C_MAX_ENTRY_SIZE);
+
+ /* Update buffer pointer */
+ *buf = p;
+
+ ret_value = pf_entry_ptr;
+
+done:
+ if(NULL == ret_value && pf_entry_ptr)
+ pf_entry_ptr = H5FL_FREE(H5C_cache_entry_t, pf_entry_ptr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__reconstruct_cache_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__write_cache_image_superblock_msg
+ *
+ * Purpose: Write the cache image superblock extension message,
+ * creating if specified.
+ *
+ * In general, the size and location of the cache image block
+ * will be unknow at the time that the cache image superblock
+ * message is created. A subsequent call to this routine will
+ * be used to write the correct data.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 7/4/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__write_cache_image_superblock_msg(H5F_t *f, hid_t dxpl_id, hbool_t create)
+{
+ H5C_t * cache_ptr;
+ H5O_mdci_t mdci_msg; /* metadata cache image message */
+ /* to insert in the superblock */
+ /* extension. */
+ unsigned mesg_flags = H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->close_warning_received);
+
+ /* Write data into the metadata cache image superblock extension message.
+ * Note that this data will be bogus when we first create the message.
+ * We will overwrite this data later in a second call to this function.
+ */
+ mdci_msg.addr = cache_ptr->image_addr;
+#ifdef H5_HAVE_PARALLEL
+ if(cache_ptr->aux_ptr) { /* we have multiple processes */
+ H5AC_aux_t * aux_ptr;
+
+ aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
+ HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
+ mdci_msg.size = aux_ptr->p0_image_len;
+ } /* end if */
+ else
+#endif /* H5_HAVE_PARALLEL */
+ mdci_msg.size = cache_ptr->image_len;
+
+ /* Write metadata cache image message to superblock extension */
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_MDCI_MSG_ID, &mdci_msg, create, mesg_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_WRITEERROR, FAIL, "can't write metadata cache image message to superblock extension")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__write_cache_image_superblock_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__write_cache_image
+ *
+ * Purpose: Write the supplied metadata cache image to the specified
+ * location in file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 8/26/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__write_cache_image(H5F_t *f, hid_t dxpl_id, const H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(cache_ptr);
+ HDassert(H5F_addr_defined(cache_ptr->image_addr));
+ HDassert(cache_ptr->image_len > 0);
+ HDassert(cache_ptr->image_buffer);
+
+#ifdef H5_HAVE_PARALLEL
+{
+ H5AC_aux_t *aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
+
+ if((NULL == aux_ptr) || (aux_ptr->mpi_rank == 0)) {
+ HDassert((NULL == aux_ptr) || (aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC));
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Write the buffer (if serial access, or rank 0 for parallel access) */
+ if(H5F_block_write(f, H5FD_MEM_SUPER, cache_ptr->image_addr, cache_ptr->image_len, dxpl_id, cache_ptr->image_buffer) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't write metadata cache image block to file")
+#ifdef H5_HAVE_PARALLEL
+ } /* end if */
+} /* end block */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__write_cache_image() */
+
diff --git a/src/H5Clog.c b/src/H5Clog.c
new file mode 100644
index 0000000..3353619
--- /dev/null
+++ b/src/H5Clog.c
@@ -0,0 +1,368 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Clog.c
+ * May 30 2016
+ * Quincey Koziol
+ *
+ * Purpose: Functions for generic cache logging in JSON format
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#ifdef H5_HAVE_PARALLEL
+#define H5AC_FRIEND /*suppress error about including H5ACpkg */
+#include "H5ACpkg.h" /* Metadata cache */
+#endif /* H5_HAVE_PARALLEL */
+#include "H5Cpkg.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_up_logging
+ *
+ * Purpose: Setup for metadata cache logging.
+ *
+ * Metadata logging is enabled and disabled at two levels. This
+ * function and the associated tear_down function open and close
+ * the log file. the start_ and stop_logging functions are then
+ * used to switch logging on/off. Optionally, logging can begin
+ * as soon as the log file is opened (set via the start_immediately
+ * parameter to this function).
+ *
+ * The log functionality is split between the H5C and H5AC
+ * packages. Log state and direct log manipulation resides in
+ * H5C. Log messages are generated in H5AC and sent to
+ * the H5C_write_log_message function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_set_up_logging(H5C_t *cache_ptr, const char log_location[],
+ hbool_t start_immediately)
+{
+#ifdef H5_HAVE_PARALLEL
+ H5AC_aux_t *aux_ptr = NULL;
+#endif /*H5_HAVE_PARALLEL*/
+ char *file_name = NULL;
+ size_t n_chars;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(cache_ptr->logging_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging already set up")
+ if(NULL == log_location)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL log location not allowed")
+
+ /* Possibly fix up the log file name.
+ * The extra 39 characters are for adding the rank to the file name
+ * under parallel HDF5. 39 characters allows > 2^127 processes which
+ * should be enough for anybody.
+ *
+ * allocation size = <path length> + dot + <rank # length> + \0
+ */
+ n_chars = HDstrlen(log_location) + 1 + 39 + 1;
+ if(NULL == (file_name = (char *)H5MM_calloc(n_chars * sizeof(char))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate memory for mdc log file name manipulation")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Add the rank to the log file name when MPI is in use */
+ aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
+
+ if(NULL == aux_ptr)
+ HDsnprintf(file_name, n_chars, "%s", log_location);
+ else {
+ if(aux_ptr->magic != H5AC__H5AC_AUX_T_MAGIC)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad aux_ptr->magic")
+ HDsnprintf(file_name, n_chars, "%s.%d", log_location, aux_ptr->mpi_rank);
+ } /* end else */
+#else /* H5_HAVE_PARALLEL */
+ HDsnprintf(file_name, n_chars, "%s", log_location);
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Open log file */
+ if(NULL == (cache_ptr->log_file_ptr = HDfopen(file_name, "w")))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't create mdc log file")
+
+ /* Set logging flags */
+ cache_ptr->logging_enabled = TRUE;
+ cache_ptr->currently_logging = start_immediately;
+
+ done:
+ if(file_name)
+ file_name = (char *)H5MM_xfree(file_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_set_up_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_tear_down_logging
+ *
+ * Purpose: Tear-down for metadata cache logging.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_tear_down_logging(H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(FALSE == cache_ptr->logging_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging not enabled")
+
+ /* Unset logging flags */
+ cache_ptr->logging_enabled = FALSE;
+ cache_ptr->currently_logging = FALSE;
+
+ /* Close log file */
+ if(EOF == HDfclose(cache_ptr->log_file_ptr))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problem closing mdc log file")
+ cache_ptr->log_file_ptr = NULL;
+
+ done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_tear_down_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_start_logging
+ *
+ * Purpose: Start logging metadata cache operations.
+ *
+ * TODO: Add a function that dumps the current state of the
+ * metadata cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_start_logging(H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(FALSE == cache_ptr->logging_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging not enabled")
+ if(cache_ptr->currently_logging)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging already in progress")
+
+ /* Set logging flags */
+ cache_ptr->currently_logging = TRUE;
+
+ /* TODO - Dump cache state */
+
+ done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_start_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_stop_logging
+ *
+ * Purpose: Stop logging metadata cache operations.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_stop_logging(H5C_t *cache_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(FALSE == cache_ptr->logging_enabled)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging not enabled")
+ if(FALSE == cache_ptr->currently_logging)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "logging not in progress")
+
+ /* Set logging flags */
+ cache_ptr->currently_logging = FALSE;
+
+ done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_stop_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_logging_status
+ *
+ * Purpose: Determines if the cache is actively logging (via the OUT
+ * parameter).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_logging_status(const H5C_t *cache_ptr, /*OUT*/ hbool_t *is_enabled,
+ /*OUT*/ hbool_t *is_currently_logging)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(NULL == is_enabled)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(NULL == is_currently_logging)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+
+ *is_enabled = cache_ptr->logging_enabled;
+ *is_currently_logging = cache_ptr->currently_logging;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_logging_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_write_log_message
+ *
+ * Purpose: Write a message to the log file and flush the file.
+ * The message string is neither modified nor freed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Sunday, March 16, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_write_log_message(const H5C_t *cache_ptr, const char message[])
+{
+ size_t n_chars;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ if(NULL == cache_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr == NULL")
+ if(H5C__H5C_T_MAGIC != cache_ptr->magic)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache magic value incorrect")
+ if(FALSE == cache_ptr->currently_logging)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "not currently logging")
+ if(NULL == message)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL log message not allowed")
+
+ /* Write the log message and flush */
+ n_chars = HDstrlen(message);
+ if((int)n_chars != HDfprintf(cache_ptr->log_file_ptr, message))
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error writing log message")
+ if(EOF == HDfflush(cache_ptr->log_file_ptr))
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error flushing log message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_write_log_message() */
+
diff --git a/src/H5Cmodule.h b/src/H5Cmodule.h
new file mode 100644
index 0000000..534404d
--- /dev/null
+++ b/src/H5Cmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5C package. Including this header means that the source file
+ * is part of the H5C package.
+ */
+#ifndef _H5Cmodule_H
+#define _H5Cmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5C_MODULE
+#define H5_MY_PKG H5C
+#define H5_MY_PKG_ERR H5E_CACHE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5Cmodule_H */
+
diff --git a/src/H5Cmpio.c b/src/H5Cmpio.c
new file mode 100644
index 0000000..a75cd88
--- /dev/null
+++ b/src/H5Cmpio.c
@@ -0,0 +1,1632 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cmpio.c
+ * June 20 2015
+ * Quincey Koziol
+ *
+ * Purpose: Functions in this file implement support for parallel I/O for
+ * generic cache code.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+
+#ifdef H5_HAVE_PARALLEL
+/****************/
+/* Local Macros */
+/****************/
+#define H5C_APPLY_CANDIDATE_LIST__DEBUG 0
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5C__collective_write(H5F_t *f, hid_t dxpl_id);
+static herr_t H5C__flush_candidate_entries(H5F_t *f, hid_t dxpl_id,
+ unsigned entries_to_flush[H5C_RING_NTYPES],
+ unsigned entries_to_clear[H5C_RING_NTYPES]);
+static herr_t H5C__flush_candidates_in_ring(H5F_t *f, hid_t dxpl_id,
+ H5C_ring_t ring, unsigned entries_to_flush, unsigned entries_to_clear);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_apply_candidate_list
+ *
+ * Purpose: Apply the supplied candidate list.
+ *
+ * We used to do this by simply having each process write
+ * every mpi_size-th entry in the candidate list, starting
+ * at index mpi_rank, and mark all the others clean.
+ *
+ * However, this can cause unnecessary contention in a file
+ * system by increasing the number of processes writing to
+ * adjacent locations in the HDF5 file.
+ *
+ * To attempt to minimize this, we now arange matters such
+ * that each process writes n adjacent entries in the
+ * candidate list, and marks all others clean. We must do
+ * this in such a fashion as to guarantee that each entry
+ * on the candidate list is written by exactly one process,
+ * and marked clean by all others.
+ *
+ * To do this, first construct a table mapping mpi_rank
+ * to the index of the first entry in the candidate list to
+ * be written by the process of that mpi_rank, and then use
+ * the table to control which entries are written and which
+ * are marked as clean as a function of the mpi_rank.
+ *
+ * Note that the table must be identical on all processes, as
+ * all see the same candidate list, mpi_size, and mpi_rank --
+ * the inputs used to construct the table.
+ *
+ * We construct the table as follows. Let:
+ *
+ * n = num_candidates / mpi_size;
+ *
+ * m = num_candidates % mpi_size;
+ *
+ * Now allocate an array of integers of length mpi_size + 1,
+ * and call this array candidate_assignment_table.
+ *
+ * Conceptually, if the number of candidates is a multiple
+ * of the mpi_size, we simply pass through the candidate list
+ * and assign n entries to each process to flush, with the
+ * index of the first entry to flush in the location in
+ * the candidate_assignment_table indicated by the mpi_rank
+ * of the process.
+ *
+ * In the more common case in which the candidate list isn't
+ * isn't a multiple of the mpi_size, we pretend it is, and
+ * give num_candidates % mpi_size processes one extra entry
+ * each to make things work out.
+ *
+ * Once the table is constructed, we determine the first and
+ * last entry this process is to flush as follows:
+ *
+ * first_entry_to_flush = candidate_assignment_table[mpi_rank]
+ *
+ * last_entry_to_flush =
+ * candidate_assignment_table[mpi_rank + 1] - 1;
+ *
+ * With these values determined, we simply scan through the
+ * candidate list, marking all entries in the range
+ * [first_entry_to_flush, last_entry_to_flush] for flush,
+ * and all others to be cleaned.
+ *
+ * Finally, we scan the LRU from tail to head, flushing
+ * or marking clean the candidate entries as indicated.
+ * If necessary, we scan the pinned list as well.
+ *
+ * Note that this function will fail if any protected or
+ * clean entries appear on the candidate list.
+ *
+ * This function is used in managing sync points, and
+ * shouldn't be used elsewhere.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_apply_candidate_list(H5F_t * f,
+ hid_t dxpl_id,
+ H5C_t * cache_ptr,
+ unsigned num_candidates,
+ haddr_t * candidates_list_ptr,
+ int mpi_rank,
+ int mpi_size)
+{
+ int i;
+ int m;
+ int n;
+ unsigned first_entry_to_flush;
+ unsigned last_entry_to_flush;
+ unsigned total_entries_to_clear = 0;
+ unsigned total_entries_to_flush = 0;
+ int * candidate_assignment_table = NULL;
+ unsigned entries_to_flush[H5C_RING_NTYPES];
+ unsigned entries_to_clear[H5C_RING_NTYPES];
+ haddr_t addr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+#if H5C_DO_SANITY_CHECKS
+ haddr_t last_addr;
+#endif /* H5C_DO_SANITY_CHECKS */
+#if H5C_APPLY_CANDIDATE_LIST__DEBUG
+ char tbl_buf[1024];
+#endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(num_candidates > 0);
+ HDassert(num_candidates <= cache_ptr->slist_len);
+ HDassert(candidates_list_ptr != NULL);
+ HDassert(0 <= mpi_rank);
+ HDassert(mpi_rank < mpi_size);
+
+ /* Initialize the entries_to_flush and entries_to_clear arrays */
+ HDmemset(entries_to_flush, 0, sizeof(entries_to_flush));
+ HDmemset(entries_to_clear, 0, sizeof(entries_to_clear));
+
+#if H5C_APPLY_CANDIDATE_LIST__DEBUG
+ HDfprintf(stdout, "%s:%d: setting up candidate assignment table.\n", FUNC, mpi_rank);
+
+ HDmemset(tbl_buf, 0, sizeof(tbl_buf));
+
+ sprintf(&(tbl_buf[0]), "candidate list = ");
+ for(u = 0; u < num_candidates; u++)
+ sprintf(&(tbl_buf[HDstrlen(tbl_buf)]), " 0x%llx", (long long)(*(candidates_list_ptr + u)));
+ sprintf(&(tbl_buf[HDstrlen(tbl_buf)]), "\n");
+
+ HDfprintf(stdout, "%s", tbl_buf);
+#endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */
+
+ if(f->coll_md_write) {
+ /* Sanity check */
+ HDassert(NULL == cache_ptr->coll_write_list);
+
+ /* Create skip list of entries for collective write */
+ if(NULL == (cache_ptr->coll_write_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for entries")
+ } /* end if */
+
+ n = num_candidates / mpi_size;
+ m = num_candidates % mpi_size;
+ HDassert(n >= 0);
+ if(NULL == (candidate_assignment_table = (int *)H5MM_malloc(sizeof(int) * (size_t)(mpi_size + 1))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for candidate assignment table")
+
+ candidate_assignment_table[0] = 0;
+ candidate_assignment_table[mpi_size] = num_candidates;
+
+ if(m == 0) { /* mpi_size is an even divisor of num_candidates */
+ HDassert(n > 0);
+ for(i = 1; i < mpi_size; i++)
+ candidate_assignment_table[i] = candidate_assignment_table[i - 1] + n;
+ } /* end if */
+ else {
+ for(i = 1; i <= m; i++)
+ candidate_assignment_table[i] = candidate_assignment_table[i - 1] + n + 1;
+
+ if(num_candidates < mpi_size) {
+ for(i = m + 1; i < mpi_size; i++)
+ candidate_assignment_table[i] = num_candidates;
+ } /* end if */
+ else {
+ for(i = m + 1; i < mpi_size; i++)
+ candidate_assignment_table[i] = candidate_assignment_table[i - 1] + n;
+ } /* end else */
+ } /* end else */
+ HDassert((candidate_assignment_table[mpi_size - 1] + n) == num_candidates);
+
+#if H5C_DO_SANITY_CHECKS
+ /* Verify that the candidate assignment table has the expected form */
+ for(i = 1; i < mpi_size - 1; i++) {
+ int a, b;
+
+ a = candidate_assignment_table[i] - candidate_assignment_table[i - 1];
+ b = candidate_assignment_table[i + 1] - candidate_assignment_table[i];
+
+ HDassert( n + 1 >= a );
+ HDassert( a >= b );
+ HDassert( b >= n );
+ }
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ first_entry_to_flush = candidate_assignment_table[mpi_rank];
+ last_entry_to_flush = candidate_assignment_table[mpi_rank + 1] - 1;
+
+#if H5C_APPLY_CANDIDATE_LIST__DEBUG
+ for ( i = 0; i < 1024; i++ )
+ tbl_buf[i] = '\0';
+ sprintf(&(tbl_buf[0]), "candidate assignment table = ");
+ for(i = 0; i <= mpi_size; i++)
+ sprintf(&(tbl_buf[HDstrlen(tbl_buf)]), " %d", candidate_assignment_table[i]);
+ sprintf(&(tbl_buf[HDstrlen(tbl_buf)]), "\n");
+ HDfprintf(stdout, "%s", tbl_buf);
+
+ HDfprintf(stdout, "%s:%d: flush entries [%u, %u].\n",
+ FUNC, mpi_rank, first_entry_to_flush, last_entry_to_flush);
+
+ HDfprintf(stdout, "%s:%d: marking entries.\n", FUNC, mpi_rank);
+#endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */
+
+ for(u = 0; u < num_candidates; u++) {
+ addr = candidates_list_ptr[u];
+ HDassert(H5F_addr_defined(addr));
+
+#if H5C_DO_SANITY_CHECKS
+ if(u > 0) {
+ if(last_addr == addr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "duplicate entry in cleaned list")
+ else if(last_addr > addr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "candidate list not sorted")
+ } /* end if */
+
+ last_addr = addr;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+ if(entry_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "listed candidate entry not in cache?!?!?")
+ if(!entry_ptr->is_dirty)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Listed entry not dirty?!?!?")
+ if(entry_ptr->is_protected)
+ /* For now at least, we can't deal with protected entries.
+ * If we encounter one, scream and die. If it becomes an
+ * issue, we should be able to work around this.
+ */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Listed entry is protected?!?!?")
+
+ /* Sanity checks */
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring >= H5C_RING_USER);
+ HDassert(entry_ptr->ring <= H5C_RING_SB);
+ HDassert(!entry_ptr->flush_immediately);
+ HDassert(!entry_ptr->clear_on_unprotect);
+
+ /* Determine whether the entry is to be cleared or flushed,
+ * and mark it accordingly. We will scan the protected and
+ * pinned list shortly, and clear or flush according to these
+ * markings.
+ */
+ if(u >= first_entry_to_flush && u <= last_entry_to_flush) {
+ total_entries_to_flush++;
+ entries_to_flush[entry_ptr->ring]++;
+ entry_ptr->flush_immediately = TRUE;
+ } /* end if */
+ else {
+ total_entries_to_clear++;
+ entries_to_clear[entry_ptr->ring]++;
+ entry_ptr->clear_on_unprotect = TRUE;
+ } /* end else */
+
+ /* Entries marked as collectively accessed and are in the
+ * candidate list to clear from the cache have to be
+ * removed from the coll list. This is OK since the
+ * candidate list is collective and uniform across all
+ * ranks.
+ */
+ if(entry_ptr->coll_access) {
+ entry_ptr->coll_access = FALSE;
+ H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, FAIL)
+ } /* end if */
+ } /* end for */
+
+#if H5C_DO_SANITY_CHECKS
+ m = 0;
+ n = 0;
+ for(i = 0; i < H5C_RING_NTYPES; i++) {
+ m += (int)entries_to_flush[i];
+ n += (int)entries_to_clear[i];
+ } /* end if */
+
+ HDassert((unsigned)m == total_entries_to_flush);
+ HDassert((unsigned)n == total_entries_to_clear);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+#if H5C_APPLY_CANDIDATE_LIST__DEBUG
+ HDfprintf(stdout, "%s:%d: num candidates/to clear/to flush = %u/%u/%u.\n",
+ FUNC, mpi_rank, num_candidates, total_entries_to_clear,
+ total_entries_to_flush);
+#endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */
+
+ /* We have now marked all the entries on the candidate list for
+ * either flush or clear -- now scan the LRU and the pinned list
+ * for these entries and do the deed. Do this via a call to
+ * H5C__flush_candidate_entries().
+ *
+ * Note that we are doing things in this round about manner so as
+ * to preserve the order of the LRU list to the best of our ability.
+ * If we don't do this, my experiments indicate that we will have a
+ * noticably poorer hit ratio as a result.
+ */
+ if(H5C__flush_candidate_entries(f, dxpl_id, entries_to_flush, entries_to_clear) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush candidates failed")
+
+ /* If we've deferred writing to do it collectively, take care of that now */
+ if(f->coll_md_write) {
+ /* Sanity check */
+ HDassert(cache_ptr->coll_write_list);
+
+ /* Write collective list */
+ if(H5C__collective_write(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_WRITEERROR, FAIL, "can't write metadata collectively")
+ } /* end if */
+
+done:
+ if(candidate_assignment_table != NULL)
+ candidate_assignment_table = (int *)H5MM_xfree((void *)candidate_assignment_table);
+ if(cache_ptr->coll_write_list) {
+ if(H5SL_close(cache_ptr->coll_write_list) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "failed to destroy skip list")
+ cache_ptr->coll_write_list = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_apply_candidate_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_construct_candidate_list__clean_cache
+ *
+ * Purpose: Construct the list of entries that should be flushed to
+ * clean all entries in the cache.
+ *
+ * This function is used in managing sync points, and
+ * shouldn't be used elsewhere.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_construct_candidate_list__clean_cache(H5C_t * cache_ptr)
+{
+ size_t space_needed;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ /* As a sanity check, set space needed to the size of the skip list.
+ * This should be the sum total of the sizes of all the dirty entries
+ * in the metadata cache.
+ */
+ space_needed = cache_ptr->slist_size;
+
+ /* Recall that while we shouldn't have any protected entries at this
+ * point, it is possible that some dirty entries may reside on the
+ * pinned list at this point.
+ */
+ HDassert( cache_ptr->slist_size <=
+ (cache_ptr->dLRU_list_size + cache_ptr->pel_size) );
+ HDassert( cache_ptr->slist_len <=
+ (cache_ptr->dLRU_list_len + cache_ptr->pel_len) );
+
+ if(space_needed > 0) { /* we have work to do */
+ H5C_cache_entry_t *entry_ptr;
+ unsigned nominated_entries_count = 0;
+ size_t nominated_entries_size = 0;
+ haddr_t nominated_addr;
+
+ HDassert( cache_ptr->slist_len > 0 );
+
+ /* Scan the dirty LRU list from tail forward and nominate sufficient
+ * entries to free up the necessary space.
+ */
+ entry_ptr = cache_ptr->dLRU_tail_ptr;
+ while((nominated_entries_size < space_needed) &&
+ (nominated_entries_count < cache_ptr->slist_len) &&
+ (entry_ptr != NULL)) {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( entry_ptr->ro_ref_count == 0 );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_slist );
+
+ nominated_addr = entry_ptr->addr;
+ if(H5AC_add_candidate((H5AC_t *)cache_ptr, nominated_addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_add_candidate() failed")
+
+ nominated_entries_size += entry_ptr->size;
+ nominated_entries_count++;
+ entry_ptr = entry_ptr->aux_prev;
+ } /* end while */
+ HDassert( entry_ptr == NULL );
+
+ /* it is possible that there are some dirty entries on the
+ * protected entry list as well -- scan it too if necessary
+ */
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while((nominated_entries_size < space_needed) &&
+ (nominated_entries_count < cache_ptr->slist_len) &&
+ (entry_ptr != NULL)) {
+ if(entry_ptr->is_dirty) {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( entry_ptr->ro_ref_count == 0 );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_slist );
+
+ nominated_addr = entry_ptr->addr;
+ if(H5AC_add_candidate((H5AC_t *)cache_ptr, nominated_addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_add_candidate() failed")
+
+ nominated_entries_size += entry_ptr->size;
+ nominated_entries_count++;
+ } /* end if */
+
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+
+ HDassert( nominated_entries_count == cache_ptr->slist_len );
+ HDassert( nominated_entries_size == space_needed );
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_construct_candidate_list__clean_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_construct_candidate_list__min_clean
+ *
+ * Purpose: Construct the list of entries that should be flushed to
+ * get the cache back within its min clean constraints.
+ *
+ * This function is used in managing sync points, and
+ * shouldn't be used elsewhere.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/17/10
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_construct_candidate_list__min_clean(H5C_t * cache_ptr)
+{
+ size_t space_needed = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( cache_ptr != NULL );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ /* compute the number of bytes (if any) that must be flushed to get the
+ * cache back within its min clean constraints.
+ */
+ if(cache_ptr->max_cache_size > cache_ptr->index_size) {
+ if(((cache_ptr->max_cache_size - cache_ptr->index_size) +
+ cache_ptr->cLRU_list_size) >= cache_ptr->min_clean_size)
+ space_needed = 0;
+ else
+ space_needed = cache_ptr->min_clean_size -
+ ((cache_ptr->max_cache_size - cache_ptr->index_size) +
+ cache_ptr->cLRU_list_size);
+ } /* end if */
+ else {
+ if(cache_ptr->min_clean_size <= cache_ptr->cLRU_list_size)
+ space_needed = 0;
+ else
+ space_needed = cache_ptr->min_clean_size -
+ cache_ptr->cLRU_list_size;
+ } /* end else */
+
+ if(space_needed > 0) { /* we have work to do */
+ H5C_cache_entry_t *entry_ptr;
+ unsigned nominated_entries_count = 0;
+ size_t nominated_entries_size = 0;
+
+ HDassert( cache_ptr->slist_len > 0 );
+
+ /* Scan the dirty LRU list from tail forward and nominate sufficient
+ * entries to free up the necessary space.
+ */
+ entry_ptr = cache_ptr->dLRU_tail_ptr;
+ while((nominated_entries_size < space_needed) &&
+ (nominated_entries_count < cache_ptr->slist_len) &&
+ (entry_ptr != NULL) &&
+ (!entry_ptr->flush_me_last)) {
+ haddr_t nominated_addr;
+
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_read_only) );
+ HDassert( entry_ptr->ro_ref_count == 0 );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_slist );
+
+ nominated_addr = entry_ptr->addr;
+ if(H5AC_add_candidate((H5AC_t *)cache_ptr, nominated_addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_add_candidate() failed")
+
+ nominated_entries_size += entry_ptr->size;
+ nominated_entries_count++;
+ entry_ptr = entry_ptr->aux_prev;
+ } /* end while */
+ HDassert( nominated_entries_count <= cache_ptr->slist_len );
+ HDassert( nominated_entries_size >= space_needed );
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_construct_candidate_list__min_clean() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_mark_entries_as_clean
+ *
+ * Purpose: When the H5C code is used to implement the metadata caches
+ * in PHDF5, only the cache with MPI_rank 0 is allowed to
+ * actually write entries to disk -- all other caches must
+ * retain dirty entries until they are advised that the
+ * entries are clean.
+ *
+ * This function exists to allow the H5C code to receive these
+ * notifications.
+ *
+ * The function receives a list of entry base addresses
+ * which must refer to dirty entries in the cache. If any
+ * of the entries are either clean or don't exist, the
+ * function flags an error.
+ *
+ * The function scans the list of entries and flushes all
+ * those that are currently unprotected with the
+ * H5C__FLUSH_CLEAR_ONLY_FLAG. Those that are currently
+ * protected are flagged for clearing when they are
+ * unprotected.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/5/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_mark_entries_as_clean(H5F_t * f,
+ hid_t dxpl_id,
+ unsigned ce_array_len,
+ haddr_t * ce_array_ptr)
+{
+ H5C_t * cache_ptr;
+ unsigned entries_cleared;
+ unsigned pinned_entries_cleared;
+ hbool_t progress;
+ unsigned entries_examined;
+ unsigned initial_list_len;
+ haddr_t addr;
+ unsigned pinned_entries_marked = 0;
+#if H5C_DO_SANITY_CHECKS
+ unsigned protected_entries_marked = 0;
+ unsigned other_entries_marked = 0;
+ haddr_t last_addr;
+#endif /* H5C_DO_SANITY_CHECKS */
+ H5C_cache_entry_t * clear_ptr = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ unsigned u;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert( f );
+ HDassert( f->shared );
+ cache_ptr = f->shared->cache;
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ HDassert( ce_array_len > 0 );
+ HDassert( ce_array_ptr != NULL );
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_protected_entry_list(cache_ptr) < 0 ||
+ H5C_validate_pinned_entry_list(cache_ptr) < 0 ||
+ H5C_validate_lru_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ for(u = 0; u < ce_array_len; u++) {
+ addr = ce_array_ptr[u];
+
+#if H5C_DO_SANITY_CHECKS
+ if(u == 0)
+ last_addr = addr;
+ else {
+ if(last_addr == addr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Duplicate entry in cleaned list")
+ if(last_addr > addr)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cleaned list not sorted")
+ } /* end else */
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_protected_entry_list(cache_ptr) < 0
+ || H5C_validate_pinned_entry_list(cache_ptr) < 0
+ || H5C_validate_lru_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed in for loop")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ HDassert( H5F_addr_defined(addr) );
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if(entry_ptr == NULL) {
+#if H5C_DO_SANITY_CHECKS
+ HDfprintf(stdout,
+ "H5C_mark_entries_as_clean: entry[%u] = %a not in cache.\n",
+ u,
+ addr);
+#endif /* H5C_DO_SANITY_CHECKS */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Listed entry not in cache?!?!?")
+ } /* end if */
+ else if(!entry_ptr->is_dirty) {
+#if H5C_DO_SANITY_CHECKS
+ HDfprintf(stdout,
+ "H5C_mark_entries_as_clean: entry %a is not dirty!?!\n",
+ addr);
+#endif /* H5C_DO_SANITY_CHECKS */
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Listed entry not dirty?!?!?")
+ } /* end else-if */
+ else {
+ /* Mark the entry to be cleared on unprotect. We will
+ * scan the LRU list shortly, and clear all those entries
+ * not currently protected.
+ */
+
+ /* Make sure first that we clear the collective flag from
+ it so it can be cleared */
+ if(TRUE == entry_ptr->coll_access) {
+ entry_ptr->coll_access = FALSE;
+ H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, FAIL)
+ } /* end if */
+
+ entry_ptr->clear_on_unprotect = TRUE;
+ if(entry_ptr->is_pinned)
+ pinned_entries_marked++;
+#if H5C_DO_SANITY_CHECKS
+ else if(entry_ptr->is_protected)
+ protected_entries_marked++;
+ else
+ other_entries_marked++;
+#endif /* H5C_DO_SANITY_CHECKS */
+ }
+ }
+
+ /* Scan through the LRU list from back to front, and flush the
+ * entries whose clear_on_unprotect flags are set. Observe that
+ * any protected entries will not be on the LRU, and therefore
+ * will not be flushed at this time.
+ *
+ * Note that unlike H5C_apply_candidate_list(),
+ * H5C_mark_entries_as_clean() makes all its calls to
+ * H5C__flush_single_entry() with the H5C__FLUSH_CLEAR_ONLY_FLAG
+ * set. As a result, the pre_serialize() and serialize calls are
+ * not made.
+ *
+ * This then implies that (assuming such actions were
+ * permitted in the parallel case) no loads, dirties,
+ * resizes, or removals of other entries can occur as
+ * a side effect of the flush. Hence, there is no need
+ * for the checks for entry removal / status change
+ * that I ported to H5C_apply_candidate_list().
+ *
+ * However, if (in addition to allowing such operations
+ * in the parallel case), we allow such operations outside
+ * of the pre_serialize / serialize routines, this may
+ * cease to be the case -- requiring a review of this
+ * point.
+ * JRM -- 4/7/15
+ */
+ entries_cleared = 0;
+ entries_examined = 0;
+ initial_list_len = cache_ptr->LRU_list_len;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+ while(entry_ptr != NULL && entries_examined <= initial_list_len &&
+ entries_cleared < ce_array_len) {
+ if(entry_ptr->clear_on_unprotect) {
+ entry_ptr->clear_on_unprotect = FALSE;
+ clear_ptr = entry_ptr;
+ entry_ptr = entry_ptr->prev;
+ entries_cleared++;
+
+ if(H5C__flush_single_entry(f, dxpl_id, clear_ptr,
+ (H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__GENERATE_IMAGE_FLAG | H5C__UPDATE_PAGE_BUFFER_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear entry")
+ } /* end if */
+ else
+ entry_ptr = entry_ptr->prev;
+ entries_examined++;
+ } /* end while */
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert( entries_cleared == other_entries_marked );
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* It is also possible that some of the cleared entries are on the
+ * pinned list. Must scan that also.
+ */
+ pinned_entries_cleared = 0;
+ progress = TRUE;
+ while((pinned_entries_cleared < pinned_entries_marked) && progress) {
+ progress = FALSE;
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while(entry_ptr != NULL) {
+ if(entry_ptr->clear_on_unprotect && entry_ptr->flush_dep_ndirty_children == 0) {
+ entry_ptr->clear_on_unprotect = FALSE;
+ clear_ptr = entry_ptr;
+ entry_ptr = entry_ptr->next;
+ entries_cleared++;
+ pinned_entries_cleared++;
+ progress = TRUE;
+
+ if(H5C__flush_single_entry(f, dxpl_id, clear_ptr,
+ (H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__GENERATE_IMAGE_FLAG | H5C__UPDATE_PAGE_BUFFER_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear entry")
+ } /* end if */
+ else
+ entry_ptr = entry_ptr->next;
+ } /* end while */
+ } /* end while */
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert( entries_cleared == pinned_entries_marked + other_entries_marked );
+ HDassert( entries_cleared + protected_entries_marked == ce_array_len );
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ HDassert( ( entries_cleared == ce_array_len ) ||
+ ( (ce_array_len - entries_cleared) <= cache_ptr->pl_len ) );
+
+#if H5C_DO_SANITY_CHECKS
+ u = 0;
+ entry_ptr = cache_ptr->pl_head_ptr;
+ while ( entry_ptr != NULL )
+ {
+ if ( entry_ptr->clear_on_unprotect ) {
+
+ u++;
+ }
+ entry_ptr = entry_ptr->next;
+ }
+ HDassert( (entries_cleared + u) == ce_array_len );
+#endif /* H5C_DO_SANITY_CHECKS */
+
+done:
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_protected_entry_list(cache_ptr) < 0
+ || H5C_validate_pinned_entry_list(cache_ptr) < 0
+ || H5C_validate_lru_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_mark_entries_as_clean() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_clear_coll_entries
+ *
+ * Purpose: Clear half or the entire list of collective entries and
+ * mark them as independent.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mohamad Chaarawi
+ * April, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_clear_coll_entries(H5C_t *cache_ptr, hbool_t partial)
+{
+ uint32_t clear_cnt;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ entry_ptr = cache_ptr->coll_tail_ptr;
+ clear_cnt = (partial ? cache_ptr->coll_list_len / 2 : cache_ptr->coll_list_len);
+ while(entry_ptr && clear_cnt > 0) {
+ H5C_cache_entry_t *prev_ptr = entry_ptr->coll_prev;
+
+ /* Sanity check */
+ HDassert(entry_ptr->coll_access);
+
+ /* Mark entry as independent */
+ entry_ptr->coll_access = FALSE;
+ H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, FAIL)
+
+ /* Decrement entry count */
+ clear_cnt--;
+
+ /* Advance to next entry */
+ entry_ptr = prev_ptr;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_clear_coll_entries */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__collective_write
+ *
+ * Purpose: Perform a collective write of a list of metadata entries.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mohamad Chaarawi
+ * February, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__collective_write(H5F_t *f, hid_t dxpl_id)
+{
+ H5AC_t *cache_ptr;
+ H5P_genplist_t *plist = NULL;
+ H5FD_mpio_xfer_t orig_xfer_mode = H5FD_MPIO_COLLECTIVE;
+ int count;
+ int *length_array = NULL;
+ MPI_Aint *buf_array = NULL;
+ MPI_Aint *offset_array = NULL;
+ MPI_Datatype btype;
+ hbool_t btype_created = FALSE;
+ MPI_Datatype ftype;
+ hbool_t ftype_created = FALSE;
+ int mpi_code;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f != NULL);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->coll_write_list != NULL);
+
+ /* Get original transfer mode */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, \
+ "not a data transfer property list")
+
+ if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &orig_xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O property")
+
+ /* Get number of entries in collective write list */
+ count = (int)H5SL_count(cache_ptr->coll_write_list);
+
+ if(count > 0) {
+ H5FD_mpio_xfer_t xfer_mode = H5FD_MPIO_COLLECTIVE;
+ H5SL_node_t *node;
+ H5C_cache_entry_t *entry_ptr;
+ void *base_buf;
+ int i;
+
+ if(H5P_set(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, \
+ "can't set MPI-I/O property")
+
+ /* Allocate arrays */
+ if ( NULL == (length_array =
+ (int *)H5MM_malloc((size_t)count * sizeof(int))) )
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, \
+ "memory allocation failed for collective write table length array")
+
+ if ( NULL == (buf_array =
+ (MPI_Aint *)H5MM_malloc((size_t)count * sizeof(MPI_Aint))) )
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, \
+ "memory allocation failed for collective buf table length array")
+
+ if(NULL == (offset_array =
+ (MPI_Aint *)H5MM_malloc((size_t)count * sizeof(MPI_Aint))) )
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, \
+ "memory allocation failed for collective offset table length array")
+
+ /* Fill arrays */
+ node = H5SL_first(cache_ptr->coll_write_list);
+ HDassert(node);
+ if(NULL == (entry_ptr = (H5C_cache_entry_t *)H5SL_item(node)))
+ HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, \
+ "can't retrieve skip list item")
+
+ /* Set up initial array position & buffer base address */
+ length_array[0] = (int)entry_ptr->size;
+ base_buf = entry_ptr->image_ptr;
+ buf_array[0] = (MPI_Aint)0;
+ offset_array[0] = (MPI_Aint)entry_ptr->addr;
+
+ node = H5SL_next(node);
+ i = 1;
+ while(node) {
+
+ if(NULL == (entry_ptr = (H5C_cache_entry_t *)H5SL_item(node)))
+ HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, \
+ "can't retrieve skip list item")
+
+ /* Set up array position */
+ length_array[i] = (int)entry_ptr->size;
+ buf_array[i] = (MPI_Aint)entry_ptr->image_ptr - (MPI_Aint)base_buf;
+ offset_array[i] = (MPI_Aint)entry_ptr->addr;
+
+ /* Advance to next node & array location */
+ node = H5SL_next(node);
+ i++;
+ } /* end while */
+
+ /* Create memory MPI type */
+ if(MPI_SUCCESS != (mpi_code =
+ MPI_Type_create_hindexed(count, length_array,
+ buf_array, MPI_BYTE,
+ &btype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
+
+ btype_created = TRUE;
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&btype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+ /* Create file MPI type */
+ if(MPI_SUCCESS != (mpi_code =
+ MPI_Type_create_hindexed(count, length_array,
+ offset_array, MPI_BYTE,
+ &ftype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
+
+ ftype_created = TRUE;
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&ftype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+ /* Pass buf type, file type to the file driver */
+ if(H5FD_mpi_setup_collective(dxpl_id, &btype, &ftype) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, \
+ "can't set MPI-I/O properties")
+
+ /* Write data */
+ if(H5F_block_write(f, H5FD_MEM_DEFAULT, (haddr_t)0,
+ (size_t)1, dxpl_id, base_buf) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to write entries collectively")
+
+ } /* end if */
+ else {
+ MPI_Status mpi_stat;
+ MPI_File *mpi_fh_p;
+ MPI_File mpi_fh;
+ MPI_Info *info_p;
+ MPI_Info info;
+
+ if(H5F_get_mpi_handle(f, (MPI_File **)&mpi_fh_p) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, \
+ "can't get mpi file handle")
+
+ mpi_fh = *(MPI_File*)mpi_fh_p;
+
+ if (H5F_get_mpi_info(f, &info_p) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, \
+ "can't get mpi file info")
+
+ info = *info_p;
+
+ /* just to match up with the 1st MPI_File_set_view from
+ * H5FD_mpio_write()
+ */
+ if(MPI_SUCCESS != (mpi_code =
+ MPI_File_set_view(mpi_fh, (MPI_Offset)0, MPI_BYTE,
+ MPI_BYTE, "native",
+ info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* just to match up with MPI_File_write_at_all from H5FD_mpio_write() */
+ HDmemset(&mpi_stat, 0, sizeof(MPI_Status));
+ if(MPI_SUCCESS != (mpi_code =
+ MPI_File_write_at_all(mpi_fh, (MPI_Offset)0,
+ NULL, 0, MPI_BYTE, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code)
+
+ /* just to match up with the 2nd MPI_File_set_view (reset) in
+ * H5FD_mpio_write()
+ */
+ if(MPI_SUCCESS != (mpi_code =
+ MPI_File_set_view(mpi_fh, (MPI_Offset)0, MPI_BYTE,
+ MPI_BYTE, "native",
+ info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ } /* end else */
+
+done:
+ /* Free arrays */
+ length_array = (int *)H5MM_xfree(length_array);
+ buf_array = (MPI_Aint *)H5MM_xfree(buf_array);
+ offset_array = (MPI_Aint *)H5MM_xfree(offset_array);
+
+ /* Free MPI Types */
+ if(btype_created && MPI_SUCCESS != (mpi_code = MPI_Type_free(&btype)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ if(ftype_created && MPI_SUCCESS != (mpi_code = MPI_Type_free(&ftype)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+ /* Reset dxpl */
+ if(orig_xfer_mode != H5FD_MPIO_COLLECTIVE) {
+ HDassert(plist);
+ if(H5P_set(plist, H5D_XFER_IO_XFER_MODE_NAME, &orig_xfer_mode) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, \
+ "can't set MPI-I/O property")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5C__collective_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__flush_candidate_entries
+ *
+ * Purpose: Flush or clear (as indicated) the candidate entries that
+ * have been marked in the metadata cache. In so doing,
+ * observe rings and flush dependencies.
+ *
+ * Note that this function presumes that:
+ *
+ * 1) no candidate entries are protected,
+ *
+ * 2) all candidate entries are dirty, and
+ *
+ * 3) if a candidate entry has a dirty flush dependency
+ * child, that child is also a candidate entry.
+ *
+ * The function will fail if any of these preconditions are
+ * not met.
+ *
+ * Candidate entries are marked by setting either the
+ * flush_immediately or the clear_on_unprotect flags in the
+ * cache entry (but not both). Entries marked flush_immediately
+ * will be flushed, those marked clear_on_unprotect will be
+ * cleared.
+ *
+ * Note that this function is a modified version of
+ * H5C_flush_cache() -- any changes there may need to be
+ * reflected here and vise versa.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer
+ * 2/10/17
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__flush_candidate_entries(H5F_t *f, hid_t dxpl_id,
+ unsigned entries_to_flush[H5C_RING_NTYPES],
+ unsigned entries_to_clear[H5C_RING_NTYPES])
+{
+#if H5C_DO_SANITY_CHECKS
+ int i;
+ uint32_t index_len = 0;
+ size_t index_size = (size_t)0;
+ size_t clean_index_size = (size_t)0;
+ size_t dirty_index_size = (size_t)0;
+ size_t slist_size = (size_t)0;
+ uint32_t slist_len = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+ H5C_ring_t ring;
+ H5C_t * cache_ptr;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ cache_ptr = f->shared->cache;
+
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+
+ HDassert(entries_to_flush[H5C_RING_UNDEFINED] == 0);
+ HDassert(entries_to_clear[H5C_RING_UNDEFINED] == 0);
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+ HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0);
+ HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0);
+
+ for(i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) {
+ index_len += cache_ptr->index_ring_len[i];
+ index_size += cache_ptr->index_ring_size[i];
+ clean_index_size += cache_ptr->clean_index_ring_size[i];
+ dirty_index_size += cache_ptr->dirty_index_ring_size[i];
+
+ slist_len += cache_ptr->slist_ring_len[i];
+ slist_size += cache_ptr->slist_ring_size[i];
+ } /* end for */
+
+ HDassert(cache_ptr->index_len == index_len);
+ HDassert(cache_ptr->index_size == index_size);
+ HDassert(cache_ptr->clean_index_size == clean_index_size);
+ HDassert(cache_ptr->dirty_index_size == dirty_index_size);
+ HDassert(cache_ptr->slist_len == slist_len);
+ HDassert(cache_ptr->slist_size == slist_size);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if(H5C_validate_protected_entry_list(cache_ptr) < 0
+ || H5C_validate_pinned_entry_list(cache_ptr) < 0
+ || H5C_validate_lru_list(cache_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+ cache_ptr->flush_in_progress = TRUE;
+
+ /* flush each ring, starting from the outermost ring and
+ * working inward.
+ */
+ ring = H5C_RING_USER;
+ while(ring < H5C_RING_NTYPES) {
+ if(H5C__flush_candidates_in_ring(f, dxpl_id, ring, entries_to_flush[ring], entries_to_clear[ring]) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush candidates in ring failed")
+
+ ring++;
+ } /* end while */
+
+done:
+ cache_ptr->flush_in_progress = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__flush_candidate_entries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__flush_candidates_in_ring
+ *
+ * Purpose: Flush or clear (as indicated) the candidate entries
+ * contained in the specified cache and ring. All candidate
+ * entries in rings outside the specified ring must have been
+ * flushed (or cleared) on entry.
+ *
+ * Note that this function presumes that:
+ *
+ * 1) no candidate entries are protected,
+ *
+ * 2) all candidate entries are dirty, and
+ *
+ * 3) if a candidate entry has a dirty flush dependency
+ * child, that child is also a candidate entry.
+ *
+ * The function will fail if any of these preconditions are
+ * not met.
+ *
+ * Candidate entries are marked by setting either the
+ * flush_immediately or the clear_on_unprotect flags in the
+ * cache entry (but not both). Entries marked flush_immediately
+ * will be flushed, those marked clear_on_unprotect will be
+ * cleared.
+ *
+ * Candidate entries residing in the LRU must be flushed
+ * (or cleared) in LRU order to avoid performance issues.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer
+ * 2/10/17
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__flush_candidates_in_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring,
+ unsigned entries_to_flush, unsigned entries_to_clear)
+{
+ H5C_t * cache_ptr;
+ hbool_t progress;
+ hbool_t restart_scan = FALSE;
+ unsigned entries_flushed = 0;
+ unsigned entries_cleared = 0;
+#if H5C_DO_SANITY_CHECKS
+ unsigned init_index_len;
+#endif /* H5C_DO_SANITY_CHECKS */
+ unsigned clear_flags = H5C__FLUSH_CLEAR_ONLY_FLAG |
+ H5C__GENERATE_IMAGE_FLAG |
+ H5C__UPDATE_PAGE_BUFFER_FLAG;
+ unsigned flush_flags = H5C__NO_FLAGS_SET;
+ unsigned op_flags;
+ H5C_cache_entry_t *op_ptr;
+ H5C_cache_entry_t *entry_ptr;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(cache_ptr->slist_ptr);
+ HDassert(ring > H5C_RING_UNDEFINED);
+ HDassert(ring < H5C_RING_NTYPES);
+
+#if H5C_DO_EXTREME_SANITY_CHECKS
+ if((H5C_validate_protected_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_pinned_entry_list(cache_ptr) < 0) ||
+ (H5C_validate_lru_list(cache_ptr) < 0))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry")
+#endif /* H5C_DO_EXTREME_SANITY_CHECKS */
+
+#if H5C_DO_SANITY_CHECKS
+ /* index len should not change */
+ init_index_len = cache_ptr->index_len;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* Examine entries in the LRU list, and flush or clear all entries
+ * so marked in the target ring.
+ *
+ * With the current implementation of flush dependencies, no entry
+ * in the LRU can have flush dependency children -- thus one pass
+ * through the LRU will be sufficient.
+ *
+ * It is possible that this will change -- hence the assertion.
+ */
+ restart_scan = FALSE;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+ while(((entries_flushed < entries_to_flush) || (entries_cleared < entries_to_clear))
+ && (entry_ptr != NULL)) {
+ hbool_t prev_is_dirty = FALSE;
+ H5C_cache_entry_t *next_ptr;
+
+ /* Entries in the LRU must not have flush dependency children */
+ HDassert(entry_ptr->flush_dep_nchildren == 0);
+
+ /* Remember dirty state of entry to advance to */
+ if(entry_ptr->prev != NULL)
+ prev_is_dirty = entry_ptr->prev->is_dirty;
+
+ /* If the entry is in the ring */
+ if(entry_ptr->ring == ring) {
+ /* If this process needs to clear this entry. */
+ if(entry_ptr->clear_on_unprotect) {
+ HDassert(entry_ptr->is_dirty);
+
+ /* Set entry and flags for operation */
+ op_ptr = entry_ptr;
+ op_flags = clear_flags;
+
+ /* Set next entry appropriately */
+ next_ptr = entry_ptr->next;
+
+ /* Reset entry flag */
+ entry_ptr->clear_on_unprotect = FALSE;
+ entries_cleared++;
+ } /* end if */
+ else if(entry_ptr->flush_immediately) {
+ HDassert(entry_ptr->is_dirty);
+
+ /* Set entry and flags for operation */
+ op_ptr = entry_ptr;
+ op_flags = flush_flags;
+
+ /* Set next entry appropriately */
+ next_ptr = entry_ptr->next;
+
+ /* Reset entry flag */
+ entry_ptr->flush_immediately = FALSE;
+ entries_flushed++;
+ } /* end else-if */
+ else {
+ /* No operation for this entry */
+ op_ptr = NULL;
+
+ /* Set next entry appropriately */
+ next_ptr = entry_ptr;
+ } /* end else */
+
+ /* Advance to next entry */
+ entry_ptr = entry_ptr->prev;
+
+ /* Check for operation */
+ if(op_ptr) {
+ /* reset entries_removed_counter and
+ * last_entry_removed_ptr prior to the call to
+ * H5C__flush_single_entry() so that we can spot
+ * unexpected removals of entries from the cache,
+ * and set the restart_scan flag if proceeding
+ * would be likely to cause us to scan an entry
+ * that is no longer in the cache.
+ *
+ * Note that as of this writing, this
+ * case cannot occur in the parallel case.
+ *
+ * Note also that there is no test code to verify
+ * that this code actually works (although similar code
+ * in the serial version exists and is tested).
+ */
+ cache_ptr->entries_removed_counter = 0;
+ cache_ptr->last_entry_removed_ptr = NULL;
+
+ if(H5C__flush_single_entry(f, dxpl_id, op_ptr, op_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't flush entry")
+
+ if(cache_ptr->entries_removed_counter != 0
+ || cache_ptr->last_entry_removed_ptr != NULL)
+ restart_scan = TRUE;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Remember "next" pointer (after advancing entries) */
+ next_ptr = entry_ptr;
+
+ /* Advance to next entry */
+ entry_ptr = entry_ptr->prev;
+ } /* end else */
+
+ /* Check for restarts, etc. */
+ if((entry_ptr != NULL) &&
+ (restart_scan || (entry_ptr->is_dirty != prev_is_dirty)
+ || (entry_ptr->next != next_ptr) || entry_ptr->is_protected
+ || entry_ptr->is_pinned)) {
+
+ /* Something has happened to the LRU -- start over
+ * from the tail.
+ *
+ * Recall that this code should be un-reachable at present,
+ * as all the operations by entries on flush that could cause
+ * it to be reachable are disallowed in the parallel case at
+ * present. Hence the following assertion which should be
+ * removed if the above changes.
+ */
+ HDassert(!restart_scan);
+ HDassert(entry_ptr->is_dirty == prev_is_dirty);
+ HDassert(entry_ptr->next == next_ptr);
+ HDassert(!entry_ptr->is_protected);
+ HDassert(!entry_ptr->is_pinned);
+
+ HDassert(FALSE); /* see comment above */
+
+ restart_scan = FALSE;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+
+ H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr)
+ } /* end if */
+ } /* end while */
+
+ /* It is also possible that some of the cleared entries are on the
+ * pinned list. Must scan that also.
+ *
+ * Observe that in the case of the pinned entry list, most of the
+ * entries will have flush dependency children. As entries with
+ * flush dependency children may not be flushed until all of their
+ * children are clean, multiple passes throguh the pinned entry list
+ * may be required.
+ *
+ * WARNING:
+ *
+ * As we now allow unpinning, and removal of other entries as a side
+ * effect of flushing an entry, it is possible that the next entry
+ * in a PEL scan could either be no longer pinned, or no longer in
+ * the cache by the time we get to it.
+ *
+ * At present, this should not be possible in this case, as we disallow
+ * such operations in the parallel version of the library. However,
+ * this may change, and to that end, I have included code to detect
+ * such changes and cause this function to fail if they are detected.
+ */
+ progress = TRUE;
+ while(progress && ((entries_flushed < entries_to_flush) || (entries_cleared < entries_to_clear))) {
+ progress = FALSE;
+ entry_ptr = cache_ptr->pel_head_ptr;
+ while((entry_ptr != NULL) &&
+ ((entries_flushed < entries_to_flush) || (entries_cleared < entries_to_clear))) {
+ H5C_cache_entry_t *prev_ptr;
+ hbool_t next_is_dirty = FALSE;
+
+ HDassert(entry_ptr->is_pinned);
+
+ /* Remember dirty state of entry to advance to */
+ if(entry_ptr->next != NULL)
+ next_is_dirty = entry_ptr->next->is_dirty;
+
+ if(entry_ptr->ring == ring && entry_ptr->flush_dep_ndirty_children == 0) {
+ if(entry_ptr->clear_on_unprotect) {
+ HDassert(entry_ptr->is_dirty);
+
+ /* Set entry and flags for operation */
+ op_ptr = entry_ptr;
+ op_flags = clear_flags;
+
+ /* Reset entry flag */
+ entry_ptr->clear_on_unprotect = FALSE;
+ entries_cleared++;
+ progress = TRUE;
+ } /* end if */
+ else if(entry_ptr->flush_immediately) {
+ HDassert(entry_ptr->is_dirty);
+
+ /* Set entry and flags for operation */
+ op_ptr = entry_ptr;
+ op_flags = flush_flags;
+
+ /* Reset entry flag */
+ entry_ptr->flush_immediately = FALSE;
+ entries_flushed++;
+ progress = TRUE;
+ } /* end else-if */
+ else
+ /* No operation for this entry */
+ op_ptr = NULL;
+
+ /* Check for operation */
+ if(op_ptr) {
+ /* reset entries_removed_counter and
+ * last_entry_removed_ptr prior to the call to
+ * H5C__flush_single_entry() so that we can spot
+ * unexpected removals of entries from the cache,
+ * and set the restart_scan flag if proceeding
+ * would be likely to cause us to scan an entry
+ * that is no longer in the cache.
+ *
+ * Note that as of this writing, this
+ * case cannot occur in the parallel case.
+ *
+ * Note also that there is no test code to verify
+ * that this code actually works (although similar code
+ * in the serial version exists and is tested).
+ */
+ cache_ptr->entries_removed_counter = 0;
+ cache_ptr->last_entry_removed_ptr = NULL;
+
+ /* Add this entry to the list of entries to collectively write
+ *
+ * This comment is misleading -- the entry will be added to the
+ * collective write list only if said list exists.
+ *
+ * JRM -- 2/9/17
+ */
+ if(H5C__flush_single_entry(f, dxpl_id, op_ptr, op_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't flush entry")
+
+ if(cache_ptr->entries_removed_counter != 0
+ || cache_ptr->last_entry_removed_ptr != NULL)
+ restart_scan = TRUE;
+ } /* end if */
+ } /* end if */
+
+ /* Remember "previous" pointer (after advancing entries) */
+ prev_ptr = entry_ptr;
+
+ /* Advance to next entry */
+ entry_ptr = entry_ptr->next;
+
+ /* Check for restarts, etc. */
+ if((entry_ptr != NULL) &&
+ (restart_scan || (entry_ptr->is_dirty != next_is_dirty)
+ || (entry_ptr->prev != prev_ptr) || entry_ptr->is_protected
+ || !entry_ptr->is_pinned)) {
+ /* Something has happened to the pinned entry list -- start
+ * over from the head.
+ *
+ * Recall that this code should be un-reachable at present,
+ * as all the operations by entries on flush that could cause
+ * it to be reachable are disallowed in the parallel case at
+ * present. Hence the following assertion which should be
+ * removed if the above changes.
+ */
+
+ HDassert(!restart_scan);
+ HDassert(entry_ptr->is_dirty == next_is_dirty);
+ HDassert(entry_ptr->prev == prev_ptr);
+ HDassert(!entry_ptr->is_protected);
+ HDassert(entry_ptr->is_pinned);
+
+ HDassert(FALSE); /* see comment above */
+
+ restart_scan = FALSE;
+
+ entry_ptr = cache_ptr->pel_head_ptr;
+
+ /* we don't keeps stats for pinned entry list scan
+ * restarts. If this code ever becomes reachable,
+ * define the necessary field, and implement the
+ * the following macro:
+ *
+ * H5C__UPDATE_STATS_FOR_PEL_SCAN_RESTART(cache_ptr)
+ */
+ } /* end if */
+ } /* end while ( ( entry_ptr != NULL ) &&
+ * ( ( entries_flushed > entries_to_flush ) ||
+ * ( entries_cleared > entries_to_clear ) ) )
+ */
+ } /* end while ( ( ( entries_flushed > entries_to_flush ) ||
+ * ( entries_cleared > entries_to_clear ) ) &&
+ * ( progress ) )
+ */
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert(init_index_len == cache_ptr->index_len);
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ if(entries_flushed != entries_to_flush || entries_cleared != entries_to_clear) {
+ entry_ptr = cache_ptr->il_head;
+ while(entry_ptr != NULL) {
+ HDassert(!entry_ptr->clear_on_unprotect || (entry_ptr->ring > ring));
+ HDassert(!entry_ptr->flush_immediately || (entry_ptr->ring > ring));
+ entry_ptr = entry_ptr->il_next;
+ } /* end while */
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't flush/clear all entries")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__flush_candidates_in_ring() */
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h
new file mode 100644
index 0000000..fdb14a5
--- /dev/null
+++ b/src/H5Cpkg.h
@@ -0,0 +1,4956 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: John Mainzer -- 10/12/04
+ *
+ * Purpose: This file contains declarations which are normally visible
+ * only within the H5C package.
+ *
+ * Source files outside the H5C package should include
+ * H5Cprivate.h instead.
+ *
+ * The one exception to this rule is test/cache.c. The test
+ * code is easier to write if it can look at the cache's
+ * internal data structures. Indeed, this is the main
+ * reason why this file was created.
+ */
+
+#if !(defined H5C_FRIEND || defined H5C_MODULE)
+#error "Do not include this file outside the H5C package!"
+#endif
+
+#ifndef _H5Cpkg_H
+#define _H5Cpkg_H
+
+/* Get package's private header */
+#include "H5Cprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5SLprivate.h" /* Skip lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Number of epoch markers active */
+#define H5C__MAX_EPOCH_MARKERS 10
+
+/* Cache configuration settings */
+#define H5C__HASH_TABLE_LEN (64 * 1024) /* must be a power of 2 */
+#define H5C__H5C_T_MAGIC 0x005CAC0E
+
+/* Initial allocated size of the "flush_dep_parent" array */
+#define H5C_FLUSH_DEP_PARENT_INIT 8
+
+/****************************************************************************
+ *
+ * We maintain doubly linked lists of instances of H5C_cache_entry_t for a
+ * variety of reasons -- protected list, LRU list, and the clean and dirty
+ * LRU lists at present. The following macros support linking and unlinking
+ * of instances of H5C_cache_entry_t by both their regular and auxilary next
+ * and previous pointers.
+ *
+ * The size and length fields are also maintained.
+ *
+ * Note that the relevant pair of prev and next pointers are presumed to be
+ * NULL on entry in the insertion macros.
+ *
+ * Finally, observe that the sanity checking macros evaluate to the empty
+ * string when H5C_DO_SANITY_CHECKS is FALSE. They also contain calls
+ * to the HGOTO_ERROR macro, which may not be appropriate in all cases.
+ * If so, we will need versions of the insertion and deletion macros which
+ * do not reference the sanity checking macros.
+ * JRM - 5/5/04
+ *
+ * Changes:
+ *
+ * - Removed the line:
+ *
+ * ( ( (Size) == (entry_ptr)->size ) && ( (len) != 1 ) ) ||
+ *
+ * from the H5C__DLL_PRE_REMOVE_SC macro. With the addition of the
+ * epoch markers used in the age out based cache size reduction algorithm,
+ * this invariant need not hold, as the epoch markers are of size 0.
+ *
+ * One could argue that I should have given the epoch markers a positive
+ * size, but this would break the index_size = LRU_list_size + pl_size
+ * + pel_size invariant.
+ *
+ * Alternatively, I could pass the current decr_mode in to the macro,
+ * and just skip the check whenever epoch markers may be in use.
+ *
+ * However, any size errors should be caught when the cache is flushed
+ * and destroyed. Until we are tracking such an error, this should be
+ * good enough.
+ * JRM - 12/9/04
+ *
+ *
+ * - In the H5C__DLL_PRE_INSERT_SC macro, replaced the lines:
+ *
+ * ( ( (len) == 1 ) &&
+ * ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) ||
+ * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
+ * )
+ * ) ||
+ *
+ * with:
+ *
+ * ( ( (len) == 1 ) &&
+ * ( ( (head_ptr) != (tail_ptr) ) ||
+ * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
+ * )
+ * ) ||
+ *
+ * Epoch markers have size 0, so we can now have a non-empty list with
+ * zero size. Hence the "( (Size) <= 0 )" clause cause false failures
+ * in the sanity check. Since "Size" is typically a size_t, it can't
+ * take on negative values, and thus the revised clause "( (Size) < 0 )"
+ * caused compiler warnings.
+ * JRM - 12/22/04
+ *
+ * - In the H5C__DLL_SC macro, replaced the lines:
+ *
+ * ( ( (len) == 1 ) &&
+ * ( ( (head_ptr) != (tail_ptr) ) || ( (cache_ptr)->size <= 0 ) ||
+ * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
+ * )
+ * ) ||
+ *
+ * with
+ *
+ * ( ( (len) == 1 ) &&
+ * ( ( (head_ptr) != (tail_ptr) ) ||
+ * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
+ * )
+ * ) ||
+ *
+ * Epoch markers have size 0, so we can now have a non-empty list with
+ * zero size. Hence the "( (Size) <= 0 )" clause cause false failures
+ * in the sanity check. Since "Size" is typically a size_t, it can't
+ * take on negative values, and thus the revised clause "( (Size) < 0 )"
+ * caused compiler warnings.
+ * JRM - 1/10/05
+ *
+ * - Added the H5C__DLL_UPDATE_FOR_SIZE_CHANGE macro and the associated
+ * sanity checking macros. These macro are used to update the size of
+ * a DLL when one of its entries changes size.
+ *
+ * JRM - 9/8/05
+ *
+ * - Added macros supporting the index list -- a doubly liked list of
+ * all entries in the index. This list is necessary to reduce the
+ * cost of visiting all entries in the cache, which was previously
+ * done via a scan of the hash table.
+ *
+ * JRM - 10/15/15
+ *
+ ****************************************************************************/
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+if ( ( (head_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (entry_ptr)->prev == NULL ) && ( (head_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (head_ptr) == (entry_ptr) ) && \
+ ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->next == NULL ) && \
+ ( (entry_ptr)->prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre remove SC failed") \
+}
+
+#define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( (Size) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL sanity check failed") \
+}
+
+#define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->next != NULL ) || \
+ ( (entry_ptr)->prev != NULL ) || \
+ ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre insert SC failed") \
+}
+
+#define H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \
+if ( ( (dll_len) <= 0 ) || \
+ ( (dll_size) <= 0 ) || \
+ ( (old_size) <= 0 ) || \
+ ( (old_size) > (dll_size) ) || \
+ ( (new_size) <= 0 ) || \
+ ( ( (dll_len) == 1 ) && ( (old_size) != (dll_size) ) ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL pre size update SC failed") \
+}
+
+#define H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \
+if ( ( (new_size) > (dll_size) ) || \
+ ( ( (dll_len) == 1 ) && ( (new_size) != (dll_size) ) ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL post size update SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
+#define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+#define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
+#define H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)
+#define H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+{ \
+ H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->next = (entry_ptr); \
+ (entry_ptr)->prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += (entry_ptr)->size; \
+} /* H5C__DLL_APPEND() */
+
+#define H5C__DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+{ \
+ H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (head_ptr)->prev = (entry_ptr); \
+ (entry_ptr)->next = (head_ptr); \
+ (head_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+} /* H5C__DLL_PREPEND() */
+
+#define H5C__DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+{ \
+ H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->next; \
+ if ( (head_ptr) != NULL ) \
+ (head_ptr)->prev = NULL; \
+ } \
+ else \
+ (entry_ptr)->prev->next = (entry_ptr)->next; \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->prev; \
+ if ( (tail_ptr) != NULL ) \
+ (tail_ptr)->next = NULL; \
+ } \
+ else \
+ (entry_ptr)->next->prev = (entry_ptr)->prev; \
+ entry_ptr->next = NULL; \
+ entry_ptr->prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ } \
+} /* H5C__DLL_REMOVE() */
+
+#define H5C__DLL_UPDATE_FOR_SIZE_CHANGE(dll_len, dll_size, old_size, new_size) \
+{ \
+ H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \
+ (dll_size) -= (old_size); \
+ (dll_size) += (new_size); \
+ H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \
+} /* H5C__DLL_UPDATE_FOR_SIZE_CHANGE() */
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (hd_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (Size) == (entry_ptr)->size ) && ( ! ( (len) == 1 ) ) ) || \
+ ( ( (entry_ptr)->aux_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->aux_next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->aux_next == NULL ) && \
+ ( (entry_ptr)->aux_prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "aux DLL pre remove SC failed") \
+}
+
+#define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( (Size) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->aux_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL sanity check failed") \
+}
+
+#define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->aux_next != NULL ) || \
+ ( (entry_ptr)->aux_prev != NULL ) || \
+ ( ( ( (hd_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (hd_ptr) != (tail_ptr) ) \
+ ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (hd_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (hd_ptr) == NULL ) || ( (hd_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (hd_ptr) == NULL ) || ( (hd_ptr)->aux_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL pre insert SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+#define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+#define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__AUX_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\
+{ \
+ H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->aux_next = (entry_ptr); \
+ (entry_ptr)->aux_prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+} /* H5C__AUX_DLL_APPEND() */
+
+#define H5C__AUX_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+{ \
+ H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (head_ptr)->aux_prev = (entry_ptr); \
+ (entry_ptr)->aux_next = (head_ptr); \
+ (head_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+} /* H5C__AUX_DLL_PREPEND() */
+
+#define H5C__AUX_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+{ \
+ H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->aux_next; \
+ if ( (head_ptr) != NULL ) \
+ (head_ptr)->aux_prev = NULL; \
+ } \
+ else \
+ (entry_ptr)->aux_prev->aux_next = (entry_ptr)->aux_next; \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->aux_prev; \
+ if ( (tail_ptr) != NULL ) \
+ (tail_ptr)->aux_next = NULL; \
+ } \
+ else \
+ (entry_ptr)->aux_next->aux_prev = (entry_ptr)->aux_prev; \
+ entry_ptr->aux_next = NULL; \
+ entry_ptr->aux_prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ } \
+} /* H5C__AUX_DLL_REMOVE() */
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__IL_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (hd_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (Size) == (entry_ptr)->size ) && ( ! ( (len) == 1 ) ) ) || \
+ ( ( (entry_ptr)->il_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->il_next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->il_next == NULL ) && \
+ ( (entry_ptr)->il_prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "il DLL pre remove SC failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "il DLL pre remove SC failed") \
+}
+
+#define H5C__IL_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->il_next != NULL ) || \
+ ( (entry_ptr)->il_prev != NULL ) || \
+ ( ( ( (hd_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (hd_ptr) != (tail_ptr) ) \
+ ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (hd_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (hd_ptr) == NULL ) || ( (hd_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (hd_ptr) == NULL ) || ( (hd_ptr)->il_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->il_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "IL DLL pre insert SC failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "IL DLL pre insert SC failed") \
+}
+
+#define H5C__IL_DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->il_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->il_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "IL DLL sanity check failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "IL DLL sanity check failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__IL_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+#define H5C__IL_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+#define H5C__IL_DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__IL_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\
+{ \
+ H5C__IL_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->il_next = (entry_ptr); \
+ (entry_ptr)->il_prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+ H5C__IL_DLL_SC(head_ptr, tail_ptr, len, Size, fail_val) \
+} /* H5C__IL_DLL_APPEND() */
+
+#define H5C__IL_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+{ \
+ H5C__IL_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->il_next; \
+ if ( (head_ptr) != NULL ) \
+ (head_ptr)->il_prev = NULL; \
+ } \
+ else \
+ (entry_ptr)->il_prev->il_next = (entry_ptr)->il_next; \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->il_prev; \
+ if ( (tail_ptr) != NULL ) \
+ (tail_ptr)->il_next = NULL; \
+ } \
+ else \
+ (entry_ptr)->il_next->il_prev = (entry_ptr)->il_prev; \
+ entry_ptr->il_next = NULL; \
+ entry_ptr->il_prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ } \
+ H5C__IL_DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+} /* H5C__IL_DLL_REMOVE() */
+
+
+/***********************************************************************
+ *
+ * Stats collection macros
+ *
+ * The following macros must handle stats collection when this collection
+ * is enabled, and evaluate to the empty string when it is not.
+ *
+ * The sole exception to this rule is
+ * H5C__UPDATE_CACHE_HIT_RATE_STATS(), which is always active as
+ * the cache hit rate stats are always collected and available.
+ *
+ ***********************************************************************/
+
+#define H5C__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit) \
+ (cache_ptr->cache_accesses)++; \
+ if ( hit ) { \
+ (cache_ptr->cache_hits)++; \
+ } \
+
+#if H5C_COLLECT_CACHE_STATS
+
+#define H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \
+ (cache_ptr)->max_index_size = (cache_ptr)->index_size; \
+ if ( (cache_ptr)->clean_index_size > \
+ (cache_ptr)->max_clean_index_size ) \
+ (cache_ptr)->max_clean_index_size = \
+ (cache_ptr)->clean_index_size; \
+ if ( (cache_ptr)->dirty_index_size > \
+ (cache_ptr)->max_dirty_index_size ) \
+ (cache_ptr)->max_dirty_index_size = \
+ (cache_ptr)->dirty_index_size;
+
+#define H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) \
+ (((cache_ptr)->dirty_pins)[(entry_ptr)->type->id])++;
+
+#define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) \
+ if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len ) \
+ (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \
+ if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
+ (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \
+ if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \
+ (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \
+ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
+ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;
+
+#define H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr) \
+ if ( cache_ptr->flush_in_progress ) \
+ ((cache_ptr)->cache_flush_moves[(entry_ptr)->type->id])++; \
+ if ( entry_ptr->flush_in_progress ) \
+ ((cache_ptr)->entry_flush_moves[(entry_ptr)->type->id])++; \
+ (((cache_ptr)->moves)[(entry_ptr)->type->id])++; \
+ (cache_ptr)->entries_relocated_counter++;
+
+#define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\
+ if ( cache_ptr->flush_in_progress ) \
+ ((cache_ptr)->cache_flush_size_changes[(entry_ptr)->type->id])++; \
+ if ( entry_ptr->flush_in_progress ) \
+ ((cache_ptr)->entry_flush_size_changes[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->size < (new_size) ) { \
+ ((cache_ptr)->size_increases[(entry_ptr)->type->id])++; \
+ H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
+ (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \
+ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \
+ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \
+ } else if ( (entry_ptr)->size > (new_size) ) { \
+ ((cache_ptr)->size_decreases[(entry_ptr)->type->id])++; \
+ }
+
+#define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \
+ (cache_ptr)->total_ht_insertions++;
+
+#define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \
+ (cache_ptr)->total_ht_deletions++;
+
+#define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth) \
+ if ( success ) { \
+ (cache_ptr)->successful_ht_searches++; \
+ (cache_ptr)->total_successful_ht_search_depth += depth; \
+ } else { \
+ (cache_ptr)->failed_ht_searches++; \
+ (cache_ptr)->total_failed_ht_search_depth += depth; \
+ }
+
+#define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) \
+ ((cache_ptr)->unpins)[(entry_ptr)->type->id]++;
+
+#define H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) \
+ ((cache_ptr)->slist_scan_restarts)++;
+
+#define H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) \
+ ((cache_ptr)->LRU_scan_restarts)++;
+
+#define H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr) \
+ ((cache_ptr)->index_scan_restarts)++;
+
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_CREATE(cache_ptr) \
+{ \
+ (cache_ptr)->images_created++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_READ(cache_ptr) \
+{ \
+ /* make sure image len is still good */ \
+ HDassert((cache_ptr)->image_len > 0); \
+ (cache_ptr)->images_read++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_LOAD(cache_ptr) \
+{ \
+ /* make sure image len is still good */ \
+ HDassert((cache_ptr)->image_len > 0); \
+ (cache_ptr)->images_loaded++; \
+ (cache_ptr)->last_image_size = (cache_ptr)->image_len; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PREFETCH(cache_ptr, dirty) \
+{ \
+ (cache_ptr)->prefetches++; \
+ if ( dirty ) \
+ (cache_ptr)->dirty_prefetches++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PREFETCH_HIT(cache_ptr) \
+{ \
+ (cache_ptr)->prefetch_hits++; \
+}
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr) \
+{ \
+ (entry_ptr)->accesses = 0; \
+ (entry_ptr)->clears = 0; \
+ (entry_ptr)->flushes = 0; \
+ (entry_ptr)->pins = 0; \
+}
+
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->clears)[(entry_ptr)->type->id])++; \
+ if((entry_ptr)->is_pinned) \
+ (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \
+ ((entry_ptr)->clears)++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \
+ if((entry_ptr)->is_pinned) \
+ (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \
+ ((entry_ptr)->flushes)++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership) \
+{ \
+ if ( take_ownership ) \
+ (((cache_ptr)->take_ownerships)[(entry_ptr)->type->id])++; \
+ else \
+ (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->accesses > \
+ ((cache_ptr)->max_accesses)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_accesses)[(entry_ptr)->type->id] = \
+ (entry_ptr)->accesses; \
+ if ( (entry_ptr)->accesses < \
+ ((cache_ptr)->min_accesses)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->min_accesses)[(entry_ptr)->type->id] = \
+ (entry_ptr)->accesses; \
+ if ( (entry_ptr)->clears > \
+ ((cache_ptr)->max_clears)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_clears)[(entry_ptr)->type->id] \
+ = (entry_ptr)->clears; \
+ if ( (entry_ptr)->flushes > \
+ ((cache_ptr)->max_flushes)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_flushes)[(entry_ptr)->type->id] \
+ = (entry_ptr)->flushes; \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] \
+ = (entry_ptr)->size; \
+ if ( (entry_ptr)->pins > \
+ ((cache_ptr)->max_pins)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_pins)[(entry_ptr)->type->id] \
+ = (entry_ptr)->pins; \
+}
+
+#define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->is_pinned ) { \
+ (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \
+ ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \
+ (entry_ptr)->pins++; \
+ if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \
+ (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \
+ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
+ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \
+ } \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len ) \
+ (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \
+ if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
+ (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] \
+ = (entry_ptr)->size; \
+ cache_ptr->entries_inserted_counter++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
+{ \
+ if ( hit ) \
+ ((cache_ptr)->hits)[(entry_ptr)->type->id]++; \
+ else \
+ ((cache_ptr)->misses)[(entry_ptr)->type->id]++; \
+ if ( ! ((entry_ptr)->is_read_only) ) { \
+ ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \
+ } else { \
+ ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \
+ if ( ((entry_ptr)->ro_ref_count) > \
+ ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \
+ ((entry_ptr)->ro_ref_count); \
+ } \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len ) \
+ (cache_ptr)->max_pl_len = (cache_ptr)->pl_len; \
+ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \
+ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] = (entry_ptr)->size; \
+ ((entry_ptr)->accesses)++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \
+{ \
+ ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \
+ (entry_ptr)->pins++; \
+ if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \
+ (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \
+ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
+ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \
+}
+
+#else /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->clears)[(entry_ptr)->type->id])++; \
+ if((entry_ptr)->is_pinned) \
+ (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->is_pinned ) \
+ (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership) \
+{ \
+ if ( take_ownership ) \
+ (((cache_ptr)->take_ownerships)[(entry_ptr)->type->id])++; \
+ else \
+ (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \
+{ \
+ (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->is_pinned ) { \
+ (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \
+ ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \
+ if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \
+ (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \
+ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
+ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \
+ } \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len ) \
+ (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \
+ if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
+ (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \
+ cache_ptr->entries_inserted_counter++; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
+{ \
+ if ( hit ) \
+ ((cache_ptr)->hits)[(entry_ptr)->type->id]++; \
+ else \
+ ((cache_ptr)->misses)[(entry_ptr)->type->id]++; \
+ if ( ! ((entry_ptr)->is_read_only) ) \
+ ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \
+ else { \
+ ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \
+ if ( ((entry_ptr)->ro_ref_count) > \
+ ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) \
+ ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \
+ ((entry_ptr)->ro_ref_count); \
+ } \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr) \
+ if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len ) \
+ (cache_ptr)->max_pl_len = (cache_ptr)->pl_len; \
+ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \
+ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \
+}
+
+#define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \
+{ \
+ ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \
+ if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \
+ (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \
+ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
+ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \
+}
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#else /* H5C_COLLECT_CACHE_STATS */
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+#define H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)
+#define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth)
+#define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership)
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)
+#define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_CREATE(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_READ(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_CACHE_IMAGE_LOAD(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_PREFETCH(cache_ptr, dirty)
+#define H5C__UPDATE_STATS_FOR_PREFETCH_HIT(cache_ptr)
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+
+/***********************************************************************
+ *
+ * Hash table access and manipulation macros:
+ *
+ * The following macros handle searches, insertions, and deletion in
+ * the hash table.
+ *
+ * When modifying these macros, remember to modify the similar macros
+ * in tst/cache.c
+ *
+ * Changes:
+ *
+ * - Updated existing index macros and sanity check macros to maintain
+ * the clean_index_size and dirty_index_size fields of H5C_t. Also
+ * added macros to allow us to track entry cleans and dirties.
+ *
+ * JRM -- 11/5/08
+ *
+ * - Updated existing index macros and sanity check macros to maintain
+ * the index_ring_len, index_ring_size, clean_index_ring_size, and
+ * dirty_index_ring_size fields of H5C_t.
+ *
+ * JRM -- 9/1/15
+ *
+ * - Updated existing index macros and sanity checks macros to
+ * maintain an doubly linked list of all entries in the index.
+ * This is necessary to reduce the computational cost of visiting
+ * all entries in the index, which used to be done by scanning
+ * the hash table.
+ *
+ * JRM -- 10/15/15
+ *
+ ***********************************************************************/
+
+/* H5C__HASH_TABLE_LEN is defined in H5Cpkg.h. It mut be a power of two. */
+
+#define H5C__HASH_MASK ((size_t)(H5C__HASH_TABLE_LEN - 1) << 3)
+
+#define H5C__HASH_FCN(x) (int)((unsigned)((x) & H5C__HASH_MASK) >> 3)
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( ! H5F_addr_defined((entry_ptr)->addr) ) || \
+ ( (entry_ptr)->ht_next != NULL ) || \
+ ( (entry_ptr)->ht_prev != NULL ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) < 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) >= H5C__HASH_TABLE_LEN ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (entry_ptr)->ring <= H5C_RING_UNDEFINED ) || \
+ ( (entry_ptr)->ring >= H5C_RING_NTYPES ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "pre HT insert SC failed") \
+}
+
+#define H5C__POST_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] == 0 ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "post HT insert SC failed") \
+}
+
+#define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len < 1 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( ! H5F_addr_defined((entry_ptr)->addr) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) < 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) >= H5C__HASH_TABLE_LEN ) || \
+ ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] \
+ == NULL ) || \
+ ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] \
+ != (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev == NULL ) ) || \
+ ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] == \
+ (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev != NULL ) ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (entry_ptr)->ring <= H5C_RING_UNDEFINED ) || \
+ ( (entry_ptr)->ring >= H5C_RING_NTYPES ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] <= 0 ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] < \
+ (entry_ptr)->size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "pre HT remove SC failed") \
+}
+
+#define H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( ! H5F_addr_defined((entry_ptr)->addr) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( (entry_ptr)->ht_prev != NULL ) || \
+ ( (entry_ptr)->ht_prev != NULL ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "post HT remove SC failed") \
+}
+
+/* (Keep in sync w/H5C_TEST__PRE_HT_SEARCH_SC macro in test/cache_common.h -QAK) */
+#define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( ! H5F_addr_defined(Addr) ) || \
+ ( H5C__HASH_FCN(Addr) < 0 ) || \
+ ( H5C__HASH_FCN(Addr) >= H5C__HASH_TABLE_LEN ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "pre HT search SC failed") \
+}
+
+/* (Keep in sync w/H5C_TEST__POST_SUC_HT_SEARCH_SC macro in test/cache_common.h -QAK) */
+#define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, k, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len < 1 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( ((cache_ptr)->index)[k] == NULL ) || \
+ ( ( ((cache_ptr)->index)[k] != (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev == NULL ) ) || \
+ ( ( ((cache_ptr)->index)[k] == (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev != NULL ) ) || \
+ ( ( (entry_ptr)->ht_prev != NULL ) && \
+ ( (entry_ptr)->ht_prev->ht_next != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->ht_next != NULL ) && \
+ ( (entry_ptr)->ht_next->ht_prev != (entry_ptr) ) ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "post successful HT search SC failed") \
+}
+
+/* (Keep in sync w/H5C_TEST__POST_HT_SHIFT_TO_FRONT macro in test/cache_common.h -QAK) */
+#define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( ((cache_ptr)->index)[k] != (entry_ptr) ) || \
+ ( (entry_ptr)->ht_prev != NULL ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "post HT shift to front SC failed") \
+}
+
+#define H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr, was_clean) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->index_len <= 0 ) || \
+ ( (cache_ptr)->index_size <= 0 ) || \
+ ( (new_size) <= 0 ) || \
+ ( (old_size) > (cache_ptr)->index_size ) || \
+ ( ( (cache_ptr)->index_len == 1 ) && \
+ ( (cache_ptr)->index_size != (old_size) ) ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( ( !( was_clean ) || \
+ ( (cache_ptr)->clean_index_size < (old_size) ) ) && \
+ ( ( (was_clean) ) || \
+ ( (cache_ptr)->dirty_index_size < (old_size) ) ) ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->ring <= H5C_RING_UNDEFINED ) || \
+ ( (entry_ptr)->ring >= H5C_RING_NTYPES ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] <= 0 ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "pre HT entry size change SC failed") \
+}
+
+#define H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->index_len <= 0 ) || \
+ ( (cache_ptr)->index_size <= 0 ) || \
+ ( (new_size) > (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + \
+ (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( ( !((entry_ptr)->is_dirty ) || \
+ ( (cache_ptr)->dirty_index_size < (new_size) ) ) && \
+ ( ( ((entry_ptr)->is_dirty) ) || \
+ ( (cache_ptr)->clean_index_size < (new_size) ) ) ) || \
+ ( ( (cache_ptr)->index_len == 1 ) && \
+ ( (cache_ptr)->index_size != (new_size) ) ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) || \
+ ( (cache_ptr)->index_len != (cache_ptr)->il_len ) || \
+ ( (cache_ptr)->index_size != (cache_ptr)->il_size ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "post HT entry size change SC failed") \
+}
+
+#define H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr) \
+if ( \
+ ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len <= 0 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->is_dirty != FALSE ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( (cache_ptr)->dirty_index_size < (entry_ptr)->size ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (entry_ptr)->ring <= H5C_RING_UNDEFINED ) || \
+ ( (entry_ptr)->ring >= H5C_RING_NTYPES ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] <= 0 ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "pre HT update for entry clean SC failed") \
+}
+
+#define H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr) \
+if ( \
+ ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len <= 0 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->is_dirty != TRUE ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( (cache_ptr)->clean_index_size < (entry_ptr)->size ) || \
+ ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (entry_ptr)->ring <= H5C_RING_UNDEFINED ) || \
+ ( (entry_ptr)->ring >= H5C_RING_NTYPES ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] <= 0 ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "pre HT update for entry dirty SC failed") \
+}
+
+#define H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr) \
+if ( ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "post HT update for entry clean SC failed") \
+}
+
+#define H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr) \
+if ( ( (cache_ptr)->index_size != \
+ ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \
+ ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \
+ ( (cache_ptr)->index_ring_len[(entry_ptr)->ring] > \
+ (cache_ptr)->index_len ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] > \
+ (cache_ptr)->index_size ) || \
+ ( (cache_ptr)->index_ring_size[(entry_ptr)->ring] != \
+ ((cache_ptr)->clean_index_ring_size[(entry_ptr)->ring] + \
+ (cache_ptr)->dirty_index_ring_size[(entry_ptr)->ring]) ) ) { \
+ HDassert(FALSE); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "post HT update for entry dirty SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val)
+#define H5C__POST_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val)
+#define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr)
+#define H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr)
+#define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)
+#define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, k, fail_val)
+#define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val)
+#define H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)
+#define H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)
+#define H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr, was_clean)
+#define H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr)
+#define H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)
+#define H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+ k = H5C__HASH_FCN((entry_ptr)->addr); \
+ if(((cache_ptr)->index)[k] != NULL) { \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr); \
+ } \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ (cache_ptr)->index_len++; \
+ (cache_ptr)->index_size += (entry_ptr)->size; \
+ ((cache_ptr)->index_ring_len[entry_ptr->ring])++; \
+ ((cache_ptr)->index_ring_size[entry_ptr->ring]) \
+ += (entry_ptr)->size; \
+ if((entry_ptr)->is_dirty) { \
+ (cache_ptr)->dirty_index_size += (entry_ptr)->size; \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring]) \
+ += (entry_ptr)->size; \
+ } else { \
+ (cache_ptr)->clean_index_size += (entry_ptr)->size; \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring]) \
+ += (entry_ptr)->size; \
+ } \
+ if((entry_ptr)->flush_me_last) { \
+ (cache_ptr)->num_last_entries++; \
+ HDassert((cache_ptr)->num_last_entries <= 2); \
+ } \
+ H5C__IL_DLL_APPEND((entry_ptr), (cache_ptr)->il_head, \
+ (cache_ptr)->il_tail, (cache_ptr)->il_len, \
+ (cache_ptr)->il_size, fail_val) \
+ H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \
+ H5C__POST_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+}
+
+#define H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+ k = H5C__HASH_FCN((entry_ptr)->addr); \
+ if((entry_ptr)->ht_next) \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ if((entry_ptr)->ht_prev) \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ if(((cache_ptr)->index)[k] == (entry_ptr)) \
+ ((cache_ptr)->index)[k] = (entry_ptr)->ht_next; \
+ (entry_ptr)->ht_next = NULL; \
+ (entry_ptr)->ht_prev = NULL; \
+ (cache_ptr)->index_len--; \
+ (cache_ptr)->index_size -= (entry_ptr)->size; \
+ ((cache_ptr)->index_ring_len[entry_ptr->ring])--; \
+ ((cache_ptr)->index_ring_size[entry_ptr->ring]) \
+ -= (entry_ptr)->size; \
+ if((entry_ptr)->is_dirty) { \
+ (cache_ptr)->dirty_index_size -= (entry_ptr)->size; \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring]) \
+ -= (entry_ptr)->size; \
+ } else { \
+ (cache_ptr)->clean_index_size -= (entry_ptr)->size; \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring]) \
+ -= (entry_ptr)->size; \
+ } \
+ if((entry_ptr)->flush_me_last) { \
+ (cache_ptr)->num_last_entries--; \
+ HDassert((cache_ptr)->num_last_entries <= 1); \
+ } \
+ H5C__IL_DLL_REMOVE((entry_ptr), (cache_ptr)->il_head, \
+ (cache_ptr)->il_tail, (cache_ptr)->il_len, \
+ (cache_ptr)->il_size, fail_val) \
+ H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \
+ H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+}
+
+#define H5C__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ int depth = 0; \
+ H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \
+ k = H5C__HASH_FCN(Addr); \
+ entry_ptr = ((cache_ptr)->index)[k]; \
+ while(entry_ptr) { \
+ if(H5F_addr_eq(Addr, (entry_ptr)->addr)) { \
+ H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, k, fail_val) \
+ if(entry_ptr != ((cache_ptr)->index)[k]) { \
+ if((entry_ptr)->ht_next) \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ HDassert((entry_ptr)->ht_prev != NULL); \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ ((cache_ptr)->index)[k]->ht_prev = (entry_ptr); \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_prev = NULL; \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
+ } \
+ break; \
+ } \
+ (entry_ptr) = (entry_ptr)->ht_next; \
+ (depth)++; \
+ } \
+ H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, (entry_ptr != NULL), depth) \
+}
+
+#define H5C__SEARCH_INDEX_NO_STATS(cache_ptr, Addr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \
+ k = H5C__HASH_FCN(Addr); \
+ entry_ptr = ((cache_ptr)->index)[k]; \
+ while(entry_ptr) { \
+ if(H5F_addr_eq(Addr, (entry_ptr)->addr)) { \
+ H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, k, fail_val) \
+ if(entry_ptr != ((cache_ptr)->index)[k]) { \
+ if((entry_ptr)->ht_next) \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ HDassert((entry_ptr)->ht_prev != NULL); \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ ((cache_ptr)->index)[k]->ht_prev = (entry_ptr); \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_prev = NULL; \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
+ } \
+ break; \
+ } \
+ (entry_ptr) = (entry_ptr)->ht_next; \
+ } \
+}
+
+#define H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr) \
+{ \
+ H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr); \
+ (cache_ptr)->dirty_index_size -= (entry_ptr)->size; \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring]) \
+ -= (entry_ptr)->size; \
+ (cache_ptr)->clean_index_size += (entry_ptr)->size; \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring]) \
+ += (entry_ptr)->size; \
+ H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr); \
+}
+
+#define H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr) \
+{ \
+ H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr); \
+ (cache_ptr)->clean_index_size -= (entry_ptr)->size; \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring]) \
+ -= (entry_ptr)->size; \
+ (cache_ptr)->dirty_index_size += (entry_ptr)->size; \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring]) \
+ += (entry_ptr)->size; \
+ H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr); \
+}
+
+#define H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size, \
+ entry_ptr, was_clean) \
+{ \
+ H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr, was_clean) \
+ (cache_ptr)->index_size -= (old_size); \
+ (cache_ptr)->index_size += (new_size); \
+ ((cache_ptr)->index_ring_size[entry_ptr->ring]) -= (old_size); \
+ ((cache_ptr)->index_ring_size[entry_ptr->ring]) += (new_size); \
+ if(was_clean) { \
+ (cache_ptr)->clean_index_size -= (old_size); \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring])-= (old_size); \
+ } else { \
+ (cache_ptr)->dirty_index_size -= (old_size); \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring])-= (old_size); \
+ } \
+ if((entry_ptr)->is_dirty) { \
+ (cache_ptr)->dirty_index_size += (new_size); \
+ ((cache_ptr)->dirty_index_ring_size[entry_ptr->ring])+= (new_size); \
+ } else { \
+ (cache_ptr)->clean_index_size += (new_size); \
+ ((cache_ptr)->clean_index_ring_size[entry_ptr->ring])+= (new_size); \
+ } \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->il_len, \
+ (cache_ptr)->il_size, \
+ (old_size), (new_size)) \
+ H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
+ entry_ptr) \
+}
+
+
+/**************************************************************************
+ *
+ * Skip list insertion and deletion macros:
+ *
+ * These used to be functions, but I converted them to macros to avoid some
+ * function call overhead.
+ *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__INSERT_ENTRY_IN_SLIST
+ *
+ * Purpose: Insert the specified instance of H5C_cache_entry_t into
+ * the skip list in the specified instance of H5C_t. Update
+ * the associated length and size fields.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function to set the in_tree flag when inserting
+ * an entry into the tree. Also modified the function to
+ * update the tree size and len fields instead of the similar
+ * index fields.
+ *
+ * All of this is part of the modifications to support the
+ * hash table.
+ *
+ * JRM -- 7/27/04
+ * Converted the function H5C_insert_entry_in_tree() into
+ * the macro H5C__INSERT_ENTRY_IN_TREE in the hopes of
+ * wringing a little more speed out of the cache.
+ *
+ * Note that we don't bother to check if the entry is already
+ * in the tree -- if it is, H5SL_insert() will fail.
+ *
+ * QAK -- 11/27/04
+ * Switched over to using skip list routines.
+ *
+ * JRM -- 6/27/06
+ * Added fail_val parameter.
+ *
+ * JRM -- 8/25/06
+ * Added the H5C_DO_SANITY_CHECKS version of the macro.
+ *
+ * This version maintains the slist_len_increase and
+ * slist_size_increase fields that are used in sanity
+ * checks in the flush routines.
+ *
+ * All this is needed as the fractal heap needs to be
+ * able to dirty, resize and/or move entries during the
+ * flush.
+ *
+ * JRM -- 12/13/14
+ * Added code to set cache_ptr->slist_changed to TRUE
+ * when an entry is inserted in the slist.
+ *
+ * JRM -- 9/1/15
+ * Added code to maintain the cache_ptr->slist_ring_len
+ * and cache_ptr->slist_ring_size arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_DO_SLIST_SANITY_CHECKS
+#define ENTRY_IN_SLIST(cache_ptr, entry_ptr) \
+ H5C_entry_in_skip_list((cache_ptr), (entry_ptr))
+#else /* H5C_DO_SLIST_SANITY_CHECKS */
+#define ENTRY_IN_SLIST(cache_ptr, entry_ptr) FALSE
+#endif /* H5C_DO_SLIST_SANITY_CHECKS */
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( H5F_addr_defined((entry_ptr)->addr) ); \
+ HDassert( !((entry_ptr)->in_slist) ); \
+ HDassert( !ENTRY_IN_SLIST((cache_ptr), (entry_ptr)) ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ if(H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) < 0) \
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), "can't insert entry in skip list") \
+ \
+ (entry_ptr)->in_slist = TRUE; \
+ (cache_ptr)->slist_changed = TRUE; \
+ (cache_ptr)->slist_len++; \
+ (cache_ptr)->slist_size += (entry_ptr)->size; \
+ ((cache_ptr)->slist_ring_len[(entry_ptr)->ring])++; \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) += (entry_ptr)->size; \
+ (cache_ptr)->slist_len_increase++; \
+ (cache_ptr)->slist_size_increase += (int64_t)((entry_ptr)->size); \
+ \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ HDassert( (cache_ptr)->slist_size > 0 ); \
+ \
+} /* H5C__INSERT_ENTRY_IN_SLIST */
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( H5F_addr_defined((entry_ptr)->addr) ); \
+ HDassert( !((entry_ptr)->in_slist) ); \
+ HDassert( !ENTRY_IN_SLIST((cache_ptr), (entry_ptr)) ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ if(H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) < 0) \
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), "can't insert entry in skip list") \
+ \
+ (entry_ptr)->in_slist = TRUE; \
+ (cache_ptr)->slist_changed = TRUE; \
+ (cache_ptr)->slist_len++; \
+ (cache_ptr)->slist_size += (entry_ptr)->size; \
+ ((cache_ptr)->slist_ring_len[(entry_ptr)->ring])++; \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) += (entry_ptr)->size; \
+ \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ HDassert( (cache_ptr)->slist_size > 0 ); \
+ \
+} /* H5C__INSERT_ENTRY_IN_SLIST */
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__REMOVE_ENTRY_FROM_SLIST
+ *
+ * Purpose: Remove the specified instance of H5C_cache_entry_t from the
+ * index skip list in the specified instance of H5C_t. Update
+ * the associated length and size fields.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_DO_SANITY_CHECKS
+#define H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( (entry_ptr)->in_slist ); \
+ HDassert( (cache_ptr)->slist_ptr ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr) \
+ != (entry_ptr) ) \
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "can't delete entry from skip list") \
+ \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ if(!(during_flush)) \
+ (cache_ptr)->slist_changed = TRUE; \
+ (cache_ptr)->slist_len--; \
+ HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size ); \
+ (cache_ptr)->slist_size -= (entry_ptr)->size; \
+ ((cache_ptr)->slist_ring_len[(entry_ptr)->ring])--; \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr->ring)] >= \
+ (entry_ptr)->size ); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) -= (entry_ptr)->size; \
+ (cache_ptr)->slist_len_increase--; \
+ (cache_ptr)->slist_size_increase -= (int64_t)((entry_ptr)->size); \
+ (entry_ptr)->in_slist = FALSE; \
+} /* H5C__REMOVE_ENTRY_FROM_SLIST */
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->in_slist ); \
+ HDassert( (cache_ptr)->slist_ptr ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr) \
+ != (entry_ptr) ) \
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "can't delete entry from skip list") \
+ \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ if(!(during_flush)) \
+ (cache_ptr)->slist_changed = TRUE; \
+ (cache_ptr)->slist_len--; \
+ HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size ); \
+ (cache_ptr)->slist_size -= (entry_ptr)->size; \
+ ((cache_ptr)->slist_ring_len[(entry_ptr)->ring])--; \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr->ring)] >= \
+ (entry_ptr)->size ); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) -= (entry_ptr)->size; \
+ (entry_ptr)->in_slist = FALSE; \
+} /* H5C__REMOVE_ENTRY_FROM_SLIST */
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__UPDATE_SLIST_FOR_SIZE_CHANGE
+ *
+ * Purpose: Update cache_ptr->slist_size for a change in the size of
+ * and entry in the slist.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 9/07/05
+ *
+ * Modifications:
+ *
+ * JRM -- 8/27/06
+ * Added the H5C_DO_SANITY_CHECKS version of the macro.
+ *
+ * This version maintains the slist_size_increase field
+ * that are used in sanity checks in the flush routines.
+ *
+ * All this is needed as the fractal heap needs to be
+ * able to dirty, resize and/or move entries during the
+ * flush.
+ *
+ * JRM -- 12/13/14
+ * Note that we do not set cache_ptr->slist_changed to TRUE
+ * in this case, as the structure of the slist is not
+ * modified.
+ *
+ * JRM -- 9/1/15
+ * Added code to maintain the cache_ptr->slist_ring_len
+ * and cache_ptr->slist_ring_size arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (old_size) > 0 ); \
+ HDassert( (new_size) > 0 ); \
+ HDassert( (old_size) <= (cache_ptr)->slist_size ); \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ HDassert( ((cache_ptr)->slist_len > 1) || \
+ ( (cache_ptr)->slist_size == (old_size) ) ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ (cache_ptr)->slist_size -= (old_size); \
+ (cache_ptr)->slist_size += (new_size); \
+ \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr->ring)] >=(old_size) ); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) -= (old_size); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) += (new_size); \
+ \
+ (cache_ptr)->slist_size_increase -= (int64_t)(old_size); \
+ (cache_ptr)->slist_size_increase += (int64_t)(new_size); \
+ \
+ HDassert( (new_size) <= (cache_ptr)->slist_size ); \
+ HDassert( ( (cache_ptr)->slist_len > 1 ) || \
+ ( (cache_ptr)->slist_size == (new_size) ) ); \
+} /* H5C__UPDATE_SLIST_FOR_SIZE_CHANGE */
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (old_size) > 0 ); \
+ HDassert( (new_size) > 0 ); \
+ HDassert( (old_size) <= (cache_ptr)->slist_size ); \
+ HDassert( (cache_ptr)->slist_len > 0 ); \
+ HDassert( ((cache_ptr)->slist_len > 1) || \
+ ( (cache_ptr)->slist_size == (old_size) ) ); \
+ HDassert( (entry_ptr)->ring > H5C_RING_UNDEFINED ); \
+ HDassert( (entry_ptr)->ring < H5C_RING_NTYPES ); \
+ HDassert( (cache_ptr)->slist_ring_len[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_len ); \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr)->ring] <= \
+ (cache_ptr)->slist_size ); \
+ \
+ (cache_ptr)->slist_size -= (old_size); \
+ (cache_ptr)->slist_size += (new_size); \
+ \
+ HDassert( (cache_ptr)->slist_ring_size[(entry_ptr->ring)] >=(old_size) ); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) -= (old_size); \
+ ((cache_ptr)->slist_ring_size[(entry_ptr)->ring]) += (new_size); \
+ \
+ HDassert( (new_size) <= (cache_ptr)->slist_size ); \
+ HDassert( ( (cache_ptr)->slist_len > 1 ) || \
+ ( (cache_ptr)->slist_size == (new_size) ) ); \
+} /* H5C__UPDATE_SLIST_FOR_SIZE_CHANGE */
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+/**************************************************************************
+ *
+ * Replacement policy update macros:
+ *
+ * These used to be functions, but I converted them to macros to avoid some
+ * function call overhead.
+ *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS
+ *
+ * Purpose: For efficiency, we sometimes change the order of flushes --
+ * but doing so can confuse the replacement policy. This
+ * macro exists to allow us to specify an entry as the
+ * most recently touched so we can repair any such
+ * confusion.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the macro
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 10/13/05
+ *
+ * Modifications:
+ *
+ * JRM -- 3/20/06
+ * Modified macro to ignore pinned entries. Pinned entries
+ * do not appear in the data structures maintained by the
+ * replacement policy code, and thus this macro has nothing
+ * to do if called for such an entry.
+ *
+ * JRM -- 3/28/07
+ * Added sanity checks using the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ((entry_ptr)->is_pinned) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head.\
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Use the dirty flag to infer whether the entry is on the clean or \
+ * dirty LRU list, and remove it. Then insert it at the head of \
+ * the same LRU list. \
+ * \
+ * At least initially, all entries should be clean. That may \
+ * change, so we may as well deal with both cases now. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ((entry_ptr)->is_pinned) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head \
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_EVICTION
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * eviction of the specified cache entry.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_eviction() to the
+ * macro H5C__UPDATE_RP_FOR_EVICTION in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * the pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ * JRM - 3/20/06
+ * Pinned entries can't be evicted, so this entry should never
+ * be called on a pinned entry. Added assert to verify this.
+ *
+ * JRM -- 3/28/07
+ * Added sanity checks for the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( !((entry_ptr)->is_pinned) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* If the entry is clean when it is evicted, it should be on the \
+ * clean LRU list, if it was dirty, it should be on the dirty LRU list. \
+ * Remove it from the appropriate list according to the value of the \
+ * dirty flag. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+} /* H5C__UPDATE_RP_FOR_EVICTION */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( !((entry_ptr)->is_pinned) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+} /* H5C__UPDATE_RP_FOR_EVICTION */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_FLUSH
+ *
+ * Purpose: Update the replacement policy data structures for a flush
+ * of the specified cache entry.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/6/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_flush() to the
+ * macro H5C__UPDATE_RP_FOR_FLUSH in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two versions, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ * JRM - 3/20/06
+ * While pinned entries can be flushed, they don't reside in
+ * the replacement policy data structures when unprotected.
+ * Thus I modified this macro to do nothing if the entry is
+ * pinned.
+ *
+ * JRM - 3/28/07
+ * Added sanity checks based on the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ((entry_ptr)->is_pinned) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the \
+ * head. \
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* since the entry is being flushed or cleared, one would think \
+ * that it must be dirty -- but that need not be the case. Use the \
+ * dirty flag to infer whether the entry is on the clean or dirty \
+ * LRU list, and remove it. Then insert it at the head of the \
+ * clean LRU list. \
+ * \
+ * The function presumes that a dirty entry will be either cleared \
+ * or flushed shortly, so it is OK if we put a dirty entry on the \
+ * clean LRU list. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__UPDATE_RP_FOR_FLUSH */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ((entry_ptr)->is_pinned) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the \
+ * head. \
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__UPDATE_RP_FOR_FLUSH */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_INSERT_APPEND
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * insertion of the specified cache entry.
+ *
+ * Unlike H5C__UPDATE_RP_FOR_INSERTION below, mark the
+ * new entry as the LEAST recently used entry, not the
+ * most recently used.
+ *
+ * For now at least, this macro should only be used in
+ * the reconstruction of the metadata cache from a cache
+ * image block.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 8/15/15
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_INSERT_APPEND(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the tail of the LRU list. */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* insert the entry at the tail of the clean or dirty LRU list as \
+ * appropriate. \
+ */ \
+ \
+ if ( entry_ptr->is_dirty ) { \
+ H5C__AUX_DLL_APPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_APPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+}
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_INSERT_APPEND(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the tail of the LRU list. */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+}
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_INSERTION
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * insertion of the specified cache entry.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/17/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_insertion() to the
+ * macro H5C__UPDATE_RP_FOR_INSERTION in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ * JRM - 3/10/06
+ * This macro should never be called on a pinned entry.
+ * Inserted an assert to verify this.
+ *
+ * JRM - 8/9/06
+ * Not any more. We must now allow insertion of pinned
+ * entries. Updated macro to support this.
+ *
+ * JRM - 3/28/07
+ * Added sanity checks using the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* insert the entry at the head of the clean or dirty LRU list as \
+ * appropriate. \
+ */ \
+ \
+ if ( entry_ptr->is_dirty ) { \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+}
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+}
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_PROTECT
+ *
+ * Purpose: Update the replacement policy data structures for a
+ * protect of the specified cache entry.
+ *
+ * To do this, unlink the specified entry from any data
+ * structures used by the replacement policy, and add the
+ * entry to the protected list.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/17/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_protect() to the
+ * macro H5C__UPDATE_RP_FOR_PROTECT in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ * JRM - 3/17/06
+ * Modified macro to attempt to remove pinned entriese from
+ * the pinned entry list instead of from the data structures
+ * maintained by the replacement policy.
+ *
+ * JRM - 3/28/07
+ * Added sanity checks based on the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Similarly, remove the entry from the clean or dirty LRU list \
+ * as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+ \
+ /* Regardless of the replacement policy, or whether the entry is \
+ * pinned, now add the entry to the protected list. \
+ */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, \
+ (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+} /* H5C__UPDATE_RP_FOR_PROTECT */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+ \
+ /* Regardless of the replacement policy, or whether the entry is \
+ * pinned, now add the entry to the protected list. \
+ */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, \
+ (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+} /* H5C__UPDATE_RP_FOR_PROTECT */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_MOVE
+ *
+ * Purpose: Update the replacement policy data structures for a
+ * move of the specified cache entry.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/17/04
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_MOVE(cache_ptr, entry_ptr, was_dirty, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ( (entry_ptr)->is_pinned ) && ! ( (entry_ptr->is_protected ) ) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. \
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* remove the entry from either the clean or dirty LUR list as \
+ * indicated by the was_dirty parameter \
+ */ \
+ if ( was_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), \
+ (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, \
+ (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), \
+ (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, \
+ (fail_val)) \
+ } \
+ \
+ /* insert the entry at the head of either the clean or dirty \
+ * LRU list as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), \
+ (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, \
+ (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), \
+ (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, \
+ (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__UPDATE_RP_FOR_MOVE */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_MOVE(cache_ptr, entry_ptr, was_dirty, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ if ( ! ( (entry_ptr)->is_pinned ) && ! ( (entry_ptr->is_protected ) ) ) { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. \
+ */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__UPDATE_RP_FOR_MOVE */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_SIZE_CHANGE
+ *
+ * Purpose: Update the replacement policy data structures for a
+ * size change of the specified cache entry.
+ *
+ * To do this, determine if the entry is pinned. If it is,
+ * update the size of the pinned entry list.
+ *
+ * If it isn't pinned, the entry must handled by the
+ * replacement policy. Update the appropriate replacement
+ * policy data structures.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 8/23/06
+ *
+ * Modifications:
+ *
+ * JRM -- 3/28/07
+ * Added sanity checks based on the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( new_size > 0 ); \
+ \
+ if ( (entry_ptr)->coll_access ) { \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->coll_list_len, \
+ (cache_ptr)->coll_list_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ } \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* Update the size of the LRU list */ \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ /* Similarly, update the size of the clean or dirty LRU list as \
+ * appropriate. At present, the entry must be clean, but that \
+ * could change. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ } else { \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+ \
+} /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( new_size > 0 ); \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* Update the size of the LRU list */ \
+ \
+ H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, \
+ (entry_ptr)->size, \
+ (new_size)); \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+ \
+} /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_UNPIN
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * unpin of the specified cache entry.
+ *
+ * To do this, unlink the specified entry from the protected
+ * entry list, and re-insert it in the data structures used
+ * by the current replacement policy.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the macro
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 3/22/06
+ *
+ * Modifications:
+ *
+ * JRM -- 3/28/07
+ * Added sanity checks based on the new is_read_only and
+ * ro_ref_count fields of struct H5C_cache_entry_t.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->is_pinned); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * pinned entry list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Similarly, insert the entry at the head of either the clean \
+ * or dirty LRU list as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), \
+ (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, \
+ (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), \
+ (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, \
+ (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_UNPIN */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( !((entry_ptr)->is_read_only) ); \
+ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \
+ HDassert( (entry_ptr)->is_pinned); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * pinned entry list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_UNPIN */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_UNPROTECT
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * unprotect of the specified cache entry.
+ *
+ * To do this, unlink the specified entry from the protected
+ * list, and re-insert it in the data structures used by the
+ * current replacement policy.
+ *
+ * At present, we only support the modified LRU policy, so
+ * this function deals with that case unconditionally. If
+ * we ever support other replacement policies, the function
+ * should switch on the current policy and act accordingly.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/19/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_unprotect() to
+ * the macro H5C__UPDATE_RP_FOR_UNPROTECT in an effort to
+ * squeeze a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ * JRM - 3/17/06
+ * Modified macro to put pinned entries on the pinned entry
+ * list instead of inserting them in the data structures
+ * maintained by the replacement policy.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->is_protected); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * protected list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Similarly, insert the entry at the head of either the clean or \
+ * dirty LRU list as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+ \
+} /* H5C__UPDATE_RP_FOR_UNPROTECT */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->is_protected); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * protected list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+ \
+ if ( (entry_ptr)->is_pinned ) { \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \
+ (cache_ptr)->pel_tail_ptr, \
+ (cache_ptr)->pel_len, \
+ (cache_ptr)->pel_size, (fail_val)) \
+ \
+ } else { \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ } \
+} /* H5C__UPDATE_RP_FOR_UNPROTECT */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#ifdef H5_HAVE_PARALLEL
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__COLL_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (hd_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (Size) == (entry_ptr)->size ) && ( ! ( (len) == 1 ) ) ) || \
+ ( ( (entry_ptr)->coll_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->coll_next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->coll_next == NULL ) && \
+ ( (entry_ptr)->coll_prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "coll DLL pre remove SC failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "coll DLL pre remove SC failed") \
+}
+
+#define H5C__COLL_DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( (Size) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->coll_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->coll_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "COLL DLL sanity check failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "COLL DLL sanity check failed") \
+}
+
+#define H5C__COLL_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->coll_next != NULL ) || \
+ ( (entry_ptr)->coll_prev != NULL ) || \
+ ( ( ( (hd_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (hd_ptr) != (tail_ptr) ) \
+ ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (hd_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (hd_ptr) == NULL ) || ( (hd_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (hd_ptr) == NULL ) || ( (hd_ptr)->coll_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->coll_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HDassert(0 && "COLL DLL pre insert SC failed"); \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "COLL DLL pre insert SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__COLL_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+#define H5C__COLL_DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+#define H5C__COLL_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__COLL_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+{ \
+ H5C__COLL_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->coll_next = (entry_ptr); \
+ (entry_ptr)->coll_prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+} /* H5C__COLL_DLL_APPEND() */
+
+#define H5C__COLL_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+{ \
+ H5C__COLL_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)\
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (head_ptr)->coll_prev = (entry_ptr); \
+ (entry_ptr)->coll_next = (head_ptr); \
+ (head_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size; \
+} /* H5C__COLL_DLL_PREPEND() */
+
+#define H5C__COLL_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+{ \
+ H5C__COLL_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)\
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->coll_next; \
+ if ( (head_ptr) != NULL ) \
+ (head_ptr)->coll_prev = NULL; \
+ } \
+ else \
+ { \
+ (entry_ptr)->coll_prev->coll_next = (entry_ptr)->coll_next; \
+ } \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->coll_prev; \
+ if ( (tail_ptr) != NULL ) \
+ (tail_ptr)->coll_next = NULL; \
+ } \
+ else \
+ (entry_ptr)->coll_next->coll_prev = (entry_ptr)->coll_prev; \
+ entry_ptr->coll_next = NULL; \
+ entry_ptr->coll_prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ } \
+} /* H5C__COLL_DLL_REMOVE() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__INSERT_IN_COLL_LIST
+ *
+ * Purpose: Insert entry into collective entries list
+ *
+ * Return: N/A
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ \
+ /* insert the entry at the head of the list. */ \
+ \
+ H5C__COLL_DLL_PREPEND((entry_ptr), (cache_ptr)->coll_head_ptr, \
+ (cache_ptr)->coll_tail_ptr, \
+ (cache_ptr)->coll_list_len, \
+ (cache_ptr)->coll_list_size, \
+ (fail_val)) \
+ \
+} /* H5C__INSERT_IN_COLL_LIST */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__REMOVE_FROM_COLL_LIST
+ *
+ * Purpose: Remove entry from collective entries list
+ *
+ * Return: N/A
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ \
+ /* remove the entry from the list. */ \
+ \
+ H5C__COLL_DLL_REMOVE((entry_ptr), (cache_ptr)->coll_head_ptr, \
+ (cache_ptr)->coll_tail_ptr, \
+ (cache_ptr)->coll_list_len, \
+ (cache_ptr)->coll_list_size, \
+ (fail_val)) \
+ \
+} /* H5C__REMOVE_FROM_COLL_LIST */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__MOVE_TO_TOP_IN_COLL_LIST
+ *
+ * Purpose: Update entry position in collective entries list
+ *
+ * Return: N/A
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5C__MOVE_TO_TOP_IN_COLL_LIST(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ \
+ /* Remove entry and insert at the head of the list. */ \
+ H5C__COLL_DLL_REMOVE((entry_ptr), (cache_ptr)->coll_head_ptr, \
+ (cache_ptr)->coll_tail_ptr, \
+ (cache_ptr)->coll_list_len, \
+ (cache_ptr)->coll_list_size, \
+ (fail_val)) \
+ \
+ H5C__COLL_DLL_PREPEND((entry_ptr), (cache_ptr)->coll_head_ptr, \
+ (cache_ptr)->coll_tail_ptr, \
+ (cache_ptr)->coll_list_len, \
+ (cache_ptr)->coll_list_size, \
+ (fail_val)) \
+ \
+} /* H5C__MOVE_TO_TOP_IN_COLL_LIST */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/****************************************************************************
+ *
+ * structure H5C_tag_info_t
+ *
+ * Structure about each set of tagged entries for an object in the file.
+ *
+ * Each H5C_tag_info_t struct corresponds to a particular object in the file.
+ *
+ * Each H5C_cache_entry struct in the linked list of entries for this tag
+ * also contains a pointer back to the H5C_tag_info_t struct for the
+ * overall object.
+ *
+ *
+ * The fields of this structure are discussed individually below:
+ *
+ * tag: Address (i.e. "tag") of the object header for all the entries
+ * corresponding to parts of that object.
+ *
+ * head: Head of doubly-linked list of all entries belonging to the tag.
+ *
+ * entry_cnt: Number of entries on linked list of entries for this tag.
+ *
+ * corked: Boolean flag indicating whether entries for this object can be
+ * evicted.
+ *
+ ****************************************************************************/
+typedef struct H5C_tag_info_t {
+ haddr_t tag; /* Tag (address) of the entries (must be first, for skiplist) */
+ H5C_cache_entry_t *head; /* Head of the list of entries for this tag */
+ size_t entry_cnt; /* Number of entries on list */
+ hbool_t corked; /* Whether this object is corked */
+} H5C_tag_info_t;
+
+
+/****************************************************************************
+ *
+ * structure H5C_t
+ *
+ * Catchall structure for all variables specific to an instance of the cache.
+ *
+ * While the individual fields of the structure are discussed below, the
+ * following overview may be helpful.
+ *
+ * Entries in the cache are stored in an instance of H5TB_TREE, indexed on
+ * the entry's disk address. While the H5TB_TREE is less efficient than
+ * hash table, it keeps the entries in address sorted order. As flushes
+ * in parallel mode are more efficient if they are issued in increasing
+ * address order, this is a significant benefit. Also the H5TB_TREE code
+ * was readily available, which reduced development time.
+ *
+ * While the cache was designed with multiple replacement policies in mind,
+ * at present only a modified form of LRU is supported.
+ *
+ * JRM - 4/26/04
+ *
+ * Profiling has indicated that searches in the instance of H5TB_TREE are
+ * too expensive. To deal with this issue, I have augmented the cache
+ * with a hash table in which all entries will be stored. Given the
+ * advantages of flushing entries in increasing address order, the TBBT
+ * is retained, but only dirty entries are stored in it. At least for
+ * now, we will leave entries in the TBBT after they are flushed.
+ *
+ * Note that index_size and index_len now refer to the total size of
+ * and number of entries in the hash table.
+ *
+ * JRM - 7/19/04
+ *
+ * The TBBT has since been replaced with a skip list. This change
+ * greatly predates this note.
+ *
+ * JRM - 9/26/05
+ *
+ * magic: Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC.
+ * This field is used to validate pointers to instances of
+ * H5C_t.
+ *
+ * flush_in_progress: Boolean flag indicating whether a flush is in
+ * progress.
+ *
+ * trace_file_ptr: File pointer pointing to the trace file, which is used
+ * to record cache operations for use in simulations and design
+ * studies. This field will usually be NULL, indicating that
+ * no trace file should be recorded.
+ *
+ * Since much of the code supporting the parallel metadata
+ * cache is in H5AC, we don't write the trace file from
+ * H5C. Instead, H5AC reads the trace_file_ptr as needed.
+ *
+ * When we get to using H5C in other places, we may add
+ * code to write trace file data at the H5C level as well.
+ *
+ * logging_enabled: Boolean flag indicating whether cache logging
+ * which is used to record cache operations for use in
+ * debugging and performance analysis. When this flag is set
+ * to TRUE, it means that the log file is open and ready to
+ * receive log entries. It does NOT mean that cache operations
+ * are currently being recorded. That is controlled by the
+ * currently_logging flag (below).
+ *
+ * Since much of the code supporting the parallel metadata
+ * cache is in H5AC, we don't write the trace file from
+ * H5C. Instead, H5AC reads the trace_file_ptr as needed.
+ *
+ * When we get to using H5C in other places, we may add
+ * code to write trace file data at the H5C level as well.
+ *
+ * currently_logging: Boolean flag that indicates if cache operations are
+ * currently being logged. This flag is flipped by the
+ * H5Fstart/stop_mdc_logging functions.
+ *
+ * log_file_ptr: File pointer pointing to the log file. The I/O functions
+ * in stdio.h are used to write to the log file regardless of
+ * the VFD selected.
+ *
+ * aux_ptr: Pointer to void used to allow wrapper code to associate
+ * its data with an instance of H5C_t. The H5C cache code
+ * sets this field to NULL, and otherwise leaves it alone.
+ *
+ * max_type_id: Integer field containing the maximum type id number assigned
+ * to a type of entry in the cache. All type ids from 0 to
+ * max_type_id inclusive must be defined. The names of the
+ * types are stored in the type_name_table discussed below, and
+ * indexed by the ids.
+ *
+ * class_table_ptr: Pointer to an array of H5C_class_t of length
+ * max_type_id + 1. Entry classes for the cache.
+ *
+ * max_cache_size: Nominal maximum number of bytes that may be stored in the
+ * cache. This value should be viewed as a soft limit, as the
+ * cache can exceed this value under the following circumstances:
+ *
+ * a) All entries in the cache are protected, and the cache is
+ * asked to insert a new entry. In this case the new entry
+ * will be created. If this causes the cache to exceed
+ * max_cache_size, it will do so. The cache will attempt
+ * to reduce its size as entries are unprotected.
+ *
+ * b) When running in parallel mode, the cache may not be
+ * permitted to flush a dirty entry in response to a read.
+ * If there are no clean entries available to evict, the
+ * cache will exceed its maximum size. Again the cache
+ * will attempt to reduce its size to the max_cache_size
+ * limit on the next cache write.
+ *
+ * c) When an entry increases in size, the cache may exceed
+ * the max_cache_size limit until the next time the cache
+ * attempts to load or insert an entry.
+ *
+ * d) When the evictions_enabled field is false (see below),
+ * the cache size will increase without limit until the
+ * field is set to true.
+ *
+ * min_clean_size: Nominal minimum number of clean bytes in the cache.
+ * The cache attempts to maintain this number of bytes of
+ * clean data so as to avoid case b) above. Again, this is
+ * a soft limit.
+ *
+ * close_warning_received: Boolean flag indicating that a file closing
+ * warning has been received.
+ *
+ *
+ * In addition to the call back functions required for each entry, the
+ * cache requires the following call back functions for this instance of
+ * the cache as a whole:
+ *
+ * check_write_permitted: In certain applications, the cache may not
+ * be allowed to write to disk at certain time. If specified,
+ * the check_write_permitted function is used to determine if
+ * a write is permissible at any given point in time.
+ *
+ * If no such function is specified (i.e. this field is NULL),
+ * the cache uses the following write_permitted field to
+ * determine whether writes are permitted.
+ *
+ * write_permitted: If check_write_permitted is NULL, this boolean flag
+ * indicates whether writes are permitted.
+ *
+ * log_flush: If provided, this function is called whenever a dirty
+ * entry is flushed to disk.
+ *
+ *
+ * In cases where memory is plentiful, and performance is an issue, it may
+ * be useful to disable all cache evictions, and thereby postpone metadata
+ * writes. The following field is used to implement this.
+ *
+ * evictions_enabled: Boolean flag that is initialized to TRUE. When
+ * this flag is set to FALSE, the metadata cache will not
+ * attempt to evict entries to make space for newly protected
+ * entries, and instead the will grow without limit.
+ *
+ * Needless to say, this feature must be used with care.
+ *
+ *
+ * The cache requires an index to facilitate searching for entries. The
+ * following fields support that index.
+ *
+ * Addendum: JRM -- 10/14/15
+ *
+ * We sometimes need to visit all entries in the cache. In the past, this
+ * was done by scanning the hash table. However, this is expensive, and
+ * we have come to scan the hash table often enough that it has become a
+ * performance issue. To repair this, I have added code to maintain a
+ * list of all entries in the index -- call this list the index list.
+ *
+ * The index list is maintained by the same macros that maintain the
+ * index, and must have the same length and size as the index proper.
+ *
+ * index_len: Number of entries currently in the hash table used to index
+ * the cache.
+ *
+ * index_size: Number of bytes of cache entries currently stored in the
+ * hash table used to index the cache.
+ *
+ * This value should not be mistaken for footprint of the
+ * cache in memory. The average cache entry is small, and
+ * the cache has a considerable overhead. Multiplying the
+ * index_size by three should yield a conservative estimate
+ * of the cache's memory footprint.
+ *
+ * index_ring_len: Array of integer of length H5C_RING_NTYPES used to
+ * maintain a count of entries in the index by ring. Note
+ * that the sum of all the cells in this array must equal
+ * the value stored in index_len above.
+ *
+ * index_ring_size: Array of size_t of length H5C_RING_NTYPES used to
+ * maintain the sum of the sizes of all entries in the index
+ * by ring. Note that the sum of all cells in this array must
+ * equal the value stored in index_size above.
+ *
+ * clean_index_size: Number of bytes of clean entries currently stored in
+ * the hash table. Note that the index_size field (above)
+ * is also the sum of the sizes of all entries in the cache.
+ * Thus we should have the invariant that clean_index_size +
+ * dirty_index_size == index_size.
+ *
+ * WARNING:
+ *
+ * The value of the clean_index_size must not be mistaken
+ * for the current clean size of the cache. Rather, the
+ * clean size of the cache is the current value of
+ * clean_index_size plus the amount of empty space (if any)
+ * in the cache.
+ *
+ * clean_index_ring_size: Array of size_t of length H5C_RING_NTYPES used to
+ * maintain the sum of the sizes of all clean entries in the
+ * index by ring. Note that the sum of all cells in this array
+ * must equal the value stored in clean_index_size above.
+ *
+ * dirty_index_size: Number of bytes of dirty entries currently stored in
+ * the hash table. Note that the index_size field (above)
+ * is also the sum of the sizes of all entries in the cache.
+ * Thus we should have the invariant that clean_index_size +
+ * dirty_index_size == index_size.
+ *
+ * dirty_index_ring_size: Array of size_t of length H5C_RING_NTYPES used to
+ * maintain the sum of the sizes of all dirty entries in the
+ * index by ring. Note that the sum of all cells in this array
+ * must equal the value stored in dirty_index_size above.
+ *
+ * index: Array of pointer to H5C_cache_entry_t of size
+ * H5C__HASH_TABLE_LEN. At present, this value is a power
+ * of two, not the usual prime number.
+ *
+ * I hope that the variable size of cache elements, the large
+ * hash table size, and the way in which HDF5 allocates space
+ * will combine to avoid problems with periodicity. If so, we
+ * can use a trivial hash function (a bit-and and a 3 bit left
+ * shift) with some small savings.
+ *
+ * If not, it will become evident in the statistics. Changing
+ * to the usual prime number length hash table will require
+ * changing the H5C__HASH_FCN macro and the deletion of the
+ * H5C__HASH_MASK #define. No other changes should be required.
+ *
+ * il_len: Number of entries on the index list.
+ *
+ * This must always be equal to index_len. As such, this
+ * field is redundant. However, the existing linked list
+ * management macros expect to maintain a length field, so
+ * this field exists primarily to avoid adding complexity to
+ * these macros.
+ *
+ * il_size: Number of bytes of cache entries currently stored in the
+ * index list.
+ *
+ * This must always be equal to index_size. As such, this
+ * field is redundant. However, the existing linked list
+ * management macros expect to maintain a size field, so
+ * this field exists primarily to avoid adding complexity to
+ * these macros.
+ *
+ * il_head: Pointer to the head of the doubly linked list of entries in
+ * the index list. Note that cache entries on this list are
+ * linked by their il_next and il_prev fields.
+ *
+ * This field is NULL if the index is empty.
+ *
+ * il_tail: Pointer to the tail of the doubly linked list of entries in
+ * the index list. Note that cache entries on this list are
+ * linked by their il_next and il_prev fields.
+ *
+ * This field is NULL if the index is empty.
+ *
+ *
+ * With the addition of the take ownership flag, it is possible that
+ * an entry may be removed from the cache as the result of the flush of
+ * a second entry. In general, this causes little trouble, but it is
+ * possible that the entry removed may be the next entry in the scan of
+ * a list. In this case, we must be able to detect the fact that the
+ * entry has been removed, so that the scan doesn't attempt to proceed with
+ * an entry that is no longer in the cache.
+ *
+ * The following fields are maintained to facilitate this.
+ *
+ * entries_removed_counter: Counter that is incremented each time an
+ * entry is removed from the cache by any means (eviction,
+ * expungement, or take ownership at this point in time).
+ * Functions that perform scans on lists may set this field
+ * to zero prior to calling H5C__flush_single_entry().
+ * Unexpected changes to the counter indicate that an entry
+ * was removed from the cache as a side effect of the flush.
+ *
+ * last_entry_removed_ptr: Pointer to the instance of H5C_cache_entry_t
+ * which contained the last entry to be removed from the cache,
+ * or NULL if there either is no such entry, or if a function
+ * performing a scan of a list has set this field to NULL prior
+ * to calling H5C__flush_single_entry().
+ *
+ * WARNING!!! This field must NEVER be dereferenced. It is
+ * maintained to allow functions that perform scans of lists
+ * to compare this pointer with their pointers to next, thus
+ * allowing them to avoid unnecessary restarts of scans if the
+ * pointers don't match, and if entries_removed_counter is
+ * one.
+ *
+ * entry_watched_for_removal: Pointer to an instance of H5C_cache_entry_t
+ * which contains the 'next' entry for an iteration. Removing
+ * this entry must trigger a rescan of the iteration, so each
+ * entry removed from the cache is compared against this pointer
+ * and the pointer is reset to NULL if the watched entry is removed.
+ * (This functions similarly to a "dead man's switch")
+ *
+ *
+ * When we flush the cache, we need to write entries out in increasing
+ * address order. An instance of a skip list is used to store dirty entries in
+ * sorted order. Whether it is cheaper to sort the dirty entries as needed,
+ * or to maintain the list is an open question. At a guess, it depends
+ * on how frequently the cache is flushed. We will see how it goes.
+ *
+ * For now at least, I will not remove dirty entries from the list as they
+ * are flushed. (this has been changed -- dirty entries are now removed from
+ * the skip list as they are flushed. JRM - 10/25/05)
+ *
+ * slist_changed: Boolean flag used to indicate whether the contents of
+ * the slist has changed since the last time this flag was
+ * reset. This is used in the cache flush code to detect
+ * conditions in which pre-serialize or serialize callbacks
+ * have modified the slist -- which obliges us to restart
+ * the scan of the slist from the beginning.
+ *
+ * slist_len: Number of entries currently in the skip list
+ * used to maintain a sorted list of dirty entries in the
+ * cache.
+ *
+ * slist_size: Number of bytes of cache entries currently stored in the
+ * skip list used to maintain a sorted list of
+ * dirty entries in the cache.
+ *
+ * slist_ring_len: Array of integer of length H5C_RING_NTYPES used to
+ * maintain a count of entries in the slist by ring. Note
+ * that the sum of all the cells in this array must equal
+ * the value stored in slist_len above.
+ *
+ * slist_ring_size: Array of size_t of length H5C_RING_NTYPES used to
+ * maintain the sum of the sizes of all entries in the
+ * slist by ring. Note that the sum of all cells in this
+ * array must equal the value stored in slist_size above.
+ *
+ * slist_ptr: pointer to the instance of H5SL_t used maintain a sorted
+ * list of dirty entries in the cache. This sorted list has
+ * two uses:
+ *
+ * a) It allows us to flush dirty entries in increasing address
+ * order, which results in significant savings.
+ *
+ * b) It facilitates checking for adjacent dirty entries when
+ * attempting to evict entries from the cache. While we
+ * don't use this at present, I hope that this will allow
+ * some optimizations when I get to it.
+ *
+ * num_last_entries: The number of entries in the cache that can only be
+ * flushed after all other entries in the cache have
+ * been flushed. At this time, this will only ever be
+ * one entry (the superblock), and the code has been
+ * protected with HDasserts to enforce this. This restraint
+ * can certainly be relaxed in the future if the need for
+ * multiple entries being flushed last arises, though
+ * explicit tests for that case should be added when said
+ * HDasserts are removed.
+ *
+ * Update: There are now two possible last entries
+ * (superblock and file driver info message). This
+ * number will probably increase as we add superblock
+ * messages. JRM -- 11/18/14
+ *
+ * With the addition of the fractal heap, the cache must now deal with
+ * the case in which entries may be dirtied, moved, or have their sizes
+ * changed during a flush. To allow sanity checks in this situation, the
+ * following two fields have been added. They are only compiled in when
+ * H5C_DO_SANITY_CHECKS is TRUE.
+ *
+ * slist_len_increase: Number of entries that have been added to the
+ * slist since the last time this field was set to zero.
+ * Note that this value can be negative.
+ *
+ * slist_size_increase: Total size of all entries that have been added
+ * to the slist since the last time this field was set to
+ * zero. Note that this value can be negative.
+ *
+ * Cache entries belonging to a particular object are "tagged" with that
+ * object's base object header address.
+ *
+ * The following fields are maintained to facilitate this.
+ *
+ * tag_list: A skip list to track entries that belong to an object.
+ * Each H5C_tag_info_t struct on the tag list corresponds to
+ * a particular object in the file. Tagged entries can be
+ * flushed or evicted as a group, or corked to prevent entries
+ * from being evicted from the cache.
+ *
+ * "Global" entries, like the superblock and the file's
+ * freelist, as well as shared entries like global
+ * heaps and shared object header messages, are not tagged.
+ *
+ * ignore_tags: Boolean flag to disable tag validation during entry insertion.
+ *
+ * When a cache entry is protected, it must be removed from the LRU
+ * list(s) as it cannot be either flushed or evicted until it is unprotected.
+ * The following fields are used to implement the protected list (pl).
+ *
+ * pl_len: Number of entries currently residing on the protected list.
+ *
+ * pl_size: Number of bytes of cache entries currently residing on the
+ * protected list.
+ *
+ * pl_head_ptr: Pointer to the head of the doubly linked list of protected
+ * entries. Note that cache entries on this list are linked
+ * by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * pl_tail_ptr: Pointer to the tail of the doubly linked list of protected
+ * entries. Note that cache entries on this list are linked
+ * by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ *
+ * For very frequently used entries, the protect/unprotect overhead can
+ * become burdensome. To avoid this overhead, I have modified the cache
+ * to allow entries to be "pinned". A pinned entry is similar to a
+ * protected entry, in the sense that it cannot be evicted, and that
+ * the entry can be modified at any time.
+ *
+ * Pinning an entry has the following implications:
+ *
+ * 1) A pinned entry cannot be evicted. Thus unprotected
+ * pinned entries reside in the pinned entry list, instead
+ * of the LRU list(s) (or other lists maintained by the current
+ * replacement policy code).
+ *
+ * 2) A pinned entry can be accessed or modified at any time.
+ * This places an additional burden on the associated pre-serialize
+ * and serialize callbacks, which must ensure the the entry is in
+ * a consistant state before creating an image of it.
+ *
+ * 3) A pinned entry can be marked as dirty (and possibly
+ * change size) while it is unprotected.
+ *
+ * 4) The flush-destroy code must allow pinned entries to
+ * be unpinned (and possibly unprotected) during the
+ * flush.
+ *
+ * Since pinned entries cannot be evicted, they must be kept on a pinned
+ * entry list (pel), instead of being entrusted to the replacement policy
+ * code.
+ *
+ * Maintaining the pinned entry list requires the following fields:
+ *
+ * pel_len: Number of entries currently residing on the pinned
+ * entry list.
+ *
+ * pel_size: Number of bytes of cache entries currently residing on
+ * the pinned entry list.
+ *
+ * pel_head_ptr: Pointer to the head of the doubly linked list of pinned
+ * but not protected entries. Note that cache entries on
+ * this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * pel_tail_ptr: Pointer to the tail of the doubly linked list of pinned
+ * but not protected entries. Note that cache entries on
+ * this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ *
+ * The cache must have a replacement policy, and the fields supporting this
+ * policy must be accessible from this structure.
+ *
+ * While there has been interest in several replacement policies for
+ * this cache, the initial development schedule is tight. Thus I have
+ * elected to support only a modified LRU (least recently used) policy
+ * for the first cut.
+ *
+ * To further simplify matters, I have simply included the fields needed
+ * by the modified LRU in this structure. When and if we add support for
+ * other policies, it will probably be easiest to just add the necessary
+ * fields to this structure as well -- we only create one instance of this
+ * structure per file, so the overhead is not excessive.
+ *
+ *
+ * Fields supporting the modified LRU policy:
+ *
+ * See most any OS text for a discussion of the LRU replacement policy.
+ *
+ * When operating in parallel mode, we must ensure that a read does not
+ * cause a write. If it does, the process will hang, as the write will
+ * be collective and the other processes will not know to participate.
+ *
+ * To deal with this issue, I have modified the usual LRU policy by adding
+ * clean and dirty LRU lists to the usual LRU list. In general, these
+ * lists are only exist in parallel builds.
+ *
+ * The clean LRU list is simply the regular LRU list with all dirty cache
+ * entries removed.
+ *
+ * Similarly, the dirty LRU list is the regular LRU list with all the clean
+ * cache entries removed.
+ *
+ * When reading in parallel mode, we evict from the clean LRU list only.
+ * This implies that we must try to ensure that the clean LRU list is
+ * reasonably well stocked at all times.
+ *
+ * We attempt to do this by trying to flush enough entries on each write
+ * to keep the cLRU_list_size >= min_clean_size.
+ *
+ * Even if we start with a completely clean cache, a sequence of protects
+ * without unprotects can empty the clean LRU list. In this case, the
+ * cache must grow temporarily. At the next sync point, we will attempt to
+ * evict enough entries to reduce index_size to less than max_cache_size.
+ * While this will usually be possible, all bets are off if enough entries
+ * are protected.
+ *
+ * Discussions of the individual fields used by the modified LRU replacement
+ * policy follow:
+ *
+ * LRU_list_len: Number of cache entries currently on the LRU list.
+ *
+ * Observe that LRU_list_len + pl_len + pel_len must always
+ * equal index_len.
+ *
+ * LRU_list_size: Number of bytes of cache entries currently residing on the
+ * LRU list.
+ *
+ * Observe that LRU_list_size + pl_size + pel_size must always
+ * equal index_size.
+ *
+ * LRU_head_ptr: Pointer to the head of the doubly linked LRU list. Cache
+ * entries on this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * LRU_tail_ptr: Pointer to the tail of the doubly linked LRU list. Cache
+ * entries on this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * cLRU_list_len: Number of cache entries currently on the clean LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * cLRU_list_size: Number of bytes of cache entries currently residing on
+ * the clean LRU list.
+ *
+ * Observe that cLRU_list_size + dLRU_list_size must always
+ * equal LRU_list_size.
+ *
+ * cLRU_head_ptr: Pointer to the head of the doubly linked clean LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * cLRU_tail_ptr: Pointer to the tail of the doubly linked clean LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * dLRU_list_len: Number of cache entries currently on the dirty LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * dLRU_list_size: Number of cache entries currently on the dirty LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * dLRU_head_ptr: Pointer to the head of the doubly linked dirty LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * dLRU_tail_ptr: Pointer to the tail of the doubly linked dirty LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ *
+ * Automatic cache size adjustment:
+ *
+ * While the default cache size is adequate for most cases, we can run into
+ * cases where the default is too small. Ideally, we will let the user
+ * adjust the cache size as required. However, this is not possible in all
+ * cases. Thus I have added automatic cache size adjustment code.
+ *
+ * The configuration for the automatic cache size adjustment is stored in
+ * the structure described below:
+ *
+ * size_increase_possible: Depending on the configuration data given
+ * in the resize_ctl field, it may or may not be possible
+ * to increase the size of the cache. Rather than test for
+ * all the ways this can happen, we simply set this flag when
+ * we receive a new configuration.
+ *
+ * flash_size_increase_possible: Depending on the configuration data given
+ * in the resize_ctl field, it may or may not be possible
+ * for a flash size increase to occur. We set this flag
+ * whenever we receive a new configuration so as to avoid
+ * repeated calculations.
+ *
+ * flash_size_increase_threshold: If a flash cache size increase is possible,
+ * this field is used to store the minimum size of a new entry
+ * or size increase needed to trigger a flash cache size
+ * increase. Note that this field must be updated whenever
+ * the size of the cache is changed.
+ *
+ * size_decrease_possible: Depending on the configuration data given
+ * in the resize_ctl field, it may or may not be possible
+ * to decrease the size of the cache. Rather than test for
+ * all the ways this can happen, we simply set this flag when
+ * we receive a new configuration.
+ *
+ * resize_enabled: This is another convenience flag which is set whenever
+ * a new set of values for resize_ctl are provided. Very
+ * simply,
+ *
+ * resize_enabled = size_increase_possible ||
+ * size_decrease_possible;
+ *
+ * cache_full: Boolean flag used to keep track of whether the cache is
+ * full, so we can refrain from increasing the size of a
+ * cache which hasn't used up the space allotted to it.
+ *
+ * The field is initialized to FALSE, and then set to TRUE
+ * whenever we attempt to make space in the cache.
+ *
+ * size_decreased: Boolean flag set to TRUE whenever the maximum cache
+ * size is decreased. The flag triggers a call to
+ * H5C__make_space_in_cache() on the next call to H5C_protect().
+ *
+ * resize_in_progress: As the metadata cache has become re-entrant, it is
+ * possible that a protect may trigger a call to
+ * H5C__auto_adjust_cache_size(), which may trigger a flush,
+ * which may trigger a protect, which will result in another
+ * call to H5C__auto_adjust_cache_size().
+ *
+ * The resize_in_progress boolean flag is used to detect this,
+ * and to prevent the infinite recursion that would otherwise
+ * occur.
+ *
+ * Note that this issue is not hypothetical -- this field
+ * was added 12/29/15 to fix a bug exposed in the testing
+ * of changes to the file driver info superblock extension
+ * management code needed to support rings.
+ *
+ * msic_in_progress: As the metadata cache has become re-entrant, and as
+ * the free space manager code has become more tightly
+ * integrated with the metadata cache, it is possible that
+ * a call to H5C_insert_entry() may trigger a call to
+ * H5C_make_space_in_cache(), which, via H5C__flush_single_entry()
+ * and client callbacks, may trigger an infinite regression
+ * of calls to H5C_make_space_in_cache().
+ *
+ * The msic_in_progress boolean flag is used to detect this,
+ * and prevent the infinite regression that would otherwise
+ * occur.
+ *
+ * Note that this is issue is not hypothetical -- this field
+ * was added 2/16/17 to address this issue when it was
+ * exposed by modifications to test/fheap.c to cause it to
+ * use paged allocation.
+ *
+ * resize_ctl: Instance of H5C_auto_size_ctl_t containing configuration
+ * data for automatic cache resizing.
+ *
+ * epoch_markers_active: Integer field containing the number of epoch
+ * markers currently in use in the LRU list. This value
+ * must be in the range [0, H5C__MAX_EPOCH_MARKERS - 1].
+ *
+ * epoch_marker_active: Array of boolean of length H5C__MAX_EPOCH_MARKERS.
+ * This array is used to track which epoch markers are currently
+ * in use.
+ *
+ * epoch_marker_ringbuf: Array of int of length H5C__MAX_EPOCH_MARKERS + 1.
+ *
+ * To manage the epoch marker cache entries, it is necessary
+ * to track their order in the LRU list. This is done with
+ * epoch_marker_ringbuf. When markers are inserted at the
+ * head of the LRU list, the index of the marker in the
+ * epoch_markers array is inserted at the tail of the ring
+ * buffer. When it becomes the epoch_marker_active'th marker
+ * in the LRU list, it will have worked its way to the head
+ * of the ring buffer as well. This allows us to remove it
+ * without scanning the LRU list if such is required.
+ *
+ * epoch_marker_ringbuf_first: Integer field containing the index of the
+ * first entry in the ring buffer.
+ *
+ * epoch_marker_ringbuf_last: Integer field containing the index of the
+ * last entry in the ring buffer.
+ *
+ * epoch_marker_ringbuf_size: Integer field containing the number of entries
+ * in the ring buffer.
+ *
+ * epoch_markers: Array of instances of H5C_cache_entry_t of length
+ * H5C__MAX_EPOCH_MARKERS. The entries are used as markers
+ * in the LRU list to identify cache entries that haven't
+ * been accessed for some (small) specified number of
+ * epochs. These entries (if any) can then be evicted and
+ * the cache size reduced -- ideally without evicting any
+ * of the current working set. Needless to say, the epoch
+ * length and the number of epochs before an unused entry
+ * must be chosen so that all, or almost all, the working
+ * set will be accessed before the limit.
+ *
+ * Epoch markers only appear in the LRU list, never in
+ * the index or slist. While they are of type
+ * H5C__EPOCH_MARKER_TYPE, and have associated class
+ * functions, these functions should never be called.
+ *
+ * The addr fields of these instances of H5C_cache_entry_t
+ * are set to the index of the instance in the epoch_markers
+ * array, the size is set to 0, and the type field points
+ * to the constant structure epoch_marker_class defined
+ * in H5C.c. The next and prev fields are used as usual
+ * to link the entry into the LRU list.
+ *
+ * All other fields are unused.
+ *
+ *
+ * Cache hit rate collection fields:
+ *
+ * We supply the current cache hit rate on request, so we must keep a
+ * simple cache hit rate computation regardless of whether statistics
+ * collection is enabled. The following fields support this capability.
+ *
+ * cache_hits: Number of cache hits since the last time the cache hit
+ * rate statistics were reset. Note that when automatic cache
+ * re-sizing is enabled, this field will be reset every automatic
+ * resize epoch.
+ *
+ * cache_accesses: Number of times the cache has been accessed while
+ * since the last since the last time the cache hit rate statistics
+ * were reset. Note that when automatic cache re-sizing is enabled,
+ * this field will be reset every automatic resize epoch.
+ *
+ *
+ * Metadata cache image management related fields.
+ *
+ * image_ctl: Instance of H5C_cache_image_ctl_t containing configuration
+ * data for generation of a cache image on file close.
+ *
+ * serialization_in_progress: Boolean field that is set to TRUE iff
+ * the cache is in the process of being serialized. This
+ * field is needed to support the H5C_serialization_in_progress()
+ * call, which is in turn required for sanity checks in some
+ * cache clients.
+ *
+ * load_image: Boolean flag indicating that the metadata cache image
+ * superblock extension message exists and should be
+ * read, and the image block read and decoded on the next
+ * call to H5C_protect().
+ *
+ * image_loaded: Boolean flag indicating that the metadata cache has
+ * loaded the metadata cache image as directed by the
+ * MDC cache image superblock extension message.
+ *
+ * delete_image: Boolean flag indicating whether the metadata cache image
+ * superblock message should be deleted and the cache image
+ * file space freed after they have been read and decoded.
+ *
+ * This flag should be set to TRUE iff the file is opened
+ * R/W and there is a cache image to be read.
+ *
+ * image_addr: haddr_t containing the base address of the on disk
+ * metadata cache image, or HADDR_UNDEF if that value is
+ * undefined. Note that this field is used both in the
+ * construction and write, and the read and decode of
+ * metadata cache image blocks.
+ *
+ * image_len: hsize_t containing the size of the on disk metadata cache
+ * image, or zero if that value is undefined. Note that this
+ * field is used both in the construction and write, and the
+ * read and decode of metadata cache image blocks.
+ *
+ * image_data_len: size_t containing the number of bytes of data in the
+ * on disk metadata cache image, or zero if that value is
+ * undefined.
+ *
+ * In most cases, this value is the same as the image_len
+ * above. It exists to allow for metadata cache image blocks
+ * that are larger than the actual image. Thus in all
+ * cases image_data_len <= image_len.
+ *
+ * To create the metadata cache image, we must first serialize all the
+ * entries in the metadata cache. This is done by a scan of the index.
+ * As entries must be serialized in increasing flush dependency height
+ * order, we scan the index repeatedly, once for each flush dependency
+ * height in increasing order.
+ *
+ * This operation is complicated by the fact that entries other the the
+ * target may be inserted, loaded, relocated, or removed from the cache
+ * (either by eviction or the take ownership flag) as the result of a
+ * pre_serialize or serialize callback. While entry removals are not
+ * a problem for the scan of the index, insertions, loads, and relocations
+ * are. Hence the entries loaded, inserted, and relocated counters
+ * listed below have been implemented to allow these conditions to be
+ * detected and dealt with by restarting the scan.
+ *
+ * The serialization operation is further complicated by the fact that
+ * the flush dependency height of a given entry may increase (as the
+ * result of an entry load or insert) or decrease (as the result of an
+ * entry removal -- via either eviction or the take ownership flag). The
+ * entry_fd_height_change_counter field is maintained to allow detection
+ * of this condition, and a restart of the scan when it occurs.
+ *
+ * Note that all these new fields would work just as well as booleans.
+ *
+ * entries_loaded_counter: Number of entries loaded into the cache
+ * since the last time this field was reset.
+ *
+ * entries_inserted_counter: Number of entries inserted into the cache
+ * since the last time this field was reset.
+ *
+ * entries relocated_counter: Number of entries whose base address has
+ * been changed since the last time this field was reset.
+ *
+ * entry_fd_height_change_counter: Number of entries whose flush dependency
+ * height has changed since the last time this field was reset.
+ *
+ * The following fields are used assemble the cache image prior to
+ * writing it to disk.
+ *
+ * num_entries_in_image: Unsigned integer field containing the number of entries
+ * to be copied into the metadata cache image. Note that
+ * this value will be less than the number of entries in
+ * the cache, and the superblock and its related entries
+ * are not written to the metadata cache image.
+ *
+ * image_entries: Pointer to a dynamically allocated array of instance of
+ * H5C_image_entry_t of length num_entries_in_image, or NULL
+ * if that array does not exist. This array is used to
+ * assemble entry data to be included in the image, and to
+ * sort them by flush dependency height and LRU rank.
+ *
+ * image_buffer: Pointer to the dynamically allocated buffer of length
+ * image_len in which the metadata cache image is assembled,
+ * or NULL if that buffer does not exist.
+ *
+ *
+ * Free Space Manager Related fields:
+ *
+ * The free space managers must be informed when we are about to close
+ * or flush the file so that they order themselves accordingly. This used
+ * to be done much later in the close process, but with cache image and
+ * page buffering, this is no longer viable, as we must finalize the on
+ * disk image of all metadata much sooner.
+ *
+ * This is handled by the H5MF_settle_raw_data_fsm() and
+ * H5MF_settle_meta_data_FSM() routines. As these calls are expensive,
+ * the following fields are used to track whether the target free space
+ * managers are clean.
+ *
+ * They are also used in sanity checking, as once a free space manager is
+ * settled, it should not become unsettled (i.e. be asked to allocate or
+ * free file space) either ever (in the case of a file close) or until the
+ * flush is complete.
+ *
+ * rdfsm_settled: Boolean flag indicating whether the raw data free space
+ * manager is settled -- i.e. whether the correct space has
+ * been allocated for it in the file.
+ *
+ * Note that the name of this field is deceptive. In the
+ * multi file case, the flag applies to all free space
+ * managers that are not involved in allocating space for
+ * free space manager metadata.
+ *
+ * mdfsm_settled: Boolean flag indicating whether the meta data free space
+ * manager is settled -- i.e. whether the correct space has
+ * been allocated for it in the file.
+ *
+ * Note that the name of this field is deceptive. In the
+ * multi file case, the flag applies only to free space
+ * managers that are involved in allocating space for free
+ * space managers.
+ *
+ *
+ * Statistics collection fields:
+ *
+ * When enabled, these fields are used to collect statistics as described
+ * below. The first set are collected only when H5C_COLLECT_CACHE_STATS
+ * is true.
+ *
+ * hits: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been in cache when requested in
+ * the current epoch.
+ *
+ * misses: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has not been in cache when
+ * requested in the current epoch.
+ *
+ * write_protects: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The
+ * cells are used to record the number of times an entry with
+ * type id equal to the array index has been write protected
+ * in the current epoch.
+ *
+ * Observe that (hits + misses) = (write_protects + read_protects).
+ *
+ * read_protects: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The
+ * cells are used to record the number of times an entry with
+ * type id equal to the array index has been read protected in
+ * the current epoch.
+ *
+ * Observe that (hits + misses) = (write_protects + read_protects).
+ *
+ * max_read_protects: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to maximum number of simultaneous read
+ * protects on any entry with type id equal to the array index
+ * in the current epoch.
+ *
+ * insertions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been inserted into the
+ * cache in the current epoch.
+ *
+ * pinned_insertions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to record the number of times an entry
+ * with type id equal to the array index has been inserted
+ * pinned into the cache in the current epoch.
+ *
+ * clears: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times a dirty entry with type
+ * id equal to the array index has been cleared in the current
+ * epoch.
+ *
+ * flushes: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been written to disk in the
+ * current epoch.
+ *
+ * evictions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been evicted from the cache in
+ * the current epoch.
+ *
+ * take_ownerships: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The
+ * cells are used to record the number of times an entry with
+ * type id equal to the array index has been removed from the
+ * cache via the H5C__TAKE_OWNERSHIP_FLAG in the current epoch.
+ *
+ * moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been moved in the current
+ * epoch.
+ *
+ * entry_flush_moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to record the number of times an entry
+ * with type id equal to the array index has been moved
+ * during its pre-serialize callback in the current epoch.
+ *
+ * cache_flush_moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to record the number of times an entry
+ * with type id equal to the array index has been moved
+ * during a cache flush in the current epoch.
+ *
+ * pins: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been pinned in the current
+ * epoch.
+ *
+ * unpins: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been unpinned in the current
+ * epoch.
+ *
+ * dirty_pins: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been marked dirty while pinned
+ * in the current epoch.
+ *
+ * pinned_flushes: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The
+ * cells are used to record the number of times an entry
+ * with type id equal to the array index has been flushed while
+ * pinned in the current epoch.
+ *
+ * pinned_clears: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The
+ * cells are used to record the number of times an entry
+ * with type id equal to the array index has been cleared while
+ * pinned in the current epoch.
+ *
+ * size_increases: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to record the number of times an entry
+ * with type id equal to the array index has increased in
+ * size in the current epoch.
+ *
+ * size_decreases: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
+ * The cells are used to record the number of times an entry
+ * with type id equal to the array index has decreased in
+ * size in the current epoch.
+ *
+ * entry_flush_size_changes: Array of int64 of length
+ * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record
+ * the number of times an entry with type id equal to the
+ * array index has changed size while in its pre-serialize
+ * callback.
+ *
+ * cache_flush_size_changes: Array of int64 of length
+ * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record
+ * the number of times an entry with type id equal to the
+ * array index has changed size during a cache flush
+ *
+ * total_ht_insertions: Number of times entries have been inserted into the
+ * hash table in the current epoch.
+ *
+ * total_ht_deletions: Number of times entries have been deleted from the
+ * hash table in the current epoch.
+ *
+ * successful_ht_searches: int64 containing the total number of successful
+ * searches of the hash table in the current epoch.
+ *
+ * total_successful_ht_search_depth: int64 containing the total number of
+ * entries other than the targets examined in successful
+ * searches of the hash table in the current epoch.
+ *
+ * failed_ht_searches: int64 containing the total number of unsuccessful
+ * searches of the hash table in the current epoch.
+ *
+ * total_failed_ht_search_depth: int64 containing the total number of
+ * entries examined in unsuccessful searches of the hash
+ * table in the current epoch.
+ *
+ * max_index_len: Largest value attained by the index_len field in the
+ * current epoch.
+ *
+ * max_index_size: Largest value attained by the index_size field in the
+ * current epoch.
+ *
+ * max_clean_index_size: Largest value attained by the clean_index_size field
+ * in the current epoch.
+ *
+ * max_dirty_index_size: Largest value attained by the dirty_index_size field
+ * in the current epoch.
+ *
+ * max_slist_len: Largest value attained by the slist_len field in the
+ * current epoch.
+ *
+ * max_slist_size: Largest value attained by the slist_size field in the
+ * current epoch.
+ *
+ * max_pl_len: Largest value attained by the pl_len field in the
+ * current epoch.
+ *
+ * max_pl_size: Largest value attained by the pl_size field in the
+ * current epoch.
+ *
+ * max_pel_len: Largest value attained by the pel_len field in the
+ * current epoch.
+ *
+ * max_pel_size: Largest value attained by the pel_size field in the
+ * current epoch.
+ *
+ * calls_to_msic: Total number of calls to H5C__make_space_in_cache
+ *
+ * total_entries_skipped_in_msic: Number of clean entries skipped while
+ * enforcing the min_clean_fraction in H5C__make_space_in_cache().
+ *
+ * total_dirty_pf_entries_skipped_in_msic: Number of dirty prefetched entries
+ * skipped in H5C__make_space_in_cache(). Note that this can
+ * only occur when a file is opened R/O with a cache image
+ * containing dirty entries.
+ *
+ * total_entries_scanned_in_msic: Number of clean entries skipped while
+ * enforcing the min_clean_fraction in H5C__make_space_in_cache().
+ *
+ * max_entries_skipped_in_msic: Maximum number of clean entries skipped
+ * in any one call to H5C__make_space_in_cache().
+ *
+ * max_dirty_pf_entries_skipped_in_msic: Maximum number of dirty prefetched
+ * entries skipped in any one call to H5C__make_space_in_cache().
+ * Note that this can only occur when the file is opened
+ * R/O with a cache image containing dirty entries.
+ *
+ * max_entries_scanned_in_msic: Maximum number of entries scanned over
+ * in any one call to H5C__make_space_in_cache().
+ *
+ * entries_scanned_to_make_space: Number of entries scanned only when looking
+ * for entries to evict in order to make space in cache.
+ *
+ *
+ * The following fields track statistics on cache images.
+ *
+ * images_created: Integer field containing the number of cache images
+ * created since the last time statistics were reset.
+ *
+ * At present, this field must always be either 0 or 1.
+ * Further, since cache images are only created at file
+ * close, this field should only be set at that time.
+ *
+ * images_read: Integer field containing the number of cache images
+ * read from file. Note that reading an image is different
+ * from loading it -- reading the image means just that,
+ * while loading the image refers to decoding it and loading
+ * it into the metadata cache.
+ *
+ * In the serial case, image_read should always equal
+ * images_loaded. However, in the parallel case, the
+ * image should only be read by process 0. All other
+ * processes should receive the cache image via a broadcast
+ * from process 0.
+ *
+ * images_loaded: Integer field containing the number of cache images
+ * loaded since the last time statistics were reset.
+ *
+ * At present, this field must always be either 0 or 1.
+ * Further, since cache images are only loaded at the
+ * time of the first protect or on file close, this value
+ * should only change on those events.
+ *
+ * last_image_size: Size of the most recently loaded metadata cache image
+ * loaded into the cache, or zero if no image has been
+ * loaded.
+ *
+ * At present, at most one cache image can be loaded into
+ * the metadata cache for any given file, and this image
+ * will be loaded either on the first protect, or on file
+ * close if no entry is protected before then.
+ *
+ *
+ * Fields for tracking prefetched entries. Note that flushes and evictions
+ * of prefetched entries are tracked in the flushes and evictions arrays
+ * discused above.
+ *
+ * prefetches: Number of prefetched entries that are loaded to the
+ * cache.
+ *
+ * dirty_prefetches: Number of dirty prefetched entries that are loaded
+ * into the cache.
+ *
+ * prefetch_hits: Number of prefetched entries that are actually used.
+ *
+ *
+ * As entries are now capable of moving, loading, dirtying, and deleting
+ * other entries in their pre_serialize and serialize callbacks, it has
+ * been necessary to insert code to restart scans of lists so as to avoid
+ * improper behavior if the next entry in the list is the target of one on
+ * these operations.
+ *
+ * The following fields are use to count such occurances. They are used
+ * both in tests (to verify that the scan has been restarted), and to
+ * obtain estimates of how frequently these restarts occur.
+ *
+ * slist_scan_restarts: Number of times a scan of the slist (that contains
+ * calls to H5C__flush_single_entry()) has been restarted to
+ * avoid potential issues with change of status of the next
+ * entry in the scan.
+ *
+ * LRU_scan_restarts: Number of times a scan of the LRU list (that contains
+ * calls to H5C__flush_single_entry()) has been restarted to
+ * avoid potential issues with change of status of the next
+ * entry in the scan.
+ *
+ * index_scan_restarts: Number of times a scan of the index has been
+ * restarted to avoid potential issues with load, insertion
+ * or change in flush dependency height of an entry other
+ * than the target entry as the result of call(s) to the
+ * pre_serialize or serialize callbacks.
+ *
+ * Note that at present, this condition can only be triggerd
+ * by a call to H5C_serialize_single_entry().
+ *
+ * The remaining stats are collected only when both H5C_COLLECT_CACHE_STATS
+ * and H5C_COLLECT_CACHE_ENTRY_STATS are true.
+ *
+ * max_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been
+ * accessed in the current epoch.
+ *
+ * min_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the minimum number of times any single
+ * entry with type id equal to the array index has been
+ * accessed in the current epoch.
+ *
+ * max_clears: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been cleared
+ * in the current epoch.
+ *
+ * max_flushes: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been
+ * flushed in the current epoch.
+ *
+ * max_size: Array of size_t of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the maximum size of any single entry
+ * with type id equal to the array index that has resided in
+ * the cache in the current epoch.
+ *
+ * max_pins: Array of size_t of length H5C__MAX_NUM_TYPE_IDS + 1. The cells
+ * are used to record the maximum number of times that any single
+ * entry with type id equal to the array index that has been
+ * marked as pinned in the cache in the current epoch.
+ *
+ *
+ * Fields supporting testing:
+ *
+ * prefix Array of char used to prefix debugging output. The
+ * field is intended to allow marking of output of with
+ * the processes mpi rank.
+ *
+ * get_entry_ptr_from_addr_counter: Counter used to track the number of
+ * times the H5C_get_entry_ptr_from_addr() function has been
+ * called successfully. This field is only defined when
+ * NDEBUG is not #defined.
+ *
+ ****************************************************************************/
+struct H5C_t {
+ uint32_t magic;
+ hbool_t flush_in_progress;
+ FILE * trace_file_ptr;
+ hbool_t logging_enabled;
+ hbool_t currently_logging;
+ FILE * log_file_ptr;
+ void * aux_ptr;
+ int32_t max_type_id;
+ const H5C_class_t * const *class_table_ptr;
+ size_t max_cache_size;
+ size_t min_clean_size;
+ H5C_write_permitted_func_t check_write_permitted;
+ hbool_t write_permitted;
+ H5C_log_flush_func_t log_flush;
+ hbool_t evictions_enabled;
+ hbool_t close_warning_received;
+
+ /* Fields for maintaining [hash table] index of entries */
+ uint32_t index_len;
+ size_t index_size;
+ uint32_t index_ring_len[H5C_RING_NTYPES];
+ size_t index_ring_size[H5C_RING_NTYPES];
+ size_t clean_index_size;
+ size_t clean_index_ring_size[H5C_RING_NTYPES];
+ size_t dirty_index_size;
+ size_t dirty_index_ring_size[H5C_RING_NTYPES];
+ H5C_cache_entry_t * index[H5C__HASH_TABLE_LEN];
+ uint32_t il_len;
+ size_t il_size;
+ H5C_cache_entry_t * il_head;
+ H5C_cache_entry_t * il_tail;
+
+ /* Fields to detect entries removed during scans */
+ int64_t entries_removed_counter;
+ H5C_cache_entry_t * last_entry_removed_ptr;
+ H5C_cache_entry_t * entry_watched_for_removal;
+
+ /* Fields for maintaining list of in-order entries, for flushing */
+ hbool_t slist_changed;
+ uint32_t slist_len;
+ size_t slist_size;
+ uint32_t slist_ring_len[H5C_RING_NTYPES];
+ size_t slist_ring_size[H5C_RING_NTYPES];
+ H5SL_t * slist_ptr;
+ uint32_t num_last_entries;
+#if H5C_DO_SANITY_CHECKS
+ int32_t slist_len_increase;
+ ssize_t slist_size_increase;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ /* Fields for maintaining list of tagged entries */
+ H5SL_t * tag_list;
+ hbool_t ignore_tags;
+
+ /* Fields for tracking protected entries */
+ uint32_t pl_len;
+ size_t pl_size;
+ H5C_cache_entry_t * pl_head_ptr;
+ H5C_cache_entry_t * pl_tail_ptr;
+
+ /* Fields for tracking pinned entries */
+ uint32_t pel_len;
+ size_t pel_size;
+ H5C_cache_entry_t * pel_head_ptr;
+ H5C_cache_entry_t * pel_tail_ptr;
+
+ /* Fields for complete LRU list of entries */
+ uint32_t LRU_list_len;
+ size_t LRU_list_size;
+ H5C_cache_entry_t * LRU_head_ptr;
+ H5C_cache_entry_t * LRU_tail_ptr;
+
+ /* Fields for clean LRU list of entries */
+ uint32_t cLRU_list_len;
+ size_t cLRU_list_size;
+ H5C_cache_entry_t * cLRU_head_ptr;
+ H5C_cache_entry_t * cLRU_tail_ptr;
+
+ /* Fields for dirty LRU list of entries */
+ uint32_t dLRU_list_len;
+ size_t dLRU_list_size;
+ H5C_cache_entry_t * dLRU_head_ptr;
+ H5C_cache_entry_t * dLRU_tail_ptr;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Fields for collective metadata reads */
+ uint32_t coll_list_len;
+ size_t coll_list_size;
+ H5C_cache_entry_t * coll_head_ptr;
+ H5C_cache_entry_t * coll_tail_ptr;
+
+ /* Fields for collective metadata writes */
+ H5SL_t * coll_write_list;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Fields for automatic cache size adjustment */
+ hbool_t size_increase_possible;
+ hbool_t flash_size_increase_possible;
+ size_t flash_size_increase_threshold;
+ hbool_t size_decrease_possible;
+ hbool_t resize_enabled;
+ hbool_t cache_full;
+ hbool_t size_decreased;
+ hbool_t resize_in_progress;
+ hbool_t msic_in_progress;
+ H5C_auto_size_ctl_t resize_ctl;
+
+ /* Fields for epoch markers used in automatic cache size adjustment */
+ int32_t epoch_markers_active;
+ hbool_t epoch_marker_active[H5C__MAX_EPOCH_MARKERS];
+ int32_t epoch_marker_ringbuf[H5C__MAX_EPOCH_MARKERS+1];
+ int32_t epoch_marker_ringbuf_first;
+ int32_t epoch_marker_ringbuf_last;
+ int32_t epoch_marker_ringbuf_size;
+ H5C_cache_entry_t epoch_markers[H5C__MAX_EPOCH_MARKERS];
+
+ /* Fields for cache hit rate collection */
+ int64_t cache_hits;
+ int64_t cache_accesses;
+
+ /* fields supporting generation of a cache image on file close */
+ H5C_cache_image_ctl_t image_ctl;
+ hbool_t serialization_in_progress;
+ hbool_t load_image;
+ hbool_t image_loaded;
+ hbool_t delete_image;
+ haddr_t image_addr;
+ hsize_t image_len;
+ hsize_t image_data_len;
+ int64_t entries_loaded_counter;
+ int64_t entries_inserted_counter;
+ int64_t entries_relocated_counter;
+ int64_t entry_fd_height_change_counter;
+ uint32_t num_entries_in_image;
+ H5C_image_entry_t * image_entries;
+ void * image_buffer;
+
+ /* Free Space Manager Related fields */
+ hbool_t rdfsm_settled;
+ hbool_t mdfsm_settled;
+
+#if H5C_COLLECT_CACHE_STATS
+ /* stats fields */
+ int64_t hits[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t misses[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t write_protects[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t read_protects[H5C__MAX_NUM_TYPE_IDS + 1];
+ int32_t max_read_protects[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t insertions[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t pinned_insertions[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t clears[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t flushes[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t evictions[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t take_ownerships[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t moves[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t entry_flush_moves[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t cache_flush_moves[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t pins[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t unpins[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t dirty_pins[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t pinned_flushes[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t pinned_clears[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t size_increases[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t size_decreases[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t entry_flush_size_changes[H5C__MAX_NUM_TYPE_IDS + 1];
+ int64_t cache_flush_size_changes[H5C__MAX_NUM_TYPE_IDS + 1];
+
+ /* Fields for hash table operations */
+ int64_t total_ht_insertions;
+ int64_t total_ht_deletions;
+ int64_t successful_ht_searches;
+ int64_t total_successful_ht_search_depth;
+ int64_t failed_ht_searches;
+ int64_t total_failed_ht_search_depth;
+ uint32_t max_index_len;
+ size_t max_index_size;
+ size_t max_clean_index_size;
+ size_t max_dirty_index_size;
+
+ /* Fields for in-order skip list */
+ uint32_t max_slist_len;
+ size_t max_slist_size;
+
+ /* Fields for protected entry list */
+ uint32_t max_pl_len;
+ size_t max_pl_size;
+
+ /* Fields for pinned entry list */
+ uint32_t max_pel_len;
+ size_t max_pel_size;
+
+ /* Fields for tracking 'make space in cache' (msic) operations */
+ int64_t calls_to_msic;
+ int64_t total_entries_skipped_in_msic;
+ int64_t total_dirty_pf_entries_skipped_in_msic;
+ int64_t total_entries_scanned_in_msic;
+ int32_t max_entries_skipped_in_msic;
+ int32_t max_dirty_pf_entries_skipped_in_msic;
+ int32_t max_entries_scanned_in_msic;
+ int64_t entries_scanned_to_make_space;
+
+ /* Fields for tracking skip list scan restarts */
+ int64_t slist_scan_restarts;
+ int64_t LRU_scan_restarts;
+ int64_t index_scan_restarts;
+
+ /* Fields for tracking cache image operations */
+ int32_t images_created;
+ int32_t images_read;
+ int32_t images_loaded;
+ hsize_t last_image_size;
+
+ /* Fields for tracking prefetched entries */
+ int64_t prefetches;
+ int64_t dirty_prefetches;
+ int64_t prefetch_hits;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+ int32_t max_accesses[H5C__MAX_NUM_TYPE_IDS + 1];
+ int32_t min_accesses[H5C__MAX_NUM_TYPE_IDS + 1];
+ int32_t max_clears[H5C__MAX_NUM_TYPE_IDS + 1];
+ int32_t max_flushes[H5C__MAX_NUM_TYPE_IDS + 1];
+ size_t max_size[H5C__MAX_NUM_TYPE_IDS + 1];
+ int32_t max_pins[H5C__MAX_NUM_TYPE_IDS + 1];
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ char prefix[H5C__PREFIX_LEN];
+
+#ifndef NDEBUG
+ int64_t get_entry_ptr_from_addr_counter;
+#endif /* NDEBUG */
+};
+
+/* Define typedef for tagged cache entry iteration callbacks */
+typedef int (*H5C_tag_iter_cb_t)(H5C_cache_entry_t *entry, void *ctx);
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+H5_DLL herr_t H5C__prep_image_for_file_close(H5F_t *f, hid_t dxpl_id,
+ hbool_t *image_generated);
+H5_DLL herr_t H5C__deserialize_prefetched_entry(H5F_t *f, hid_t dxpl_id,
+ H5C_t * cache_ptr, H5C_cache_entry_t** entry_ptr_ptr,
+ const H5C_class_t * type, haddr_t addr, void * udata);
+
+/* General routines */
+H5_DLL herr_t H5C__flush_single_entry(H5F_t *f, hid_t dxpl_id,
+ H5C_cache_entry_t *entry_ptr, unsigned flags);
+H5_DLL herr_t H5C__generate_cache_image(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr);
+H5_DLL herr_t H5C__load_cache_image(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C__mark_flush_dep_serialized(H5C_cache_entry_t * entry_ptr);
+H5_DLL herr_t H5C__mark_flush_dep_unserialized(H5C_cache_entry_t * entry_ptr);
+H5_DLL herr_t H5C__make_space_in_cache(H5F_t * f, hid_t dxpl_id,
+ size_t space_needed, hbool_t write_permitted);
+H5_DLL herr_t H5C__flush_marked_entries(H5F_t * f, hid_t dxpl_id);
+H5_DLL herr_t H5C__generate_image(H5F_t *f, H5C_t *cache_ptr,
+ H5C_cache_entry_t *entry_ptr, hid_t dxpl_id);
+H5_DLL herr_t H5C__serialize_cache(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C__iter_tagged_entries(H5C_t *cache, haddr_t tag, hbool_t match_global,
+ H5C_tag_iter_cb_t cb, void *cb_ctx);
+
+/* Routines for operating on entry tags */
+H5_DLL herr_t H5C__tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr,
+ hid_t dxpl_id);
+H5_DLL herr_t H5C__untag_entry(H5C_t *cache, H5C_cache_entry_t *entry);
+
+/* Testing functions */
+#ifdef H5C_TESTING
+H5_DLL herr_t H5C__verify_cork_tag_test(hid_t fid, haddr_t tag, hbool_t status);
+#endif /* H5C_TESTING */
+
+#endif /* _H5Cpkg_H */
+
diff --git a/src/H5Cprefetched.c b/src/H5Cprefetched.c
new file mode 100644
index 0000000..6237d57
--- /dev/null
+++ b/src/H5Cprefetched.c
@@ -0,0 +1,350 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cprefetched.c
+ * December 28 2016
+ * Quincey Koziol
+ *
+ * Purpose: Metadata cache prefetched entry callbacks.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/****************************************************************************
+ *
+ * Declarations for prefetched cache entry callbacks.
+ *
+ ****************************************************************************/
+static herr_t H5C__prefetched_entry_get_initial_load_size(void *udata_ptr,
+ size_t *image_len_ptr);
+static herr_t H5C__prefetched_entry_get_final_load_size(const void *image_ptr,
+ size_t image_len, void *udata_ptr, size_t *actual_len_ptr);
+static htri_t H5C__prefetched_entry_verify_chksum(const void *image_ptr,
+ size_t len, void *udata_ptr);
+static void * H5C__prefetched_entry_deserialize(const void *image_ptr,
+ size_t len, void *udata, hbool_t *dirty_ptr);
+static herr_t H5C__prefetched_entry_image_len(const void *thing,
+ size_t *image_len_ptr);
+static herr_t H5C__prefetched_entry_pre_serialize(H5F_t *f,
+ hid_t dxpl_id, void *thing, haddr_t addr, size_t len,
+ haddr_t *new_addr_ptr, size_t *new_len_ptr, unsigned *flags_ptr);
+static herr_t H5C__prefetched_entry_serialize(const H5F_t *f, void *image_ptr,
+ size_t len, void *thing);
+static herr_t H5C__prefetched_entry_notify(H5C_notify_action_t action,
+ void *thing);
+static herr_t H5C__prefetched_entry_free_icr(void *thing);
+static herr_t H5C__prefetched_entry_fsf_size(const void *thing,
+ size_t *fsf_size_ptr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare external the free list for H5C_cache_entry_t's */
+H5FL_EXTERN(H5C_cache_entry_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+const H5AC_class_t H5AC_PREFETCHED_ENTRY[1] = {{
+ /* id = */ H5AC_PREFETCHED_ENTRY_ID,
+ /* name = */ "prefetched entry",
+ /* mem_type = */ H5FD_MEM_DEFAULT, /* value doesn't matter */
+ /* flags = */ H5AC__CLASS_NO_FLAGS_SET,
+ /* get_initial_load_size = */ H5C__prefetched_entry_get_initial_load_size,
+ /* get_final_load_size = */ H5C__prefetched_entry_get_final_load_size,
+ /* verify_chksum = */ H5C__prefetched_entry_verify_chksum,
+ /* deserialize = */ H5C__prefetched_entry_deserialize,
+ /* image_len = */ H5C__prefetched_entry_image_len,
+ /* pre_serialize = */ H5C__prefetched_entry_pre_serialize,
+ /* serialize = */ H5C__prefetched_entry_serialize,
+ /* notify = */ H5C__prefetched_entry_notify,
+ /* free_icr = */ H5C__prefetched_entry_free_icr,
+ /* fsf_size = */ H5C__prefetched_entry_fsf_size,
+}};
+
+
+
+/***************************************************************************
+ * With two exceptions, these functions should never be called, and thus
+ * there is little point in documenting them separately as they all simply
+ * throw an error.
+ *
+ * See header comments for the two exceptions (free_icr and notify).
+ *
+ * JRM - 8/13/15
+ *
+ ***************************************************************************/
+
+static herr_t
+H5C__prefetched_entry_get_initial_load_size(void H5_ATTR_UNUSED *udata_ptr,
+ size_t H5_ATTR_UNUSED *image_len_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_get_initial_load_size() */
+
+static herr_t
+H5C__prefetched_entry_get_final_load_size(const void H5_ATTR_UNUSED *image_ptr,
+ size_t H5_ATTR_UNUSED image_len, void H5_ATTR_UNUSED *udata_ptr,
+ size_t H5_ATTR_UNUSED *actual_len_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_get_final_load_size() */
+
+static htri_t
+H5C__prefetched_entry_verify_chksum(const void H5_ATTR_UNUSED *image_ptr,
+ size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *udata_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_verify_chksum() */
+
+
+static void *
+H5C__prefetched_entry_deserialize(const void H5_ATTR_UNUSED * image_ptr,
+ size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED * udata,
+ hbool_t H5_ATTR_UNUSED * dirty_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5C__prefetched_entry_deserialize() */
+
+
+static herr_t
+H5C__prefetched_entry_image_len(const void H5_ATTR_UNUSED *thing,
+ size_t H5_ATTR_UNUSED *image_len_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_image_len() */
+
+
+static herr_t
+H5C__prefetched_entry_pre_serialize(H5F_t H5_ATTR_UNUSED *f,
+ hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_UNUSED *thing,
+ haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED len,
+ haddr_t H5_ATTR_UNUSED *new_addr_ptr,
+ size_t H5_ATTR_UNUSED *new_len_ptr,
+ unsigned H5_ATTR_UNUSED *flags_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_pre_serialize() */
+
+
+static herr_t
+H5C__prefetched_entry_serialize(const H5F_t H5_ATTR_UNUSED *f,
+ void H5_ATTR_UNUSED *image_ptr,
+ size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *thing)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prefetched_entry_notify
+ *
+ * Purpose: On H5AC_NOTIFY_ACTION_BEFORE_EVICT, check to see if the
+ * target entry is a child in a flush dependency relationship.
+ * If it is, destroy that flush dependency relationship.
+ *
+ * Ignore on all other notifications.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 8/13/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__prefetched_entry_notify(H5C_notify_action_t action, void *_thing)
+{
+ H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)_thing;
+ unsigned u;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->prefetched);
+
+ switch(action) {
+ case H5C_NOTIFY_ACTION_AFTER_INSERT:
+ case H5C_NOTIFY_ACTION_AFTER_LOAD:
+ case H5C_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5C_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5C_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5C_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5C_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5C_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5C_NOTIFY_ACTION_BEFORE_EVICT:
+ for(u = 0; u < entry_ptr->flush_dep_nparents; u++) {
+ H5C_cache_entry_t * parent_ptr;
+
+ /* Sanity checks */
+ HDassert(entry_ptr->flush_dep_parent);
+ parent_ptr = entry_ptr->flush_dep_parent[u];
+ HDassert(parent_ptr);
+ HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(parent_ptr->flush_dep_nchildren > 0);
+
+ /* Destroy flush dependency with flush dependency parent */
+ if(H5C_destroy_flush_dependency(parent_ptr, entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "unable to destroy prefetched entry flush dependency")
+
+ if(parent_ptr->prefetched) {
+ /* In prefetched entries, the fd_child_count field is
+ * used in sanity checks elsewhere. Thus update this
+ * field to reflect the destruction of the flush
+ * dependency relationship.
+ */
+ HDassert(parent_ptr->fd_child_count > 0);
+ (parent_ptr->fd_child_count)--;
+ } /* end if */
+ } /* end for */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5C__prefetched_entry_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__prefetched_entry_free_icr
+ *
+ * Purpose: Free the in core representation of the prefetched entry.
+ * Verify that the image buffer associated with the entry
+ * has been either transferred or freed.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 8/13/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__prefetched_entry_free_icr(void *_thing)
+{
+ H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(entry_ptr->prefetched);
+
+ /* Release array for flush dependency parent addresses */
+ if(entry_ptr->fd_parent_addrs != NULL) {
+ HDassert(entry_ptr->fd_parent_count > 0);
+ entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree((void *)entry_ptr->fd_parent_addrs);
+ } /* end if */
+ else
+ HDassert(entry_ptr->fd_parent_count == 0);
+
+ if(entry_ptr->image_ptr != NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "prefetched entry image buffer still attatched?")
+
+ entry_ptr = H5FL_FREE(H5C_cache_entry_t, entry_ptr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5C__prefetched_entry_free_icr() */
+
+
+static herr_t
+H5C__prefetched_entry_fsf_size(const void H5_ATTR_UNUSED *thing,
+ size_t H5_ATTR_UNUSED *fsf_size_ptr)
+{
+ FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */
+
+ HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn.");
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* end H5C__prefetched_entry_fsf_size() */
+
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
new file mode 100644
index 0000000..5335f80
--- /dev/null
+++ b/src/H5Cprivate.h
@@ -0,0 +1,2355 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cprivate.h
+ * 6/3/04
+ * John Mainzer
+ *
+ * Purpose: Constants and typedefs available to the rest of the
+ * library.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5Cprivate_H
+#define _H5Cprivate_H
+
+#include "H5Cpublic.h" /* public prototypes */
+
+/* Private headers needed by this header */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* File access */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Cache configuration settings */
+#define H5C__MAX_NUM_TYPE_IDS 30
+#define H5C__PREFIX_LEN 32
+
+/* This sanity checking constant was picked out of the air. Increase
+ * or decrease it if appropriate. Its purposes is to detect corrupt
+ * object sizes, so it probably doesn't matter if it is a bit big.
+ *
+ * JRM - 5/17/04
+ */
+#define H5C_MAX_ENTRY_SIZE ((size_t)(32 * 1024 * 1024))
+
+#ifdef H5_HAVE_PARALLEL
+/* we must maintain the clean and dirty LRU lists when we are compiled
+ * with parallel support.
+ */
+#define H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS 1
+#else /* H5_HAVE_PARALLEL */
+/* The clean and dirty LRU lists don't buy us anything here -- we may
+ * want them on for testing on occasion, but in general they should be
+ * off.
+ */
+#define H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS 0
+#endif /* H5_HAVE_PARALLEL */
+
+/* Flags for cache client class behavior */
+#define H5C__CLASS_NO_FLAGS_SET ((unsigned)0x0)
+#define H5C__CLASS_SPECULATIVE_LOAD_FLAG ((unsigned)0x1)
+/* The following flags may only appear in test code */
+#define H5C__CLASS_SKIP_READS ((unsigned)0x2)
+#define H5C__CLASS_SKIP_WRITES ((unsigned)0x4)
+
+/* Flags for pre-serialize callback */
+#define H5C__SERIALIZE_NO_FLAGS_SET ((unsigned)0)
+#define H5C__SERIALIZE_RESIZED_FLAG ((unsigned)0x1)
+#define H5C__SERIALIZE_MOVED_FLAG ((unsigned)0x2)
+
+/* Upper and lower limits on cache size. These limits are picked
+ * out of a hat -- you should be able to change them as necessary.
+ *
+ * However, if you need a very big cache, you should also increase the
+ * size of the hash table (H5C__HASH_TABLE_LEN in H5Cpkg.h). The current
+ * upper bound on cache size is rather large for the current hash table
+ * size.
+ */
+#define H5C__MAX_MAX_CACHE_SIZE ((size_t)(128 * 1024 * 1024))
+#define H5C__MIN_MAX_CACHE_SIZE ((size_t)(1024))
+
+/* Default max cache size and min clean size are give here to make
+ * them generally accessable.
+ */
+#define H5C__DEFAULT_MAX_CACHE_SIZE ((size_t)(4 * 1024 * 1024))
+#define H5C__DEFAULT_MIN_CLEAN_SIZE ((size_t)(2 * 1024 * 1024))
+
+/* Values for cache entry magic field */
+#define H5C__H5C_CACHE_ENTRY_T_MAGIC 0x005CAC0A
+#define H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC 0xDeadBeef
+
+/* Cache configuration validation definitions */
+#define H5C_RESIZE_CFG__VALIDATE_GENERAL 0x1
+#define H5C_RESIZE_CFG__VALIDATE_INCREMENT 0x2
+#define H5C_RESIZE_CFG__VALIDATE_DECREMENT 0x4
+#define H5C_RESIZE_CFG__VALIDATE_INTERACTIONS 0x8
+#define H5C_RESIZE_CFG__VALIDATE_ALL \
+( \
+ H5C_RESIZE_CFG__VALIDATE_GENERAL | \
+ H5C_RESIZE_CFG__VALIDATE_INCREMENT | \
+ H5C_RESIZE_CFG__VALIDATE_DECREMENT | \
+ H5C_RESIZE_CFG__VALIDATE_INTERACTIONS \
+)
+
+/* Cache configuration versions */
+#define H5C__CURR_AUTO_SIZE_CTL_VER 1
+#define H5C__CURR_AUTO_RESIZE_RPT_FCN_VER 1
+#define H5C__CURR_CACHE_IMAGE_CTL_VER 1
+
+/* Default configuration settings */
+#define H5C__DEF_AR_UPPER_THRESHHOLD 0.9999f
+#define H5C__DEF_AR_LOWER_THRESHHOLD 0.9f
+#define H5C__DEF_AR_MAX_SIZE ((size_t)(16 * 1024 * 1024))
+#define H5C__DEF_AR_INIT_SIZE ((size_t)( 1 * 1024 * 1024))
+#define H5C__DEF_AR_MIN_SIZE ((size_t)( 1 * 1024 * 1024))
+#define H5C__DEF_AR_MIN_CLEAN_FRAC 0.5f
+#define H5C__DEF_AR_INCREMENT 2.0f
+#define H5C__DEF_AR_MAX_INCREMENT ((size_t)( 2 * 1024 * 1024))
+#define H5C__DEF_AR_FLASH_MULTIPLE 1.0f
+#define H5C__DEV_AR_FLASH_THRESHOLD 0.25f
+#define H5C__DEF_AR_DECREMENT 0.9f
+#define H5C__DEF_AR_MAX_DECREMENT ((size_t)( 1 * 1024 * 1024))
+#define H5C__DEF_AR_EPCHS_B4_EVICT 3
+#define H5C__DEF_AR_EMPTY_RESERVE 0.05f
+#define H5C__MIN_AR_EPOCH_LENGTH 100
+#define H5C__DEF_AR_EPOCH_LENGTH 50000
+#define H5C__MAX_AR_EPOCH_LENGTH 1000000
+
+/* #defines of flags used in the flags parameters in some of the
+ * following function calls. Note that not all flags are applicable
+ * to all function calls. Flags that don't apply to a particular
+ * function are ignored in that function.
+ *
+ * These flags apply to all function calls:
+ * H5C__NO_FLAGS_SET (generic "no flags set" for all fcn calls)
+ *
+ *
+ * These flags apply to H5C_insert_entry():
+ * H5C__SET_FLUSH_MARKER_FLAG
+ * H5C__PIN_ENTRY_FLAG
+ * H5C__FLUSH_LAST_FLAG ; super block only
+ * H5C__FLUSH_COLLECTIVELY_FLAG ; super block only
+ *
+ * These flags apply to H5C_protect()
+ * H5C__READ_ONLY_FLAG
+ * H5C__FLUSH_LAST_FLAG ; super block only
+ * H5C__FLUSH_COLLECTIVELY_FLAG ; super block only
+ *
+ * These flags apply to H5C_unprotect():
+ * H5C__SET_FLUSH_MARKER_FLAG
+ * H5C__DELETED_FLAG
+ * H5C__DIRTIED_FLAG
+ * H5C__PIN_ENTRY_FLAG
+ * H5C__UNPIN_ENTRY_FLAG
+ * H5C__FREE_FILE_SPACE_FLAG
+ * H5C__TAKE_OWNERSHIP_FLAG
+ *
+ * These flags apply to H5C_expunge_entry():
+ * H5C__FREE_FILE_SPACE_FLAG
+ *
+ * These flags apply to H5C_evict():
+ * H5C__EVICT_ALLOW_LAST_PINS_FLAG
+ *
+ * These flags apply to H5C_flush_cache():
+ * H5C__FLUSH_INVALIDATE_FLAG
+ * H5C__FLUSH_CLEAR_ONLY_FLAG
+ * H5C__FLUSH_MARKED_ENTRIES_FLAG
+ * H5C__FLUSH_IGNORE_PROTECTED_FLAG (can't use this flag in combination
+ * with H5C__FLUSH_INVALIDATE_FLAG)
+ * H5C__DURING_FLUSH_FLAG
+ *
+ * These flags apply to H5C_flush_single_entry():
+ * H5C__FLUSH_INVALIDATE_FLAG
+ * H5C__FLUSH_CLEAR_ONLY_FLAG
+ * H5C__FLUSH_MARKED_ENTRIES_FLAG
+ * H5C__TAKE_OWNERSHIP_FLAG
+ * H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG
+ * H5C__GENERATE_IMAGE_FLAG
+ * H5C__UPDATE_PAGE_BUFFER_FLAG
+ */
+#define H5C__NO_FLAGS_SET 0x00000
+#define H5C__SET_FLUSH_MARKER_FLAG 0x00001
+#define H5C__DELETED_FLAG 0x00002
+#define H5C__DIRTIED_FLAG 0x00004
+#define H5C__PIN_ENTRY_FLAG 0x00008
+#define H5C__UNPIN_ENTRY_FLAG 0x00010
+#define H5C__FLUSH_INVALIDATE_FLAG 0x00020
+#define H5C__FLUSH_CLEAR_ONLY_FLAG 0x00040
+#define H5C__FLUSH_MARKED_ENTRIES_FLAG 0x00080
+#define H5C__FLUSH_IGNORE_PROTECTED_FLAG 0x00100
+#define H5C__READ_ONLY_FLAG 0x00200
+#define H5C__FREE_FILE_SPACE_FLAG 0x00400
+#define H5C__TAKE_OWNERSHIP_FLAG 0x00800
+#define H5C__FLUSH_LAST_FLAG 0x01000
+#define H5C__FLUSH_COLLECTIVELY_FLAG 0x02000
+#define H5C__EVICT_ALLOW_LAST_PINS_FLAG 0x04000
+#define H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG 0x08000
+#define H5C__DURING_FLUSH_FLAG 0x10000 /* Set when the entire cache is being flushed */
+#define H5C__GENERATE_IMAGE_FLAG 0x20000 /* Set during parallel I/O */
+#define H5C__UPDATE_PAGE_BUFFER_FLAG 0x40000 /* Set during parallel I/O */
+
+/* Debugging/sanity checking/statistics settings */
+#ifndef NDEBUG
+#define H5C_DO_SANITY_CHECKS 1
+#define H5C_DO_SLIST_SANITY_CHECKS 0
+#define H5C_DO_TAGGING_SANITY_CHECKS 1
+#define H5C_DO_EXTREME_SANITY_CHECKS 0
+#else /* NDEBUG */
+/* With rare execptions, the following defines should be set
+ * to 0 if NDEBUG is defined
+ */
+#define H5C_DO_SANITY_CHECKS 0
+#define H5C_DO_SLIST_SANITY_CHECKS 0
+#define H5C_DO_TAGGING_SANITY_CHECKS 0
+#define H5C_DO_EXTREME_SANITY_CHECKS 0
+#endif /* NDEBUG */
+
+/* Cork actions: cork/uncork/get cork status of an object */
+#define H5C__SET_CORK 0x1
+#define H5C__UNCORK 0x2
+#define H5C__GET_CORKED 0x4
+
+/* Note: The memory sanity checks aren't going to work until I/O filters are
+ * changed to call a particular alloc/free routine for their buffers,
+ * because the H5AC__SERIALIZE_RESIZED_FLAG set by the fractal heap
+ * direct block serialize callback calls H5Z_pipeline(). When the I/O
+ * filters are changed, then we should implement "cache image alloc/free"
+ * routines that the fractal heap direct block (and global heap) serialize
+ * calls can use when resizing (and re-allocating) their image in the
+ * cache. -QAK */
+#define H5C_DO_MEMORY_SANITY_CHECKS 0
+
+/* H5C_COLLECT_CACHE_STATS controls overall collection of statistics
+ * on cache activity. In general, this #define should be set to 1 in
+ * debug mode, and 0 in production mode..
+ */
+
+#ifndef NDEBUG
+#define H5C_COLLECT_CACHE_STATS 1
+#else /* NDEBUG */
+#define H5C_COLLECT_CACHE_STATS 0
+#endif /* NDEBUG */
+
+/* H5C_COLLECT_CACHE_ENTRY_STATS controls collection of statistics
+ * in individual cache entries.
+ *
+ * H5C_COLLECT_CACHE_ENTRY_STATS should only be defined to true if
+ * H5C_COLLECT_CACHE_STATS is also defined to true.
+ */
+#if H5C_COLLECT_CACHE_STATS
+#define H5C_COLLECT_CACHE_ENTRY_STATS 1
+#else
+#define H5C_COLLECT_CACHE_ENTRY_STATS 0
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Typedef for the main structure for the cache (defined in H5Cpkg.h) */
+typedef struct H5C_t H5C_t;
+
+/*
+ *
+ * Struct H5C_class_t
+ *
+ * Instances of H5C_class_t are used to specify the callback functions
+ * used by the metadata cache for each class of metadata cache entry.
+ * The fields of the structure are discussed below:
+ *
+ * id: Integer field containing the unique ID of the class of metadata
+ * cache entries.
+ *
+ * name: Pointer to a string containing the name of the class of metadata
+ * cache entries.
+ *
+ * mem_type: Instance of H5FD_mem_t, that is used to supply the
+ * mem type passed into H5F_block_read().
+ *
+ * flags: Flags indicating class-specific behavior.
+ *
+ * Possible flags are:
+ *
+ * H5C__CLASS_NO_FLAGS_SET: No special processing.
+ *
+ * H5C__CLASS_SPECULATIVE_LOAD_FLAG: This flag is used only in
+ * H5C_load_entry(). When it is set, entries are
+ * permitted to change their sizes on the first attempt
+ * to load.
+ *
+ * If the new size is larger than the old, the read buffer
+ * is reallocated to the new size, loaded from file, and the
+ * deserialize routine is called a second time on the
+ * new buffer. The entry returned by the first call to
+ * the deserialize routine is discarded (via the free_icr
+ * call) after the new size is retrieved (via the image_len
+ * call). Note that the new size is used as the size of the
+ * entry in the cache.
+ *
+ * If the new size is smaller than the old, no new loads
+ * or deserializes are performed, but the new size becomes
+ * the size of the entry in the cache.
+ *
+ * When this flag is set, an attempt to read past the
+ * end of file could occur. In this case, if the size
+ * returned get_load_size callback would result in a
+ * read past the end of file, the size is truncated to
+ * avoid this, and processing proceeds as normal.
+ *
+ * The following flags may only appear in test code.
+ *
+ * H5C__CLASS_SKIP_READS: This flags is intended only for use in test
+ * code. When it is set, reads on load will be skipped,
+ * and an uninitialize buffer will be passed to the
+ * deserialize function.
+ *
+ * H5C__CLASS_SKIP_WRITES: This flags is intended only for use in test
+ * code. When it is set, writes of buffers prepared by the
+ * serialize callback will be skipped.
+ *
+ * GET_INITIAL_LOAD_SIZE: Pointer to the 'get initial load size' function.
+ *
+ * This function determines the size based on the information in the
+ * parameter "udata" or an initial speculative guess. The size is
+ * returned in the parameter "image_len_ptr".
+ *
+ * For an entry with H5C__CLASS_NO_FLAGS_SET:
+ * This function returns in "image_len_ptr" the on disk size of the
+ * entry.
+ *
+ * For an entry with H5C__CLASS_SPECULATIVE_LOAD_FLAG:
+ * This function returns in "image_len_ptr" an initial guess of the
+ * entry's on disk size. This many bytes will be loaded from
+ * the file and then passed to 'get_final_load_size' callback
+ * for the actual (final) image length to be determined.
+ *
+ * The typedef for the get_initial_load_size callback is as follows:
+ *
+ * typedef herr_t (*H5C_get_initial_load_size_func_t)(void *udata_ptr,
+ * size_t *image_len_ptr);
+ *
+ * The parameters of the get_initial_load_size callback are as follows:
+ *
+ * udata_ptr: Pointer to user data provided in the protect call, which
+ * will also be passed through to the 'get_final_load_size',
+ * 'verify_chksum', and 'deserialize' callbacks.
+ *
+ * image_len_ptr: Pointer to the length in bytes of the in-file image to
+ * be deserialized is to be returned.
+ *
+ * This value is used by the cache to determine the size of
+ * the disk image for the metadata, in order to read the disk
+ * image from the file.
+ *
+ * Processing in the get_load_size function should proceed as follows:
+ *
+ * If successful, the function will place the length in the *image_len_ptr
+ * associated with supplied user data and then return SUCCEED.
+ *
+ * On failure, the function must return FAIL and push error information
+ * onto the error stack with the error API routines, without modifying
+ * the value pointed to by image_len_ptr.
+ *
+ *
+ * GET_FINAL_LOAD_SIZE: Pointer to the 'get final load size' function.
+ *
+ * This function determines the final size of a speculatively loaded
+ * metadata cache entry based on the parameter "image" and the "udata"
+ * parameters. This callback _must_ be implemented for cache clients
+ * which set the H5C__CLASS_SPECULATIVE_LOAD_FLAG and must return the
+ * actual length of on-disk image after being called once.
+ *
+ * This function might deserialize the needed metadata information to
+ * determine the actual size. The size is returned in the parameter
+ * "actual_len_ptr".
+ *
+ * The typedef for the get_load_size callback is as follows:
+ *
+ * typedef herr_t (*H5C_get_final_load_size_func_t)(const void *image_ptr,
+ * size_t image_len,
+ * void *udata_ptr,
+ * size_t *actual_len_ptr);
+ *
+ * The parameters of the get_load_size callback are as follows:
+ *
+ * image_ptr: Pointer to a buffer containing the (possibly partial)
+ * metadata read in.
+ *
+ * image_len: The length in bytes of the (possibly partial) in-file image
+ * to be queried for an actual length.
+ *
+ * udata_ptr: Pointer to user data provided in the protect call, which
+ * will also be passed through to the 'verify_chksum' and
+ * 'deserialize' callbacks.
+ *
+ * actual_len_ptr: Pointer to the location containing the actual length
+ * of the metadata entry on disk.
+ *
+ * Processing in the get_final_load_size function should proceed as follows:
+ *
+ * If successful, the function will place the length in the *actual_len_ptr
+ * associated with supplied image and/or user data and then return SUCCEED.
+ *
+ * On failure, the function must return FAIL and push error information
+ * onto the error stack with the error API routines, without modifying
+ * the value pointed to by actual_len_ptr.
+ *
+ *
+ * VERIFY_CHKSUM: Pointer to the verify_chksum function.
+ *
+ * This function verifies the checksum computed for the metadata is
+ * the same as the checksum stored in the metadata.
+ *
+ * It computes the checksum based on the metadata stored in the
+ * parameter "image_ptr" and the actual length of the metadata in the
+ * parameter "len" which is obtained from the "get_load_size" callback.
+ *
+ * The typedef for the verify_chksum callback is as follows:
+ *
+ * typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr,
+ * size_t len,
+ * void *udata_ptr);
+ *
+ * The parameters of the verify_chksum callback are as follows:
+ *
+ * image_ptr: Pointer to a buffer containing the metadata read in.
+ *
+ * len: The actual length of the metadata.
+ *
+ * udata_ptr: Pointer to user data.
+ *
+ *
+ * DESERIALIZE: Pointer to the deserialize function.
+ *
+ * This function must be able to deserialize a buffer containing the
+ * on-disk image of a metadata cache entry, allocate and initialize the
+ * equivalent in core representation, and return a pointer to that
+ * representation.
+ *
+ * The typedef for the deserialize callback is as follows:
+ *
+ * typedef void *(*H5C_deserialize_func_t)(const void * image_ptr,
+ * size_t len,
+ * void * udata_ptr,
+ * boolean * dirty_ptr);
+ *
+ * The parameters of the deserialize callback are as follows:
+ *
+ * image_ptr: Pointer to a buffer of length len containing the
+ * contents of the file starting at addr and continuing
+ * for len bytes.
+ *
+ * len: Length in bytes of the in file image to be deserialized.
+ *
+ * This parameter is supplied mainly for sanity checking.
+ * Sanity checks should be performed when compiled in debug
+ * mode, but the parameter may be unused when compiled in
+ * production mode.
+ *
+ * udata_ptr: Pointer to user data provided in the protect call, which
+ * must be passed through to the deserialize callback.
+ *
+ * dirty_ptr: Pointer to boolean which the deserialize function
+ * must use to mark the entry dirty if it has to modify
+ * the entry to clean up file corruption left over from
+ * an old bug in the HDF5 library.
+ *
+ * Processing in the deserialize function should proceed as follows:
+ *
+ * If the image contains valid data, and is of the correct length,
+ * the deserialize function must allocate space for an in-core
+ * representation of that data, deserialize the contents of the image
+ * into the space allocated for the in-core representation, and return
+ * a pointer to the in core representation. Observe that an
+ * instance of H5C_cache_entry_t must be the first item in this
+ * representation. The cache will initialize it after the callback
+ * returns.
+ *
+ * Note that the structure of the in-core representation is otherwise
+ * up to the cache client. All that is required is that the pointer
+ * returned be sufficient for the client's purposes when it is returned
+ * on a protect call.
+ *
+ * If the deserialize function has to clean up file corruption
+ * left over from an old bug in the HDF5 library, it must set
+ * *dirty_ptr to TRUE. If it doesn't, no action is needed as
+ * *dirty_ptr will be set to FALSE before the deserialize call.
+ *
+ * If the operation fails for any reason (i.e. bad data in buffer, bad
+ * buffer length, malloc failure, etc.) the function must return NULL and
+ * push error information on the error stack with the error API routines.
+ *
+ *
+ * IMAGE_LEN: Pointer to the image length callback.
+ *
+ * The image_len callback is used to obtain the size of newly inserted
+ * entries and assert verification.
+ *
+ * The typedef for the image_len callback is as follows:
+ *
+ * typedef herr_t (*H5C_image_len_func_t)(void *thing,
+ * size_t *image_len_ptr);
+ *
+ * The parameters of the image_len callback are as follows:
+ *
+ * thing: Pointer to the in core representation of the entry.
+ *
+ * image_len_ptr: Pointer to size_t in which the callback will return
+ * the length (in bytes) of the cache entry.
+ *
+ * Processing in the image_len function should proceed as follows:
+ *
+ * If successful, the function will place the length of the on disk
+ * image associated with the in core representation provided in the
+ * thing parameter in *image_len_ptr, and then return SUCCEED.
+ *
+ * If the function fails, it must return FAIL and push error information
+ * onto the error stack with the error API routines, and return without
+ * modifying the values pointed to by the image_len_ptr parameter.
+ *
+ *
+ * PRE_SERIALIZE: Pointer to the pre-serialize callback.
+ *
+ * The pre-serialize callback is invoked by the metadata cache before
+ * it needs a current on-disk image of the metadata entry for purposes
+ * either constructing a journal or flushing the entry to disk.
+ *
+ * If the client needs to change the address or length of the entry prior
+ * to flush, the pre-serialize callback is responsible for these actions,
+ * so that the actual serialize callback (described below) is only
+ * responsible for serializing the data structure, not moving it on disk
+ * or resizing it.
+ *
+ * In addition, the client may use the pre-serialize callback to
+ * ensure that the entry is ready to be flushed -- in particular,
+ * if the entry contains references to other entries that are in
+ * temporary file space, the pre-serialize callback must move those
+ * entries into real file space so that the serialzed entry will
+ * contain no invalid data.
+ *
+ * One would think that the base address and length of
+ * the length of the entry's image on disk would be well known.
+ * However, that need not be the case as free space section info
+ * entries will change size (and possibly location) depending on the
+ * number of blocks of free space being manages, and fractal heap
+ * direct blocks can change compressed size (and possibly location)
+ * on serialization if compression is enabled. Similarly, it may
+ * be necessary to move entries from temporary to real file space.
+ *
+ * The pre-serialize callback must report any such changes to the
+ * cache, which must then update its internal structures as needed.
+ *
+ * The typedef for the pre-serialize callback is as follows:
+ *
+ * typedef herr_t (*H5C_pre_serialize_func_t)(H5F_t *f,
+ * hid_t dxpl_id,
+ * void * thing,
+ * haddr_t addr,
+ * size_t len,
+ * haddr_t * new_addr_ptr,
+ * size_t * new_len_ptr,
+ * unsigned * flags_ptr);
+ *
+ * The parameters of the pre-serialize callback are as follows:
+ *
+ * f: File pointer -- needed if other metadata cache entries
+ * must be modified in the process of serializing the
+ * target entry.
+ *
+ * dxpl_id: dxpl_id passed with the file pointer to the cache, and
+ * passed on to the callback. Necessary as some callbacks
+ * revise the size and location of the target entry, or
+ * possibly other entries on pre-serialize.
+ *
+ * thing: Pointer to void containing the address of the in core
+ * representation of the target metadata cache entry.
+ * This is the same pointer returned by a protect of the
+ * addr and len given above.
+ *
+ * addr: Base address in file of the entry to be serialized.
+ *
+ * This parameter is supplied mainly for sanity checking.
+ * Sanity checks should be performed when compiled in debug
+ * mode, but the parameter may be unused when compiled in
+ * production mode.
+ *
+ * len: Length in bytes of the in file image of the entry to be
+ * serialized. Also the size the image passed to the
+ * serialize callback (discussed below) unless that
+ * value is altered by this function.
+ *
+ * This parameter is supplied mainly for sanity checking.
+ * Sanity checks should be performed when compiled in debug
+ * mode, but the parameter may be unused when compiled in
+ * production mode.
+ *
+ * new_addr_ptr: Pointer to haddr_t. If the entry is moved by
+ * the serialize function, the new on disk base address must
+ * be stored in *new_addr_ptr, and the appropriate flag set
+ * in *flags_ptr.
+ *
+ * If the entry is not moved by the serialize function,
+ * *new_addr_ptr is undefined on pre-serialize callback
+ * return.
+ *
+ * new_len_ptr: Pointer to size_t. If the entry is resized by the
+ * serialize function, the new length of the on disk image
+ * must be stored in *new_len_ptr, and the appropriate flag set
+ * in *flags_ptr.
+ *
+ * If the entry is not resized by the pre-serialize function,
+ * *new_len_ptr is undefined on pre-serialize callback
+ * return.
+ *
+ * flags_ptr: Pointer to an unsigned integer used to return flags
+ * indicating whether the preserialize function resized or moved
+ * the entry. If the entry was neither resized or moved, the
+ * serialize function must set *flags_ptr to zero. The
+ * H5C__SERIALIZE_RESIZED_FLAG or H5C__SERIALIZE_MOVED_FLAG must
+ * be set to indicate a resize or move respectively.
+ *
+ * If the H5C__SERIALIZE_RESIZED_FLAG is set, the new length
+ * must be stored in *new_len_ptr.
+ *
+ * If the H5C__SERIALIZE_MOVED_FLAG flag is set, the
+ * new image base address must be stored in *new_addr_ptr.
+ *
+ * Processing in the pre-serialize function should proceed as follows:
+ *
+ * The pre-serialize function must examine the in core representation
+ * indicated by the thing parameter, if the pre-serialize function does
+ * not need to change the size or location of the on-disk image, it must
+ * set *flags_ptr to zero.
+ *
+ * If the size of the on-disk image must be changed, the pre-serialize
+ * function must load the length of the new image into *new_len_ptr, and
+ * set the H5C__SERIALIZE_RESIZED_FLAG in *flags_ptr.
+ *
+ * If the base address of the on disk image must be changed, the
+ * pre-serialize function must set *new_addr_ptr to the new base address,
+ * and set the H5C__SERIALIZE_MOVED_FLAG in *flags_ptr.
+ *
+ * In addition, the pre-serialize callback may perform any other
+ * processing required before the entry is written to disk
+ *
+ * If it is successful, the function must return SUCCEED.
+ *
+ * If it fails for any reason, the function must return FAIL and
+ * push error information on the error stack with the error API
+ * routines.
+ *
+ *
+ * SERIALIZE: Pointer to the serialize callback.
+ *
+ * The serialize callback is invoked by the metadata cache whenever
+ * it needs a current on disk image of the metadata entry for purposes
+ * either constructing a journal entry or flushing the entry to disk.
+ *
+ * At this point, the base address and length of the entry's image on
+ * disk must be well known and not change during the serialization
+ * process.
+ *
+ * While any size and/or location changes must have been handled
+ * by a pre-serialize call, the client may elect to handle any other
+ * changes to the entry required to place it in correct form for
+ * writing to disk in this call.
+ *
+ * The typedef for the serialize callback is as follows:
+ *
+ * typedef herr_t (*H5C_serialize_func_t)(const H5F_t *f,
+ * void * image_ptr,
+ * size_t len,
+ * void * thing);
+ *
+ * The parameters of the serialize callback are as follows:
+ *
+ * f: File pointer -- needed if other metadata cache entries
+ * must be modified in the process of serializing the
+ * target entry.
+ *
+ * image_ptr: Pointer to a buffer of length len bytes into which a
+ * serialized image of the target metadata cache entry is
+ * to be written.
+ *
+ * Note that this buffer will not in general be initialized
+ * to any particular value. Thus the serialize function may
+ * not assume any initial value and must set each byte in
+ * the buffer.
+ *
+ * len: Length in bytes of the in file image of the entry to be
+ * serialized. Also the size of *image_ptr (below).
+ *
+ * This parameter is supplied mainly for sanity checking.
+ * Sanity checks should be performed when compiled in debug
+ * mode, but the parameter may be unused when compiled in
+ * production mode.
+ *
+ * thing: Pointer to void containing the address of the in core
+ * representation of the target metadata cache entry.
+ * This is the same pointer returned by a protect of the
+ * addr and len given above.
+ *
+ * Processing in the serialize function should proceed as follows:
+ *
+ * If there are any remaining changes to the entry required before
+ * write to disk, they must be dealt with first.
+ *
+ * The serialize function must then examine the in core
+ * representation indicated by the thing parameter, and write a
+ * serialized image of its contents into the provided buffer.
+ *
+ * If it is successful, the function must return SUCCEED.
+ *
+ * If it fails for any reason, the function must return FAIL and
+ * push error information on the error stack with the error API
+ * routines.
+ *
+ *
+ * NOTIFY: Pointer to the notify callback.
+ *
+ * The notify callback is invoked by the metadata cache when a cache
+ * action on an entry has taken/will take place and the client indicates
+ * it wishes to be notified about the action.
+ *
+ * The typedef for the notify callback is as follows:
+ *
+ * typedef herr_t (*H5C_notify_func_t)(H5C_notify_action_t action,
+ * void *thing);
+ *
+ * The parameters of the notify callback are as follows:
+ *
+ * action: An enum indicating the metadata cache action that has taken/
+ * will take place.
+ *
+ * thing: Pointer to void containing the address of the in core
+ * representation of the target metadata cache entry. This
+ * is the same pointer that would be returned by a protect
+ * of the addr and len of the entry.
+ *
+ * Processing in the notify function should proceed as follows:
+ *
+ * The notify function may perform any action it would like, including
+ * metadata cache calls.
+ *
+ * If the function is successful, it must return SUCCEED.
+ *
+ * If it fails for any reason, the function must return FAIL and
+ * push error information on the error stack with the error API
+ * routines.
+ *
+ *
+ * FREE_ICR: Pointer to the free ICR callback.
+ *
+ * The free ICR callback is invoked by the metadata cache when it
+ * wishes to evict an entry, and needs the client to free the memory
+ * allocated for the in core representation.
+ *
+ * The typedef for the free ICR callback is as follows:
+ *
+ * typedef herr_t (*H5C_free_icr_func_t)(void * thing));
+ *
+ * The parameters of the free ICR callback are as follows:
+ *
+ * thing: Pointer to void containing the address of the in core
+ * representation of the target metadata cache entry. This
+ * is the same pointer that would be returned by a protect
+ * of the addr and len of the entry.
+ *
+ * Processing in the free ICR function should proceed as follows:
+ *
+ * The free ICR function must free all memory allocated to the
+ * in core representation.
+ *
+ * If the function is successful, it must return SUCCEED.
+ *
+ * If it fails for any reason, the function must return FAIL and
+ * push error information on the error stack with the error API
+ * routines.
+ *
+ * At least when compiled with debug, it would be useful if the
+ * free ICR call would fail if the in core representation has been
+ * modified since the last serialize callback.
+ *
+ * GET_FSF_SIZE: Pointer to the get file space free size callback.
+ *
+ * In principle, there is no need for the get file space free size
+ * callback. However, as an optimization, it is sometimes convenient
+ * to allocate and free file space for a number of cache entries
+ * simultaneously in a single contiguous block of file space.
+ *
+ * File space allocation is done by the client, so the metadata cache
+ * need not be involved. However, since the metadata cache typically
+ * handles file space release when an entry is destroyed, some
+ * adjustment on the part of the metadata cache is required for this
+ * operation.
+ *
+ * The get file space free size callback exists to support this
+ * operation.
+ *
+ * If a group of cache entries that were allocated as a group are to
+ * be discarded and their file space released, the type of the first
+ * (i.e. lowest address) entry in the group must implement the
+ * get free file space size callback.
+ *
+ * To free the file space of all entries in the group in a single
+ * operation, first expunge all entries other than the first without
+ * the free file space flag.
+ *
+ * Then, to complete the operation, unprotect or expunge the first
+ * entry in the block with the free file space flag set. Since
+ * the get free file space callback is implemented, the metadata
+ * cache will use this callback to get the size of the block to be
+ * freed, instead of using the size of the entry as is done otherwise.
+ *
+ * At present this callback is used only by the H5FA and H5EA dblock
+ * and dblock page client classes.
+ *
+ * The typedef for the get_fsf_size callback is as follows:
+ *
+ * typedef herr_t (*H5C_get_fsf_size_t)(const void * thing,
+ * size_t *fsf_size_ptr);
+ *
+ * The parameters of the get_fsf_size callback are as follows:
+ *
+ * thing: Pointer to void containing the address of the in core
+ * representation of the target metadata cache entry. This
+ * is the same pointer that would be returned by a protect()
+ * call of the associated addr and len.
+ *
+ * fs_size_ptr: Pointer to size_t in which the callback will return
+ * the size of the piece of file space to be freed. Note
+ * that the space to be freed is presumed to have the same
+ * base address as the cache entry.
+ *
+ * The function simply returns the size of the block of file space
+ * to be freed in *fsf_size_ptr.
+ *
+ * If the function is successful, it must return SUCCEED.
+ *
+ * If it fails for any reason, the function must return FAIL and
+ * push error information on the error stack with the error API
+ * routines.
+ *
+ ***************************************************************************/
+
+/* Actions that can be reported to 'notify' client callback */
+typedef enum H5C_notify_action_t {
+ H5C_NOTIFY_ACTION_AFTER_INSERT, /* Entry has been added to the cache
+ * via the insert call
+ */
+ H5C_NOTIFY_ACTION_AFTER_LOAD, /* Entry has been loaded into the
+ * from file via the protect call
+ */
+ H5C_NOTIFY_ACTION_AFTER_FLUSH, /* Entry has just been flushed to
+ * file.
+ */
+ H5C_NOTIFY_ACTION_BEFORE_EVICT, /* Entry is about to be evicted
+ * from cache.
+ */
+ H5C_NOTIFY_ACTION_ENTRY_DIRTIED, /* Entry has been marked dirty. */
+ H5C_NOTIFY_ACTION_ENTRY_CLEANED, /* Entry has been marked clean. */
+ H5C_NOTIFY_ACTION_CHILD_DIRTIED, /* Dependent child has been marked dirty. */
+ H5C_NOTIFY_ACTION_CHILD_CLEANED, /* Dependent child has been marked clean. */
+ H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED, /* Dependent child has been marked unserialized. */
+ H5C_NOTIFY_ACTION_CHILD_SERIALIZED /* Dependent child has been marked serialized. */
+} H5C_notify_action_t;
+
+/* Cache client callback function pointers */
+typedef herr_t (*H5C_get_initial_load_size_func_t)(void *udata_ptr, size_t *image_len_ptr);
+typedef herr_t (*H5C_get_final_load_size_func_t)(const void *image_ptr,
+ size_t image_len, void *udata_ptr, size_t *actual_len_ptr);
+typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr, size_t len, void *udata_ptr);
+typedef void *(*H5C_deserialize_func_t)(const void *image_ptr,
+ size_t len, void *udata_ptr, hbool_t *dirty_ptr);
+typedef herr_t (*H5C_image_len_func_t)(const void *thing, size_t *image_len_ptr);
+typedef herr_t (*H5C_pre_serialize_func_t)(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr_ptr,
+ size_t *new_len_ptr, unsigned *flags_ptr);
+typedef herr_t (*H5C_serialize_func_t)(const H5F_t *f, void *image_ptr,
+ size_t len, void *thing);
+typedef herr_t (*H5C_notify_func_t)(H5C_notify_action_t action, void *thing);
+typedef herr_t (*H5C_free_icr_func_t)(void *thing);
+typedef herr_t (*H5C_get_fsf_size_t)(const void * thing, size_t *fsf_size_ptr);
+
+/* Metadata cache client class definition */
+typedef struct H5C_class_t {
+ int id;
+ const char * name;
+ H5FD_mem_t mem_type;
+ unsigned flags;
+ H5C_get_initial_load_size_func_t get_initial_load_size;
+ H5C_get_final_load_size_func_t get_final_load_size;
+ H5C_verify_chksum_func_t verify_chksum;
+ H5C_deserialize_func_t deserialize;
+ H5C_image_len_func_t image_len;
+ H5C_pre_serialize_func_t pre_serialize;
+ H5C_serialize_func_t serialize;
+ H5C_notify_func_t notify;
+ H5C_free_icr_func_t free_icr;
+ H5C_get_fsf_size_t fsf_size;
+} H5C_class_t;
+
+/* Type defintions of callback functions used by the cache as a whole */
+typedef herr_t (*H5C_write_permitted_func_t)(const H5F_t *f,
+ hbool_t *write_permitted_ptr);
+typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr,
+ hbool_t was_dirty, unsigned flags);
+
+/****************************************************************************
+ *
+ * H5C_ring_t & associated #defines
+ *
+ * The metadata cache uses the concept of rings to order the flushes of
+ * classes of entries. In this arrangement, each entry in the cache is
+ * assigned to a ring, and on flush, the members of the outermost ring
+ * are flushed first, followed by the next outermost, and so on with the
+ * members of the innermost ring being flushed last.
+ *
+ * Note that flush dependencies are used to order flushes within rings.
+ *
+ * Note also that at the conceptual level, rings are argueably superfluous,
+ * as a similar effect could be obtained via the flush dependency mechanism.
+ * However, this would require all entries in the cache to participate in a
+ * flush dependency -- with the implied setup and takedown overhead and
+ * added complexity. Further, the flush ordering between rings need only
+ * be enforced on flush operations, and thus the use of flush dependencies
+ * instead would apply unecessary constraints on flushes under normal
+ * operating circumstances.
+ *
+ * As of this writing, all metadata entries pretaining to data sets and
+ * groups must be flushed first, and are thus assigned to the outermost
+ * ring.
+ *
+ * Free space managers managing file space must be flushed next,
+ * and are assigned to the second and third outermost rings. Two rings
+ * are used here as the raw data free space manager must be flushed before
+ * the metadata free space manager.
+ *
+ * The object header and associated chunks used to implement superblock
+ * extension messages must be flushed next, and are thus assigned to
+ * the fourth outermost ring.
+ *
+ * The superblock proper must be flushed last, and is thus assigned to
+ * the innermost ring.
+ *
+ * The H5C_ring_t and the associated #defines below are used to define
+ * the rings. Each entry must be assigned to the appropriate ring on
+ * insertion or protect.
+ *
+ * Note that H5C_ring_t was originally an enumerated type. It was
+ * converted to an integer and a set of #defines for convenience in
+ * debugging.
+ */
+
+#define H5C_RING_UNDEFINED 0 /* shouldn't appear in the cache */
+#define H5C_RING_USER 1 /* outermost ring */
+#define H5C_RING_RDFSM 2
+#define H5C_RING_MDFSM 3
+#define H5C_RING_SBE 4
+#define H5C_RING_SB 5 /* innermost ring */
+#define H5C_RING_NTYPES 6
+
+typedef int H5C_ring_t;
+
+
+/****************************************************************************
+ *
+ * structure H5C_cache_entry_t
+ *
+ * Instances of the H5C_cache_entry_t structure are used to store cache
+ * entries in a hash table and sometimes in a skip list.
+ * See H5SL.c for the particulars of the skip list.
+ *
+ * In typical application, this structure is the first field in a
+ * structure to be cached. For historical reasons, the external module
+ * is responsible for managing the is_dirty field (this is no longer
+ * completely true. See the comment on the is_dirty field for details).
+ * All other fields are managed by the cache.
+ *
+ * The fields of this structure are discussed individually below:
+ *
+ * JRM - 4/26/04
+ *
+ * magic: Unsigned 32 bit integer that must always be set to
+ * H5C__H5C_CACHE_ENTRY_T_MAGIC when the entry is valid.
+ * The field must be set to H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC
+ * just before the entry is freed.
+ *
+ * This is necessary, as the LRU list can be changed out
+ * from under H5C__make_space_in_cache() by the serialize
+ * callback which may change the size of an existing entry,
+ * and/or load a new entry while serializing the target entry.
+ *
+ * This in turn can cause a recursive call to
+ * H5C__make_space_in_cache() which may either flush or evict
+ * the next entry that the first invocation of that function
+ * was about to examine.
+ *
+ * The magic field allows H5C__make_space_in_cache() to
+ * detect this case, and re-start its scan from the bottom
+ * of the LRU when this situation occurs.
+ *
+ * cache_ptr: Pointer to the cache that this entry is contained within.
+ *
+ * addr: Base address of the cache entry on disk.
+ *
+ * size: Length of the cache entry on disk in bytes Note that unlike
+ * normal caches, the entries in this cache are of arbitrary size.
+ *
+ * The file space allocations for cache entries implied by the
+ * addr and size fields must be disjoint.
+ *
+ * image_ptr: Pointer to void. When not NULL, this field points to a
+ * dynamically allocated block of size bytes in which the
+ * on disk image of the metadata cache entry is stored.
+ *
+ * If the entry is dirty, the pre-serialize and serialize
+ * callbacks must be used to update this image before it is
+ * written to disk
+ *
+ * image_up_to_date: Boolean flag that is set to TRUE when *image_ptr
+ * is up to date, and set to false when the entry is dirtied.
+ *
+ * type: Pointer to the instance of H5C_class_t containing pointers
+ * to the methods for cache entries of the current type. This
+ * field should be NULL when the instance of H5C_cache_entry_t
+ * is not in use.
+ *
+ * The name is not particularly descriptive, but is retained
+ * to avoid changes in existing code.
+ *
+ * is_dirty: Boolean flag indicating whether the contents of the cache
+ * entry has been modified since the last time it was written
+ * to disk.
+ *
+ * dirtied: Boolean flag used to indicate that the entry has been
+ * dirtied while protected.
+ *
+ * This field is set to FALSE in the protect call, and may
+ * be set to TRUE by the H5C_mark_entry_dirty() call at any
+ * time prior to the unprotect call.
+ *
+ * The H5C_mark_entry_dirty() call exists as a convenience
+ * function for the fractal heap code which may not know if
+ * an entry is protected or pinned, but knows that is either
+ * protected or pinned. The dirtied field was added as in
+ * the parallel case, it is necessary to know whether a
+ * protected entry is dirty prior to the protect call.
+ *
+ * is_protected: Boolean flag indicating whether this entry is protected
+ * (or locked, to use more conventional terms). When it is
+ * protected, the entry cannot be flushed or accessed until
+ * it is unprotected (or unlocked -- again to use more
+ * conventional terms).
+ *
+ * Note that protected entries are removed from the LRU lists
+ * and inserted on the protected list.
+ *
+ * is_read_only: Boolean flag that is only meaningful if is_protected is
+ * TRUE. In this circumstance, it indicates whether the
+ * entry has been protected read-only, or read/write.
+ *
+ * If the entry has been protected read-only (i.e. is_protected
+ * and is_read_only are both TRUE), we allow the entry to be
+ * protected more than once.
+ *
+ * In this case, the number of readers is maintained in the
+ * ro_ref_count field (see below), and unprotect calls simply
+ * decrement that field until it drops to zero, at which point
+ * the entry is actually unprotected.
+ *
+ * ro_ref_count: Integer field used to maintain a count of the number of
+ * outstanding read-only protects on this entry. This field
+ * must be zero whenever either is_protected or is_read_only
+ * are TRUE.
+ *
+ * is_pinned: Boolean flag indicating whether the entry has been pinned
+ * in the cache.
+ *
+ * For very hot entries, the protect / unprotect overhead
+ * can become excessive. Thus the cache has been extended
+ * to allow an entry to be "pinned" in the cache.
+ *
+ * Pinning an entry in the cache has several implications:
+ *
+ * 1) A pinned entry cannot be evicted. Thus unprotected
+ * pinned entries must be stored in the pinned entry
+ * list, instead of being managed by the replacement
+ * policy code (LRU at present).
+ *
+ * 2) A pinned entry can be accessed or modified at any time.
+ * This places an extra burden on the pre-serialize and
+ * serialize callbacks, which must ensure that a pinned
+ * entry is consistant and ready to write to disk before
+ * generating an image.
+ *
+ * 3) A pinned entry can be marked as dirty (and possibly
+ * change size) while it is unprotected.
+ *
+ * 4) The flush-destroy code must allow pinned entries to
+ * be unpinned (and possibly unprotected) during the
+ * flush.
+ *
+ * JRM -- 3/16/06
+ *
+ * in_slist: Boolean flag indicating whether the entry is in the skip list
+ * As a general rule, entries are placed in the list when they
+ * are marked dirty. However they may remain in the list after
+ * being flushed.
+ *
+ * Update: Dirty entries are now removed from the skip list
+ * when they are flushed.
+ *
+ * flush_marker: Boolean flag indicating that the entry is to be flushed
+ * the next time H5C_flush_cache() is called with the
+ * H5C__FLUSH_MARKED_ENTRIES_FLAG. The flag is reset when
+ * the entry is flushed for whatever reason.
+ *
+ * flush_me_last: Boolean flag indicating that this entry should not be
+ * flushed from the cache until all other entries without
+ * the flush_me_last flag set have been flushed.
+ *
+ * Note:
+ *
+ * At this time, the flush_me_last
+ * flag will only be applied to one entry, the superblock,
+ * and the code utilizing these flags is protected with HDasserts
+ * to enforce this. This restraint can certainly be relaxed in
+ * the future if the the need for multiple entries getting flushed
+ * last or collectively arises, though the code allowing for that
+ * will need to be expanded and tested appropriately if that
+ * functionality is desired.
+ *
+ * Update: There are now two possible last entries
+ * (superblock and file driver info message). This
+ * number will probably increase as we add superblock
+ * messages. JRM -- 11/18/14
+ *
+ * clear_on_unprotect: Boolean flag used only in PHDF5. When H5C is used
+ * to implement the metadata cache In the parallel case, only
+ * the cache with mpi rank 0 is allowed to actually write to
+ * file -- all other caches must retain dirty entries until they
+ * are advised that the entry is clean.
+ *
+ * This flag is used in the case that such an advisory is
+ * received when the entry is protected. If it is set when an
+ * entry is unprotected, and the dirtied flag is not set in
+ * the unprotect, the entry's is_dirty flag is reset by flushing
+ * it with the H5C__FLUSH_CLEAR_ONLY_FLAG.
+ *
+ * flush_immediately: Boolean flag used only in Phdf5 -- and then only
+ * for H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED.
+ *
+ * When a destributed metadata write is triggered at a
+ * sync point, this field is used to mark entries that
+ * must be flushed before leaving the sync point. At all
+ * other times, this field should be set to FALSE.
+ *
+ * flush_in_progress: Boolean flag that is set to true iff the entry
+ * is in the process of being flushed. This allows the cache
+ * to detect when a call is the result of a flush callback.
+ *
+ * destroy_in_progress: Boolean flag that is set to true iff the entry
+ * is in the process of being flushed and destroyed.
+ *
+ *
+ * Fields supporting rings for flush ordering:
+ *
+ * All entries in the metadata cache are assigned to a ring. On cache
+ * flush, all entries in the outermost ring are flushed first, followed
+ * by all members of the next outermost ring, and so on until the
+ * innermost ring is flushed. Note that this ordering is ONLY applied
+ * in flush and serialize calls. Rings are ignored during normal operations
+ * in which entries are flushed as directed by the replacement policy.
+ *
+ * See the header comment on H5C_ring_t above for further details.
+ *
+ * Note that flush dependencies (see below) are used to order flushes
+ * within rings. Unlike rings, flush dependencies are applied to ALL
+ * writes, not just those triggered by flush or serialize calls.
+ *
+ * ring: Instance of H5C_ring_t indicating the ring to which this
+ * entry is assigned.
+ *
+ *
+ * Fields supporting the 'flush dependency' feature:
+ *
+ * Entries in the cache may have 'flush dependencies' on other entries in the
+ * cache. A flush dependency requires that all dirty child entries be flushed
+ * to the file before a dirty parent entry (of those child entries) can be
+ * flushed to the file. This can be used by cache clients to create data
+ * structures that allow Single-Writer/Multiple-Reader (SWMR) access for the
+ * data structure.
+ *
+ * flush_dep_parent: Pointer to the array of flush dependency parent entries
+ * for this entry.
+ *
+ * flush_dep_nparents: Number of flush dependency parent entries for this
+ * entry, i.e. the number of valid elements in flush_dep_parent.
+ *
+ * flush_dep_parent_nalloc: The number of allocated elements in
+ * flush_dep_parent_nalloc.
+ *
+ * flush_dep_nchildren: Number of flush dependency children for this entry. If
+ * this field is nonzero, then this entry must be pinned and
+ * therefore cannot be evicted.
+ *
+ * flush_dep_ndirty_children: Number of flush dependency children that are
+ * either dirty or have a nonzero flush_dep_ndirty_children. If
+ * this field is nonzero, then this entry cannot be flushed.
+ *
+ * flush_dep_nunser_children: Number of flush dependency children
+ * that are either unserialized, or have a non-zero number of
+ * positive number of unserialized children.
+ *
+ * Note that since there is no requirement that a clean entry
+ * be serialized, it is possible that flush_dep_nunser_children
+ * to be greater than flush_dep_ndirty_children.
+ *
+ * This field exist to facilitate correct ordering of entry
+ * serializations when it is necessary to serialize all the
+ * entries in the metadata cache. Thus in the cache
+ * serialization, no entry can be serialized unless this
+ * field contains 0.
+ *
+ * Fields supporting the hash table:
+ *
+ * Entries in the cache are indexed by a more or less conventional hash table.
+ * If there are multiple entries in any hash bin, they are stored in a doubly
+ * linked list.
+ *
+ * Addendum: JRM -- 10/14/15
+ *
+ * We have come to scan all entries in the cache frequently enough that
+ * the cost of doing so by scanning the hash table has become unacceptable.
+ * To reduce this cost, the index now also maintains a doubly linked list
+ * of all entries in the index. This list is known as the index list.
+ * The il_next and il_prev fields discussed below were added to support
+ * the index list.
+ *
+ * ht_next: Next pointer used by the hash table to store multiple
+ * entries in a single hash bin. This field points to the
+ * next entry in the doubly linked list of entries in the
+ * hash bin, or NULL if there is no next entry.
+ *
+ * ht_prev: Prev pointer used by the hash table to store multiple
+ * entries in a single hash bin. This field points to the
+ * previous entry in the doubly linked list of entries in
+ * the hash bin, or NULL if there is no previuos entry.
+ *
+ * il_next: Next pointer used by the index to maintain a doubly linked
+ * list of all entries in the index (and thus in the cache).
+ * This field contains a pointer to the next entry in the
+ * index list, or NULL if there is no next entry.
+ *
+ * il_prev: Prev pointer used by the index to maintain a doubly linked
+ * list of all entries in the index (and thus in the cache).
+ * This field contains a pointer to the previous entry in the
+ * index list, or NULL if there is no previous entry.
+ *
+ *
+ * Fields supporting replacement policies:
+ *
+ * The cache must have a replacement policy, and it will usually be
+ * necessary for this structure to contain fields supporting that policy.
+ *
+ * While there has been interest in several replacement policies for
+ * this cache, the initial development schedule is tight. Thus I have
+ * elected to support only a modified LRU policy for the first cut.
+ *
+ * When additional replacement policies are added, the fields in this
+ * section will be used in different ways or not at all. Thus the
+ * documentation of these fields is repeated for each replacement policy.
+ *
+ * Modified LRU:
+ *
+ * When operating in parallel mode, we must ensure that a read does not
+ * cause a write. If it does, the process will hang, as the write will
+ * be collective and the other processes will not know to participate.
+ *
+ * To deal with this issue, I have modified the usual LRU policy by adding
+ * clean and dirty LRU lists to the usual LRU list. When reading in
+ * parallel mode, we evict from the clean LRU list only. This implies
+ * that we must try to ensure that the clean LRU list is reasonably well
+ * stocked. See the comments on H5C_t in H5Cpkg.h for more details.
+ *
+ * Note that even if we start with a completely clean cache, a sequence
+ * of protects without unprotects can empty the clean LRU list. In this
+ * case, the cache must grow temporarily. At the next write, we will
+ * attempt to evict enough entries to get the cache down to its nominal
+ * maximum size.
+ *
+ * The use of the replacement policy fields under the Modified LRU policy
+ * is discussed below:
+ *
+ * next: Next pointer in either the LRU, the protected list, or
+ * the pinned list depending on the current values of
+ * is_protected and is_pinned. If there is no next entry
+ * on the list, this field should be set to NULL.
+ *
+ * prev: Prev pointer in either the LRU, the protected list,
+ * or the pinned list depending on the current values of
+ * is_protected and is_pinned. If there is no previous
+ * entry on the list, this field should be set to NULL.
+ *
+ * aux_next: Next pointer on either the clean or dirty LRU lists.
+ * This entry should be NULL when either is_protected or
+ * is_pinned is true.
+ *
+ * When is_protected and is_pinned are false, and is_dirty is
+ * true, it should point to the next item on the dirty LRU
+ * list.
+ *
+ * When is_protected and is_pinned are false, and is_dirty is
+ * false, it should point to the next item on the clean LRU
+ * list. In either case, when there is no next item, it
+ * should be NULL.
+ *
+ * aux_prev: Previous pointer on either the clean or dirty LRU lists.
+ * This entry should be NULL when either is_protected or
+ * is_pinned is true.
+ *
+ * When is_protected and is_pinned are false, and is_dirty is
+ * true, it should point to the previous item on the dirty
+ * LRU list.
+ *
+ * When is_protected and is_pinned are false, and is_dirty
+ * is false, it should point to the previous item on the
+ * clean LRU list.
+ *
+ * In either case, when there is no previous item, it should
+ * be NULL.
+ *
+ * Fields supporting the cache image feature:
+ *
+ * The following fields are used to store data about the entry which must
+ * be stored in the cache image block, but which will typically be either
+ * lost or heavily altered in the process of serializing the cache and
+ * preparing its contents to be copied into the cache image block.
+ *
+ * Some fields are also used in loading the contents of the metadata cache
+ * image back into the cache, and in managing such entries until they are
+ * either protected by the library (at which point they become regular
+ * entries) or are evicted. See discussion of the prefetched field for
+ * further details.
+ *
+ * include_in_image: Boolean flag indicating whether this entry should
+ * be included in the metadata cache image. This field should
+ * always be false prior to the H5C_prep_for_file_close() call.
+ * During that call, it should be set to TRUE for all entries
+ * that are to be included in the metadata cache image. At
+ * present, only the superblock, the superblock extension
+ * object header and its chunks (if any) are omitted from
+ * the image.
+ *
+ * lru_rank: Rank of the entry in the LRU just prior to file close.
+ *
+ * Note that the first entry on the LRU has lru_rank 1,
+ * and that entries not on the LRU at that time will have
+ * either lru_rank -1 (if pinned) or 0 (if loaded during
+ * the process of flushing the cache.
+ *
+ * image_dirty: Boolean flag indicating whether the entry should be marked
+ * as dirty in the metadata cache image. The flag is set to
+ * TRUE iff the entry is dirty when H5C_prep_for_file_close()
+ * is called.
+ *
+ * fd_parent_count: If the entry is a child in one or more flush dependency
+ * relationships, this field contains the number of flush
+ * dependency parents.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields above, if the entry is in the
+ * cache image (i.e. include_in_image is TRUE), any parents
+ * that are not in the image are removed from this count and
+ * from the fd_parent_addrs array below.
+ *
+ * Finally observe that if the entry is dirty and in the
+ * cache image, and its parent is dirty and not in the cache
+ * image, then the entry must be removed from the cache image
+ * to avoid violating the flush dependency flush ordering.
+ *
+ * fd_parent_addrs: If the entry is a child in one or more flush dependency
+ * relationship when H5C_prep_for_file_close() is called, this
+ * field must contain a pointer to an array of size
+ * fd_parent_count containing the on disk addresses of the
+ * parent.
+ *
+ * In all other cases, the field is set to NULL.
+ *
+ * Note that while this list of addresses is initially taken
+ * from the flush dependency fields above, if the entry is in the
+ * cache image (i.e. include_in_image is TRUE), any parents
+ * that are not in the image are removed from this list, and
+ * and from the fd_parent_count above.
+ *
+ * Finally observe that if the entry is dirty and in the
+ * cache image, and its parent is dirty and not in the cache
+ * image, then the entry must be removed from the cache image
+ * to avoid violating the flush dependency flush ordering.
+ *
+ * fd_child_count: If the entry is a parent in a flush dependency
+ * relationship, this field contains the number of flush
+ * dependency children.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields above, if the entry is in the
+ * cache image (i.e. include_in_image is TRUE), any children
+ * that are not in the image are removed from this count.
+ *
+ * fd_dirty_child_count: If the entry is a parent in a flush dependency
+ * relationship, this field contains the number of dirty flush
+ * dependency children.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields above, if the entry is in the
+ * cache image (i.e. include_in_image is TRUE), any dirty
+ * children that are not in the image are removed from this
+ * count.
+ *
+ * image_fd_height: Flush dependency height of the entry in the cache image.
+ *
+ * The flush dependency height of any entry involved in a
+ * flush dependency relationship is defined to be the
+ * longest flush dependency path from that entry to an entry
+ * with no flush depenency children.
+ *
+ * Since the image_fd_height is used to order entries in the
+ * cache image so that fd parents preceed fd children, for
+ * purposes of this field, and entry is at flush dependency
+ * level 0 if it either has no children, or if all of its
+ * children are not in the cache image.
+ *
+ * Note that if a child in a flush dependency relationship is
+ * dirty and in the cache image, and its parent is dirty and
+ * not in the cache image, then the child must be excluded
+ * from the cache image to maintain flush ordering.
+ *
+ * prefetched: Boolean flag indicating that the on disk image of the entry
+ * has been loaded into the cache prior any request for the
+ * entry by the rest of the library.
+ *
+ * As of this writing (8/10/15), this can only happen through
+ * the load of a cache image block, although other scenarios
+ * are contemplated for the use of this feature. Note that
+ * unlike the usual prefetch situation, this means that a
+ * prefetched entry can be dirty, and/or can be a party to
+ * flush dependency relationship(s). This complicates matters
+ * somewhat.
+ *
+ * The essential feature of a prefetched entry is that it
+ * consists only of a buffer containing the on disk image of
+ * the entry. Thus it must be deserialized before it can
+ * be passed back to the library on a protect call. This
+ * task is handled by H5C_deserialized_prefetched_entry().
+ * In essence, this routine calls the deserialize callback
+ * provided in the protect call with the on disk image,
+ * deletes the prefetched entry from the cache, and replaces
+ * it with the deserialized entry returned by the deserialize
+ * callback.
+ *
+ * Further, if the prefetched entry is a flush dependency parent,
+ * all its flush dependency children (which must also be
+ * prefetched entries), must be tranfered to the new cache
+ * entry returned by the deserailization callback.
+ *
+ * Finally, if the prefetched entry is a flush dependency child,
+ * this flush dependency must be destroyed prior to the
+ * deserialize call.
+ *
+ * In addition to the above special processing on the first
+ * protect call on a prefetched entry (after which is no longer
+ * a prefetched entry), prefetched entries also require special
+ * tretment on flush and evict.
+ *
+ * On flush, a dirty prefetched entry must simply be written
+ * to disk and marked clean without any call to any client
+ * callback.
+ *
+ * On eviction, if a prefetched entry is a flush dependency
+ * child, that flush dependency relationship must be destroyed
+ * just prior to the eviction. If the flush dependency code
+ * is working properly, it should be impossible for any entry
+ * that is a flush dependency parent to be evicted.
+ *
+ * prefetch_type_id: Integer field containing the type ID of the prefetched
+ * entry. This ID must match the ID of the type provided in any
+ * protect call on the prefetched entry.
+ *
+ * The value of this field is undefined in prefetched is FALSE.
+ *
+ * age: Number of times a prefetched entry has appeared in
+ * subsequent cache images. The field exists to allow
+ * imposition of a limit on how many times a prefetched
+ * entry can appear in subsequent cache images without being
+ * converted to a regular entry.
+ *
+ * This field must be zero if prefetched is FALSE.
+ *
+ * prefetched_dirty: Boolean field that must be set to FALSE unless the
+ * following conditions hold:
+ *
+ * 1) The file has been opened R/O.
+ *
+ * 2) The entry is either a prefetched entry, or was
+ * re-constructed from a prefetched entry.
+ *
+ * 3) The base prefetched entry was marked dirty.
+ *
+ * This field exists to solve the following problem with
+ * files containing cache images that are opened R/O.
+ *
+ * If the cache image contains a dirty entry, that entry
+ * must be marked clean when it is inserted into the cache
+ * in the read-only case, as otherwise the metadata cache
+ * will attempt to flush it on file close -- which is poor
+ * form in the read-only case.
+ *
+ * However, since the entry is marked clean, it is possible
+ * that the metadata cache will evict it if the size of the
+ * metadata in the file exceeds the size of the metadata cache,
+ * and the application visits much of this data.
+ *
+ * If this happens, and the metadata cache is then asked for
+ * this entry, it will attempt to read it from file, and will
+ * obtain either obsolete or invalid data depending on whether
+ * the entry has ever been written to it assigned location in
+ * the file.
+ *
+ * With this background, the purpose of this field should be
+ * obvious -- when set, it allows the eviction candidate
+ * selection code to skip over the entry, thus avoiding the
+ * issue.
+ *
+ * Since the issue only arises in the R/O case, there is
+ * no possible interaction with SWMR. There are also
+ * potential interactions with Evict On Close -- at present,
+ * we deal with this by disabling EOC in the R/O case.
+ *
+ * serialization_count: Integer field used to maintain a count of the
+ * number of times each entry is serialized during cache
+ * serialization. While no entry should be serialized more than
+ * once in any serialization call, throw an assertion if any
+ * flush depencency parent is serialized more than once during
+ * a single cache serialization.
+ *
+ * This is a debugging field, and thus is maintained only if
+ * NDEBUG is undefined.
+ *
+ * Fields supporting tagged entries:
+ *
+ * Entries in the cache that belong to a single object in the file are
+ * joined into a doubly-linked list, and are "tagged" with the object header
+ * address for that object's base header "chunk" (which is used as the
+ * canonical address for the object). Global and shared entries are
+ * not tagged. Tagged entries have a pointer to the tag info for the object,
+ * which is shared state for all the entries for that object.
+ *
+ * tl_next: Pointer to the next entry in the tag list for an object.
+ * NULL for the tail entry in the list, as well as untagged
+ * entries.
+ *
+ * tl_prev: Pointer to the previous entry in the tag list for an object.
+ * NULL for the head entry in the list, as well as untagged
+ * entries.
+ *
+ * tag_info: Pointer to the common tag state for all entries belonging to
+ * an object. NULL for untagged entries.
+ *
+ *
+ * Cache entry stats collection fields:
+ *
+ * These fields should only be compiled in when both H5C_COLLECT_CACHE_STATS
+ * and H5C_COLLECT_CACHE_ENTRY_STATS are true. When present, they allow
+ * collection of statistics on individual cache entries.
+ *
+ * accesses: int32_t containing the number of times this cache entry has
+ * been referenced in its lifetime.
+ *
+ * clears: int32_t containing the number of times this cache entry has
+ * been cleared in its life time.
+ *
+ * flushes: int32_t containing the number of times this cache entry has
+ * been flushed to file in its life time.
+ *
+ * pins: int32_t containing the number of times this cache entry has
+ * been pinned in cache in its life time.
+ *
+ ****************************************************************************/
+typedef struct H5C_cache_entry_t {
+ uint32_t magic;
+ H5C_t *cache_ptr;
+ haddr_t addr;
+ size_t size;
+ void *image_ptr;
+ hbool_t image_up_to_date;
+ const H5C_class_t *type;
+ hbool_t is_dirty;
+ hbool_t dirtied;
+ hbool_t is_protected;
+ hbool_t is_read_only;
+ int ro_ref_count;
+ hbool_t is_pinned;
+ hbool_t in_slist;
+ hbool_t flush_marker;
+ hbool_t flush_me_last;
+#ifdef H5_HAVE_PARALLEL
+ hbool_t clear_on_unprotect;
+ hbool_t flush_immediately;
+ hbool_t coll_access;
+#endif /* H5_HAVE_PARALLEL */
+ hbool_t flush_in_progress;
+ hbool_t destroy_in_progress;
+
+ /* fields supporting rings for purposes of flush ordering */
+ H5C_ring_t ring;
+
+ /* fields supporting the 'flush dependency' feature: */
+ struct H5C_cache_entry_t ** flush_dep_parent;
+ unsigned flush_dep_nparents;
+ unsigned flush_dep_parent_nalloc;
+ unsigned flush_dep_nchildren;
+ unsigned flush_dep_ndirty_children;
+ unsigned flush_dep_nunser_children;
+ hbool_t pinned_from_client;
+ hbool_t pinned_from_cache;
+
+ /* fields supporting the hash table: */
+ struct H5C_cache_entry_t *ht_next;
+ struct H5C_cache_entry_t *ht_prev;
+ struct H5C_cache_entry_t *il_next;
+ struct H5C_cache_entry_t *il_prev;
+
+ /* fields supporting replacement policies: */
+ struct H5C_cache_entry_t *next;
+ struct H5C_cache_entry_t *prev;
+ struct H5C_cache_entry_t *aux_next;
+ struct H5C_cache_entry_t *aux_prev;
+#ifdef H5_HAVE_PARALLEL
+ struct H5C_cache_entry_t *coll_next;
+ struct H5C_cache_entry_t *coll_prev;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* fields supporting cache image */
+ hbool_t include_in_image;
+ int32_t lru_rank;
+ hbool_t image_dirty;
+ uint64_t fd_parent_count;
+ haddr_t *fd_parent_addrs;
+ uint64_t fd_child_count;
+ uint64_t fd_dirty_child_count;
+ uint32_t image_fd_height;
+ hbool_t prefetched;
+ int prefetch_type_id;
+ int32_t age;
+ hbool_t prefetched_dirty;
+
+#ifndef NDEBUG /* debugging field */
+ int serialization_count;
+#endif /* NDEBUG */
+
+ /* fields supporting tag lists */
+ struct H5C_cache_entry_t *tl_next;
+ struct H5C_cache_entry_t *tl_prev;
+ struct H5C_tag_info_t *tag_info;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+ /* cache entry stats fields */
+ int32_t accesses;
+ int32_t clears;
+ int32_t flushes;
+ int32_t pins;
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+} H5C_cache_entry_t;
+
+
+/****************************************************************************
+ *
+ * structure H5C_image_entry_t
+ *
+ * Instances of the H5C_image_entry_t structure are used to store data on
+ * metadata cache entries used in the construction of the metadata cache
+ * image block. In essence this structure is a greatly simplified version
+ * of H5C_cache_entry_t.
+ *
+ * The fields of this structure are discussed individually below:
+ *
+ * JRM - 8/5/15
+ *
+ * magic: Unsigned 32 bit integer that must always be set to
+ * H5C_IMAGE_ENTRY_T_MAGIC when the entry is valid.
+ * The field must be set to H5C_IMAGE_ENTRY_T_BAD_MAGIC
+ * just before the entry is freed.
+ *
+ * addr: Base address of the cache entry on disk.
+ *
+ * size: Length of the cache entry on disk in bytes.
+ *
+ * ring: Instance of H5C_ring_t indicating the flush ordering ring
+ * to which this entry is assigned.
+ *
+ * age: Number of times this prefetech entry has appeared in
+ * the current sequence of cache images. This field is
+ * initialized to 0 if the instance of H5C_image_entry_t
+ * is constructed from a regular entry.
+ *
+ * If the instance is constructed from a prefetched entry
+ * currently residing in the metadata cache, the field is
+ * set to 1 + the age of the prefetched entry, or to
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX if that sum exceeds
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX.
+ *
+ * type_id: Integer field containing the type ID of the entry.
+ *
+ * lru_rank: Rank of the entry in the LRU just prior to file close.
+ *
+ * Note that the first entry on the LRU has lru_rank 1,
+ * and that entries not on the LRU at that time will have
+ * either lru_rank -1 (if pinned) or 0 (if loaded during
+ * the process of flushing the cache.
+ *
+ * is_dirty: Boolean flag indicating whether the contents of the cache
+ * entry has been modified since the last time it was written
+ * to disk as a regular piece of metadata.
+ *
+ * image_fd_height: Flush dependency height of the entry in the cache image.
+ *
+ * The flush dependency height of any entry involved in a
+ * flush dependency relationship is defined to be the
+ * longest flush dependency path from that entry to an entry
+ * with no flush depenency children.
+ *
+ * Since the image_fd_height is used to order entries in the
+ * cache image so that fd parents preceed fd children, for
+ * purposes of this field, an entry is at flush dependency
+ * level 0 if it either has no children, or if all of its
+ * children are not in the cache image.
+ *
+ * Note that if a child in a flush dependency relationship is
+ * dirty and in the cache image, and its parent is dirty and
+ * not in the cache image, then the child must be excluded
+ * from the cache image to maintain flush ordering.
+ *
+ * fd_parent_count: If the entry is a child in one or more flush dependency
+ * relationships, this field contains the number of flush
+ * dependency parents.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields in the associated instance of
+ * H5C_cache_entry_t, if the entry is in the cache image
+ * (i.e. include_in_image is TRUE), any parents that are
+ * not in the image are removed from this count and
+ * from the fd_parent_addrs array below.
+ *
+ * Finally observe that if the entry is dirty and in the
+ * cache image, and its parent is dirty and not in the cache
+ * image, then the entry must be removed from the cache image
+ * to avoid violating the flush dependency flush ordering.
+ * This should have happened before the construction of
+ * the instance of H5C_image_entry_t.
+ *
+ * fd_parent_addrs: If the entry is a child in one or more flush dependency
+ * relationship when H5C_prep_for_file_close() is called, this
+ * field must contain a pointer to an array of size
+ * fd_parent_count containing the on disk addresses of the
+ * parents.
+ *
+ * In all other cases, the field is set to NULL.
+ *
+ * Note that while this list of addresses is initially taken
+ * from the flush dependency fields in the associated instance of
+ * H5C_cache_entry_t, if the entry is in the cache image
+ * (i.e. include_in_image is TRUE), any parents that are not
+ * in the image are removed from this list, and from the
+ * fd_parent_count above.
+ *
+ * Finally observe that if the entry is dirty and in the
+ * cache image, and its parent is dirty and not in the cache
+ * image, then the entry must be removed from the cache image
+ * to avoid violating the flush dependency flush ordering.
+ * This should have happened before the construction of
+ * the instance of H5C_image_entry_t.
+ *
+ * fd_child_count: If the entry is a parent in a flush dependency
+ * relationship, this field contains the number of flush
+ * dependency children.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields in the associated instance of
+ * H5C_cache_entry_t, if the entry is in the cache image
+ * (i.e. include_in_image is TRUE), any children
+ * that are not in the image are removed from this count.
+ *
+ * fd_dirty_child_count: If the entry is a parent in a flush dependency
+ * relationship, this field contains the number of dirty flush
+ * dependency children.
+ *
+ * In all other cases, the field is set to zero.
+ *
+ * Note that while this count is initially taken from the
+ * flush dependency fields in the associated instance of
+ * H5C_cache_entry_t, if the entry is in the cache image
+ * (i.e. include_in_image is TRUE), any dirty children
+ * that are not in the image are removed from this count.
+ *
+ * image_ptr: Pointer to void. When not NULL, this field points to a
+ * dynamically allocated block of size bytes in which the
+ * on disk image of the metadata cache entry is stored.
+ *
+ * If the entry is dirty, the pre-serialize and serialize
+ * callbacks must be used to update this image before it is
+ * written to disk
+ *
+ *
+ ****************************************************************************/
+
+typedef struct H5C_image_entry_t {
+ uint32_t magic;
+ haddr_t addr;
+ size_t size;
+ H5C_ring_t ring;
+ int32_t age;
+ int32_t type_id;
+ int32_t lru_rank;
+ hbool_t is_dirty;
+ unsigned image_fd_height;
+ uint64_t fd_parent_count;
+ haddr_t *fd_parent_addrs;
+ uint64_t fd_child_count;
+ uint64_t fd_dirty_child_count;
+ void *image_ptr;
+} H5C_image_entry_t;
+
+/****************************************************************************
+ *
+ * structure H5C_auto_size_ctl_t
+ *
+ * Instances of H5C_auto_size_ctl_t are used to get and set the control
+ * fields for automatic cache re-sizing.
+ *
+ * The fields of the structure are discussed individually below:
+ *
+ * version: Integer field containing the version number of this version
+ * of the H5C_auto_size_ctl_t structure. Any instance of
+ * H5C_auto_size_ctl_t passed to the cache must have a known
+ * version number, or an error will be flagged.
+ *
+ * report_fcn: Pointer to the function that is to be called to report
+ * activities each time the auto cache resize code is executed. If the
+ * field is NULL, no call is made.
+ *
+ * If the field is not NULL, it must contain the address of a function
+ * of type H5C_auto_resize_report_fcn.
+ *
+ * set_initial_size: Boolean flag indicating whether the size of the
+ * initial size of the cache is to be set to the value given in
+ * the initial_size field. If set_initial_size is FALSE, the
+ * initial_size field is ignored.
+ *
+ * initial_size: If enabled, this field contain the size the cache is
+ * to be set to upon receipt of this structure. Needless to say,
+ * initial_size must lie in the closed interval [min_size, max_size].
+ *
+ * min_clean_fraction: double in the range 0 to 1 indicating the fraction
+ * of the cache that is to be kept clean. This field is only used
+ * in parallel mode. Typical values are 0.1 to 0.5.
+ *
+ * max_size: Maximum size to which the cache can be adjusted. The
+ * supplied value must fall in the closed interval
+ * [MIN_MAX_CACHE_SIZE, MAX_MAX_CACHE_SIZE]. Also, max_size must
+ * be greater than or equal to min_size.
+ *
+ * min_size: Minimum size to which the cache can be adjusted. The
+ * supplied value must fall in the closed interval
+ * [MIN_MAX_CACHE_SIZE, MAX_MAX_CACHE_SIZE]. Also, min_size must
+ * be less than or equal to max_size.
+ *
+ * epoch_length: Number of accesses on the cache over which to collect
+ * hit rate stats before running the automatic cache resize code,
+ * if it is enabled.
+ *
+ * At the end of an epoch, we discard prior hit rate data and start
+ * collecting afresh. The epoch_length must lie in the closed
+ * interval [H5C__MIN_AR_EPOCH_LENGTH, H5C__MAX_AR_EPOCH_LENGTH].
+ *
+ *
+ * Cache size increase control fields:
+ *
+ * incr_mode: Instance of the H5C_cache_incr_mode enumerated type whose
+ * value indicates how we determine whether the cache size should be
+ * increased. At present there are two possible values:
+ *
+ * H5C_incr__off: Don't attempt to increase the size of the cache
+ * automatically.
+ *
+ * When this increment mode is selected, the remaining fields
+ * in the cache size increase section ar ignored.
+ *
+ * H5C_incr__threshold: Attempt to increase the size of the cache
+ * whenever the average hit rate over the last epoch drops
+ * below the value supplied in the lower_hr_threshold
+ * field.
+ *
+ * Note that this attempt will fail if the cache is already
+ * at its maximum size, or if the cache is not already using
+ * all available space.
+ *
+ * lower_hr_threshold: Lower hit rate threshold. If the increment mode
+ * (incr_mode) is H5C_incr__threshold and the hit rate drops below the
+ * value supplied in this field in an epoch, increment the cache size by
+ * size_increment. Note that cache size may not be incremented above
+ * max_size, and that the increment may be further restricted by the
+ * max_increment field if it is enabled.
+ *
+ * When enabled, this field must contain a value in the range [0.0, 1.0].
+ * Depending on the incr_mode selected, it may also have to be less than
+ * upper_hr_threshold.
+ *
+ * increment: Double containing the multiplier used to derive the new
+ * cache size from the old if a cache size increment is triggered.
+ * The increment must be greater than 1.0, and should not exceed 2.0.
+ *
+ * The new cache size is obtained by multiplying the current max cache
+ * size by the increment, and then clamping to max_size and to stay
+ * within the max_increment as necessary.
+ *
+ * apply_max_increment: Boolean flag indicating whether the max_increment
+ * field should be used to limit the maximum cache size increment.
+ *
+ * max_increment: If enabled by the apply_max_increment field described
+ * above, this field contains the maximum number of bytes by which the
+ * cache size can be increased in a single re-size.
+ *
+ * flash_incr_mode: Instance of the H5C_cache_flash_incr_mode enumerated
+ * type whose value indicates whether and by what algorithm we should
+ * make flash increases in the size of the cache to accomodate insertion
+ * of large entries and large increases in the size of a single entry.
+ *
+ * The addition of the flash increment mode was occasioned by performance
+ * problems that appear when a local heap is increased to a size in excess
+ * of the current cache size. While the existing re-size code dealt with
+ * this eventually, performance was very bad for the remainder of the
+ * epoch.
+ *
+ * At present, there are two possible values for the flash_incr_mode:
+ *
+ * H5C_flash_incr__off: Don't perform flash increases in the size of
+ * the cache.
+ *
+ * H5C_flash_incr__add_space: Let x be either the size of a newly
+ * newly inserted entry, or the number of bytes by which the
+ * size of an existing entry has been increased.
+ *
+ * If
+ * x > flash_threshold * current max cache size,
+ *
+ * increase the current maximum cache size by x * flash_multiple
+ * less any free space in the cache, and start a new epoch. For
+ * now at least, pay no attention to the maximum increment.
+ *
+ *
+ * With a little thought, it should be obvious that the above flash
+ * cache size increase algorithm is not sufficient for all
+ * circumstances -- for example, suppose the user round robins through
+ * (1/flash_threshold) +1 groups, adding one data set to each on each
+ * pass. Then all will increase in size at about the same time, requiring
+ * the max cache size to at least double to maintain acceptable
+ * performance, however the above flash increment algorithm will not be
+ * triggered.
+ *
+ * Hopefully, the add space algorithm detailed above will be sufficient
+ * for the performance problems encountered to date. However, we should
+ * expect to revisit the issue.
+ *
+ * flash_multiple: Double containing the multiple described above in the
+ * H5C_flash_incr__add_space section of the discussion of the
+ * flash_incr_mode section. This field is ignored unless flash_incr_mode
+ * is H5C_flash_incr__add_space.
+ *
+ * flash_threshold: Double containing the factor by which current max cache
+ * size is multiplied to obtain the size threshold for the add_space
+ * flash increment algorithm. The field is ignored unless
+ * flash_incr_mode is H5C_flash_incr__add_space.
+ *
+ *
+ * Cache size decrease control fields:
+ *
+ * decr_mode: Instance of the H5C_cache_decr_mode enumerated type whose
+ * value indicates how we determine whether the cache size should be
+ * decreased. At present there are four possibilities.
+ *
+ * H5C_decr__off: Don't attempt to decrease the size of the cache
+ * automatically.
+ *
+ * When this increment mode is selected, the remaining fields
+ * in the cache size decrease section are ignored.
+ *
+ * H5C_decr__threshold: Attempt to decrease the size of the cache
+ * whenever the average hit rate over the last epoch rises
+ * above the value supplied in the upper_hr_threshold
+ * field.
+ *
+ * H5C_decr__age_out: At the end of each epoch, search the cache for
+ * entries that have not been accessed for at least the number
+ * of epochs specified in the epochs_before_eviction field, and
+ * evict these entries. Conceptually, the maximum cache size
+ * is then decreased to match the new actual cache size. However,
+ * this reduction may be modified by the min_size, the
+ * max_decrement, and/or the empty_reserve.
+ *
+ * H5C_decr__age_out_with_threshold: Same as age_out, but we only
+ * attempt to reduce the cache size when the hit rate observed
+ * over the last epoch exceeds the value provided in the
+ * upper_hr_threshold field.
+ *
+ * upper_hr_threshold: Upper hit rate threshold. The use of this field
+ * varies according to the current decr_mode:
+ *
+ * H5C_decr__off or H5C_decr__age_out: The value of this field is
+ * ignored.
+ *
+ * H5C_decr__threshold: If the hit rate exceeds this threshold in any
+ * epoch, attempt to decrement the cache size by size_decrement.
+ *
+ * Note that cache size may not be decremented below min_size.
+ *
+ * Note also that if the upper_threshold is 1.0, the cache size
+ * will never be reduced.
+ *
+ * H5C_decr__age_out_with_threshold: If the hit rate exceeds this
+ * threshold in any epoch, attempt to reduce the cache size
+ * by evicting entries that have not been accessed for more
+ * than the specified number of epochs.
+ *
+ * decrement: This field is only used when the decr_mode is
+ * H5C_decr__threshold.
+ *
+ * The field is a double containing the multiplier used to derive the
+ * new cache size from the old if a cache size decrement is triggered.
+ * The decrement must be in the range 0.0 (in which case the cache will
+ * try to contract to its minimum size) to 1.0 (in which case the
+ * cache will never shrink).
+ *
+ * apply_max_decrement: Boolean flag used to determine whether decrements
+ * in cache size are to be limited by the max_decrement field.
+ *
+ * max_decrement: Maximum number of bytes by which the cache size can be
+ * decreased in a single re-size. Note that decrements may also be
+ * restricted by the min_size of the cache, and (in age out modes) by
+ * the empty_reserve field.
+ *
+ * epochs_before_eviction: Integer field used in H5C_decr__age_out and
+ * H5C_decr__age_out_with_threshold decrement modes.
+ *
+ * This field contains the number of epochs an entry must remain
+ * unaccessed before it is evicted in an attempt to reduce the
+ * cache size. If applicable, this field must lie in the range
+ * [1, H5C__MAX_EPOCH_MARKERS].
+ *
+ * apply_empty_reserve: Boolean field controlling whether the empty_reserve
+ * field is to be used in computing the new cache size when the
+ * decr_mode is H5C_decr__age_out or H5C_decr__age_out_with_threshold.
+ *
+ * empty_reserve: To avoid a constant racheting down of cache size by small
+ * amounts in the H5C_decr__age_out and H5C_decr__age_out_with_threshold
+ * modes, this field allows one to require that any cache size
+ * reductions leave the specified fraction of unused space in the cache.
+ *
+ * The value of this field must be in the range [0.0, 1.0]. I would
+ * expect typical values to be in the range of 0.01 to 0.1.
+ *
+ ****************************************************************************/
+
+enum H5C_resize_status
+{
+ in_spec,
+ increase,
+ flash_increase,
+ decrease,
+ at_max_size,
+ at_min_size,
+ increase_disabled,
+ decrease_disabled,
+ not_full
+}; /* enum H5C_resize_conditions */
+
+typedef void (*H5C_auto_resize_rpt_fcn)(H5C_t * cache_ptr, int32_t version,
+ double hit_rate, enum H5C_resize_status status, size_t old_max_cache_size,
+ size_t new_max_cache_size, size_t old_min_clean_size, size_t new_min_clean_size);
+
+typedef struct H5C_auto_size_ctl_t {
+ /* general configuration fields: */
+ int32_t version;
+ H5C_auto_resize_rpt_fcn rpt_fcn;
+ hbool_t set_initial_size;
+ size_t initial_size;
+ double min_clean_fraction;
+ size_t max_size;
+ size_t min_size;
+ int64_t epoch_length;
+
+ /* size increase control fields: */
+ enum H5C_cache_incr_mode incr_mode;
+ double lower_hr_threshold;
+ double increment;
+ hbool_t apply_max_increment;
+ size_t max_increment;
+ enum H5C_cache_flash_incr_mode flash_incr_mode;
+ double flash_multiple;
+ double flash_threshold;
+
+ /* size decrease control fields: */
+ enum H5C_cache_decr_mode decr_mode;
+ double upper_hr_threshold;
+ double decrement;
+ hbool_t apply_max_decrement;
+ size_t max_decrement;
+ int32_t epochs_before_eviction;
+ hbool_t apply_empty_reserve;
+ double empty_reserve;
+} H5C_auto_size_ctl_t;
+
+/****************************************************************************
+ *
+ * structure H5C_cache_image_ctl_t
+ *
+ * Instances of H5C_image_ctl_t are used to get and set the control
+ * fields for generation of a metadata cache image on file close.
+ *
+ * At present control of construction of a cache image is via a FAPL
+ * property at file open / create.
+ *
+ * The fields of the structure are discussed individually below:
+ *
+ * version: Integer field containing the version number of this version
+ * of the H5C_image_ctl_t structure. Any instance of
+ * H5C_image_ctl_t passed to the cache must have a known
+ * version number, or an error will be flagged.
+ *
+ * generate_image: Boolean flag indicating whether a cache image should
+ * be created on file close.
+ *
+ * save_resize_status: Boolean flag indicating whether the cache image
+ * should include the adaptive cache resize configuration and status.
+ * Note that this field is ignored at present.
+ *
+ * entry_ageout: Integer field indicating the maximum number of
+ * times a prefetched entry can appear in subsequent cache images.
+ * This field exists to allow the user to avoid the buildup of
+ * infrequently used entries in long sequences of cache images.
+ *
+ * The value of this field must lie in the range
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE (-1) to
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX (100).
+ *
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE means that no limit
+ * is imposed on number of times a prefeteched entry can appear
+ * in subsequent cache images.
+ *
+ * A value of 0 prevents prefetched entries from being included
+ * in cache images.
+ *
+ * Positive integers restrict prefetched entries to the specified
+ * number of appearances.
+ *
+ * Note that the number of subsequent cache images that a prefetched
+ * entry has appeared in is tracked in an 8 bit field. Thus, while
+ * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX can be increased from its
+ * current value, any value in excess of 255 will be the functional
+ * equivalent of H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE.
+ *
+ * flags: Unsigned integer containing flags controling which aspects of the
+ * cache image functinality is actually executed. The primary impetus
+ * behind this field is to allow developement of tests for partial
+ * implementations that will require little if any modification to run
+ * with the full implementation. In normal operation, all flags should
+ * be set.
+ *
+ ****************************************************************************/
+
+#define H5C_CI__GEN_MDCI_SBE_MESG ((unsigned)0x0001)
+#define H5C_CI__GEN_MDC_IMAGE_BLK ((unsigned)0x0002)
+#define H5C_CI__SUPRESS_ENTRY_WRITES ((unsigned)0x0004)
+#define H5C_CI__WRITE_CACHE_IMAGE ((unsigned)0x0008)
+
+/* This #define must set all defined H5C_CI flags. It is
+ * used in the default value for instances of H5C_cache_image_ctl_t.
+ * This value will only be modified in test code.
+ */
+#define H5C_CI__ALL_FLAGS ((unsigned)0x000F)
+
+#define H5C__DEFAULT_CACHE_IMAGE_CTL \
+{ \
+ /* version = */ H5C__CURR_CACHE_IMAGE_CTL_VER, \
+ /* generate_image = */ FALSE, \
+ /* save_resize_status = */ FALSE, \
+ /* entry_ageout = */ H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE, \
+ /* flags = */ H5C_CI__ALL_FLAGS \
+}
+
+typedef struct H5C_cache_image_ctl_t {
+ int32_t version;
+ hbool_t generate_image;
+ hbool_t save_resize_status;
+ int32_t entry_ageout;
+ unsigned flags;
+} H5C_cache_image_ctl_t;
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+H5_DLL H5C_t *H5C_create(size_t max_cache_size, size_t min_clean_size,
+ int max_type_id, const H5C_class_t * const *class_table_ptr,
+ H5C_write_permitted_func_t check_write_permitted, hbool_t write_permitted,
+ H5C_log_flush_func_t log_flush, void *aux_ptr);
+H5_DLL herr_t H5C_set_up_logging(H5C_t *cache_ptr, const char log_location[], hbool_t start_immediately);
+H5_DLL herr_t H5C_tear_down_logging(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_start_logging(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_stop_logging(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_get_logging_status(const H5C_t *cache_ptr, /*OUT*/ hbool_t *is_enabled,
+ /*OUT*/ hbool_t *is_currently_logging);
+H5_DLL herr_t H5C_write_log_message(const H5C_t *cache_ptr, const char message[]);
+H5_DLL void H5C_def_auto_resize_rpt_fcn(H5C_t *cache_ptr, int32_t version,
+ double hit_rate, enum H5C_resize_status status,
+ size_t old_max_cache_size, size_t new_max_cache_size,
+ size_t old_min_clean_size, size_t new_min_clean_size);
+H5_DLL herr_t H5C_dest(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C_evict(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C_expunge_entry(H5F_t *f, hid_t dxpl_id,
+ const H5C_class_t *type, haddr_t addr, unsigned flags);
+H5_DLL herr_t H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags);
+H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag);
+H5_DLL herr_t H5C_force_cache_image_load(H5F_t * f, hid_t dxpl_id);
+H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag, hbool_t match_global);
+H5_DLL herr_t H5C_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id, unsigned flags);
+H5_DLL herr_t H5C_get_tag(const void *thing, /*OUT*/ haddr_t *tag);
+#if H5C_DO_TAGGING_SANITY_CHECKS
+herr_t H5C_verify_tag(int id, haddr_t tag);
+#endif
+H5_DLL herr_t H5C_flush_to_min_clean(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C_get_cache_auto_resize_config(const H5C_t *cache_ptr,
+ H5C_auto_size_ctl_t *config_ptr);
+H5_DLL herr_t H5C_get_cache_image_config(const H5C_t * cache_ptr,
+ H5C_cache_image_ctl_t *config_ptr);
+H5_DLL herr_t H5C_get_cache_size(H5C_t *cache_ptr, size_t *max_size_ptr,
+ size_t *min_clean_size_ptr, size_t *cur_size_ptr,
+ uint32_t *cur_num_entries_ptr);
+H5_DLL herr_t H5C_get_cache_hit_rate(H5C_t *cache_ptr, double *hit_rate_ptr);
+H5_DLL herr_t H5C_get_entry_status(const H5F_t *f, haddr_t addr,
+ size_t *size_ptr, hbool_t *in_cache_ptr, hbool_t *is_dirty_ptr,
+ hbool_t *is_protected_ptr, hbool_t *is_pinned_ptr, hbool_t *is_corked_ptr,
+ hbool_t *is_flush_dep_parent_ptr, hbool_t *is_flush_dep_child_ptr,
+ hbool_t *image_up_to_date_ptr);
+H5_DLL herr_t H5C_get_evictions_enabled(const H5C_t *cache_ptr, hbool_t *evictions_enabled_ptr);
+H5_DLL void * H5C_get_aux_ptr(const H5C_t *cache_ptr);
+H5_DLL FILE *H5C_get_trace_file_ptr(const H5C_t *cache_ptr);
+H5_DLL FILE *H5C_get_trace_file_ptr_from_entry(const H5C_cache_entry_t *entry_ptr);
+H5_DLL herr_t H5C_image_stats(H5C_t * cache_ptr, hbool_t print_header);
+H5_DLL herr_t H5C_insert_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type,
+ haddr_t addr, void *thing, unsigned int flags);
+H5_DLL herr_t H5C_load_cache_image_on_next_protect(H5F_t *f, haddr_t addr,
+ hsize_t len, hbool_t rw);
+H5_DLL herr_t H5C_mark_entry_dirty(void *thing);
+H5_DLL herr_t H5C_mark_entry_clean(void *thing);
+H5_DLL herr_t H5C_mark_entry_unserialized(void *thing);
+H5_DLL herr_t H5C_mark_entry_serialized(void *thing);
+H5_DLL herr_t H5C_move_entry(H5C_t *cache_ptr, const H5C_class_t *type,
+ haddr_t old_addr, haddr_t new_addr);
+H5_DLL herr_t H5C_pin_protected_entry(void *thing);
+H5_DLL herr_t H5C_prep_for_file_close(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5C_create_flush_dependency(void *parent_thing, void *child_thing);
+H5_DLL void * H5C_protect(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type,
+ haddr_t addr, void *udata, unsigned flags);
+H5_DLL herr_t H5C_reset_cache_hit_rate_stats(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_resize_entry(void *thing, size_t new_size);
+H5_DLL herr_t H5C_set_cache_auto_resize_config(H5C_t *cache_ptr, H5C_auto_size_ctl_t *config_ptr);
+H5_DLL herr_t H5C_set_cache_image_config(const H5F_t *f, H5C_t *cache_ptr,
+ H5C_cache_image_ctl_t *config_ptr);
+H5_DLL herr_t H5C_set_evictions_enabled(H5C_t *cache_ptr, hbool_t evictions_enabled);
+H5_DLL herr_t H5C_set_prefix(H5C_t *cache_ptr, char *prefix);
+H5_DLL herr_t H5C_set_trace_file_ptr(H5C_t *cache_ptr, FILE *trace_file_ptr);
+H5_DLL herr_t H5C_stats(H5C_t *cache_ptr, const char *cache_name,
+ hbool_t display_detailed_stats);
+H5_DLL void H5C_stats__reset(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_unpin_entry(void *thing);
+H5_DLL herr_t H5C_destroy_flush_dependency(void *parent_thing, void *child_thing);
+H5_DLL herr_t H5C_unprotect(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *thing,
+ unsigned int flags);
+H5_DLL herr_t H5C_validate_cache_image_config(H5C_cache_image_ctl_t * ctl_ptr);
+H5_DLL herr_t H5C_validate_resize_config(H5C_auto_size_ctl_t *config_ptr,
+ unsigned int tests);
+H5_DLL herr_t H5C_ignore_tags(H5C_t *cache_ptr);
+H5_DLL hbool_t H5C_get_ignore_tags(const H5C_t *cache_ptr);
+H5_DLL herr_t H5C_retag_entries(H5C_t * cache_ptr, haddr_t src_tag, haddr_t dest_tag);
+H5_DLL herr_t H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked);
+H5_DLL herr_t H5C_get_entry_ring(const H5F_t *f, haddr_t addr, H5C_ring_t *ring);
+H5_DLL herr_t H5C_unsettle_entry_ring(void *thing);
+H5_DLL herr_t H5C_unsettle_ring(H5F_t * f, H5C_ring_t ring);
+H5_DLL herr_t H5C_remove_entry(void *thing);
+H5_DLL herr_t H5C_cache_image_status(H5F_t * f, hbool_t *load_ci_ptr,
+ hbool_t *write_ci_ptr);
+H5_DLL hbool_t H5C_cache_image_pending(const H5C_t *cache_ptr);
+H5_DLL herr_t H5C_get_mdc_image_info(H5C_t *cache_ptr, haddr_t *image_addr, hsize_t *image_len);
+
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5C_apply_candidate_list(H5F_t *f, hid_t dxpl_id,
+ H5C_t *cache_ptr, unsigned num_candidates, haddr_t *candidates_list_ptr,
+ int mpi_rank, int mpi_size);
+H5_DLL herr_t H5C_construct_candidate_list__clean_cache(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_construct_candidate_list__min_clean(H5C_t *cache_ptr);
+H5_DLL herr_t H5C_clear_coll_entries(H5C_t * cache_ptr, hbool_t partial);
+H5_DLL herr_t H5C_mark_entries_as_clean(H5F_t *f, hid_t dxpl_id, unsigned ce_array_len,
+ haddr_t *ce_array_ptr);
+#endif /* H5_HAVE_PARALLEL */
+
+#ifndef NDEBUG /* debugging functions */
+H5_DLL herr_t H5C_dump_cache(H5C_t *cache_ptr, const char *cache_name);
+H5_DLL herr_t H5C_dump_cache_LRU(H5C_t *cache_ptr, const char *cache_name);
+H5_DLL hbool_t H5C_get_serialization_in_progress(const H5C_t *cache_ptr);
+H5_DLL hbool_t H5C_cache_is_clean(const H5C_t *cache_ptr, H5C_ring_t inner_ring);
+H5_DLL herr_t H5C_dump_cache_skip_list(H5C_t *cache_ptr, char *calling_fcn);
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5C_dump_coll_write_list(H5C_t * cache_ptr, char * calling_fcn);
+#endif /* H5_HAVE_PARALLEL */
+H5_DLL herr_t H5C_get_entry_ptr_from_addr(H5C_t *cache_ptr, haddr_t addr,
+ void **entry_ptr_ptr);
+H5_DLL herr_t H5C_flush_dependency_exists(H5C_t *cache_ptr, haddr_t parent_addr,
+ haddr_t child_addr, hbool_t *fd_exists_ptr);
+H5_DLL herr_t H5C_verify_entry_type(H5C_t *cache_ptr, haddr_t addr,
+ const H5C_class_t *expected_type, hbool_t *in_cache_ptr,
+ hbool_t *type_ok_ptr);
+H5_DLL herr_t H5C_validate_index_list(H5C_t *cache_ptr);
+#endif /* NDEBUG */
+
+#endif /* !_H5Cprivate_H */
+
diff --git a/src/H5Cpublic.h b/src/H5Cpublic.h
new file mode 100644
index 0000000..62107d9
--- /dev/null
+++ b/src/H5Cpublic.h
@@ -0,0 +1,59 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cpublic.h
+ * June 4, 2005
+ * John Mainzer
+ *
+ * Purpose: Public include file for cache functions.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Cpublic_H
+#define _H5Cpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum H5C_cache_incr_mode
+{
+ H5C_incr__off,
+ H5C_incr__threshold
+};
+
+enum H5C_cache_flash_incr_mode
+{
+ H5C_flash_incr__off,
+ H5C_flash_incr__add_space
+};
+
+enum H5C_cache_decr_mode
+{
+ H5C_decr__off,
+ H5C_decr__threshold,
+ H5C_decr__age_out,
+ H5C_decr__age_out_with_threshold
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/H5Cquery.c b/src/H5Cquery.c
new file mode 100644
index 0000000..6c927b0
--- /dev/null
+++ b/src/H5Cquery.c
@@ -0,0 +1,484 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cquery.c
+ * May 30 2016
+ * Quincey Koziol
+ *
+ * Purpose: Routines which query different components of the generic
+ * cache structure or entries.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_cache_auto_resize_config
+ *
+ * Purpose: Copy the current configuration of the cache automatic
+ * re-sizing function into the instance of H5C_auto_size_ctl_t
+ * pointed to by config_ptr.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 10/8/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_cache_auto_resize_config(const H5C_t * cache_ptr,
+ H5C_auto_size_ctl_t *config_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad config_ptr on entry.")
+
+ *config_ptr = cache_ptr->resize_ctl;
+
+ config_ptr->set_initial_size = FALSE;
+ config_ptr->initial_size = cache_ptr->max_cache_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_cache_auto_resize_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_cache_size
+ *
+ * Purpose: Return the cache maximum size, the minimum clean size, the
+ * current size, and the current number of entries in
+ * *max_size_ptr, *min_clean_size_ptr, *cur_size_ptr, and
+ * *cur_num_entries_ptr respectively. If any of these
+ * parameters are NULL, skip that value.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 10/8/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_cache_size(H5C_t * cache_ptr,
+ size_t * max_size_ptr,
+ size_t * min_clean_size_ptr,
+ size_t * cur_size_ptr,
+ uint32_t * cur_num_entries_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+
+ if(max_size_ptr != NULL)
+ *max_size_ptr = cache_ptr->max_cache_size;
+
+ if(min_clean_size_ptr != NULL)
+ *min_clean_size_ptr = cache_ptr->min_clean_size;
+
+ if(cur_size_ptr != NULL)
+ *cur_size_ptr = cache_ptr->index_size;
+
+ if(cur_num_entries_ptr != NULL)
+ *cur_num_entries_ptr = cache_ptr->index_len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_cache_hit_rate
+ *
+ * Purpose: Compute and return the current cache hit rate in
+ * *hit_rate_ptr. If there have been no accesses since the
+ * last time the cache hit rate stats were reset, set
+ * *hit_rate_ptr to 0.0. On error, *hit_rate_ptr is
+ * undefined.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 10/7/04
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_cache_hit_rate(H5C_t * cache_ptr, double * hit_rate_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+ if(hit_rate_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad hit_rate_ptr on entry.")
+
+ HDassert(cache_ptr->cache_hits >= 0);
+ HDassert(cache_ptr->cache_accesses >= cache_ptr->cache_hits);
+
+ if(cache_ptr->cache_accesses > 0)
+ *hit_rate_ptr = ((double)(cache_ptr->cache_hits)) /
+ ((double)(cache_ptr->cache_accesses));
+ else
+ *hit_rate_ptr = 0.0f;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_cache_hit_rate() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_get_entry_status
+ *
+ * Purpose: This function is used to determine whether the cache
+ * contains an entry with the specified base address. If
+ * the entry exists, it also reports some status information
+ * on the entry.
+ *
+ * Status information is reported in the locations pointed
+ * to by the size_ptr, in_cache_ptr, is_dirty_ptr, and
+ * is_protected_ptr. While in_cache_ptr must be defined,
+ * the remaining pointers may be NULL, in which case the
+ * associated data is not reported.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 7/1/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_entry_status(const H5F_t *f,
+ haddr_t addr,
+ size_t * size_ptr,
+ hbool_t * in_cache_ptr,
+ hbool_t * is_dirty_ptr,
+ hbool_t * is_protected_ptr,
+ hbool_t * is_pinned_ptr,
+ hbool_t * is_corked_ptr,
+ hbool_t * is_flush_dep_parent_ptr,
+ hbool_t * is_flush_dep_child_ptr,
+ hbool_t * image_up_to_date_ptr)
+{
+ H5C_t * cache_ptr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+
+ cache_ptr = f->shared->cache;
+
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(in_cache_ptr != NULL);
+
+ /* this test duplicates two of the above asserts, but we need an
+ * invocation of HGOTO_ERROR to keep the compiler happy.
+ */
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ if(entry_ptr == NULL) {
+ /* the entry doesn't exist in the cache -- report this
+ * and quit.
+ */
+ *in_cache_ptr = FALSE;
+ } /* end if */
+ else {
+ *in_cache_ptr = TRUE;
+ if(size_ptr != NULL)
+ *size_ptr = entry_ptr->size;
+ if(is_dirty_ptr != NULL)
+ *is_dirty_ptr = entry_ptr->is_dirty;
+ if(is_protected_ptr != NULL)
+ *is_protected_ptr = entry_ptr->is_protected;
+ if(is_pinned_ptr != NULL)
+ *is_pinned_ptr = entry_ptr->is_pinned;
+ if(is_corked_ptr != NULL)
+ *is_corked_ptr = entry_ptr->tag_info ? entry_ptr->tag_info->corked : FALSE;
+ if(is_flush_dep_parent_ptr != NULL)
+ *is_flush_dep_parent_ptr = (entry_ptr->flush_dep_nchildren > 0);
+ if(is_flush_dep_child_ptr != NULL)
+ *is_flush_dep_child_ptr = (entry_ptr->flush_dep_nparents > 0);
+ if(image_up_to_date_ptr != NULL )
+ *image_up_to_date_ptr = entry_ptr->image_up_to_date;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_entry_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_evictions_enabled()
+ *
+ * Purpose: Copy the current value of cache_ptr->evictions_enabled into
+ * *evictions_enabled_ptr.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: John Mainzer
+ * 7/27/07
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_evictions_enabled(const H5C_t *cache_ptr,
+ hbool_t * evictions_enabled_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL ) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.")
+
+ if(evictions_enabled_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad evictions_enabled_ptr on entry.")
+
+ *evictions_enabled_ptr = cache_ptr->evictions_enabled;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_evictions_enabled() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_aux_ptr
+ *
+ * Purpose: Get the aux_ptr field from the cache.
+ *
+ * This field will either be NULL (when accessing a file serially)
+ * or contains a pointer to the auxiliary info for parallel I/O.
+ *
+ * Return: NULL/non-NULL (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * 6/29/15
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5C_get_aux_ptr(const H5C_t *cache_ptr)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Check arguments */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ FUNC_LEAVE_NOAPI(cache_ptr->aux_ptr)
+} /* H5C_get_aux_ptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_trace_file_ptr
+ *
+ * Purpose: Get the trace_file_ptr field from the cache.
+ *
+ * This field will either be NULL (which indicates that trace
+ * file logging is turned off), or contain a pointer to the
+ * open file to which trace file data is to be written.
+ *
+ * Return: Non-NULL trace file pointer (can't fail)
+ *
+ * Programmer: John Mainzer
+ * 1/20/06
+ *
+ *-------------------------------------------------------------------------
+ */
+FILE *
+H5C_get_trace_file_ptr(const H5C_t *cache_ptr)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Check arguments */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ FUNC_LEAVE_NOAPI(cache_ptr->trace_file_ptr)
+} /* H5C_get_trace_file_ptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_trace_file_ptr_from_entry
+ *
+ * Purpose: Get the trace_file_ptr field from the cache, via an entry.
+ *
+ * This field will either be NULL (which indicates that trace
+ * file logging is turned off), or contain a pointer to the
+ * open file to which trace file data is to be written.
+ *
+ * Return: Non-NULL trace file pointer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * 6/9/08
+ *
+ *-------------------------------------------------------------------------
+ */
+FILE *
+H5C_get_trace_file_ptr_from_entry(const H5C_cache_entry_t *entry_ptr)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(entry_ptr);
+ HDassert(entry_ptr->cache_ptr);
+
+ FUNC_LEAVE_NOAPI(H5C_get_trace_file_ptr(entry_ptr->cache_ptr))
+} /* H5C_get_trace_file_ptr_from_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_entry_ring
+ *
+ * Purpose: Given a file address, retrieve the ring for an entry at that
+ * address.
+ *
+ * On error, the value of *ring is not modified.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 9/8/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_entry_ring(const H5F_t *f, haddr_t addr, H5C_ring_t *ring)
+{
+ H5C_t *cache_ptr; /* Pointer to cache */
+ H5C_cache_entry_t *entry_ptr; /* Pointer to cache entry at address */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache_ptr = f->shared->cache;
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Locate the entry at the address */
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+ if(entry_ptr == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, "can't find entry in index")
+
+ /* Return the ring value */
+ *ring = entry_ptr->ring;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_entry_ring() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_get_mdc_image_info
+ *
+ * Purpose: To retrieve the address and size of the cache image in the file.
+ *
+ * Return: SUCCEED on success, and FAIL on failure.
+ *
+ * Programmer: Vailin Choi; March 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_mdc_image_info(H5C_t * cache_ptr, haddr_t *image_addr, hsize_t *image_len)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry")
+ if(image_addr == NULL || image_len == NULL)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad image_addr or image_len on entry")
+
+ *image_addr = cache_ptr->image_addr;
+ *image_len = cache_ptr->image_len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_get_mdc_image_info() */
+
diff --git a/src/H5Ctag.c b/src/H5Ctag.c
new file mode 100644
index 0000000..a9b2ec0
--- /dev/null
+++ b/src/H5Ctag.c
@@ -0,0 +1,907 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ctag.c
+ * June 5 2016
+ * Quincey Koziol
+ *
+ * Purpose: Functions in this file operate on tags for metadata
+ * cache entries.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for tagged entry iterator callback context - evict tagged entries */
+typedef struct {
+ H5F_t * f; /* File pointer for evicting entry */
+ hid_t dxpl_id; /* DXPL for evicting entry */
+ hbool_t evicted_entries_last_pass; /* Flag to indicate that an entry
+ * was evicted when iterating over
+ * cache
+ */
+ hbool_t pinned_entries_need_evicted;/* Flag to indicate that a pinned
+ * entry was attempted to be evicted
+ */
+ hbool_t skipped_pf_dirty_entries; /* Flag indicating that one or more
+ * entries marked prefetched_dirty
+ * were encountered and not
+ * evicted.
+ */
+} H5C_tag_iter_evict_ctx_t;
+
+/* Typedef for tagged entry iterator callback context - expunge tag type metadata */
+typedef struct {
+ H5F_t * f; /* File pointer for evicting entry */
+ hid_t dxpl_id; /* DXPL for evicting entry */
+ int type_id; /* Cache entry type to expunge */
+ unsigned flags; /* Flags for expunging entry */
+} H5C_tag_iter_ettm_ctx_t;
+
+/* Typedef for tagged entry iterator callback context - mark corked */
+typedef struct {
+ hbool_t cork_val; /* Corked value */
+} H5C_tag_iter_cork_ctx_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5C__mark_tagged_entries(H5C_t *cache_ptr, haddr_t tag);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare extern free list to manage the tag info struct */
+H5FL_EXTERN(H5C_tag_info_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_ignore_tags
+ *
+ * Purpose: Override all assertion frameworks associated with making
+ * sure proper tags are applied to cache entries.
+ *
+ * NOTE: This should really only be used in tests that need
+ * to access internal functions without going through
+ * standard API paths. Since tags are set inside dxpl_id's
+ * before coming into the cache, any external functions that
+ * use the internal library functions (i.e., tests) should
+ * use this function if they don't plan on setting up proper
+ * metadata tags.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * December 1, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_ignore_tags(H5C_t * cache_ptr)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Assertions */
+ HDassert(cache_ptr != NULL);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Set variable to ignore tag values upon assignment */
+ cache_ptr->ignore_tags = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C_ignore_tags */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_get_ignore_tags
+ *
+ * Purpose: Retrieve the 'ignore_tags' field for the cache
+ *
+ * Return: 'ignore_tags' value (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * April 30, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5C_get_ignore_tags(const H5C_t *cache_ptr)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Return ignore tag value */
+ FUNC_LEAVE_NOAPI(cache_ptr->ignore_tags)
+} /* H5C_get_ignore_tags */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__tag_entry
+ *
+ * Purpose: Tags an entry with the provided tag (contained in the dxpl_id).
+ * If sanity checking is enabled, this function will perform
+ * validation that a proper tag is contained within the provided
+ * data access property list id before application.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * January 14, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__tag_entry(H5C_t *cache, H5C_cache_entry_t *entry, hid_t dxpl_id)
+{
+ H5P_genplist_t *dxpl; /* dataset transfer property list */
+ H5C_tag_info_t *tag_info; /* Points to a tag info struct */
+ haddr_t tag; /* Tag value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Assertions */
+ HDassert(cache != NULL);
+ HDassert(entry != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the tag from the DXPL */
+ if((H5P_get(dxpl, H5AC_TAG_NAME, &tag)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value")
+
+ if(cache->ignore_tags) {
+ /* if we're ignoring tags, it's because we're running
+ tests on internal functions and may not have inserted a tag
+ value into a given dxpl_id before creating some metadata. Thus,
+ in this case only, if a tag value has not been set, we can
+ arbitrarily set it to something for the sake of passing the tests.
+ If the tag value is set, then we'll just let it get assigned without
+ additional checking for correctness. */
+ if(!H5F_addr_defined(tag))
+ tag = H5AC__IGNORE_TAG;
+ } /* end if */
+#if H5C_DO_TAGGING_SANITY_CHECKS
+ else {
+ /* Perform some sanity checks to ensure that a correct tag is being applied */
+ if(H5C_verify_tag(entry->type->id, tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "tag verification failed")
+ } /* end else */
+#endif
+
+ /* Search the list of tagged object addresses in the cache */
+ tag_info = (H5C_tag_info_t *)H5SL_search(cache->tag_list, &tag);
+
+ /* Check if this is the first entry for this tagged object */
+ if(NULL == tag_info) {
+ /* Allocate new tag info struct */
+ if(NULL == (tag_info = H5FL_CALLOC(H5C_tag_info_t)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "can't allocate tag info for cache entry")
+
+ /* Set the tag for all entries */
+ tag_info->tag = tag;
+
+ /* Insert tag info into skip list */
+ if(H5SL_insert(cache->tag_list, tag_info, &(tag_info->tag)) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert tag info in skip list")
+ } /* end if */
+ else
+ HDassert(tag_info->corked || (tag_info->entry_cnt > 0 && tag_info->head));
+
+ /* Sanity check entry, to avoid double insertions, etc */
+ HDassert(entry->tl_next == NULL);
+ HDassert(entry->tl_prev == NULL);
+ HDassert(entry->tag_info == NULL);
+
+ /* Add the entry to the list for the tagged object */
+ entry->tl_next = tag_info->head;
+ entry->tag_info = tag_info;
+ if(tag_info->head)
+ tag_info->head->tl_prev = entry;
+ tag_info->head = entry;
+ tag_info->entry_cnt++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__tag_entry */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__untag_entry
+ *
+ * Purpose: Removes an entry from a tag list, possibly removing the tag
+ * info from the list of tagged objects with entries.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Quincey Koziol
+ * July 8, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__untag_entry(H5C_t *cache, H5C_cache_entry_t *entry)
+{
+ H5C_tag_info_t *tag_info; /* Points to a tag info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Assertions */
+ HDassert(cache != NULL);
+ HDassert(entry != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Get the entry's tag info struct */
+ if(NULL != (tag_info = entry->tag_info)) {
+ /* Remove the entry from the list */
+ if(entry->tl_next)
+ entry->tl_next->tl_prev = entry->tl_prev;
+ if(entry->tl_prev)
+ entry->tl_prev->tl_next = entry->tl_next;
+ if(tag_info->head == entry)
+ tag_info->head = entry->tl_next;
+ tag_info->entry_cnt--;
+
+ /* Reset pointers, to avoid confusion */
+ entry->tl_next = NULL;
+ entry->tl_prev = NULL;
+ entry->tag_info = NULL;
+
+ /* Remove the tag info from the tag list, if there's no more entries with this tag */
+ if(!tag_info->corked && 0 == tag_info->entry_cnt) {
+ /* Sanity check */
+ HDassert(NULL == tag_info->head);
+
+ if(H5SL_remove(cache->tag_list, &(tag_info->tag)) != tag_info)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove tag info from list")
+
+ /* Release the tag info */
+ tag_info = H5FL_FREE(H5C_tag_info_t, tag_info);
+ } /* end if */
+ else
+ HDassert(tag_info->corked || NULL != tag_info->head);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__untag_entry */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__iter_tagged_entries_real
+ *
+ * Purpose: Iterate over tagged entries, making a callback for matches
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Quincey Koziol
+ * June 7, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__iter_tagged_entries_real(H5C_t *cache, haddr_t tag, H5C_tag_iter_cb_t cb,
+ void *cb_ctx)
+{
+ H5C_tag_info_t *tag_info; /* Points to a tag info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(cache != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Search the list of tagged object addresses in the cache */
+ tag_info = (H5C_tag_info_t *)H5SL_search(cache->tag_list, &tag);
+
+ /* If there's any entries for this tag, iterate over them */
+ if(tag_info) {
+ H5C_cache_entry_t *entry; /* Pointer to current entry */
+ H5C_cache_entry_t *next_entry; /* Pointer to next entry in hash bucket chain */
+
+ /* Sanity check */
+ HDassert(tag_info->head);
+ HDassert(tag_info->entry_cnt > 0);
+
+ /* Iterate over the entries for this tag */
+ entry = tag_info->head;
+ while(entry) {
+ /* Acquire pointer to next entry */
+ next_entry = entry->tl_next;
+
+ /* Make callback for entry */
+ if((cb)(entry, cb_ctx) != H5_ITER_CONT)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "tagged entry iteration callback failed")
+
+ /* Advance to next entry */
+ entry = next_entry;
+ } /* end while */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__iter_tagged_entries_real() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__iter_tagged_entries
+ *
+ * Purpose: Iterate over tagged entries, making a callback for matches
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Quincey Koziol
+ * June 7, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__iter_tagged_entries(H5C_t *cache, haddr_t tag, hbool_t match_global,
+ H5C_tag_iter_cb_t cb, void *cb_ctx)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(cache != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Iterate over the entries for this tag */
+ if(H5C__iter_tagged_entries_real(cache, tag, cb, cb_ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "iteration of tagged entries failed")
+
+ /* Check for iterating over global metadata */
+ if(match_global) {
+ /* Iterate over the entries for SOHM entries */
+ if(H5C__iter_tagged_entries_real(cache, H5AC__SOHM_TAG, cb, cb_ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "iteration of tagged entries failed")
+
+ /* Iterate over the entries for global heap entries */
+ if(H5C__iter_tagged_entries_real(cache, H5AC__GLOBALHEAP_TAG, cb, cb_ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "iteration of tagged entries failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__iter_tagged_entries() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__evict_tagged_entries_cb
+ *
+ * Purpose: Callback for evicting tagged entries
+ *
+ * Return: H5_ITER_ERROR if error is detected, H5_ITER_CONT otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * August 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__evict_tagged_entries_cb(H5C_cache_entry_t *entry, void *_ctx)
+{
+ H5C_tag_iter_evict_ctx_t *ctx = (H5C_tag_iter_evict_ctx_t *)_ctx; /* Get pointer to iterator context */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Santify checks */
+ HDassert(entry);
+ HDassert(ctx);
+
+ /* Attempt to evict entry */
+ if(entry->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Cannot evict protected entry")
+ else if(entry->is_dirty)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Cannot evict dirty entry")
+ else if(entry->is_pinned)
+ /* Can't evict at this time, but let's note that we hit a pinned
+ entry and we'll loop back around again (as evicting other
+ entries will hopefully unpin this entry) */
+ ctx->pinned_entries_need_evicted = TRUE;
+ else if(!entry->prefetched_dirty) {
+ /* Evict the Entry */
+ if(H5C__flush_single_entry(ctx->f, ctx->dxpl_id, entry, H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Entry eviction failed.")
+ ctx->evicted_entries_last_pass = TRUE;
+ } else {
+ ctx->skipped_pf_dirty_entries = TRUE;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__evict_tagged_entries_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_evict_tagged_entries
+ *
+ * Purpose: Evicts all entries with the specified tag from cache
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * August 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag, hbool_t match_global)
+{
+ H5C_t *cache; /* Pointer to cache structure */
+ H5C_tag_iter_evict_ctx_t ctx; /* Context for iterator callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache = f->shared->cache; /* Get cache pointer */
+ HDassert(cache != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Construct context for iterator callbacks */
+ ctx.f = f;
+ ctx.dxpl_id = dxpl_id;
+
+ /* Start evicting entries */
+ do {
+ /* Reset pinned/evicted tracking flags */
+ ctx.pinned_entries_need_evicted = FALSE;
+ ctx.evicted_entries_last_pass = FALSE;
+ ctx.skipped_pf_dirty_entries = FALSE;
+
+ /* Iterate through entries in the cache */
+ if(H5C__iter_tagged_entries(cache, tag, match_global, H5C__evict_tagged_entries_cb, &ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "Iteration of tagged entries failed")
+
+ /* Keep doing this until we have stopped evicted entries */
+ } while(TRUE == ctx.evicted_entries_last_pass);
+
+ /* In most cases, fail if we have finished evicting entries and pinned
+ * entries still need evicted
+ *
+ * However, things can get strange if the file was opened R/O and
+ * the file contains a cache image and the cache image contains dirty
+ * entries.
+ *
+ * Since the file was opened read only, dirty entries in the cache
+ * image were marked as clean when they were inserted into the metadata
+ * cache. This is necessary, as if they are marked dirty, the metadata
+ * cache will attempt to write them on file close, which is frowned
+ * upon when the file is opened R/O.
+ *
+ * On the other hand, such entries (marked prefetched_dirty) must not
+ * be evicted, as should the cache be asked to re-load them, the cache
+ * will attempt to read them from the file, and at best load an outdated
+ * version.
+ *
+ * To avoid this, H5C__evict_tagged_entries_cb has been modified to
+ * skip such entries. However, by doing so, it may prevent pinned
+ * entries from becoming unpinned.
+ *
+ * Thus we must ignore ctx.pinned_entries_need_evicted if
+ * ctx.skipped_pf_dirty_entries is TRUE.
+ */
+ if((!ctx.skipped_pf_dirty_entries) && (ctx.pinned_entries_need_evicted))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entries still need evicted?!")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_evict_tagged_entries() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__mark_tagged_entries_cb
+ *
+ * Purpose: Callback to set the flush marker on dirty entries in the cache
+ *
+ * Return: H5_ITER_CONT (can't fail)
+ *
+ * Programmer: Mike McGreevy
+ * September 9, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__mark_tagged_entries_cb(H5C_cache_entry_t *entry, void H5_ATTR_UNUSED *_ctx)
+{
+ /* Function enter macro */
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(entry);
+
+ /* We only want to set the flush marker on entries that
+ * actually need flushed (i.e., dirty ones) */
+ if(entry->is_dirty)
+ entry->flush_marker = TRUE;
+
+ FUNC_LEAVE_NOAPI(H5_ITER_CONT)
+} /* H5C__mark_tagged_entries_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__mark_tagged_entries
+ *
+ * Purpose: Set the flush marker on dirty entries in the cache that have
+ * the specified tag, as well as all globally tagged entries.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * September 9, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C__mark_tagged_entries(H5C_t *cache, haddr_t tag)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(cache);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Iterate through hash table entries, marking those with specified tag, as
+ * well as any major global entries which should always be flushed
+ * when flushing based on tag value */
+ if(H5C__iter_tagged_entries(cache, tag, TRUE, H5C__mark_tagged_entries_cb, NULL) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "Iteration of tagged entries failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__mark_tagged_entries() */
+
+#if H5C_DO_TAGGING_SANITY_CHECKS
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_verify_tag
+ *
+ * Purpose: Performs sanity checking on an entrytype/tag pair.
+ *
+ * Return: SUCCEED or FAIL.
+ *
+ * Programmer: Mike McGreevy
+ * January 14, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_verify_tag(int id, haddr_t tag)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Perform some sanity checks on tag value. Certain entry
+ * types require certain tag values, so check that these
+ * constraints are met. */
+ if(tag == H5AC__IGNORE_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "cannot ignore a tag while doing verification.")
+ else if(tag == H5AC__INVALID_TAG) {
+ if(id != H5AC_PROXY_ENTRY_ID)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "no metadata tag provided")
+ } /* end else-if */
+ else {
+ /* Perform some sanity checks on tag value. Certain entry
+ * types require certain tag values, so check that these
+ * constraints are met. */
+
+ /* Superblock */
+ if((id == H5AC_SUPERBLOCK_ID) || (id == H5AC_DRVRINFO_ID)) {
+ if(tag != H5AC__SUPERBLOCK_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock not tagged with H5AC__SUPERBLOCK_TAG")
+ } /* end if */
+ else {
+ if(tag == H5AC__SUPERBLOCK_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__SUPERBLOCK_TAG applied to non-superblock entry")
+ } /* end else */
+
+ /* Free Space Manager */
+ if(tag == H5AC__FREESPACE_TAG && ((id != H5AC_FSPACE_HDR_ID) && (id != H5AC_FSPACE_SINFO_ID)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__FREESPACE_TAG applied to non-freespace entry")
+
+ /* SOHM */
+ if((id == H5AC_SOHM_TABLE_ID) || (id == H5AC_SOHM_LIST_ID))
+ if(tag != H5AC__SOHM_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "sohm entry not tagged with H5AC__SOHM_TAG")
+
+ /* Global Heap */
+ if(id == H5AC_GHEAP_ID) {
+ if(tag != H5AC__GLOBALHEAP_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "global heap not tagged with H5AC__GLOBALHEAP_TAG")
+ } /* end if */
+ else {
+ if(tag == H5AC__GLOBALHEAP_TAG)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__GLOBALHEAP_TAG applied to non-globalheap entry")
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_verify_tag */
+#endif
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_flush_tagged_entries
+ *
+ * Purpose: Flushes all entries with the specified tag to disk.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * August 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag)
+{
+ /* Variable Declarations */
+ H5C_t *cache_ptr = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Assertions */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Get cache pointer */
+ cache_ptr = f->shared->cache;
+
+ /* Mark all entries with specified tag */
+ if(H5C__mark_tagged_entries(cache_ptr, tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't mark tagged entries")
+
+ /* Flush all marked entries */
+ if(H5C__flush_marked_entries(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush marked entries")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_flush_tagged_entries */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_retag_entries
+ *
+ * Purpose: Searches through cache index for all entries with the
+ * value specified by src_tag and changes it to the value
+ * specified by dest_tag.
+ *
+ * Return: SUCCEED or FAIL.
+ *
+ * Programmer: Mike McGreevy
+ * March 17, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_retag_entries(H5C_t *cache, haddr_t src_tag, haddr_t dest_tag)
+{
+ H5C_tag_info_t *tag_info; /* Points to a tag info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cache);
+
+ /* Remove tag info from tag list */
+ if(NULL != (tag_info = (H5C_tag_info_t *)H5SL_remove(cache->tag_list, &src_tag))) {
+ /* Change to new tag */
+ tag_info->tag = dest_tag;
+
+ /* Re-insert tag info into skip list */
+ if(H5SL_insert(cache->tag_list, tag_info, &(tag_info->tag)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert tag info in skip list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_retag_entries() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__expunge_tag_type_metadata_cb
+ *
+ * Purpose: Expunge from the cache entries associated
+ * with 'tag' and type id.
+ *
+ * Return: H5_ITER_ERROR if error is detected, H5_ITER_CONT otherwise.
+ *
+ * Programmer: Vailin Choi
+ * May 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__expunge_tag_type_metadata_cb(H5C_cache_entry_t *entry, void *_ctx)
+{
+ H5C_tag_iter_ettm_ctx_t *ctx = (H5C_tag_iter_ettm_ctx_t *)_ctx; /* Get pointer to iterator context */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Santify checks */
+ HDassert(entry);
+ HDassert(ctx);
+
+ /* Found one with the same tag and type id */
+ if(entry->type->id == ctx->type_id)
+ if(H5C_expunge_entry(ctx->f, ctx->dxpl_id, entry->type, entry->addr, ctx->flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, H5_ITER_ERROR, "can't expunge entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__expunge_tag_type_metadata_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_expunge_tag_type_metadata
+ *
+ * Purpose: Search and expunge from the cache entries associated
+ * with 'tag' and type id.
+ *
+ * Return: FAIL if error is detected, SUCCEED otherwise.
+ *
+ * Programmer: Vailin Choi
+ * May 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id,
+ unsigned flags)
+{
+ H5C_t *cache; /* Pointer to cache structure */
+ H5C_tag_iter_ettm_ctx_t ctx; /* Context for iterator callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache = f->shared->cache; /* Get cache pointer */
+ HDassert(cache != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Construct context for iterator callbacks */
+ ctx.f = f;
+ ctx.dxpl_id = dxpl_id;
+ ctx.type_id = type_id;
+ ctx.flags = flags;
+
+ /* Iterate through hash table entries, expunge those with specified tag and type id */
+ if(H5C__iter_tagged_entries(cache, tag, FALSE, H5C__expunge_tag_type_metadata_cb, &ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "Iteration of tagged entries failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_expunge_tag_type_metadata() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_get_tag()
+ *
+ * Purpose: Get the tag for a metadata cache entry.
+ *
+ * Return: SUCCEED (can't fail)
+ *
+ * Programmer: Dana Robinson
+ * Fall 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_get_tag(const void *thing, haddr_t *tag /*OUT*/)
+{
+ const H5C_cache_entry_t *entry = (const H5C_cache_entry_t *)thing; /* Pointer to cache entry */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ HDassert(entry);
+ HDassert(entry->tag_info);
+ HDassert(tag);
+
+ /* Return the tag */
+ *tag = entry->tag_info->tag;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5C_get_tag() */
+
diff --git a/src/H5Ctest.c b/src/H5Ctest.c
new file mode 100644
index 0000000..2cd0a5d
--- /dev/null
+++ b/src/H5Ctest.c
@@ -0,0 +1,161 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ctest.c
+ * June 7 2016
+ * Quincey Koziol
+ *
+ * Purpose: Functions in this file support the metadata cache regression
+ * tests>
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Cmodule.h" /* This source code file is part of the H5C module */
+#define H5C_TESTING /*suppress warning about H5C testing funcs*/
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Cpkg.h" /* Cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for tagged entry iterator callback context - verify cork tag */
+typedef struct {
+ hbool_t status; /* Corked status */
+} H5C_tag_iter_vct_ctx_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__verify_cork_tag_test_cb
+ *
+ * Purpose: Verify the cork status for an entry
+ *
+ * Return: SUCCEED on success, FAIL on error
+ *
+ * Programmer: Vailin Choi
+ * Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__verify_cork_tag_test_cb(H5C_cache_entry_t *entry, void *_ctx)
+{
+ H5C_tag_iter_vct_ctx_t *ctx = (H5C_tag_iter_vct_ctx_t *)_ctx; /* Get pointer to iterator context */
+ hbool_t is_corked; /* Corked status for entry */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Santify checks */
+ HDassert(entry);
+ HDassert(ctx);
+
+ /* Retrieve corked status for entry */
+ is_corked = entry->tag_info ? entry->tag_info->corked : FALSE;
+
+ /* Verify corked status for entry */
+ if(is_corked != ctx->status)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, H5_ITER_ERROR, "bad cork status")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__verify_cork_tag_test_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C__verify_cork_tag_test
+ *
+ * Purpose: This routine verifies that all cache entries associated with
+ * the object tag are marked with the desired "cork" status.
+ *
+ * Return: SUCCEED on success, FAIL on error
+ *
+ * Programmer: Vailin Choi
+ * Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C__verify_cork_tag_test(hid_t fid, haddr_t tag, hbool_t status)
+{
+ H5F_t * f; /* File Pointer */
+ H5C_t * cache; /* Cache Pointer */
+ H5C_tag_iter_vct_ctx_t ctx; /* Context for iterator callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_PACKAGE
+
+ /* Get file pointer */
+ if(NULL == (f = (H5F_t *)H5I_object_verify(fid, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Get cache pointer */
+ cache = f->shared->cache;
+
+ /* Construct context for iterator callbacks */
+ ctx.status = status;
+
+ /* Iterate through tagged entries in the cache */
+ if(H5C__iter_tagged_entries(cache, tag, FALSE, H5C__verify_cork_tag_test_cb, &ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "iteration of tagged entries failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__verify_cork_tag_test() */
+
diff --git a/src/H5D.c b/src/H5D.c
new file mode 100644
index 0000000..6f69ee4
--- /dev/null
+++ b/src/H5D.c
@@ -0,0 +1,1089 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare extern the free list to manage blocks of VL data */
+H5FL_BLK_EXTERN(vlen_vl_buf);
+
+/* Declare extern the free list to manage other blocks of VL data */
+H5FL_BLK_EXTERN(vlen_fl_buf);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dcreate2
+ *
+ * Purpose: Creates a new dataset named NAME at LOC_ID, opens the
+ * dataset for access, and associates with that dataset constant
+ * and initial persistent properties including the type of each
+ * datapoint as stored in the file (TYPE_ID), the size of the
+ * dataset (SPACE_ID), and other initial miscellaneous
+ * properties (DCPL_ID).
+ *
+ * All arguments are copied into the dataset, so the caller is
+ * allowed to derive new types, dataspaces, and creation
+ * parameters from the old ones and reuse them in calls to
+ * create other datasets.
+ *
+ * Return: Success: The object ID of the new dataset. At this
+ * point, the dataset is ready to receive its
+ * raw data. Attempting to read raw data from
+ * the dataset will probably return the fill
+ * value. The dataset should be closed when the
+ * caller is no longer interested in it.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dcreate2(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id,
+ hid_t lcpl_id, hid_t dcpl_id, hid_t dapl_id)
+{
+ H5G_loc_t loc; /* Object location to insert dataset into */
+ H5D_t *dset = NULL; /* New dataset's info */
+ const H5S_t *space; /* Dataspace for dataset */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("i", "i*siiiii", loc_id, name, type_id, space_id, lcpl_id, dcpl_id,
+ dapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location ID")
+ if(H5I_DATATYPE != H5I_get_type(type_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype ID")
+ if(NULL == (space = (const H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace ID")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == lcpl_id)
+ lcpl_id = H5P_LINK_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == dcpl_id)
+ dcpl_id = H5P_DATASET_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dcpl_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not dataset create property list ID")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&dapl_id, H5P_CLS_DACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Create the new dataset & get its ID */
+ if(NULL == (dset = H5D__create_named(&loc, name, type_id, space, lcpl_id, dcpl_id, dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset")
+ if((ret_value = H5I_register(H5I_DATASET, dset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register dataset")
+
+done:
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dcreate2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dcreate_anon
+ *
+ * Purpose: Creates a new dataset named NAME at LOC_ID, opens the
+ * dataset for access, and associates with that dataset constant
+ * and initial persistent properties including the type of each
+ * datapoint as stored in the file (TYPE_ID), the size of the
+ * dataset (SPACE_ID), and other initial miscellaneous
+ * properties (DCPL_ID).
+ *
+ * All arguments are copied into the dataset, so the caller is
+ * allowed to derive new types, dataspaces, and creation
+ * parameters from the old ones and reuse them in calls to
+ * create other datasets.
+ *
+ * The resulting ID should be linked into the file with
+ * H5Olink or it will be deleted when closed.
+ *
+ * Return: Success: The object ID of the new dataset. At this
+ * point, the dataset is ready to receive its
+ * raw data. Attempting to read raw data from
+ * the dataset will probably return the fill
+ * value. The dataset should be linked into
+ * the group hierarchy before being closed or
+ * it will be deleted. The dataset should be
+ * closed when the caller is no longer interested
+ * in it.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: James Laird
+ * Tuesday, January 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dcreate_anon(hid_t loc_id, hid_t type_id, hid_t space_id, hid_t dcpl_id,
+ hid_t dapl_id)
+{
+ H5G_loc_t loc; /* Object location to insert dataset into */
+ H5D_t *dset = NULL; /* New dataset's info */
+ const H5S_t *space; /* Dataspace for dataset */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("i", "iiiii", loc_id, type_id, space_id, dcpl_id, dapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location ID")
+ if(H5I_DATATYPE != H5I_get_type(type_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype ID")
+ if(NULL == (space = (const H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace ID")
+ if(H5P_DEFAULT == dcpl_id)
+ dcpl_id = H5P_DATASET_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dcpl_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not dataset create property list ID")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&dapl_id, H5P_CLS_DACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* build and open the new dataset */
+ if(NULL == (dset = H5D__create(loc.oloc->file, type_id, space, dcpl_id, dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset")
+
+ /* Register the new dataset to get an ID for it */
+ if((ret_value = H5I_register(H5I_DATASET, dset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register dataset")
+
+done:
+ /* Release the dataset's object header, if it was created */
+ if(dset) {
+ H5O_loc_t *oloc; /* Object location for dataset */
+
+ /* Get the new dataset's object location */
+ if(NULL == (oloc = H5D_oloc(dset)))
+ HDONE_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get object location of dataset")
+
+ /* Decrement refcount on dataset's object header in memory */
+ if(H5O_dec_rc_by_loc(oloc, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+ } /* end if */
+
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dcreate_anon() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dopen2
+ *
+ * Purpose: Finds a dataset named NAME at LOC_ID, opens it, and returns
+ * its ID. The dataset should be close when the caller is no
+ * longer interested in it.
+ *
+ * Takes a dataset access property list
+ *
+ * Return: Success: A new dataset ID
+ * Failure: FAIL
+ *
+ * Programmer: James Laird
+ * Thursday, July 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dopen2(hid_t loc_id, const char *name, hid_t dapl_id)
+{
+ H5D_t *dset = NULL;
+ H5G_loc_t loc; /* Object location of group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl to use to open datset */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*si", loc_id, name, dapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&dapl_id, H5P_CLS_DACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the dataset */
+ if(NULL == (dset = H5D__open_name(&loc, name, dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
+
+ /* Register an atom for the dataset */
+ if((ret_value = H5I_register(H5I_DATASET, dset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "can't register dataset atom")
+
+done:
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dopen2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dclose
+ *
+ * Purpose: Closes access to a dataset (DATASET_ID) and releases
+ * resources used by it. It is illegal to subsequently use that
+ * same dataset ID in calls to other dataset functions.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dclose(hid_t dset_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", dset_id);
+
+ /* Check args */
+ if(NULL == H5I_object_verify(dset_id, H5I_DATASET))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /*
+ * Decrement the counter on the dataset. It will be freed if the count
+ * reaches zero.
+ */
+ if(H5I_dec_app_ref_always_close(dset_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't decrement count on dataset ID")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_space
+ *
+ * Purpose: Returns a copy of the file dataspace for a dataset.
+ *
+ * Return: Success: ID for a copy of the dataspace. The data
+ * space should be released by calling
+ * H5Sclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 28, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dget_space(hid_t dset_id)
+{
+ H5D_t *dset = NULL;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if((ret_value = H5D_get_space(dset)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get dataspace")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_space_status
+ *
+ * Purpose: Returns the status of dataspace allocation.
+ *
+ * Return:
+ * Success: Non-negative
+ *
+ * Failture: Negative
+ *
+ * Programmer: Raymond Lu
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dget_space_status(hid_t dset_id, H5D_space_status_t *allocation)
+{
+ H5D_t *dset = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Ds", dset_id, allocation);
+
+ /* Check arguments */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* Read dataspace address and return */
+ if(H5D__get_space_status(dset, allocation, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get space status")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dget_space_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_type
+ *
+ * Purpose: Returns a copy of the file datatype for a dataset.
+ *
+ * Return: Success: ID for a copy of the datatype. The data
+ * type should be released by calling
+ * H5Tclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, February 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dget_type(hid_t dset_id)
+{
+
+ H5D_t *dset; /* Dataset */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if((ret_value = H5D_get_type(dset)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get dataspace")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_create_plist
+ *
+ * Purpose: Returns a copy of the dataset creation property list.
+ *
+ * Return: Success: ID for a copy of the dataset creation
+ * property list. The template should be
+ * released by calling H5P_close().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, February 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dget_create_plist(hid_t dset_id)
+{
+ H5D_t *dataset; /* Dataset structure */
+ hid_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dataset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if((ret_value = H5D_get_create_plist(dataset)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "Can't get creation plist")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_access_plist
+ *
+ * Purpose: Returns a copy of the dataset creation property list.
+ *
+ * Description: H5Dget_access_plist returns the dataset access property
+ * list identifier of the specified dataset.
+ *
+ * The chunk cache parameters in the returned property lists will be
+ * those used by the dataset. If the properties in the file access
+ * property list were used to determine the dataset’s chunk cache
+ * configuration, then those properties will be present in the
+ * returned dataset access property list. If the dataset does not
+ * use a chunked layout, then the chunk cache properties will be set
+ * to the default. The chunk cache properties in the returned list
+ * are considered to be “set”, and any use of this list will override
+ * the corresponding properties in the file’s file access property
+ * list.
+ *
+ * All link access properties in the returned list will be set to the
+ * default values.
+ *
+ * Return: Success: ID for a copy of the dataset access
+ * property list. The template should be
+ * released by calling H5Pclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, October 29, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dget_access_plist(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset structure */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", dset_id);
+
+ /* Check args */
+ if (NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if((ret_value = H5D_get_access_plist(dset)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "Can't get access plist")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_access_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_storage_size
+ *
+ * Purpose: Returns the amount of storage that is required for the
+ * dataset. For chunked datasets this is the number of allocated
+ * chunks times the chunk size.
+ *
+ * Return: Success: The amount of storage space allocated for the
+ * dataset, not counting meta data. The return
+ * value may be zero if no data has been stored.
+ *
+ * Failure: Zero
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 21, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5Dget_storage_size(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset to query */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE1("h", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a dataset")
+
+ /* Set return value */
+ if(H5D__get_storage_size(dset, H5AC_ind_read_dxpl_id, &ret_value) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't get size of dataset's storage")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_storage_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_offset
+ *
+ * Purpose: Returns the address of dataset in file.
+ *
+ * Return: Success: the address of dataset
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Raymond Lu
+ * November 6, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5Dget_offset(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset to query */
+ haddr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(HADDR_UNDEF)
+ H5TRACE1("a", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, HADDR_UNDEF, "not a dataset")
+
+ /* Set return value */
+ ret_value = H5D__get_offset(dset);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dget_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Diterate
+ *
+ * Purpose: This routine iterates over all the elements selected in a memory
+ * buffer. The callback function is called once for each element selected
+ * in the dataspace. The selection in the dataspace is modified so
+ * that any elements already iterated over are removed from the selection
+ * if the iteration is interrupted (by the H5D_operator_t function
+ * returning non-zero) in the "middle" of the iteration and may be
+ * re-started by the user where it left off.
+ *
+ * NOTE: Until "subtracting" elements from a selection is implemented,
+ * the selection is not modified.
+ *
+ * Parameters:
+ * void *buf; IN/OUT: Pointer to the buffer in memory containing
+ * the elements to iterate over.
+ * hid_t type_id; IN: Datatype ID for the elements stored in BUF.
+ * hid_t space_id; IN: Dataspace ID for BUF, also contains the
+ * selection to iterate over.
+ * H5D_operator_t op; IN: Function pointer to the routine to be
+ * called for each element in BUF iterated over.
+ * void *operator_data; IN/OUT: Pointer to any user-defined data
+ * associated with the operation.
+ *
+ * Operation information:
+ * H5D_operator_t is defined as:
+ * typedef herr_t (*H5D_operator_t)(void *elem, hid_t type_id,
+ * unsigned ndim, const hsize_t *point, void *operator_data);
+ *
+ * H5D_operator_t parameters:
+ * void *elem; IN/OUT: Pointer to the element in memory containing
+ * the current point.
+ * hid_t type_id; IN: Datatype ID for the elements stored in ELEM.
+ * unsigned ndim; IN: Number of dimensions for POINT array
+ * const hsize_t *point; IN: Array containing the location of the element
+ * within the original dataspace.
+ * void *operator_data; IN/OUT: Pointer to any user-defined data
+ * associated with the operation.
+ *
+ * The return values from an operator are:
+ * Zero causes the iterator to continue, returning zero when all
+ * elements have been processed.
+ * Positive causes the iterator to immediately return that positive
+ * value, indicating short-circuit success. The iterator can be
+ * restarted at the next element.
+ * Negative causes the iterator to immediately return that value,
+ * indicating failure. The iterator can be restarted at the next
+ * element.
+ *
+ * Return: Returns the return value of the last operator if it was non-zero,
+ * or zero if all elements were processed. Otherwise returns a
+ * negative value.
+ *
+ * Programmer: Quincey Koziol
+ * Friday, June 11, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Diterate(void *buf, hid_t type_id, hid_t space_id, H5D_operator_t op,
+ void *operator_data)
+{
+ H5T_t *type; /* Datatype */
+ H5S_t *space; /* Dataspace for iteration */
+ H5S_sel_iter_op_t dset_op; /* Operator for iteration */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*xiix*x", buf, type_id, space_id, op, operator_data);
+
+ /* Check args */
+ if(NULL == op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid operator")
+ if(NULL == buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid buffer")
+ if(H5I_DATATYPE != H5I_get_type(type_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid datatype")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataspace")
+ if(!(H5S_has_extent(space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspace does not have extent set")
+
+ dset_op.op_type = H5S_SEL_ITER_OP_APP;
+ dset_op.u.app_op.op = op;
+ dset_op.u.app_op.type_id = type_id;
+
+ ret_value = H5S_select_iterate(buf, type, space, &dset_op, operator_data);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Diterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dvlen_reclaim
+ *
+ * Purpose: Frees the buffers allocated for storing variable-length data
+ * in memory. Only frees the VL data in the selection defined in the
+ * dataspace. The dataset transfer property list is required to find the
+ * correct allocation/free methods for the VL data in the buffer.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 10, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dvlen_reclaim(hid_t type_id, hid_t space_id, hid_t plist_id, void *buf)
+{
+ H5S_t *space; /* Dataspace for iteration */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iii*x", type_id, space_id, plist_id, buf);
+
+ /* Check args */
+ if(H5I_DATATYPE != H5I_get_type(type_id) || buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataspace")
+ if(!(H5S_has_extent(space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspace does not have extent set")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if(H5P_DEFAULT == plist_id)
+ plist_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms")
+
+ /* Call internal routine */
+ ret_value = H5D_vlen_reclaim(type_id, space, plist_id, buf);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dvlen_reclaim() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dvlen_get_buf_size
+ *
+ * Purpose: This routine checks the number of bytes required to store the VL
+ * data from the dataset, using the space_id for the selection in the
+ * dataset on disk and the type_id for the memory representation of the
+ * VL data, in memory. The *size value is modified according to how many
+ * bytes are required to store the VL data in memory.
+ *
+ * Implementation: This routine actually performs the read with a custom
+ * memory manager which basically just counts the bytes requested and
+ * uses a temporary memory buffer (through the H5FL API) to make certain
+ * enough space is available to perform the read. Then the temporary
+ * buffer is released and the number of bytes allocated is returned.
+ * Kinda kludgy, but easier than the other method of trying to figure out
+ * the sizes without actually reading the data in... - QAK
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 11, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_id,
+ hsize_t *size)
+{
+ H5D_vlen_bufsize_t vlen_bufsize = {0, 0, 0, 0, 0, 0, 0};
+ H5D_t *dset; /* Dataset for operation */
+ H5S_t *fspace = NULL; /* Dataset's dataspace */
+ H5S_t *mspace = NULL; /* Memory dataspace */
+ char bogus; /* bogus value to pass to H5Diterate() */
+ H5S_t *space; /* Dataspace for iteration */
+ H5P_genplist_t *plist; /* Property list */
+ H5T_t *type; /* Datatype */
+ H5S_sel_iter_op_t dset_op; /* Operator for iteration */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iii*h", dataset_id, type_id, space_id, size);
+
+ /* Check args */
+ if(H5I_DATASET != H5I_get_type(dataset_id) ||
+ H5I_DATATYPE != H5I_get_type(type_id) || size == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument")
+ if(NULL == (dset = (H5D_t *)H5I_object(dataset_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataspace")
+ if(!(H5S_has_extent(space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspace does not have extent set")
+
+ /* Save the dataset */
+ vlen_bufsize.dset = dset;
+
+ /* Get a copy of the dataset's dataspace */
+ if(NULL == (fspace = H5S_copy(dset->shared->space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to get dataspace")
+ vlen_bufsize.fspace = fspace;
+
+ /* Create a scalar for the memory dataspace */
+ if(NULL == (mspace = H5S_create(H5S_SCALAR)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace")
+ vlen_bufsize.mspace = mspace;
+
+ /* Grab the temporary buffers required */
+ if(NULL == (vlen_bufsize.fl_tbuf = H5FL_BLK_MALLOC(vlen_fl_buf, (size_t)1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "no temporary buffers available")
+ if(NULL == (vlen_bufsize.vl_tbuf = H5FL_BLK_MALLOC(vlen_vl_buf, (size_t)1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "no temporary buffers available")
+
+ /* Change to the custom memory allocation routines for reading VL data */
+ if((vlen_bufsize.xfer_pid = H5P_create_id(H5P_CLS_DATASET_XFER_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "no dataset xfer plists available")
+
+ /* Get the property list struct */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(vlen_bufsize.xfer_pid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Set the memory manager to the special allocation routine */
+ if(H5P_set_vlen_mem_manager(plist, H5D__vlen_get_buf_size_alloc, &vlen_bufsize, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set VL data allocation routine")
+
+ /* Set the initial number of bytes required */
+ vlen_bufsize.size = 0;
+
+ /* Call H5S_select_iterate with args, etc. */
+ dset_op.op_type = H5S_SEL_ITER_OP_APP;
+ dset_op.u.app_op.op = H5D__vlen_get_buf_size;
+ dset_op.u.app_op.type_id = type_id;
+
+ ret_value = H5S_select_iterate(&bogus, type, space, &dset_op, &vlen_bufsize);
+
+ /* Get the size if we succeeded */
+ if(ret_value >= 0)
+ *size = vlen_bufsize.size;
+
+done:
+ if(fspace && H5S_close(fspace) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+ if(mspace && H5S_close(mspace) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+ if(vlen_bufsize.fl_tbuf != NULL)
+ vlen_bufsize.fl_tbuf = H5FL_BLK_FREE(vlen_fl_buf, vlen_bufsize.fl_tbuf);
+ if(vlen_bufsize.vl_tbuf != NULL)
+ vlen_bufsize.vl_tbuf = H5FL_BLK_FREE(vlen_vl_buf, vlen_bufsize.vl_tbuf);
+ if(vlen_bufsize.xfer_pid > 0 && H5I_dec_ref(vlen_bufsize.xfer_pid) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement ref count on property list")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dvlen_get_buf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dset_extent
+ *
+ * Purpose: Modifies the dimensions of a dataset.
+ * Can change to a smaller dimension.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * April 9, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dset_extent(hid_t dset_id, const hsize_t size[])
+{
+ H5D_t *dset; /* Dataset for this operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", dset_id, size);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(!size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no size specified")
+
+ /* Private function */
+ if(H5D__set_extent(dset, size, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set extend dataset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dset_extent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dflush
+ *
+ * Purpose: Flushes all buffers associated with a dataset.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dflush(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset for this operation */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* Flush any dataset information still cached in memory */
+ if(H5D__flush_real(dset, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info")
+
+ /* Flush object's metadata to file */
+ if(H5O_flush_common(&dset->oloc, dset_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush dataset and object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dflush */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Drefresh
+ *
+ * Purpose: Refreshes all buffers associated with a dataset.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * July 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Drefresh(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* Call private function to refresh the dataset object */
+ if((H5D__refresh(dset_id, dset, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to refresh dataset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Drefresh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dformat_convert (Internal)
+ *
+ * Purpose: For chunked:
+ * Convert the chunk indexing type to version 1 B-tree if not
+ * For compact/contiguous:
+ * Downgrade layout version to 3 if greater than 3
+ * For virtual: no conversion
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dformat_convert(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ switch(dset->shared->layout.type) {
+ case H5D_CHUNKED:
+ /* Convert the chunk indexing type to version 1 B-tree if not */
+ if(dset->shared->layout.u.chunk.idx_type != H5D_CHUNK_IDX_BTREE)
+ if((H5D__format_convert(dset, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to downgrade chunk indexing type for dataset")
+ break;
+
+ case H5D_CONTIGUOUS:
+ case H5D_COMPACT:
+ /* Downgrade the layout version to 3 if greater than 3 */
+ if(dset->shared->layout.version > H5O_LAYOUT_VERSION_DEFAULT)
+ if((H5D__format_convert(dset, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to downgrade layout version for dataset")
+ break;
+
+ case H5D_VIRTUAL:
+ /* Nothing to do even though layout is version 4 */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset layout type")
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown dataset layout type")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dformat_convert */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dget_chunk_index_type (Internal)
+ *
+ * Purpose: Retrieve a dataset's chunk indexing type
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dget_chunk_index_type(hid_t did, H5D_chunk_index_t *idx_type)
+{
+ H5D_t *dset; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Dk", did, idx_type);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* Should be a chunked dataset */
+ if(dset->shared->layout.type != H5D_CHUNKED)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset is not chunked")
+
+ /* Get the chunk indexing type */
+ if(idx_type)
+ *idx_type = dset->shared->layout.u.chunk.idx_type;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dget_chunk_index_type() */
+
diff --git a/src/H5Dbtree.c b/src/H5Dbtree.c
new file mode 100644
index 0000000..8177e13
--- /dev/null
+++ b/src/H5Dbtree.c
@@ -0,0 +1,1527 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, October 8, 1997
+ *
+ * Purpose: v1 B-tree indexed (chunked) I/O functions. The chunks are
+ * given a multi-dimensional index which is used as a lookup key
+ * in a B-tree that maps chunk index to disk address.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Bprivate.h" /* B-link trees */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File space management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/*
+ * B-tree key. A key contains the minimum logical N-dimensional coordinates and
+ * the logical size of the chunk to which this key refers. The
+ * fastest-varying dimension is assumed to reference individual bytes of the
+ * array, so a 100-element 1-d array of 4-byte integers would really be a 2-d
+ * array with the slow varying dimension of size 100 and the fast varying
+ * dimension of size 4 (the storage dimensionality has very little to do with
+ * the real dimensionality).
+ *
+ * Only the first few values of the OFFSET and SIZE fields are actually
+ * stored on disk, depending on the dimensionality.
+ *
+ * The chunk's file address is part of the B-tree and not part of the key.
+ */
+typedef struct H5D_btree_key_t {
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /*logical offset to start*/
+ uint32_t nbytes; /*size of stored data */
+ unsigned filter_mask; /*excluded filters */
+} H5D_btree_key_t;
+
+/* B-tree callback info for iteration over chunks */
+typedef struct H5D_btree_it_ud_t {
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+ H5D_chunk_cb_func_t cb; /* Chunk callback routine */
+ void *udata; /* User data for chunk callback routine */
+} H5D_btree_it_ud_t;
+
+/* B-tree callback info for debugging */
+typedef struct H5D_btree_dbg_t {
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+ unsigned ndims; /* Number of dimensions */
+} H5D_btree_dbg_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5D__btree_shared_free(void *_shared);
+static herr_t H5D__btree_shared_create(const H5F_t *f, H5O_storage_chunk_t *store,
+ const H5O_layout_chunk_t *layout);
+
+/* B-tree iterator callbacks */
+static int H5D__btree_idx_iterate_cb(H5F_t *f, hid_t dxpl_id, const void *left_key,
+ haddr_t addr, const void *right_key, void *_udata);
+
+/* B-tree callbacks */
+static H5UC_t *H5D__btree_get_shared(const H5F_t *f, const void *_udata);
+static herr_t H5D__btree_new_node(H5F_t *f, hid_t dxpl_id, H5B_ins_t, void *_lt_key,
+ void *_udata, void *_rt_key, haddr_t *addr_p /*out*/);
+static int H5D__btree_cmp2(void *_lt_key, void *_udata, void *_rt_key);
+static int H5D__btree_cmp3(void *_lt_key, void *_udata, void *_rt_key);
+static htri_t H5D__btree_found(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *_lt_key, void *_udata);
+static H5B_ins_t H5D__btree_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ void *_lt_key, hbool_t *lt_key_changed, void *_md_key, void *_udata,
+ void *_rt_key, hbool_t *rt_key_changed, haddr_t *new_node/*out*/);
+static H5B_ins_t H5D__btree_remove( H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ void *_lt_key, hbool_t *lt_key_changed, void *_udata, void *_rt_key,
+ hbool_t *rt_key_changed);
+static herr_t H5D__btree_decode_key(const H5B_shared_t *shared, const uint8_t *raw,
+ void *_key);
+static herr_t H5D__btree_encode_key(const H5B_shared_t *shared, uint8_t *raw,
+ const void *_key);
+static herr_t H5D__btree_debug_key(FILE *stream, int indent, int fwidth,
+ const void *key, const void *udata);
+
+/* Chunked layout indexing callbacks */
+static herr_t H5D__btree_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+static herr_t H5D__btree_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__btree_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__btree_idx_insert(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+static herr_t H5D__btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static int H5D__btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__btree_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__btree_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__btree_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__btree_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id);
+static herr_t H5D__btree_idx_size(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *size);
+static herr_t H5D__btree_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__btree_idx_dump(const H5O_storage_chunk_t *storage,
+ FILE *stream);
+static herr_t H5D__btree_idx_dest(const H5D_chk_idx_info_t *idx_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* v1 B-tree indexed chunk I/O ops */
+const H5D_chunk_ops_t H5D_COPS_BTREE[1] = {{
+ FALSE, /* v1 B-tree indices does not support SWMR access */
+ H5D__btree_idx_init, /* insert */
+ H5D__btree_idx_create, /* create */
+ H5D__btree_idx_is_space_alloc, /* is_space_alloc */
+ H5D__btree_idx_insert, /* insert */
+ H5D__btree_idx_get_addr, /* get_addr */
+ NULL, /* resize */
+ H5D__btree_idx_iterate, /* iterate */
+ H5D__btree_idx_remove, /* remove */
+ H5D__btree_idx_delete, /* delete */
+ H5D__btree_idx_copy_setup, /* copy_setup */
+ H5D__btree_idx_copy_shutdown, /* copy_shutdown */
+ H5D__btree_idx_size, /* size */
+ H5D__btree_idx_reset, /* reset */
+ H5D__btree_idx_dump, /* dump */
+ H5D__btree_idx_dest /* destroy */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* inherits B-tree like properties from H5B */
+H5B_class_t H5B_BTREE[1] = {{
+ H5B_CHUNK_ID, /*id */
+ sizeof(H5D_btree_key_t), /*sizeof_nkey */
+ H5D__btree_get_shared, /*get_shared */
+ H5D__btree_new_node, /*new */
+ H5D__btree_cmp2, /*cmp2 */
+ H5D__btree_cmp3, /*cmp3 */
+ H5D__btree_found, /*found */
+ H5D__btree_insert, /*insert */
+ FALSE, /*follow min branch? */
+ FALSE, /*follow max branch? */
+ H5B_LEFT, /*critical key */
+ H5D__btree_remove, /*remove */
+ H5D__btree_decode_key, /*decode */
+ H5D__btree_encode_key, /*encode */
+ H5D__btree_debug_key /*debug */
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage H5O_layout_chunk_t objects */
+H5FL_DEFINE_STATIC(H5O_layout_chunk_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_get_shared
+ *
+ * Purpose: Returns the shared B-tree info for the specified UDATA.
+ *
+ * Return: Success: Pointer to the raw B-tree page for this dataset
+ *
+ * Failure: Can't fail
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 5, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5UC_t *
+H5D__btree_get_shared(const H5F_t H5_ATTR_UNUSED *f, const void *_udata)
+{
+ const H5D_chunk_common_ud_t *udata = (const H5D_chunk_common_ud_t *) _udata;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(udata);
+ HDassert(udata->storage);
+ HDassert(udata->storage->idx_type == H5D_CHUNK_IDX_BTREE);
+ HDassert(udata->storage->u.btree.shared);
+
+ /* Return the pointer to the ref-count object */
+ FUNC_LEAVE_NOAPI(udata->storage->u.btree.shared)
+} /* end H5D__btree_get_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_new_node
+ *
+ * Purpose: Adds a new entry to an i-storage B-tree. We can assume that
+ * the domain represented by UDATA doesn't intersect the domain
+ * already represented by the B-tree.
+ *
+ * Return: Success: Non-negative. The address of leaf is returned
+ * through the ADDR argument. It is also added
+ * to the UDATA.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 14, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_new_node(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5B_ins_t op,
+ void *_lt_key, void *_udata, void *_rt_key,
+ haddr_t *addr_p/*out*/)
+{
+ H5D_btree_key_t *lt_key = (H5D_btree_key_t *) _lt_key;
+ H5D_btree_key_t *rt_key = (H5D_btree_key_t *) _rt_key;
+ H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *) _udata;
+ unsigned u;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(lt_key);
+ HDassert(rt_key);
+ HDassert(udata);
+ HDassert(udata->common.layout->ndims > 0 && udata->common.layout->ndims < H5O_LAYOUT_NDIMS);
+ HDassert(addr_p);
+
+ /* Set address */
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+ HDassert(udata->chunk_block.length > 0);
+ *addr_p = udata->chunk_block.offset;
+
+ /*
+ * The left key describes the storage of the UDATA chunk being
+ * inserted into the tree.
+ */
+ H5_CHECKED_ASSIGN(lt_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ lt_key->filter_mask = udata->filter_mask;
+ for(u = 0; u < udata->common.layout->ndims; u++)
+ lt_key->scaled[u] = udata->common.scaled[u];
+
+ /*
+ * The right key might already be present. If not, then add a zero-width
+ * chunk.
+ */
+ if(H5B_INS_LEFT != op) {
+ rt_key->nbytes = 0;
+ rt_key->filter_mask = 0;
+ for(u = 0; u < udata->common.layout->ndims; u++) {
+ HDassert(udata->common.scaled[u] + 1 > udata->common.scaled[u]);
+ rt_key->scaled[u] = udata->common.scaled[u] + 1;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_new_node() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_cmp2
+ *
+ * Purpose: Compares two keys sort of like strcmp(). The UDATA pointer
+ * is only to supply extra information not carried in the keys
+ * (in this case, the dimensionality) and is not compared
+ * against the keys.
+ *
+ * Return: Success: -1 if LT_KEY is less than RT_KEY;
+ * 1 if LT_KEY is greater than RT_KEY;
+ * 0 if LT_KEY and RT_KEY are equal.
+ *
+ * Failure: FAIL (same as LT_KEY<RT_KEY)
+ *
+ * Programmer: Robb Matzke
+ * Thursday, November 6, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__btree_cmp2(void *_lt_key, void *_udata, void *_rt_key)
+{
+ H5D_btree_key_t *lt_key = (H5D_btree_key_t *) _lt_key;
+ H5D_btree_key_t *rt_key = (H5D_btree_key_t *) _rt_key;
+ H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *) _udata;
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(lt_key);
+ HDassert(rt_key);
+ HDassert(udata);
+ HDassert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS);
+
+ /* Compare the offsets but ignore the other fields */
+ ret_value = H5VM_vector_cmp_u(udata->layout->ndims, lt_key->scaled, rt_key->scaled);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_cmp2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_cmp3
+ *
+ * Purpose: Compare the requested datum UDATA with the left and right
+ * keys of the B-tree.
+ *
+ * Return: Success: negative if the min_corner of UDATA is less
+ * than the min_corner of LT_KEY.
+ *
+ * positive if the min_corner of UDATA is
+ * greater than or equal the min_corner of
+ * RT_KEY.
+ *
+ * zero otherwise. The min_corner of UDATA is
+ * not necessarily contained within the address
+ * space represented by LT_KEY, but a key that
+ * would describe the UDATA min_corner address
+ * would fall lexicographically between LT_KEY
+ * and RT_KEY.
+ *
+ * Failure: FAIL (same as UDATA < LT_KEY)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__btree_cmp3(void *_lt_key, void *_udata, void *_rt_key)
+{
+ H5D_btree_key_t *lt_key = (H5D_btree_key_t *) _lt_key;
+ H5D_btree_key_t *rt_key = (H5D_btree_key_t *) _rt_key;
+ H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *) _udata;
+ int ret_value = 0;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(lt_key);
+ HDassert(rt_key);
+ HDassert(udata);
+ HDassert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS);
+
+ /* Special case for faster checks on 1-D chunks */
+ /* (Checking for ndims==2 because last dimension is the datatype size) */
+ /* The additional checking for the right key is necessary due to the */
+ /* slightly odd way the library initializes the right-most node in the */
+ /* indexed storage B-tree... */
+ /* (Dump the B-tree with h5debug to look at it) -QAK */
+ if(udata->layout->ndims == 2) {
+ if(udata->scaled[0] > rt_key->scaled[0])
+ ret_value = 1;
+ else if(udata->scaled[0] == rt_key->scaled[0] &&
+ udata->scaled[1] >= rt_key->scaled[1])
+ ret_value = 1;
+ else if(udata->scaled[0] < lt_key->scaled[0])
+ ret_value = (-1);
+ } /* end if */
+ else {
+ if(H5VM_vector_ge_u(udata->layout->ndims, udata->scaled, rt_key->scaled))
+ ret_value = 1;
+ else if(H5VM_vector_lt_u(udata->layout->ndims, udata->scaled, lt_key->scaled))
+ ret_value = (-1);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_cmp3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_found
+ *
+ * Purpose: This function is called when the B-tree search engine has
+ * found the leaf entry that points to a chunk of storage that
+ * contains the beginning of the logical address space
+ * represented by UDATA. The LT_KEY is the left key (the one
+ * that describes the chunk) and RT_KEY is the right key (the
+ * one that describes the next or last chunk).
+ *
+ * Note: It's possible that the chunk isn't really found. For
+ * instance, in a sparse dataset the requested chunk might fall
+ * between two stored chunks in which case this function is
+ * called with the maximum stored chunk indices less than the
+ * requested chunk indices.
+ *
+ * Return: Non-negative (TRUE/FALSE) on success with information about the
+ * chunk returned through the UDATA argument. Negative on failure.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 9, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5D__btree_found(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, const void *_lt_key,
+ void *_udata)
+{
+ H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *) _udata;
+ const H5D_btree_key_t *lt_key = (const H5D_btree_key_t *) _lt_key;
+ unsigned u;
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+ HDassert(lt_key);
+
+ /* Is this *really* the requested chunk? */
+ for(u = 0; u < udata->common.layout->ndims; u++)
+ if(udata->common.scaled[u] >= (lt_key->scaled[u] + 1))
+ HGOTO_DONE(FALSE)
+
+ /* Initialize return values */
+ HDassert(lt_key->nbytes > 0);
+ udata->chunk_block.offset = addr;
+ udata->chunk_block.length = lt_key->nbytes;
+ udata->filter_mask = lt_key->filter_mask;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_disjoint
+ *
+ * Purpose: Determines if two chunks are disjoint.
+ *
+ * Return: Success: FALSE if they are not disjoint.
+ * TRUE if they are disjoint.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 6, 2015
+ *
+ * Note: Assumes that the chunk offsets are scaled coordinates
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__chunk_disjoint(unsigned n, const hsize_t *scaled1, const hsize_t *scaled2)
+{
+ unsigned u; /* Local index variable */
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(n);
+ HDassert(scaled1);
+ HDassert(scaled2);
+
+ /* Loop over two chunks, detecting disjointness and getting out quickly */
+ for(u = 0; u < n; u++)
+ if((scaled1[u] + 1) <= scaled2[u] || (scaled2[u] + 1) <= scaled1[u])
+ HGOTO_DONE(TRUE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_disjoint() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_insert
+ *
+ * Purpose: This function is called when the B-tree insert engine finds
+ * the node to use to insert new data. The UDATA argument
+ * points to a struct that describes the logical addresses being
+ * added to the file. This function allocates space for the
+ * data and returns information through UDATA describing a
+ * file chunk to receive (part of) the data.
+ *
+ * The LT_KEY is always the key describing the chunk of file
+ * memory at address ADDR. On entry, UDATA describes the logical
+ * addresses for which storage is being requested (through the
+ * `offset' and `size' fields). On return, UDATA describes the
+ * logical addresses contained in a chunk on disk.
+ *
+ * Return: Success: An insertion command for the caller, one of
+ * the H5B_INS_* constants. The address of the
+ * new chunk is returned through the NEW_NODE
+ * argument.
+ *
+ * Failure: H5B_INS_ERROR
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 9, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5D__btree_insert(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, void *_lt_key,
+ hbool_t *lt_key_changed,
+ void *_md_key, void *_udata, void *_rt_key,
+ hbool_t H5_ATTR_UNUSED *rt_key_changed,
+ haddr_t *new_node_p/*out*/)
+{
+ H5D_btree_key_t *lt_key = (H5D_btree_key_t *) _lt_key;
+ H5D_btree_key_t *md_key = (H5D_btree_key_t *) _md_key;
+ H5D_btree_key_t *rt_key = (H5D_btree_key_t *) _rt_key;
+ H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *) _udata;
+ int cmp;
+ unsigned u;
+ H5B_ins_t ret_value = H5B_INS_ERROR; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(lt_key);
+ HDassert(lt_key_changed);
+ HDassert(md_key);
+ HDassert(udata);
+ HDassert(rt_key);
+ HDassert(new_node_p);
+
+ cmp = H5D__btree_cmp3(lt_key, udata, rt_key);
+ HDassert(cmp <= 0);
+
+ if(cmp < 0) {
+ /* Negative indices not supported yet */
+ HGOTO_ERROR(H5E_STORAGE, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error")
+
+ } else if(H5VM_vector_eq_u(udata->common.layout->ndims,
+ udata->common.scaled, lt_key->scaled) && lt_key->nbytes > 0) {
+ /*
+ * Already exists. If the new size is not the same as the old size
+ * then we should reallocate storage.
+ */
+ if(lt_key->nbytes != udata->chunk_block.length) {
+ /* Set node's address (already re-allocated by main chunk routines) */
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+ *new_node_p = udata->chunk_block.offset;
+ H5_CHECKED_ASSIGN(lt_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ lt_key->filter_mask = udata->filter_mask;
+ *lt_key_changed = TRUE;
+ ret_value = H5B_INS_CHANGE;
+ } else {
+ /* Already have address in udata, from main chunk routines */
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+ ret_value = H5B_INS_NOOP;
+ }
+
+ } else if (H5D__chunk_disjoint(udata->common.layout->ndims,
+ lt_key->scaled, udata->common.scaled)) {
+ HDassert(H5D__chunk_disjoint(udata->common.layout->ndims,
+ rt_key->scaled, udata->common.scaled));
+ /*
+ * Split this node, inserting the new new node to the right of the
+ * current node. The MD_KEY is where the split occurs.
+ */
+ H5_CHECKED_ASSIGN(md_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ md_key->filter_mask = udata->filter_mask;
+ for(u = 0; u < udata->common.layout->ndims; u++)
+ md_key->scaled[u] = udata->common.scaled[u];
+
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+ *new_node_p = udata->chunk_block.offset;
+ ret_value = H5B_INS_RIGHT;
+
+ } else {
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_remove
+ *
+ * Purpose: Removes chunks that are no longer necessary in the B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Pedro Vicente, pvn@ncsa.uiuc.edu
+ * March 28, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5D__btree_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key /*in,out */ ,
+ hbool_t *lt_key_changed /*out */ ,
+ void H5_ATTR_UNUSED * _udata /*in,out */ ,
+ void H5_ATTR_UNUSED * _rt_key /*in,out */ ,
+ hbool_t *rt_key_changed /*out */ )
+{
+ H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key;
+ H5B_ins_t ret_value=H5B_INS_REMOVE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Remove raw data chunk from file */
+ H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk")
+
+ /* Mark keys as unchanged */
+ *lt_key_changed = FALSE;
+ *rt_key_changed = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_decode_key
+ *
+ * Purpose: Decodes a raw key into a native key for the B-tree
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key)
+{
+ const H5O_layout_chunk_t *layout; /* Chunk layout description */
+ H5D_btree_key_t *key = (H5D_btree_key_t *) _key; /* Pointer to decoded key */
+ hsize_t tmp_offset; /* Temporary coordinate offset, from file */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(shared);
+ HDassert(raw);
+ HDassert(key);
+ layout = (const H5O_layout_chunk_t *)shared->udata;
+ HDassert(layout);
+ HDassert(layout->ndims > 0 && layout->ndims <= H5O_LAYOUT_NDIMS);
+
+ /* decode */
+ UINT32DECODE(raw, key->nbytes);
+ UINT32DECODE(raw, key->filter_mask);
+ for(u = 0; u < layout->ndims; u++) {
+ /* Retrieve coordinate offset */
+ UINT64DECODE(raw, tmp_offset);
+ HDassert(0 == (tmp_offset % layout->dim[u]));
+
+ /* Convert to a scaled offset */
+ key->scaled[u] = tmp_offset / layout->dim[u];
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__btree_decode_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_encode_key
+ *
+ * Purpose: Encode a key from native format to raw format.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key)
+{
+ const H5O_layout_chunk_t *layout; /* Chunk layout description */
+ const H5D_btree_key_t *key = (const H5D_btree_key_t *)_key;
+ hsize_t tmp_offset; /* Temporary coordinate offset, from file */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(shared);
+ HDassert(raw);
+ HDassert(key);
+ layout = (const H5O_layout_chunk_t *)shared->udata;
+ HDassert(layout);
+ HDassert(layout->ndims > 0 && layout->ndims <= H5O_LAYOUT_NDIMS);
+
+ /* encode */
+ UINT32ENCODE(raw, key->nbytes);
+ UINT32ENCODE(raw, key->filter_mask);
+ for(u = 0; u < layout->ndims; u++) {
+ /* Compute coordinate offset from scaled offset */
+ tmp_offset = key->scaled[u] * layout->dim[u];
+ UINT64ENCODE(raw, tmp_offset);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__btree_encode_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_debug_key
+ *
+ * Purpose: Prints a key.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_debug_key(FILE *stream, int indent, int fwidth, const void *_key,
+ const void *_udata)
+{
+ const H5D_btree_key_t *key = (const H5D_btree_key_t *)_key;
+ const H5D_btree_dbg_t *udata = (const H5D_btree_dbg_t *)_udata;
+ unsigned u;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(key);
+
+ HDfprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth, "Chunk size:", (unsigned)key->nbytes);
+ HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", key->filter_mask);
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:");
+ for(u = 0; u < udata->ndims; u++)
+ HDfprintf(stream, "%s%Hd", u?", ":"", (key->scaled[u] * udata->common.layout->dim[u]));
+ HDfputs("}\n", stream);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__btree_debug_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_shared_free
+ *
+ * Purpose: Free "local" B-tree shared info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_shared_free(void *_shared)
+{
+ H5B_shared_t *shared = (H5B_shared_t *)_shared;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Free the chunk layout information */
+ shared->udata = H5FL_FREE(H5O_layout_chunk_t, shared->udata);
+
+ /* Chain up to the generic B-tree shared info free routine */
+ if(H5B_shared_free(shared) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free shared B-tree info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_shared_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_shared_create
+ *
+ * Purpose: Create & initialize B-tree shared info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 27, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_shared_create(const H5F_t *f, H5O_storage_chunk_t *store,
+ const H5O_layout_chunk_t *layout)
+{
+ H5B_shared_t *shared; /* Shared B-tree node info */
+ H5O_layout_chunk_t *my_layout = NULL; /* Pointer to copy of layout info */
+ size_t sizeof_rkey; /* Size of raw (disk) key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Set the raw key size */
+ sizeof_rkey = 4 + /*storage size */
+ 4 + /*filter mask */
+ layout->ndims * 8; /*dimension indices */
+
+ /* Allocate & initialize global info for the shared structure */
+ if(NULL == (shared = H5B_shared_new(f, H5B_BTREE, sizeof_rkey)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "memory allocation failed for shared B-tree info")
+
+ /* Set up the "local" information for this dataset's chunks */
+ if(NULL == (my_layout = H5FL_MALLOC(H5O_layout_chunk_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk layout")
+ HDmemcpy(my_layout, layout, sizeof(H5O_layout_chunk_t));
+ shared->udata = my_layout;
+
+ /* Make shared B-tree info reference counted */
+ if(NULL == (store->u.btree.shared = H5UC_create(shared, H5D__btree_shared_free)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't create ref-count wrapper for shared B-tree info")
+
+done:
+ if(ret_value < 0)
+ if(my_layout)
+ my_layout = H5FL_FREE(H5O_layout_chunk_t, my_layout);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_shared_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_init
+ *
+ * Purpose: Initialize the indexing information for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, May 18, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space,
+ haddr_t dset_ohdr_addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(dset_ohdr_addr));
+
+ idx_info->storage->u.btree.dset_ohdr_addr = dset_ohdr_addr;
+
+ /* Allocate the shared structure */
+ if(H5D__btree_shared_create(idx_info->f, idx_info->storage, idx_info->layout) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_create
+ *
+ * Purpose: Creates a new indexed-storage B-tree and initializes the
+ * layout struct with information about the storage. The
+ * struct should be immediately written to the object header.
+ *
+ * This function must be called before passing LAYOUT to any of
+ * the other indexed storage functions!
+ *
+ * Return: Non-negative on success (with the LAYOUT argument initialized
+ * and ready to write to an object header). Negative on failure.
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 21, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ H5D_chunk_common_ud_t udata; /* User data for B-tree callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+
+ /* Initialize "user" data for B-tree callbacks, etc. */
+ udata.layout = idx_info->layout;
+ udata.storage = idx_info->storage;
+
+ /* Create the v1 B-tree for the chunk index */
+ if(H5B_create(idx_info->f, idx_info->dxpl_id, H5B_BTREE, &udata, &(idx_info->storage->idx_addr)/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create B-tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for index method
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__btree_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__btree_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_insert
+ *
+ * Purpose: Insert chunk entry into the indexing structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
+ const H5D_t H5_ATTR_UNUSED *dset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /*
+ * Create the chunk it if it doesn't exist, or reallocate the chunk if
+ * its size changed.
+ */
+ if(H5B_insert(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to allocate chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__btree_idx_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk if file space has been
+ * assigned. Save the retrieved information in the udata
+ * supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Albert Cheng
+ * June 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->layout->ndims > 0);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Go get the chunk information from the B-tree */
+ if(H5B_find(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__btree_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_iterate_cb
+ *
+ * Purpose: Translate the B-tree specific chunk record into a generic
+ * form and make the callback to the generic chunk callback
+ * routine.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__btree_idx_iterate_cb(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ const void *_lt_key, haddr_t addr, const void H5_ATTR_UNUSED *_rt_key,
+ void *_udata)
+{
+ H5D_btree_it_ud_t *udata = (H5D_btree_it_ud_t *)_udata; /* User data */
+ const H5D_btree_key_t *lt_key = (const H5D_btree_key_t *)_lt_key; /* B-tree key for chunk */
+ H5D_chunk_rec_t chunk_rec; /* Generic chunk record for callback */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check for memcpy() */
+ HDcompile_assert(offsetof(H5D_chunk_rec_t, nbytes) == offsetof(H5D_btree_key_t, nbytes));
+ HDcompile_assert(sizeof(chunk_rec.nbytes) == sizeof(lt_key->nbytes));
+ HDcompile_assert(offsetof(H5D_chunk_rec_t, scaled) == offsetof(H5D_btree_key_t, scaled));
+ HDcompile_assert(sizeof(chunk_rec.scaled) == sizeof(lt_key->scaled));
+ HDcompile_assert(offsetof(H5D_chunk_rec_t, filter_mask) == offsetof(H5D_btree_key_t, filter_mask));
+ HDcompile_assert(sizeof(chunk_rec.filter_mask) == sizeof(lt_key->filter_mask));
+
+ /* Compose generic chunk record for callback */
+ HDmemcpy(&chunk_rec, lt_key, sizeof(*lt_key));
+ chunk_rec.chunk_addr = addr;
+
+ /* Make "generic chunk" callback */
+ if((ret_value = (udata->cb)(&chunk_rec, udata->udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__btree_idx_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_iterate
+ *
+ * Purpose: Iterate over the chunks in an index, making a callback
+ * for each one.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__btree_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5D_btree_it_ud_t udata; /* User data for B-tree iterator callback */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+
+ /* Initialize userdata */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.common.layout = idx_info->layout;
+ udata.common.storage = idx_info->storage;
+ udata.cb = chunk_cb;
+ udata.udata = chunk_udata;
+
+ /* Iterate over existing chunks */
+ if((ret_value = H5B_iterate(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, H5D__btree_idx_iterate_cb, &udata)) < 0)
+ HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk B-tree");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_remove
+ *
+ * Purpose: Remove chunk from index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Remove the chunk from the v1 B-tree index and release the space for the
+ * chunk (in the B-tree callback).
+ */
+ if(H5B_remove(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to remove chunk entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__btree_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_delete
+ *
+ * Purpose: Delete index and raw data storage for entire dataset
+ * (i.e. all chunks)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ /* Check if the index data structure has been allocated */
+ if(H5F_addr_defined(idx_info->storage->idx_addr)) {
+ H5O_storage_chunk_t tmp_storage; /* Local copy of storage info */
+ H5D_chunk_common_ud_t udata; /* User data for B-tree operations */
+
+ /* Set up temporary chunked storage info */
+ tmp_storage = *idx_info->storage;
+
+ /* Set up the shared structure */
+ if(H5D__btree_shared_create(idx_info->f, &tmp_storage, idx_info->layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info")
+
+ /* Set up B-tree user data */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.layout = idx_info->layout;
+ udata.storage = &tmp_storage;
+
+ /* Delete entire B-tree */
+ if(H5B_delete(idx_info->f, idx_info->dxpl_id, H5B_BTREE, tmp_storage.idx_addr, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk B-tree")
+
+ /* Release the shared B-tree page */
+ if(NULL == tmp_storage.u.btree.shared)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "ref-counted page nil")
+ if(H5UC_DEC(tmp_storage.u.btree.shared) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to decrement ref-counted page")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 29, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL)
+
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+ HDassert(!H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Create shared B-tree info for each file */
+ if(H5D__btree_shared_create(idx_info_src->f, idx_info_src->storage, idx_info_src->layout) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for source shared B-tree info")
+ if(H5D__btree_shared_create(idx_info_dst->f, idx_info_dst->storage, idx_info_dst->layout) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for destination shared B-tree info")
+
+ /* Create the root of the B-tree that describes chunked storage in the dest. file */
+ if(H5D__btree_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+ HDassert(H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__btree_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_copy_shutdown
+ *
+ * Purpose: Shutdown any information from copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 29, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(storage_src);
+ HDassert(storage_dst);
+
+ /* Decrement refcount on shared B-tree info */
+ if(H5UC_DEC(storage_src->u.btree.shared) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement ref-counted page")
+ if(H5UC_DEC(storage_dst->u.btree.shared) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement ref-counted page")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_copy_shutdown() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * June 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
+{
+ H5D_chunk_common_ud_t udata; /* User-data for loading B-tree nodes */
+ H5B_info_t bt_info; /* B-tree info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(index_size);
+
+ /* Initialize B-tree node user-data */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.layout = idx_info->layout;
+ udata.storage = idx_info->storage;
+
+ /* Get metadata information for B-tree */
+ if(H5B_get_info(idx_info->f, idx_info->dxpl_id, H5B_BTREE, idx_info->storage->idx_addr, &bt_info, NULL, &udata) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to iterate over chunk B-tree")
+
+ /* Set the size of the B-tree */
+ *index_size = bt_info.size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr)
+ storage->idx_addr = HADDR_UNDEF;
+ storage->u.btree.shared = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__btree_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_dump
+ *
+ * Purpose: Dump indexing information to a stream.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__btree_idx_dump() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree_idx_dest
+ *
+ * Purpose: Release indexing information in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree_idx_dest(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ /* Free the raw B-tree node buffer */
+ if(NULL == idx_info->storage->u.btree.shared)
+ HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted page nil")
+ if(H5UC_DEC(idx_info->storage->u.btree.shared) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "unable to decrement ref-counted page")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree_idx_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_btree_debug
+ *
+ * Purpose: Debugs a B-tree node for indexed raw data storage.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_btree_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent,
+ int fwidth, unsigned ndims, const uint32_t *dim)
+{
+ H5D_btree_dbg_t udata; /* User data for B-tree callback */
+ H5O_storage_chunk_t storage; /* Storage information for B-tree callback */
+ H5O_layout_chunk_t layout; /* Layout information for B-tree callback */
+ hbool_t shared_init = FALSE; /* Whether B-tree shared info is initialized */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Reset "fake" storage info */
+ HDmemset(&storage, 0, sizeof(storage));
+ storage.idx_type = H5D_CHUNK_IDX_BTREE;
+
+ /* Reset "fake" layout info */
+ HDmemset(&layout, 0, sizeof(layout));
+ layout.ndims = ndims;
+ for(u = 0; u < ndims; u++)
+ layout.dim[u] = dim[u];
+
+ /* Allocate the shared structure */
+ if(H5D__btree_shared_create(f, &storage, &layout) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info")
+ shared_init = TRUE;
+
+ /* Set up user data for callback */
+ udata.common.layout = &layout;
+ udata.common.storage = &storage;
+ udata.common.scaled = NULL;
+ udata.ndims = ndims;
+
+ /* Dump the records for the B-tree */
+ (void)H5B_debug(f, dxpl_id, addr, stream, indent, fwidth, H5B_BTREE, &udata);
+
+done:
+ if(shared_init) {
+ /* Free the raw B-tree node buffer */
+ if(NULL == storage.u.btree.shared)
+ HDONE_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted shared info nil")
+ else
+ if(H5UC_DEC(storage.u.btree.shared) < 0)
+ HDONE_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "unable to decrement ref-counted shared info")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_btree_debug() */
+
diff --git a/src/H5Dbtree2.c b/src/H5Dbtree2.c
new file mode 100644
index 0000000..2e19392
--- /dev/null
+++ b/src/H5Dbtree2.c
@@ -0,0 +1,1575 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ *
+ * Purpose: v2 B-tree indexing for chunked datasets with > 1 unlimited dimensions.
+ * Each dataset chunk in the b-tree is identified by its dimensional offset.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+/* User data for creating callback context */
+typedef struct H5D_bt2_ctx_ud_t {
+ const H5F_t *f; /* Pointer to file info */
+ uint32_t chunk_size; /* Size of chunk (bytes; for filtered object) */
+ unsigned ndims; /* Number of dimensions */
+ uint32_t *dim; /* Size of chunk in elements */
+} H5D_bt2_ctx_ud_t;
+
+/* The callback context */
+typedef struct H5D_bt2_ctx_t {
+ uint32_t chunk_size; /* Size of chunk (bytes; constant for unfiltered object) */
+ size_t sizeof_addr; /* Size of file addresses in the file (bytes) */
+ size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */
+ unsigned ndims; /* Number of dimensions in chunk */
+ uint32_t *dim; /* Size of chunk in elements */
+} H5D_bt2_ctx_t;
+
+/* User data for the chunk's removal callback routine */
+typedef struct H5D_bt2_remove_ud_t {
+ H5F_t *f; /* File pointer for operation */
+ hid_t dxpl_id; /* DXPL ID for operation */
+} H5D_bt2_remove_ud_t;
+
+/* Callback info for iteration over chunks in v2 B-tree */
+typedef struct H5D_bt2_it_ud_t {
+ H5D_chunk_cb_func_t cb; /* Callback routine for the chunk */
+ void *udata; /* User data for the chunk's callback routine */
+} H5D_bt2_it_ud_t;
+
+/* User data for compare callback */
+typedef struct H5D_bt2_ud_t {
+ H5D_chunk_rec_t rec; /* The record to search for */
+ unsigned ndims; /* Number of dimensions for the chunked dataset */
+} H5D_bt2_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Shared v2 B-tree methods for indexing filtered and non-filtered chunked datasets */
+static void *H5D__bt2_crt_context(void *udata);
+static herr_t H5D__bt2_dst_context(void *ctx);
+static herr_t H5D__bt2_store(void *native, const void *udata);
+static herr_t H5D__bt2_compare(const void *rec1, const void *rec2, int *result);
+
+/* v2 B-tree class for indexing non-filtered chunked datasets */
+static herr_t H5D__bt2_unfilt_encode(uint8_t *raw, const void *native, void *ctx);
+static herr_t H5D__bt2_unfilt_decode(const uint8_t *raw, void *native, void *ctx);
+static herr_t H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *u_ctx);
+
+/* v2 B-tree class for indexing filtered chunked datasets */
+static herr_t H5D__bt2_filt_encode(uint8_t *raw, const void *native, void *ctx);
+static herr_t H5D__bt2_filt_decode(const uint8_t *raw, void *native, void *ctx);
+static herr_t H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *u_ctx);
+
+/* Helper routine */
+static herr_t H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info);
+
+/* Callback for H5B2_iterate() which is called in H5D__bt2_idx_iterate() */
+static int H5D__bt2_idx_iterate_cb(const void *_record, void *_udata);
+
+/* Callback for H5B2_find() which is called in H5D__bt2_idx_get_addr() */
+static herr_t H5D__bt2_found_cb(const void *nrecord, void *op_data);
+
+/*
+ * Callback for H5B2_remove() and H5B2_delete() which is called
+ * in H5D__bt2_idx_remove() and H5D__bt2_idx_delete().
+ */
+static herr_t H5D__bt2_remove_cb(const void *nrecord, void *_udata);
+
+/* Callback for H5B2_modify() which is called in H5D__bt2_idx_insert() */
+static herr_t H5D__bt2_mod_cb(void *_record, void *_op_data, hbool_t *changed);
+
+/* Chunked layout indexing callbacks for v2 B-tree indexing */
+static herr_t H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+static herr_t H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+static herr_t H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static int H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id);
+static herr_t H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size);
+static herr_t H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage,
+ FILE *stream);
+static herr_t H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Chunked dataset I/O ops for v2 B-tree indexing */
+const H5D_chunk_ops_t H5D_COPS_BT2[1] = {{
+ TRUE, /* Fixed array indices support SWMR access */
+ H5D__bt2_idx_init, /* init */
+ H5D__bt2_idx_create, /* create */
+ H5D__bt2_idx_is_space_alloc, /* is_space_alloc */
+ H5D__bt2_idx_insert, /* insert */
+ H5D__bt2_idx_get_addr, /* get_addr */
+ NULL, /* resize */
+ H5D__bt2_idx_iterate, /* iterate */
+ H5D__bt2_idx_remove, /* remove */
+ H5D__bt2_idx_delete, /* delete */
+ H5D__bt2_idx_copy_setup, /* copy_setup */
+ H5D__bt2_idx_copy_shutdown, /* copy_shutdown */
+ H5D__bt2_idx_size, /* size */
+ H5D__bt2_idx_reset, /* reset */
+ H5D__bt2_idx_dump, /* dump */
+ H5D__bt2_idx_dest /* destroy */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* v2 B-tree class for indexing non-filtered chunked datasets */
+const H5B2_class_t H5D_BT2[1] = {{ /* B-tree class information */
+ H5B2_CDSET_ID, /* Type of B-tree */
+ "H5B2_CDSET_ID", /* Name of B-tree class */
+ sizeof(H5D_chunk_rec_t), /* Size of native record */
+ H5D__bt2_crt_context, /* Create client callback context */
+ H5D__bt2_dst_context, /* Destroy client callback context */
+ H5D__bt2_store, /* Record storage callback */
+ H5D__bt2_compare, /* Record comparison callback */
+ H5D__bt2_unfilt_encode, /* Record encoding callback */
+ H5D__bt2_unfilt_decode, /* Record decoding callback */
+ H5D__bt2_unfilt_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for indexing filtered chunked datasets */
+const H5B2_class_t H5D_BT2_FILT[1] = {{ /* B-tree class information */
+ H5B2_CDSET_FILT_ID, /* Type of B-tree */
+ "H5B2_CDSET_FILT_ID", /* Name of B-tree class */
+ sizeof(H5D_chunk_rec_t), /* Size of native record */
+ H5D__bt2_crt_context, /* Create client callback context */
+ H5D__bt2_dst_context, /* Destroy client callback context */
+ H5D__bt2_store, /* Record storage callback */
+ H5D__bt2_compare, /* Record comparison callback */
+ H5D__bt2_filt_encode, /* Record encoding callback */
+ H5D__bt2_filt_decode, /* Record decoding callback */
+ H5D__bt2_filt_debug /* Record debugging callback */
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5D_bt2_ctx_t struct */
+H5FL_DEFINE_STATIC(H5D_bt2_ctx_t);
+/* Declare a free list to manage the page elements */
+H5FL_BLK_DEFINE(chunk_dim);
+
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_crt_context
+ *
+ * Purpose: Create client callback context
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__bt2_crt_context(void *_udata)
+{
+ H5D_bt2_ctx_ud_t *udata = (H5D_bt2_ctx_ud_t *)_udata; /* User data for building callback context */
+ H5D_bt2_ctx_t *ctx; /* Callback context structure */
+ uint32_t *my_dim = NULL; /* Pointer to copy of chunk dimension size */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->ndims > 0 && udata->ndims < H5O_LAYOUT_NDIMS);
+
+ /* Allocate callback context */
+ if(NULL == (ctx = H5FL_MALLOC(H5D_bt2_ctx_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate callback context")
+
+ /* Determine the size of addresses and set the chunk size and # of dimensions for the dataset */
+ ctx->sizeof_addr = H5F_SIZEOF_ADDR(udata->f);
+ ctx->chunk_size = udata->chunk_size;
+ ctx->ndims = udata->ndims;
+
+ /* Set up the "local" information for this dataset's chunk dimension sizes */
+ if(NULL == (my_dim = (uint32_t *)H5FL_BLK_MALLOC(chunk_dim, H5O_LAYOUT_NDIMS * sizeof(uint32_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate chunk dims")
+ HDmemcpy(my_dim, udata->dim, H5O_LAYOUT_NDIMS * sizeof(uint32_t));
+ ctx->dim = my_dim;
+
+ /*
+ * Compute the size required for encoding the size of a chunk,
+ * allowing for an extra byte, in case the filter makes the chunk larger.
+ */
+ ctx->chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)udata->chunk_size) + 8) / 8);
+ if(ctx->chunk_size_len > 8)
+ ctx->chunk_size_len = 8;
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_dst_context
+ *
+ * Purpose: Destroy client callback context
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_dst_context(void *_ctx)
+{
+ H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Free array for chunk dimension sizes */
+ if(ctx->dim)
+ (void)H5FL_BLK_FREE(chunk_dim, ctx->dim);
+ /* Release callback context */
+ ctx = H5FL_FREE(H5D_bt2_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_store
+ *
+ * Purpose: Store native information into record for v2 B-tree
+ * (non-filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_store(void *record, const void *_udata)
+{
+ const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5D_chunk_rec_t *)record = udata->rec;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ * (non-filtered)
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_compare(const void *_udata, const void *_rec2, int *result)
+{
+ const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */
+ const H5D_chunk_rec_t *rec1 = &(udata->rec); /* The search record */
+ const H5D_chunk_rec_t *rec2 = (const H5D_chunk_rec_t *)_rec2; /* The native record */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(rec1);
+ HDassert(rec2);
+
+ /* Compare the offsets but ignore the other fields */
+ *result = H5VM_vector_cmp_u(udata->ndims, rec1->scaled, rec2->scaled);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_unfilt_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ * (non-filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_unfilt_encode(uint8_t *raw, const void *_record, void *_ctx)
+{
+ H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
+ unsigned u; /* Local index varible */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr);
+ /* (Don't encode the chunk size & filter mask for non-filtered B-tree records) */
+ for(u = 0; u < ctx->ndims; u++)
+ UINT64ENCODE(raw, record->scaled[u]);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_unfilt_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_unfilt_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ * (non-filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_unfilt_decode(const uint8_t *raw, void *_record, void *_ctx)
+{
+ H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr);
+ record->nbytes = ctx->chunk_size;
+ record->filter_mask = 0;
+ for(u = 0; u < ctx->ndims; u++)
+ UINT64DECODE(raw, record->scaled[u]);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_unfilt_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_unfilt_debug
+ *
+ * Purpose: Debug native form of record (non-filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth,
+ const void *_record, const void *_ctx)
+{
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
+ const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(record);
+ HDassert(ctx->chunk_size == record->nbytes);
+ HDassert(0 == record->filter_mask);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, "Chunk address:", record->chunk_addr);
+
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:");
+ for(u = 0; u < ctx->ndims; u++)
+ HDfprintf(stream, "%s%Hd", u?", ":"", record->scaled[u] * ctx->dim[u]);
+ HDfputs("}\n", stream);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_unfilt_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_filt_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ * (filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_filt_encode(uint8_t *raw, const void *_record, void *_ctx)
+{
+ H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+ HDassert(record);
+ HDassert(H5F_addr_defined(record->chunk_addr));
+ HDassert(0 != record->nbytes);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr);
+ UINT64ENCODE_VAR(raw, record->nbytes, ctx->chunk_size_len);
+ UINT32ENCODE(raw, record->filter_mask);
+ for(u = 0; u < ctx->ndims; u++)
+ UINT64ENCODE(raw, record->scaled[u]);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_filt_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_filt_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ * (filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_filt_decode(const uint8_t *raw, void *_record, void *_ctx)
+{
+ H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+ HDassert(record);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr);
+ UINT64DECODE_VAR(raw, record->nbytes, ctx->chunk_size_len);
+ UINT32DECODE(raw, record->filter_mask);
+ for(u = 0; u < ctx->ndims; u++)
+ UINT64DECODE(raw, record->scaled[u]);
+
+ /* Sanity checks */
+ HDassert(H5F_addr_defined(record->chunk_addr));
+ HDassert(0 != record->nbytes);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_filt_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_filt_debug
+ *
+ * Purpose: Debug native form of record (filtered)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth,
+ const void *_record, const void *_ctx)
+{
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
+ const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(record);
+ HDassert(H5F_addr_defined(record->chunk_addr));
+ HDassert(0 != record->nbytes);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, "Chunk address:", record->chunk_addr);
+ HDfprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth, "Chunk size:", (unsigned)record->nbytes);
+ HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", record->filter_mask);
+
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:");
+ for(u = 0; u < ctx->ndims; u++)
+ HDfprintf(stream, "%s%Hd", u?", ":"", record->scaled[u] * ctx->dim[u]);
+ HDfputs("}\n", stream);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_filt_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_init
+ *
+ * Purpose: Initialize the indexing information for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, May 23, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_init(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info,
+ const H5S_t H5_ATTR_UNUSED *space, haddr_t dset_ohdr_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(H5F_addr_defined(dset_ohdr_addr));
+
+ idx_info->storage->u.btree2.dset_ohdr_addr = dset_ohdr_addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__bt2_idx_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__btree2_idx_depend
+ *
+ * Purpose: Create flush dependency between v2 B-tree and dataset's
+ * object header.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 18, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5AC_proxy_entry_t *oh_proxy; /* Dataset's object header proxy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_BT2 == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5D_CHUNK_IDX_BT2 == idx_info->storage->idx_type);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(idx_info->storage->u.btree2.bt2);
+
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr;
+
+ /* Get header */
+ if(NULL == (oh = H5O_protect(&oloc, idx_info->dxpl_id, H5AC__READ_ONLY_FLAG, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Retrieve the dataset's object header proxy */
+ if(NULL == (oh_proxy = H5O_get_proxy(oh)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy")
+
+ /* Make the v2 B-tree a child flush dependency of the dataset's object header proxy */
+ if(H5B2_depend(idx_info->storage->u.btree2.bt2, idx_info->dxpl_id, oh_proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header proxy")
+
+done:
+ /* Release the object header from the cache */
+ if(oh && H5O_unprotect(&oloc, idx_info->dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__btree2_idx_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_open()
+ *
+ * Purpose: Opens an existing v2 B-tree.
+ *
+ * Note: This information is passively initialized from each index
+ * operation callback because those abstract chunk index operations
+ * are designed to work with the v2 B-tree chunk indices also,
+ * which don't require an 'open' for the data structure.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info)
+{
+ H5D_bt2_ctx_ud_t u_ctx; /* user data for creating context */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_BT2 == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(NULL == idx_info->storage->u.btree2.bt2);
+
+ /* Set up the user data */
+ u_ctx.f = idx_info->f;
+ u_ctx.ndims = idx_info->layout->ndims - 1;
+ u_ctx.chunk_size = idx_info->layout->size;
+ u_ctx.dim = idx_info->layout->dim;
+
+ /* Open v2 B-tree for the chunk index */
+ if(NULL == (idx_info->storage->u.btree2.bt2 = H5B2_open(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &u_ctx)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open v2 B-tree for tracking chunked dataset")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__btree2_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_create
+ *
+ * Purpose: Create the v2 B-tree for tracking dataset chunks
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ H5D_bt2_ctx_ud_t u_ctx; /* data for context call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+
+ bt2_cparam.rrec_size = H5F_SIZEOF_ADDR(idx_info->f) /* Address of chunk */
+ + (idx_info->layout->ndims - 1) * 8; /* # of dimensions x 64-bit chunk offsets */
+
+ /* General parameters */
+ if(idx_info->pline->nused > 0) {
+ unsigned chunk_size_len; /* Size of encoded chunk size */
+
+ /*
+ * Compute the size required for encoding the size of a chunk,
+ * allowing for an extra byte, in case the filter makes the chunk larger.
+ */
+ chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)idx_info->layout->size) + 8) / 8);
+ if(chunk_size_len > 8)
+ chunk_size_len = 8;
+
+ bt2_cparam.rrec_size += chunk_size_len + 4; /* Size of encoded chunk size & filter mask */
+ bt2_cparam.cls = H5D_BT2_FILT;
+ } /* end if */
+ else
+ bt2_cparam.cls = H5D_BT2;
+
+ bt2_cparam.node_size = idx_info->layout->u.btree2.cparam.node_size;
+ bt2_cparam.split_percent = idx_info->layout->u.btree2.cparam.split_percent;
+ bt2_cparam.merge_percent = idx_info->layout->u.btree2.cparam.merge_percent;
+
+ u_ctx.f = idx_info->f;
+ u_ctx.ndims = idx_info->layout->ndims - 1;
+ u_ctx.chunk_size = idx_info->layout->size;
+ u_ctx.dim = idx_info->layout->dim;
+
+ /* Create the v2 B-tree for the chunked dataset */
+ if(NULL == (idx_info->storage->u.btree2.bt2 = H5B2_create(idx_info->f, idx_info->dxpl_id, &bt2_cparam, &u_ctx)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking chunked dataset")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(idx_info->storage->u.btree2.bt2, &(idx_info->storage->idx_addr)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get v2 B-tree address for tracking chunked dataset")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__btree2_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for index method
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__bt2_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_mod_cb
+ *
+ * Purpose: Modify record for dataset chunk when it is found in a v2 B-tree.
+ * This is the callback for H5B2_modify() which is called in
+ * H5D__bt2_idx_insert().
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_mod_cb(void *_record, void *_op_data, hbool_t *changed)
+{
+ H5D_bt2_ud_t *op_data = (H5D_bt2_ud_t *)_op_data; /* User data for v2 B-tree calls */
+ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* Chunk record */
+
+ FUNC_ENTER_STATIC_NOERR
+
+/* Sanity check */
+#ifndef NDEBUG
+{
+ unsigned u; /* Local index variable */
+
+ for(u = 0; u < op_data->ndims; u++)
+ HDassert(record->scaled[u] == op_data->rec.scaled[u]);
+}
+#endif /* NDEBUG */
+
+ /* Modify record */
+ *record = op_data->rec;
+
+ /* Note that the record changed */
+ *changed = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__bt2_mod_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_insert
+ *
+ * Purpose: Insert chunk address into the indexing structure.
+ * A non-filtered chunk:
+ * Should not exist
+ * Allocate the chunk and pass chunk address back up
+ * A filtered chunk:
+ * If it was not found, create the chunk and pass chunk address back up
+ * If it was found but its size changed, reallocate the chunk and pass chunk address back up
+ * If it was found but its size was the same, pass chunk address back up
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
+ const H5D_t H5_ATTR_UNUSED *dset)
+{
+ H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */
+ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+
+ /* Check if the v2 B-tree is open yet */
+ if(NULL == idx_info->storage->u.btree2.bt2) {
+ /* Open existing v2 B-tree */
+ if(H5D__bt2_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+ } /* end if */
+ else /* Patch the top level file pointer contained in bt2 if needed */
+ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer")
+
+ /* Set convenience pointer to v2 B-tree structure */
+ bt2 = idx_info->storage->u.btree2.bt2;
+
+ /* Set up callback info */
+ bt2_udata.ndims = idx_info->layout->ndims - 1;
+ bt2_udata.rec.chunk_addr = udata->chunk_block.offset;
+ if(idx_info->pline->nused > 0) { /* filtered chunk */
+ H5_CHECKED_ASSIGN(bt2_udata.rec.nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ bt2_udata.rec.filter_mask = udata->filter_mask;
+ } /* end if */
+ else { /* non-filtered chunk */
+ bt2_udata.rec.nbytes = idx_info->layout->size;
+ bt2_udata.rec.filter_mask = 0;
+ } /* end else */
+ for(u = 0; u < (idx_info->layout->ndims - 1); u++)
+ bt2_udata.rec.scaled[u] = udata->common.scaled[u];
+
+ /* Update record for v2 B-tree (could be insert or modify) */
+ if(H5B2_update(bt2, idx_info->dxpl_id, &bt2_udata, H5D__bt2_mod_cb, &bt2_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTUPDATE, FAIL, "unable to update record in v2 B-tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_idx_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_found_cb
+ *
+ * Purpose: Retrieve record for dataset chunk when it is found in a v2 B-tree.
+ * This is the callback for H5B2_find() which is called in
+ * H5D__bt2_idx_get_addr() and H5D__bt2_idx_insert().
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_found_cb(const void *nrecord, void *op_data)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5D_chunk_rec_t *)op_data = *(const H5D_chunk_rec_t *)nrecord;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__bt2_found_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk if file space has been
+ * assigned. Save the retrieved information in the udata
+ * supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */
+ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */
+ H5D_chunk_rec_t found_rec; /* Record found from searching for object */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->layout->ndims > 0);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the v2 B-tree is open yet */
+ if(NULL == idx_info->storage->u.btree2.bt2) {
+ /* Open existing v2 B-tree */
+ if(H5D__bt2_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+ } /* end if */
+ else /* Patch the top level file pointer contained in bt2 if needed */
+ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer")
+
+ /* Set convenience pointer to v2 B-tree structure */
+ bt2 = idx_info->storage->u.btree2.bt2;
+
+ /* Clear the found record */
+ found_rec.chunk_addr = HADDR_UNDEF;
+ found_rec.nbytes = 0;
+ found_rec.filter_mask = 0;
+
+ /* Prepare user data for compare callback */
+ bt2_udata.rec.chunk_addr = HADDR_UNDEF;
+ bt2_udata.ndims = idx_info->layout->ndims - 1;
+
+ /* Set the chunk offset to be searched for */
+ for(u = 0; u < (idx_info->layout->ndims - 1); u++)
+ bt2_udata.rec.scaled[u] = udata->common.scaled[u];
+
+ /* Go get chunk information from v2 B-tree */
+ if(H5B2_find(bt2, idx_info->dxpl_id, &bt2_udata, H5D__bt2_found_cb, &found_rec) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in v2 B-tree")
+
+ /* Set common info for the chunk */
+ udata->chunk_block.offset = found_rec.chunk_addr;
+
+ /* Check for setting other info */
+ if(H5F_addr_defined(udata->chunk_block.offset)) {
+ /* Sanity check */
+ HDassert(0 != found_rec.nbytes);
+
+ /* Set other info for the chunk */
+ if(idx_info->pline->nused > 0) { /* filtered chunk */
+ udata->chunk_block.length = found_rec.nbytes;
+ udata->filter_mask = found_rec.filter_mask;
+ } /* end if */
+ else { /* non-filtered chunk */
+ udata->chunk_block.length = idx_info->layout->size;
+ udata->filter_mask = 0;
+ } /* end else */
+ } /* end if */
+ else {
+ udata->chunk_block.length = 0;
+ udata->filter_mask = 0;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_iterate_cb
+ *
+ * Purpose: Translate the B-tree specific chunk record into a generic
+ * form and make the callback to the generic chunk callback
+ * routine.
+ * This is the callback for H5B2_iterate() which is called in
+ * H5D__bt2_idx_iterate().
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__bt2_idx_iterate_cb(const void *_record, void *_udata)
+{
+ H5D_bt2_it_ud_t *udata = (H5D_bt2_it_ud_t *)_udata; /* User data */
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* Native record */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Make "generic chunk" callback */
+ if((ret_value = (udata->cb)(record, udata->udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_idx_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_iterate
+ *
+ * Purpose: Iterate over the chunks in an index, making a callback
+ * for each one.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */
+ H5D_bt2_it_ud_t udata; /* User data for B-tree iterator callback */
+ int ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+
+ /* Check if the v2 B-tree is open yet */
+ if(NULL == idx_info->storage->u.btree2.bt2) {
+ /* Open existing v2 B-tree */
+ if(H5D__bt2_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+ } /* end if */
+ else /* Patch the top level file pointer contained in bt2 if needed */
+ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer")
+
+ /* Set convenience pointer to v2 B-tree structure */
+ bt2 = idx_info->storage->u.btree2.bt2;
+
+ /* Prepare user data for iterate callback */
+ udata.cb = chunk_cb;
+ udata.udata = chunk_udata;
+
+ /* Iterate over the records in the v2 B-tree */
+ if((ret_value = H5B2_iterate(bt2, idx_info->dxpl_id, H5D__bt2_idx_iterate_cb, &udata)) < 0)
+ HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk v2 B-tree");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_remove_cb()
+ *
+ * Purpose: Free space for 'dataset chunk' object as v2 B-tree
+ * is being deleted or v2 B-tree node is removed.
+ * This is the callback for H5B2_remove() and H5B2_delete() which
+ * which are called in H5D__bt2_idx_remove() and H5D__bt2_idx_delete().
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_remove_cb(const void *_record, void *_udata)
+{
+ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */
+ H5D_bt2_remove_ud_t *udata = (H5D_bt2_remove_ud_t *)_udata; /* User data for removal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Free the space in the file for the object being removed */
+ H5_CHECK_OVERFLOW(record->nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(udata->f, H5FD_MEM_DRAW, udata->dxpl_id, record->chunk_addr, (hsize_t)record->nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_remove_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_remove
+ *
+ * Purpose: Remove chunk from index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
+{
+ H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */
+ H5D_bt2_remove_ud_t remove_udata; /* User data for removal callback */
+ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree find call */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the v2 B-tree is open yet */
+ if(NULL == idx_info->storage->u.btree2.bt2) {
+ /* Open existing v2 B-tree */
+ if(H5D__bt2_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+ } /* end if */
+ else /* Patch the top level file pointer contained in bt2 if needed */
+ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer")
+
+ /* Set convenience pointer to v2 B-tree structure */
+ bt2 = idx_info->storage->u.btree2.bt2;
+
+ /* Initialize user data for removal callback */
+ remove_udata.f = idx_info->f;
+ remove_udata.dxpl_id = idx_info->dxpl_id;
+
+ /* Prepare user data for compare callback */
+ bt2_udata.ndims = idx_info->layout->ndims - 1;
+
+ /* Initialize the record to search for */
+ for(u = 0; u < (idx_info->layout->ndims - 1); u++)
+ bt2_udata.rec.scaled[u] = udata->scaled[u];
+
+ /* Remove the record for the "dataset chunk" object from the v2 B-tree */
+ /* (space in the file for the object is freed in the 'remove' callback) */
+ if(H5B2_remove(bt2, idx_info->dxpl_id, &bt2_udata, (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) ? NULL : H5D__bt2_remove_cb, &remove_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__bt2_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_delete
+ *
+ * Purpose: Delete index and raw data storage for entire dataset
+ * (i.e. all chunks)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ * Modifications:
+ * Vailin Choi; March 2011
+ * Initialize size of an unfiltered chunk.
+ * This is a fix for for the assertion failure in:
+ * [src/H5FSsection.c:968: H5FS_sect_link_size: Assertion `bin < sinfo->nbins' failed.]
+ * which is uncovered by test_unlink_chunked_dataset() in test/unlink.c
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ H5D_bt2_remove_ud_t remove_udata; /* User data for removal callback */
+ H5B2_remove_t remove_op; /* The removal callback */
+ H5D_bt2_ctx_ud_t u_ctx; /* data for context call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ /* Check if the index data structure has been allocated */
+ if(H5F_addr_defined(idx_info->storage->idx_addr)) {
+ /* Set up user data for creating context */
+ u_ctx.f = idx_info->f;
+ u_ctx.ndims = idx_info->layout->ndims - 1;
+ u_ctx.chunk_size = idx_info->layout->size;
+ u_ctx.dim = idx_info->layout->dim;
+
+ /* Initialize user data for removal callback */
+ remove_udata.f = idx_info->f;
+ remove_udata.dxpl_id = idx_info->dxpl_id;
+
+ /* Set remove operation. Do not remove chunks in SWMR_WRITE mode */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ remove_op = NULL;
+ else
+ remove_op = H5D__bt2_remove_cb;
+
+ /* Delete the v2 B-tree */
+ /*(space in the file for each object is freed in the 'remove' callback) */
+ if(H5B2_delete(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &u_ctx, remove_op, &remove_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree")
+
+ idx_info->storage->idx_addr = HADDR_UNDEF;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Source file */
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+
+ /* Destination file */
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+ HDassert(!H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Check if the source v2 B-tree is open yet */
+ if(NULL == idx_info_src->storage->u.btree2.bt2)
+ if(H5D__bt2_idx_open(idx_info_src) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Create v2 B-tree that describes the chunked dataset in the destination file */
+ if(H5D__bt2_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+ HDassert(H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_copy_shutdown
+ *
+ * Purpose: Shutdown any information from copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(storage_src);
+ HDassert(storage_src->u.btree2.bt2);
+ HDassert(storage_dst);
+ HDassert(storage_dst->u.btree2.bt2);
+
+ /* Close v2 B-tree for source file */
+ if(H5B2_close(storage_src->u.btree2.bt2, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree")
+ storage_src->u.btree2.bt2 = NULL;
+
+ /* Close v2 B-tree for destination file */
+ if(H5B2_close(storage_dst->u.btree2.bt2, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree")
+ storage_dst->u.btree2.bt2 = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_copy_shutdown() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
+{
+ H5B2_t *bt2_cdset = NULL; /* Pointer to v2 B-tree structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(index_size);
+
+ /* Open v2 B-tree */
+ if(H5D__bt2_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree")
+
+ /* Set convenience pointer to v2 B-tree structure */
+ bt2_cdset = idx_info->storage->u.btree2.bt2;
+
+ /* Get v2 B-tree size for indexing chunked dataset */
+ if(H5B2_size(bt2_cdset, idx_info->dxpl_id, index_size) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve v2 B-tree storage info for chunked dataset")
+
+done:
+ /* Close v2 B-tree index */
+ if(bt2_cdset && H5B2_close(bt2_cdset, idx_info->dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for tracking chunked dataset")
+ idx_info->storage->u.btree2.bt2 = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr)
+ storage->idx_addr = HADDR_UNDEF;
+ storage->u.btree2.bt2 = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__bt2_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_dump
+ *
+ * Purpose: Dump indexing information to a stream.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__bt2_idx_dump() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__bt2_idx_dest
+ *
+ * Purpose: Release indexing information in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->storage);
+
+ /* Check if the v2-btree is open */
+ if(idx_info->storage->u.btree2.bt2) {
+
+ /* Patch the top level file pointer contained in bt2 if needed */
+ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer")
+
+ /* Close v2 B-tree */
+ if(H5B2_close(idx_info->storage->u.btree2.bt2, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree")
+ idx_info->storage->u.btree2.bt2 = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__bt2_idx_dest() */
+
diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c
new file mode 100644
index 0000000..ce684a0
--- /dev/null
+++ b/src/H5Dchunk.c
@@ -0,0 +1,6491 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, April 24, 2008
+ *
+ * Purpose: Abstract indexed (chunked) I/O functions. The logical
+ * multi-dimensional dataspace is regularly partitioned into
+ * same-sized "chunks", the first of which is aligned with the
+ * logical origin. The chunks are indexed by different methods,
+ * that map a chunk index to disk address. Each chunk can be
+ * compressed independently and the chunks may move around in the
+ * file as their storage requirements change.
+ *
+ * Cache: Disk I/O is performed in units of chunks and H5MF_alloc()
+ * contains code to optionally align chunks on disk block
+ * boundaries for performance.
+ *
+ * The chunk cache is an extendible hash indexed by a function
+ * of storage B-tree address and chunk N-dimensional offset
+ * within the dataset. Collisions are not resolved -- one of
+ * the two chunks competing for the hash slot must be preempted
+ * from the cache. All entries in the hash also participate in
+ * a doubly-linked list and entries are penalized by moving them
+ * toward the front of the list. When a new chunk is about to
+ * be added to the cache the heap is pruned by preempting
+ * entries near the front of the list to make room for the new
+ * entry which is added to the end of the list.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#ifdef H5_HAVE_PARALLEL
+#include "H5ACprivate.h" /* Metadata cache */
+#endif /* H5_HAVE_PARALLEL */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File functions */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Macros for iterating over chunks to operate on */
+#define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->sel_chunks))
+#define H5D_CHUNK_GET_NODE_INFO(map, node) (map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node))
+#define H5D_CHUNK_GET_NEXT_NODE(map, node) (map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node))
+
+/* Sanity check on chunk index types: commonly used by a lot of routines in this file */
+#define H5D_CHUNK_STORAGE_INDEX_CHK(storage) \
+ HDassert((H5D_CHUNK_IDX_EARRAY == storage->idx_type && H5D_COPS_EARRAY == storage->ops) || \
+ (H5D_CHUNK_IDX_FARRAY == storage->idx_type && H5D_COPS_FARRAY == storage->ops) || \
+ (H5D_CHUNK_IDX_BT2 == storage->idx_type && H5D_COPS_BT2 == storage->ops) || \
+ (H5D_CHUNK_IDX_BTREE == storage->idx_type && H5D_COPS_BTREE == storage->ops) || \
+ (H5D_CHUNK_IDX_SINGLE == storage->idx_type && H5D_COPS_SINGLE == storage->ops) || \
+ (H5D_CHUNK_IDX_NONE == storage->idx_type && H5D_COPS_NONE == storage->ops));
+
+/*
+ * Feature: If this constant is defined then every cache preemption and load
+ * causes a character to be printed on the standard error stream:
+ *
+ * `.': Entry was preempted because it has been completely read or
+ * completely written but not partially read and not partially
+ * written. This is often a good reason for preemption because such
+ * a chunk will be unlikely to be referenced in the near future.
+ *
+ * `:': Entry was preempted because it hasn't been used recently.
+ *
+ * `#': Entry was preempted because another chunk collided with it. This
+ * is usually a relatively bad thing. If there are too many of
+ * these then the number of entries in the cache can be increased.
+ *
+ * c: Entry was preempted because the file is closing.
+ *
+ * w: A chunk read operation was eliminated because the library is
+ * about to write new values to the entire chunk. This is a good
+ * thing, especially on files where the chunk size is the same as
+ * the disk block size, chunks are aligned on disk block boundaries,
+ * and the operating system can also eliminate a read operation.
+ */
+
+/*#define H5D_CHUNK_DEBUG */
+
+/* Flags for the "edge_chunk_state" field below */
+#define H5D_RDCC_DISABLE_FILTERS 0x01u /* Disable filters on this chunk */
+#define H5D_RDCC_NEWLY_DISABLED_FILTERS 0x02u /* Filters have been disabled since
+ * the last flush */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Raw data chunks are cached. Each entry in the cache is: */
+typedef struct H5D_rdcc_ent_t {
+ hbool_t locked; /*entry is locked in cache */
+ hbool_t dirty; /*needs to be written to disk? */
+ hbool_t deleted; /*chunk about to be deleted */
+ unsigned edge_chunk_state; /*states related to edge chunks (see above) */
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /*scaled chunk 'name' (coordinates) */
+ uint32_t rd_count; /*bytes remaining to be read */
+ uint32_t wr_count; /*bytes remaining to be written */
+ H5F_block_t chunk_block; /*offset/length of chunk in file */
+ hsize_t chunk_idx; /*index of chunk in dataset */
+ uint8_t *chunk; /*the unfiltered chunk data */
+ unsigned idx; /*index in hash table */
+ struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */
+ struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */
+ struct H5D_rdcc_ent_t *tmp_next;/*next item in temporary doubly-linked list */
+ struct H5D_rdcc_ent_t *tmp_prev;/*previous item in temporary doubly-linked list */
+} H5D_rdcc_ent_t;
+typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */
+
+/* Callback info for iteration to prune chunks */
+typedef struct H5D_chunk_it_ud1_t {
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+ const H5D_chk_idx_info_t *idx_info; /* Chunked index info */
+ const H5D_io_info_t *io_info; /* I/O info for dataset operation */
+ const hsize_t *space_dim; /* New dataset dimensions */
+ const hbool_t *shrunk_dim; /* Dimensions which have been shrunk */
+ H5S_t *chunk_space; /* Dataspace for a chunk */
+ uint32_t elmts_per_chunk;/* Elements in chunk */
+ hsize_t *hyper_start; /* Starting location of hyperslab */
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init; /* Whether the fill value buffer has been initialized */
+} H5D_chunk_it_ud1_t;
+
+/* Callback info for iteration to obtain chunk address and the index of the chunk for all chunks in the B-tree. */
+typedef struct H5D_chunk_it_ud2_t {
+ /* down */
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+
+ /* up */
+ haddr_t *chunk_addr; /* Array of chunk addresses to fill in */
+} H5D_chunk_it_ud2_t;
+
+/* Callback info for iteration to copy data */
+typedef struct H5D_chunk_it_ud3_t {
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+ H5F_t *file_src; /* Source file for copy */
+ H5D_chk_idx_info_t *idx_info_dst; /* Dest. chunk index info object */
+ void *buf; /* Buffer to hold chunk data for read/write */
+ void *bkg; /* Buffer for background information during type conversion */
+ size_t buf_size; /* Buffer size */
+ hbool_t do_convert; /* Whether to perform type conversions */
+
+ /* needed for converting variable-length data */
+ hid_t tid_src; /* Datatype ID for source datatype */
+ hid_t tid_dst; /* Datatype ID for destination datatype */
+ hid_t tid_mem; /* Datatype ID for memory datatype */
+ const H5T_t *dt_src; /* Source datatype */
+ H5T_path_t *tpath_src_mem; /* Datatype conversion path from source file to memory */
+ H5T_path_t *tpath_mem_dst; /* Datatype conversion path from memory to dest. file */
+ void *reclaim_buf; /* Buffer for reclaiming data */
+ size_t reclaim_buf_size; /* Reclaim buffer size */
+ uint32_t nelmts; /* Number of elements in buffer */
+ H5S_t *buf_space; /* Dataspace describing buffer */
+
+ /* needed for compressed variable-length data */
+ const H5O_pline_t *pline; /* Filter pipeline */
+ unsigned dset_ndims; /* Number of dimensions in dataset */
+ const hsize_t *dset_dims; /* Dataset dimensions */
+
+ /* needed for copy object pointed by refs */
+ H5O_copy_t *cpy_info; /* Copy options */
+} H5D_chunk_it_ud3_t;
+
+/* Callback info for iteration to dump index */
+typedef struct H5D_chunk_it_ud4_t {
+ FILE *stream; /* Output stream */
+ hbool_t header_displayed; /* Node's header is displayed? */
+ unsigned ndims; /* Number of dimensions for chunk/dataset */
+ uint32_t *chunk_dim; /* Chunk dimensions */
+} H5D_chunk_it_ud4_t;
+
+/* Callback info for iteration to format convert chunks */
+typedef struct H5D_chunk_it_ud5_t {
+ H5D_chk_idx_info_t *new_idx_info; /* Dest. chunk index info object */
+ unsigned dset_ndims; /* Number of dimensions in dataset */
+ hsize_t *dset_dims; /* Dataset dimensions */
+} H5D_chunk_it_ud5_t;
+
+/* Callback info for nonexistent readvv operation */
+typedef struct H5D_chunk_readvv_ud_t {
+ unsigned char *rbuf; /* Read buffer to initialize */
+ const H5D_t *dset; /* Dataset to operate on */
+ hid_t dxpl_id; /* DXPL for operation */
+} H5D_chunk_readvv_ud_t;
+
+/* Callback info for file selection iteration */
+typedef struct H5D_chunk_file_iter_ud_t {
+ H5D_chunk_map_t *fm; /* File->memory chunk mapping info */
+#ifdef H5_HAVE_PARALLEL
+ const H5D_io_info_t *io_info; /* I/O info for operation */
+#endif /* H5_HAVE_PARALLEL */
+} H5D_chunk_file_iter_ud_t;
+
+#ifdef H5_HAVE_PARALLEL
+/* information to construct a collective I/O operation for filling chunks */
+typedef struct H5D_chunk_coll_info_t {
+ size_t num_io; /* Number of write operations */
+ haddr_t *addr; /* array of the file addresses of the write operation */
+} H5D_chunk_coll_info_t;
+#endif /* H5_HAVE_PARALLEL */
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Chunked layout operation callbacks */
+static herr_t H5D__chunk_construct(H5F_t *f, H5D_t *dset);
+static herr_t H5D__chunk_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset,
+ hid_t dapl_id);
+static herr_t H5D__chunk_io_init(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_flush(H5D_t *dset, hid_t dxpl_id);
+static herr_t H5D__chunk_io_term(const H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_dest(H5D_t *dset, hid_t dxpl_id);
+
+/* "Nonexistent" layout operation callback */
+static ssize_t
+H5D__nonexistent_readvv(const H5D_io_info_t *io_info,
+ size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+
+/* format convert cb */
+static int H5D__chunk_format_convert_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
+
+/* Helper routines */
+static herr_t H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims,
+ const hsize_t *curr_dims, const hsize_t *max_dims);
+static void *H5D__chunk_mem_alloc(size_t size, const H5O_pline_t *pline);
+static void *H5D__chunk_mem_xfree(void *chk, const H5O_pline_t *pline);
+static void *H5D__chunk_mem_realloc(void *chk, size_t size,
+ const H5O_pline_t *pline);
+static herr_t H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last);
+static herr_t H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last,
+ const H5D_chunk_ud_t *udata);
+static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last,
+ H5D_chunk_ud_t *udata);
+static herr_t H5D__free_chunk_info(void *item, void *key, void *opdata);
+static herr_t H5D__create_chunk_map_single(H5D_chunk_map_t *fm,
+ const H5D_io_info_t *io_info);
+static herr_t H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm,
+ const H5D_io_info_t *io_info);
+static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm);
+static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims,
+ const hsize_t *coords, void *fm);
+static herr_t H5D__chunk_mem_cb(void *elem, const H5T_t *type, unsigned ndims,
+ const hsize_t *coords, void *fm);
+static unsigned H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled);
+static herr_t H5D__chunk_flush_entry(const H5D_t *dset, hid_t dxpl_id,
+ const H5D_dxpl_cache_t *dxpl_cache, H5D_rdcc_ent_t *ent, hbool_t reset);
+static herr_t H5D__chunk_cache_evict(const H5D_t *dset, hid_t dxpl_id,
+ const H5D_dxpl_cache_t *dxpl_cache, H5D_rdcc_ent_t *ent, hbool_t flush);
+static hbool_t H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims,
+ const uint32_t *chunk_dims, const hsize_t *chunk_scaled, const hsize_t *dset_dims);
+static void *H5D__chunk_lock(const H5D_io_info_t *io_info,
+ H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk);
+static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info,
+ const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk,
+ uint32_t naccessed);
+static herr_t H5D__chunk_cache_prune(const H5D_t *dset, hid_t dxpl_id,
+ const H5D_dxpl_cache_t *dxpl_cache, size_t size);
+static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk);
+static herr_t H5D__chunk_file_alloc(const H5D_chk_idx_info_t *idx_info,
+ const H5F_block_t *old_chunk, H5F_block_t *new_chunk, hbool_t *need_insert,
+ hsize_t scaled[]);
+#ifdef H5_HAVE_PARALLEL
+static herr_t H5D__chunk_collective_fill(const H5D_t *dset, hid_t dxpl_id,
+ H5D_chunk_coll_info_t *chunk_info, size_t chunk_size, const void *fill_buf);
+#endif /* H5_HAVE_PARALLEL */
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Chunked storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{
+ H5D__chunk_construct,
+ H5D__chunk_init,
+ H5D__chunk_is_space_alloc,
+ H5D__chunk_io_init,
+ H5D__chunk_read,
+ H5D__chunk_write,
+#ifdef H5_HAVE_PARALLEL
+ H5D__chunk_collective_read,
+ H5D__chunk_collective_write,
+#endif /* H5_HAVE_PARALLEL */
+ NULL,
+ NULL,
+ H5D__chunk_flush,
+ H5D__chunk_io_term,
+ H5D__chunk_dest
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* "nonexistent" storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_NONEXISTENT[1] = {{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#ifdef H5_HAVE_PARALLEL
+ NULL,
+ NULL,
+#endif /* H5_HAVE_PARALLEL */
+ H5D__nonexistent_readvv,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+}};
+
+/* Declare a free list to manage the H5F_rdcc_ent_ptr_t sequence information */
+H5FL_SEQ_DEFINE_STATIC(H5D_rdcc_ent_ptr_t);
+
+/* Declare a free list to manage H5D_rdcc_ent_t objects */
+H5FL_DEFINE_STATIC(H5D_rdcc_ent_t);
+
+/* Declare a free list to manage the H5D_chunk_info_t struct */
+H5FL_DEFINE(H5D_chunk_info_t);
+
+/* Declare a free list to manage the chunk sequence information */
+H5FL_BLK_DEFINE_STATIC(chunk);
+
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_direct_write
+ *
+ * Purpose: Internal routine to write a chunk
+ * directly into the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 30 July 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_direct_write(const H5D_t *dset, hid_t dxpl_id, uint32_t filters,
+ hsize_t *offset, uint32_t data_size, const void *buf)
+{
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
+ H5D_chunk_ud_t udata; /* User data for querying chunk info */
+ H5F_block_t old_chunk; /* Offset/length of old chunk */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+ H5D_io_info_t io_info; /* to hold the dset and two dxpls (meta and raw data) */
+ hbool_t md_dxpl_generated = FALSE; /* bool to indicate whether we should free the md_dxpl_id at exit */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ io_info.dset = dset;
+ io_info.raw_dxpl_id = dxpl_id;
+ io_info.md_dxpl_id = dxpl_id;
+
+ /* set the dxpl IO type for sanity checking at the FD layer */
+#ifdef H5_DEBUG_BUILD
+ if(H5D_set_io_info_dxpls(&io_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't set metadata and raw data dxpls")
+ md_dxpl_generated = TRUE;
+#endif /* H5_DEBUG_BUILD */
+
+ /* Allocate dataspace and initialize it if it hasn't been. */
+ if(!(*layout->ops->is_space_alloc)(&layout->storage)) {
+ /* Allocate storage */
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, FALSE, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
+ }
+ /* Calculate the index of this chunk */
+ H5VM_chunk_scaled(dset->shared->ndims, offset, layout->u.chunk.dim, scaled);
+ scaled[dset->shared->ndims] = 0;
+
+ /* Find out the file address of the chunk (if any) */
+ if(H5D__chunk_lookup(dset, io_info.md_dxpl_id, scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Set the file block information for the old chunk */
+ /* (Which is only defined when overwriting an existing chunk) */
+ old_chunk.offset = udata.chunk_block.offset;
+ old_chunk.length = udata.chunk_block.length;
+
+ /* Check if the chunk needs to be inserted (it also could exist already
+ * and the chunk allocate operation could resize it)
+ */
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = io_info.md_dxpl_id;
+ idx_info.pline = &(dset->shared->dcpl_cache.pline);
+ idx_info.layout = &(dset->shared->layout.u.chunk);
+ idx_info.storage = &(dset->shared->layout.storage.u.chunk);
+
+ /* Set up the size of chunk for user data */
+ udata.chunk_block.length = data_size;
+
+ /* Create the chunk it if it doesn't exist, or reallocate the chunk
+ * if its size changed.
+ */
+ if(H5D__chunk_file_alloc(&idx_info, &old_chunk, &udata.chunk_block, &need_insert, scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate chunk")
+
+ /* Make sure the address of the chunk is returned. */
+ if(!H5F_addr_defined(udata.chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk address isn't defined")
+
+ /* Evict the (old) entry from the cache if present, but do not flush
+ * it to disk */
+ if(UINT_MAX != udata.idx_hint) {
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(io_info.raw_dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ if(H5D__chunk_cache_evict(dset, io_info.md_dxpl_id, dxpl_cache, rdcc->slot[udata.idx_hint], FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
+ } /* end if */
+
+ /* Write the data to the file */
+ if(H5F_block_write(dset->oloc.file, H5FD_MEM_DRAW, udata.chunk_block.offset, data_size, io_info.raw_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
+
+ /* Insert the chunk record into the index */
+ if(need_insert && layout->storage.u.chunk.ops->insert) {
+ /* Set the chunk's filter mask to the new settings */
+ udata.filter_mask = filters;
+
+ if((layout->storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
+ } /* end if */
+
+done:
+#ifdef H5_DEBUG_BUILD
+ if(md_dxpl_generated && H5I_dec_ref(io_info.md_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't close metadata dxpl")
+#endif /* H5_DEBUG_BUILD */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__chunk_direct_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_set_info_real
+ *
+ * Purpose: Internal routine to set the information about chunks for a dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_set_info_real(H5O_layout_chunk_t *layout, unsigned ndims,
+ const hsize_t *curr_dims, const hsize_t *max_dims)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(layout);
+ HDassert(ndims > 0);
+ HDassert(curr_dims);
+
+ /* Compute the # of chunks in dataset dimensions */
+ for(u = 0, layout->nchunks = 1, layout->max_nchunks = 1; u < ndims; u++) {
+ /* Round up to the next integer # of chunks, to accomodate partial chunks */
+ layout->chunks[u] = ((curr_dims[u] + layout->dim[u]) - 1) / layout->dim[u];
+ if(H5S_UNLIMITED == max_dims[u])
+ layout->max_chunks[u] = H5S_UNLIMITED;
+ else
+ layout->max_chunks[u] = ((max_dims[u] + layout->dim[u]) - 1) / layout->dim[u];
+
+ /* Accumulate the # of chunks */
+ layout->nchunks *= layout->chunks[u];
+ layout->max_nchunks *= layout->max_chunks[u];
+ } /* end for */
+
+ /* Get the "down" sizes for each dimension */
+ if(H5VM_array_down(ndims, layout->chunks, layout->down_chunks) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value")
+ if(H5VM_array_down(ndims, layout->max_chunks, layout->max_down_chunks) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_set_info_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_set_info
+ *
+ * Purpose: Sets the information about chunks for a dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_set_info(const H5D_t *dset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(dset);
+
+ /* Set the base layout information */
+ if(H5D__chunk_set_info_real(&dset->shared->layout.u.chunk, dset->shared->ndims, dset->shared->curr_dims, dset->shared->max_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set layout's chunk info")
+
+ /* Call the index's "resize" callback */
+ if(dset->shared->layout.storage.u.chunk.ops->resize && (dset->shared->layout.storage.u.chunk.ops->resize)(&dset->shared->layout.u.chunk) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to resize chunk index information")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_set_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_set_sizes
+ *
+ * Purpose: Sets chunk and type sizes.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * December 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_set_sizes(H5D_t *dset)
+{
+ uint64_t chunk_size; /* Size of chunk in bytes */
+ unsigned max_enc_bytes_per_dim; /* Max. number of bytes required to encode this dimension */
+ unsigned u; /* Iterator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(dset);
+
+ /* Increment # of chunk dimensions, to account for datatype size as last element */
+ dset->shared->layout.u.chunk.ndims++;
+
+ /* Set the last dimension of the chunk size to the size of the datatype */
+ dset->shared->layout.u.chunk.dim[dset->shared->layout.u.chunk.ndims - 1] = (uint32_t)H5T_GET_SIZE(dset->shared->type);
+
+ /* Compute number of bytes to use for encoding chunk dimensions */
+ max_enc_bytes_per_dim = 0;
+ for(u = 0; u < (unsigned)dset->shared->layout.u.chunk.ndims; u++) {
+ unsigned enc_bytes_per_dim; /* Number of bytes required to encode this dimension */
+
+ /* Get encoded size of dim, in bytes */
+ enc_bytes_per_dim = (H5VM_log2_gen(dset->shared->layout.u.chunk.dim[u]) + 8) / 8;
+
+ /* Check if this is the largest value so far */
+ if(enc_bytes_per_dim > max_enc_bytes_per_dim)
+ max_enc_bytes_per_dim = enc_bytes_per_dim;
+ } /* end for */
+ HDassert(max_enc_bytes_per_dim > 0 && max_enc_bytes_per_dim <= 8);
+ dset->shared->layout.u.chunk.enc_bytes_per_dim = max_enc_bytes_per_dim;
+
+ /* Compute and store the total size of a chunk */
+ /* (Use 64-bit value to ensure that we can detect >4GB chunks) */
+ for(u = 1, chunk_size = (uint64_t)dset->shared->layout.u.chunk.dim[0]; u < dset->shared->layout.u.chunk.ndims; u++)
+ chunk_size *= (uint64_t)dset->shared->layout.u.chunk.dim[u];
+
+ /* Check for chunk larger than can be represented in 32-bits */
+ /* (Chunk size is encoded in 32-bit value in v1 B-tree records) */
+ if(chunk_size > (uint64_t)0xffffffff)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "chunk size must be < 4GB")
+
+ H5_CHECKED_ASSIGN(dset->shared->layout.u.chunk.size, uint32_t, chunk_size, uint64_t);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_set_sizes */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_construct
+ *
+ * Purpose: Constructs new chunked layout information for dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_construct(H5F_t H5_ATTR_UNUSED *f, H5D_t *dset)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(dset);
+
+ /* Check for invalid chunk dimension rank */
+ if(0 == dset->shared->layout.u.chunk.ndims)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "no chunk information set?")
+ if(dset->shared->layout.u.chunk.ndims != dset->shared->ndims)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "dimensionality of chunks doesn't match the dataspace")
+
+ /* Set chunk sizes */
+ if(H5D__chunk_set_sizes(dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to set chunk sizes")
+ HDassert((unsigned)(dset->shared->layout.u.chunk.ndims) <= NELMTS(dset->shared->layout.u.chunk.dim));
+
+ /* Chunked storage is not compatible with external storage (currently) */
+ if(dset->shared->dcpl_cache.efl.nused > 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "external storage not supported with chunked layout")
+
+ /* Sanity check dimensions */
+ for(u = 0; u < dset->shared->layout.u.chunk.ndims - 1; u++) {
+ /* Don't allow zero-sized chunk dimensions */
+ if(0 == dset->shared->layout.u.chunk.dim[u])
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "chunk size must be > 0, dim = %u ", u)
+
+ /*
+ * The chunk size of a dimension with a fixed size cannot exceed
+ * the maximum dimension size. If any dimension size is zero, there
+ * will be no such restriction.
+ */
+ if(dset->shared->curr_dims[u] && dset->shared->max_dims[u] != H5S_UNLIMITED && dset->shared->max_dims[u] < dset->shared->layout.u.chunk.dim[u])
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "chunk size must be <= maximum dimension size for fixed-sized dimensions")
+ } /* end for */
+
+ /* Reset address and pointer of the array struct for the chunked storage index */
+ if(H5D_chunk_idx_reset(&dset->shared->layout.storage.u.chunk, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to reset chunked storage index")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_construct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_init
+ *
+ * Purpose: Initialize the raw data chunk cache for a dataset. This is
+ * called when the dataset is initialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, May 18, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, hid_t dapl_id)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /* Convenience pointer to dataset's chunk cache */
+ H5P_genplist_t *dapl; /* Data access property list object pointer */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(dset);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ if(NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for fapl ID")
+
+ /* Use the properties in dapl_id if they have been set, otherwise use the properties from the file */
+ if(H5P_get(dapl, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &rdcc->nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache number of slots")
+ if(rdcc->nslots == H5D_CHUNK_CACHE_NSLOTS_DEFAULT)
+ rdcc->nslots = H5F_RDCC_NSLOTS(f);
+
+ if(H5P_get(dapl, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &rdcc->nbytes_max) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache byte size")
+ if(rdcc->nbytes_max == H5D_CHUNK_CACHE_NBYTES_DEFAULT)
+ rdcc->nbytes_max = H5F_RDCC_NBYTES(f);
+
+ if(H5P_get(dapl, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &rdcc->w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get preempt read chunks")
+ if(rdcc->w0 < 0)
+ rdcc->w0 = H5F_RDCC_W0(f);
+
+ /* If nbytes_max or nslots is 0, set them both to 0 and avoid allocating space */
+ if(!rdcc->nbytes_max || !rdcc->nslots)
+ rdcc->nbytes_max = rdcc->nslots = 0;
+ else {
+ rdcc->slot = H5FL_SEQ_CALLOC(H5D_rdcc_ent_ptr_t, rdcc->nslots);
+ if(NULL == rdcc->slot)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&(rdcc->last));
+ } /* end else */
+
+ /* Compute scaled dimension info, if dataset dims > 1 */
+ if(dset->shared->ndims > 1) {
+ unsigned u; /* Local index value */
+
+ for(u = 0; u < dset->shared->ndims; u++) {
+ /* Initial scaled dimension sizes */
+ rdcc->scaled_dims[u] = dset->shared->curr_dims[u] / dset->shared->layout.u.chunk.dim[u];
+
+ /* Inital 'power2up' values for scaled dimensions */
+ rdcc->scaled_power2up[u] = H5VM_power2up(rdcc->scaled_dims[u]);
+
+ /* Number of bits required to encode scaled dimension size */
+ rdcc->scaled_encode_bits[u] = H5VM_log2_gen(rdcc->scaled_power2up[u]);
+ } /* end for */
+ } /* end if */
+
+ /* Compose chunked index info struct */
+ idx_info.f = f;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Allocate any indexing structures */
+ if(dset->shared->layout.storage.u.chunk.ops->init && (dset->shared->layout.storage.u.chunk.ops->init)(&idx_info, dset->shared->space, dset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize indexing information")
+
+ /* Set the number of chunks in dataset, etc. */
+ if(H5D__chunk_set_info(dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set # of chunks for dataset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for layout
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5D__chunk_is_space_alloc(const H5O_storage_t *storage)
+{
+ const H5O_storage_chunk_t *sc = &(storage->u.chunk);
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ /* Query index layer */
+ ret_value = (storage->u.chunk.ops->is_space_alloc)(&storage->u.chunk);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_io_init
+ *
+ * Purpose: Performs initialization before any sort of I/O on the raw data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm)
+{
+ const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
+ const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */
+ H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */
+ hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */
+ htri_t file_space_normalized = FALSE; /* File dataspace was normalized */
+ H5T_t *file_type = NULL; /* Temporary copy of file datatype for iteration */
+ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
+ unsigned f_ndims; /* The number of dimensions of the file's dataspace */
+ int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */
+ H5SL_node_t *curr_node; /* Current node in skip list */
+ char bogus; /* "bogus" buffer to pass to selection iterator */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get layout for dataset */
+ fm->layout = &(dataset->shared->layout);
+ fm->nelmts = nelmts;
+
+ /* Check if the memory space is scalar & make equivalent memory space */
+ if((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number")
+ /* Set the number of dimensions for the memory dataspace */
+ H5_CHECKED_ASSIGN(fm->m_ndims, unsigned, sm_ndims, int);
+
+ /* Get rank for file dataspace */
+ fm->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1;
+
+ /* Normalize hyperslab selections by adjusting them by the offset */
+ /* (It might be worthwhile to normalize both the file and memory dataspaces
+ * before any (contiguous, chunked, etc) file I/O operation, in order to
+ * speed up hyperslab calculations by removing the extra checks and/or
+ * additions involving the offset and the hyperslab selection -QAK)
+ */
+ if((file_space_normalized = H5S_hyper_normalize_offset((H5S_t *)file_space, old_offset)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
+
+ /* Decide the number of chunks in each dimension*/
+ for(u = 0; u < f_ndims; u++) {
+ /* Keep the size of the chunk dimensions as hsize_t for various routines */
+ fm->chunk_dim[u] = fm->layout->u.chunk.dim[u];
+ } /* end for */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Calculate total chunk in file map*/
+ fm->select_chunk = NULL;
+ if(io_info->using_mpi_vfd) {
+ H5_CHECK_OVERFLOW(fm->layout->u.chunk.nchunks, hsize_t, size_t);
+ if(fm->layout->u.chunk.nchunks) {
+ if(NULL == (fm->select_chunk = (H5D_chunk_info_t **)H5MM_calloc((size_t)fm->layout->u.chunk.nchunks * sizeof(H5D_chunk_info_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
+ }
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+
+ /* Initialize "last chunk" information */
+ fm->last_index = (hsize_t)-1;
+ fm->last_chunk_info = NULL;
+
+ /* Point at the dataspaces */
+ fm->file_space = file_space;
+ fm->mem_space = mem_space;
+
+ /* Special case for only one element in selection */
+ /* (usually appending a record) */
+ if(nelmts == 1
+#ifdef H5_HAVE_PARALLEL
+ && !(io_info->using_mpi_vfd)
+#endif /* H5_HAVE_PARALLEL */
+ && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(file_space)) {
+ /* Initialize skip list for chunk selections */
+ fm->sel_chunks = NULL;
+ fm->use_single = TRUE;
+
+ /* Initialize single chunk dataspace */
+ if(NULL == dataset->shared->cache.chunk.single_space) {
+ /* Make a copy of the dataspace for the dataset */
+ if((dataset->shared->cache.chunk.single_space = H5S_copy(file_space, TRUE, FALSE)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space")
+
+ /* Resize chunk's dataspace dimensions to size of chunk */
+ if(H5S_set_extent_real(dataset->shared->cache.chunk.single_space, fm->chunk_dim) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust chunk dimensions")
+
+ /* Set the single chunk dataspace to 'all' selection */
+ if(H5S_select_all(dataset->shared->cache.chunk.single_space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to set all selection")
+ } /* end if */
+ fm->single_space = dataset->shared->cache.chunk.single_space;
+ HDassert(fm->single_space);
+
+ /* Allocate the single chunk information */
+ if(NULL == dataset->shared->cache.chunk.single_chunk_info) {
+ if(NULL == (dataset->shared->cache.chunk.single_chunk_info = H5FL_MALLOC(H5D_chunk_info_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
+ } /* end if */
+ fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info;
+ HDassert(fm->single_chunk_info);
+
+ /* Reset chunk template information */
+ fm->mchunk_tmpl = NULL;
+
+ /* Set up chunk mapping for single element */
+ if(H5D__create_chunk_map_single(fm, io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk selections for single element")
+ } /* end if */
+ else {
+ hbool_t sel_hyper_flag; /* Whether file selection is a hyperslab */
+
+ /* Initialize skip list for chunk selections */
+ if(NULL == dataset->shared->cache.chunk.sel_chunks) {
+ if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, NULL)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections")
+ } /* end if */
+ fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks;
+ HDassert(fm->sel_chunks);
+
+ /* We are not using single element mode */
+ fm->use_single = FALSE;
+
+ /* Get type of selection on disk & in memory */
+ if((fm->fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection")
+ if((fm->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection")
+
+ /* If the selection is NONE or POINTS, set the flag to FALSE */
+ if(fm->fsel_type == H5S_SEL_POINTS || fm->fsel_type == H5S_SEL_NONE)
+ sel_hyper_flag = FALSE;
+ else
+ sel_hyper_flag = TRUE;
+
+ /* Check if file selection is a not a hyperslab selection */
+ if(sel_hyper_flag) {
+ /* Build the file selection for each chunk */
+ if(H5D__create_chunk_file_map_hyper(fm, io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
+
+ /* Clean file chunks' hyperslab span "scratch" information */
+ curr_node = H5SL_first(fm->sel_chunks);
+ while(curr_node) {
+ H5D_chunk_info_t *chunk_info; /* Pointer chunk information */
+
+ /* Get pointer to chunk's information */
+ chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
+ HDassert(chunk_info);
+
+ /* Clean hyperslab span's "scratch" information */
+ if(H5S_hyper_reset_scratch(chunk_info->fspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info")
+
+ /* Get the next chunk node in the skip list */
+ curr_node = H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+ else {
+ H5S_sel_iter_op_t iter_op; /* Operator for iteration */
+ H5D_chunk_file_iter_ud_t udata; /* User data for iteration */
+
+ /* Create temporary datatypes for selection iteration */
+ if(NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype")
+
+ /* Initialize the user data */
+ udata.fm = fm;
+#ifdef H5_HAVE_PARALLEL
+ udata.io_info = io_info;
+#endif /* H5_HAVE_PARALLEL */
+
+ iter_op.op_type = H5S_SEL_ITER_OP_LIB;
+ iter_op.u.lib_op = H5D__chunk_file_cb;
+
+ /* Spaces might not be the same shape, iterate over the file selection directly */
+ if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections")
+
+ /* Reset "last chunk" info */
+ fm->last_index = (hsize_t)-1;
+ fm->last_chunk_info = NULL;
+ } /* end else */
+
+ /* Build the memory selection for each chunk */
+ if(sel_hyper_flag && H5S_select_shape_same(file_space, mem_space) == TRUE) {
+ /* Reset chunk template information */
+ fm->mchunk_tmpl = NULL;
+
+ /* If the selections are the same shape, use the file chunk information
+ * to generate the memory chunk information quickly.
+ */
+ if(H5D__create_chunk_mem_map_hyper(fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections")
+ } /* end if */
+ else {
+ H5S_sel_iter_op_t iter_op; /* Operator for iteration */
+ size_t elmt_size; /* Memory datatype size */
+
+ /* Make a copy of equivalent memory space */
+ if((tmp_mspace = H5S_copy(mem_space, TRUE, FALSE)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
+
+ /* De-select the mem space copy */
+ if(H5S_select_none(tmp_mspace) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space")
+
+ /* Save chunk template information */
+ fm->mchunk_tmpl = tmp_mspace;
+
+ /* Create temporary datatypes for selection iteration */
+ if(!file_type) {
+ if(NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype")
+ } /* end if */
+
+ /* Create selection iterator for memory selection */
+ if(0 == (elmt_size = H5T_get_size(mem_type)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid")
+ if(H5S_select_iter_init(&(fm->mem_iter), mem_space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ iter_init = TRUE; /* Selection iteration info has been initialized */
+
+ iter_op.op_type = H5S_SEL_ITER_OP_LIB;
+ iter_op.u.lib_op = H5D__chunk_mem_cb;
+
+ /* Spaces aren't the same shape, iterate over the memory selection directly */
+ if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections")
+
+ /* Clean up hyperslab stuff, if necessary */
+ if(fm->msel_type != H5S_SEL_POINTS) {
+ /* Clean memory chunks' hyperslab span "scratch" information */
+ curr_node = H5SL_first(fm->sel_chunks);
+ while(curr_node) {
+ H5D_chunk_info_t *chunk_info; /* Pointer chunk information */
+
+ /* Get pointer to chunk's information */
+ chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
+ HDassert(chunk_info);
+
+ /* Clean hyperslab span's "scratch" information */
+ if(H5S_hyper_reset_scratch(chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info")
+
+ /* Get the next chunk node in the skip list */
+ curr_node = H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+done:
+ /* Release the [potentially partially built] chunk mapping information if an error occurs */
+ if(ret_value < 0) {
+ if(tmp_mspace && !fm->mchunk_tmpl) {
+ if(H5S_close(tmp_mspace) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template")
+ } /* end if */
+
+ if(H5D__chunk_io_term(fm) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping")
+ } /* end if */
+
+ /* Reset the global dataspace info */
+ fm->file_space = NULL;
+ fm->mem_space = NULL;
+
+ if(iter_init && H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(file_type && (H5T_close(file_type) < 0))
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Can't free temporary datatype")
+ if(file_space_normalized) {
+ /* (Casting away const OK -QAK) */
+ if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_io_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_mem_alloc
+ *
+ * Purpose: Allocate space for a chunk in memory. This routine allocates
+ * memory space for non-filtered chunks from a block free list
+ * and uses malloc()/free() for filtered chunks.
+ *
+ * Return: Pointer to memory for chunk on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * April 22, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__chunk_mem_alloc(size_t size, const H5O_pline_t *pline)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(size);
+
+ if(pline && pline->nused)
+ ret_value = H5MM_malloc(size);
+ else
+ ret_value = H5FL_BLK_MALLOC(chunk, size);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_mem_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_mem_xfree
+ *
+ * Purpose: Free space for a chunk in memory. This routine allocates
+ * memory space for non-filtered chunks from a block free list
+ * and uses malloc()/free() for filtered chunks.
+ *
+ * Return: NULL (never fails)
+ *
+ * Programmer: Quincey Koziol
+ * April 22, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__chunk_mem_xfree(void *chk, const H5O_pline_t *pline)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ if(chk) {
+ if(pline && pline->nused)
+ H5MM_xfree(chk);
+ else
+ chk = H5FL_BLK_FREE(chunk, chk);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* H5D__chunk_mem_xfree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_mem_realloc
+ *
+ * Purpose: Reallocate space for a chunk in memory. This routine allocates
+ * memory space for non-filtered chunks from a block free list
+ * and uses malloc()/free() for filtered chunks.
+ *
+ * Return: Pointer to memory for chunk on success/NULL on failure
+ *
+ * Programmer: Neil Fortner
+ * May 3, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(size);
+ HDassert(pline);
+
+ if(pline->nused > 0)
+ ret_value = H5MM_realloc(chk, size);
+ else
+ ret_value = H5FL_BLK_REALLOC(chunk, chk, size);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_mem_realloc() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__free_chunk_info
+ PURPOSE
+ Internal routine to destroy a chunk info node
+ USAGE
+ void H5D__free_chunk_info(chunk_info)
+ void *chunk_info; IN: Pointer to chunk info to destroy
+ RETURNS
+ No return value
+ DESCRIPTION
+ Releases all the memory for a chunk info node. Called by H5SL_free
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5D__free_chunk_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata)
+{
+ H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(chunk_info);
+
+ /* Close the chunk's file dataspace, if it's not shared */
+ if(!chunk_info->fspace_shared)
+ (void)H5S_close(chunk_info->fspace);
+ else
+ H5S_select_all(chunk_info->fspace, TRUE);
+
+ /* Close the chunk's memory dataspace, if it's not shared */
+ if(!chunk_info->mspace_shared && chunk_info->mspace)
+ (void)H5S_close(chunk_info->mspace);
+
+ /* Free the actual chunk info */
+ chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5D__free_chunk_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__create_chunk_map_single
+ *
+ * Purpose: Create chunk selections when appending a single record
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 20, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t
+#ifndef H5_HAVE_PARALLEL
+ H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ *io_info)
+{
+ H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */
+ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk */
+ hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
+ hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(fm->f_ndims > 0);
+
+ /* Get coordinate for selection */
+ if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
+
+ /* Initialize the 'single chunk' file & memory chunk information */
+ chunk_info = fm->single_chunk_info;
+ chunk_info->chunk_points = 1;
+
+ /* Set chunk location & hyperslab size */
+ for(u = 0; u < fm->f_ndims; u++) {
+ HDassert(sel_start[u] == sel_end[u]);
+ chunk_info->scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u];
+ coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u];
+ } /* end for */
+ chunk_info->scaled[fm->f_ndims] = 0;
+
+ /* Calculate the index of this chunk */
+ chunk_info->index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, chunk_info->scaled);
+
+ /* Copy selection for file's dataspace into chunk dataspace */
+ if(H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file selection")
+
+ /* Move selection back to have correct offset in chunk */
+ if(H5S_SELECT_ADJUST_U(fm->single_space, coords) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection")
+
+#ifdef H5_HAVE_PARALLEL
+ /* store chunk selection information */
+ if(io_info->using_mpi_vfd)
+ fm->select_chunk[chunk_info->index] = chunk_info;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Set the file dataspace for the chunk to the shared 'single' dataspace */
+ chunk_info->fspace = fm->single_space;
+
+ /* Indicate that the chunk's file dataspace is shared */
+ chunk_info->fspace_shared = TRUE;
+
+ /* Just point at the memory dataspace & selection */
+ /* (Casting away const OK -QAK) */
+ chunk_info->mspace = (H5S_t *)fm->mem_space;
+
+ /* Indicate that the chunk's memory dataspace is shared */
+ chunk_info->mspace_shared = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__create_chunk_map_single() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__create_chunk_file_map_hyper
+ *
+ * Purpose: Create all chunk selections in file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 29, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t
+#ifndef H5_HAVE_PARALLEL
+ H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ *io_info)
+{
+ hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
+ hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
+ hsize_t sel_points; /* Number of elements in file selection */
+ hsize_t start_coords[H5O_LAYOUT_NDIMS]; /* Starting coordinates of selection */
+ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */
+ hsize_t end[H5O_LAYOUT_NDIMS]; /* Final coordinates of chunk */
+ hsize_t chunk_index; /* Index of chunk */
+ hsize_t start_scaled[H5S_MAX_RANK]; /* Starting scaled coordinates of selection */
+ hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
+ int curr_dim; /* Current dimension to increment */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(fm->f_ndims>0);
+
+ /* Get number of elements selected in file */
+ sel_points = fm->nelmts;
+
+ /* Get bounding box for selection (to reduce the number of chunks to iterate over) */
+ if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
+
+ /* Set initial chunk location & hyperslab size */
+ for(u = 0; u < fm->f_ndims; u++) {
+ scaled[u] = start_scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u];
+ coords[u] = start_coords[u] = scaled[u] * fm->layout->u.chunk.dim[u];
+ end[u] = (coords[u] + fm->chunk_dim[u]) - 1;
+ } /* end for */
+
+ /* Calculate the index of this chunk */
+ chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled);
+
+ /* Iterate through each chunk in the dataset */
+ while(sel_points) {
+ /* Check for intersection of temporary chunk and file selection */
+ /* (Casting away const OK - QAK) */
+ if(TRUE == H5S_hyper_intersect_block((H5S_t *)fm->file_space, coords, end)) {
+ H5S_t *tmp_fchunk; /* Temporary file dataspace */
+ H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */
+ hssize_t schunk_points; /* Number of elements in chunk selection */
+
+ /* Create "temporary" chunk for selection operations (copy file space) */
+ if(NULL == (tmp_fchunk = H5S_copy(fm->file_space, TRUE, FALSE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
+
+ /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */
+ if(H5S_hyper_convert(tmp_fchunk) < 0) {
+ (void)H5S_close(tmp_fchunk);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees")
+ } /* end if */
+
+ /* "AND" temporary chunk and current chunk */
+ if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL) < 0) {
+ (void)H5S_close(tmp_fchunk);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create chunk selection")
+ } /* end if */
+
+ /* Resize chunk's dataspace dimensions to size of chunk */
+ if(H5S_set_extent_real(tmp_fchunk,fm->chunk_dim) < 0) {
+ (void)H5S_close(tmp_fchunk);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions")
+ } /* end if */
+
+ /* Move selection back to have correct offset in chunk */
+ if(H5S_SELECT_ADJUST_U(tmp_fchunk, coords) < 0) {
+ (void)H5S_close(tmp_fchunk);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection")
+ } /* end if */
+
+ /* Add temporary chunk to the list of chunks */
+
+ /* Allocate the file & memory chunk information */
+ if (NULL==(new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) {
+ (void)H5S_close(tmp_fchunk);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
+ } /* end if */
+
+ /* Initialize the chunk information */
+
+ /* Set the chunk index */
+ new_chunk_info->index=chunk_index;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Store chunk selection information, for multi-chunk I/O */
+ if(io_info->using_mpi_vfd)
+ fm->select_chunk[chunk_index] = new_chunk_info;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Set the file chunk dataspace */
+ new_chunk_info->fspace = tmp_fchunk;
+ new_chunk_info->fspace_shared = FALSE;
+
+ /* Set the memory chunk dataspace */
+ new_chunk_info->mspace=NULL;
+ new_chunk_info->mspace_shared = FALSE;
+
+ /* Copy the chunk's scaled coordinates */
+ HDmemcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
+ new_chunk_info->scaled[fm->f_ndims] = 0;
+
+ /* Copy the chunk's scaled coordinates */
+ HDmemcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
+
+ /* Insert the new chunk into the skip list */
+ if(H5SL_insert(fm->sel_chunks, new_chunk_info, &new_chunk_info->index) < 0) {
+ H5D__free_chunk_info(new_chunk_info, NULL, NULL);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list")
+ } /* end if */
+
+ /* Get number of elements selected in chunk */
+ if((schunk_points = H5S_GET_SELECT_NPOINTS(tmp_fchunk)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection # of elements")
+ H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, schunk_points, hssize_t);
+
+ /* Decrement # of points left in file selection */
+ sel_points -= (hsize_t)schunk_points;
+
+ /* Leave if we are done */
+ if(sel_points == 0)
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Increment chunk index */
+ chunk_index++;
+
+ /* Set current increment dimension */
+ curr_dim=(int)fm->f_ndims-1;
+
+ /* Increment chunk location in fastest changing dimension */
+ H5_CHECK_OVERFLOW(fm->chunk_dim[curr_dim],hsize_t,hssize_t);
+ coords[curr_dim]+=fm->chunk_dim[curr_dim];
+ end[curr_dim]+=fm->chunk_dim[curr_dim];
+ scaled[curr_dim]++;
+
+ /* Bring chunk location back into bounds, if necessary */
+ if(coords[curr_dim] > sel_end[curr_dim]) {
+ do {
+ /* Reset current dimension's location to 0 */
+ scaled[curr_dim] = start_scaled[curr_dim];
+ coords[curr_dim] = start_coords[curr_dim]; /*lint !e771 The start_coords will always be initialized */
+ end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1;
+
+ /* Decrement current dimension */
+ curr_dim--;
+
+ /* Increment chunk location in current dimension */
+ scaled[curr_dim]++;
+ coords[curr_dim] += fm->chunk_dim[curr_dim];
+ end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1;
+ } while(coords[curr_dim] > sel_end[curr_dim]);
+
+ /* Re-calculate the index of this chunk */
+ chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled);
+ } /* end if */
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__create_chunk_file_map_hyper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__create_chunk_mem_map_hyper
+ *
+ * Purpose: Create all chunk selections in memory by copying the file
+ * chunk selections and adjusting their offsets to be correct
+ * for the memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 29, 2003
+ *
+ * Assumptions: That the file and memory selections are the same shape.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm)
+{
+ H5SL_node_t *curr_node; /* Current node in skip list */
+ hsize_t file_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
+ hsize_t file_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
+ hsize_t mem_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */
+ hsize_t mem_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */
+ hssize_t adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to all file chunks */
+ hssize_t chunk_adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to a particular chunk */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(fm->f_ndims>0);
+
+ /* Check for all I/O going to a single chunk */
+ if(H5SL_count(fm->sel_chunks)==1) {
+ H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */
+
+ /* Get the node */
+ curr_node=H5SL_first(fm->sel_chunks);
+
+ /* Get pointer to chunk's information */
+ chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
+ HDassert(chunk_info);
+
+ /* Just point at the memory dataspace & selection */
+ /* (Casting away const OK -QAK) */
+ chunk_info->mspace = (H5S_t *)fm->mem_space;
+
+ /* Indicate that the chunk's memory space is shared */
+ chunk_info->mspace_shared = TRUE;
+ } /* end if */
+ else {
+ /* Get bounding box for file selection */
+ if(H5S_SELECT_BOUNDS(fm->file_space, file_sel_start, file_sel_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
+
+ /* Get bounding box for memory selection */
+ if(H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info")
+
+ /* Calculate the adjustment for memory selection from file selection */
+ HDassert(fm->m_ndims==fm->f_ndims);
+ for(u=0; u<fm->f_ndims; u++) {
+ H5_CHECK_OVERFLOW(file_sel_start[u],hsize_t,hssize_t);
+ H5_CHECK_OVERFLOW(mem_sel_start[u],hsize_t,hssize_t);
+ adjust[u]=(hssize_t)file_sel_start[u]-(hssize_t)mem_sel_start[u];
+ } /* end for */
+
+ /* Iterate over each chunk in the chunk list */
+ curr_node=H5SL_first(fm->sel_chunks);
+ while(curr_node) {
+ H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */
+
+ /* Get pointer to chunk's information */
+ chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node);
+ HDassert(chunk_info);
+
+ /* Copy the information */
+
+ /* Copy the memory dataspace */
+ if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space")
+
+ /* Release the current selection */
+ if(H5S_SELECT_RELEASE(chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection")
+
+ /* Copy the file chunk's selection */
+ if(H5S_select_copy(chunk_info->mspace,chunk_info->fspace,FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection")
+
+ /* Compute the adjustment for this chunk */
+ for(u = 0; u < fm->f_ndims; u++) {
+ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */
+
+ /* Compute the chunk coordinates from the scaled coordinates */
+ coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u];
+
+ /* Compensate for the chunk offset */
+ H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t);
+ chunk_adjust[u] = adjust[u] - (hssize_t)coords[u]; /*lint !e771 The adjust array will always be initialized */
+ } /* end for */
+
+ /* Adjust the selection */
+ if(H5S_hyper_adjust_s(chunk_info->mspace,chunk_adjust) < 0) /*lint !e772 The chunk_adjust array will always be initialized */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection")
+
+ /* Get the next chunk node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__create_chunk_mem_map_hyper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_file_cb
+ *
+ * Purpose: Callback routine for file selection iterator. Used when
+ * creating selections in file for each point selected.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 23, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_udata)
+{
+ H5D_chunk_file_iter_ud_t *udata = (H5D_chunk_file_iter_ud_t *)_udata; /* User data for operation */
+ H5D_chunk_map_t *fm = udata->fm; /* File<->memory chunk mapping info */
+ H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */
+ hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */
+ hsize_t chunk_index; /* Chunk index */
+ hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Calculate the index of this chunk */
+ chunk_index = H5VM_chunk_index_scaled(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks, scaled);
+
+ /* Find correct chunk in file & memory skip list */
+ if(chunk_index==fm->last_index) {
+ /* If the chunk index is the same as the last chunk index we used,
+ * get the cached info to operate on.
+ */
+ chunk_info = fm->last_chunk_info;
+ } /* end if */
+ else {
+ /* If the chunk index is not the same as the last chunk index we used,
+ * find the chunk in the skip list.
+ */
+ /* Get the chunk node from the skip list */
+ if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) {
+ H5S_t *fspace; /* Memory chunk's dataspace */
+
+ /* Allocate the file & memory chunk information */
+ if (NULL==(chunk_info = H5FL_MALLOC (H5D_chunk_info_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info")
+
+ /* Initialize the chunk information */
+
+ /* Set the chunk index */
+ chunk_info->index=chunk_index;
+
+ /* Create a dataspace for the chunk */
+ if((fspace = H5S_create_simple(fm->f_ndims,fm->chunk_dim,NULL))==NULL) {
+ chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk")
+ } /* end if */
+
+ /* De-select the chunk space */
+ if(H5S_select_none(fspace) < 0) {
+ (void)H5S_close(fspace);
+ chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select dataspace")
+ } /* end if */
+
+ /* Set the file chunk dataspace */
+ chunk_info->fspace = fspace;
+ chunk_info->fspace_shared = FALSE;
+
+ /* Set the memory chunk dataspace */
+ chunk_info->mspace = NULL;
+ chunk_info->mspace_shared = FALSE;
+
+ /* Set the number of selected elements in chunk to zero */
+ chunk_info->chunk_points = 0;
+
+ /* Set the chunk's scaled coordinates */
+ HDmemcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
+ chunk_info->scaled[fm->f_ndims] = 0;
+ HDmemcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims);
+
+ /* Insert the new chunk into the skip list */
+ if(H5SL_insert(fm->sel_chunks,chunk_info,&chunk_info->index) < 0) {
+ H5D__free_chunk_info(chunk_info,NULL,NULL);
+ HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list")
+ } /* end if */
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Store chunk selection information, for collective multi-chunk I/O */
+ if(udata->io_info->using_mpi_vfd)
+ fm->select_chunk[chunk_index] = chunk_info;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Update the "last chunk seen" information */
+ fm->last_index = chunk_index;
+ fm->last_chunk_info = chunk_info;
+ } /* end else */
+
+ /* Get the offset of the element within the chunk */
+ for(u = 0; u < fm->f_ndims; u++)
+ coords_in_chunk[u] = coords[u] - (scaled[u] * fm->layout->u.chunk.dim[u]);
+
+ /* Add point to file selection for chunk */
+ if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element")
+
+ /* Increment the number of elemented selected in chunk */
+ chunk_info->chunk_points++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_file_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_mem_cb
+ *
+ * Purpose: Callback routine for file selection iterator. Used when
+ * creating selections in memory for each chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 10, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_fm)
+{
+ H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */
+ H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */
+ hsize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */
+ hsize_t chunk_index; /* Chunk index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Calculate the index of this chunk */
+ chunk_index = H5VM_chunk_index(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks);
+
+ /* Find correct chunk in file & memory skip list */
+ if(chunk_index == fm->last_index) {
+ /* If the chunk index is the same as the last chunk index we used,
+ * get the cached spaces to operate on.
+ */
+ chunk_info = fm->last_chunk_info;
+ } /* end if */
+ else {
+ /* If the chunk index is not the same as the last chunk index we used,
+ * find the chunk in the skip list.
+ */
+ /* Get the chunk node from the skip list */
+ if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't locate chunk in skip list")
+
+ /* Check if the chunk already has a memory space */
+ if(NULL == chunk_info->mspace) {
+ /* Copy the template memory chunk dataspace */
+ if(NULL == (chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space")
+ } /* end else */
+
+ /* Update the "last chunk seen" information */
+ fm->last_index = chunk_index;
+ fm->last_chunk_info = chunk_info;
+ } /* end else */
+
+ /* Get coordinates of selection iterator for memory */
+ if(H5S_SELECT_ITER_COORDS(&fm->mem_iter, coords_in_mem) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get iterator coordinates")
+
+ /* Add point to memory selection for chunk */
+ if(fm->msel_type == H5S_SEL_POINTS) {
+ if(H5S_select_elements(chunk_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element")
+ } /* end if */
+ else {
+ if(H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element")
+ } /* end else */
+
+ /* Move memory selection iterator to next element in selection */
+ if(H5S_SELECT_ITER_NEXT(&fm->mem_iter, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to move to next iterator location")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_mem_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cacheable
+ *
+ * Purpose: A small internal function to if it's possible to load the
+ * chunk into cache.
+ *
+ * Return: TRUE or FALSE
+ *
+ * Programmer: Raymond Lu
+ * 17 July 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_op)
+{
+ const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */
+ hbool_t has_filters = FALSE; /* Whether there are filters on the chunk or not */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(dataset);
+
+ /* Must bring the whole chunk in if there are any filters on the chunk.
+ * Make sure to check if filters are on the dataset but disabled for the
+ * chunk because it is a partial edge chunk. */
+ if(dataset->shared->dcpl_cache.pline.nused > 0) {
+ if(dataset->shared->layout.u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
+ has_filters = !H5D__chunk_is_partial_edge_chunk(
+ io_info->dset->shared->ndims,
+ io_info->dset->shared->layout.u.chunk.dim,
+ io_info->store->chunk.scaled,
+ io_info->dset->shared->curr_dims);
+ } /* end if */
+ else
+ has_filters = TRUE;
+ } /* end if */
+
+ if(has_filters)
+ ret_value = TRUE;
+ else {
+#ifdef H5_HAVE_PARALLEL
+ /* If MPI based VFD is used and the file is opened for write access, must
+ * bypass the chunk-cache scheme because other MPI processes could
+ * be writing to other elements in the same chunk. Do a direct
+ * write-through of only the elements requested.
+ */
+ if(io_info->using_mpi_vfd && (H5F_ACC_RDWR & H5F_INTENT(dataset->oloc.file)))
+ ret_value = FALSE;
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ /* If the chunk is too large to keep in the cache and if we don't
+ * need to write the fill value, then don't load the chunk into the
+ * cache, just write the data to it directly.
+ */
+ H5_CHECK_OVERFLOW(dataset->shared->layout.u.chunk.size, uint32_t, size_t);
+ if((size_t)dataset->shared->layout.u.chunk.size > dataset->shared->cache.chunk.nbytes_max) {
+ if(write_op && !H5F_addr_defined(caddr)) {
+ const H5O_fill_t *fill = &(dataset->shared->dcpl_cache.fill); /* Fill value info */
+ H5D_fill_value_t fill_status; /* Fill value status */
+
+ /* Revtrieve the fill value status */
+ if(H5P_is_fill_value_defined(fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* If the fill value needs to be written then we will need
+ * to use the cache to write the fill value */
+ if(fill->fill_time == H5D_FILL_TIME_ALLOC ||
+ (fill->fill_time == H5D_FILL_TIME_IFSET &&
+ (fill_status == H5D_FILL_VALUE_USER_DEFINED ||
+ fill_status == H5D_FILL_VALUE_DEFAULT)))
+ ret_value = TRUE;
+ else
+ ret_value = FALSE;
+ } else
+ ret_value = FALSE;
+ } else
+ ret_value = TRUE;
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_cacheable() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_read
+ *
+ * Purpose: Read from a chunked dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 10, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t *fm)
+{
+ H5SL_node_t *chunk_node; /* Current node in chunk skip list */
+ H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */
+ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
+ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
+ H5D_io_info_t cpt_io_info; /* Compact I/O info object */
+ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
+ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
+ uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */
+ hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.rbuf);
+ HDassert(type_info);
+ HDassert(fm);
+
+ /* Set up "nonexistent" I/O info object */
+ HDmemcpy(&nonexistent_io_info, io_info, sizeof(nonexistent_io_info));
+ nonexistent_io_info.layout_ops = *H5D_LOPS_NONEXISTENT;
+
+ /* Set up contiguous I/O info object */
+ HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
+ ctg_io_info.store = &ctg_store;
+ ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
+
+ /* Initialize temporary contiguous storage info */
+ H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, uint32_t);
+
+ /* Set up compact I/O info object */
+ HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
+ cpt_io_info.store = &cpt_store;
+ cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
+
+ /* Initialize temporary compact storage info */
+ cpt_store.compact.dirty = &cpt_dirty;
+
+ {
+ const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */
+ H5D_fill_value_t fill_status; /* Fill value status */
+
+ /* Check the fill value status */
+ if(H5P_is_fill_value_defined(fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* If we are never to return fill values, or if we would return them
+ * but they aren't set, set the flag to skip missing chunks.
+ */
+ if(fill->fill_time == H5D_FILL_TIME_NEVER ||
+ (fill->fill_time == H5D_FILL_TIME_IFSET &&
+ fill_status != H5D_FILL_VALUE_USER_DEFINED &&
+ fill_status != H5D_FILL_VALUE_DEFAULT))
+ skip_missing_chunks = TRUE;
+ }
+
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while(chunk_node) {
+ H5D_chunk_info_t *chunk_info; /* Chunk information */
+ H5D_chunk_ud_t udata; /* Chunk index pass-through */
+
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+
+ /* Get the info for the chunk in the file */
+ if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Check for non-existant chunk & skip it if appropriate */
+ if(H5F_addr_defined(udata.chunk_block.offset) || UINT_MAX != udata.idx_hint
+ || !skip_missing_chunks) {
+ H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */
+ void *chunk = NULL; /* Pointer to locked chunk buffer */
+ htri_t cacheable; /* Whether the chunk is cacheable */
+
+ /* Set chunk's [scaled] coordinates */
+ io_info->store->chunk.scaled = chunk_info->scaled;
+
+ /* Determine if we should use the chunk cache */
+ if((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
+ if(cacheable) {
+ /* Load the chunk into cache and lock it. */
+
+ /* Compute # of bytes accessed in chunk */
+ H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
+ src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size;
+
+ /* Lock the chunk into the cache */
+ if(NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE)))
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+
+ /* Set up the storage buffer information for this chunk */
+ cpt_store.compact.buf = chunk;
+
+ /* Point I/O info at contiguous I/O info for this chunk */
+ chk_io_info = &cpt_io_info;
+ } /* end if */
+ else if(H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Set up the storage address information for this chunk */
+ ctg_store.contig.dset_addr = udata.chunk_block.offset;
+
+ /* Point I/O info at temporary I/O info for this chunk */
+ chk_io_info = &ctg_io_info;
+ } /* end else if */
+ else {
+ /* Point I/O info at "nonexistent" I/O info for this chunk */
+ chk_io_info = &nonexistent_io_info;
+ } /* end else */
+
+ /* Perform the actual read operation */
+ if((io_info->io_ops.single_read)(chk_io_info, type_info,
+ (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed")
+
+ /* Release the cache lock on the chunk. */
+ if(chunk && H5D__chunk_unlock(io_info, &udata, FALSE, chunk, src_accessed_bytes) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_write
+ *
+ * Purpose: Writes to a chunked dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 10, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t *fm)
+{
+ H5SL_node_t *chunk_node; /* Current node in chunk skip list */
+ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
+ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
+ H5D_io_info_t cpt_io_info; /* Compact I/O info object */
+ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
+ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
+ uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.wbuf);
+ HDassert(type_info);
+ HDassert(fm);
+
+ /* Set up contiguous I/O info object */
+ HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
+ ctg_io_info.store = &ctg_store;
+ ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
+
+ /* Initialize temporary contiguous storage info */
+ H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, uint32_t);
+
+ /* Set up compact I/O info object */
+ HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
+ cpt_io_info.store = &cpt_store;
+ cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
+
+ /* Initialize temporary compact storage info */
+ cpt_store.compact.dirty = &cpt_dirty;
+
+ /* Iterate through nodes in chunk skip list */
+ chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm);
+ while(chunk_node) {
+ H5D_chunk_info_t *chunk_info; /* Chunk information */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_io_info_t *chk_io_info; /* Pointer to I/O info object for this chunk */
+ void *chunk; /* Pointer to locked chunk buffer */
+ H5D_chunk_ud_t udata; /* Index pass-through */
+ htri_t cacheable; /* Whether the chunk is cacheable */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+
+ /* Get the actual chunk information from the skip list node */
+ chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node);
+
+ /* Look up the chunk */
+ if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* Sanity check */
+ HDassert((H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length > 0) ||
+ (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0));
+
+ /* Set chunk's [scaled] coordinates */
+ io_info->store->chunk.scaled = chunk_info->scaled;
+
+ /* Determine if we should use the chunk cache */
+ if((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable")
+ if(cacheable) {
+ /* Load the chunk into cache. But if the whole chunk is written,
+ * simply allocate space instead of load the chunk. */
+ hbool_t entire_chunk = TRUE; /* Whether whole chunk is selected */
+
+ /* Compute # of bytes accessed in chunk */
+ H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t);
+ dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size;
+
+ /* Determine if we will access all the data in the chunk */
+ if(dst_accessed_bytes != ctg_store.contig.dset_size ||
+ (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size ||
+ fm->fsel_type == H5S_SEL_POINTS)
+ entire_chunk = FALSE;
+
+ /* Lock the chunk into the cache */
+ if(NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE)))
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk")
+
+ /* Set up the storage buffer information for this chunk */
+ cpt_store.compact.buf = chunk;
+
+ /* Point I/O info at main I/O info for this chunk */
+ chk_io_info = &cpt_io_info;
+ } /* end if */
+ else {
+ /* If the chunk hasn't been allocated on disk, do so now. */
+ if(!H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Compose chunked index info struct */
+ idx_info.f = io_info->dset->oloc.file;
+ idx_info.dxpl_id = io_info->md_dxpl_id;
+ idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline);
+ idx_info.layout = &(io_info->dset->shared->layout.u.chunk);
+ idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk);
+
+ /* Set up the size of chunk for user data */
+ udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size;
+
+ /* Allocate the chunk */
+ if(H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, chunk_info->scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
+
+ /* Make sure the address of the chunk is returned. */
+ if(!H5F_addr_defined(udata.chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined")
+
+ /* Cache the new chunk information */
+ H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata);
+ } /* end if */
+
+ /* Set up the storage address information for this chunk */
+ ctg_store.contig.dset_addr = udata.chunk_block.offset;
+
+ /* No chunk cached */
+ chunk = NULL;
+
+ /* Point I/O info at temporary I/O info for this chunk */
+ chk_io_info = &ctg_io_info;
+ } /* end else */
+
+ /* Perform the actual write operation */
+ if((io_info->io_ops.single_write)(chk_io_info, type_info,
+ (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed")
+
+ /* Release the cache lock on the chunk, or insert chunk into index. */
+ if(chunk) {
+ if(H5D__chunk_unlock(io_info, &udata, TRUE, chunk, dst_accessed_bytes) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+ else {
+ if(need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert)
+ if((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
+ } /* end else */
+
+ /* Advance to next chunk in list */
+ chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node);
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_flush
+ *
+ * Purpose: Writes all dirty chunks to disk and optionally preempts them
+ * from the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_flush(H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
+ H5D_rdcc_ent_t *ent, *next;
+ unsigned nerrors = 0; /* Count of any errors encountered when flushing chunks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Loop over all entries in the chunk cache */
+ for(ent = rdcc->head; ent; ent = next) {
+ next = ent->next;
+ if(H5D__chunk_flush_entry(dset, dxpl_id, dxpl_cache, ent, FALSE) < 0)
+ nerrors++;
+ } /* end for */
+ if(nerrors)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_io_term
+ *
+ * Purpose: Destroy I/O operation information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 17, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_io_term(const H5D_chunk_map_t *fm)
+{
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Single element I/O vs. multiple element I/O cleanup */
+ if(fm->use_single) {
+ /* Sanity checks */
+ HDassert(fm->sel_chunks == NULL);
+ HDassert(fm->single_chunk_info);
+ HDassert(fm->single_chunk_info->fspace_shared);
+ HDassert(fm->single_chunk_info->mspace_shared);
+
+ /* Reset the selection for the single element I/O */
+ H5S_select_all(fm->single_space, TRUE);
+ } /* end if */
+ else {
+ /* Release the nodes on the list of selected chunks */
+ if(fm->sel_chunks)
+ if(H5SL_free(fm->sel_chunks, H5D__free_chunk_info, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTNEXT, FAIL, "can't iterate over chunks")
+ } /* end else */
+
+ /* Free the memory chunk dataspace template */
+ if(fm->mchunk_tmpl)
+ if(H5S_close(fm->mchunk_tmpl) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template")
+#ifdef H5_HAVE_PARALLEL
+ if(fm->select_chunk)
+ H5MM_xfree(fm->select_chunk);
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_io_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_dest
+ *
+ * Purpose: Destroy the entire chunk cache by flushing dirty entries,
+ * preempting all entries, and freeing the cache itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_dest(H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /* Dataset's chunk cache */
+ H5D_rdcc_ent_t *ent = NULL, *next = NULL; /* Pointer to current & next cache entries */
+ int nerrors = 0; /* Accumulated count of errors */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ /* Sanity checks */
+ HDassert(dset);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ nerrors++;
+
+ /* Flush all the cached chunks */
+ for(ent = rdcc->head; ent; ent = next) {
+ next = ent->next;
+ if(H5D__chunk_cache_evict(dset, dxpl_id, dxpl_cache, ent, TRUE) < 0)
+ nerrors++;
+ } /* end for */
+
+ /* Continue even if there are failures. */
+ if(nerrors)
+ HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
+
+ /* Release cache structures */
+ if(rdcc->slot)
+ rdcc->slot = H5FL_SEQ_FREE(H5D_rdcc_ent_ptr_t, rdcc->slot);
+ HDmemset(rdcc, 0, sizeof(H5D_rdcc_t));
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Free any index structures */
+ if(dset->shared->layout.storage.u.chunk.ops->dest &&
+ (dset->shared->layout.storage.u.chunk.ops->dest)(&idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__chunk_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_chunk_idx_reset
+ *
+ * Purpose: Reset index information
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_chunk_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(storage);
+ HDassert(storage->ops);
+ H5D_CHUNK_STORAGE_INDEX_CHK(storage);
+
+ /* Reset index structures */
+ if((storage->ops->reset)(storage, reset_addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset chunk index info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_chunk_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cinfo_cache_reset
+ *
+ * Purpose: Reset the cached chunk info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 27, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_cinfo_cache_reset(H5D_chunk_cached_t *last)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDassert(last);
+
+ /* Indicate that the cached info is not valid */
+ last->valid = FALSE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__chunk_cinfo_cache_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cinfo_cache_update
+ *
+ * Purpose: Update the cached chunk info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 27, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(last);
+ HDassert(udata);
+ HDassert(udata->common.layout);
+ HDassert(udata->common.scaled);
+
+ /* Stored the information to cache */
+ HDmemcpy(last->scaled, udata->common.scaled, sizeof(hsize_t) * udata->common.layout->ndims);
+ last->addr = udata->chunk_block.offset;
+ H5_CHECKED_ASSIGN(last->nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ last->chunk_idx = udata->chunk_idx;
+ last->filter_mask = udata->filter_mask;
+
+ /* Indicate that the cached info is valid */
+ last->valid = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__chunk_cinfo_cache_update() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cinfo_cache_found
+ *
+ * Purpose: Look for chunk info in cache
+ *
+ * Return: TRUE/FALSE/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 27, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(last);
+ HDassert(udata);
+ HDassert(udata->common.layout);
+ HDassert(udata->common.scaled);
+
+ /* Check if the cached information is what is desired */
+ if(last->valid) {
+ unsigned u; /* Local index variable */
+
+ /* Check that the scaled offset is the same */
+ for(u = 0; u < udata->common.layout->ndims; u++)
+ if(last->scaled[u] != udata->common.scaled[u])
+ HGOTO_DONE(FALSE)
+
+ /* Retrieve the information from the cache */
+ udata->chunk_block.offset = last->addr;
+ udata->chunk_block.length = last->nbytes;
+ udata->chunk_idx = last->chunk_idx;
+ udata->filter_mask = last->filter_mask;
+
+ /* Indicate that the data was found */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_cinfo_cache_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_create
+ *
+ * Purpose: Creates a new chunked storage index and initializes the
+ * layout information with information about the storage. The
+ * layout info should be immediately written to the object header.
+ *
+ * Return: Non-negative on success (with the layout information initialized
+ * and ready to write to an object header). Negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_create(const H5D_t *dset /*in,out*/, hid_t dxpl_id)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dset);
+ HDassert(H5D_CHUNKED == dset->shared->layout.type);
+ HDassert(dset->shared->layout.u.chunk.ndims > 0 && dset->shared->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+#ifndef NDEBUG
+{
+ unsigned u; /* Local index variable */
+
+ for(u = 0; u < dset->shared->layout.u.chunk.ndims; u++)
+ HDassert(dset->shared->layout.u.chunk.dim[u] > 0);
+}
+#endif
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Create the index for the chunks */
+ if((dset->shared->layout.storage.u.chunk.ops->create)(&idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create chunk index")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_hash_val
+ *
+ * Purpose: To calculate an index based on the dataset's scaled coordinates and
+ * sizes of the faster dimensions.
+ *
+ * Return: Hash value index
+ *
+ * Programmer: Vailin Choi; Nov 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static unsigned
+H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled)
+{
+ hsize_t val; /* Intermediate value */
+ unsigned ndims = shared->ndims; /* Rank of dataset */
+ unsigned ret = 0; /* Value to return */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(shared);
+ HDassert(scaled);
+
+ /* If the fastest changing dimension doesn't have enough entropy, use
+ * other dimensions too
+ */
+ if(ndims > 1 && shared->cache.chunk.scaled_dims[ndims - 1] <= shared->cache.chunk.nslots) {
+ unsigned u; /* Local index variable */
+
+ val = scaled[0];
+ for(u = 1; u < ndims; u++) {
+ val <<= shared->cache.chunk.scaled_encode_bits[u];
+ val ^= scaled[u];
+ } /* end for */
+ } /* end if */
+ else
+ val = scaled[ndims - 1];
+
+ /* Modulo value against the number of array slots */
+ ret = (unsigned)(val % shared->cache.chunk.nslots);
+
+ FUNC_LEAVE_NOAPI(ret)
+} /* H5D__chunk_hash_val() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_lookup
+ *
+ * Purpose: Loops up a chunk in cache and on disk, and retrieves
+ * information about that chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Albert Cheng
+ * June 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_lookup(const H5D_t *dset, hid_t dxpl_id, const hsize_t *scaled,
+ H5D_chunk_ud_t *udata)
+{
+ H5D_rdcc_ent_t *ent = NULL; /* Cache entry */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ unsigned idx; /* Index of chunk in cache, if present */
+ hbool_t found = FALSE; /* In cache? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(dset);
+ HDassert(dset->shared->layout.u.chunk.ndims > 0);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(scaled);
+ HDassert(udata);
+
+ /* Initialize the query information about the chunk we are looking for */
+ udata->common.layout = &(dset->shared->layout.u.chunk);
+ udata->common.storage = &(dset->shared->layout.storage.u.chunk);
+ udata->common.scaled = scaled;
+
+ /* Reset information about the chunk we are looking for */
+ udata->chunk_block.offset = HADDR_UNDEF;
+ udata->chunk_block.length = 0;
+ udata->filter_mask = 0;
+ udata->new_unfilt_chunk = FALSE;
+
+ /* Check for chunk in cache */
+ if(dset->shared->cache.chunk.nslots > 0) {
+ /* Determine the chunk's location in the hash table */
+ idx = H5D__chunk_hash_val(dset->shared, scaled);
+
+ /* Get the chunk cache entry for that location */
+ ent = dset->shared->cache.chunk.slot[idx];
+ if(ent) {
+ unsigned u; /* Counter */
+
+ /* Speculatively set the 'found' flag */
+ found = TRUE;
+
+ /* Verify that the cache entry is the correct chunk */
+ for(u = 0; u < dset->shared->ndims; u++)
+ if(scaled[u] != ent->scaled[u]) {
+ found = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Retrieve chunk addr */
+ if(found) {
+ udata->idx_hint = idx;
+ udata->chunk_block.offset = ent->chunk_block.offset;
+ udata->chunk_block.length = ent->chunk_block.length;;
+ udata->chunk_idx = ent->chunk_idx;
+ } /* end if */
+ else {
+ /* Invalidate idx_hint, to signal that the chunk is not in cache */
+ udata->idx_hint = UINT_MAX;
+
+ /* Check for cached information */
+ if(!H5D__chunk_cinfo_cache_found(&dset->shared->cache.chunk.last, udata)) {
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+#ifdef H5_HAVE_PARALLEL
+ H5P_coll_md_read_flag_t temp_cmr; /* Temp value to hold the coll metadata read setting */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(idx_info.f, H5FD_FEAT_HAS_MPI)) {
+ /* disable collective metadata read for chunk indexes
+ as it is highly unlikely that users would read the
+ same chunks from all processes. MSC - might turn on
+ for root node? */
+ temp_cmr = H5F_COLL_MD_READ(idx_info.f);
+ H5F_set_coll_md_read(idx_info.f, H5P_FORCE_FALSE);
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Go get the chunk information */
+ if((dset->shared->layout.storage.u.chunk.ops->get_addr)(&idx_info, udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address")
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(idx_info.f, H5FD_FEAT_HAS_MPI))
+ H5F_set_coll_md_read(idx_info.f, temp_cmr);
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Cache the information retrieved */
+ H5D__chunk_cinfo_cache_update(&dset->shared->cache.chunk.last, udata);
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_flush_entry
+ *
+ * Purpose: Writes a chunk to disk. If RESET is non-zero then the
+ * entry is cleared -- it's slightly faster to flush a chunk if
+ * the RESET flag is turned on because it results in one fewer
+ * memory copy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_flush_entry(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache,
+ H5D_rdcc_ent_t *ent, hbool_t reset)
+{
+ void *buf = NULL; /* Temporary buffer */
+ hbool_t point_of_no_return = FALSE;
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ HDassert(dset);
+ HDassert(dset->shared);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(dxpl_cache);
+ HDassert(ent);
+ HDassert(!ent->locked);
+
+ buf = ent->chunk;
+ if(ent->dirty) {
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_chunk_ud_t udata; /* pass through B-tree */
+ hbool_t must_alloc = FALSE; /* Whether the chunk must be allocated */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+
+ /* Set up user data for index callbacks */
+ udata.common.layout = &dset->shared->layout.u.chunk;
+ udata.common.storage = &dset->shared->layout.storage.u.chunk;
+ udata.common.scaled = ent->scaled;
+ udata.chunk_block.offset = ent->chunk_block.offset;
+ udata.chunk_block.length = dset->shared->layout.u.chunk.size;
+ udata.filter_mask = 0;
+ udata.chunk_idx = ent->chunk_idx;
+
+ /* Should the chunk be filtered before writing it to disk? */
+ if(dset->shared->dcpl_cache.pline.nused
+ && !(ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS)) {
+ size_t alloc = udata.chunk_block.length; /* Bytes allocated for BUF */
+ size_t nbytes; /* Chunk size (in bytes) */
+
+ if(!reset) {
+ /*
+ * Copy the chunk to a new buffer before running it through
+ * the pipeline because we'll want to save the original buffer
+ * for later.
+ */
+ if(NULL == (buf = H5MM_malloc(alloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline")
+ HDmemcpy(buf, ent->chunk, alloc);
+ } /* end if */
+ else {
+ /*
+ * If we are reseting and something goes wrong after this
+ * point then it's too late to recover because we may have
+ * destroyed the original data by calling H5Z_pipeline().
+ * The only safe option is to continue with the reset
+ * even if we can't write the data to disk.
+ */
+ point_of_no_return = TRUE;
+ ent->chunk = NULL;
+ } /* end else */
+ H5_CHECKED_ASSIGN(nbytes, size_t, udata.chunk_block.length, hsize_t);
+ if(H5Z_pipeline(&(dset->shared->dcpl_cache.pline), 0, &(udata.filter_mask), dxpl_cache->err_detect,
+ dxpl_cache->filter_cb, &nbytes, &alloc, &buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "output pipeline failed")
+#if H5_SIZEOF_SIZE_T > 4
+ /* Check for the chunk expanding too much to encode in a 32-bit value */
+ if(nbytes > ((size_t)0xffffffff))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
+#endif /* H5_SIZEOF_SIZE_T > 4 */
+ H5_CHECKED_ASSIGN(udata.chunk_block.length, hsize_t, nbytes, size_t);
+
+ /* Indicate that the chunk must be allocated */
+ must_alloc = TRUE;
+ } /* end if */
+ else if(!H5F_addr_defined(udata.chunk_block.offset)) {
+ /* Indicate that the chunk must be allocated */
+ must_alloc = TRUE;
+
+ /* This flag could be set for this chunk, just remove and ignore it
+ */
+ ent->edge_chunk_state &= ~H5D_RDCC_NEWLY_DISABLED_FILTERS;
+ } /* end else */
+ else if(ent->edge_chunk_state & H5D_RDCC_NEWLY_DISABLED_FILTERS) {
+ /* Chunk on disk is still filtered, must insert to allocate correct
+ * size */
+ must_alloc = TRUE;
+
+ /* Set the disable filters field back to the standard disable
+ * filters setting, as it no longer needs to be inserted with every
+ * flush */
+ ent->edge_chunk_state &= ~H5D_RDCC_NEWLY_DISABLED_FILTERS;
+ } /* end else */
+
+ HDassert(!(ent->edge_chunk_state & H5D_RDCC_NEWLY_DISABLED_FILTERS));
+
+ /* Check if the chunk needs to be allocated (it also could exist already
+ * and the chunk alloc operation could resize it)
+ */
+ if(must_alloc) {
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Create the chunk it if it doesn't exist, or reallocate the chunk
+ * if its size changed.
+ */
+ if(H5D__chunk_file_alloc(&idx_info, &(ent->chunk_block), &udata.chunk_block, &need_insert, ent->scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
+
+ /* Update the chunk entry's info, in case it was allocated or relocated */
+ ent->chunk_block.offset = udata.chunk_block.offset;
+ ent->chunk_block.length = udata.chunk_block.length;
+ } /* end if */
+
+ /* Write the data to the file */
+ HDassert(H5F_addr_defined(udata.chunk_block.offset));
+ H5_CHECK_OVERFLOW(udata.chunk_block.length, hsize_t, size_t);
+ if(H5F_block_write(dset->oloc.file, H5FD_MEM_DRAW, udata.chunk_block.offset, (size_t)udata.chunk_block.length, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
+
+ /* Insert the chunk record into the index */
+ if(need_insert && dset->shared->layout.storage.u.chunk.ops->insert)
+ if((dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
+
+ /* Cache the chunk's info, in case it's accessed again shortly */
+ H5D__chunk_cinfo_cache_update(&dset->shared->cache.chunk.last, &udata);
+
+ /* Mark cache entry as clean */
+ ent->dirty = FALSE;
+
+ /* Increment # of flushed entries */
+ dset->shared->cache.chunk.stats.nflushes++;
+ } /* end if */
+
+ /* Reset, but do not free or removed from list */
+ if(reset) {
+ point_of_no_return = FALSE;
+ if(buf == ent->chunk)
+ buf = NULL;
+ if(ent->chunk != NULL)
+ ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
+ ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS) ? NULL
+ : &(dset->shared->dcpl_cache.pline)));
+ } /* end if */
+
+done:
+ /* Free the temp buffer only if it's different than the entry chunk */
+ if(buf != ent->chunk)
+ H5MM_xfree(buf);
+
+ /*
+ * If we reached the point of no return then we have no choice but to
+ * reset the entry. This can only happen if RESET is true but the
+ * output pipeline failed. Do not free the entry or remove it from the
+ * list.
+ */
+ if(ret_value < 0 && point_of_no_return)
+ if(ent->chunk)
+ ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
+ ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS) ? NULL
+ : &(dset->shared->dcpl_cache.pline)));
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__chunk_flush_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cache_evict
+ *
+ * Purpose: Preempts the specified entry from the cache, flushing it to
+ * disk if necessary.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_cache_evict(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache,
+ H5D_rdcc_ent_t *ent, hbool_t flush)
+{
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(dset);
+ HDassert(dxpl_cache);
+ HDassert(ent);
+ HDassert(!ent->locked);
+ HDassert(ent->idx < rdcc->nslots);
+
+ if(flush) {
+ /* Flush */
+ if(H5D__chunk_flush_entry(dset, dxpl_id, dxpl_cache, ent, TRUE) < 0)
+ HDONE_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
+ } /* end if */
+ else {
+ /* Don't flush, just free chunk */
+ if(ent->chunk != NULL)
+ ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk,
+ ((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS) ? NULL
+ : &(dset->shared->dcpl_cache.pline)));
+ } /* end else */
+
+ /* Unlink from list */
+ if(ent->prev)
+ ent->prev->next = ent->next;
+ else
+ rdcc->head = ent->next;
+ if(ent->next)
+ ent->next->prev = ent->prev;
+ else
+ rdcc->tail = ent->prev;
+ ent->prev = ent->next = NULL;
+
+ /* Unlink from temporary list */
+ if(ent->tmp_prev) {
+ HDassert(rdcc->tmp_head->tmp_next);
+ ent->tmp_prev->tmp_next = ent->tmp_next;
+ if(ent->tmp_next) {
+ ent->tmp_next->tmp_prev = ent->tmp_prev;
+ ent->tmp_next = NULL;
+ } /* end if */
+ ent->tmp_prev = NULL;
+ } /* end if */
+ else
+ /* Only clear hash table slot if the chunk was not on the temporary list
+ */
+ rdcc->slot[ent->idx] = NULL;
+
+ /* Remove from cache */
+ HDassert(rdcc->slot[ent->idx] != ent);
+ ent->idx = UINT_MAX;
+ rdcc->nbytes_used -= dset->shared->layout.u.chunk.size;
+ --rdcc->nused;
+
+ /* Free */
+ ent = H5FL_FREE(H5D_rdcc_ent_t, ent);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_cache_evict() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_cache_prune
+ *
+ * Purpose: Prune the cache by preempting some things until the cache has
+ * room for something which is SIZE bytes. Only unlocked
+ * entries are considered for preemption.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_cache_prune(const H5D_t *dset, hid_t dxpl_id,
+ const H5D_dxpl_cache_t *dxpl_cache, size_t size)
+{
+ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
+ size_t total = rdcc->nbytes_max;
+ const int nmeth = 2; /*number of methods */
+ int w[1]; /*weighting as an interval */
+ H5D_rdcc_ent_t *p[2], *cur; /*list pointers */
+ H5D_rdcc_ent_t *n[2]; /*list next pointers */
+ int nerrors = 0; /* Accumulated error count during preemptions */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Preemption is accomplished by having multiple pointers (currently two)
+ * slide down the list beginning at the head. Pointer p(N+1) will start
+ * traversing the list when pointer pN reaches wN percent of the original
+ * list. In other words, preemption method N gets to consider entries in
+ * approximate least recently used order w0 percent before method N+1
+ * where 100% means tha method N will run to completion before method N+1
+ * begins. The pointers participating in the list traversal are each
+ * given a chance at preemption before any of the pointers are advanced.
+ */
+ w[0] = (int)(rdcc->nused * rdcc->w0);
+ p[0] = rdcc->head;
+ p[1] = NULL;
+
+ while((p[0] || p[1]) && (rdcc->nbytes_used + size) > total) {
+ int i; /* Local index variable */
+
+ /* Introduce new pointers */
+ for(i = 0; i < nmeth - 1; i++)
+ if(0 == w[i])
+ p[i + 1] = rdcc->head;
+
+ /* Compute next value for each pointer */
+ for(i = 0; i < nmeth; i++)
+ n[i] = p[i] ? p[i]->next : NULL;
+
+ /* Give each method a chance */
+ for(i = 0; i < nmeth && (rdcc->nbytes_used + size) > total; i++) {
+ if(0 == i && p[0] && !p[0]->locked &&
+ ((0 == p[0]->rd_count && 0 == p[0]->wr_count) ||
+ (0 == p[0]->rd_count && dset->shared->layout.u.chunk.size == p[0]->wr_count) ||
+ (dset->shared->layout.u.chunk.size == p[0]->rd_count && 0 == p[0]->wr_count))) {
+ /*
+ * Method 0: Preempt entries that have been completely written
+ * and/or completely read but not entries that are partially
+ * written or partially read.
+ */
+ cur = p[0];
+ } else if(1 == i && p[1] && !p[1]->locked) {
+ /*
+ * Method 1: Preempt the entry without regard to
+ * considerations other than being locked. This is the last
+ * resort preemption.
+ */
+ cur = p[1];
+ } else {
+ /* Nothing to preempt at this point */
+ cur = NULL;
+ }
+
+ if(cur) {
+ int j; /* Local index variable */
+
+ for(j = 0; j < nmeth; j++) {
+ if(p[j] == cur)
+ p[j] = NULL;
+ if(n[j] == cur)
+ n[j] = cur->next;
+ } /* end for */
+ if(H5D__chunk_cache_evict(dset, dxpl_id, dxpl_cache, cur, TRUE) < 0)
+ nerrors++;
+ } /* end if */
+ } /* end for */
+
+ /* Advance pointers */
+ for(i = 0; i < nmeth; i++)
+ p[i] = n[i];
+ for(i = 0; i < nmeth - 1; i++)
+ w[i] -= 1;
+ } /* end while */
+
+ if(nerrors)
+ HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to preempt one or more raw data cache entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_cache_prune() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_lock
+ *
+ * Purpose: Return a pointer to a dataset chunk. The pointer points
+ * directly into the chunk cache and should not be freed
+ * by the caller but will be valid until it is unlocked. The
+ * input value IDX_HINT is used to speed up cache lookups and
+ * it's output value should be given to H5D__chunk_unlock().
+ * IDX_HINT is ignored if it is out of range, and if it points
+ * to the wrong entry then we fall back to the normal search
+ * method.
+ *
+ * If RELAX is non-zero and the chunk isn't in the cache then
+ * don't try to read it from the file, but just allocate an
+ * uninitialized buffer to hold the result. This is intended
+ * for output functions that are about to overwrite the entire
+ * chunk.
+ *
+ * Return: Success: Ptr to a file chunk.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata,
+ hbool_t relax, hbool_t prev_unfilt_chunk)
+{
+ const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */
+ const H5O_pline_t *pline = &(dset->shared->dcpl_cache.pline); /* I/O pipeline info - always equal to the pline passed to H5D__chunk_mem_alloc */
+ const H5O_pline_t *old_pline = pline; /* Old pipeline, i.e. pipeline used to read the chunk */
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
+ const H5O_fill_t *fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache*/
+ H5D_rdcc_ent_t *ent; /*cache entry */
+ size_t chunk_size; /*size of a chunk */
+ hbool_t disable_filters = FALSE; /* Whether to disable filters (when adding to cache) */
+ void *chunk = NULL; /*the file chunk */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(io_info);
+ HDassert(io_info->dxpl_cache);
+ HDassert(io_info->store);
+ HDassert(udata);
+ HDassert(dset);
+ HDassert(TRUE == H5P_isa_class(io_info->md_dxpl_id, H5P_DATASET_XFER));
+ HDassert(TRUE == H5P_isa_class(io_info->raw_dxpl_id, H5P_DATASET_XFER));
+ HDassert(!(udata->new_unfilt_chunk && prev_unfilt_chunk));
+ HDassert(!rdcc->tmp_head);
+
+ /* Get the chunk's size */
+ HDassert(layout->u.chunk.size > 0);
+ H5_CHECKED_ASSIGN(chunk_size, size_t, layout->u.chunk.size, uint32_t);
+
+ /* Check if the chunk is in the cache */
+ if(UINT_MAX != udata->idx_hint) {
+ /* Sanity check */
+ HDassert(udata->idx_hint < rdcc->nslots);
+ HDassert(rdcc->slot[udata->idx_hint]);
+
+ /* Get the entry */
+ ent = rdcc->slot[udata->idx_hint];
+
+#ifndef NDEBUG
+{
+ unsigned u; /*counters */
+
+ /* Make sure this is the right chunk */
+ for(u = 0; u < layout->u.chunk.ndims - 1; u++)
+ HDassert(io_info->store->chunk.scaled[u] == ent->scaled[u]);
+}
+#endif /* NDEBUG */
+
+ /*
+ * Already in the cache. Count a hit.
+ */
+ rdcc->stats.nhits++;
+
+ /* Make adjustments if the edge chunk status changed recently */
+ if(pline->nused) {
+ /* If the chunk recently became an unfiltered partial edge chunk
+ * while in cache, we must make some changes to the entry */
+ if(udata->new_unfilt_chunk) {
+ /* If this flag is set then partial chunk filters must be
+ * disabled, and the chunk must not have previously been a
+ * partial chunk (with disabled filters) */
+ HDassert(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+ HDassert(!(ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS));
+ HDassert(old_pline->nused);
+
+ /* Disable filters. Set pline to NULL instead of just the
+ * default pipeline to make a quick failure more likely if the
+ * code is changed in an inappropriate/incomplete way. */
+ pline = NULL;
+
+ /* Reallocate the chunk so H5D__chunk_mem_xfree doesn't get confused
+ */
+ if(NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+ HDmemcpy(chunk, ent->chunk, chunk_size);
+ ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline);
+ ent->chunk = (uint8_t *)chunk;
+ chunk = NULL;
+
+ /* Mark the chunk as having filters disabled as well as "newly
+ * disabled" so it is inserted on flush */
+ ent->edge_chunk_state |= H5D_RDCC_DISABLE_FILTERS;
+ ent->edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
+ } /* end if */
+ else if(prev_unfilt_chunk) {
+ /* If this flag is set then partial chunk filters must be
+ * disabled, and the chunk must have previously been a partial
+ * chunk (with disabled filters) */
+ HDassert(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+ HDassert((ent->edge_chunk_state & H5D_RDCC_DISABLE_FILTERS));
+ HDassert(pline->nused);
+
+ /* Mark the old pipeline as having been disabled */
+ old_pline = NULL;
+
+ /* Reallocate the chunk so H5D__chunk_mem_xfree doesn't get confused
+ */
+ if(NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+ HDmemcpy(chunk, ent->chunk, chunk_size);
+
+ ent->chunk = (uint8_t *)H5D__chunk_mem_xfree(ent->chunk, old_pline);
+ ent->chunk = (uint8_t *)chunk;
+ chunk = NULL;
+
+ /* Mark the chunk as having filters enabled */
+ ent->edge_chunk_state &= ~(H5D_RDCC_DISABLE_FILTERS
+ | H5D_RDCC_NEWLY_DISABLED_FILTERS);
+ } /* end else */
+ } /* end if */
+
+ /*
+ * If the chunk is not at the beginning of the cache; move it backward
+ * by one slot. This is how we implement the LRU preemption
+ * algorithm.
+ */
+ if(ent->next) {
+ if(ent->next->next)
+ ent->next->next->prev = ent;
+ else
+ rdcc->tail = ent;
+ ent->next->prev = ent->prev;
+ if(ent->prev)
+ ent->prev->next = ent->next;
+ else
+ rdcc->head = ent->next;
+ ent->prev = ent->next;
+ ent->next = ent->next->next;
+ ent->prev->next = ent;
+ } /* end if */
+ } /* end if */
+ else {
+ haddr_t chunk_addr; /* Address of chunk on disk */
+ hsize_t chunk_alloc; /* Length of chunk on disk */
+
+ /* Save the chunk info so the cache stays consistent */
+ chunk_addr = udata->chunk_block.offset;
+ chunk_alloc = udata->chunk_block.length;
+
+ /* Check if we should disable filters on this chunk */
+ if(pline->nused) {
+ if(udata->new_unfilt_chunk) {
+ HDassert(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+
+ /* Disable the filters for writing */
+ disable_filters = TRUE;
+ pline = NULL;
+ } /* end if */
+ else if(prev_unfilt_chunk) {
+ HDassert(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+
+ /* Mark the filters as having been previously disabled (for the
+ * chunk as currently on disk) - disable the filters for reading
+ */
+ old_pline = NULL;
+ } /* end if */
+ else if(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
+ /* Check if this is an edge chunk */
+ if(H5D__chunk_is_partial_edge_chunk(io_info->dset->shared->ndims,
+ layout->u.chunk.dim, io_info->store->chunk.scaled,
+ io_info->dset->shared->curr_dims)) {
+ /* Disable the filters for both writing and reading */
+ disable_filters = TRUE;
+ old_pline = NULL;
+ pline = NULL;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ if(relax) {
+ /*
+ * Not in the cache, but we're about to overwrite the whole thing
+ * anyway, so just allocate a buffer for it but don't initialize that
+ * buffer with the file contents. Count this as a hit instead of a
+ * miss because we saved ourselves lots of work.
+ */
+ rdcc->stats.nhits++;
+
+ if(NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+
+ /* In the case that some dataset functions look through this data,
+ * clear it to all 0s. */
+ HDmemset(chunk, 0, chunk_size);
+ } /* end if */
+ else {
+ /*
+ * Not in the cache. Count this as a miss if it's in the file
+ * or an init if it isn't.
+ */
+
+ /* Check if the chunk exists on disk */
+ if(H5F_addr_defined(chunk_addr)) {
+ size_t my_chunk_alloc = chunk_alloc; /* Allocated buffer size */
+ size_t buf_alloc = chunk_alloc; /* [Re-]allocated buffer size */
+
+ /* Chunk size on disk isn't [likely] the same size as the final chunk
+ * size in memory, so allocate memory big enough. */
+ if(NULL == (chunk = H5D__chunk_mem_alloc(my_chunk_alloc, (udata->new_unfilt_chunk ? old_pline : pline))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+ if(H5F_block_read(dset->oloc.file, H5FD_MEM_DRAW, chunk_addr, my_chunk_alloc, io_info->raw_dxpl_id, chunk) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "unable to read raw data chunk")
+
+ if(old_pline && old_pline->nused) {
+ if(H5Z_pipeline(old_pline, H5Z_FLAG_REVERSE,
+ &(udata->filter_mask),
+ io_info->dxpl_cache->err_detect,
+ io_info->dxpl_cache->filter_cb,
+ &my_chunk_alloc, &buf_alloc, &chunk) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, NULL, "data pipeline read failed")
+
+ /* Reallocate chunk if necessary */
+ if(udata->new_unfilt_chunk) {
+ void *tmp_chunk = chunk;
+
+ if(NULL == (chunk = H5D__chunk_mem_alloc(my_chunk_alloc, pline))) {
+ (void)H5D__chunk_mem_xfree(tmp_chunk, old_pline);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+ } /* end if */
+ HDmemcpy(chunk, tmp_chunk, chunk_size);
+ (void)H5D__chunk_mem_xfree(tmp_chunk, old_pline);
+ } /* end if */
+ } /* end if */
+
+ /* Increment # of cache misses */
+ rdcc->stats.nmisses++;
+ } /* end if */
+ else {
+ H5D_fill_value_t fill_status;
+
+ /* Sanity check */
+ HDassert(fill->alloc_time != H5D_ALLOC_TIME_EARLY);
+
+ /* Chunk size on disk isn't [likely] the same size as the final chunk
+ * size in memory, so allocate memory big enough. */
+ if(NULL == (chunk = H5D__chunk_mem_alloc(chunk_size, pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk")
+
+ if(H5P_is_fill_value_defined(fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't tell if fill value defined")
+
+ if(fill->fill_time == H5D_FILL_TIME_ALLOC ||
+ (fill->fill_time == H5D_FILL_TIME_IFSET &&
+ (fill_status == H5D_FILL_VALUE_USER_DEFINED ||
+ fill_status == H5D_FILL_VALUE_DEFAULT))) {
+ /*
+ * The chunk doesn't exist in the file. Replicate the fill
+ * value throughout the chunk, if the fill value is defined.
+ */
+
+ /* Initialize the fill value buffer */
+ /* (use the compact dataset storage buffer as the fill value buffer) */
+ if(H5D__fill_init(&fb_info, chunk, NULL, NULL, NULL, NULL,
+ &dset->shared->dcpl_cache.fill, dset->shared->type,
+ dset->shared->type_id, (size_t)0, chunk_size, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't initialize fill buffer info")
+ fb_info_init = TRUE;
+
+ /* Check for VL datatype & non-default fill value */
+ if(fb_info.has_vlen_fill_type)
+ /* Fill the buffer with VL datatype fill values */
+ if(H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, NULL, "can't refill fill value buffer")
+ } /* end if */
+ else
+ HDmemset(chunk, 0, chunk_size);
+
+ /* Increment # of creations */
+ rdcc->stats.ninits++;
+ } /* end else */
+ } /* end else */
+
+ /* See if the chunk can be cached */
+ if(rdcc->nslots > 0 && chunk_size <= rdcc->nbytes_max) {
+ /* Calculate the index */
+ udata->idx_hint = H5D__chunk_hash_val(io_info->dset->shared, udata->common.scaled);
+
+ /* Add the chunk to the cache only if the slot is not already locked */
+ ent = rdcc->slot[udata->idx_hint];
+ if(!ent || !ent->locked) {
+ /* Preempt enough things from the cache to make room */
+ if(ent) {
+ if(H5D__chunk_cache_evict(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, ent, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk from cache")
+ } /* end if */
+ if(H5D__chunk_cache_prune(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, chunk_size) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk(s) from cache")
+
+ /* Create a new entry */
+ if(NULL == (ent = H5FL_CALLOC(H5D_rdcc_ent_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate raw data chunk entry")
+
+ ent->edge_chunk_state = disable_filters ? H5D_RDCC_DISABLE_FILTERS : 0;
+ if(udata->new_unfilt_chunk)
+ ent->edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
+
+ /* Initialize the new entry */
+ ent->chunk_block.offset = chunk_addr;
+ ent->chunk_block.length = chunk_alloc;
+ ent->chunk_idx = udata->chunk_idx;
+ HDmemcpy(ent->scaled, udata->common.scaled, sizeof(hsize_t) * layout->u.chunk.ndims);
+ H5_CHECKED_ASSIGN(ent->rd_count, uint32_t, chunk_size, size_t);
+ H5_CHECKED_ASSIGN(ent->wr_count, uint32_t, chunk_size, size_t);
+ ent->chunk = (uint8_t *)chunk;
+
+ /* Add it to the cache */
+ HDassert(NULL == rdcc->slot[udata->idx_hint]);
+ rdcc->slot[udata->idx_hint] = ent;
+ ent->idx = udata->idx_hint;
+ rdcc->nbytes_used += chunk_size;
+ rdcc->nused++;
+
+ /* Add it to the linked list */
+ if(rdcc->tail) {
+ rdcc->tail->next = ent;
+ ent->prev = rdcc->tail;
+ rdcc->tail = ent;
+ } /* end if */
+ else
+ rdcc->head = rdcc->tail = ent;
+ ent->tmp_next = NULL;
+ ent->tmp_prev = NULL;
+
+ } /* end if */
+ else
+ /* We did not add the chunk to cache */
+ ent = NULL;
+ } /* end else */
+ else /* No cache set up, or chunk is too large: chunk is uncacheable */
+ ent = NULL;
+ } /* end else */
+
+ /* Lock the chunk into the cache */
+ if(ent) {
+ HDassert(!ent->locked);
+ ent->locked = TRUE;
+ chunk = ent->chunk;
+ } /* end if */
+ else
+ /*
+ * The chunk cannot be placed in cache so we don't cache it. This is the
+ * reason all those arguments have to be repeated for the unlock
+ * function.
+ */
+ udata->idx_hint = UINT_MAX;
+
+ /* Set return value */
+ ret_value = chunk;
+
+done:
+ /* Release the fill buffer info, if it's been initialized */
+ if(fb_info_init && H5D__fill_term(&fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, NULL, "Can't release fill buffer info")
+
+ /* Release the chunk allocated, on error */
+ if(!ret_value)
+ if(chunk)
+ chunk = H5D__chunk_mem_xfree(chunk, pline);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_unlock
+ *
+ * Purpose: Unlocks a previously locked chunk. The LAYOUT, COMP, and
+ * OFFSET arguments should be the same as for H5D__chunk_lock().
+ * The DIRTY argument should be set to non-zero if the chunk has
+ * been modified since it was locked. The IDX_HINT argument is
+ * the returned index hint from the lock operation and BUF is
+ * the return value from the lock.
+ *
+ * The NACCESSED argument should be the number of bytes accessed
+ * for reading or writing (depending on the value of DIRTY).
+ * It's only purpose is to provide additional information to the
+ * preemption policy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata,
+ hbool_t dirty, void *chunk, uint32_t naccessed)
+{
+ const H5O_layout_t *layout = &(io_info->dset->shared->layout); /* Dataset layout */
+ const H5D_rdcc_t *rdcc = &(io_info->dset->shared->cache.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(udata);
+
+ if(UINT_MAX == udata->idx_hint) {
+ /*
+ * It's not in the cache, probably because it's too big. If it's
+ * dirty then flush it to disk. In any case, free the chunk.
+ */
+ hbool_t is_unfiltered_edge_chunk = FALSE; /* Whether the chunk is an unfiltered edge chunk */
+
+ /* Check if we should disable filters on this chunk */
+ if(udata->new_unfilt_chunk) {
+ HDassert(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+
+ is_unfiltered_edge_chunk = TRUE;
+ } /* end if */
+ else if(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
+ /* Check if the chunk is an edge chunk, and disable filters if so */
+ is_unfiltered_edge_chunk = H5D__chunk_is_partial_edge_chunk(
+ io_info->dset->shared->ndims, layout->u.chunk.dim,
+ io_info->store->chunk.scaled, io_info->dset->shared->curr_dims);
+ } /* end if */
+
+ if(dirty) {
+ H5D_rdcc_ent_t fake_ent; /* "fake" chunk cache entry */
+
+ HDmemset(&fake_ent, 0, sizeof(fake_ent));
+ fake_ent.dirty = TRUE;
+ if(is_unfiltered_edge_chunk)
+ fake_ent.edge_chunk_state = H5D_RDCC_DISABLE_FILTERS;
+ if(udata->new_unfilt_chunk)
+ fake_ent.edge_chunk_state |= H5D_RDCC_NEWLY_DISABLED_FILTERS;
+ HDmemcpy(fake_ent.scaled, udata->common.scaled, sizeof(hsize_t) * layout->u.chunk.ndims);
+ HDassert(layout->u.chunk.size > 0);
+ fake_ent.chunk_idx = udata->chunk_idx;
+ fake_ent.chunk_block.offset = udata->chunk_block.offset;
+ fake_ent.chunk_block.length = udata->chunk_block.length;
+ fake_ent.chunk = (uint8_t *)chunk;
+
+ if(H5D__chunk_flush_entry(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, &fake_ent, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
+ } /* end if */
+ else {
+ if(chunk)
+ chunk = H5D__chunk_mem_xfree(chunk, (is_unfiltered_edge_chunk ? NULL
+ : &(io_info->dset->shared->dcpl_cache.pline)));
+ } /* end else */
+ } /* end if */
+ else {
+ H5D_rdcc_ent_t *ent; /* Chunk's entry in the cache */
+
+ /* Sanity check */
+ HDassert(udata->idx_hint < rdcc->nslots);
+ HDassert(rdcc->slot[udata->idx_hint]);
+ HDassert(rdcc->slot[udata->idx_hint]->chunk == chunk);
+
+ /*
+ * It's in the cache so unlock it.
+ */
+ ent = rdcc->slot[udata->idx_hint];
+ HDassert(ent->locked);
+ if(dirty) {
+ ent->dirty = TRUE;
+ ent->wr_count -= MIN(ent->wr_count, naccessed);
+ } /* end if */
+ else
+ ent->rd_count -= MIN(ent->rd_count, naccessed);
+ ent->locked = FALSE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_unlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_allocated_cb
+ *
+ * Purpose: Simply counts the number of chunks for a dataset.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 21, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__chunk_allocated_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ hsize_t *nbytes = (hsize_t *)_udata;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ *(hsize_t *)nbytes += chunk_rec->nbytes;
+
+ FUNC_LEAVE_NOAPI(H5_ITER_CONT)
+} /* H5D__chunk_allocated_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_allocated
+ *
+ * Purpose: Return the number of bytes allocated in the file for storage
+ * of raw data in the chunked dataset
+ *
+ * Return: Success: Number of bytes stored in all chunks.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_allocated(H5D_t *dset, hid_t dxpl_id, hsize_t *nbytes)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /* Raw data chunk cache */
+ H5D_rdcc_ent_t *ent; /* Cache entry */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ hsize_t chunk_bytes = 0; /* Number of bytes allocated for chunks */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dset);
+ HDassert(dset->shared);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Search for cached chunks that haven't been written out */
+ for(ent = rdcc->head; ent; ent = ent->next) {
+ /* Flush the chunk out to disk, to make certain the size is correct later */
+ if(H5D__chunk_flush_entry(dset, dxpl_id, dxpl_cache, ent, FALSE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer")
+ } /* end for */
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Iterate over the chunks */
+ if((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__chunk_allocated_cb, &chunk_bytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve allocated chunk information from index")
+
+ /* Set number of bytes for caller */
+ *nbytes = chunk_bytes;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_allocated() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_allocate
+ *
+ * Purpose: Allocate file space for all chunks that are not allocated yet.
+ * Return SUCCEED if all needed allocation succeed, otherwise
+ * FAIL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Albert Cheng
+ * June 26, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_allocate(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[])
+{
+ const H5D_t *dset = io_info->dset; /* the dataset pointer */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ const H5D_chunk_ops_t *ops = dset->shared->layout.storage.u.chunk.ops; /* Chunk operations */
+ hsize_t min_unalloc[H5O_LAYOUT_NDIMS]; /* First chunk in each dimension that is unallocated (in scaled coordinates) */
+ hsize_t max_unalloc[H5O_LAYOUT_NDIMS]; /* Last chunk in each dimension that is unallocated (in scaled coordinates) */
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Offset of current chunk (in scaled coordinates) */
+ size_t orig_chunk_size; /* Original size of chunk in bytes */
+ size_t chunk_size; /* Actual size of chunk in bytes, possibly filtered */
+ unsigned filter_mask = 0; /* Filter mask for chunks that have them */
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
+ const H5O_pline_t *pline = &(dset->shared->dcpl_cache.pline); /* I/O pipeline info */
+ const H5O_pline_t def_pline = H5O_CRT_PIPELINE_DEF; /* Default pipeline */
+ const H5O_fill_t *fill = &(dset->shared->dcpl_cache.fill); /* Fill value info */
+ H5D_fill_value_t fill_status; /* The fill value status */
+ hbool_t should_fill = FALSE; /* Whether fill values should be written */
+ void *unfilt_fill_buf = NULL; /* Unfiltered fill value buffer */
+ void **fill_buf = NULL; /* Pointer to the fill buffer to use for a chunk */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+#ifdef H5_HAVE_PARALLEL
+ hbool_t blocks_written = FALSE; /* Flag to indicate that chunk was actually written */
+ hbool_t using_mpi = FALSE; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */
+ H5D_chunk_coll_info_t chunk_info; /* chunk address information for doing I/O */
+#endif /* H5_HAVE_PARALLEL */
+ hid_t md_dxpl_id = io_info->md_dxpl_id;
+ hid_t raw_dxpl_id = io_info->raw_dxpl_id;
+ hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
+ unsigned space_ndims; /* Dataset's space rank */
+ const hsize_t *space_dim; /* Dataset's dataspace dimensions */
+ const uint32_t *chunk_dim = layout->u.chunk.dim; /* Convenience pointer to chunk dimensions */
+ unsigned op_dim; /* Current operating dimension */
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
+ hbool_t has_unfilt_edge_chunks = FALSE; /* Whether there are partial edge chunks with disabled filters */
+ hbool_t unfilt_edge_chunk_dim[H5O_LAYOUT_NDIMS]; /* Whether there are unfiltered edge chunks at the edge of each dimension */
+ hsize_t edge_chunk_scaled[H5O_LAYOUT_NDIMS]; /* Offset of the unfiltered edge chunks at the edge of each dimension */
+ unsigned nunfilt_edge_chunk_dims = 0; /* Number of dimensions on an edge */
+ const H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(md_dxpl_id, dset->oloc.addr, FAIL)
+
+ /* Check args */
+ HDassert(dset && H5D_CHUNKED == layout->type);
+ HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(TRUE == H5P_isa_class(md_dxpl_id, H5P_DATASET_XFER));
+ HDassert(TRUE == H5P_isa_class(raw_dxpl_id, H5P_DATASET_XFER));
+
+ /* Retrieve the dataset dimensions */
+ space_dim = dset->shared->curr_dims;
+ space_ndims = dset->shared->ndims;
+
+ /* The last dimension in scaled chunk coordinates is always 0 */
+ scaled[space_ndims] = (hsize_t)0;
+
+ /* Check if any space dimensions are 0, if so we do not have to do anything
+ */
+ for(op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++)
+ if(space_dim[op_dim] == 0) {
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Retrieve MPI parameters */
+ if(H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
+ /* Set the MPI-capable file driver flag */
+ using_mpi = TRUE;
+
+ /* init chunk info stuff for collective I/O */
+ chunk_info.num_io = 0;
+ chunk_info.addr = NULL;
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(raw_dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Calculate the minimum and maximum chunk offsets in each dimension, and
+ * determine if there are any unfiltered partial edge chunks. Note that we
+ * assume here that all elements of space_dim are > 0. This is checked at
+ * the top of this function. */
+ for(op_dim=0; op_dim<space_ndims; op_dim++) {
+ min_unalloc[op_dim] = (old_dim[op_dim] + chunk_dim[op_dim] - 1) / chunk_dim[op_dim];
+ max_unalloc[op_dim] = (space_dim[op_dim] - 1) / chunk_dim[op_dim];
+
+ /* Calculate if there are unfiltered edge chunks at the edge of this
+ * dimension. Note the edge_chunk_scaled is uninitialized for
+ * dimensions where unfilt_edge_chunk_dim is FALSE. Also */
+ if((layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS)
+ && pline->nused > 0
+ && space_dim[op_dim] % chunk_dim[op_dim] != 0) {
+ has_unfilt_edge_chunks = TRUE;
+ unfilt_edge_chunk_dim[op_dim] = TRUE;
+ edge_chunk_scaled[op_dim] = max_unalloc[op_dim];
+ } /* end if */
+ else
+ unfilt_edge_chunk_dim[op_dim] = FALSE;
+ } /* end for */
+
+ /* Get original chunk size */
+ H5_CHECKED_ASSIGN(orig_chunk_size, size_t, layout->u.chunk.size, uint32_t);
+
+ /* Check the dataset's fill-value status */
+ if(H5P_is_fill_value_defined(fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* If we are filling the dataset on allocation or "if set" and
+ * the fill value _is_ set, _and_ we are not overwriting the new blocks,
+ * or if there are any pipeline filters defined,
+ * set the "should fill" flag
+ */
+ if((!full_overwrite && (fill->fill_time == H5D_FILL_TIME_ALLOC ||
+ (fill->fill_time == H5D_FILL_TIME_IFSET &&
+ (fill_status == H5D_FILL_VALUE_USER_DEFINED ||
+ fill_status == H5D_FILL_VALUE_DEFAULT))))
+ || pline->nused > 0)
+ should_fill = TRUE;
+
+ /* Check if fill values should be written to chunks */
+ if(should_fill) {
+ /* Initialize the fill value buffer */
+ /* (delay allocating fill buffer for VL datatypes until refilling) */
+ /* (casting away const OK - QAK) */
+ if(H5D__fill_init(&fb_info, NULL, (H5MM_allocate_t)H5D__chunk_mem_alloc,
+ (void *)pline, (H5MM_free_t)H5D__chunk_mem_xfree, (void *)pline,
+ &dset->shared->dcpl_cache.fill, dset->shared->type,
+ dset->shared->type_id, (size_t)0, orig_chunk_size, md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
+ fb_info_init = TRUE;
+
+ /* Initialize the fill_buf pointer to the buffer in fb_info. If edge
+ * chunk filters are disabled, we will switch the buffer as appropriate
+ * for each chunk. */
+ fill_buf = &fb_info.fill_buf;
+
+ /* Check if there are filters which need to be applied to the chunk */
+ /* (only do this in advance when the chunk info can be re-used (i.e.
+ * it doesn't contain any non-default VL datatype fill values)
+ */
+ if(!fb_info.has_vlen_fill_type && pline->nused > 0) {
+ size_t buf_size = orig_chunk_size;
+
+ /* If the dataset has disabled partial chunk filters, create a copy
+ * of the unfiltered fill_buf to use for partial chunks */
+ if(has_unfilt_edge_chunks) {
+ if(NULL == (unfilt_fill_buf = H5D__chunk_mem_alloc(orig_chunk_size, &def_pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
+ HDmemcpy(unfilt_fill_buf, fb_info.fill_buf, orig_chunk_size);
+ } /* end if */
+
+ /* Push the chunk through the filters */
+ if(H5Z_pipeline(pline, 0, &filter_mask, dxpl_cache->err_detect, dxpl_cache->filter_cb, &orig_chunk_size, &buf_size, &fb_info.fill_buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed")
+#if H5_SIZEOF_SIZE_T > 4
+ /* Check for the chunk expanding too much to encode in a 32-bit value */
+ if(orig_chunk_size > ((size_t)0xffffffff))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
+#endif /* H5_SIZEOF_SIZE_T > 4 */
+ } /* end if */
+ } /* end if */
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = md_dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Loop over all chunks */
+ /* The algorithm is:
+ * For each dimension:
+ * -Allocate all chunks in the new dataspace that are beyond the original
+ * dataspace in the operating dimension, except those that have already
+ * been allocated.
+ *
+ * This is accomplished mainly using the min_unalloc and max_unalloc arrays.
+ * min_unalloc represents the lowest offset in each dimension of chunks that
+ * have not been allocated (whether or not they need to be). max_unalloc
+ * represents the highest offset in each dimension of chunks in the new
+ * dataset that have not been allocated by this routine (they may have been
+ * allocated previously).
+ *
+ * Every time the algorithm finishes allocating chunks allocated beyond a
+ * certain dimension, max_unalloc is updated in order to avoid allocating
+ * those chunks again.
+ *
+ * Note that min_unalloc & max_unalloc are in scaled coordinates.
+ *
+ */
+ chunk_size = orig_chunk_size;
+ for(op_dim = 0; op_dim < space_ndims; op_dim++) {
+ H5D_chunk_ud_t udata; /* User data for querying chunk info */
+ unsigned u; /* Local index variable */
+ int i; /* Local index variable */
+
+ /* Check if allocation along this dimension is really necessary */
+ if(min_unalloc[op_dim] > max_unalloc[op_dim])
+ continue;
+ else {
+ /* Reset the chunk offset indices */
+ HDmemset(scaled, 0, (space_ndims * sizeof(scaled[0])));
+ scaled[op_dim] = min_unalloc[op_dim];
+
+ if(has_unfilt_edge_chunks) {
+ /* Initialize nunfilt_edge_chunk_dims */
+ nunfilt_edge_chunk_dims = 0;
+ for(u = 0; u < space_ndims; u++)
+ if(unfilt_edge_chunk_dim[u] && scaled[u]
+ == edge_chunk_scaled[u])
+ nunfilt_edge_chunk_dims++;
+
+ /* Initialize chunk_size and fill_buf */
+ if(should_fill && !fb_info.has_vlen_fill_type) {
+ HDassert(fb_info_init);
+ HDassert(unfilt_fill_buf);
+ if(nunfilt_edge_chunk_dims) {
+ fill_buf = &unfilt_fill_buf;
+ chunk_size = layout->u.chunk.size;
+ } /* end if */
+ else {
+ fill_buf = &fb_info.fill_buf;
+ chunk_size = orig_chunk_size;
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ carry = FALSE;
+ } /* end else */
+
+ while(!carry) {
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+
+ /* Look up this chunk */
+ if(H5D__chunk_lookup(dset, md_dxpl_id, scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+#ifndef NDEBUG
+ /* None of the chunks should be allocated */
+ if(H5D_CHUNK_IDX_NONE != layout->storage.u.chunk.idx_type)
+ HDassert(!H5F_addr_defined(udata.chunk_block.offset));
+
+ /* Make sure the chunk is really in the dataset and outside the
+ * original dimensions */
+ {
+ unsigned v; /* Local index variable */
+ hbool_t outside_orig = FALSE;
+
+ for(v = 0; v < space_ndims; v++) {
+ HDassert((scaled[v] * chunk_dim[v]) < space_dim[v]);
+ if((scaled[v] * chunk_dim[v]) >= old_dim[v])
+ outside_orig = TRUE;
+ } /* end for */
+ HDassert(outside_orig);
+ } /* end block */
+#endif /* NDEBUG */
+
+ /* Check for VL datatype & non-default fill value */
+ if(fb_info_init && fb_info.has_vlen_fill_type) {
+ /* Sanity check */
+ HDassert(should_fill);
+ HDassert(!unfilt_fill_buf);
+#ifdef H5_HAVE_PARALLEL
+ HDassert(!using_mpi); /* Can't write VL datatypes in parallel currently */
+#endif
+
+ /* Check to make sure the buffer is large enough. It is
+ * possible (though ill-advised) for the filter to shrink the
+ * buffer. */
+ if(fb_info.fill_buf_size < orig_chunk_size) {
+ if(NULL == (fb_info.fill_buf = H5D__chunk_mem_realloc(fb_info.fill_buf, orig_chunk_size, pline)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory reallocation failed for raw data chunk")
+ fb_info.fill_buf_size = orig_chunk_size;
+ } /* end if */
+
+ /* Fill the buffer with VL datatype fill values */
+ if(H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf, md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
+
+ /* Check if there are filters which need to be applied to the chunk */
+ if((pline->nused > 0) && !nunfilt_edge_chunk_dims) {
+ size_t nbytes = orig_chunk_size;
+
+ /* Push the chunk through the filters */
+ if(H5Z_pipeline(pline, 0, &filter_mask, dxpl_cache->err_detect, dxpl_cache->filter_cb, &nbytes, &fb_info.fill_buf_size, &fb_info.fill_buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed")
+
+#if H5_SIZEOF_SIZE_T > 4
+ /* Check for the chunk expanding too much to encode in a 32-bit value */
+ if(nbytes > ((size_t)0xffffffff))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk too large for 32-bit length")
+#endif /* H5_SIZEOF_SIZE_T > 4 */
+
+ /* Keep the number of bytes the chunk turned in to */
+ chunk_size = nbytes;
+ } /* end if */
+ else
+ chunk_size = layout->u.chunk.size;
+
+ HDassert(*fill_buf == fb_info.fill_buf);
+ } /* end if */
+
+ /* Initialize the chunk information */
+ udata.common.layout = &layout->u.chunk;
+ udata.common.storage = &layout->storage.u.chunk;
+ udata.common.scaled = scaled;
+ udata.chunk_block.offset = HADDR_UNDEF;
+ H5_CHECKED_ASSIGN(udata.chunk_block.length, uint32_t, chunk_size, size_t);
+ udata.filter_mask = filter_mask;
+
+ /* Allocate the chunk (with all processes) */
+ if(H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
+ HDassert(H5F_addr_defined(udata.chunk_block.offset));
+
+ /* Check if fill values should be written to chunks */
+ if(should_fill) {
+ /* Sanity check */
+ HDassert(fb_info_init);
+ HDassert(udata.chunk_block.length == chunk_size);
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check if this file is accessed with an MPI-capable file driver */
+ if(using_mpi) {
+ /* collect all chunk addresses to be written to
+ write collectively at the end */
+ /* allocate/resize address array if no more space left */
+ /* Note that if we add support for parallel filters we must
+ * also store an array of chunk sizes and pass it to the
+ * apporpriate collective write function */
+ if(0 == chunk_info.num_io % 1024)
+ if(NULL == (chunk_info.addr = (haddr_t *)H5MM_realloc(chunk_info.addr, (chunk_info.num_io + 1024) * sizeof(haddr_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for chunk addresses")
+
+ /* Store the chunk's address for later */
+ chunk_info.addr[chunk_info.num_io] = udata.chunk_block.offset;
+ chunk_info.num_io++;
+
+ /* Indicate that blocks will be written */
+ blocks_written = TRUE;
+ } /* end if */
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ if(H5F_block_write(dset->oloc.file, H5FD_MEM_DRAW, udata.chunk_block.offset, chunk_size, raw_dxpl_id, *fill_buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+ } /* end if */
+
+ /* Insert the chunk record into the index */
+ if(need_insert && ops->insert)
+ if((ops->insert)(&idx_info, &udata, dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index")
+
+ /* Increment indices and adjust the edge chunk state */
+ carry = TRUE;
+ for(i = ((int)space_ndims - 1); i >= 0; --i) {
+ scaled[i]++;
+ if(scaled[i] > max_unalloc[i]) {
+ if((unsigned)i == op_dim)
+ scaled[i] = min_unalloc[i];
+ else
+ scaled[i] = 0;
+
+ /* Check if we just left the edge in this dimension */
+ if(unfilt_edge_chunk_dim[i]
+ && edge_chunk_scaled[i] == max_unalloc[i]
+ && scaled[i] < edge_chunk_scaled[i]) {
+ nunfilt_edge_chunk_dims--;
+ if(should_fill && nunfilt_edge_chunk_dims == 0 && !fb_info.has_vlen_fill_type) {
+ HDassert(!H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, scaled, space_dim));
+ fill_buf = &fb_info.fill_buf;
+ chunk_size = orig_chunk_size;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ else {
+ /* Check if we just entered the edge in this dimension */
+ if(unfilt_edge_chunk_dim[i] && scaled[i] == edge_chunk_scaled[i]) {
+ HDassert(edge_chunk_scaled[i] == max_unalloc[i]);
+ nunfilt_edge_chunk_dims++;
+ if(should_fill && nunfilt_edge_chunk_dims == 1 && !fb_info.has_vlen_fill_type) {
+ HDassert(H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, scaled, space_dim));
+ fill_buf = &unfilt_fill_buf;
+ chunk_size = layout->u.chunk.size;
+ } /* end if */
+ } /* end if */
+
+ carry = FALSE;
+ break;
+ } /* end else */
+ } /* end for */
+ } /* end while(!carry) */
+
+ /* Adjust max_unalloc so we don't allocate the same chunk twice. Also
+ * check if this dimension started from 0 (and hence allocated all of
+ * the chunks. */
+ if(min_unalloc[op_dim] == 0)
+ break;
+ else
+ max_unalloc[op_dim] = min_unalloc[op_dim] - 1;
+ } /* end for(op_dim=0...) */
+
+#ifdef H5_HAVE_PARALLEL
+ /* do final collective I/O */
+ if(using_mpi && blocks_written)
+ if(H5D__chunk_collective_fill(dset, raw_dxpl_id, &chunk_info, chunk_size, fb_info.fill_buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+
+done:
+ /* Release the fill buffer info, if it's been initialized */
+ if(fb_info_init && H5D__fill_term(&fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ /* Free the unfiltered fill value buffer */
+ unfilt_fill_buf = H5D__chunk_mem_xfree(unfilt_fill_buf, &def_pline);
+
+#ifdef H5_HAVE_PARALLEL
+ if(using_mpi && chunk_info.addr)
+ H5MM_free(chunk_info.addr);
+#endif
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__chunk_allocate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_update_old_edge_chunks
+ *
+ * Purpose: Update all chunks which were previously partial edge
+ * chunks and are now complete. Determines exactly which
+ * chunks need to be updated and locks each into cache using
+ * the 'prev_unfilt_chunk' flag, then unlocks it, causing
+ * filters to be applied as necessary.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * April 14, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_update_old_edge_chunks(H5D_t *dset, hid_t dxpl_id, hsize_t old_dim[])
+{
+ hsize_t old_edge_chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of first previously incomplete chunk in each dimension */
+ hsize_t max_edge_chunk_sc[H5O_LAYOUT_NDIMS]; /* largest offset of chunks that might need to be modified in each dimension */
+ hbool_t new_full_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of chunks in this dimension needs to be modified */
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */
+ const H5O_pline_t *pline = &(dset->shared->dcpl_cache.pline); /* I/O pipeline info */
+ hsize_t chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of current chunk */
+ const uint32_t *chunk_dim = layout->u.chunk.dim; /* Convenience pointer to chunk dimensions */
+ unsigned space_ndims; /* Dataset's space rank */
+ const hsize_t *space_dim; /* Dataset's dataspace dimensions */
+ unsigned op_dim; /* Current operationg dimension */
+ H5D_io_info_t chk_io_info; /* Chunked I/O info object */
+ H5D_chunk_ud_t chk_udata; /* User data for locking chunk */
+ H5D_storage_t chk_store; /* Chunk storage information */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ void *chunk; /* The file chunk */
+ hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
+ const H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dset && H5D_CHUNKED == layout->type);
+ HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(TRUE == H5P_isa_class(dxpl_id, H5P_DATASET_XFER));
+ HDassert(pline->nused > 0);
+ HDassert(layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS);
+
+ /* Retrieve the dataset dimensions */
+ space_dim = dset->shared->curr_dims;
+ space_ndims = dset->shared->ndims;
+
+ /* The last dimension in chunk_offset is always 0 */
+ chunk_sc[space_ndims] = (hsize_t)0;
+
+ /* Check if any current dimensions are smaller than the chunk size, or if
+ * any old dimensions are 0. If so we do not have to do anything. */
+ for(op_dim=0; op_dim<space_ndims; op_dim++)
+ if((space_dim[op_dim] < chunk_dim[op_dim]) || old_dim[op_dim] == 0) {
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /*
+ * Initialize structures needed to lock chunks into cache
+ */
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Set up chunked I/O info object, for operations on chunks (in callback).
+ * Note that we only need to set chunk_offset once, as the array's address
+ * will never change. */
+ chk_store.chunk.scaled = chunk_sc;
+ H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, dxpl_cache, dxpl_id, H5AC_rawdata_dxpl_id, &chk_store, NULL);
+
+ /*
+ * Determine the edges of the dataset which need to be modified
+ */
+ for(op_dim=0; op_dim<space_ndims; op_dim++) {
+ /* Start off with this dimension marked as not needing to be modified */
+ new_full_dim[op_dim] = FALSE;
+
+ /* Calulate offset of first previously incomplete chunk in this
+ * dimension */
+ old_edge_chunk_sc[op_dim] = (old_dim[op_dim] / chunk_dim[op_dim]);
+
+ /* Calculate the largest offset of chunks that might need to be
+ * modified in this dimension */
+ max_edge_chunk_sc[op_dim] = MIN((old_dim[op_dim] - 1) / chunk_dim[op_dim],
+ MAX((space_dim[op_dim] / chunk_dim[op_dim]), 1) - 1);
+
+ /* Check for old_dim aligned with chunk boundary in this dimension, if
+ * so we do not need to modify chunks along the edge in this dimension
+ */
+ if(old_dim[op_dim] % chunk_dim[op_dim] == 0)
+ continue;
+
+ /* Check if the dataspace expanded enough to cause the old edge chunks
+ * in this dimension to become full */
+ if((space_dim[op_dim]/chunk_dim[op_dim]) >= (old_edge_chunk_sc[op_dim] + 1))
+ new_full_dim[op_dim] = TRUE;
+ } /* end for */
+
+ /* Main loop: fix old edge chunks */
+ for(op_dim=0; op_dim<space_ndims; op_dim++) {
+ /* Check if allocation along this dimension is really necessary */
+ if(!new_full_dim[op_dim])
+ continue;
+ else {
+ HDassert(max_edge_chunk_sc[op_dim] == old_edge_chunk_sc[op_dim]);
+
+ /* Reset the chunk offset indices */
+ HDmemset(chunk_sc, 0, (space_ndims * sizeof(chunk_sc[0])));
+ chunk_sc[op_dim] = old_edge_chunk_sc[op_dim];
+
+ carry = FALSE;
+ } /* end if */
+
+ while(!carry) {
+ int i; /* Local index variable */
+
+ /* Make sure the chunk is really a former edge chunk */
+ HDassert(H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, chunk_sc, old_dim)
+ && !H5D__chunk_is_partial_edge_chunk(space_ndims, chunk_dim, chunk_sc, space_dim));
+
+ /* Lookup the chunk */
+ if(H5D__chunk_lookup(dset, dxpl_id, chunk_sc, &chk_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+
+ /* If this chunk does not exist in cache or on disk, no need to do
+ * anything */
+ if(H5F_addr_defined(chk_udata.chunk_block.offset)
+ || (UINT_MAX != chk_udata.idx_hint)) {
+ /* Lock the chunk into cache. H5D__chunk_lock will take care of
+ * updating the chunk to no longer be an edge chunk. */
+ if(NULL == (chunk = (void *)H5D__chunk_lock(&chk_io_info, &chk_udata, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk")
+
+ /* Unlock the chunk */
+ if(H5D__chunk_unlock(&chk_io_info, &chk_udata, TRUE, chunk, (uint32_t)0) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk")
+ } /* end if */
+
+ /* Increment indices */
+ carry = TRUE;
+ for(i = ((int)space_ndims - 1); i >= 0; --i) {
+ if((unsigned)i != op_dim) {
+ ++chunk_sc[i];
+ if(chunk_sc[i] > (hsize_t) max_edge_chunk_sc[i])
+ chunk_sc[i] = 0;
+ else {
+ carry = FALSE;
+ break;
+ } /* end else */
+ } /* end if */
+ } /* end for */
+ } /* end while(!carry) */
+
+ /* Adjust max_edge_chunk_sc so we don't modify the same chunk twice.
+ * Also check if this dimension started from 0 (and hence modified all
+ * of the old edge chunks. */
+ if(old_edge_chunk_sc[op_dim] == 0)
+ break;
+ else
+ --max_edge_chunk_sc[op_dim];
+ } /* end for(op_dim=0...) */
+
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_update_old_edge_chunks() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_collective_fill
+ *
+ * Purpose: Use MPIO collective write to fill the chunks (if number of
+ * chunks to fill is greater than the number of MPI procs;
+ * otherwise use independent I/O).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * July 30, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_collective_fill(const H5D_t *dset, hid_t dxpl_id,
+ H5D_chunk_coll_info_t *chunk_info, size_t chunk_size, const void *fill_buf)
+{
+ MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */
+ int mpi_rank = (-1); /* This process's rank */
+ int mpi_size = (-1); /* MPI Comm size */
+ int mpi_code; /* MPI return code */
+ size_t num_blocks; /* Number of blocks between processes. */
+ size_t leftover_blocks; /* Number of leftover blocks to handle */
+ int blocks, leftover, block_len; /* converted to int for MPI */
+ MPI_Aint *chunk_disp_array = NULL;
+ int *block_lens = NULL;
+ MPI_Datatype mem_type, file_type;
+ hid_t data_dxpl_id = -1; /* DXPL ID to use for raw data I/O operations */
+ int i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the MPI communicator */
+ if(MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(dset->oloc.file)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator")
+
+ /* Get the MPI rank */
+ if((mpi_rank = H5F_mpi_get_rank(dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank")
+
+ /* Get the MPI size */
+ if((mpi_size = H5F_mpi_get_size(dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI size")
+
+ /* Get a copy of the DXPL, to modify */
+ if((data_dxpl_id = H5P_copy_plist((H5P_genplist_t *)H5I_object(dxpl_id), TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property list")
+
+ /* Distribute evenly the number of blocks between processes. */
+ num_blocks = chunk_info->num_io / mpi_size; /* value should be the same on all procs */
+
+ /* after evenly distributing the blocks between processes, are
+ there any leftover blocks for each individual process
+ (round-robin) */
+ leftover_blocks = chunk_info->num_io % mpi_size;
+
+ /* Cast values to types needed by MPI */
+ H5_CHECKED_ASSIGN(blocks, int, num_blocks, size_t);
+ H5_CHECKED_ASSIGN(leftover, int, leftover_blocks, size_t);
+ H5_CHECKED_ASSIGN(block_len, int, chunk_size, size_t);
+
+ /* Allocate buffers */
+ /* (MSC - should not need block_lens if MPI_type_create_hindexed_block is working) */
+ if(NULL == (block_lens = (int *)H5MM_malloc((blocks + 1) * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk lengths buffer")
+ if(NULL == (chunk_disp_array = (MPI_Aint *)H5MM_malloc((blocks + 1) * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file displacement buffer")
+
+ for(i = 0 ; i < blocks ; i++) {
+ /* store the chunk address as an MPI_Aint */
+ chunk_disp_array[i] = (MPI_Aint)(chunk_info->addr[i + mpi_rank*blocks]);
+
+ /* MSC - should not need this if MPI_type_create_hindexed_block is working */
+ block_lens[i] = block_len;
+
+ /* make sure that the addresses in the datatype are
+ monotonically non decreasing */
+ if(i)
+ HDassert(chunk_disp_array[i] > chunk_disp_array[i - 1]);
+ } /* end if */
+
+ /* calculate if there are any leftover blocks after evenly
+ distributing. If there are, then round robin the distribution
+ to processes 0 -> leftover. */
+ if(leftover && leftover > mpi_rank) {
+ chunk_disp_array[blocks] = (MPI_Aint)chunk_info->addr[blocks*mpi_size + mpi_rank];
+ block_lens[blocks] = block_len;
+ blocks++;
+ }
+
+ /* MSC
+ * should use this if MPI_type_create_hindexed block is working
+ * mpi_code = MPI_Type_create_hindexed_block(blocks, block_len, chunk_disp_array, MPI_BYTE, &file_type);
+ */
+ mpi_code = MPI_Type_create_hindexed(blocks, block_lens, chunk_disp_array, MPI_BYTE, &file_type);
+ if(mpi_code != MPI_SUCCESS)
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&file_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+ mpi_code = MPI_Type_create_hvector(blocks, block_len, 0, MPI_BYTE, &mem_type);
+ if(mpi_code != MPI_SUCCESS)
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hvector failed", mpi_code)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&mem_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+ /* set MPI-IO VFD properties */
+ {
+ H5FD_mpio_xfer_t xfer_mode = H5FD_MPIO_COLLECTIVE;
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ if(NULL == (plist = H5P_object_verify(data_dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dataset transfer list")
+
+ /* Set buffer MPI type */
+ if(H5P_set(plist, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, &mem_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O property")
+
+ /* Set File MPI type */
+ if(H5P_set(plist, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, &file_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O property")
+
+ /* set transfer mode */
+ if(H5P_set(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode")
+ }
+
+ /* low level write (collective) */
+ if(H5F_block_write(dset->oloc.file, H5FD_MEM_DRAW, (haddr_t)0, (blocks) ? (size_t)1 : (size_t)0, data_dxpl_id, fill_buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file")
+
+ /* Barrier so processes don't race ahead */
+ if(MPI_SUCCESS != (mpi_code = MPI_Barrier(mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
+
+done:
+ if(data_dxpl_id > 0 && H5I_dec_ref(data_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't free property list")
+
+ /* free things */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&file_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&mem_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ H5MM_xfree(chunk_disp_array);
+ H5MM_xfree(block_lens);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_collective_fill() */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_prune_fill
+ *
+ * Purpose: Write the fill value to the parts of the chunk that are no
+ * longer part of the dataspace
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * March 26, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk)
+{
+ const H5D_io_info_t *io_info = udata->io_info; /* Local pointer to I/O info */
+ const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */
+ unsigned rank = udata->common.layout->ndims - 1; /* Dataset rank */
+ const hsize_t *scaled = udata->common.scaled; /* Scaled chunk offset */
+ H5S_sel_iter_t *chunk_iter = NULL; /* Memory selection iteration info */
+ hbool_t chunk_iter_init = FALSE; /* Whether the chunk iterator has been initialized */
+ hssize_t sel_nelmts; /* Number of elements in selection */
+ hsize_t count[H5O_LAYOUT_NDIMS]; /* Element count of hyperslab */
+ size_t chunk_size; /*size of a chunk */
+ void *chunk; /* The file chunk */
+ H5D_chunk_ud_t chk_udata; /* User data for locking chunk */
+ uint32_t bytes_accessed; /* Bytes accessed in chunk */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the chunk's size */
+ HDassert(layout->u.chunk.size > 0);
+ H5_CHECKED_ASSIGN(chunk_size, size_t, layout->u.chunk.size, uint32_t);
+
+ /* Get the info for the chunk in the file */
+ if(H5D__chunk_lookup(dset, io_info->md_dxpl_id, scaled, &chk_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address")
+ chk_udata.new_unfilt_chunk = new_unfilt_chunk;
+
+ /* If this chunk does not exist in cache or on disk, no need to do anything */
+ if(!H5F_addr_defined(chk_udata.chunk_block.offset) && UINT_MAX == chk_udata.idx_hint)
+ HGOTO_DONE(SUCCEED)
+
+ /* Initialize the fill value buffer, if necessary */
+ if(!udata->fb_info_init) {
+ H5_CHECK_OVERFLOW(udata->elmts_per_chunk, uint32_t, size_t);
+ if(H5D__fill_init(&udata->fb_info, NULL, NULL, NULL, NULL, NULL,
+ &dset->shared->dcpl_cache.fill,
+ dset->shared->type, dset->shared->type_id, (size_t)udata->elmts_per_chunk,
+ chunk_size, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
+ udata->fb_info_init = TRUE;
+ } /* end if */
+
+ /* Compute the # of elements to leave with existing value, in each dimension */
+ for(u = 0; u < rank; u++) {
+ count[u] = MIN(layout->u.chunk.dim[u], (udata->space_dim[u] - (scaled[u] * layout->u.chunk.dim[u])));
+ HDassert(count[u] > 0);
+ } /* end for */
+
+ /* Select all elements in chunk, to begin with */
+ if(H5S_select_all(udata->chunk_space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select space")
+
+ /* "Subtract out" the elements to keep */
+ if(H5S_select_hyperslab(udata->chunk_space, H5S_SELECT_NOTB, udata->hyper_start, NULL, count, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to select hyperslab")
+
+ /* Lock the chunk into the cache, to get a pointer to the chunk buffer */
+ if(NULL == (chunk = (void *)H5D__chunk_lock(io_info, &chk_udata, FALSE, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to lock raw data chunk")
+
+
+ /* Fill the selection in the memory buffer */
+ /* Use the size of the elements in the chunk directly instead of */
+ /* relying on the fill.size, which might be set to 0 if there is */
+ /* no fill-value defined for the dataset -QAK */
+
+ /* Get the number of elements in the selection */
+ sel_nelmts = H5S_GET_SELECT_NPOINTS(udata->chunk_space);
+ HDassert(sel_nelmts >= 0);
+ H5_CHECK_OVERFLOW(sel_nelmts, hssize_t, size_t);
+
+ /* Check for VL datatype & non-default fill value */
+ if(udata->fb_info.has_vlen_fill_type)
+ /* Re-fill the buffer to use for this I/O operation */
+ if(H5D__fill_refill_vl(&udata->fb_info, (size_t)sel_nelmts, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
+
+ /* Allocate the chunk selection iterator */
+ if(NULL == (chunk_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk selection iterator")
+
+ /* Create a selection iterator for scattering the elements to memory buffer */
+ if(H5S_select_iter_init(chunk_iter, udata->chunk_space, layout->u.chunk.dim[rank]) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunk selection information")
+ chunk_iter_init = TRUE;
+
+ /* Scatter the data into memory */
+ if(H5D__scatter_mem(udata->fb_info.fill_buf, udata->chunk_space, chunk_iter, (size_t)sel_nelmts, io_info->dxpl_cache, chunk/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed")
+
+
+ /* The number of bytes accessed in the chunk */
+ /* (i.e. the bytes replaced with fill values) */
+ H5_CHECK_OVERFLOW(sel_nelmts, hssize_t, uint32_t);
+ bytes_accessed = (uint32_t)sel_nelmts * layout->u.chunk.dim[rank];
+
+ /* Release lock on chunk */
+ if(H5D__chunk_unlock(io_info, &chk_udata, TRUE, chunk, bytes_accessed) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk")
+
+done:
+ /* Release the selection iterator */
+ if(chunk_iter_init && H5S_SELECT_ITER_RELEASE(chunk_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(chunk_iter)
+ chunk_iter = H5FL_FREE(H5S_sel_iter_t, chunk_iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_prune_fill */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_prune_by_extent
+ *
+ * Purpose: This function searches for chunks that are no longer necessary
+ * both in the raw data cache and in the chunk index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * Algorithm: Robb Matzke
+ * March 27, 2002
+ *
+ * The algorithm is:
+ *
+ * For chunks that are no longer necessary:
+ *
+ * 1. Search in the raw data cache for each chunk
+ * 2. If found then preempt it from the cache
+ * 3. Search in the B-tree for each chunk
+ * 4. If found then remove it from the B-tree and deallocate file storage for the chunk
+ *
+ * This example shows a 2d dataset of 90x90 with a chunk size of 20x20.
+ *
+ *
+ * 0 20 40 60 80 90 100
+ * 0 +---------+---------+---------+---------+-----+...+
+ * |:::::X:::::::::::::: : : | :
+ * |:::::::X:::::::::::: : : | : Key
+ * |::::::::::X::::::::: : : | : --------
+ * |::::::::::::X::::::: : : | : +-+ Dataset
+ * 20+::::::::::::::::::::.........:.........:.....+...: | | Extent
+ * | :::::X::::: : : | : +-+
+ * | ::::::::::: : : | :
+ * | ::::::::::: : : | : ... Chunk
+ * | :::::::X::: : : | : : : Boundary
+ * 40+.........:::::::::::.........:.........:.....+...: :.:
+ * | : : : : | :
+ * | : : : : | : ... Allocated
+ * | : : : : | : ::: & Filled
+ * | : : : : | : ::: Chunk
+ * 60+.........:.........:.........:.........:.....+...:
+ * | : :::::::X::: : | : X Element
+ * | : ::::::::::: : | : Written
+ * | : ::::::::::: : | :
+ * | : ::::::::::: : | :
+ * 80+.........:.........:::::::::::.........:.....+...: O Fill Val
+ * | : : ::::::::::: | : Explicitly
+ * | : : ::::::X:::: | : Written
+ * 90+---------+---------+---------+---------+-----+ :
+ * : : : ::::::::::: :
+ * 100:.........:.........:.........:::::::::::.........:
+ *
+ *
+ * We have 25 total chunks for this dataset, 5 of which have space
+ * allocated in the file because they were written to one or more
+ * elements. These five chunks (and only these five) also have entries in
+ * the storage B-tree for this dataset.
+ *
+ * Now lets say we want to shrink the dataset down to 70x70:
+ *
+ *
+ * 0 20 40 60 70 80 90 100
+ * 0 +---------+---------+---------+----+----+-----+...+
+ * |:::::X:::::::::::::: : | : | :
+ * |:::::::X:::::::::::: : | : | : Key
+ * |::::::::::X::::::::: : | : | : --------
+ * |::::::::::::X::::::: : | : | : +-+ Dataset
+ * 20+::::::::::::::::::::.........:....+....:.....|...: | | Extent
+ * | :::::X::::: : | : | : +-+
+ * | ::::::::::: : | : | :
+ * | ::::::::::: : | : | : ... Chunk
+ * | :::::::X::: : | : | : : : Boundary
+ * 40+.........:::::::::::.........:....+....:.....|...: :.:
+ * | : : : | : | :
+ * | : : : | : | : ... Allocated
+ * | : : : | : | : ::: & Filled
+ * | : : : | : | : ::: Chunk
+ * 60+.........:.........:.........:....+....:.....|...:
+ * | : :::::::X::: | : | : X Element
+ * | : ::::::::::: | : | : Written
+ * +---------+---------+---------+----+ : | :
+ * | : ::::::::::: : | :
+ * 80+.........:.........:::::::::X:.........:.....|...: O Fill Val
+ * | : : ::::::::::: | : Explicitly
+ * | : : ::::::X:::: | : Written
+ * 90+---------+---------+---------+---------+-----+ :
+ * : : : ::::::::::: :
+ * 100:.........:.........:.........:::::::::::.........:
+ *
+ *
+ * That means that the nine chunks along the bottom and right side should
+ * no longer exist. Of those nine chunks, (0,80), (20,80), (40,80),
+ * (60,80), (80,80), (80,60), (80,40), (80,20), and (80,0), one is actually allocated
+ * that needs to be released.
+ * To release the chunks, we traverse the B-tree to obtain a list of unused
+ * allocated chunks, and then call H5B_remove() for each chunk.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_prune_by_extent(H5D_t *dset, hid_t dxpl_id, const hsize_t *old_dim)
+{
+ hsize_t min_mod_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of first chunk to modify in each dimension */
+ hsize_t max_mod_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of last chunk to modify in each dimension */
+ hssize_t max_fill_chunk_sc[H5O_LAYOUT_NDIMS]; /* Scaled offset of last chunk that might be filled in each dimension */
+ hbool_t fill_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of edge chunks in this dimension needs to be filled */
+ hsize_t min_partial_chunk_sc[H5O_LAYOUT_NDIMS]; /* Offset of first partial (or empty) chunk in each dimension */
+ hbool_t new_unfilt_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of edge chunks in this dimension are newly unfiltered */
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_io_info_t chk_io_info; /* Chunked I/O info object */
+ H5D_storage_t chk_store; /* Chunk storage information */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */
+ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
+ unsigned space_ndims; /* Dataset's space rank */
+ const hsize_t *space_dim; /* Current dataspace dimensions */
+ unsigned op_dim; /* Current operating dimension */
+ hbool_t shrunk_dim[H5O_LAYOUT_NDIMS]; /* Dimensions which have shrunk */
+ H5D_chunk_it_ud1_t udata; /* Chunk index iterator user data */
+ hbool_t udata_init = FALSE; /* Whether the chunk index iterator user data has been initialized */
+ H5D_chunk_common_ud_t idx_udata; /* User data for index removal routine */
+ H5S_t *chunk_space = NULL; /* Dataspace for a chunk */
+ hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Chunk dimensions */
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled offset of current chunk */
+ hsize_t hyper_start[H5O_LAYOUT_NDIMS]; /* Starting location of hyperslab */
+ uint32_t elmts_per_chunk; /* Elements in chunk */
+ hbool_t disable_edge_filters = FALSE; /* Whether to disable filters on partial edge chunks */
+ hbool_t new_unfilt_chunk = FALSE; /* Whether the chunk is newly unfiltered */
+ unsigned u; /* Local index variable */
+ const H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dset && H5D_CHUNKED == layout->type);
+ HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(dxpl_cache);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Go get the rank & dimensions (including the element size) */
+ space_dim = dset->shared->curr_dims;
+ space_ndims = dset->shared->ndims;
+
+ /* The last dimension in scaled is always 0 */
+ scaled[space_ndims] = (hsize_t)0;
+
+ /* Check if any old dimensions are 0, if so we do not have to do anything */
+ for(op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++)
+ if(old_dim[op_dim] == 0) {
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Round up to the next integer # of chunks, to accomodate partial chunks */
+ /* Use current dims because the indices have already been updated! -NAF */
+ /* (also compute the number of elements per chunk) */
+ /* (also copy the chunk dimensions into 'hsize_t' array for creating dataspace) */
+ /* (also compute the dimensions which have been shrunk) */
+ elmts_per_chunk = 1;
+ for(u = 0; u < space_ndims; u++) {
+ elmts_per_chunk *= layout->u.chunk.dim[u];
+ chunk_dim[u] = layout->u.chunk.dim[u];
+ shrunk_dim[u] = (space_dim[u] < old_dim[u]);
+ } /* end for */
+
+ /* Create a dataspace for a chunk & set the extent */
+ if(NULL == (chunk_space = H5S_create_simple(space_ndims, chunk_dim, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Reset hyperslab start array */
+ /* (hyperslabs will always start from origin) */
+ HDmemset(hyper_start, 0, sizeof(hyper_start));
+
+ /* Set up chunked I/O info object, for operations on chunks (in callback)
+ * Note that we only need to set scaled once, as the array's address
+ * will never change. */
+ chk_store.chunk.scaled = scaled;
+ H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, dxpl_cache, dxpl_id, H5AC_rawdata_dxpl_id, &chk_store, NULL);
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Initialize the user data for the iteration */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.common.layout = &layout->u.chunk;
+ udata.common.storage = &layout->storage.u.chunk;
+ udata.common.scaled = scaled;
+ udata.io_info = &chk_io_info;
+ udata.idx_info = &idx_info;
+ udata.space_dim = space_dim;
+ udata.shrunk_dim = shrunk_dim;
+ udata.elmts_per_chunk = elmts_per_chunk;
+ udata.chunk_space = chunk_space;
+ udata.hyper_start = hyper_start;
+ udata_init = TRUE;
+
+ /* Initialize user data for removal */
+ idx_udata.layout = &layout->u.chunk;
+ idx_udata.storage = &layout->storage.u.chunk;
+
+ /* Determine if partial edge chunk filters are disabled */
+ disable_edge_filters = (layout->u.chunk.flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS)
+ && (idx_info.pline->nused > 0);
+
+ /*
+ * Determine the chunks which need to be filled or removed
+ */
+ HDmemset(min_mod_chunk_sc, 0, sizeof(min_mod_chunk_sc));
+ HDmemset(max_mod_chunk_sc, 0, sizeof(max_mod_chunk_sc));
+ for(op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++) {
+ /* Calculate the largest offset of chunks that might need to be
+ * modified in this dimension */
+ max_mod_chunk_sc[op_dim] = (old_dim[op_dim] - 1) / chunk_dim[op_dim];
+
+ /* Calculate the largest offset of chunks that might need to be
+ * filled in this dimension */
+ if(0 == space_dim[op_dim])
+ max_fill_chunk_sc[op_dim] = -1;
+ else
+ max_fill_chunk_sc[op_dim] = (hssize_t)(((MIN(space_dim[op_dim], old_dim[op_dim]) - 1)
+ / chunk_dim[op_dim]));
+
+ if(shrunk_dim[op_dim]) {
+ /* Calculate the smallest offset of chunks that might need to be
+ * modified in this dimension. Note that this array contains
+ * garbage for all dimensions which are not shrunk. These locations
+ * must not be read from! */
+ min_mod_chunk_sc[op_dim] = space_dim[op_dim] / chunk_dim[op_dim];
+
+ /* Determine if we need to fill chunks in this dimension */
+ if((hssize_t)min_mod_chunk_sc[op_dim] == max_fill_chunk_sc[op_dim]) {
+ fill_dim[op_dim] = TRUE;
+
+ /* If necessary, check if chunks in this dimension that need to
+ * be filled are new partial edge chunks */
+ if(disable_edge_filters && old_dim[op_dim] >= (min_mod_chunk_sc[op_dim] + 1))
+ new_unfilt_dim[op_dim] = TRUE;
+ else
+ new_unfilt_dim[op_dim] = FALSE;
+ } /* end if */
+ else {
+ fill_dim[op_dim] = FALSE;
+ new_unfilt_dim[op_dim] = FALSE;
+ } /* end else */
+ } /* end if */
+ else {
+ fill_dim[op_dim] = FALSE;
+ new_unfilt_dim[op_dim] = FALSE;
+ } /* end else */
+
+ /* If necessary, calculate the smallest offset of non-previously full
+ * chunks in this dimension, so we know these chunks were previously
+ * unfiltered */
+ if(disable_edge_filters)
+ min_partial_chunk_sc[op_dim] = old_dim[op_dim] / chunk_dim[op_dim];
+ } /* end for */
+
+ /* Main loop: fill or remove chunks */
+ for(op_dim = 0; op_dim < (unsigned)space_ndims; op_dim++) {
+ hbool_t dims_outside_fill[H5O_LAYOUT_NDIMS]; /* Dimensions in chunk offset outside fill dimensions */
+ int ndims_outside_fill; /* Number of dimensions in chunk offset outside fill dimensions */
+ hbool_t carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */
+
+ /* Check if modification along this dimension is really necessary */
+ if(!shrunk_dim[op_dim])
+ continue;
+ else {
+ HDassert(max_mod_chunk_sc[op_dim] >= min_mod_chunk_sc[op_dim]);
+
+ /* Reset the chunk offset indices */
+ HDmemset(scaled, 0, (space_ndims * sizeof(scaled[0])));
+ scaled[op_dim] = min_mod_chunk_sc[op_dim];
+
+ /* Initialize "dims_outside_fill" array */
+ ndims_outside_fill = 0;
+ for(u = 0; u < space_ndims; u++)
+ if((hssize_t)scaled[u] > max_fill_chunk_sc[u]) {
+ dims_outside_fill[u] = TRUE;
+ ndims_outside_fill++;
+ } /* end if */
+ else
+ dims_outside_fill[u] = FALSE;
+ } /* end if */
+
+ carry = FALSE;
+ while(!carry) {
+ int i; /* Local index variable */
+
+ udata.common.scaled = scaled;
+
+ if(0 == ndims_outside_fill) {
+ HDassert(fill_dim[op_dim]);
+ HDassert(scaled[op_dim] == min_mod_chunk_sc[op_dim]);
+
+ /* Make sure this is an edge chunk */
+ HDassert(H5D__chunk_is_partial_edge_chunk(space_ndims, layout->u.chunk.dim, scaled, space_dim));
+
+ /* Determine if the chunk just became an unfiltered chunk */
+ if(new_unfilt_dim[op_dim]) {
+ new_unfilt_chunk = TRUE;
+ for(u = 0; u < space_ndims; u++)
+ if(scaled[u] == min_partial_chunk_sc[u]) {
+ new_unfilt_chunk = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Make sure that, if we think this is a new unfiltered chunk,
+ * it was previously not an edge chunk */
+ HDassert(!new_unfilt_dim[op_dim] || (!new_unfilt_chunk !=
+ !H5D__chunk_is_partial_edge_chunk(space_ndims, layout->u.chunk.dim, scaled, old_dim)));
+ HDassert(!new_unfilt_chunk || new_unfilt_dim[op_dim]);
+
+ /* Fill the unused parts of the chunk */
+ if(H5D__chunk_prune_fill(&udata, new_unfilt_chunk) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write fill value")
+ } /* end if */
+ else {
+ H5D_chunk_ud_t chk_udata; /* User data for getting chunk info */
+
+#ifndef NDEBUG
+ /* Make sure this chunk is really outside the new dimensions */
+ {
+ hbool_t outside_dim = FALSE;
+
+ for(u = 0; u < space_ndims; u++)
+ if((scaled[u] * chunk_dim[u]) >= space_dim[u]) {
+ outside_dim = TRUE;
+ break;
+ } /* end if */
+ HDassert(outside_dim);
+ } /* end block */
+#endif /* NDEBUG */
+
+ /* Check if the chunk exists in cache or on disk */
+ if(H5D__chunk_lookup(dset, dxpl_id, scaled, &chk_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk")
+
+ /* Evict the entry from the cache if present, but do not flush
+ * it to disk */
+ if(UINT_MAX != chk_udata.idx_hint)
+ if(H5D__chunk_cache_evict(dset, dxpl_id, dxpl_cache, rdcc->slot[chk_udata.idx_hint], FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to evict chunk")
+
+ /* Remove the chunk from disk, if present */
+ if(H5F_addr_defined(chk_udata.chunk_block.offset)) {
+ /* Update the offset in idx_udata */
+ idx_udata.scaled = udata.common.scaled;
+
+ /* Remove the chunk from disk */
+ if((layout->storage.u.chunk.ops->remove)(&idx_info, &idx_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to remove chunk entry from index")
+ } /* end if */
+ } /* end else */
+
+ /* Increment indices */
+ carry = TRUE;
+ for(i = (int)(space_ndims - 1); i >= 0; --i) {
+ scaled[i]++;
+ if(scaled[i] > max_mod_chunk_sc[i]) {
+ /* Left maximum dimensions, "wrap around" and check if this
+ * dimension is no longer outside the fill dimension */
+ if((unsigned)i == op_dim) {
+ scaled[i] = min_mod_chunk_sc[i];
+ if(dims_outside_fill[i] && fill_dim[i]) {
+ dims_outside_fill[i] = FALSE;
+ ndims_outside_fill--;
+ } /* end if */
+ } /* end if */
+ else {
+ scaled[i] = 0;
+ if(dims_outside_fill[i] && max_fill_chunk_sc[i] >= 0) {
+ dims_outside_fill[i] = FALSE;
+ ndims_outside_fill--;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check if we just went outside the fill dimension */
+ if(!dims_outside_fill[i] && (hssize_t)scaled[i] > max_fill_chunk_sc[i]) {
+ dims_outside_fill[i] = TRUE;
+ ndims_outside_fill++;
+ } /* end if */
+
+ /* We found the next chunk, so leave the loop */
+ carry = FALSE;
+ break;
+ } /* end else */
+ } /* end for */
+ } /* end while(!carry) */
+
+ /* Adjust max_mod_chunk_sc so we don't modify the same chunk twice.
+ * Also check if this dimension started from 0 (and hence removed all
+ * of the chunks). */
+ if(min_mod_chunk_sc[op_dim] == 0)
+ break;
+ else
+ max_mod_chunk_sc[op_dim] = min_mod_chunk_sc[op_dim] - 1;
+ } /* end for(op_dim=0...) */
+
+ /* Reset any cached chunk info for this dataset */
+ H5D__chunk_cinfo_cache_reset(&dset->shared->cache.chunk.last);
+
+done:
+ /* Release resources */
+ if(chunk_space && H5S_close(chunk_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+ if(udata_init)
+ if(udata.fb_info_init && H5D__fill_term(&udata.fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_prune_by_extent() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_addrmap_cb
+ *
+ * Purpose: Callback when obtaining the chunk addresses for all existing chunks
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Kent Yang
+ * Tuesday, November 15, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__chunk_addrmap_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_chunk_it_ud2_t *udata = (H5D_chunk_it_ud2_t *)_udata; /* User data for callback */
+ unsigned rank = udata->common.layout->ndims - 1; /* # of dimensions of dataset */
+ hsize_t chunk_index;
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Compute the index for this chunk */
+ chunk_index = H5VM_array_offset_pre(rank, udata->common.layout->down_chunks, chunk_rec->scaled);
+
+ /* Set it in the userdata to return */
+ udata->chunk_addr[chunk_index] = chunk_rec->chunk_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_addrmap_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_addrmap
+ *
+ * Purpose: Obtain the chunk addresses for all existing chunks
+ *
+ * Return: Success: Non-negative on succeed.
+ * Failure: negative value
+ *
+ * Programmer: Kent Yang
+ * November 15, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[])
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ const H5D_t *dset = io_info->dset; /* Local pointer to dataset info */
+ H5D_chunk_it_ud2_t udata; /* User data for iteration callback */
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dset);
+ HDassert(dset->shared);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(chunk_addr);
+
+ /* Set up user data for B-tree callback */
+ HDmemset(&udata, 0, sizeof(udata));
+ udata.common.layout = &dset->shared->layout.u.chunk;
+ udata.common.storage = &dset->shared->layout.storage.u.chunk;
+ udata.chunk_addr = chunk_addr;
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = io_info->md_dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Iterate over chunks to build mapping of chunk addresses */
+ if((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__chunk_addrmap_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to iterate over chunk index to build address map")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_addrmap() */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_delete
+ *
+ * Purpose: Delete raw data storage for entire dataset (i.e. all chunks)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_storage_t *storage)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5O_layout_t layout; /* Dataset layout message */
+ hbool_t layout_read = FALSE; /* Whether the layout message was read from the file */
+ H5O_pline_t pline; /* I/O pipeline message */
+ hbool_t pline_read = FALSE; /* Whether the I/O pipeline message was read from the file */
+ htri_t exists; /* Flag if header message of interest exists */
+ H5O_storage_chunk_t *sc = &(storage->u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(storage);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ /* Check for I/O pipeline message */
+ if((exists = H5O_msg_exists_oh(oh, H5O_PLINE_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to check for object header message")
+ else if(exists) {
+ if(NULL == H5O_msg_read_oh(f, dxpl_id, oh, H5O_PLINE_ID, &pline))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get I/O pipeline message")
+ pline_read = TRUE;
+ } /* end else if */
+ else
+ HDmemset(&pline, 0, sizeof(pline));
+
+ /* Retrieve dataset layout message */
+ if((exists = H5O_msg_exists_oh(oh, H5O_LAYOUT_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to check for object header message")
+ else if(exists) {
+ if(NULL == H5O_msg_read_oh(f, dxpl_id, oh, H5O_LAYOUT_ID, &layout))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get layout message")
+ layout_read = TRUE;
+ } /* end else if */
+ else
+ HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, FAIL, "can't find layout message")
+
+ /* Compose chunked index info struct */
+ idx_info.f = f;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &pline;
+ idx_info.layout = &layout.u.chunk;
+ idx_info.storage = &storage->u.chunk;
+
+ /* Delete the chunked storage information in the file */
+ if((storage->u.chunk.ops->idx_delete)(&idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk index")
+
+done:
+ /* Clean up any messages read in */
+ if(pline_read)
+ if(H5O_msg_reset(H5O_PLINE_ID, &pline) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message")
+ if(layout_read)
+ if(H5O_msg_reset(H5O_LAYOUT_ID, &layout) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset layout message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_update_cache
+ *
+ * Purpose: Update any cached chunks index values after the dataspace
+ * size has changed
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 29, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_update_cache(H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /*raw data chunk cache */
+ H5D_rdcc_ent_t *ent, *next; /*cache entry */
+ H5D_rdcc_ent_t tmp_head; /* Sentinel entry for temporary entry list */
+ H5D_rdcc_ent_t *tmp_tail; /* Tail pointer for temporary entry list */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dset && H5D_CHUNKED == dset->shared->layout.type);
+ HDassert(dset->shared->layout.u.chunk.ndims > 0 && dset->shared->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+
+ /* Check the rank */
+ HDassert((dset->shared->layout.u.chunk.ndims - 1) > 1);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Add temporary entry list to rdcc */
+ (void)HDmemset(&tmp_head, 0, sizeof(tmp_head));
+ rdcc->tmp_head = &tmp_head;
+ tmp_tail = &tmp_head;
+
+ /* Recompute the index for each cached chunk that is in a dataset */
+ for(ent = rdcc->head; ent; ent = next) {
+ unsigned old_idx; /* Previous index number */
+
+ /* Get the pointer to the next cache entry */
+ next = ent->next;
+
+ /* Compute the index for the chunk entry */
+ old_idx = ent->idx; /* Save for later */
+ ent->idx = H5D__chunk_hash_val(dset->shared, ent->scaled);
+
+ if(old_idx != ent->idx) {
+ H5D_rdcc_ent_t *old_ent; /* Old cache entry */
+
+ /* Check if there is already a chunk at this chunk's new location */
+ old_ent = rdcc->slot[ent->idx];
+ if(old_ent != NULL) {
+ HDassert(old_ent->locked == FALSE);
+ HDassert(old_ent->deleted == FALSE);
+
+ /* Insert the old entry into the temporary list, but do not
+ * evict (yet). Make sure we do not make any calls to the index
+ * until all chunks have updated indices! */
+ HDassert(!old_ent->tmp_next);
+ HDassert(!old_ent->tmp_prev);
+ tmp_tail->tmp_next = old_ent;
+ old_ent->tmp_prev = tmp_tail;
+ tmp_tail = old_ent;
+ } /* end if */
+
+ /* Insert this chunk into correct location in hash table */
+ rdcc->slot[ent->idx] = ent;
+
+ /* If this chunk was previously on the temporary list and therefore
+ * not in the hash table, remove it from the temporary list.
+ * Otherwise clear the old hash table slot. */
+ if(ent->tmp_prev) {
+ HDassert(tmp_head.tmp_next);
+ HDassert(tmp_tail != &tmp_head);
+ ent->tmp_prev->tmp_next = ent->tmp_next;
+ if(ent->tmp_next) {
+ ent->tmp_next->tmp_prev = ent->tmp_prev;
+ ent->tmp_next = NULL;
+ } /* end if */
+ else {
+ HDassert(tmp_tail == ent);
+ tmp_tail = ent->tmp_prev;
+ } /* end else */
+ ent->tmp_prev = NULL;
+ } /* end if */
+ else
+ rdcc->slot[old_idx] = NULL;
+ } /* end if */
+ } /* end for */
+
+ /* tmp_tail is no longer needed, and will be invalidated by
+ * H5D_chunk_cache_evict anyways. */
+ tmp_tail = NULL;
+
+ /* Evict chunks that are still on the temporary list */
+ while(tmp_head.tmp_next) {
+ ent = tmp_head.tmp_next;
+
+ /* Remove the old entry from the cache */
+ if(H5D__chunk_cache_evict(dset, dxpl_id, dxpl_cache, ent, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks")
+ } /* end while */
+
+done:
+ /* Remove temporary list from rdcc */
+ rdcc->tmp_head = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_update_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_copy_cb
+ *
+ * Purpose: Copy chunked raw data from source file and insert to the
+ * index in the destination file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * August 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__chunk_copy_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_chunk_it_ud3_t *udata = (H5D_chunk_it_ud3_t *)_udata; /* User data for callback */
+ H5D_chunk_ud_t udata_dst; /* User data about new destination chunk */
+ hbool_t is_vlen = FALSE; /* Whether datatype is variable-length */
+ hbool_t fix_ref = FALSE; /* Whether to fix up references in the dest. file */
+ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */
+
+ /* General information about chunk copy */
+ void *bkg = udata->bkg; /* Background buffer for datatype conversion */
+ void *buf = udata->buf; /* Chunk buffer for I/O & datatype conversions */
+ size_t buf_size = udata->buf_size; /* Size of chunk buffer */
+ const H5O_pline_t *pline = udata->pline; /* I/O pipeline for applying filters */
+
+ /* needed for commpressed variable length data */
+ hbool_t must_filter = FALSE; /* Whether chunk must be filtered during copy */
+ size_t nbytes; /* Size of chunk in file (in bytes) */
+ H5Z_cb_t cb_struct; /* Filter failure callback struct */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get 'size_t' local value for number of bytes in chunk */
+ H5_CHECKED_ASSIGN(nbytes, size_t, chunk_rec->nbytes, uint32_t);
+
+ /* Check parameter for type conversion */
+ if(udata->do_convert) {
+ if(H5T_detect_class(udata->dt_src, H5T_VLEN, FALSE) > 0)
+ is_vlen = TRUE;
+ else if((H5T_get_class(udata->dt_src, FALSE) == H5T_REFERENCE) && (udata->file_src != udata->idx_info_dst->f))
+ fix_ref = TRUE;
+ else
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy dataset elements")
+ } /* end if */
+
+ /* Check for filtered chunks */
+ if((is_vlen || fix_ref) && pline && pline->nused) {
+ /* Check if we should disable filters on this chunk */
+ if(udata->common.layout->flags
+ & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) {
+ /* Check if the chunk is an edge chunk, and disable filters if so */
+ if(!H5D__chunk_is_partial_edge_chunk(udata->dset_ndims, udata->common.layout->dim, chunk_rec->scaled, udata->dset_dims))
+ must_filter = TRUE;
+ } /* end if */
+ else
+ must_filter = TRUE;
+ } /* end if */
+
+ /* Resize the buf if it is too small to hold the data */
+ if(nbytes > buf_size) {
+ void *new_buf; /* New buffer for data */
+
+ /* Re-allocate memory for copying the chunk */
+ if(NULL == (new_buf = H5MM_realloc(udata->buf, nbytes)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed for raw data chunk")
+ udata->buf = new_buf;
+ if(udata->bkg) {
+ if(NULL == (new_buf = H5MM_realloc(udata->bkg, nbytes)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed for raw data chunk")
+ udata->bkg = new_buf;
+ if(!udata->cpy_info->expand_ref)
+ HDmemset((uint8_t *)udata->bkg + buf_size, 0, (size_t)(nbytes - buf_size));
+
+ bkg = udata->bkg;
+ } /* end if */
+
+ buf = udata->buf;
+ udata->buf_size = buf_size = nbytes;
+ } /* end if */
+
+ /* read chunk data from the source file */
+ if(H5F_block_read(udata->file_src, H5FD_MEM_DRAW, chunk_rec->chunk_addr, nbytes, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, H5_ITER_ERROR, "unable to read raw data chunk")
+
+ /* Need to uncompress variable-length & reference data elements */
+ if(must_filter) {
+ unsigned filter_mask = chunk_rec->filter_mask;
+
+ cb_struct.func = NULL; /* no callback function when failed */
+ if(H5Z_pipeline(pline, H5Z_FLAG_REVERSE, &filter_mask, H5Z_NO_EDC, cb_struct, &nbytes, &buf_size, &buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "data pipeline read failed")
+ } /* end if */
+
+ /* Perform datatype conversion, if necessary */
+ if(is_vlen) {
+ H5T_path_t *tpath_src_mem = udata->tpath_src_mem;
+ H5T_path_t *tpath_mem_dst = udata->tpath_mem_dst;
+ H5S_t *buf_space = udata->buf_space;
+ hid_t tid_src = udata->tid_src;
+ hid_t tid_dst = udata->tid_dst;
+ hid_t tid_mem = udata->tid_mem;
+ void *reclaim_buf = udata->reclaim_buf;
+ size_t reclaim_buf_size = udata->reclaim_buf_size;
+
+ /* Convert from source file to memory */
+ H5_CHECK_OVERFLOW(udata->nelmts, uint32_t, size_t);
+ if(H5T_convert(tpath_src_mem, tid_src, tid_mem, (size_t)udata->nelmts, (size_t)0, (size_t)0, buf, bkg, udata->idx_info_dst->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "datatype conversion failed")
+
+ /* Copy into another buffer, to reclaim memory later */
+ HDmemcpy(reclaim_buf, buf, reclaim_buf_size);
+
+ /* Set background buffer to all zeros */
+ HDmemset(bkg, 0, buf_size);
+
+ /* Convert from memory to destination file */
+ if(H5T_convert(tpath_mem_dst, tid_mem, tid_dst, udata->nelmts, (size_t)0, (size_t)0, buf, bkg, udata->idx_info_dst->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "datatype conversion failed")
+
+ /* Reclaim space from variable length data */
+ if(H5D_vlen_reclaim(tid_mem, buf_space, udata->idx_info_dst->dxpl_id, reclaim_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, H5_ITER_ERROR, "unable to reclaim variable-length data")
+ } /* end if */
+ else if(fix_ref) {
+ /* Check for expanding references */
+ /* (background buffer has already been zeroed out, if not expanding) */
+ if(udata->cpy_info->expand_ref) {
+ size_t ref_count;
+
+ /* Determine # of reference elements to copy */
+ ref_count = nbytes / H5T_get_size(udata->dt_src);
+
+ /* Copy the reference elements */
+ if(H5O_copy_expand_ref(udata->file_src, buf, udata->idx_info_dst->dxpl_id, udata->idx_info_dst->f, bkg, ref_count, H5T_get_ref_type(udata->dt_src), udata->cpy_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy reference attribute")
+ } /* end if */
+
+ /* After fix ref, copy the new reference elements to the buffer to write out */
+ HDmemcpy(buf, bkg, buf_size);
+ } /* end if */
+
+ /* Set up destination chunk callback information for insertion */
+ udata_dst.common.layout = udata->idx_info_dst->layout;
+ udata_dst.common.storage = udata->idx_info_dst->storage;
+ udata_dst.common.scaled = chunk_rec->scaled;
+ udata_dst.chunk_block.offset = HADDR_UNDEF;
+ udata_dst.chunk_block.length = chunk_rec->nbytes;
+ udata_dst.filter_mask = chunk_rec->filter_mask;
+
+ /* Need to compress variable-length & reference data elements before writing to file */
+ if(must_filter) {
+ if(H5Z_pipeline(pline, 0, &(udata_dst.filter_mask), H5Z_NO_EDC, cb_struct, &nbytes, &buf_size, &buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "output pipeline failed")
+#if H5_SIZEOF_SIZE_T > 4
+ /* Check for the chunk expanding too much to encode in a 32-bit value */
+ if(nbytes > ((size_t)0xffffffff))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, H5_ITER_ERROR, "chunk too large for 32-bit length")
+#endif /* H5_SIZEOF_SIZE_T > 4 */
+ H5_CHECKED_ASSIGN(udata_dst.chunk_block.length, uint32_t, nbytes, size_t);
+ udata->buf = buf;
+ udata->buf_size = buf_size;
+ } /* end if */
+
+ udata_dst.chunk_idx = H5VM_array_offset_pre(udata_dst.common.layout->ndims - 1,
+ udata_dst.common.layout->max_down_chunks, udata_dst.common.scaled);
+
+ /* Allocate chunk in the file */
+ if(H5D__chunk_file_alloc(udata->idx_info_dst, NULL, &udata_dst.chunk_block, &need_insert, udata_dst.common.scaled) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert/resize chunk on chunk level")
+
+ /* Write chunk data to destination file */
+ HDassert(H5F_addr_defined(udata_dst.chunk_block.offset));
+ if(H5F_block_write(udata->idx_info_dst->f, H5FD_MEM_DRAW, udata_dst.chunk_block.offset, nbytes, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, H5_ITER_ERROR, "unable to write raw data to file")
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(udata->idx_info_dst->dxpl_id, H5AC__COPIED_TAG, H5_ITER_ERROR);
+
+ /* Insert chunk record into index */
+ if(need_insert && udata->idx_info_dst->storage->ops->insert)
+ if((udata->idx_info_dst->storage->ops->insert)(udata->idx_info_dst, &udata_dst, NULL) < 0)
+ HGOTO_ERROR_TAG(H5E_DATASET, H5E_CANTINSERT, H5_ITER_ERROR, "unable to insert chunk addr into index")
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(H5_ITER_ERROR);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_copy_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_copy
+ *
+ * Purpose: Copy chunked storage from SRC file to DST file.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Peter Cao
+ * August 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_copy(H5F_t *f_src, H5O_storage_chunk_t *storage_src,
+ H5O_layout_chunk_t *layout_src, H5F_t *f_dst, H5O_storage_chunk_t *storage_dst,
+ const H5S_extent_t *ds_extent_src, const H5T_t *dt_src,
+ const H5O_pline_t *pline_src, H5O_copy_t *cpy_info, hid_t dxpl_id)
+{
+ H5D_chunk_it_ud3_t udata; /* User data for iteration callback */
+ H5D_chk_idx_info_t idx_info_dst; /* Dest. chunked index info */
+ H5D_chk_idx_info_t idx_info_src; /* Source chunked index info */
+ int sndims; /* Rank of dataspace */
+ hsize_t curr_dims[H5O_LAYOUT_NDIMS]; /* Curr. size of dataset dimensions */
+ hsize_t max_dims[H5O_LAYOUT_NDIMS]; /* Curr. size of dataset dimensions */
+ H5O_pline_t _pline; /* Temporary pipeline info */
+ const H5O_pline_t *pline; /* Pointer to pipeline info to use */
+ H5T_path_t *tpath_src_mem = NULL, *tpath_mem_dst = NULL; /* Datatype conversion paths */
+ hid_t tid_src = -1; /* Datatype ID for source datatype */
+ hid_t tid_dst = -1; /* Datatype ID for destination datatype */
+ hid_t tid_mem = -1; /* Datatype ID for memory datatype */
+ size_t buf_size; /* Size of copy buffer */
+ size_t reclaim_buf_size; /* Size of reclaim buffer */
+ void *buf = NULL; /* Buffer for copying data */
+ void *bkg = NULL; /* Buffer for background during type conversion */
+ void *reclaim_buf = NULL; /* Buffer for reclaiming data */
+ H5S_t *buf_space = NULL; /* Dataspace describing buffer */
+ hid_t sid_buf = -1; /* ID for buffer dataspace */
+ uint32_t nelmts = 0; /* Number of elements in buffer */
+ hbool_t do_convert = FALSE; /* Indicate that type conversions should be performed */
+ hbool_t copy_setup_done = FALSE; /* Indicate that 'copy setup' is done */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(f_src);
+ HDassert(storage_src);
+ H5D_CHUNK_STORAGE_INDEX_CHK(storage_src);
+ HDassert(layout_src);
+ HDassert(f_dst);
+ HDassert(storage_dst);
+ H5D_CHUNK_STORAGE_INDEX_CHK(storage_dst);
+ HDassert(ds_extent_src);
+ HDassert(dt_src);
+
+ /* Initialize the temporary pipeline info */
+ if(NULL == pline_src) {
+ HDmemset(&_pline, 0, sizeof(_pline));
+ pline = &_pline;
+ } /* end if */
+ else
+ pline = pline_src;
+
+ /* Layout is not created in the destination file, reset index address */
+ if(H5D_chunk_idx_reset(storage_dst, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to reset chunked storage index in dest")
+
+ /* Initialize layout information */
+ {
+ unsigned ndims; /* Rank of dataspace */
+
+ /* Get the dim info for dataset */
+ if((sndims = H5S_extent_get_dims(ds_extent_src, curr_dims, max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions")
+ H5_CHECKED_ASSIGN(ndims, unsigned, sndims, int);
+
+ /* Set the source layout chunk information */
+ if(H5D__chunk_set_info_real(layout_src, ndims, curr_dims, max_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set layout's chunk info")
+ } /* end block */
+
+ /* Compose source & dest chunked index info structs */
+ idx_info_src.f = f_src;
+ idx_info_src.dxpl_id = dxpl_id;
+ idx_info_src.pline = pline;
+ idx_info_src.layout = layout_src;
+ idx_info_src.storage = storage_src;
+
+ idx_info_dst.f = f_dst;
+ idx_info_dst.dxpl_id = dxpl_id;
+ idx_info_dst.pline = pline; /* Use same I/O filter pipeline for dest. */
+ idx_info_dst.layout = layout_src /* Use same layout for dest. */;
+ idx_info_dst.storage = storage_dst;
+
+ /* Call the index-specific "copy setup" routine */
+ if((storage_src->ops->copy_setup)(&idx_info_src, &idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up index-specific chunk copying information")
+ copy_setup_done = TRUE;
+
+ /* Create datatype ID for src datatype */
+ if((tid_src = H5I_register(H5I_DATATYPE, dt_src, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register source file datatype")
+
+ /* If there's a VLEN source datatype, set up type conversion information */
+ if(H5T_detect_class(dt_src, H5T_VLEN, FALSE) > 0) {
+ H5T_t *dt_dst; /* Destination datatype */
+ H5T_t *dt_mem; /* Memory datatype */
+ size_t mem_dt_size; /* Memory datatype size */
+ size_t tmp_dt_size; /* Temp. datatype size */
+ size_t max_dt_size; /* Max atatype size */
+ hsize_t buf_dim; /* Dimension for buffer */
+ unsigned u;
+
+ /* create a memory copy of the variable-length datatype */
+ if(NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+ if((tid_mem = H5I_register(H5I_DATATYPE, dt_mem, FALSE)) < 0) {
+ (void)H5T_close(dt_mem);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register memory datatype")
+ } /* end if */
+
+ /* create variable-length datatype at the destinaton file */
+ if(NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+ if(H5T_set_loc(dt_dst, f_dst, H5T_LOC_DISK) < 0) {
+ (void)H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
+ } /* end if */
+ if((tid_dst = H5I_register(H5I_DATATYPE, dt_dst, FALSE)) < 0) {
+ (void)H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register destination file datatype")
+ } /* end if */
+
+ /* Set up the conversion functions */
+ if(NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes")
+ if(NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes")
+
+ /* Determine largest datatype size */
+ if(0 == (max_dt_size = H5T_get_size(dt_src)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ if(0 == (mem_dt_size = H5T_get_size(dt_mem)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(max_dt_size, mem_dt_size);
+ if(0 == (tmp_dt_size = H5T_get_size(dt_dst)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(max_dt_size, tmp_dt_size);
+
+ /* Compute the number of elements per chunk */
+ nelmts = 1;
+ for(u = 0; u < (layout_src->ndims - 1); u++)
+ nelmts *= layout_src->dim[u];
+
+ /* Create the space and set the initial extent */
+ buf_dim = nelmts;
+ if(NULL == (buf_space = H5S_create_simple((unsigned)1, &buf_dim, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Atomize */
+ if((sid_buf = H5I_register(H5I_DATASPACE, buf_space, FALSE)) < 0) {
+ (void)H5S_close(buf_space);
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ } /* end if */
+
+ /* Set initial buffer sizes */
+ buf_size = nelmts * max_dt_size;
+ reclaim_buf_size = nelmts * mem_dt_size;
+
+ /* Allocate memory for reclaim buf */
+ if(NULL == (reclaim_buf = H5MM_malloc(reclaim_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
+
+ /* Indicate that type conversion should be performed */
+ do_convert = TRUE;
+ } /* end if */
+ else {
+ if(H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) {
+ /* Indicate that type conversion should be performed */
+ do_convert = TRUE;
+ } /* end if */
+
+ H5_CHECKED_ASSIGN(buf_size, size_t, layout_src->size, uint32_t);
+ reclaim_buf_size = 0;
+ } /* end else */
+
+ /* Set up conversion buffer, if appropriate */
+ if(do_convert) {
+ /* Allocate background memory for converting the chunk */
+ if(NULL == (bkg = H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
+
+ /* Check for reference datatype and no expanding references & clear background buffer */
+ if(!cpy_info->expand_ref &&
+ ((H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) && (f_src != f_dst)))
+ /* Reset value to zero */
+ HDmemset(bkg, 0, buf_size);
+ } /* end if */
+
+ /* Allocate memory for copying the chunk */
+ if(NULL == (buf = H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk")
+
+ /* Initialize the callback structure for the source */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.common.layout = layout_src;
+ udata.common.storage = storage_src;
+ udata.file_src = f_src;
+ udata.idx_info_dst = &idx_info_dst;
+ udata.buf = buf;
+ udata.bkg = bkg;
+ udata.buf_size = buf_size;
+ udata.tid_src = tid_src;
+ udata.tid_mem = tid_mem;
+ udata.tid_dst = tid_dst;
+ udata.dt_src = dt_src;
+ udata.do_convert = do_convert;
+ udata.tpath_src_mem = tpath_src_mem;
+ udata.tpath_mem_dst = tpath_mem_dst;
+ udata.reclaim_buf = reclaim_buf;
+ udata.reclaim_buf_size = reclaim_buf_size;
+ udata.buf_space = buf_space;
+ udata.nelmts = nelmts;
+ udata.pline = pline;
+ udata.dset_ndims = (unsigned)sndims;
+ udata.dset_dims = curr_dims;
+ udata.cpy_info = cpy_info;
+
+ /* Iterate over chunks to copy data */
+ if((storage_src->ops->iterate)(&idx_info_src, H5D__chunk_copy_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk index to copy data")
+
+ /* I/O buffers may have been re-allocated */
+ buf = udata.buf;
+ bkg = udata.bkg;
+
+done:
+ if(sid_buf > 0 && H5I_dec_ref(sid_buf) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't decrement temporary dataspace ID")
+ if(tid_src > 0 && H5I_dec_ref(tid_src) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_dst > 0 && H5I_dec_ref(tid_dst) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_mem > 0 && H5I_dec_ref(tid_mem) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(buf)
+ H5MM_xfree(buf);
+ if(bkg)
+ H5MM_xfree(bkg);
+ if(reclaim_buf)
+ H5MM_xfree(reclaim_buf);
+
+ /* Clean up any index information */
+ if(copy_setup_done)
+ if(storage_src->ops->copy_shutdown && (storage_src->ops->copy_shutdown)(storage_src, storage_dst, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to shut down index copying info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_bh_info
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * June 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, H5O_layout_t *layout,
+ hsize_t *index_size)
+{
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5S_t *space = NULL; /* Dataset's dataspace */
+ H5O_pline_t pline; /* I/O pipeline message */
+ H5O_storage_chunk_t *sc = &(layout->storage.u.chunk);
+ htri_t exists; /* Flag if header message of interest exists */
+ hbool_t idx_info_init = FALSE; /* Whether the chunk index info has been initialized */
+ hbool_t pline_read = FALSE; /* Whether the I/O pipeline message was read */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(layout);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+ HDassert(index_size);
+
+ /* Check for I/O pipeline message */
+ if((exists = H5O_msg_exists_oh(oh, H5O_PLINE_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header")
+ else if(exists) {
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_PLINE_ID, &pline))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't find I/O pipeline message")
+ pline_read = TRUE;
+ } /* end else if */
+ else
+ HDmemset(&pline, 0, sizeof(pline));
+
+ /* Compose chunked index info struct */
+ idx_info.f = loc->file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &pline;
+ idx_info.layout = &layout->u.chunk;
+ idx_info.storage = &layout->storage.u.chunk;
+
+ /* Get the dataspace for the dataset */
+ if(NULL == (space = H5S_read(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load dataspace info from dataset header")
+
+ /* Allocate any indexing structures */
+ if(layout->storage.u.chunk.ops->init && (layout->storage.u.chunk.ops->init)(&idx_info, space, loc->addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize indexing information")
+ idx_info_init = TRUE;
+
+ /* Get size of index structure */
+ if(layout->storage.u.chunk.ops->size && (layout->storage.u.chunk.ops->size)(&idx_info, index_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve chunk index info")
+
+done:
+ /* Free resources, if they've been initialized */
+ if(idx_info_init && layout->storage.u.chunk.ops->dest &&
+ (layout->storage.u.chunk.ops->dest)(&idx_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
+ if(pline_read && H5O_msg_reset(H5O_PLINE_ID, &pline) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message")
+ if(space && H5S_close(space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_bh_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_dump_index_cb
+ *
+ * Purpose: If the UDATA.STREAM member is non-null then debugging
+ * information is written to that stream.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 21, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__chunk_dump_index_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_chunk_it_ud4_t *udata = (H5D_chunk_it_ud4_t *)_udata; /* User data from caller */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(udata->stream) {
+ unsigned u; /* Local index variable */
+
+ /* Print header if not already displayed */
+ if(!udata->header_displayed) {
+ HDfprintf(udata->stream, " Flags Bytes Address Logical Offset\n");
+ HDfprintf(udata->stream, " ========== ======== ========== ==============================\n");
+
+ /* Set flag that the headers has been printed */
+ udata->header_displayed = TRUE;
+ } /* end if */
+
+ /* Print information about this chunk */
+ HDfprintf(udata->stream, " 0x%08x %8Zu %10a [", chunk_rec->filter_mask, chunk_rec->nbytes, chunk_rec->chunk_addr);
+ for(u = 0; u < udata->ndims; u++)
+ HDfprintf(udata->stream, "%s%Hu", (u ? ", " : ""), (chunk_rec->scaled[u] * udata->chunk_dim[u]));
+ HDfputs("]\n", udata->stream);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(H5_ITER_CONT)
+} /* H5D__chunk_dump_index_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_dump_index
+ *
+ * Purpose: Prints information about the storage index to the specified
+ * stream.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 28, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_dump_index(H5D_t *dset, hid_t dxpl_id, FILE *stream)
+{
+ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+ H5D_CHUNK_STORAGE_INDEX_CHK(sc);
+
+ /* Only display info if stream is defined */
+ if(stream) {
+ H5D_chk_idx_info_t idx_info; /* Chunked index info */
+ H5D_chunk_it_ud4_t udata; /* User data for callback */
+
+ /* Display info for index */
+ if((dset->shared->layout.storage.u.chunk.ops->dump)(&dset->shared->layout.storage.u.chunk, stream) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to dump chunk index info")
+
+ /* Compose chunked index info struct */
+ idx_info.f = dset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dset->shared->dcpl_cache.pline;
+ idx_info.layout = &dset->shared->layout.u.chunk;
+ idx_info.storage = &dset->shared->layout.storage.u.chunk;
+
+ /* Set up user data for callback */
+ udata.stream = stream;
+ udata.header_displayed = FALSE;
+ udata.ndims = dset->shared->layout.u.chunk.ndims;
+ udata.chunk_dim = dset->shared->layout.u.chunk.dim;
+
+ /* Iterate over index and dump chunk info */
+ if((dset->shared->layout.storage.u.chunk.ops->iterate)(&idx_info, H5D__chunk_dump_index_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk index to dump chunk info")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_dump_index() */
+
+#ifdef H5D_CHUNK_DEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_stats
+ *
+ * Purpose: Print raw data cache statistics to the debug stream. If
+ * HEADERS is non-zero then print table column headers,
+ * otherwise assume that the H5AC layer has already printed them.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_stats(const H5D_t *dset, hbool_t headers)
+{
+ H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk);
+ double miss_rate;
+ char ascii[32];
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ if (!H5DEBUG(AC))
+ HGOTO_DONE(SUCCEED)
+
+ if (headers) {
+ fprintf(H5DEBUG(AC), "H5D: raw data cache statistics\n");
+ fprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s+%-8s\n",
+ "Layer", "Hits", "Misses", "MissRate", "Inits", "Flushes");
+ fprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s-%-8s\n",
+ "-----", "----", "------", "--------", "-----", "-------");
+ }
+
+#ifdef H5AC_DEBUG
+ if (H5DEBUG(AC)) headers = TRUE;
+#endif
+
+ if (headers) {
+ if (rdcc->stats.nhits>0 || rdcc->stats.nmisses>0) {
+ miss_rate = 100.0 * rdcc->stats.nmisses /
+ (rdcc->stats.nhits + rdcc->stats.nmisses);
+ } else {
+ miss_rate = 0.0;
+ }
+ if (miss_rate > 100) {
+ sprintf(ascii, "%7d%%", (int) (miss_rate + 0.5));
+ } else {
+ sprintf(ascii, "%7.2f%%", miss_rate);
+ }
+
+ fprintf(H5DEBUG(AC), " %-18s %8u %8u %7s %8d+%-9ld\n",
+ "raw data chunks", rdcc->stats.nhits, rdcc->stats.nmisses, ascii,
+ rdcc->stats.ninits, (long)(rdcc->stats.nflushes)-(long)(rdcc->stats.ninits));
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_stats() */
+#endif /* H5D_CHUNK_DEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__nonexistent_readvv_cb
+ *
+ * Purpose: Callback operation for performing fill value I/O operation
+ * on memory buffer.
+ *
+ * Note: This algorithm is pretty inefficient about initializing and
+ * terminating the fill buffer info structure and it would be
+ * faster to refactor this into a "real" initialization routine,
+ * and a "vectorized fill" routine. -QAK
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 30 Sep 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__nonexistent_readvv_cb(hsize_t H5_ATTR_UNUSED dst_off, hsize_t src_off, size_t len,
+ void *_udata)
+{
+ H5D_chunk_readvv_ud_t *udata = (H5D_chunk_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Initialize the fill value buffer */
+ if(H5D__fill_init(&fb_info, (udata->rbuf + src_off), NULL, NULL, NULL, NULL,
+ &udata->dset->shared->dcpl_cache.fill, udata->dset->shared->type,
+ udata->dset->shared->type_id, (size_t)0, len, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
+ fb_info_init = TRUE;
+
+ /* Check for VL datatype & fill the buffer with VL datatype fill values */
+ if(fb_info.has_vlen_fill_type && H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
+
+done:
+ /* Release the fill buffer info, if it's been initialized */
+ if(fb_info_init && H5D__fill_term(&fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__nonexistent_readvv_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__nonexistent_readvv
+ *
+ * Purpose: When the chunk doesn't exist on disk and the chunk is bigger
+ * than the cache size, performs fill value I/O operation on
+ * memory buffer, advancing through two I/O vectors, until one
+ * runs out.
+ *
+ * Note: This algorithm is pretty inefficient about initializing and
+ * terminating the fill buffer info structure and it would be
+ * faster to refactor this into a "real" initialization routine,
+ * and a "vectorized fill" routine. -QAK
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 6 Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__nonexistent_readvv(const H5D_io_info_t *io_info,
+ size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_off_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
+{
+ H5D_chunk_readvv_ud_t udata; /* User data for H5VM_opvv() operator */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(chunk_curr_seq);
+ HDassert(chunk_len_arr);
+ HDassert(chunk_off_arr);
+ HDassert(mem_curr_seq);
+ HDassert(mem_len_arr);
+ HDassert(mem_off_arr);
+
+ /* Set up user data for H5VM_opvv() */
+ udata.rbuf = (unsigned char *)io_info->u.rbuf;
+ udata.dset = io_info->dset;
+ udata.dxpl_id = io_info->md_dxpl_id;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__nonexistent_readvv_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized fill value init")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__nonexistent_readvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_is_partial_edge_chunk
+ *
+ * Purpose: Checks to see if the chunk is a partial edge chunk.
+ * Either dset or (dset_dims and dset_ndims) must be
+ * provided.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 19 Nov 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__chunk_is_partial_edge_chunk(unsigned dset_ndims, const uint32_t *chunk_dims,
+ const hsize_t scaled[], const hsize_t *dset_dims)
+{
+ unsigned u; /* Local index variable */
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(scaled);
+ HDassert(dset_ndims > 0);
+ HDassert(dset_dims);
+ HDassert(chunk_dims);
+
+ /* check if this is a partial edge chunk */
+ for(u = 0; u < dset_ndims; u++)
+ if(((scaled[u] + 1) * chunk_dims[u]) > dset_dims[u])
+ HGOTO_DONE(TRUE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_is_partial_edge_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_file_alloc()
+ *
+ * Purpose: Chunk allocation:
+ * Create the chunk if it doesn't exist, or reallocate the
+ * chunk if its size changed.
+ * The coding is moved and modified from each index structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_file_alloc(const H5D_chk_idx_info_t *idx_info, const H5F_block_t *old_chunk,
+ H5F_block_t *new_chunk, hbool_t *need_insert, hsize_t scaled[])
+{
+ hbool_t alloc_chunk = FALSE; /* Whether to allocate chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(new_chunk);
+ HDassert(need_insert);
+
+ *need_insert = FALSE;
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ /* Sanity/error checking block */
+ HDassert(idx_info->storage->idx_type != H5D_CHUNK_IDX_NONE);
+ {
+ unsigned allow_chunk_size_len; /* Allowed size of encoded chunk size */
+ unsigned new_chunk_size_len; /* Size of encoded chunk size */
+
+ /* Compute the size required for encoding the size of a chunk, allowing
+ * for an extra byte, in case the filter makes the chunk larger.
+ */
+ allow_chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)(idx_info->layout->size)) + 8) / 8);
+ if(allow_chunk_size_len > 8)
+ allow_chunk_size_len = 8;
+
+ /* Compute encoded size of chunk */
+ new_chunk_size_len = (H5VM_log2_gen((uint64_t)(new_chunk->length)) + 8) / 8;
+ if(new_chunk_size_len > 8)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "encoded chunk size is more than 8 bytes?!?")
+
+ /* Check if the chunk became too large to be encoded */
+ if(new_chunk_size_len > allow_chunk_size_len)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "chunk size can't be encoded")
+ } /* end block */
+
+ if(old_chunk && H5F_addr_defined(old_chunk->offset)) {
+ /* Sanity check */
+ HDassert(!H5F_addr_defined(new_chunk->offset) || H5F_addr_eq(new_chunk->offset, old_chunk->offset));
+
+ /* Check for chunk being same size */
+ if(new_chunk->length != old_chunk->length) {
+ /* Release previous chunk */
+ /* Only free the old location if not doing SWMR writes - otherwise
+ * we must keep the old chunk around in case a reader has an
+ * outdated version of the B-tree node
+ */
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE))
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, old_chunk->offset, old_chunk->length) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ alloc_chunk = TRUE;
+ } /* end if */
+ else {
+ /* Don't need to reallocate chunk, but send its address back up */
+ if(!H5F_addr_defined(new_chunk->offset))
+ new_chunk->offset = old_chunk->offset;
+ } /* end else */
+ } /* end if */
+ else {
+ HDassert(!H5F_addr_defined(new_chunk->offset));
+ alloc_chunk = TRUE;
+ } /* end else */
+ } /* end if */
+ else {
+ HDassert(!H5F_addr_defined(new_chunk->offset));
+ HDassert(new_chunk->length == idx_info->layout->size);
+ alloc_chunk = TRUE;
+ } /* end else */
+
+ /* Actually allocate space for the chunk in the file */
+ if(alloc_chunk) {
+ switch(idx_info->storage->idx_type) {
+ case H5D_CHUNK_IDX_NONE:
+ {
+ H5D_chunk_ud_t udata;
+
+ udata.common.scaled = scaled;
+ if((idx_info->storage->ops->get_addr)(idx_info, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address")
+ new_chunk->offset = udata.chunk_block.offset;
+ HDassert(new_chunk->length == udata.chunk_block.length);
+ break;
+ }
+
+ case H5D_CHUNK_IDX_EARRAY:
+ case H5D_CHUNK_IDX_FARRAY:
+ case H5D_CHUNK_IDX_BT2:
+ case H5D_CHUNK_IDX_BTREE:
+ case H5D_CHUNK_IDX_SINGLE:
+ HDassert(new_chunk->length > 0);
+ H5_CHECK_OVERFLOW(new_chunk->length, /*From: */uint32_t, /*To: */hsize_t);
+ new_chunk->offset = H5MF_alloc(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, (hsize_t)new_chunk->length);
+ if(!H5F_addr_defined(new_chunk->offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "file allocation failed")
+ *need_insert = TRUE;
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HDassert(0 && "This should never be executed!");
+ break;
+ } /* end switch */
+ } /* end if */
+
+ HDassert(H5F_addr_defined(new_chunk->offset));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_file_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_format_convert_cb
+ *
+ * Purpose: Callback routine to insert chunk address into v1 B-tree
+ * chunk index.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__chunk_format_convert_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_chunk_it_ud5_t *udata = (H5D_chunk_it_ud5_t *)_udata; /* User data */
+ H5D_chk_idx_info_t *new_idx_info; /* The new chunk index information */
+ H5D_chunk_ud_t insert_udata; /* Chunk information to be inserted */
+ haddr_t chunk_addr; /* Chunk address */
+ size_t nbytes; /* Chunk size */
+ void *buf = NULL; /* Pointer to buffer of chunk data */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Set up */
+ new_idx_info = udata->new_idx_info;
+ H5_CHECKED_ASSIGN(nbytes, size_t, chunk_rec->nbytes, uint32_t);
+ chunk_addr = chunk_rec->chunk_addr;
+
+ if(new_idx_info->pline->nused &&
+ (new_idx_info->layout->flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) &&
+ (H5D__chunk_is_partial_edge_chunk(udata->dset_ndims, new_idx_info->layout->dim, chunk_rec->scaled, udata->dset_dims))) {
+ /* This is a partial non-filtered edge chunk */
+ /* Convert the chunk to a filtered edge chunk for v1 B-tree chunk index */
+
+ unsigned filter_mask = chunk_rec->filter_mask;
+ H5Z_cb_t cb_struct; /* Filter failure callback struct */
+ size_t read_size = nbytes; /* Bytes to read */
+
+ HDassert(read_size == new_idx_info->layout->size);
+
+ cb_struct.func = NULL; /* no callback function when failed */
+
+ /* Allocate buffer for chunk data */
+ if(NULL == (buf = H5MM_malloc(read_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed for raw data chunk")
+
+ /* Read the non-filtered edge chunk */
+ if(H5F_block_read(new_idx_info->f, H5FD_MEM_DRAW, chunk_addr, read_size, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, H5_ITER_ERROR, "unable to read raw data chunk")
+
+ /* Pass the chunk through the pipeline */
+ if(H5Z_pipeline(new_idx_info->pline, 0, &filter_mask, H5Z_NO_EDC, cb_struct, &nbytes, &read_size, &buf) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, H5_ITER_ERROR, "output pipeline failed")
+
+#if H5_SIZEOF_SIZE_T > 4
+ /* Check for the chunk expanding too much to encode in a 32-bit value */
+ if(nbytes > ((size_t)0xffffffff))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, H5_ITER_ERROR, "chunk too large for 32-bit length")
+#endif /* H5_SIZEOF_SIZE_T > 4 */
+
+ /* Allocate space for the filtered chunk */
+ if((chunk_addr = H5MF_alloc(new_idx_info->f, H5FD_MEM_DRAW, new_idx_info->dxpl_id, (hsize_t)nbytes)) == HADDR_UNDEF)
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, H5_ITER_ERROR, "file allocation failed for filtered chunk")
+ HDassert(H5F_addr_defined(chunk_addr));
+
+ /* Write the filtered chunk to disk */
+ if(H5F_block_write(new_idx_info->f, H5FD_MEM_DRAW, chunk_addr, nbytes, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, H5_ITER_ERROR, "unable to write raw data to file")
+ } /* end if */
+
+ /* Set up chunk information for insertion to chunk index */
+ insert_udata.chunk_block.offset = chunk_addr;
+ insert_udata.chunk_block.length = nbytes;
+ insert_udata.filter_mask = chunk_rec->filter_mask;
+ insert_udata.common.scaled = chunk_rec->scaled;
+ insert_udata.common.layout = new_idx_info->layout;
+ insert_udata.common.storage = new_idx_info->storage;
+
+ /* Insert chunk into the v1 B-tree chunk index */
+ if((new_idx_info->storage->ops->insert)(new_idx_info, &insert_udata, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, H5_ITER_ERROR, "unable to insert chunk addr into index")
+
+done:
+ if(buf)
+ H5MM_xfree(buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__chunk_format_convert_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_format_convert
+ *
+ * Purpose: Iterate over the chunks for the current chunk index and insert the
+ * the chunk addresses into v1 B-tree chunk index via callback.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_format_convert(H5D_t *dset, H5D_chk_idx_info_t *idx_info, H5D_chk_idx_info_t *new_idx_info)
+{
+ H5D_chunk_it_ud5_t udata; /* User data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dset);
+
+ /* Set up user data */
+ udata.new_idx_info = new_idx_info;
+ udata.dset_ndims = dset->shared->ndims;
+ udata.dset_dims = dset->shared->curr_dims;
+
+ /* terate over the chunks in the current index and insert the chunk addresses into version 1 B-tree index */
+ if((idx_info->storage->ops->iterate)(idx_info, H5D__chunk_format_convert_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk index to chunk info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_format_convert() */
+
diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c
new file mode 100644
index 0000000..2578975
--- /dev/null
+++ b/src/H5Dcompact.c
@@ -0,0 +1,597 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <slu@ncsa.uiuc.edu>
+ * August 5, 2002
+ *
+ * Purpose: Compact dataset I/O functions. These routines are similar
+ * H5D_contig_* and H5D_chunk_*.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Layout operation callbacks */
+static herr_t H5D__compact_construct(H5F_t *f, H5D_t *dset);
+static hbool_t H5D__compact_is_space_alloc(const H5O_storage_t *storage);
+static herr_t H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *cm);
+static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]);
+static ssize_t H5D__compact_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]);
+static herr_t H5D__compact_flush(H5D_t *dset, hid_t dxpl_id);
+static herr_t H5D__compact_dest(H5D_t *dset, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Compact storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_COMPACT[1] = {{
+ H5D__compact_construct,
+ NULL,
+ H5D__compact_is_space_alloc,
+ H5D__compact_io_init,
+ H5D__contig_read,
+ H5D__contig_write,
+#ifdef H5_HAVE_PARALLEL
+ NULL,
+ NULL,
+#endif /* H5_HAVE_PARALLEL */
+ H5D__compact_readvv,
+ H5D__compact_writevv,
+ H5D__compact_flush,
+ NULL,
+ H5D__compact_dest
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_fill
+ *
+ * Purpose: Write fill values to a compactly stored dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * May 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__compact_fill(const H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(TRUE == H5P_isa_class(dxpl_id, H5P_DATASET_XFER));
+ HDassert(dset && H5D_COMPACT == dset->shared->layout.type);
+ HDassert(dset->shared->layout.storage.u.compact.buf);
+ HDassert(dset->shared->type);
+ HDassert(dset->shared->space);
+
+ /* Initialize the fill value buffer */
+ /* (use the compact dataset storage buffer as the fill value buffer) */
+ if(H5D__fill_init(&fb_info, dset->shared->layout.storage.u.compact.buf,
+ NULL, NULL, NULL, NULL,
+ &dset->shared->dcpl_cache.fill, dset->shared->type,
+ dset->shared->type_id, (size_t)0, dset->shared->layout.storage.u.compact.size, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
+ fb_info_init = TRUE;
+
+ /* Check for VL datatype & non-default fill value */
+ if(fb_info.has_vlen_fill_type)
+ /* Fill the buffer with VL datatype fill values */
+ if(H5D__fill_refill_vl(&fb_info, fb_info.elmts_per_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
+
+done:
+ /* Release the fill buffer info, if it's been initialized */
+ if(fb_info_init && H5D__fill_term(&fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_construct
+ *
+ * Purpose: Constructs new compact layout information for dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compact_construct(H5F_t *f, H5D_t *dset)
+{
+ hssize_t stmp_size; /* Temporary holder for raw data size */
+ hsize_t tmp_size; /* Temporary holder for raw data size */
+ hsize_t max_comp_data_size; /* Max. allowed size of compact data */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(dset);
+
+ /* Check for invalid dataset dimensions */
+ for(u = 0; u < dset->shared->ndims; u++)
+ if(dset->shared->max_dims[u] > dset->shared->curr_dims[u])
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "extendible compact dataset not allowed")
+
+ /*
+ * Compact dataset is stored in dataset object header message of
+ * layout.
+ */
+ stmp_size = H5S_GET_EXTENT_NPOINTS(dset->shared->space);
+ HDassert(stmp_size >= 0);
+ tmp_size = H5T_get_size(dset->shared->type);
+ HDassert(tmp_size > 0);
+ tmp_size = tmp_size * (hsize_t)stmp_size;
+ H5_CHECKED_ASSIGN(dset->shared->layout.storage.u.compact.size, size_t, tmp_size, hssize_t);
+
+ /* Verify data size is smaller than maximum header message size
+ * (64KB) minus other layout message fields.
+ */
+ max_comp_data_size = H5O_MESG_MAX_SIZE - H5D__layout_meta_size(f, &(dset->shared->layout), FALSE);
+ if(dset->shared->layout.storage.u.compact.size > max_comp_data_size)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "compact dataset size is bigger than header message maximum size")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_construct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for layout
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__compact_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+
+ /* Compact storage is currently always allocated */
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* end H5D__compact_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_io_init
+ *
+ * Purpose: Performs initialization before any sort of I/O on the raw data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *cm)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ io_info->store->compact.buf = io_info->dset->shared->layout.storage.u.compact.buf;
+ io_info->store->compact.dirty = &io_info->dset->shared->layout.storage.u.compact.dirty;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__compact_io_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_readvv
+ *
+ * Purpose: Reads some data vectors from a dataset into a buffer.
+ * The data is in compact dataset. The address is relative
+ * to the beginning address of the dataset. The offsets and
+ * sequence lengths are in bytes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * May 7, 2003
+ *
+ * Notes:
+ * Offsets in the sequences must be monotonically increasing
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__compact_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[])
+{
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(io_info);
+
+ /* Use the vectorized memory copy routine to do actual work */
+ if((ret_value = H5VM_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_readvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_writevv
+ *
+ * Purpose: Writes some data vectors from a dataset into a buffer.
+ * The data is in compact dataset. The address is relative
+ * to the beginning address for the file. The offsets and
+ * sequence lengths are in bytes. This function only copies
+ * data into the buffer in the LAYOUT struct and mark it
+ * as DIRTY. Later in H5D_close, the data is copied into
+ * header message in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * May 2, 2003
+ *
+ * Notes:
+ * Offsets in the sequences must be monotonically increasing
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__compact_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[])
+{
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(io_info);
+
+ /* Use the vectorized memory copy routine to do actual work */
+ if((ret_value = H5VM_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr, io_info->u.wbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+
+ /* Mark the compact dataset's buffer as dirty */
+ *io_info->store->compact.dirty = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_writevv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_flush
+ *
+ * Purpose: Writes dirty compact data to object header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compact_flush(H5D_t *dset, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Check if the buffered compact information is dirty */
+ if(dset->shared->layout.storage.u.compact.dirty) {
+ if(H5O_msg_write(&(dset->oloc), H5O_LAYOUT_ID, 0, H5O_UPDATE_TIME, &(dset->shared->layout), dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update layout message")
+ dset->shared->layout.storage.u.compact.dirty = FALSE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_dest
+ *
+ * Purpose: Free the compact buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compact_dest(H5D_t *dset, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Free the buffer for the raw data for compact datasets */
+ dset->shared->layout.storage.u.compact.buf = H5MM_xfree(dset->shared->layout.storage.u.compact.buf);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__compact_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compact_copy
+ *
+ * Purpose: Copy compact storage raw data from SRC file to DST file.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Peter Cao
+ * December 11, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__compact_copy(H5F_t *f_src, H5O_storage_compact_t *storage_src, H5F_t *f_dst,
+ H5O_storage_compact_t *storage_dst, H5T_t *dt_src, H5O_copy_t *cpy_info,
+ hid_t dxpl_id)
+{
+ hid_t tid_src = -1; /* Datatype ID for source datatype */
+ hid_t tid_dst = -1; /* Datatype ID for destination datatype */
+ hid_t tid_mem = -1; /* Datatype ID for memory datatype */
+ void *buf = NULL; /* Buffer for copying data */
+ void *bkg = NULL; /* Temporary buffer for copying data */
+ void *reclaim_buf = NULL; /* Buffer for reclaiming data */
+ hid_t buf_sid = -1; /* ID for buffer dataspace */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(f_src);
+ HDassert(storage_src);
+ HDassert(f_dst);
+ HDassert(storage_dst);
+ HDassert(storage_dst->buf);
+ HDassert(dt_src);
+
+ /* Create datatype ID for src datatype, so it gets freed */
+ if((tid_src = H5I_register(H5I_DATATYPE, dt_src, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register source file datatype")
+
+ /* If there's a VLEN source datatype, do type conversion information */
+ if(H5T_detect_class(dt_src, H5T_VLEN, FALSE) > 0) {
+ H5T_path_t *tpath_src_mem, *tpath_mem_dst; /* Datatype conversion paths */
+ H5T_t *dt_dst; /* Destination datatype */
+ H5T_t *dt_mem; /* Memory datatype */
+ H5S_t *buf_space; /* Dataspace describing buffer */
+ size_t buf_size; /* Size of copy buffer */
+ size_t nelmts; /* Number of elements in buffer */
+ size_t src_dt_size; /* Source datatype size */
+ size_t tmp_dt_size; /* Temporary datatype size */
+ size_t max_dt_size; /* Max atatype size */
+ hsize_t buf_dim; /* Dimension for buffer */
+
+ /* create a memory copy of the variable-length datatype */
+ if(NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+ if((tid_mem = H5I_register(H5I_DATATYPE, dt_mem, FALSE)) < 0) {
+ H5T_close(dt_mem);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register memory datatype")
+ } /* end if */
+
+ /* create variable-length datatype at the destinaton file */
+ if(NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+ if(H5T_set_loc(dt_dst, f_dst, H5T_LOC_DISK) < 0) {
+ H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
+ } /* end if */
+ if((tid_dst = H5I_register(H5I_DATATYPE, dt_dst, FALSE)) < 0) {
+ H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register destination file datatype")
+ } /* end if */
+
+ /* Set up the conversion functions */
+ if(NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes")
+ if(NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes")
+
+ /* Determine largest datatype size */
+ if(0 == (src_dt_size = H5T_get_size(dt_src)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ if(0 == (tmp_dt_size = H5T_get_size(dt_mem)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(src_dt_size, tmp_dt_size);
+ if(0 == (tmp_dt_size = H5T_get_size(dt_dst)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(max_dt_size, tmp_dt_size);
+
+ /* Set number of whole elements that fit in buffer */
+ if(0 == (nelmts = storage_src->size / src_dt_size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "element size too large")
+
+ /* Set up number of bytes to copy, and initial buffer size */
+ buf_size = nelmts * max_dt_size;
+
+ /* Create dataspace for number of elements in buffer */
+ buf_dim = nelmts;
+
+ /* Create the space and set the initial extent */
+ if(NULL == (buf_space = H5S_create_simple((unsigned)1, &buf_dim, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Atomize */
+ if((buf_sid = H5I_register(H5I_DATASPACE, buf_space, FALSE)) < 0) {
+ H5S_close(buf_space);
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ } /* end if */
+
+ /* Allocate memory for recclaim buf */
+ if(NULL == (reclaim_buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Allocate memory for copying the chunk */
+ if(NULL == (buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ HDmemcpy(buf, storage_src->buf, storage_src->size);
+
+ /* allocate temporary bkg buff for data conversion */
+ if(NULL == (bkg = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Convert from source file to memory */
+ if(H5T_convert(tpath_src_mem, tid_src, tid_mem, nelmts, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ /* Copy into another buffer, to reclaim memory later */
+ HDmemcpy(reclaim_buf, buf, buf_size);
+
+ /* Set background buffer to all zeros */
+ HDmemset(bkg, 0, buf_size);
+
+ /* Convert from memory to destination file */
+ if(H5T_convert(tpath_mem_dst, tid_mem, tid_dst, nelmts, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ HDmemcpy(storage_dst->buf, buf, storage_dst->size);
+
+ if(H5D_vlen_reclaim(tid_mem, buf_space, dxpl_id, reclaim_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to reclaim variable-length data")
+ } /* end if */
+ else if(H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) {
+ if(f_src != f_dst) {
+ /* Check for expanding references */
+ if(cpy_info->expand_ref) {
+ size_t ref_count;
+
+ /* Determine # of reference elements to copy */
+ ref_count = storage_src->size / H5T_get_size(dt_src);
+
+ /* Copy objects referenced in source buffer to destination file and set destination elements */
+ if(H5O_copy_expand_ref(f_src, storage_src->buf, dxpl_id, f_dst,
+ storage_dst->buf, ref_count, H5T_get_ref_type(dt_src), cpy_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy reference attribute")
+ } /* end if */
+ else
+ /* Reset value to zero */
+ HDmemset(storage_dst->buf, 0, storage_src->size);
+ } /* end if */
+ else
+ /* Type conversion not necessary */
+ HDmemcpy(storage_dst->buf, storage_src->buf, storage_src->size);
+ } /* end if */
+ else
+ /* Type conversion not necessary */
+ HDmemcpy(storage_dst->buf, storage_src->buf, storage_src->size);
+
+ /* Mark destination buffer as dirty */
+ storage_dst->dirty = TRUE;
+
+done:
+ if(buf_sid > 0 && H5I_dec_ref(buf_sid) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't decrement temporary dataspace ID")
+ if(tid_src > 0 && H5I_dec_ref(tid_src) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_dst > 0 && H5I_dec_ref(tid_dst) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_mem > 0 && H5I_dec_ref(tid_mem) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(buf)
+ buf = H5FL_BLK_FREE(type_conv, buf);
+ if(reclaim_buf)
+ reclaim_buf = H5FL_BLK_FREE(type_conv, reclaim_buf);
+ if(bkg)
+ bkg = H5FL_BLK_FREE(type_conv, bkg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_copy() */
+
diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c
new file mode 100644
index 0000000..0ee4d28
--- /dev/null
+++ b/src/H5Dcontig.c
@@ -0,0 +1,1585 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, September 28, 2000
+ *
+ * Purpose:
+ * Contiguous dataset I/O functions. These routines are similar to
+ * the H5D_chunk_* routines and really only an abstract way of dealing
+ * with the data sieve buffer from H5F_seq_read/write.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Callback info for sieve buffer readvv operation */
+typedef struct H5D_contig_readvv_sieve_ud_t {
+ H5F_t *file; /* File for dataset */
+ H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */
+ const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */
+ unsigned char *rbuf; /* Pointer to buffer to fill */
+ hid_t dxpl_id; /* DXPL for operation */
+} H5D_contig_readvv_sieve_ud_t;
+
+/* Callback info for [plain] readvv operation */
+typedef struct H5D_contig_readvv_ud_t {
+ H5F_t *file; /* File for dataset */
+ haddr_t dset_addr; /* Address of dataset */
+ unsigned char *rbuf; /* Pointer to buffer to fill */
+ hid_t dxpl_id; /* DXPL for operation */
+} H5D_contig_readvv_ud_t;
+
+/* Callback info for sieve buffer writevv operation */
+typedef struct H5D_contig_writevv_sieve_ud_t {
+ H5F_t *file; /* File for dataset */
+ H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */
+ const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */
+ const unsigned char *wbuf; /* Pointer to buffer to write */
+ hid_t dxpl_id; /* DXPL for operation */
+} H5D_contig_writevv_sieve_ud_t;
+
+/* Callback info for [plain] writevv operation */
+typedef struct H5D_contig_writevv_ud_t {
+ H5F_t *file; /* File for dataset */
+ haddr_t dset_addr; /* Address of dataset */
+ const unsigned char *wbuf; /* Pointer to buffer to write */
+ hid_t dxpl_id; /* DXPL for operation */
+} H5D_contig_writevv_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Layout operation callbacks */
+static herr_t H5D__contig_construct(H5F_t *f, H5D_t *dset);
+static herr_t H5D__contig_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset,
+ hid_t dapl_id);
+static herr_t H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *cm);
+static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+static ssize_t H5D__contig_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+static herr_t H5D__contig_flush(H5D_t *dset, hid_t dxpl_id);
+
+/* Helper routines */
+static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset,
+ size_t size);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Contiguous storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{
+ H5D__contig_construct,
+ H5D__contig_init,
+ H5D__contig_is_space_alloc,
+ H5D__contig_io_init,
+ H5D__contig_read,
+ H5D__contig_write,
+#ifdef H5_HAVE_PARALLEL
+ H5D__contig_collective_read,
+ H5D__contig_collective_write,
+#endif /* H5_HAVE_PARALLEL */
+ H5D__contig_readvv,
+ H5D__contig_writevv,
+ H5D__contig_flush,
+ NULL,
+ NULL
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a PQ free list to manage the sieve buffer information */
+H5FL_BLK_DEFINE(sieve_buf);
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_alloc
+ *
+ * Purpose: Allocate file space for a contiguously stored dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * April 19, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_alloc(H5F_t *f, hid_t dxpl_id, H5O_storage_contig_t *storage /*out */ )
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(f);
+ HDassert(storage);
+
+ /* Allocate space for the contiguous data */
+ if(HADDR_UNDEF == (storage->addr = H5MF_alloc(f, H5FD_MEM_DRAW, dxpl_id, storage->size)))
+ HGOTO_ERROR(H5E_IO, H5E_NOSPACE, FAIL, "unable to reserve file space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_alloc */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_fill
+ *
+ * Purpose: Write fill values to a contiguously stored dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 22, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_fill(const H5D_io_info_t *io_info)
+{
+ const H5D_t *dset = io_info->dset; /* the dataset pointer */
+ H5D_io_info_t ioinfo; /* Dataset I/O info */
+ H5D_storage_t store; /* Union of storage info for dataset */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ hssize_t snpoints; /* Number of points in space (for error checking) */
+ size_t npoints; /* Number of points in space */
+ hsize_t offset; /* Offset of dataset */
+#ifdef H5_HAVE_PARALLEL
+ MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */
+ int mpi_rank = (-1); /* This process's rank */
+ int mpi_code; /* MPI return code */
+ hbool_t blocks_written = FALSE; /* Flag to indicate that chunk was actually written */
+ hbool_t using_mpi = FALSE; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */
+#endif /* H5_HAVE_PARALLEL */
+ hid_t md_dxpl_id = io_info->md_dxpl_id;
+ hid_t raw_dxpl_id = io_info->raw_dxpl_id;
+ H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */
+ hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(TRUE == H5P_isa_class(md_dxpl_id, H5P_DATASET_XFER));
+ HDassert(TRUE == H5P_isa_class(raw_dxpl_id, H5P_DATASET_XFER));
+ HDassert(dset && H5D_CONTIGUOUS == dset->shared->layout.type);
+ HDassert(H5F_addr_defined(dset->shared->layout.storage.u.contig.addr));
+ HDassert(dset->shared->layout.storage.u.contig.size > 0);
+ HDassert(dset->shared->space);
+ HDassert(dset->shared->type);
+
+#ifdef H5_HAVE_PARALLEL
+ /* Retrieve MPI parameters */
+ if(H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
+ /* Get the MPI communicator */
+ if(MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(dset->oloc.file)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator")
+
+ /* Get the MPI rank */
+ if((mpi_rank = H5F_mpi_get_rank(dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank")
+
+ /* Set the MPI-capable file driver flag */
+ using_mpi = TRUE;
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(raw_dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Initialize storage info for this dataset */
+ store.contig.dset_addr = dset->shared->layout.storage.u.contig.addr;
+ store.contig.dset_size = dset->shared->layout.storage.u.contig.size;
+
+ /* Get the number of elements in the dataset's dataspace */
+ if((snpoints = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "dataset has negative number of elements")
+ H5_CHECKED_ASSIGN(npoints, size_t, snpoints, hssize_t);
+
+ /* Initialize the fill value buffer */
+ if(H5D__fill_init(&fb_info, NULL, NULL, NULL, NULL, NULL,
+ &dset->shared->dcpl_cache.fill,
+ dset->shared->type, dset->shared->type_id, npoints,
+ dxpl_cache->max_temp_buf, md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info")
+ fb_info_init = TRUE;
+
+ /* Start at the beginning of the dataset */
+ offset = 0;
+
+ /* Simple setup for dataset I/O info struct */
+ H5D_BUILD_IO_INFO_WRT(&ioinfo, dset, dxpl_cache, H5AC_ind_read_dxpl_id, raw_dxpl_id, &store, fb_info.fill_buf);
+
+ /*
+ * Fill the entire current extent with the fill value. We can do
+ * this quite efficiently by making sure we copy the fill value
+ * in relatively large pieces.
+ */
+
+ /* Loop through writing the fill value to the dataset */
+ while(npoints > 0) {
+ size_t curr_points; /* Number of elements to write on this iteration of the loop */
+ size_t size; /* Size of buffer to write */
+
+ /* Compute # of elements and buffer size to write for this iteration */
+ curr_points = MIN(fb_info.elmts_per_buf, npoints);
+ size = curr_points * fb_info.file_elmt_size;
+
+ /* Check for VL datatype & non-default fill value */
+ if(fb_info.has_vlen_fill_type)
+ /* Re-fill the buffer to use for this I/O operation */
+ if(H5D__fill_refill_vl(&fb_info, curr_points, md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Check if this file is accessed with an MPI-capable file driver */
+ if(using_mpi) {
+ /* Write the chunks out from only one process */
+ /* !! Use the internal "independent" DXPL!! -QAK */
+ if(H5_PAR_META_WRITE == mpi_rank)
+ if(H5D__contig_write_one(&ioinfo, offset, size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset")
+
+ /* Indicate that blocks are being written */
+ blocks_written = TRUE;
+ } /* end if */
+ else {
+#endif /* H5_HAVE_PARALLEL */
+ H5_CHECK_OVERFLOW(size, size_t, hsize_t);
+ if(H5D__contig_write_one(&ioinfo, offset, size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset")
+#ifdef H5_HAVE_PARALLEL
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+
+ npoints -= curr_points;
+ offset += size;
+ } /* end while */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Only need to block at the barrier if we actually wrote fill values */
+ /* And if we are using an MPI-capable file driver */
+ if(using_mpi && blocks_written) {
+ /* Wait at barrier to avoid race conditions where some processes are
+ * still writing out fill values and other processes race ahead to data
+ * in, getting bogus data.
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_Barrier(mpi_comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
+ } /* end if */
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ /* Release the fill buffer info, if it's been initialized */
+ if(fb_info_init && H5D__fill_term(&fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_delete
+ *
+ * Purpose: Delete the file space for a contiguously stored dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * March 20, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_delete(H5F_t *f, hid_t dxpl_id, const H5O_storage_t *storage)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(f);
+ HDassert(storage);
+
+ /* Free the file space for the chunk */
+ if(H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, storage->u.contig.addr, storage->u.contig.size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free contiguous storage space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_delete */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_construct
+ *
+ * Purpose: Constructs new contiguous layout information for dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_construct(H5F_t *f, H5D_t *dset)
+{
+ hssize_t snelmts; /* Temporary holder for number of elements in dataspace */
+ hsize_t nelmts; /* Number of elements in dataspace */
+ size_t dt_size; /* Size of datatype */
+ hsize_t tmp_size; /* Temporary holder for raw data size */
+ size_t tmp_sieve_buf_size; /* Temporary holder for sieve buffer size */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(dset);
+
+ /*
+ * The maximum size of the dataset cannot exceed the storage size.
+ * Also, only the slowest varying dimension of a simple data space
+ * can be extendible (currently only for external data storage).
+ */
+
+ /* Check for invalid dataset dimensions */
+ for(u = 0; u < dset->shared->ndims; u++)
+ if(dset->shared->max_dims[u] > dset->shared->curr_dims[u])
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "extendible contiguous non-external dataset not allowed")
+
+ /* Retrieve the number of elements in the dataspace */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace")
+ nelmts = (hsize_t)snelmts;
+
+ /* Get the datatype's size */
+ if(0 == (dt_size = H5T_GET_SIZE(dset->shared->type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype")
+
+ /* Compute the size of the dataset's contiguous storage */
+ tmp_size = nelmts * dt_size;
+
+ /* Check for overflow during multiplication */
+ if(nelmts != (tmp_size / dt_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed")
+
+ /* Assign the dataset's contiguous storage size */
+ dset->shared->layout.storage.u.contig.size = tmp_size;
+
+ /* Get the sieve buffer size for the file */
+ tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(f);
+
+ /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size
+ * from the file access property. (SLU - 2012/3/30) */
+ if(tmp_size < tmp_sieve_buf_size)
+ dset->shared->cache.contig.sieve_buf_size = tmp_size;
+ else
+ dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_construct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_init
+ *
+ * Purpose: Initialize the contiguous info for a dataset. This is
+ * called when the dataset is initialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 28, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_init(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ const H5D_t *dset, hid_t H5_ATTR_UNUSED dapl_id)
+{
+ hsize_t tmp_size; /* Temporary holder for raw data size */
+ size_t tmp_sieve_buf_size; /* Temporary holder for sieve buffer size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(dset);
+
+ /* Compute the size of the contiguous storage for versions of the
+ * layout message less than version 3 because versions 1 & 2 would
+ * truncate the dimension sizes to 32-bits of information. - QAK 5/26/04
+ */
+ if(dset->shared->layout.version < 3) {
+ hssize_t snelmts; /* Temporary holder for number of elements in dataspace */
+ hsize_t nelmts; /* Number of elements in dataspace */
+ size_t dt_size; /* Size of datatype */
+
+ /* Retrieve the number of elements in the dataspace */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace")
+ nelmts = (hsize_t)snelmts;
+
+ /* Get the datatype's size */
+ if(0 == (dt_size = H5T_GET_SIZE(dset->shared->type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype")
+
+ /* Compute the size of the dataset's contiguous storage */
+ tmp_size = nelmts * dt_size;
+
+ /* Check for overflow during multiplication */
+ if(nelmts != (tmp_size / dt_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed")
+
+ /* Assign the dataset's contiguous storage size */
+ dset->shared->layout.storage.u.contig.size = tmp_size;
+ } /* end if */
+ else
+ tmp_size = dset->shared->layout.storage.u.contig.size;
+
+ /* Get the sieve buffer size for the file */
+ tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(dset->oloc.file);
+
+ /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size
+ * from the file access property. (SLU - 2012/3/30) */
+ if(tmp_size < tmp_sieve_buf_size)
+ dset->shared->cache.contig.sieve_buf_size = tmp_size;
+ else
+ dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for layout
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5D__contig_is_space_alloc(const H5O_storage_t *storage)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+
+ /* Set return value */
+ ret_value = (hbool_t)H5F_addr_defined(storage->u.contig.addr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_io_init
+ *
+ * Purpose: Performs initialization before any sort of I/O on the raw data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *cm)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ io_info->store->contig.dset_addr = io_info->dset->shared->layout.storage.u.contig.addr;
+ io_info->store->contig.dset_size = io_info->dset->shared->layout.storage.u.contig.size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__contig_io_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_read
+ *
+ * Purpose: Read from a contiguous dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 10, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.rbuf);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+
+ /* Read data */
+ if((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_write
+ *
+ * Purpose: Write to a contiguous dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 10, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.wbuf);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+
+ /* Write data */
+ if((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_write_one
+ *
+ * Purpose: Writes some data from a dataset into a buffer.
+ * The data is contiguous. The address is relative to the base
+ * address for the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 28, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_write_one(H5D_io_info_t *io_info, hsize_t offset, size_t size)
+{
+ hsize_t dset_off = offset; /* Offset in dataset */
+ size_t dset_len = size; /* Length in dataset */
+ size_t dset_curr_seq = 0; /* "Current sequence" in dataset */
+ hsize_t mem_off = 0; /* Offset in memory */
+ size_t mem_len = size; /* Length in memory */
+ size_t mem_curr_seq = 0; /* "Current sequence" in memory */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(io_info);
+
+ if(H5D__contig_writevv(io_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off,
+ (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vector write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_write_one() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_readvv_sieve_cb
+ *
+ * Purpose: Callback operator for H5D__contig_readvv() with sieve buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len,
+ void *_udata)
+{
+ H5D_contig_readvv_sieve_ud_t *udata = (H5D_contig_readvv_sieve_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ H5F_t *file = udata->file; /* File for dataset */
+ H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */
+ const H5D_contig_storage_t *store_contig = udata->store_contig; /* Contiguous storage info for this I/O operation */
+ unsigned char *buf; /* Pointer to buffer to fill */
+ haddr_t addr; /* Actual address to read */
+ haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */
+ haddr_t contig_end; /* End locations of block to write */
+ size_t sieve_size = (size_t)-1; /* Size of sieve buffer */
+ haddr_t rel_eoa; /* Relative end of file address */
+ hsize_t max_data; /* Actual maximum size of data to cache */
+ hsize_t min; /* temporary minimum value (avoids some ugly macro nesting) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Stash local copies of these value */
+ if(dset_contig->sieve_buf != NULL) {
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+ } /* end if */
+
+ /* Compute offset on disk */
+ addr = store_contig->dset_addr + dst_off;
+
+ /* Compute offset in memory */
+ buf = udata->rbuf + src_off;
+
+ /* Check if the sieve buffer is allocated yet */
+ if(NULL == dset_contig->sieve_buf) {
+ /* Check if we can actually hold the I/O request in the sieve buffer */
+ if(len > dset_contig->sieve_buf_size) {
+ if(H5F_block_read(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+ } /* end if */
+ else {
+ /* Allocate room for the data sieve buffer */
+ if(NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Determine the new sieve buffer size & location */
+ dset_contig->sieve_loc = addr;
+
+ /* Make certain we don't read off the end of the file */
+ if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size")
+
+ /* Set up the buffer parameters */
+ max_data = store_contig->dset_size - dst_off;
+
+ /* Compute the size of the sieve buffer */
+ min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
+ H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
+
+ /* Read the new sieve buffer */
+ if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+
+ /* Grab the data out of the buffer (must be first piece of data in buffer ) */
+ HDmemcpy(buf, dset_contig->sieve_buf, len);
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+
+ /* Stash local copies of these value */
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start+sieve_size;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Compute end of sequence to retrieve */
+ contig_end = addr + len - 1;
+
+ /* If entire read is within the sieve buffer, read it from the buffer */
+ if(addr >= sieve_start && contig_end < sieve_end) {
+ unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start);
+
+ /* Grab the data out of the buffer */
+ HDmemcpy(buf, base_sieve_buf, len);
+ } /* end if */
+ /* Entire request is not within this data sieve buffer */
+ else {
+ /* Check if we can actually hold the I/O request in the sieve buffer */
+ if(len > dset_contig->sieve_buf_size) {
+ /* Check for any overlap with the current sieve buffer */
+ if((sieve_start >= addr && sieve_start < (contig_end + 1))
+ || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) {
+ /* Flush the sieve buffer, if it's dirty */
+ if(dset_contig->sieve_dirty) {
+ /* Write to file */
+ if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+ } /* end if */
+ } /* end if */
+
+ /* Read directly into the user's buffer */
+ if(H5F_block_read(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+ } /* end if */
+ /* Element size fits within the buffer size */
+ else {
+ /* Flush the sieve buffer if it's dirty */
+ if(dset_contig->sieve_dirty) {
+ /* Write to file */
+ if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+ } /* end if */
+
+ /* Determine the new sieve buffer size & location */
+ dset_contig->sieve_loc = addr;
+
+ /* Make certain we don't read off the end of the file */
+ if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size")
+
+ /* Only need this when resizing sieve buffer */
+ max_data = store_contig->dset_size - dst_off;
+
+ /* Compute the size of the sieve buffer.
+ * Don't read off the end of the file, don't read past
+ * the end of the data element, and don't read more than
+ * the buffer size.
+ */
+ min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
+ H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
+
+ /* Update local copies of sieve information */
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+
+ /* Read the new sieve buffer */
+ if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+
+ /* Grab the data out of the buffer (must be first piece of data in buffer ) */
+ HDmemcpy(buf, dset_contig->sieve_buf, len);
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_readvv_sieve_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_readvv_cb
+ *
+ * Purpose: Callback operator for H5D__contig_readvv() without sieve buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
+{
+ H5D_contig_readvv_ud_t *udata = (H5D_contig_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Write data */
+ if(H5F_block_read(udata->file, H5FD_MEM_DRAW, (udata->dset_addr + dst_off),
+ len, udata->dxpl_id, (udata->rbuf + src_off)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_readvv_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_readvv
+ *
+ * Purpose: Reads some data vectors from a dataset into a buffer.
+ * The data is contiguous. The address is the start of the dataset,
+ * relative to the base address for the file and the offsets and
+ * sequence lengths are in bytes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 3, 2001
+ *
+ * Notes:
+ * Offsets in the sequences must be monotonically increasing
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__contig_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
+{
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(dset_curr_seq);
+ HDassert(dset_len_arr);
+ HDassert(dset_off_arr);
+ HDassert(mem_curr_seq);
+ HDassert(mem_len_arr);
+ HDassert(mem_off_arr);
+
+ /* Check if data sieving is enabled */
+ if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) {
+ H5D_contig_readvv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */
+
+ /* Set up user data for H5VM_opvv() */
+ udata.file = io_info->dset->oloc.file;
+ udata.dset_contig = &(io_info->dset->shared->cache.contig);
+ udata.store_contig = &(io_info->store->contig);
+ udata.rbuf = (unsigned char *)io_info->u.rbuf;
+ udata.dxpl_id = io_info->raw_dxpl_id;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__contig_readvv_sieve_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer read")
+ } /* end if */
+ else {
+ H5D_contig_readvv_ud_t udata; /* User data for H5VM_opvv() operator */
+
+ /* Set up user data for H5VM_opvv() */
+ udata.file = io_info->dset->oloc.file;
+ udata.dset_addr = io_info->store->contig.dset_addr;
+ udata.rbuf = (unsigned char *)io_info->u.rbuf;
+ udata.dxpl_id = io_info->raw_dxpl_id;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__contig_readvv_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_readvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_writevv_sieve_cb
+ *
+ * Purpose: Callback operator for H5D__contig_writevv() with sieve buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len,
+ void *_udata)
+{
+ H5D_contig_writevv_sieve_ud_t *udata = (H5D_contig_writevv_sieve_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ H5F_t *file = udata->file; /* File for dataset */
+ H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */
+ const H5D_contig_storage_t *store_contig = udata->store_contig; /* Contiguous storage info for this I/O operation */
+ const unsigned char *buf; /* Pointer to buffer to fill */
+ haddr_t addr; /* Actual address to read */
+ haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */
+ haddr_t contig_end; /* End locations of block to write */
+ size_t sieve_size = (size_t)-1; /* size of sieve buffer */
+ haddr_t rel_eoa; /* Relative end of file address */
+ hsize_t max_data; /* Actual maximum size of data to cache */
+ hsize_t min; /* temporary minimum value (avoids some ugly macro nesting) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Stash local copies of these values */
+ if(dset_contig->sieve_buf != NULL) {
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+ } /* end if */
+
+ /* Compute offset on disk */
+ addr = store_contig->dset_addr + dst_off;
+
+ /* Compute offset in memory */
+ buf = udata->wbuf + src_off;
+
+ /* No data sieve buffer yet, go allocate one */
+ if(NULL == dset_contig->sieve_buf) {
+ /* Check if we can actually hold the I/O request in the sieve buffer */
+ if(len > dset_contig->sieve_buf_size) {
+ if(H5F_block_write(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+ } /* end if */
+ else {
+ /* Allocate room for the data sieve buffer */
+ if(NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Clear memory */
+ if(dset_contig->sieve_size > len)
+ HDmemset(dset_contig->sieve_buf + len, 0, (dset_contig->sieve_size - len));
+
+ /* Determine the new sieve buffer size & location */
+ dset_contig->sieve_loc = addr;
+
+ /* Make certain we don't read off the end of the file */
+ if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size")
+
+ /* Set up the buffer parameters */
+ max_data = store_contig->dset_size - dst_off;
+
+ /* Compute the size of the sieve buffer */
+ min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
+ H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
+
+ /* Check if there is any point in reading the data from the file */
+ if(dset_contig->sieve_size > len) {
+ /* Read the new sieve buffer */
+ if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+ } /* end if */
+
+ /* Grab the data out of the buffer (must be first piece of data in buffer ) */
+ HDmemcpy(dset_contig->sieve_buf, buf, len);
+
+ /* Set sieve buffer dirty flag */
+ dset_contig->sieve_dirty = TRUE;
+
+ /* Stash local copies of these values */
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Compute end of sequence to retrieve */
+ contig_end = addr + len - 1;
+
+ /* If entire write is within the sieve buffer, write it to the buffer */
+ if(addr >= sieve_start && contig_end < sieve_end) {
+ unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start);
+
+ /* Put the data into the sieve buffer */
+ HDmemcpy(base_sieve_buf, buf, len);
+
+ /* Set sieve buffer dirty flag */
+ dset_contig->sieve_dirty = TRUE;
+ } /* end if */
+ /* Entire request is not within this data sieve buffer */
+ else {
+ /* Check if we can actually hold the I/O request in the sieve buffer */
+ if(len > dset_contig->sieve_buf_size) {
+ /* Check for any overlap with the current sieve buffer */
+ if((sieve_start >= addr && sieve_start < (contig_end + 1))
+ || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) {
+ /* Flush the sieve buffer, if it's dirty */
+ if(dset_contig->sieve_dirty) {
+ /* Write to file */
+ if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+ } /* end if */
+
+ /* Force the sieve buffer to be re-read the next time */
+ dset_contig->sieve_loc = HADDR_UNDEF;
+ dset_contig->sieve_size = 0;
+ } /* end if */
+
+ /* Write directly from the user's buffer */
+ if(H5F_block_write(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+ } /* end if */
+ /* Element size fits within the buffer size */
+ else {
+ /* Check if it is possible to (exactly) prepend or append to existing (dirty) sieve buffer */
+ if(((addr + len) == sieve_start || addr == sieve_end) &&
+ (len + sieve_size) <= dset_contig->sieve_buf_size &&
+ dset_contig->sieve_dirty) {
+ /* Prepend to existing sieve buffer */
+ if((addr + len) == sieve_start) {
+ /* Move existing sieve information to correct location */
+ HDmemmove(dset_contig->sieve_buf + len, dset_contig->sieve_buf, dset_contig->sieve_size);
+
+ /* Copy in new information (must be first in sieve buffer) */
+ HDmemcpy(dset_contig->sieve_buf, buf, len);
+
+ /* Adjust sieve location */
+ dset_contig->sieve_loc = addr;
+
+ } /* end if */
+ /* Append to existing sieve buffer */
+ else {
+ /* Copy in new information */
+ HDmemcpy(dset_contig->sieve_buf + sieve_size, buf, len);
+ } /* end else */
+
+ /* Adjust sieve size */
+ dset_contig->sieve_size += len;
+
+ /* Update local copies of sieve information */
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+ } /* end if */
+ /* Can't add the new data onto the existing sieve buffer */
+ else {
+ /* Flush the sieve buffer if it's dirty */
+ if(dset_contig->sieve_dirty) {
+ /* Write to file */
+ if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+ /* Reset sieve buffer dirty flag */
+ dset_contig->sieve_dirty = FALSE;
+ } /* end if */
+
+ /* Determine the new sieve buffer size & location */
+ dset_contig->sieve_loc = addr;
+
+ /* Make certain we don't read off the end of the file */
+ if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size")
+
+ /* Only need this when resizing sieve buffer */
+ max_data = store_contig->dset_size - dst_off;
+
+ /* Compute the size of the sieve buffer.
+ * Don't read off the end of the file, don't read past
+ * the end of the data element, and don't read more than
+ * the buffer size.
+ */
+ min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
+ H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
+
+ /* Update local copies of sieve information */
+ sieve_start = dset_contig->sieve_loc;
+ sieve_size = dset_contig->sieve_size;
+ sieve_end = sieve_start + sieve_size;
+
+ /* Check if there is any point in reading the data from the file */
+ if(dset_contig->sieve_size > len) {
+ /* Read the new sieve buffer */
+ if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed")
+ } /* end if */
+
+ /* Grab the data out of the buffer (must be first piece of data in buffer ) */
+ HDmemcpy(dset_contig->sieve_buf, buf, len);
+
+ /* Set sieve buffer dirty flag */
+ dset_contig->sieve_dirty = TRUE;
+ } /* end else */
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_writevv_sieve_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_writevv_cb
+ *
+ * Purpose: Callback operator for H5D__contig_writevv().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
+{
+ H5D_contig_writevv_ud_t *udata = (H5D_contig_writevv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Write data */
+ if(H5F_block_write(udata->file, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len, udata->dxpl_id, (udata->wbuf + src_off)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_writevv_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_writevv
+ *
+ * Purpose: Writes some data vectors into a dataset from vectors into a
+ * buffer. The address is the start of the dataset,
+ * relative to the base address for the file and the offsets and
+ * sequence lengths are in bytes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 2, 2003
+ *
+ * Notes:
+ * Offsets in the sequences must be monotonically increasing
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__contig_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
+{
+ ssize_t ret_value = -1; /* Return value (Size of sequence in bytes) */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(dset_curr_seq);
+ HDassert(dset_len_arr);
+ HDassert(dset_off_arr);
+ HDassert(mem_curr_seq);
+ HDassert(mem_len_arr);
+ HDassert(mem_off_arr);
+
+ /* Check if data sieving is enabled */
+ if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) {
+ H5D_contig_writevv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */
+
+ /* Set up user data for H5VM_opvv() */
+ udata.file = io_info->dset->oloc.file;
+ udata.dset_contig = &(io_info->dset->shared->cache.contig);
+ udata.store_contig = &(io_info->store->contig);
+ udata.wbuf = (const unsigned char *)io_info->u.wbuf;
+ udata.dxpl_id = io_info->raw_dxpl_id;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__contig_writevv_sieve_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer write")
+ } /* end if */
+ else {
+ H5D_contig_writevv_ud_t udata; /* User data for H5VM_opvv() operator */
+
+ /* Set up user data for H5VM_opvv() */
+ udata.file = io_info->dset->oloc.file;
+ udata.dset_addr = io_info->store->contig.dset_addr;
+ udata.wbuf = (const unsigned char *)io_info->u.wbuf;
+ udata.dxpl_id = io_info->raw_dxpl_id;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__contig_writevv_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_writevv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_flush
+ *
+ * Purpose: Writes all dirty data to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__contig_flush(H5D_t *dset, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Flush any data in sieve buffer - use the raw data dxpl since
+ the one passed in is a metadata dxpl. */
+ if(H5D__flush_sieve_buf(dset, H5AC_rawdata_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush sieve buffer")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_copy
+ *
+ * Purpose: Copy contiguous storage raw data from SRC file to DST file.
+ *
+ * Return: Non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src,
+ H5F_t *f_dst, H5O_storage_contig_t *storage_dst, H5T_t *dt_src,
+ H5O_copy_t *cpy_info, hid_t dxpl_id)
+{
+ haddr_t addr_src; /* File offset in source dataset */
+ haddr_t addr_dst; /* File offset in destination dataset */
+ H5T_path_t *tpath_src_mem = NULL, *tpath_mem_dst = NULL; /* Datatype conversion paths */
+ H5T_t *dt_dst = NULL; /* Destination datatype */
+ H5T_t *dt_mem = NULL; /* Memory datatype */
+ hid_t tid_src = -1; /* Datatype ID for source datatype */
+ hid_t tid_dst = -1; /* Datatype ID for destination datatype */
+ hid_t tid_mem = -1; /* Datatype ID for memory datatype */
+ size_t src_dt_size = 0; /* Source datatype size */
+ size_t mem_dt_size = 0; /* Memory datatype size */
+ size_t dst_dt_size = 0; /* Destination datatype size */
+ size_t max_dt_size; /* Max. datatype size */
+ size_t nelmts = 0; /* Number of elements in buffer */
+ size_t src_nbytes; /* Number of bytes to read from source */
+ size_t mem_nbytes; /* Number of bytes to convert in memory */
+ size_t dst_nbytes; /* Number of bytes to write to destination */
+ hsize_t total_src_nbytes; /* Total number of bytes to copy */
+ size_t buf_size; /* Size of copy buffer */
+ void *buf = NULL; /* Buffer for copying data */
+ void *bkg = NULL; /* Temporary buffer for copying data */
+ void *reclaim_buf = NULL; /* Buffer for reclaiming data */
+ H5S_t *buf_space = NULL; /* Dataspace describing buffer */
+ hid_t buf_sid = -1; /* ID for buffer dataspace */
+ hsize_t buf_dim[1] = {0}; /* Dimension for buffer */
+ hbool_t is_vlen = FALSE; /* Flag to indicate that VL type conversion should occur */
+ hbool_t fix_ref = FALSE; /* Flag to indicate that ref values should be fixed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(f_src);
+ HDassert(storage_src);
+ HDassert(f_dst);
+ HDassert(storage_dst);
+ HDassert(dt_src);
+
+ /* Allocate space for destination raw data */
+ if(H5D__contig_alloc(f_dst, dxpl_id, storage_dst) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to allocate contiguous storage")
+
+ /* Set up number of bytes to copy, and initial buffer size */
+ /* (actually use the destination size, which has been fixed up, if necessary) */
+ total_src_nbytes = storage_dst->size;
+ H5_CHECK_OVERFLOW(total_src_nbytes, hsize_t, size_t);
+ buf_size = MIN(H5D_TEMP_BUF_SIZE, (size_t)total_src_nbytes);
+
+ /* Create datatype ID for src datatype. We may or may not use this ID,
+ * but this ensures that the src datatype will be freed.
+ */
+ if((tid_src = H5I_register(H5I_DATATYPE, dt_src, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register source file datatype")
+
+ /* If there's a VLEN source datatype, set up type conversion information */
+ if(H5T_detect_class(dt_src, H5T_VLEN, FALSE) > 0) {
+ /* create a memory copy of the variable-length datatype */
+ if(NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+ if((tid_mem = H5I_register(H5I_DATATYPE, dt_mem, FALSE)) < 0) {
+ H5T_close(dt_mem);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register memory datatype")
+ } /* end if */
+
+ /* create variable-length datatype at the destinaton file */
+ if(NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy")
+ if(H5T_set_loc(dt_dst, f_dst, H5T_LOC_DISK) < 0) {
+ H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
+ } /* end if */
+ if((tid_dst = H5I_register(H5I_DATATYPE, dt_dst, FALSE)) < 0) {
+ H5T_close(dt_dst);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register destination file datatype")
+ } /* end if */
+
+ /* Set up the conversion functions */
+ if(NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes")
+ if(NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes")
+
+ /* Determine largest datatype size */
+ if(0 == (src_dt_size = H5T_get_size(dt_src)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ if(0 == (mem_dt_size = H5T_get_size(dt_mem)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(src_dt_size, mem_dt_size);
+ if(0 == (dst_dt_size = H5T_get_size(dt_dst)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+ max_dt_size = MAX(max_dt_size, dst_dt_size);
+
+ /* Set maximum number of whole elements that fit in buffer */
+ if(0 == (nelmts = buf_size / max_dt_size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "element size too large")
+
+ /* Set the number of bytes to transfer */
+ src_nbytes = nelmts * src_dt_size;
+ dst_nbytes = nelmts * dst_dt_size;
+ mem_nbytes = nelmts * mem_dt_size;
+
+ /* Adjust buffer size to be multiple of elements */
+ buf_size = nelmts * max_dt_size;
+
+ /* Create dataspace for number of elements in buffer */
+ buf_dim[0] = nelmts;
+
+ /* Create the space and set the initial extent */
+ if(NULL == (buf_space = H5S_create_simple((unsigned)1, buf_dim, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Atomize */
+ if((buf_sid = H5I_register(H5I_DATASPACE, buf_space, FALSE)) < 0) {
+ H5S_close(buf_space);
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ } /* end if */
+
+ /* Set flag to do type conversion */
+ is_vlen = TRUE;
+ } /* end if */
+ else {
+ /* Check for reference datatype */
+ if(H5T_get_class(dt_src, FALSE) == H5T_REFERENCE) {
+ /* Need to fix values of references when copying across files */
+ if(f_src != f_dst)
+ fix_ref = TRUE;
+ } /* end if */
+
+ /* Set the number of bytes to read & write to the buffer size */
+ src_nbytes = dst_nbytes = mem_nbytes = buf_size;
+ } /* end else */
+
+ /* Allocate space for copy buffer */
+ HDassert(buf_size);
+ if(NULL == (buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer")
+
+ /* Need extra buffer for datatype conversions, to prevent stranding/leaking memory */
+ if(is_vlen || fix_ref) {
+ if(NULL == (reclaim_buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer")
+
+ /* allocate temporary bkg buff for data conversion */
+ if(NULL == (bkg = H5FL_BLK_MALLOC(type_conv, buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer")
+ } /* end if */
+
+ /* Loop over copying data */
+ addr_src = storage_src->addr;
+ addr_dst = storage_dst->addr;
+ while(total_src_nbytes > 0) {
+ /* Check if we should reduce the number of bytes to transfer */
+ if(total_src_nbytes < src_nbytes) {
+ /* Adjust bytes to transfer */
+ src_nbytes = (size_t)total_src_nbytes;
+
+ /* Adjust dataspace describing buffer */
+ if(is_vlen) {
+ /* Adjust destination & memory bytes to transfer */
+ nelmts = src_nbytes / src_dt_size;
+ dst_nbytes = nelmts * dst_dt_size;
+ mem_nbytes = nelmts * mem_dt_size;
+
+ /* Adjust size of buffer's dataspace dimension */
+ buf_dim[0] = nelmts;
+
+ /* Adjust size of buffer's dataspace */
+ if(H5S_set_extent_real(buf_space, buf_dim) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to change buffer dataspace size")
+ } /* end if */
+ else
+ /* Adjust destination & memory bytes to transfer */
+ dst_nbytes = mem_nbytes = src_nbytes;
+ } /* end if */
+
+ /* Read raw data from source file - use raw dxpl because passed in one is metadata */
+ if(H5F_block_read(f_src, H5FD_MEM_DRAW, addr_src, src_nbytes, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read raw data")
+
+ /* Perform datatype conversion, if necessary */
+ if(is_vlen) {
+ /* Convert from source file to memory */
+ if(H5T_convert(tpath_src_mem, tid_src, tid_mem, nelmts, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ /* Copy into another buffer, to reclaim memory later */
+ HDmemcpy(reclaim_buf, buf, mem_nbytes);
+
+ /* Set background buffer to all zeros */
+ HDmemset(bkg, 0, buf_size);
+
+ /* Convert from memory to destination file */
+ if(H5T_convert(tpath_mem_dst, tid_mem, tid_dst, nelmts, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ /* Reclaim space from variable length data */
+ if(H5D_vlen_reclaim(tid_mem, buf_space, dxpl_id, reclaim_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to reclaim variable-length data")
+ } /* end if */
+ else if(fix_ref) {
+ /* Check for expanding references */
+ if(cpy_info->expand_ref) {
+ size_t ref_count;
+
+ /* Determine # of reference elements to copy */
+ ref_count = src_nbytes / H5T_get_size(dt_src);
+
+ /* Copy the reference elements */
+ if(H5O_copy_expand_ref(f_src, buf, dxpl_id, f_dst, bkg, ref_count, H5T_get_ref_type(dt_src), cpy_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy reference attribute")
+
+ /* After fix ref, copy the new reference elements to the buffer to write out */
+ HDmemcpy(buf, bkg, buf_size);
+ } /* end if */
+ else
+ /* Reset value to zero */
+ HDmemset(buf, 0, src_nbytes);
+ } /* end if */
+
+ /* Write raw data to destination file - use raw dxpl because passed in one is metadata */
+ if(H5F_block_write(f_dst, H5FD_MEM_DRAW, addr_dst, dst_nbytes, H5AC_rawdata_dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data")
+
+ /* Adjust loop variables */
+ addr_src += src_nbytes;
+ addr_dst += dst_nbytes;
+ total_src_nbytes -= src_nbytes;
+ } /* end while */
+
+done:
+ if(buf_sid > 0 && H5I_dec_ref(buf_sid) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't decrement temporary dataspace ID")
+ if(tid_src > 0 && H5I_dec_ref(tid_src) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_dst > 0 && H5I_dec_ref(tid_dst) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tid_mem > 0 && H5I_dec_ref(tid_mem) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(buf)
+ buf = H5FL_BLK_FREE(type_conv, buf);
+ if(reclaim_buf)
+ reclaim_buf = H5FL_BLK_FREE(type_conv, reclaim_buf);
+ if(bkg)
+ bkg = H5FL_BLK_FREE(type_conv, bkg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_copy() */
+
diff --git a/src/H5Ddbg.c b/src/H5Ddbg.c
new file mode 100644
index 0000000..b1efb20
--- /dev/null
+++ b/src/H5Ddbg.c
@@ -0,0 +1,98 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ddebug
+ *
+ * Purpose: Prints various information about a dataset. This function is
+ * not to be documented in the API at this time.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 28, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ddebug(hid_t dset_id)
+{
+ H5D_t *dset; /* Dataset to debug */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", dset_id);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* Print B-tree information */
+ if(H5D_CHUNKED == dset->shared->layout.type)
+ (void)H5D__chunk_dump_index(dset, H5AC_ind_read_dxpl_id, stdout);
+ else if(H5D_CONTIGUOUS == dset->shared->layout.type)
+ HDfprintf(stdout, " %-10s %a\n", "Address:", dset->shared->layout.storage.u.contig.addr);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ddebug() */
+
diff --git a/src/H5Ddeprec.c b/src/H5Ddeprec.c
new file mode 100644
index 0000000..8d9461c
--- /dev/null
+++ b/src/H5Ddeprec.c
@@ -0,0 +1,378 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ddeprec.c
+ * April 5 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5D interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+static herr_t H5D__extend(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dcreate1
+ *
+ * Purpose: Creates a new dataset named NAME at LOC_ID, opens the
+ * dataset for access, and associates with that dataset constant
+ * and initial persistent properties including the type of each
+ * datapoint as stored in the file (TYPE_ID), the size of the
+ * dataset (SPACE_ID), and other initial miscellaneous
+ * properties (DCPL_ID).
+ *
+ * All arguments are copied into the dataset, so the caller is
+ * allowed to derive new types, data spaces, and creation
+ * parameters from the old ones and reuse them in calls to
+ * create other datasets.
+ *
+ * Return: Success: The object ID of the new dataset. At this
+ * point, the dataset is ready to receive its
+ * raw data. Attempting to read raw data from
+ * the dataset will probably return the fill
+ * value. The dataset should be closed when
+ * the caller is no longer interested in it.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 3, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dcreate1(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id,
+ hid_t dcpl_id)
+{
+ H5G_loc_t loc; /* Object location to insert dataset into */
+ H5D_t *dset = NULL; /* New dataset's info */
+ const H5S_t *space; /* Dataspace for dataset */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("i", "i*siii", loc_id, name, type_id, space_id, dcpl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location ID")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(H5I_DATATYPE != H5I_get_type(type_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype ID")
+ if(NULL == (space = (const H5S_t *)H5I_object_verify(space_id,H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace ID")
+ if(H5P_DEFAULT == dcpl_id)
+ dcpl_id = H5P_DATASET_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dcpl_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not dataset create property list ID")
+
+ /* Build and open the new dataset */
+ if(NULL == (dset = H5D__create_named(&loc, name, type_id, space, H5P_LINK_CREATE_DEFAULT, dcpl_id, H5P_DATASET_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset")
+
+ /* Register the new dataset to get an ID for it */
+ if((ret_value = H5I_register(H5I_DATASET, dset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register dataset")
+
+done:
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dcreate1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dopen1
+ *
+ * Purpose: Finds a dataset named NAME at LOC_ID, opens it, and returns
+ * its ID. The dataset should be close when the caller is no
+ * longer interested in it.
+ *
+ * Note: Deprecated in favor of H5Dopen2
+ *
+ * Return: Success: A new dataset ID
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Dopen1(hid_t loc_id, const char *name)
+{
+ H5D_t *dset = NULL;
+ H5G_loc_t loc; /* Object location of group */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "i*s", loc_id, name);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Open the dataset */
+ if(NULL == (dset = H5D__open_name(&loc, name, H5P_DATASET_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
+
+ /* Register an atom for the dataset */
+ if((ret_value = H5I_register(H5I_DATASET, dset, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "can't register dataset atom")
+
+done:
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dopen1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dextend
+ *
+ * Purpose: This function makes sure that the dataset is at least of size
+ * SIZE. The dimensionality of SIZE is the same as the data
+ * space of the dataset being changed.
+ *
+ * Note: Deprecated in favor of H5Dset_extent
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dextend(hid_t dset_id, const hsize_t size[])
+{
+ H5D_t *dset;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", dset_id, size);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(!size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no size specified")
+
+ /* Increase size */
+ if(H5D__extend(dset, size, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to extend dataset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dextend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__extend
+ *
+ * Purpose: Increases the size of a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__extend(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id)
+{
+ htri_t changed; /* Flag to indicate that the dataspace was successfully extended */
+ hsize_t old_dims[H5S_MAX_RANK]; /* Current (i.e. old, if changed) dimension sizes */
+ H5O_fill_t *fill; /* Dataset's fill value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(dataset);
+ HDassert(size);
+
+ /* Check if the filters in the DCPL will need to encode, and if so, can they? */
+ if(H5D__check_filters(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't apply filters")
+
+ /*
+ * NOTE: Restrictions on extensions were checked when the dataset was
+ * created. All extensions are allowed here since none should be
+ * able to muck things up.
+ */
+
+ /* Retrieve the current dimensions */
+ HDcompile_assert(sizeof(old_dims) == sizeof(dataset->shared->curr_dims));
+ HDmemcpy(old_dims, dataset->shared->curr_dims, H5S_MAX_RANK * sizeof(old_dims[0]));
+
+ /* Increase the size of the data space */
+ if((changed = H5S_extend(dataset->shared->space, size)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to increase size of dataspace")
+
+ /* Updated the dataset's info if the dataspace was successfully extended */
+ if(changed) {
+ /* Get the extended dimension sizes */
+ /* (Need to retrieve this here, since the 'size' dimensions could
+ * extend one dimension but be smaller in a different dimension,
+ * and the dataspace's extent is the larger of the current and
+ * 'size' dimension values. - QAK)
+ */
+ if(H5S_get_simple_extent_dims(dataset->shared->space, dataset->shared->curr_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions")
+
+ /* Update the index values for the cached chunks for this dataset */
+ if(H5D_CHUNKED == dataset->shared->layout.type) {
+ hbool_t update_chunks = FALSE; /* Flag to indicate chunk cache update is needed */
+
+ /* Check if we need to track & update scaled dimension information */
+ if(dataset->shared->ndims > 1) {
+ unsigned u; /* Local indicate variable */
+
+ /* Update scaled chunk information */
+ for(u = 0; u < dataset->shared->ndims; u++) {
+ hsize_t scaled; /* Scaled value */
+
+ /* Compute the scaled dimension size value */
+ scaled = size[u] / dataset->shared->layout.u.chunk.dim[u];
+
+ /* Check if scaled dimension size changed */
+ if(scaled != dataset->shared->cache.chunk.scaled_dims[u]) {
+ hsize_t scaled_power2up; /* New size value, rounded to next power of 2 */
+
+ /* Update the scaled dimension size value for the current dimension */
+ dataset->shared->cache.chunk.scaled_dims[u] = scaled;
+
+ /* Check if algorithm for computing hash values will change */
+ if((scaled > dataset->shared->cache.chunk.nslots &&
+ dataset->shared->cache.chunk.scaled_dims[u] <= dataset->shared->cache.chunk.nslots)
+ || (scaled <= dataset->shared->cache.chunk.nslots &&
+ dataset->shared->cache.chunk.scaled_dims[u] > dataset->shared->cache.chunk.nslots))
+ update_chunks = TRUE;
+
+ /* Check if the number of bits required to encode the scaled size value changed */
+ if(dataset->shared->cache.chunk.scaled_power2up[u] != (scaled_power2up = H5VM_power2up(scaled))) {
+ /* Update the 'power2up' & 'encode_bits' values for the current dimension */
+ dataset->shared->cache.chunk.scaled_power2up[u] = scaled_power2up;
+ dataset->shared->cache.chunk.scaled_encode_bits[u] = H5VM_log2_gen(scaled_power2up);
+
+ /* Indicate that the chunk cache indices should be updated */
+ update_chunks = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Update general information for chunks */
+ if(H5D__chunk_set_info(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to update # of chunks")
+
+ /* Check for updating chunk cache indices */
+ if(update_chunks) {
+ /* Update the chunk cache indices */
+ if(H5D__chunk_update_cache(dataset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to update cached chunk indices")
+ } /* end if */
+ } /* end if */
+
+ /* Allocate space for the new parts of the dataset, if appropriate */
+ fill = &dataset->shared->dcpl_cache.fill;
+ if(fill->alloc_time == H5D_ALLOC_TIME_EARLY) {
+ H5D_io_info_t io_info;
+
+ io_info.dset = dataset;
+ io_info.raw_dxpl_id = H5AC_rawdata_dxpl_id;
+ io_info.md_dxpl_id = dxpl_id;
+
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_EXTEND, FALSE, old_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize dataset with fill value")
+ }
+ /* Mark the dataspace as dirty, for later writing to the file */
+ if(H5D__mark(dataset, dxpl_id, H5D_MARK_SPACE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__extend() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Dearray.c b/src/H5Dearray.c
new file mode 100644
index 0000000..1df0a58
--- /dev/null
+++ b/src/H5Dearray.c
@@ -0,0 +1,1834 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, January 27, 2009
+ *
+ * Purpose: Extensible array indexed (chunked) I/O functions. The chunks
+ * are given a single-dimensional index which is used as the
+ * offset in an extensible array that maps a chunk coordinate to
+ * a disk address.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EAprivate.h" /* Extensible arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Value to fill unset array elements with */
+#define H5D_EARRAY_FILL HADDR_UNDEF
+#define H5D_EARRAY_FILT_FILL {HADDR_UNDEF, 0, 0}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Extensible array create/open user data */
+typedef struct H5D_earray_ctx_ud_t {
+ const H5F_t *f; /* Pointer to file info */
+ uint32_t chunk_size; /* Size of chunk (bytes) */
+} H5D_earray_ctx_ud_t;
+
+/* Extensible array callback context */
+typedef struct H5D_earray_ctx_t {
+ size_t file_addr_len; /* Size of addresses in the file (bytes) */
+ size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */
+} H5D_earray_ctx_t;
+
+/* User data for chunk callbacks */
+typedef struct H5D_earray_ud_t {
+ H5F_t *f; /* File pointer for operation */
+ hid_t dxpl_id; /* DXPL ID for operation */
+} H5D_earray_ud_t;
+
+/* Extensible Array callback info for iteration over chunks */
+typedef struct H5D_earray_it_ud_t {
+ H5D_chunk_common_ud_t common; /* Common info for Fixed Array user data (must be first) */
+ H5D_chunk_rec_t chunk_rec; /* Generic chunk record for callback */
+ hbool_t filtered; /* Whether the chunks are filtered */
+ H5D_chunk_cb_func_t cb; /* Chunk callback routine */
+ void *udata; /* User data for chunk callback routine */
+} H5D_earray_it_ud_t;
+
+/* Native extensible array element for chunks w/filters */
+typedef struct H5D_earray_filt_elmt_t {
+ haddr_t addr; /* Address of chunk */
+ uint32_t nbytes; /* Size of chunk (in file) */
+ uint32_t filter_mask; /* Excluded filters for chunk */
+} H5D_earray_filt_elmt_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+/* Extensible array iterator callbacks */
+static int H5D__earray_idx_iterate_cb(hsize_t idx, const void *_elmt, void *_udata);
+static int H5D__earray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
+
+/* Extensible array class callbacks for chunks w/o filters */
+static void *H5D__earray_crt_context(void *udata);
+static herr_t H5D__earray_dst_context(void *ctx);
+static herr_t H5D__earray_fill(void *nat_blk, size_t nelmts);
+static herr_t H5D__earray_encode(void *raw, const void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__earray_decode(const void *raw, void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__earray_debug(FILE *stream, int indent, int fwidth,
+ hsize_t idx, const void *elmt);
+static void *H5D__earray_crt_dbg_context(H5F_t *f, hid_t dxpl_id, haddr_t obj_addr);
+static herr_t H5D__earray_dst_dbg_context(void *dbg_ctx);
+
+/* Extensible array class callbacks for chunks w/filters */
+/* (some shared with callbacks for chunks w/o filters) */
+static herr_t H5D__earray_filt_fill(void *nat_blk, size_t nelmts);
+static herr_t H5D__earray_filt_encode(void *raw, const void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__earray_filt_decode(const void *raw, void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__earray_filt_debug(FILE *stream, int indent, int fwidth,
+ hsize_t idx, const void *elmt);
+
+/* Chunked layout indexing callbacks */
+static herr_t H5D__earray_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+static herr_t H5D__earray_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__earray_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__earray_idx_insert(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+static herr_t H5D__earray_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static herr_t H5D__earray_idx_resize(H5O_layout_chunk_t *layout);
+static int H5D__earray_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__earray_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__earray_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__earray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__earray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id);
+static herr_t H5D__earray_idx_size(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *size);
+static herr_t H5D__earray_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__earray_idx_dump(const H5O_storage_chunk_t *storage,
+ FILE *stream);
+static herr_t H5D__earray_idx_dest(const H5D_chk_idx_info_t *idx_info);
+
+/* Generic extensible array routines */
+static herr_t H5D__earray_idx_open(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__earray_idx_depend(const H5D_chk_idx_info_t *idx_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Extensible array indexed chunk I/O ops */
+const H5D_chunk_ops_t H5D_COPS_EARRAY[1] = {{
+ TRUE, /* Extensible array indices support SWMR access */
+ H5D__earray_idx_init, /* init */
+ H5D__earray_idx_create, /* create */
+ H5D__earray_idx_is_space_alloc, /* is_space_alloc */
+ H5D__earray_idx_insert, /* insert */
+ H5D__earray_idx_get_addr, /* get_addr */
+ H5D__earray_idx_resize, /* resize */
+ H5D__earray_idx_iterate, /* iterate */
+ H5D__earray_idx_remove, /* remove */
+ H5D__earray_idx_delete, /* delete */
+ H5D__earray_idx_copy_setup, /* copy_setup */
+ H5D__earray_idx_copy_shutdown, /* copy_shutdown */
+ H5D__earray_idx_size, /* size */
+ H5D__earray_idx_reset, /* reset */
+ H5D__earray_idx_dump, /* dump */
+ H5D__earray_idx_dest /* destroy */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Extensible array class callbacks for dataset chunks w/o filters */
+const H5EA_class_t H5EA_CLS_CHUNK[1]={{
+ H5EA_CLS_CHUNK_ID, /* Type of extensible array */
+ "Chunk w/o filters", /* Name of extensible array class */
+ sizeof(haddr_t), /* Size of native element */
+ H5D__earray_crt_context, /* Create context */
+ H5D__earray_dst_context, /* Destroy context */
+ H5D__earray_fill, /* Fill block of missing elements callback */
+ H5D__earray_encode, /* Element encoding callback */
+ H5D__earray_decode, /* Element decoding callback */
+ H5D__earray_debug, /* Element debugging callback */
+ H5D__earray_crt_dbg_context, /* Create debugging context */
+ H5D__earray_dst_dbg_context /* Destroy debugging context */
+}};
+
+/* Extensible array class callbacks for dataset chunks w/filters */
+const H5EA_class_t H5EA_CLS_FILT_CHUNK[1]={{
+ H5EA_CLS_FILT_CHUNK_ID, /* Type of extensible array */
+ "Chunk w/filters", /* Name of extensible array class */
+ sizeof(H5D_earray_filt_elmt_t), /* Size of native element */
+ H5D__earray_crt_context, /* Create context */
+ H5D__earray_dst_context, /* Destroy context */
+ H5D__earray_filt_fill, /* Fill block of missing elements callback */
+ H5D__earray_filt_encode, /* Element encoding callback */
+ H5D__earray_filt_decode, /* Element decoding callback */
+ H5D__earray_filt_debug, /* Element debugging callback */
+ H5D__earray_crt_dbg_context, /* Create debugging context */
+ H5D__earray_dst_dbg_context /* Destroy debugging context */
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5D_earray_ctx_t struct */
+/* Declare a free list to manage the H5D_earray_ctx_ud_t struct */
+H5FL_DEFINE_STATIC(H5D_earray_ctx_t);
+H5FL_DEFINE_STATIC(H5D_earray_ctx_ud_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_crt_context
+ *
+ * Purpose: Create context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__earray_crt_context(void *_udata)
+{
+ H5D_earray_ctx_t *ctx; /* Extensible array callback context */
+ H5D_earray_ctx_ud_t *udata = (H5D_earray_ctx_ud_t *)_udata; /* User data for extensible array context */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->chunk_size > 0);
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5D_earray_ctx_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate extensible array client callback context")
+
+ /* Initialize the context */
+ ctx->file_addr_len = H5F_SIZEOF_ADDR(udata->f);
+
+ /* Compute the size required for encoding the size of a chunk, allowing
+ * for an extra byte, in case the filter makes the chunk larger.
+ */
+ ctx->chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)udata->chunk_size) + 8) / 8);
+ if(ctx->chunk_size_len > 8)
+ ctx->chunk_size_len = 8;
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_dst_context
+ *
+ * Purpose: Destroy context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_dst_context(void *_ctx)
+{
+ H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(ctx);
+
+ /* Release context structure */
+ ctx = H5FL_FREE(H5D_earray_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_fill(void *nat_blk, size_t nelmts)
+{
+ haddr_t fill_val = H5D_EARRAY_FILL; /* Value to fill elements with */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+
+ H5VM_array_fill(nat_blk, &fill_val, H5EA_CLS_CHUNK->nat_elmt_size, nelmts);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_encode(void *raw, const void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
+ const haddr_t *elmt = (const haddr_t *)_elmt; /* Convenience pointer to native elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(ctx);
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_encode_len(ctx->file_addr_len, (uint8_t **)&raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
+ haddr_t *elmt = (haddr_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_decode_len(ctx->file_addr_len, &raw, elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *elmt)
+{
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, temp_str,
+ *(const haddr_t *)elmt);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_filt_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_filt_fill(void *nat_blk, size_t nelmts)
+{
+ H5D_earray_filt_elmt_t fill_val = H5D_EARRAY_FILT_FILL; /* Value to fill elements with */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+ HDassert(sizeof(fill_val) == H5EA_CLS_FILT_CHUNK->nat_elmt_size);
+
+ H5VM_array_fill(nat_blk, &fill_val, H5EA_CLS_FILT_CHUNK->nat_elmt_size, nelmts);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_filt_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_filt_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_filt_encode(void *_raw, const void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
+ uint8_t *raw = (uint8_t *)_raw; /* Convenience pointer to raw elements */
+ const H5D_earray_filt_elmt_t *elmt = (const H5D_earray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(ctx);
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_encode_len(ctx->file_addr_len, &raw, elmt->addr);
+ UINT64ENCODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
+ UINT32ENCODE(raw, elmt->filter_mask);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_filt_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_filt_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_filt_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_earray_ctx_t *ctx = (H5D_earray_ctx_t *)_ctx; /* Extensible array callback context */
+ H5D_earray_filt_elmt_t *elmt = (H5D_earray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_decode_len(ctx->file_addr_len, &raw, &elmt->addr);
+ UINT64DECODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
+ UINT32DECODE(raw, elmt->filter_mask);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_filt_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_filt_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_filt_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *_elmt)
+{
+ const H5D_earray_filt_elmt_t *elmt = (const H5D_earray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s {%a, %u, %0x}\n", indent, "", fwidth, temp_str,
+ elmt->addr, elmt->nbytes, elmt->filter_mask);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_filt_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_crt_dbg_context
+ *
+ * Purpose: Create context for debugging callback
+ * (get the layout message in the specified object header)
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi; July 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__earray_crt_dbg_context(H5F_t *f, hid_t dxpl_id, haddr_t obj_addr)
+{
+ H5D_earray_ctx_ud_t *dbg_ctx = NULL; /* Context for fixed array callback */
+ H5O_loc_t obj_loc; /* Pointer to an object's location */
+ hbool_t obj_opened = FALSE; /* Flag to indicate that the object header was opened */
+ H5O_layout_t layout; /* Layout message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(H5F_addr_defined(obj_addr));
+
+ /* Allocate context for debugging callback */
+ if(NULL == (dbg_ctx = H5FL_MALLOC(H5D_earray_ctx_ud_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate extensible array client callback context")
+
+ /* Set up the object header location info */
+ H5O_loc_reset(&obj_loc);
+ obj_loc.file = f;
+ obj_loc.addr = obj_addr;
+
+ /* Open the object header where the layout message resides */
+ if(H5O_open(&obj_loc) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "can't open object header")
+ obj_opened = TRUE;
+
+ /* Read the layout message */
+ if(NULL == H5O_msg_read(&obj_loc, H5O_LAYOUT_ID, &layout, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get layout info")
+
+ /* close the object header */
+ if(H5O_close(&obj_loc, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header")
+
+ /* Create user data */
+ dbg_ctx->f = f;
+ dbg_ctx->chunk_size = layout.u.chunk.size;
+
+ /* Set return value */
+ ret_value = dbg_ctx;
+
+done:
+ /* Cleanup on error */
+ if(ret_value == NULL) {
+ /* Release context structure */
+ if(dbg_ctx)
+ dbg_ctx = H5FL_FREE(H5D_earray_ctx_ud_t, dbg_ctx);
+
+ /* Close object header */
+ if(obj_opened) {
+ if(H5O_close(&obj_loc, NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_crt_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_dst_dbg_context
+ *
+ * Purpose: Destroy context for debugging callback
+ * (free the layout message from the specified object header)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; July 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_dst_dbg_context(void *_dbg_ctx)
+{
+ H5D_earray_ctx_ud_t *dbg_ctx = (H5D_earray_ctx_ud_t *)_dbg_ctx; /* Context for extensible array callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(dbg_ctx);
+
+ /* Release context structure */
+ dbg_ctx = H5FL_FREE(H5D_earray_ctx_ud_t, dbg_ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_dst_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_depend
+ *
+ * Purpose: Create flush dependency between extensible array and dataset's
+ * object header.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 2, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_depend(const H5D_chk_idx_info_t *idx_info)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5AC_proxy_entry_t *oh_proxy; /* Dataset's object header proxy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5D_CHUNK_IDX_EARRAY == idx_info->storage->idx_type);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(idx_info->storage->u.earray.ea);
+
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.earray.dset_ohdr_addr;
+
+ /* Get header */
+ if(NULL == (oh = H5O_protect(&oloc, idx_info->dxpl_id, H5AC__READ_ONLY_FLAG, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Retrieve the dataset's object header proxy */
+ if(NULL == (oh_proxy = H5O_get_proxy(oh)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy")
+
+ /* Make the extensible array a child flush dependency of the dataset's object header */
+ if(H5EA_depend(idx_info->storage->u.earray.ea, idx_info->dxpl_id, oh_proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header proxy")
+
+done:
+ /* Release the object header from the cache */
+ if(oh && H5O_unprotect(&oloc, idx_info->dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_open
+ *
+ * Purpose: Opens an existing extensible array.
+ *
+ * Note: This information is passively initialized from each index
+ * operation callback because those abstract chunk index operations
+ * are designed to work with the v1 B-tree chunk indices also,
+ * which don't require an 'open' for the data structure.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_open(const H5D_chk_idx_info_t *idx_info)
+{
+ H5D_earray_ctx_ud_t udata; /* User data for extensible array open call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_EARRAY == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5D_CHUNK_IDX_EARRAY == idx_info->storage->idx_type);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(NULL == idx_info->storage->u.earray.ea);
+
+ /* Set up the user data */
+ udata.f = idx_info->f;
+ udata.chunk_size = idx_info->layout->size;
+
+ /* Open the extensible array for the chunk index */
+ if(NULL == (idx_info->storage->u.earray.ea = H5EA_open(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &udata)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open extensible array")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__earray_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_init
+ *
+ * Purpose: Initialize the indexing information for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space,
+ haddr_t dset_ohdr_addr)
+{
+ hsize_t max_dims[H5O_LAYOUT_NDIMS]; /* Max. size of dataset dimensions */
+ int unlim_dim; /* Rank of the dataset's unlimited dimension */
+ int sndims; /* Rank of dataspace */
+ unsigned ndims; /* Rank of dataspace */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(space);
+ HDassert(H5F_addr_defined(dset_ohdr_addr));
+
+ /* Get the dim info for dataset */
+ if((sndims = H5S_get_simple_extent_dims(space, NULL, max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions")
+ H5_CHECKED_ASSIGN(ndims, unsigned, sndims, int);
+
+ /* Find the rank of the unlimited dimension */
+ unlim_dim = (-1);
+ for(u = 0; u < ndims; u++) {
+ /* Check for unlimited dimension */
+ if(H5S_UNLIMITED == max_dims[u]) {
+ /* Check if we've already found an unlimited dimension */
+ if(unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_ALREADYINIT, FAIL, "already found unlimited dimension")
+
+ /* Set the unlimited dimension */
+ unlim_dim = (int)u;
+ } /* end if */
+ } /* end for */
+
+ /* Check if we didn't find an unlimited dimension */
+ if(unlim_dim < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNINITIALIZED, FAIL, "didn't find unlimited dimension")
+
+ /* Set the unlimited dimension for the layout's future use */
+ idx_info->layout->u.earray.unlim_dim = (unsigned)unlim_dim;
+
+ /* Store the dataset's object header address for later */
+ idx_info->storage->u.earray.dset_ohdr_addr = dset_ohdr_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_create
+ *
+ * Purpose: Creates a new indexed-storage extensible array and initializes
+ * the layout struct with information about the storage. The
+ * struct should be immediately written to the object header.
+ *
+ * This function must be called before passing LAYOUT to any of
+ * the other indexed storage functions!
+ *
+ * Return: Non-negative on success (with the LAYOUT argument initialized
+ * and ready to write to an object header). Negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ H5EA_create_t cparam; /* Extensible array creation parameters */
+ H5D_earray_ctx_ud_t udata; /* User data for extensible array create call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(NULL == idx_info->storage->u.earray.ea);
+
+ /* General parameters */
+ if(idx_info->pline->nused > 0) {
+ unsigned chunk_size_len; /* Size of encoded chunk size */
+
+ /* Compute the size required for encoding the size of a chunk, allowing
+ * for an extra byte, in case the filter makes the chunk larger.
+ */
+ chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)idx_info->layout->size) + 8) / 8);
+ if(chunk_size_len > 8)
+ chunk_size_len = 8;
+
+ cparam.cls = H5EA_CLS_FILT_CHUNK;
+ cparam.raw_elmt_size = (uint8_t)(H5F_SIZEOF_ADDR(idx_info->f) + chunk_size_len + 4);
+ } /* end if */
+ else {
+ cparam.cls = H5EA_CLS_CHUNK;
+ cparam.raw_elmt_size = (uint8_t)H5F_SIZEOF_ADDR(idx_info->f);
+ } /* end else */
+ cparam.max_nelmts_bits = idx_info->layout->u.earray.cparam.max_nelmts_bits;
+ HDassert(cparam.max_nelmts_bits > 0);
+ cparam.idx_blk_elmts = idx_info->layout->u.earray.cparam.idx_blk_elmts;
+ HDassert(cparam.idx_blk_elmts > 0);
+ cparam.sup_blk_min_data_ptrs = idx_info->layout->u.earray.cparam.sup_blk_min_data_ptrs;
+ HDassert(cparam.sup_blk_min_data_ptrs > 0);
+ cparam.data_blk_min_elmts = idx_info->layout->u.earray.cparam.data_blk_min_elmts;
+ HDassert(cparam.data_blk_min_elmts > 0);
+ cparam.max_dblk_page_nelmts_bits = idx_info->layout->u.earray.cparam.max_dblk_page_nelmts_bits;
+ HDassert(cparam.max_dblk_page_nelmts_bits > 0);
+
+ /* Set up the user data */
+ udata.f = idx_info->f;
+ udata.chunk_size = idx_info->layout->size;
+
+ /* Create the extensible array for the chunk index */
+ if(NULL == (idx_info->storage->u.earray.ea = H5EA_create(idx_info->f, idx_info->dxpl_id, &cparam, &udata)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create extensible array")
+
+ /* Get the address of the extensible array in file */
+ if(H5EA_get_addr(idx_info->storage->u.earray.ea, &(idx_info->storage->idx_addr)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query extensible array address")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__earray_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for index method
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__earray_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__earray_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_insert
+ *
+ * Purpose: Insert chunk address into the indexing structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; May 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
+ const H5D_t H5_ATTR_UNUSED *dset)
+{
+ H5EA_t *ea; /* Pointer to extensible array structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the extensible array is open yet */
+ if(NULL == idx_info->storage->u.earray.ea) {
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+ } else /* Patch the top level file pointer contained in ea if needed */
+ H5EA_patch_file(idx_info->storage->u.earray.ea, idx_info->f);
+
+ /* Set convenience pointer to extensible array structure */
+ ea = idx_info->storage->u.earray.ea;
+
+ if(!H5F_addr_defined(udata->chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "The chunk should have allocated already")
+ if(udata->chunk_idx != (udata->chunk_idx & 0xffffffff)) /* negative value */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk index must be less than 2^32")
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_earray_filt_elmt_t elmt; /* Extensible array element */
+
+ elmt.addr = udata->chunk_block.offset;
+ H5_CHECKED_ASSIGN(elmt.nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ elmt.filter_mask = udata->filter_mask;
+
+ /* Set the info for the chunk */
+ if(H5EA_set(ea, idx_info->dxpl_id, udata->chunk_idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk info")
+ } /* end if */
+ else {
+ /* Set the address for the chunk */
+ if(H5EA_set(ea, idx_info->dxpl_id, udata->chunk_idx, &udata->chunk_block.offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk address")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__earray_idx_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk if file space has been
+ * assigned. Save the retrieved information in the udata
+ * supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ H5EA_t *ea; /* Pointer to extensible array structure */
+ hsize_t idx; /* Array index of chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the extensible array is open yet */
+ if(NULL == idx_info->storage->u.earray.ea) {
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+ } else /* Patch the top level file pointer contained in ea if needed */
+ H5EA_patch_file(idx_info->storage->u.earray.ea, idx_info->f);
+
+ /* Set convenience pointer to extensible array structure */
+ ea = idx_info->storage->u.earray.ea;
+
+ /* Check for unlimited dim. not being the slowest-changing dim. */
+ if(idx_info->layout->u.earray.unlim_dim > 0) {
+ hsize_t swizzled_coords[H5O_LAYOUT_NDIMS]; /* swizzled chunk coordinates */
+ unsigned ndims = (idx_info->layout->ndims - 1); /* Number of dimensions */
+ unsigned u;
+
+ /* Compute coordinate offset from scaled offset */
+ for(u = 0; u < ndims; u++)
+ swizzled_coords[u] = udata->common.scaled[u] * idx_info->layout->dim[u];
+
+ H5VM_swizzle_coords(hsize_t, swizzled_coords, idx_info->layout->u.earray.unlim_dim);
+
+ /* Calculate the index of this chunk */
+ idx = H5VM_chunk_index(ndims, swizzled_coords, idx_info->layout->u.earray.swizzled_dim, idx_info->layout->u.earray.swizzled_max_down_chunks);
+ } /* end if */
+ else {
+ /* Calculate the index of this chunk */
+ idx = H5VM_array_offset_pre((idx_info->layout->ndims - 1), idx_info->layout->max_down_chunks, udata->common.scaled);
+ } /* end else */
+
+ udata->chunk_idx = idx;
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_earray_filt_elmt_t elmt; /* Extensible array element */
+
+ /* Get the information for the chunk */
+ if(H5EA_get(ea, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
+
+ /* Set the info for the chunk */
+ udata->chunk_block.offset = elmt.addr;
+ udata->chunk_block.length = elmt.nbytes;
+ udata->filter_mask = elmt.filter_mask;
+ } /* end if */
+ else {
+ /* Get the address for the chunk */
+ if(H5EA_get(ea, idx_info->dxpl_id, idx, &udata->chunk_block.offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+
+ /* Update the other (constant) information for the chunk */
+ udata->chunk_block.length = idx_info->layout->size;
+ udata->filter_mask = 0;
+ } /* end else */
+
+ if(!H5F_addr_defined(udata->chunk_block.offset))
+ udata->chunk_block.length = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__earray_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_resize
+ *
+ * Purpose: Calculate/setup the swizzled down chunk array, used for chunk
+ * index calculations.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 23, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_resize(H5O_layout_chunk_t *layout)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(layout);
+
+ /* "Swizzle" constant dimensions for this dataset */
+ if(layout->u.earray.unlim_dim > 0) {
+ hsize_t swizzled_chunks[H5O_LAYOUT_NDIMS]; /* Swizzled form of # of chunks in each dimension */
+ hsize_t swizzled_max_chunks[H5O_LAYOUT_NDIMS]; /* Swizzled form of max # of chunks in each dimension */
+
+ /* Get the swizzled chunk dimensions */
+ HDmemcpy(layout->u.earray.swizzled_dim, layout->dim, (layout->ndims - 1) * sizeof(layout->dim[0]));
+ H5VM_swizzle_coords(uint32_t, layout->u.earray.swizzled_dim, layout->u.earray.unlim_dim);
+
+ /* Get the swizzled number of chunks in each dimension */
+ HDmemcpy(swizzled_chunks, layout->chunks, (layout->ndims - 1) * sizeof(swizzled_chunks[0]));
+ H5VM_swizzle_coords(hsize_t, swizzled_chunks, layout->u.earray.unlim_dim);
+
+ /* Get the swizzled "down" sizes for each dimension */
+ if(H5VM_array_down((layout->ndims - 1), swizzled_chunks, layout->u.earray.swizzled_down_chunks) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't compute swizzled 'down' chunk size value")
+
+ /* Get the swizzled max number of chunks in each dimension */
+ HDmemcpy(swizzled_max_chunks, layout->max_chunks, (layout->ndims - 1) * sizeof(swizzled_max_chunks[0]));
+ H5VM_swizzle_coords(hsize_t, swizzled_max_chunks, layout->u.earray.unlim_dim);
+
+ /* Get the swizzled max "down" sizes for each dimension */
+ if(H5VM_array_down((layout->ndims - 1), swizzled_max_chunks, layout->u.earray.swizzled_max_down_chunks) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't compute swizzled 'down' chunk size value")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_resize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_iterate_cb
+ *
+ * Purpose: Callback routine for extensible array element iteration.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__earray_idx_iterate_cb(hsize_t H5_ATTR_UNUSED idx, const void *_elmt, void *_udata)
+{
+ H5D_earray_it_ud_t *udata = (H5D_earray_it_ud_t *)_udata; /* User data */
+ unsigned ndims; /* Rank of chunk */
+ int curr_dim; /* Current dimension */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Compose generic chunk record for callback */
+ if(udata->filtered) {
+ const H5D_earray_filt_elmt_t *filt_elmt = (const H5D_earray_filt_elmt_t *)_elmt;
+
+ udata->chunk_rec.chunk_addr = filt_elmt->addr;
+ udata->chunk_rec.nbytes = filt_elmt->nbytes;
+ udata->chunk_rec.filter_mask = filt_elmt->filter_mask;
+ } /* end if */
+ else
+ udata->chunk_rec.chunk_addr = *(const haddr_t *)_elmt;
+
+ /* Make "generic chunk" callback */
+ if(H5F_addr_defined(udata->chunk_rec.chunk_addr))
+ if((ret_value = (udata->cb)(&udata->chunk_rec, udata->udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ /* Update coordinates of chunk in dataset */
+ ndims = udata->common.layout->ndims - 1;
+ HDassert(ndims > 0);
+ curr_dim = (int)(ndims - 1);
+ while(curr_dim >= 0) {
+ /* Increment coordinate in current dimension */
+ udata->chunk_rec.scaled[curr_dim]++;
+
+ /* Check if we went off the end of the current dimension */
+ if(udata->chunk_rec.scaled[curr_dim] >= udata->common.layout->max_chunks[curr_dim]) {
+ /* Reset coordinate & move to next faster dimension */
+ udata->chunk_rec.scaled[curr_dim] = 0;
+ curr_dim--;
+ } /* end if */
+ else
+ break;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__earray_idx_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_iterate
+ *
+ * Purpose: Iterate over the chunks in an index, making a callback
+ * for each one.
+ *
+ * Note: This implementation is slow, particularly for sparse
+ * extensible arrays, replace it with call to H5EA_iterate()
+ * when that's available.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__earray_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5EA_t *ea; /* Pointer to extensible array structure */
+ H5EA_stat_t ea_stat; /* Extensible array statistics */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+
+ /* Check if the extensible array is open yet */
+ if(NULL == idx_info->storage->u.earray.ea) {
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+ } else /* Patch the top level file pointer contained in ea if needed */
+ H5EA_patch_file(idx_info->storage->u.earray.ea, idx_info->f);
+
+ /* Set convenience pointer to extensible array structure */
+ ea = idx_info->storage->u.earray.ea;
+
+ /* Get the extensible array statistics */
+ if(H5EA_get_stats(ea, &ea_stat) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query extensible array statistics")
+
+ if(ea_stat.stored.max_idx_set > 0) {
+ H5D_earray_it_ud_t udata; /* User data for iteration callback */
+
+ /* Initialize userdata */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.common.layout = idx_info->layout;
+ udata.common.storage = idx_info->storage;
+ HDmemset(&udata.chunk_rec, 0, sizeof(udata.chunk_rec));
+ udata.filtered = (idx_info->pline->nused > 0);
+ if(!udata.filtered) {
+ udata.chunk_rec.nbytes = idx_info->layout->size;
+ udata.chunk_rec.filter_mask = 0;
+ } /* end if */
+ udata.cb = chunk_cb;
+ udata.udata = chunk_udata;
+
+ /* Iterate over the extensible array elements */
+ if((ret_value = H5EA_iterate(ea, idx_info->dxpl_id, H5D__earray_idx_iterate_cb, &udata)) < 0)
+ HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over fixed array chunk index");
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_remove
+ *
+ * Purpose: Remove chunk from index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
+{
+ H5EA_t *ea; /* Pointer to extensible array structure */
+ hsize_t idx; /* Array index of chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the extensible array is open yet */
+ if(NULL == idx_info->storage->u.earray.ea) {
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+ } else /* Patch the top level file pointer contained in ea if needed */
+ if(H5EA_patch_file(idx_info->storage->u.earray.ea, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch earray file pointer")
+
+ /* Set convenience pointer to extensible array structure */
+ ea = idx_info->storage->u.earray.ea;
+
+ /* Check for unlimited dim. not being the slowest-changing dim. */
+ if(idx_info->layout->u.earray.unlim_dim > 0) {
+ hsize_t swizzled_coords[H5O_LAYOUT_NDIMS]; /* swizzled chunk coordinates */
+ unsigned ndims = (idx_info->layout->ndims - 1); /* Number of dimensions */
+ unsigned u;
+
+ /* Compute coordinate offset from scaled offset */
+ for(u = 0; u < ndims; u++)
+ swizzled_coords[u] = udata->scaled[u] * idx_info->layout->dim[u];
+
+ H5VM_swizzle_coords(hsize_t, swizzled_coords, idx_info->layout->u.earray.unlim_dim);
+
+ /* Calculate the index of this chunk */
+ idx = H5VM_chunk_index(ndims, swizzled_coords, idx_info->layout->u.earray.swizzled_dim, idx_info->layout->u.earray.swizzled_max_down_chunks);
+ } /* end if */
+ else {
+ /* Calculate the index of this chunk */
+ idx = H5VM_array_offset_pre((idx_info->layout->ndims - 1), idx_info->layout->max_down_chunks, udata->scaled);
+ } /* end else */
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_earray_filt_elmt_t elmt; /* Extensible array element */
+
+ /* Get the info about the chunk for the index */
+ if(H5EA_get(ea, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
+
+ /* Remove raw data chunk from file if not doing SWMR writes */
+ HDassert(H5F_addr_defined(elmt.addr));
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(elmt.nbytes, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
+
+ /* Reset the info about the chunk for the index */
+ elmt.addr = HADDR_UNDEF;
+ elmt.nbytes = 0;
+ elmt.filter_mask = 0;
+ if(H5EA_set(ea, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk info")
+ } /* end if */
+ else {
+ haddr_t addr = HADDR_UNDEF; /* Chunk address */
+
+ /* Get the address of the chunk for the index */
+ if(H5EA_get(ea, idx_info->dxpl_id, idx, &addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+
+ /* Remove raw data chunk from file if not doing SWMR writes */
+ HDassert(H5F_addr_defined(addr));
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(idx_info->layout->size, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, addr, (hsize_t)idx_info->layout->size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
+
+ /* Reset the address of the chunk for the index */
+ addr = HADDR_UNDEF;
+ if(H5EA_set(ea, idx_info->dxpl_id, idx, &addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk address")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__earray_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_delete_cb
+ *
+ * Purpose: Delete space for chunk in file
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__earray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_earray_ud_t *udata = (H5D_earray_ud_t *)_udata; /* User data for callback */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(chunk_rec);
+ HDassert(H5F_addr_defined(chunk_rec->chunk_addr));
+ HDassert(chunk_rec->nbytes > 0);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Remove raw data chunk from file */
+ H5_CHECK_OVERFLOW(chunk_rec->nbytes, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(udata->f, H5FD_MEM_DRAW, udata->dxpl_id, chunk_rec->chunk_addr, (hsize_t)chunk_rec->nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_delete_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_delete
+ *
+ * Purpose: Delete index and raw data storage for entire dataset
+ * (i.e. all chunks)
+ *
+ * Note: This implementation is slow, particularly for sparse
+ * extensible arrays, replace it with call to H5EA_iterate()
+ * when that's available.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 29, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ /* Check if the index data structure has been allocated */
+ if(H5F_addr_defined(idx_info->storage->idx_addr)) {
+ H5D_earray_ud_t udata; /* User data for callback */
+ H5D_earray_ctx_ud_t ctx_udata; /* User data for extensible array open call */
+
+ /* Initialize user data for callback */
+ udata.f = idx_info->f;
+ udata.dxpl_id = idx_info->dxpl_id;
+
+ /* Iterate over the chunk addresses in the extensible array, deleting each chunk */
+ if(H5D__earray_idx_iterate(idx_info, H5D__earray_idx_delete_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk addresses")
+
+ /* Close extensible array */
+ if(H5EA_close(idx_info->storage->u.earray.ea, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array")
+ idx_info->storage->u.earray.ea = NULL;
+
+ /* Set up the context user data */
+ ctx_udata.f = idx_info->f;
+ ctx_udata.chunk_size = idx_info->layout->size;
+
+ /* Delete extensible array */
+ if(H5EA_delete(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &ctx_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk extensible array")
+ idx_info->storage->idx_addr = HADDR_UNDEF;
+ } /* end if */
+ else
+ HDassert(NULL == idx_info->storage->u.earray.ea);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+ HDassert(!H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Check if the source extensible array is open yet */
+ if(NULL == idx_info_src->storage->u.earray.ea)
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info_src) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Create the extensible array that describes chunked storage in the dest. file */
+ if(H5D__earray_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+ HDassert(H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_copy_shutdown
+ *
+ * Purpose: Shutdown any information from copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(storage_src);
+ HDassert(storage_src->u.earray.ea);
+ HDassert(storage_dst);
+ HDassert(storage_dst->u.earray.ea);
+
+ /* Close extensible arrays */
+ if(H5EA_close(storage_src->u.earray.ea, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array")
+ storage_src->u.earray.ea = NULL;
+ if(H5EA_close(storage_dst->u.earray.ea, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array")
+ storage_dst->u.earray.ea = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_copy_shutdown() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
+{
+ H5EA_t *ea; /* Pointer to extensible array structure */
+ H5EA_stat_t ea_stat; /* Extensible array statistics */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(index_size);
+
+ /* Open the extensible array in file */
+ if(H5D__earray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open extensible array")
+
+ /* Set convenience pointer to extensible array structure */
+ ea = idx_info->storage->u.earray.ea;
+
+ /* Get the extensible array statistics */
+ if(H5EA_get_stats(ea, &ea_stat) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query extensible array statistics")
+
+ /* Set the size of the extensible array */
+ *index_size = ea_stat.computed.hdr_size + ea_stat.computed.index_blk_size
+ + ea_stat.stored.super_blk_size + ea_stat.stored.data_blk_size;
+
+done:
+ if(idx_info->storage->u.earray.ea) {
+ if(H5EA_close(idx_info->storage->u.earray.ea, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array")
+ idx_info->storage->u.earray.ea = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr) {
+ storage->idx_addr = HADDR_UNDEF;
+ storage->u.earray.dset_ohdr_addr = HADDR_UNDEF;
+ } /* end if */
+ storage->u.earray.ea = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_dump
+ *
+ * Purpose: Dump indexing information to a stream.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__earray_idx_dump() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__earray_idx_dest
+ *
+ * Purpose: Release indexing information in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__earray_idx_dest(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->storage);
+
+ /* Check if the extensible array is open */
+ if(idx_info->storage->u.earray.ea) {
+
+ /* Patch the top level file pointer contained in ea if needed */
+ if(H5EA_patch_file(idx_info->storage->u.earray.ea, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch earray file pointer")
+
+ /* Close extensible array */
+ if(H5EA_close(idx_info->storage->u.earray.ea, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close extensible array")
+ idx_info->storage->u.earray.ea = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__earray_idx_dest() */
+
diff --git a/src/H5Defl.c b/src/H5Defl.c
new file mode 100644
index 0000000..5536ba3
--- /dev/null
+++ b/src/H5Defl.c
@@ -0,0 +1,618 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, September 30, 2004
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Callback info for readvv operation */
+typedef struct H5D_efl_readvv_ud_t {
+ const H5O_efl_t *efl; /* Pointer to efl info */
+ const H5D_t *dset; /* The dataset */
+ unsigned char *rbuf; /* Read buffer */
+} H5D_efl_readvv_ud_t;
+
+/* Callback info for writevv operation */
+typedef struct H5D_efl_writevv_ud_t {
+ const H5O_efl_t *efl; /* Pointer to efl info */
+ const H5D_t *dset; /* The dataset */
+ const unsigned char *wbuf; /* Write buffer */
+} H5D_efl_writevv_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Layout operation callbacks */
+static herr_t H5D__efl_construct(H5F_t *f, H5D_t *dset);
+static herr_t H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *cm);
+static ssize_t H5D__efl_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+static ssize_t H5D__efl_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+
+/* Helper routines */
+static herr_t H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size,
+ uint8_t *buf);
+static herr_t H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size,
+ const uint8_t *buf);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* External File List (EFL) storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_EFL[1] = {{
+ H5D__efl_construct,
+ NULL,
+ H5D__efl_is_space_alloc,
+ H5D__efl_io_init,
+ H5D__contig_read,
+ H5D__contig_write,
+#ifdef H5_HAVE_PARALLEL
+ NULL,
+ NULL,
+#endif /* H5_HAVE_PARALLEL */
+ H5D__efl_readvv,
+ H5D__efl_writevv,
+ NULL,
+ NULL,
+ NULL
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_construct
+ *
+ * Purpose: Constructs new EFL layout information for dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_construct(H5F_t *f, H5D_t *dset)
+{
+ size_t dt_size; /* Size of datatype */
+ hssize_t stmp_size; /* Temporary holder for raw data size */
+ hsize_t tmp_size; /* Temporary holder for raw data size */
+ hsize_t max_points; /* Maximum elements */
+ hsize_t max_storage; /* Maximum storage size */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(dset);
+
+ /*
+ * The maximum size of the dataset cannot exceed the storage size.
+ * Also, only the slowest varying dimension of a simple data space
+ * can be extendible (currently only for external data storage).
+ */
+
+ /* Check for invalid dataset dimensions */
+ for(u = 1; u < dset->shared->ndims; u++)
+ if(dset->shared->max_dims[u] > dset->shared->curr_dims[u])
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "only the first dimension can be extendible")
+
+ /* Retrieve the size of the dataset's datatype */
+ if(0 == (dt_size = H5T_get_size(dset->shared->type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size")
+
+ /* Check for storage overflows */
+ max_points = H5S_get_npoints_max(dset->shared->space);
+ max_storage = H5O_efl_total_size(&dset->shared->dcpl_cache.efl);
+ if(H5S_UNLIMITED == max_points) {
+ if(H5O_EFL_UNLIMITED != max_storage)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unlimited dataspace but finite storage")
+ } /* end if */
+ else if((max_points * dt_size) < max_points)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "dataspace * type size overflowed")
+ else if((max_points * dt_size) > max_storage)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "dataspace size exceeds external storage size")
+
+ /* Compute the total size of dataset */
+ stmp_size = H5S_GET_EXTENT_NPOINTS(dset->shared->space);
+ HDassert(stmp_size >= 0);
+ tmp_size = (hsize_t)stmp_size * dt_size;
+ H5_CHECKED_ASSIGN(dset->shared->layout.storage.u.contig.size, hsize_t, tmp_size, hssize_t);
+
+ /* Get the sieve buffer size for this dataset */
+ dset->shared->cache.contig.sieve_buf_size = H5F_SIEVE_BUF_SIZE(f);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_construct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for layout
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5D__efl_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(storage);
+
+ /* EFL storage is currently always treated as allocated */
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* end H5D__efl_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_io_init
+ *
+ * Purpose: Performs initialization before any sort of I/O on the raw data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *cm)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDmemcpy(&io_info->store->efl, &(io_info->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__efl_io_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_read
+ *
+ * Purpose: Reads data from an external file list. It is an error to
+ * read past the logical end of file, but reading past the end
+ * of any particular member of the external file list results in
+ * zeros.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, uint8_t *buf)
+{
+ int fd = -1;
+ size_t to_read;
+#ifndef NDEBUG
+ hsize_t tempto_read;
+#endif /* NDEBUG */
+ hsize_t skip = 0;
+ haddr_t cur;
+ ssize_t n;
+ size_t u; /* Local index variable */
+ char *full_name = NULL; /* File name with prefix */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(efl && efl->nused > 0);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(size < SIZET_MAX);
+ HDassert(buf || 0 == size);
+
+ /* Find the first efl member from which to read */
+ for (u=0, cur=0; u<efl->nused; u++) {
+ if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) {
+ skip = addr - cur;
+ break;
+ } /* end if */
+ cur += efl->slot[u].size;
+ } /* end for */
+
+ /* Read the data */
+ while(size) {
+ HDassert(buf);
+ if(u >= efl->nused)
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "read past logical end of file")
+ if(H5F_OVERFLOW_HSIZET2OFFT((hsize_t)efl->slot[u].offset + skip))
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed")
+ if(H5_combine_path(dset->shared->extfile_prefix, efl->slot[u].name, &full_name) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_NOSPACE, FAIL, "can't build external file name")
+ if((fd = HDopen(full_name, O_RDONLY, 0)) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file")
+ if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + (HDoff_t)skip), SEEK_SET) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file")
+#ifndef NDEBUG
+ tempto_read = MIN((size_t)(efl->slot[u].size-skip), (hsize_t)size);
+ H5_CHECK_OVERFLOW(tempto_read, hsize_t, size_t);
+ to_read = (size_t)tempto_read;
+#else /* NDEBUG */
+ to_read = MIN((size_t)(efl->slot[u].size - skip), (hsize_t)size);
+#endif /* NDEBUG */
+ if((n = HDread(fd, buf, to_read)) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file")
+ else if((size_t)n < to_read)
+ HDmemset(buf + n, 0, to_read - (size_t)n);
+ full_name = (char *)H5MM_xfree(full_name);
+ HDclose(fd);
+ fd = -1;
+ size -= to_read;
+ buf += to_read;
+ skip = 0;
+ u++;
+ } /* end while */
+
+done:
+ if(full_name)
+ full_name = (char *)H5MM_xfree(full_name);
+ if(fd >= 0)
+ HDclose(fd);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_write
+ *
+ * Purpose: Writes data to an external file list. It is an error to
+ * write past the logical end of file, but writing past the end
+ * of any particular member of the external file list just
+ * extends that file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, const uint8_t *buf)
+{
+ int fd = -1;
+ size_t to_write;
+#ifndef NDEBUG
+ hsize_t tempto_write;
+#endif /* NDEBUG */
+ haddr_t cur;
+ hsize_t skip = 0;
+ size_t u; /* Local index variable */
+ char *full_name = NULL; /* File name with prefix */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(efl && efl->nused > 0);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(size < SIZET_MAX);
+ HDassert(buf || 0 == size);
+
+ /* Find the first efl member in which to write */
+ for(u = 0, cur = 0; u < efl->nused; u++) {
+ if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) {
+ skip = addr - cur;
+ break;
+ } /* end if */
+ cur += efl->slot[u].size;
+ } /* end for */
+
+ /* Write the data */
+ while(size) {
+ HDassert(buf);
+ if(u >= efl->nused)
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "write past logical end of file")
+ if(H5F_OVERFLOW_HSIZET2OFFT((hsize_t)efl->slot[u].offset + skip))
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed")
+ if(H5_combine_path(dset->shared->extfile_prefix, efl->slot[u].name, &full_name) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_NOSPACE, FAIL, "can't build external file name")
+ if((fd = HDopen(full_name, O_CREAT | O_RDWR, 0666)) < 0) {
+ if(HDaccess(full_name, F_OK) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "external raw data file does not exist")
+ else
+ HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file")
+ } /* end if */
+ if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + (HDoff_t)skip), SEEK_SET) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file")
+#ifndef NDEBUG
+ tempto_write = MIN(efl->slot[u].size - skip, (hsize_t)size);
+ H5_CHECK_OVERFLOW(tempto_write, hsize_t, size_t);
+ to_write = (size_t)tempto_write;
+#else /* NDEBUG */
+ to_write = MIN((size_t)(efl->slot[u].size - skip), size);
+#endif /* NDEBUG */
+ if((size_t)HDwrite(fd, buf, to_write) != to_write)
+ HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "write error in external raw data file")
+ full_name = (char *)H5MM_xfree(full_name);
+ HDclose (fd);
+ fd = -1;
+ size -= to_write;
+ buf += to_write;
+ skip = 0;
+ u++;
+ } /* end while */
+
+done:
+ if(full_name)
+ full_name = (char *)H5MM_xfree(full_name);
+ if(fd >= 0)
+ HDclose(fd);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_readvv_cb
+ *
+ * Purpose: Callback operator for H5D__efl_readvv().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
+{
+ H5D_efl_readvv_ud_t *udata = (H5D_efl_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Read data */
+ if(H5D__efl_read(udata->efl, udata->dset, dst_off, len, (udata->rbuf + src_off)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "EFL read failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_readvv_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_readvv
+ *
+ * Purpose: Reads data from an external file list. It is an error to
+ * read past the logical end of file, but reading past the end
+ * of any particular member of the external file list results in
+ * zeros.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 7, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__efl_readvv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
+{
+ H5D_efl_readvv_ud_t udata; /* User data for H5VM_opvv() operator */
+ ssize_t ret_value = -1; /* Return value (Total size of sequence in bytes) */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(io_info->store->efl.nused > 0);
+ HDassert(io_info->u.rbuf);
+ HDassert(io_info->dset);
+ HDassert(io_info->dset->shared);
+ HDassert(io_info->dset->shared->extfile_prefix);
+ HDassert(dset_curr_seq);
+ HDassert(dset_len_arr);
+ HDassert(dset_off_arr);
+ HDassert(mem_curr_seq);
+ HDassert(mem_len_arr);
+ HDassert(mem_off_arr);
+
+ /* Set up user data for H5VM_opvv() */
+ udata.efl = &(io_info->store->efl);
+ udata.dset = io_info->dset;
+ udata.rbuf = (unsigned char *)io_info->u.rbuf;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__efl_readvv_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized EFL read")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_readvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_writevv_cb
+ *
+ * Purpose: Callback operator for H5D__efl_writevv().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__efl_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
+{
+ H5D_efl_writevv_ud_t *udata = (H5D_efl_writevv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Write data */
+ if(H5D__efl_write(udata->efl, udata->dset, dst_off, len, (udata->wbuf + src_off)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "EFL write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_writevv_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_writevv
+ *
+ * Purpose: Writes data to an external file list. It is an error to
+ * write past the logical end of file, but writing past the end
+ * of any particular member of the external file list just
+ * extends that file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 2, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5D__efl_writevv(const H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
+{
+ H5D_efl_writevv_ud_t udata; /* User data for H5VM_opvv() operator */
+ ssize_t ret_value = -1; /* Return value (Total size of sequence in bytes) */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(io_info->store->efl.nused > 0);
+ HDassert(io_info->u.wbuf);
+ HDassert(io_info->dset);
+ HDassert(io_info->dset->shared);
+ HDassert(io_info->dset->shared->extfile_prefix);
+ HDassert(dset_curr_seq);
+ HDassert(dset_len_arr);
+ HDassert(dset_off_arr);
+ HDassert(mem_curr_seq);
+ HDassert(mem_len_arr);
+ HDassert(mem_off_arr);
+
+ /* Set up user data for H5VM_opvv() */
+ udata.efl = &(io_info->store->efl);
+ udata.dset = io_info->dset;
+ udata.wbuf = (const unsigned char *)io_info->u.wbuf;
+
+ /* Call generic sequence operation routine */
+ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr,
+ mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr,
+ H5D__efl_writevv_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized EFL write")
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_writevv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__efl_bh_info
+ *
+ * Purpose: Retrieve the amount of heap storage used for External File
+ * List message
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; August 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__efl_bh_info(H5F_t *f, hid_t dxpl_id, H5O_efl_t *efl, hsize_t *heap_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(f);
+ HDassert(efl);
+ HDassert(H5F_addr_defined(efl->heap_addr));
+ HDassert(heap_size);
+
+ /* Get the size of the local heap for EFL's file list */
+ if(H5HL_heapsize(f, dxpl_id, efl->heap_addr, heap_size) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_CANTINIT, FAIL, "unable to retrieve local heap info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__efl_bh_info() */
diff --git a/src/H5Dfarray.c b/src/H5Dfarray.c
new file mode 100644
index 0000000..d183a8c
--- /dev/null
+++ b/src/H5Dfarray.c
@@ -0,0 +1,1687 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Vailin Choi <vchoi@hdfgroup.org>
+ * Thursday, April 30, 2009
+ *
+ * Purpose: Fixed array indexed (chunked) I/O functions.
+ * The chunk coordinate is mapped as an index into an array of
+ * disk addresses for the chunks.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FAprivate.h" /* Fixed arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Value to fill unset array elements with */
+#define H5D_FARRAY_FILL HADDR_UNDEF
+#define H5D_FARRAY_FILT_FILL {HADDR_UNDEF, 0, 0}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Fixed array create/open user data */
+typedef struct H5D_farray_ctx_ud_t {
+ const H5F_t *f; /* Pointer to file info */
+ uint32_t chunk_size; /* Size of chunk (bytes) */
+} H5D_farray_ctx_ud_t;
+
+/* Fixed array callback context */
+typedef struct H5D_farray_ctx_t {
+ size_t file_addr_len; /* Size of addresses in the file (bytes) */
+ size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */
+} H5D_farray_ctx_t;
+
+/* User data for chunk callbacks */
+typedef struct H5D_farray_ud_t {
+ H5F_t *f; /* File pointer for operation */
+ hid_t dxpl_id; /* DXPL ID for operation */
+} H5D_farray_ud_t;
+
+/* Fixed Array callback info for iteration over chunks */
+typedef struct H5D_farray_it_ud_t {
+ H5D_chunk_common_ud_t common; /* Common info for Fixed Array user data (must be first) */
+ H5D_chunk_rec_t chunk_rec; /* Generic chunk record for callback */
+ hbool_t filtered; /* Whether the chunks are filtered */
+ H5D_chunk_cb_func_t cb; /* Chunk callback routine */
+ void *udata; /* User data for chunk callback routine */
+} H5D_farray_it_ud_t;
+
+/* Native fixed array element for chunks w/filters */
+typedef struct H5D_farray_filt_elmt_t {
+ haddr_t addr; /* Address of chunk */
+ uint32_t nbytes; /* Size of chunk (in file) */
+ uint32_t filter_mask; /* Excluded filters for chunk */
+} H5D_farray_filt_elmt_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Fixed Array iterator callbacks */
+static int H5D__farray_idx_iterate_cb(hsize_t idx, const void *_elmt, void *_udata);
+static int H5D__farray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata);
+
+/* Fixed array class callbacks for chunks w/o filters */
+static void *H5D__farray_crt_context(void *udata);
+static herr_t H5D__farray_dst_context(void *ctx);
+static herr_t H5D__farray_fill(void *nat_blk, size_t nelmts);
+static herr_t H5D__farray_encode(void *raw, const void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__farray_decode(const void *raw, void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__farray_debug(FILE *stream, int indent, int fwidth,
+ hsize_t idx, const void *elmt);
+static void *H5D__farray_crt_dbg_context(H5F_t *f, hid_t dxpl_id,
+ haddr_t obj_addr);
+static herr_t H5D__farray_dst_dbg_context(void *dbg_ctx);
+
+/* Fixed array class callbacks for chunks w/filters */
+/* (some shared with callbacks for chunks w/o filters) */
+static herr_t H5D__farray_filt_fill(void *nat_blk, size_t nelmts);
+static herr_t H5D__farray_filt_encode(void *raw, const void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__farray_filt_decode(const void *raw, void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5D__farray_filt_debug(FILE *stream, int indent, int fwidth,
+ hsize_t idx, const void *elmt);
+
+/* Chunked layout indexing callbacks */
+static herr_t H5D__farray_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+static herr_t H5D__farray_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__farray_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__farray_idx_insert(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+static herr_t H5D__farray_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static int H5D__farray_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__farray_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__farray_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__farray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__farray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id);
+static herr_t H5D__farray_idx_size(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *size);
+static herr_t H5D__farray_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__farray_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);
+static herr_t H5D__farray_idx_dest(const H5D_chk_idx_info_t *idx_info);
+
+/* Generic fixed array routines */
+static herr_t H5D__farray_idx_open(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__farray_idx_depend(const H5D_chk_idx_info_t *idx_info);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Fixed array indexed chunk I/O ops */
+const H5D_chunk_ops_t H5D_COPS_FARRAY[1] = {{
+ TRUE, /* Fixed array indices support SWMR access */
+ H5D__farray_idx_init, /* init */
+ H5D__farray_idx_create, /* create */
+ H5D__farray_idx_is_space_alloc, /* is_space_alloc */
+ H5D__farray_idx_insert, /* insert */
+ H5D__farray_idx_get_addr, /* get_addr */
+ NULL, /* resize */
+ H5D__farray_idx_iterate, /* iterate */
+ H5D__farray_idx_remove, /* remove */
+ H5D__farray_idx_delete, /* delete */
+ H5D__farray_idx_copy_setup, /* copy_setup */
+ H5D__farray_idx_copy_shutdown, /* copy_shutdown */
+ H5D__farray_idx_size, /* size */
+ H5D__farray_idx_reset, /* reset */
+ H5D__farray_idx_dump, /* dump */
+ H5D__farray_idx_dest /* destroy */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Fixed array class callbacks for dataset chunks w/o filters */
+const H5FA_class_t H5FA_CLS_CHUNK[1]={{
+ H5FA_CLS_CHUNK_ID, /* Type of fixed array */
+ "Chunk w/o filters", /* Name of fixed array class */
+ sizeof(haddr_t), /* Size of native element */
+ H5D__farray_crt_context, /* Create context */
+ H5D__farray_dst_context, /* Destroy context */
+ H5D__farray_fill, /* Fill block of missing elements callback */
+ H5D__farray_encode, /* Element encoding callback */
+ H5D__farray_decode, /* Element decoding callback */
+ H5D__farray_debug, /* Element debugging callback */
+ H5D__farray_crt_dbg_context, /* Create debugging context */
+ H5D__farray_dst_dbg_context /* Destroy debugging context */
+}};
+
+/* Fixed array class callbacks for dataset chunks w/filters */
+const H5FA_class_t H5FA_CLS_FILT_CHUNK[1]={{
+ H5FA_CLS_FILT_CHUNK_ID, /* Type of fixed array */
+ "Chunk w/filters", /* Name of fixed array class */
+ sizeof(H5D_farray_filt_elmt_t), /* Size of native element */
+ H5D__farray_crt_context, /* Create context */
+ H5D__farray_dst_context, /* Destroy context */
+ H5D__farray_filt_fill, /* Fill block of missing elements callback */
+ H5D__farray_filt_encode, /* Element encoding callback */
+ H5D__farray_filt_decode, /* Element decoding callback */
+ H5D__farray_filt_debug, /* Element debugging callback */
+ H5D__farray_crt_dbg_context, /* Create debugging context */
+ H5D__farray_dst_dbg_context /* Destroy debugging context */
+}};
+
+/* Declare a free list to manage the H5D_farray_ctx_t struct */
+H5FL_DEFINE_STATIC(H5D_farray_ctx_t);
+
+/* Declare a free list to manage the H5D_farray_ctx_ud_t struct */
+H5FL_DEFINE_STATIC(H5D_farray_ctx_ud_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_crt_context
+ *
+ * Purpose: Create context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__farray_crt_context(void *_udata)
+{
+ H5D_farray_ctx_t *ctx; /* Fixed array callback context */
+ H5D_farray_ctx_ud_t *udata = (H5D_farray_ctx_ud_t *)_udata; /* User data for fixed array context */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->chunk_size > 0);
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5D_farray_ctx_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate fixed array client callback context")
+
+ /* Initialize the context */
+ ctx->file_addr_len = H5F_SIZEOF_ADDR(udata->f);
+
+ /* Compute the size required for encoding the size of a chunk, allowing
+ * for an extra byte, in case the filter makes the chunk larger.
+ */
+ ctx->chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)udata->chunk_size) + 8) / 8);
+ if(ctx->chunk_size_len > 8)
+ ctx->chunk_size_len = 8;
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_dst_context
+ *
+ * Purpose: Destroy context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_dst_context(void *_ctx)
+{
+ H5D_farray_ctx_t *ctx = (H5D_farray_ctx_t *)_ctx; /* Fixed array callback context */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(ctx);
+
+ /* Release context structure */
+ ctx = H5FL_FREE(H5D_farray_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_fill(void *nat_blk, size_t nelmts)
+{
+ haddr_t fill_val = H5D_FARRAY_FILL; /* Value to fill elements with */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+
+ H5VM_array_fill(nat_blk, &fill_val, H5FA_CLS_CHUNK->nat_elmt_size, nelmts);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_encode(void *raw, const void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_farray_ctx_t *ctx = (H5D_farray_ctx_t *)_ctx; /* Fixed array callback context */
+ const haddr_t *elmt = (const haddr_t *)_elmt; /* Convenience pointer to native elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(ctx);
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_encode_len(ctx->file_addr_len, (uint8_t **)&raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_farray_ctx_t *ctx = (H5D_farray_ctx_t *)_ctx; /* Fixed array callback context */
+ haddr_t *elmt = (haddr_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_decode_len(ctx->file_addr_len, &raw, elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *elmt)
+{
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, temp_str,
+ *(const haddr_t *)elmt);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_crt_dbg_context
+ *
+ * Purpose: Create context for debugging callback
+ * (get the layout message in the specified object header)
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi
+ * 5th August, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5D__farray_crt_dbg_context(H5F_t *f, hid_t dxpl_id, haddr_t obj_addr)
+{
+ H5D_farray_ctx_ud_t *dbg_ctx = NULL; /* Context for fixed array callback */
+ H5O_loc_t obj_loc; /* Pointer to an object's location */
+ hbool_t obj_opened = FALSE; /* Flag to indicate that the object header was opened */
+ H5O_layout_t layout; /* Layout message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(H5F_addr_defined(obj_addr));
+
+ /* Allocate context for debugging callback */
+ if(NULL == (dbg_ctx = H5FL_MALLOC(H5D_farray_ctx_ud_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate fixed array client callback context")
+
+ /* Set up the object header location info */
+ H5O_loc_reset(&obj_loc);
+ obj_loc.file = f;
+ obj_loc.addr = obj_addr;
+
+ /* Open the object header where the layout message resides */
+ if(H5O_open(&obj_loc) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "can't open object header")
+ obj_opened = TRUE;
+
+ /* Read the layout message */
+ if(NULL == H5O_msg_read(&obj_loc, H5O_LAYOUT_ID, &layout, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get layout info")
+
+ /* close the object header */
+ if(H5O_close(&obj_loc, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header")
+
+ /* Create user data */
+ dbg_ctx->f = f;
+ dbg_ctx->chunk_size = layout.u.chunk.size;
+
+ /* Set return value */
+ ret_value = dbg_ctx;
+
+done:
+ /* Cleanup on error */
+ if(ret_value == NULL) {
+ /* Release context structure */
+ if(dbg_ctx)
+ dbg_ctx = H5FL_FREE(H5D_farray_ctx_ud_t, dbg_ctx);
+
+ /* Close object header */
+ if(obj_opened) {
+ if(H5O_close(&obj_loc, NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, NULL, "can't close object header")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_crt_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_dst_dbg_context
+ *
+ * Purpose: Destroy context for debugging callback
+ * (free the layout message from the specified object header)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * 24th September, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_dst_dbg_context(void *_dbg_ctx)
+{
+ H5D_farray_ctx_ud_t *dbg_ctx = (H5D_farray_ctx_ud_t *)_dbg_ctx; /* Context for fixed array callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(dbg_ctx);
+
+ /* Release context structure */
+ dbg_ctx = H5FL_FREE(H5D_farray_ctx_ud_t, dbg_ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_dst_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_filt_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_filt_fill(void *nat_blk, size_t nelmts)
+{
+ H5D_farray_filt_elmt_t fill_val = H5D_FARRAY_FILT_FILL; /* Value to fill elements with */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+ HDassert(sizeof(fill_val) == H5FA_CLS_FILT_CHUNK->nat_elmt_size);
+
+ H5VM_array_fill(nat_blk, &fill_val, H5FA_CLS_FILT_CHUNK->nat_elmt_size, nelmts);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_filt_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_filt_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_filt_encode(void *_raw, const void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_farray_ctx_t *ctx = (H5D_farray_ctx_t *)_ctx; /* Fixed array callback context */
+ uint8_t *raw = (uint8_t *)_raw; /* Convenience pointer to raw elements */
+ const H5D_farray_filt_elmt_t *elmt = (const H5D_farray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(ctx);
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_encode_len(ctx->file_addr_len, &raw, elmt->addr);
+ UINT64ENCODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
+ UINT32ENCODE(raw, elmt->filter_mask);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_filt_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_filt_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_filt_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx)
+{
+ H5D_farray_ctx_t *ctx = (H5D_farray_ctx_t *)_ctx; /* Fixed array callback context */
+ H5D_farray_filt_elmt_t *elmt = (H5D_farray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ H5F_addr_decode_len(ctx->file_addr_len, &raw, &elmt->addr);
+ UINT64DECODE_VAR(raw, elmt->nbytes, ctx->chunk_size_len);
+ UINT32DECODE(raw, elmt->filter_mask);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_filt_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_filt_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_filt_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *_elmt)
+{
+ const H5D_farray_filt_elmt_t *elmt = (const H5D_farray_filt_elmt_t *)_elmt; /* Convenience pointer to native elements */
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s {%a, %u, %0x}\n", indent, "", fwidth, temp_str,
+ elmt->addr, elmt->nbytes, elmt->filter_mask);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_filt_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_depend
+ *
+ * Purpose: Create flush dependency between fixed array and dataset's
+ * object header.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_depend(const H5D_chk_idx_info_t *idx_info)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t oloc; /* Temporary object header location for dataset */
+ H5AC_proxy_entry_t *oh_proxy; /* Dataset's object header proxy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_FARRAY == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5D_CHUNK_IDX_FARRAY == idx_info->storage->idx_type);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(idx_info->storage->u.farray.fa);
+
+ /* Set up object header location for dataset */
+ H5O_loc_reset(&oloc);
+ oloc.file = idx_info->f;
+ oloc.addr = idx_info->storage->u.farray.dset_ohdr_addr;
+
+ /* Get header */
+ if(NULL == (oh = H5O_protect(&oloc, idx_info->dxpl_id, H5AC__READ_ONLY_FLAG, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Retrieve the dataset's object header proxy */
+ if(NULL == (oh_proxy = H5O_get_proxy(oh)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy")
+
+ /* Make the fixed array a child flush dependency of the dataset's object header proxy */
+ if(H5FA_depend(idx_info->storage->u.farray.fa, idx_info->dxpl_id, oh_proxy) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header proxy")
+
+done:
+ /* Release the object header from the cache */
+ if(oh && H5O_unprotect(&oloc, idx_info->dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_init
+ *
+ * Purpose: Initialize the indexing information for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednensday, May 23, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space, haddr_t dset_ohdr_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(dset_ohdr_addr));
+
+ idx_info->storage->u.farray.dset_ohdr_addr = dset_ohdr_addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_idx_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_open
+ *
+ * Purpose: Opens an existing fixed array and initializes
+ * the layout struct with information about the storage.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_open(const H5D_chk_idx_info_t *idx_info)
+{
+ H5D_farray_ctx_ud_t udata; /* User data for fixed array open call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(H5D_CHUNK_IDX_FARRAY == idx_info->layout->idx_type);
+ HDassert(idx_info->storage);
+ HDassert(H5D_CHUNK_IDX_FARRAY == idx_info->storage->idx_type);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(NULL == idx_info->storage->u.farray.fa);
+
+ /* Set up the user data */
+ udata.f = idx_info->f;
+ udata.chunk_size = idx_info->layout->size;
+
+ /* Open the fixed array for the chunk index */
+ if(NULL == (idx_info->storage->u.farray.fa = H5FA_open(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &udata)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open fixed array")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__farray_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_create
+ *
+ * Purpose: Creates a new indexed-storage fixed array and initializes
+ * the layout struct with information about the storage. The
+ * struct should be immediately written to the object header.
+ *
+ * This function must be called before passing LAYOUT to any of
+ * the other indexed storage functions!
+ *
+ * Return: Non-negative on success (with the LAYOUT argument initialized
+ * and ready to write to an object header). Negative on failure.
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ H5FA_create_t cparam; /* Fixed array creation parameters */
+ H5D_farray_ctx_ud_t udata; /* User data for fixed array create call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(NULL == idx_info->storage->u.farray.fa);
+ HDassert(idx_info->layout->nchunks);
+
+ /* General parameters */
+ if(idx_info->pline->nused > 0) {
+ unsigned chunk_size_len; /* Size of encoded chunk size */
+
+ /* Compute the size required for encoding the size of a chunk, allowing
+ * for an extra byte, in case the filter makes the chunk larger.
+ */
+ chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)idx_info->layout->size) + 8) / 8);
+ if(chunk_size_len > 8)
+ chunk_size_len = 8;
+
+ cparam.cls = H5FA_CLS_FILT_CHUNK;
+ cparam.raw_elmt_size = (uint8_t)(H5F_SIZEOF_ADDR(idx_info->f) + chunk_size_len + 4);
+ } /* end if */
+ else {
+ cparam.cls = H5FA_CLS_CHUNK;
+ cparam.raw_elmt_size = (uint8_t)H5F_SIZEOF_ADDR(idx_info->f);
+ } /* end else */
+ cparam.max_dblk_page_nelmts_bits = idx_info->layout->u.farray.cparam.max_dblk_page_nelmts_bits;
+ HDassert(cparam.max_dblk_page_nelmts_bits > 0);
+ cparam.nelmts = idx_info->layout->max_nchunks;
+
+ /* Set up the user data */
+ udata.f = idx_info->f;
+ udata.chunk_size = idx_info->layout->size;
+
+ /* Create the fixed array for the chunk index */
+ if(NULL == (idx_info->storage->u.farray.fa = H5FA_create(idx_info->f, idx_info->dxpl_id, &cparam, &udata)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create fixed array")
+
+ /* Get the address of the fixed array in file */
+ if(H5FA_get_addr(idx_info->storage->u.farray.fa, &(idx_info->storage->idx_addr)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query fixed array address")
+
+ /* Check for SWMR writes to the file */
+ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)
+ if(H5D__farray_idx_depend(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for index method
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__farray_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__farray_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_insert
+ *
+ * Purpose: Insert chunk address into the indexing structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; 5 May 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
+ const H5D_t H5_ATTR_UNUSED *dset)
+{
+ H5FA_t *fa; /* Pointer to fixed array structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the fixed array is open yet */
+ if(NULL == idx_info->storage->u.farray.fa) {
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+ } else /* Patch the top level file pointer contained in fa if needed */
+ H5FA_patch_file(idx_info->storage->u.farray.fa, idx_info->f);
+
+ /* Set convenience pointer to fixed array structure */
+ fa = idx_info->storage->u.farray.fa;
+
+ if(!H5F_addr_defined(udata->chunk_block.offset))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "The chunk should have allocated already")
+ if(udata->chunk_idx != (udata->chunk_idx & 0xffffffff)) /* negative value */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk index must be less than 2^32")
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_farray_filt_elmt_t elmt; /* Fixed array element */
+
+ elmt.addr = udata->chunk_block.offset;
+ H5_CHECKED_ASSIGN(elmt.nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ elmt.filter_mask = udata->filter_mask;
+
+ /* Set the info for the chunk */
+ if(H5FA_set(fa, idx_info->dxpl_id, udata->chunk_idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk info")
+ } /* end if */
+ else {
+ /* Set the address for the chunk */
+ if(H5FA_set(fa, idx_info->dxpl_id, udata->chunk_idx, &udata->chunk_block.offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set chunk address")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__farray_idx_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk if file space has been
+ * assigned. Save the retrieved information in the udata
+ * supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ H5FA_t *fa; /* Pointer to fixed array structure */
+ hsize_t idx; /* Array index of chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the fixed array is open yet */
+ if(NULL == idx_info->storage->u.farray.fa) {
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+ } else /* Patch the top level file pointer contained in fa if needed */
+ H5FA_patch_file(idx_info->storage->u.farray.fa, idx_info->f);
+
+ /* Set convenience pointer to fixed array structure */
+ fa = idx_info->storage->u.farray.fa;
+
+ /* Calculate the index of this chunk */
+ idx = H5VM_array_offset_pre((idx_info->layout->ndims - 1), idx_info->layout->max_down_chunks, udata->common.scaled);
+
+ udata->chunk_idx = idx;
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_farray_filt_elmt_t elmt; /* Fixed array element */
+
+ /* Get the information for the chunk */
+ if(H5FA_get(fa, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
+
+ /* Set the info for the chunk */
+ udata->chunk_block.offset = elmt.addr;
+ udata->chunk_block.length = elmt.nbytes;
+ udata->filter_mask = elmt.filter_mask;
+ } /* end if */
+ else {
+ /* Get the address for the chunk */
+ if(H5FA_get(fa, idx_info->dxpl_id, idx, &udata->chunk_block.offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+
+ /* Update the other (constant) information for the chunk */
+ udata->chunk_block.length = idx_info->layout->size;
+ udata->filter_mask = 0;
+ } /* end else */
+
+ if(!H5F_addr_defined(udata->chunk_block.offset))
+ udata->chunk_block.length = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__farray_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_iterate_cb
+ *
+ * Purpose: Callback routine for fixed array element iteration.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__farray_idx_iterate_cb(hsize_t H5_ATTR_UNUSED idx, const void *_elmt, void *_udata)
+{
+ H5D_farray_it_ud_t *udata = (H5D_farray_it_ud_t *)_udata; /* User data */
+ unsigned ndims; /* Rank of chunk */
+ int curr_dim; /* Current dimension */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Compose generic chunk record for callback */
+ if(udata->filtered) {
+ const H5D_farray_filt_elmt_t *filt_elmt = (const H5D_farray_filt_elmt_t *)_elmt;
+
+ udata->chunk_rec.chunk_addr = filt_elmt->addr;
+ udata->chunk_rec.nbytes = filt_elmt->nbytes;
+ udata->chunk_rec.filter_mask = filt_elmt->filter_mask;
+ } /* end if */
+ else
+ udata->chunk_rec.chunk_addr = *(const haddr_t *)_elmt;
+
+ /* Make "generic chunk" callback */
+ if(H5F_addr_defined(udata->chunk_rec.chunk_addr))
+ if((ret_value = (udata->cb)(&udata->chunk_rec, udata->udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ /* Update coordinates of chunk in dataset */
+ ndims = udata->common.layout->ndims - 1;
+ HDassert(ndims > 0);
+ curr_dim = (int)(ndims - 1);
+ while(curr_dim >= 0) {
+ /* Increment coordinate in current dimension */
+ udata->chunk_rec.scaled[curr_dim]++;
+
+ /* Check if we went off the end of the current dimension */
+ if(udata->chunk_rec.scaled[curr_dim] >= udata->common.layout->max_chunks[curr_dim]) {
+ /* Reset coordinate & move to next faster dimension */
+ udata->chunk_rec.scaled[curr_dim] = 0;
+ curr_dim--;
+ } /* end if */
+ else
+ break;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__farray_idx_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_iterate
+ *
+ * Purpose: Iterate over the chunks in an index, making a callback
+ * for each one.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__farray_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5FA_t *fa; /* Pointer to fixed array structure */
+ H5FA_stat_t fa_stat; /* Fixed array statistics */
+ int ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+
+ /* Check if the fixed array is open yet */
+ if(NULL == idx_info->storage->u.farray.fa) {
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+ } else /* Patch the top level file pointer contained in fa if needed */
+ H5FA_patch_file(idx_info->storage->u.farray.fa, idx_info->f);
+
+ /* Set convenience pointer to fixed array structure */
+ fa = idx_info->storage->u.farray.fa;
+
+ /* Get the fixed array statistics */
+ if(H5FA_get_stats(fa, &fa_stat) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query fixed array statistics")
+
+ /* Check if there are any array elements */
+ if(fa_stat.nelmts > 0) {
+ H5D_farray_it_ud_t udata; /* User data for iteration callback */
+
+ /* Initialize userdata */
+ HDmemset(&udata, 0, sizeof udata);
+ udata.common.layout = idx_info->layout;
+ udata.common.storage = idx_info->storage;
+ HDmemset(&udata.chunk_rec, 0, sizeof(udata.chunk_rec));
+ udata.filtered = (idx_info->pline->nused > 0);
+ if(!udata.filtered) {
+ udata.chunk_rec.nbytes = idx_info->layout->size;
+ udata.chunk_rec.filter_mask = 0;
+ } /* end if */
+ udata.cb = chunk_cb;
+ udata.udata = chunk_udata;
+
+ /* Iterate over the fixed array elements */
+ if((ret_value = H5FA_iterate(fa, idx_info->dxpl_id, H5D__farray_idx_iterate_cb, &udata)) < 0)
+ HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over fixed array chunk index");
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_remove
+ *
+ * Purpose: Remove chunk from index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata)
+{
+ H5FA_t *fa; /* Pointer to fixed array structure */
+ hsize_t idx; /* Array index of chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(udata);
+
+ /* Check if the fixed array is open yet */
+ if(NULL == idx_info->storage->u.farray.fa) {
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+ } else /* Patch the top level file pointer contained in fa if needed */
+ if(H5FA_patch_file(idx_info->storage->u.farray.fa, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch fixed array file pointer")
+
+ /* Set convenience pointer to fixed array structure */
+ fa = idx_info->storage->u.farray.fa;
+
+ /* Calculate the index of this chunk */
+ idx = H5VM_array_offset_pre((idx_info->layout->ndims - 1), idx_info->layout->max_down_chunks, udata->scaled);
+
+ /* Check for filters on chunks */
+ if(idx_info->pline->nused > 0) {
+ H5D_farray_filt_elmt_t elmt; /* Fixed array element */
+
+ /* Get the info about the chunk for the index */
+ if(H5FA_get(fa, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk info")
+
+ /* Remove raw data chunk from file if not doing SWMR writes */
+ HDassert(H5F_addr_defined(elmt.addr));
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(elmt.nbytes, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, elmt.addr, (hsize_t)elmt.nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
+
+ /* Reset the info about the chunk for the index */
+ elmt.addr = HADDR_UNDEF;
+ elmt.nbytes = 0;
+ elmt.filter_mask = 0;
+ if(H5FA_set(fa, idx_info->dxpl_id, idx, &elmt) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk info")
+ } /* end if */
+ else {
+ haddr_t addr = HADDR_UNDEF; /* Chunk address */
+
+ /* Get the address of the chunk for the index */
+ if(H5FA_get(fa, idx_info->dxpl_id, idx, &addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+
+ /* Remove raw data chunk from file if not doing SWMR writes */
+ HDassert(H5F_addr_defined(addr));
+ if(!(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE)) {
+ H5_CHECK_OVERFLOW(idx_info->layout->size, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, addr, (hsize_t)idx_info->layout->size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk")
+ } /* end if */
+
+ /* Reset the address of the chunk for the index */
+ addr = HADDR_UNDEF;
+ if(H5FA_set(fa, idx_info->dxpl_id, idx, &addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to reset chunk address")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__farray_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_delete_cb
+ *
+ * Purpose: Delete space for chunk in file
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__farray_idx_delete_cb(const H5D_chunk_rec_t *chunk_rec, void *_udata)
+{
+ H5D_farray_ud_t *udata = (H5D_farray_ud_t *)_udata; /* User data for callback */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(chunk_rec);
+ HDassert(H5F_addr_defined(chunk_rec->chunk_addr));
+ HDassert(chunk_rec->nbytes > 0);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Remove raw data chunk from file */
+ H5_CHECK_OVERFLOW(chunk_rec->nbytes, /*From: */uint32_t, /*To: */hsize_t);
+ if(H5MF_xfree(udata->f, H5FD_MEM_DRAW, udata->dxpl_id, chunk_rec->chunk_addr, (hsize_t)chunk_rec->nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_delete_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_delete
+ *
+ * Purpose: Delete index and raw data storage for entire dataset
+ * (i.e. all chunks)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ /* Check if the index data structure has been allocated */
+ if(H5F_addr_defined(idx_info->storage->idx_addr)) {
+ H5D_farray_ud_t udata; /* User data for callback */
+ H5D_farray_ctx_ud_t ctx_udata; /* User data for fixed array open call */
+
+ /* Initialize user data for callback */
+ udata.f = idx_info->f;
+ udata.dxpl_id = idx_info->dxpl_id;
+
+ /* Iterate over the chunk addresses in the fixed array, deleting each chunk */
+ if(H5D__farray_idx_iterate(idx_info, H5D__farray_idx_delete_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate over chunk addresses")
+
+ /* Close fixed array */
+ if(H5FA_close(idx_info->storage->u.farray.fa, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close fixed array")
+ idx_info->storage->u.farray.fa = NULL;
+
+ /* Set up the user data */
+ ctx_udata.f = idx_info->f;
+ ctx_udata.chunk_size = idx_info->layout->size;
+
+ /* Delete fixed array */
+ if(H5FA_delete(idx_info->f, idx_info->dxpl_id, idx_info->storage->idx_addr, &ctx_udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk fixed array")
+ idx_info->storage->idx_addr = HADDR_UNDEF;
+ } /* end if */
+ else
+ HDassert(NULL == idx_info->storage->u.farray.fa);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+ HDassert(!H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Check if the source fixed array is open yet */
+ if(NULL == idx_info_src->storage->u.farray.fa)
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info_src) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Create the fixed array that describes chunked storage in the dest. file */
+ if(H5D__farray_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+ HDassert(H5F_addr_defined(idx_info_dst->storage->idx_addr));
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_copy_shutdown
+ *
+ * Purpose: Shutdown any information from copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_copy_shutdown(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(storage_src);
+ HDassert(storage_src->u.farray.fa);
+ HDassert(storage_dst);
+ HDassert(storage_dst->u.farray.fa);
+
+ /* Close fixed arrays */
+ if(H5FA_close(storage_src->u.farray.fa, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close fixed array")
+ storage_src->u.farray.fa = NULL;
+ if(H5FA_close(storage_dst->u.farray.fa, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close fixed array")
+ storage_dst->u.farray.fa = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_copy_shutdown() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size)
+{
+ H5FA_t *fa; /* Pointer to fixed array structure */
+ H5FA_stat_t fa_stat; /* Fixed array statistics */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+ HDassert(index_size);
+
+ /* Open the fixed array in file */
+ if(H5D__farray_idx_open(idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open fixed array")
+
+ /* Set convenience pointer to fixed array structure */
+ fa = idx_info->storage->u.farray.fa;
+
+ /* Get the fixed array statistics */
+ if(H5FA_get_stats(fa, &fa_stat) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query fixed array statistics")
+
+ *index_size = fa_stat.hdr_size;
+ *index_size += fa_stat.dblk_size;
+
+done:
+ if(idx_info->storage->u.farray.fa) {
+ if(H5FA_close(idx_info->storage->u.farray.fa, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close fixed array")
+ idx_info->storage->u.farray.fa = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr)
+ storage->idx_addr = HADDR_UNDEF;
+ storage->u.farray.fa = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_dump
+ *
+ * Purpose: Dump indexing information to a stream.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__farray_idx_dump() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__farray_idx_dest
+ *
+ * Purpose: Release indexing information in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__farray_idx_dest(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->storage);
+
+ /* Check if the fixed array is open */
+ if(idx_info->storage->u.farray.fa) {
+
+ /* Patch the top level file pointer contained in fa if needed */
+ if(H5FA_patch_file(idx_info->storage->u.farray.fa, idx_info->f) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch fixed array file pointer")
+
+ /* Close fixed array */
+ if(H5FA_close(idx_info->storage->u.farray.fa, idx_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close fixed array")
+ idx_info->storage->u.farray.fa = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__farray_idx_dest() */
+
diff --git a/src/H5Dfill.c b/src/H5Dfill.c
new file mode 100644
index 0000000..922ac98
--- /dev/null
+++ b/src/H5Dfill.c
@@ -0,0 +1,713 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Dfill.c
+ * Jun 19 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Fill value operations for datasets
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5VMprivate.h" /* Vector and array functions */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5D__fill_release(H5D_fill_buf_info_t *fb_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare the free list to manage blocks of non-zero fill-value data */
+H5FL_BLK_DEFINE_STATIC(non_zero_fill);
+
+/* Declare the free list to manage blocks of zero fill-value data */
+H5FL_BLK_DEFINE_STATIC(zero_fill);
+
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Dfill
+ PURPOSE
+ Fill a selection in memory with a value
+ USAGE
+ herr_t H5Dfill(fill, fill_type, space, buf, buf_type)
+ const void *fill; IN: Pointer to fill value to use
+ hid_t fill_type_id; IN: Datatype of the fill value
+ void *buf; IN/OUT: Memory buffer to fill selection within
+ hid_t buf_type_id; IN: Datatype of the elements in buffer
+ hid_t space_id; IN: Dataspace describing memory buffer &
+ containing selection to use.
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to fill elements in a memory buffer.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ If "fill" parameter is NULL, use all zeros as fill value
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Dfill(const void *fill, hid_t fill_type_id, void *buf, hid_t buf_type_id, hid_t space_id)
+{
+ H5S_t *space; /* Dataspace */
+ H5T_t *fill_type; /* Fill-value datatype */
+ H5T_t *buf_type; /* Buffer datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*xi*xii", fill, fill_type_id, buf, buf_type_id, space_id);
+
+ /* Check args */
+ if(buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid buffer")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a dataspace")
+ if(NULL == (fill_type = (H5T_t *)H5I_object_verify(fill_type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype")
+ if(NULL == (buf_type = (H5T_t *)H5I_object_verify(buf_type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype")
+
+ /* Fill the selection in the memory buffer */
+ if(H5D__fill(fill, fill_type, buf, buf_type, space, H5AC_noio_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dfill() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__fill
+ PURPOSE
+ Fill a selection in memory with a value (internal version)
+ USAGE
+ herr_t H5D__fill(fill, fill_type, buf, buf_type, space)
+ const void *fill; IN: Pointer to fill value to use
+ H5T_t *fill_type; IN: Datatype of the fill value
+ void *buf; IN/OUT: Memory buffer to fill selection within
+ H5T_t *buf_type; IN: Datatype of the elements in buffer
+ H5S_t *space; IN: Dataspace describing memory buffer &
+ containing selection to use.
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to fill elements in a memory buffer.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ If "fill" parameter is NULL, use all zeros as fill value.
+ EXAMPLES
+ REVISION LOG
+ Raymond Lu - 20 March 2007
+ If there's VL type of data, the address of the data is copied multiple
+ times into the buffer, causing some trouble when the data is released.
+ Instead, make multiple copies of fill value first, then do conversion
+ on each element so that each of them has a copy of the VL data.
+--------------------------------------------------------------------------*/
+herr_t
+H5D__fill(const void *fill, const H5T_t *fill_type, void *buf,
+ const H5T_t *buf_type, const H5S_t *space, hid_t dxpl_id)
+{
+ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info */
+ hbool_t mem_iter_init = FALSE; /* Whether the memory selection iterator has been initialized */
+ H5WB_t *elem_wb = NULL; /* Wrapped buffer for element data */
+ uint8_t elem_buf[H5T_ELEM_BUF_SIZE]; /* Buffer for element data */
+ H5WB_t *bkg_elem_wb = NULL; /* Wrapped buffer for background data */
+ uint8_t bkg_elem_buf[H5T_ELEM_BUF_SIZE]; /* Buffer for background data */
+ uint8_t *bkg_buf = NULL; /* Background conversion buffer */
+ uint8_t *tmp_buf = NULL; /* Temp conversion buffer */
+ hid_t src_id = -1, dst_id = -1; /* Temporary type IDs */
+ size_t dst_type_size; /* Size of destination type*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(fill_type);
+ HDassert(buf);
+ HDassert(buf_type);
+ HDassert(space);
+
+ /* Make sure the dataspace has an extent set (or is NULL) */
+ if(!(H5S_has_extent(space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspace extent has not been set")
+
+ /* Get the memory datatype size */
+ dst_type_size = H5T_get_size(buf_type);
+
+ /* If there's no fill value, just use zeros */
+ if(fill == NULL) {
+ void *elem_ptr; /* Pointer to element to use for fill value */
+
+ /* Wrap the local buffer for elements */
+ if(NULL == (elem_wb = H5WB_wrap(elem_buf, sizeof(elem_buf))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for element */
+ if(NULL == (elem_ptr = H5WB_actual_clear(elem_wb, dst_type_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Fill the selection in the memory buffer */
+ if(H5S_select_fill(elem_ptr, dst_type_size, space, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed")
+ } /* end if */
+ else {
+ H5T_path_t *tpath; /* Conversion path information */
+ size_t src_type_size; /* Size of source type */
+ size_t buf_size; /* Desired buffer size */
+
+ /* Get the file datatype size */
+ src_type_size = H5T_get_size(fill_type);
+
+ /* Get the maximum buffer size needed and allocate it */
+ buf_size = MAX(src_type_size, dst_type_size);
+
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(fill_type, buf_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype")
+
+ /* Construct source & destination datatype IDs, if we will need them */
+ if(!H5T_path_noop(tpath)) {
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill_type, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+
+ if((dst_id = H5I_register(H5I_DATATYPE, H5T_copy(buf_type, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+ } /* end if */
+
+ /* If there's VL type of data, make multiple copies of fill value first,
+ * then do conversion on each element so that each of them has a copy
+ * of the VL data.
+ */
+ if(TRUE == H5T_detect_class(fill_type, H5T_VLEN, FALSE)) {
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ hssize_t nelmts; /* Number of data elements */
+
+ /* Get the number of elements in the selection */
+ nelmts = H5S_GET_SELECT_NPOINTS(space);
+ HDassert(nelmts >= 0);
+ H5_CHECK_OVERFLOW(nelmts, hssize_t, size_t);
+
+ /* Allocate a temporary buffer */
+ if(NULL == (tmp_buf = H5FL_BLK_MALLOC(type_conv, (size_t)nelmts * buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Allocate a background buffer, if necessary */
+ if(H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (size_t)nelmts * buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Replicate the file's fill value into the temporary buffer */
+ H5VM_array_fill(tmp_buf, fill, src_type_size, (size_t)nelmts);
+
+ /* Convert from file's fill value into memory form */
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)nelmts, (size_t)0, (size_t)0, tmp_buf, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed")
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Allocate the chunk selection iterator */
+ if(NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory selection iterator")
+
+ /* Create a selection iterator for scattering the elements to memory buffer */
+ if(H5S_select_iter_init(mem_iter, space, dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information")
+ mem_iter_init = TRUE;
+
+ /* Scatter the data into memory */
+ if(H5D__scatter_mem(tmp_buf, space, mem_iter, (size_t)nelmts, dxpl_cache, buf/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed")
+ } /* end if */
+ else {
+ const uint8_t *fill_buf; /* Buffer to use for writing fill values */
+
+ /* Convert disk buffer into memory buffer */
+ if(!H5T_path_noop(tpath)) {
+ void *elem_ptr; /* Pointer to element to use for fill value */
+ void *bkg_ptr = NULL; /* Pointer to background element to use for fill value */
+
+ /* Wrap the local buffer for elements */
+ if(NULL == (elem_wb = H5WB_wrap(elem_buf, sizeof(elem_buf))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for element */
+ if(NULL == (elem_ptr = H5WB_actual(elem_wb, buf_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Copy the user's data into the buffer for conversion */
+ HDmemcpy(elem_ptr, fill, src_type_size);
+
+ /* If there's no VL type of data, do conversion first then fill the data into
+ * the memory buffer. */
+ if(H5T_path_bkg(tpath)) {
+ /* Wrap the local buffer for background elements */
+ if(NULL == (bkg_elem_wb = H5WB_wrap(bkg_elem_buf, sizeof(bkg_elem_buf))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for element */
+ if(NULL == (bkg_ptr = H5WB_actual_clear(bkg_elem_wb, buf_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer")
+ } /* end if */
+
+ /* Perform datatype conversion */
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, elem_ptr, bkg_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed")
+
+ /* Point at element buffer */
+ fill_buf = (const uint8_t *)elem_ptr;
+ } /* end if */
+ else
+ fill_buf = (const uint8_t *)fill;
+
+ /* Fill the selection in the memory buffer */
+ if(H5S_select_fill(fill_buf, dst_type_size, space, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed")
+ } /* end else */
+ } /* end else */
+
+done:
+ if(mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(mem_iter)
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+ if(src_id != (-1) && H5I_dec_ref(src_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(dst_id != (-1) && H5I_dec_ref(dst_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID")
+ if(tmp_buf)
+ tmp_buf = H5FL_BLK_FREE(type_conv, tmp_buf);
+ if(elem_wb && H5WB_unwrap(elem_wb) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+ if(bkg_elem_wb && H5WB_unwrap(bkg_elem_wb) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__fill_init
+ *
+ * Purpose: Initialize buffer filling operation
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June 21, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf,
+ H5MM_allocate_t alloc_func, void *alloc_info,
+ H5MM_free_t free_func, void *free_info,
+ const H5O_fill_t *fill, const H5T_t *dset_type, hid_t dset_type_id,
+ size_t total_nelmts, size_t max_buf_size, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(fb_info);
+ HDassert(fill);
+ HDassert(dset_type);
+ HDassert(dset_type_id > 0);
+
+ /* Reset fill buffer information */
+ HDmemset(fb_info, 0, sizeof(*fb_info));
+
+ /* Cache constant information from the dataset */
+ fb_info->fill = fill;
+ fb_info->file_type = dset_type;
+ fb_info->file_tid = dset_type_id;
+ fb_info->fill_alloc_func = alloc_func;
+ fb_info->fill_alloc_info = alloc_info;
+ fb_info->fill_free_func = free_func;
+ fb_info->fill_free_info = free_info;
+
+ /* Fill the buffer with the user's fill value */
+ if(fill->buf) {
+ htri_t has_vlen_type; /* Whether the datatype has a VL component */
+
+ /* Detect whether the datatype has a VL component */
+ if((has_vlen_type = H5T_detect_class(dset_type, H5T_VLEN, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to detect vlen datatypes?")
+ fb_info->has_vlen_fill_type = (hbool_t)has_vlen_type;
+
+ /* If necessary, convert fill value datatypes (which copies VL components, etc.) */
+ if(fb_info->has_vlen_fill_type) {
+ /* Create temporary datatype for conversion operation */
+ if(NULL == (fb_info->mem_type = H5T_copy(dset_type, H5T_COPY_REOPEN)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy file datatype")
+ if((fb_info->mem_tid = H5I_register(H5I_DATATYPE, fb_info->mem_type, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register memory datatype")
+
+ /* Retrieve sizes of memory & file datatypes */
+ fb_info->mem_elmt_size = H5T_get_size(fb_info->mem_type);
+ HDassert(fb_info->mem_elmt_size > 0);
+ fb_info->file_elmt_size = H5T_get_size(dset_type);
+ HDassert(fb_info->file_elmt_size == (size_t)fill->size);
+
+ /* If fill value is not library default, use it to set the element size */
+ fb_info->max_elmt_size = MAX(fb_info->mem_elmt_size, fb_info->file_elmt_size);
+
+ /* Compute the number of elements that fit within a buffer to write */
+ if(total_nelmts > 0)
+ fb_info->elmts_per_buf = MIN(total_nelmts, MAX(1, (max_buf_size / fb_info->max_elmt_size)));
+ else
+ fb_info->elmts_per_buf = max_buf_size / fb_info->max_elmt_size;
+ HDassert(fb_info->elmts_per_buf > 0);
+
+ /* Compute the buffer size to use */
+ fb_info->fill_buf_size = MIN(max_buf_size, (fb_info->elmts_per_buf * fb_info->max_elmt_size));
+
+ /* Allocate fill buffer */
+ if(caller_fill_buf) {
+ fb_info->fill_buf = caller_fill_buf;
+ fb_info->use_caller_fill_buf = TRUE;
+ } /* end if */
+ else {
+ if(alloc_func)
+ fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info);
+ else
+ fb_info->fill_buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size);
+ if(NULL == fb_info->fill_buf)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer")
+ } /* end else */
+
+ /* Get the datatype conversion path for this operation */
+ if(NULL == (fb_info->fill_to_mem_tpath = H5T_path_find(dset_type, fb_info->mem_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes")
+
+ /* Get the inverse datatype conversion path for this operation */
+ if(NULL == (fb_info->mem_to_dset_tpath = H5T_path_find(fb_info->mem_type, dset_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes")
+
+ /* Check if we need to allocate a background buffer */
+ if(H5T_path_bkg(fb_info->fill_to_mem_tpath) || H5T_path_bkg(fb_info->mem_to_dset_tpath)) {
+ /* Check for inverse datatype conversion needing a background buffer */
+ /* (do this first, since it needs a larger buffer) */
+ if(H5T_path_bkg(fb_info->mem_to_dset_tpath))
+ fb_info->bkg_buf_size = fb_info->elmts_per_buf * fb_info->max_elmt_size;
+ else
+ fb_info->bkg_buf_size = fb_info->max_elmt_size;
+
+ /* Allocate the background buffer */
+ if(NULL == (fb_info->bkg_buf = H5FL_BLK_MALLOC(type_conv, fb_info->bkg_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end if */
+ } /* end if */
+ else {
+ /* If fill value is not library default, use it to set the element size */
+ HDassert(fill->size >= 0);
+ fb_info->max_elmt_size = fb_info->file_elmt_size = fb_info->mem_elmt_size = (size_t)fill->size;
+
+ /* Compute the number of elements that fit within a buffer to write */
+ if(total_nelmts > 0)
+ fb_info->elmts_per_buf = MIN(total_nelmts, MAX(1, (max_buf_size / fb_info->max_elmt_size)));
+ else
+ fb_info->elmts_per_buf = max_buf_size / fb_info->max_elmt_size;
+ HDassert(fb_info->elmts_per_buf > 0);
+
+ /* Compute the buffer size to use */
+ fb_info->fill_buf_size = MIN(max_buf_size, fb_info->elmts_per_buf * fb_info->max_elmt_size);
+
+ /* Allocate temporary buffer */
+ if(caller_fill_buf) {
+ fb_info->fill_buf = caller_fill_buf;
+ fb_info->use_caller_fill_buf = TRUE;
+ } /* end if */
+ else {
+ if(alloc_func)
+ fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info);
+ else
+ fb_info->fill_buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size);
+ if(NULL == fb_info->fill_buf)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer")
+ } /* end else */
+
+ /* Replicate the fill value into the cached buffer */
+ H5VM_array_fill(fb_info->fill_buf, fill->buf, fb_info->max_elmt_size, fb_info->elmts_per_buf);
+ } /* end else */
+ } /* end if */
+ else { /* Fill the buffer with the default fill value */
+ /* Retrieve size of elements */
+ fb_info->max_elmt_size = fb_info->file_elmt_size = fb_info->mem_elmt_size = H5T_get_size(dset_type);
+ HDassert(fb_info->max_elmt_size > 0);
+
+ /* Compute the number of elements that fit within a buffer to write */
+ if(total_nelmts > 0)
+ fb_info->elmts_per_buf = MIN(total_nelmts, MAX(1, (max_buf_size / fb_info->max_elmt_size)));
+ else
+ fb_info->elmts_per_buf = max_buf_size / fb_info->max_elmt_size;
+ HDassert(fb_info->elmts_per_buf > 0);
+
+ /* Compute the buffer size to use */
+ fb_info->fill_buf_size = MIN(max_buf_size, (fb_info->elmts_per_buf * fb_info->max_elmt_size));
+
+ /* Use (and zero) caller's buffer, if provided */
+ if(caller_fill_buf) {
+ fb_info->fill_buf = caller_fill_buf;
+ fb_info->use_caller_fill_buf = TRUE;
+
+ HDmemset(fb_info->fill_buf, 0, fb_info->fill_buf_size);
+ } /* end if */
+ else {
+ if(alloc_func) {
+ fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info);
+
+ HDmemset(fb_info->fill_buf, 0, fb_info->fill_buf_size);
+ } /* end if */
+ else {
+ htri_t buf_avail = H5FL_BLK_AVAIL(zero_fill, fb_info->fill_buf_size); /* Check if there is an already zeroed out buffer available */
+ HDassert(buf_avail != FAIL);
+
+ /* Allocate temporary buffer (zeroing it if no buffer is available) */
+ if(!buf_avail)
+ fb_info->fill_buf = H5FL_BLK_CALLOC(zero_fill, fb_info->fill_buf_size);
+ else
+ fb_info->fill_buf = H5FL_BLK_MALLOC(zero_fill, fb_info->fill_buf_size);
+ } /* end else */
+ if(fb_info->fill_buf == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer")
+ } /* end else */
+ } /* end else */
+
+done:
+ /* Cleanup on error */
+ if(ret_value < 0)
+ if(H5D__fill_term(fb_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__fill_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__fill_refill_vl
+ *
+ * Purpose: Refill fill value buffer that contains VL-datatype fill values
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June 21, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__fill_refill_vl(H5D_fill_buf_info_t *fb_info, size_t nelmts, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ void * buf = NULL; /* Temporary fill buffer */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(fb_info);
+ HDassert(fb_info->has_vlen_fill_type);
+ HDassert(fb_info->fill_buf);
+
+ /* Make a copy of the (disk-based) fill value into the buffer */
+ HDmemcpy(fb_info->fill_buf, fb_info->fill->buf, fb_info->file_elmt_size);
+
+ /* Reset first element of background buffer, if necessary */
+ if(H5T_path_bkg(fb_info->fill_to_mem_tpath))
+ HDmemset(fb_info->bkg_buf, 0, fb_info->max_elmt_size);
+
+ /* Type convert the dataset buffer, to copy any VL components */
+ if(H5T_convert(fb_info->fill_to_mem_tpath, fb_info->file_tid, fb_info->mem_tid, (size_t)1, (size_t)0, (size_t)0, fb_info->fill_buf, fb_info->bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed")
+
+ /* Replicate the fill value into the cached buffer */
+ if(nelmts > 1)
+ H5VM_array_fill((void *)((unsigned char *)fb_info->fill_buf + fb_info->mem_elmt_size), fb_info->fill_buf, fb_info->mem_elmt_size, (nelmts - 1));
+
+ /* Reset the entire background buffer, if necessary */
+ if(H5T_path_bkg(fb_info->mem_to_dset_tpath))
+ HDmemset(fb_info->bkg_buf, 0, fb_info->bkg_buf_size);
+
+ /* Make a copy of the fill buffer so we can free dynamic elements after conversion */
+ if(fb_info->fill_alloc_func)
+ buf = fb_info->fill_alloc_func(fb_info->fill_buf_size, fb_info->fill_alloc_info);
+ else
+ buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size);
+ if(!buf)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary fill buffer")
+
+ HDmemcpy(buf, fb_info->fill_buf, fb_info->fill_buf_size);
+
+ /* Type convert the dataset buffer, to copy any VL components */
+ if(H5T_convert(fb_info->mem_to_dset_tpath, fb_info->mem_tid, fb_info->file_tid, nelmts, (size_t)0, (size_t)0, fb_info->fill_buf, fb_info->bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed")
+
+done:
+ if(buf) {
+ /* Free dynamically allocated VL elements in fill buffer */
+ if(fb_info->fill->type) {
+ if(H5T_vlen_reclaim_elmt(buf, fb_info->fill->type, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't reclaim vlen element")
+ } /* end if */
+ else {
+ if(H5T_vlen_reclaim_elmt(buf, fb_info->mem_type, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't reclaim vlen element")
+ } /* end else */
+
+ /* Free temporary fill buffer */
+ if(fb_info->fill_free_func)
+ fb_info->fill_free_func(buf, fb_info->fill_free_info);
+ else
+ buf = H5FL_BLK_FREE(non_zero_fill, buf);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__fill_refill_vl() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__fill_release
+ *
+ * Purpose: Release fill value buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June 22, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__fill_release(H5D_fill_buf_info_t *fb_info)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check args */
+ HDassert(fb_info);
+ HDassert(fb_info->fill);
+
+ /* Free the buffer for fill values */
+ if(!fb_info->use_caller_fill_buf && fb_info->fill_buf) {
+ if(fb_info->fill_free_func)
+ fb_info->fill_free_func(fb_info->fill_buf, fb_info->fill_free_info);
+ else {
+ if(fb_info->fill->buf)
+ fb_info->fill_buf = H5FL_BLK_FREE(non_zero_fill, fb_info->fill_buf);
+ else
+ fb_info->fill_buf = H5FL_BLK_FREE(zero_fill, fb_info->fill_buf);
+ } /* end else */
+ fb_info->fill_buf = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__fill_release() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__fill_term
+ *
+ * Purpose: Release fill value buffer info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June 21, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__fill_term(H5D_fill_buf_info_t *fb_info)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check args */
+ HDassert(fb_info);
+
+ /* Free the buffer for fill values */
+ H5D__fill_release(fb_info);
+
+ /* Free other resources for vlen fill values */
+ if(fb_info->has_vlen_fill_type) {
+ if(fb_info->mem_tid > 0)
+ H5I_dec_ref(fb_info->mem_tid);
+ else if(fb_info->mem_type)
+ H5T_close(fb_info->mem_type);
+ if(fb_info->bkg_buf)
+ fb_info->bkg_buf = H5FL_BLK_FREE(type_conv, fb_info->bkg_buf);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__fill_term() */
+
diff --git a/src/H5Dint.c b/src/H5Dint.c
new file mode 100644
index 0000000..1813ca6
--- /dev/null
+++ b/src/H5Dint.c
@@ -0,0 +1,3676 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Struct for holding callback info during H5D_flush operation */
+typedef struct {
+ const H5F_t *f; /* Pointer to file being flushed */
+ hid_t dxpl_id; /* DXPL for I/O operations */
+} H5D_flush_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* General stuff */
+static herr_t H5D__get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache);
+static H5D_shared_t *H5D__new(hid_t dcpl_id, hbool_t creating,
+ hbool_t vl_type);
+static herr_t H5D__init_type(H5F_t *file, const H5D_t *dset, hid_t type_id,
+ const H5T_t *type);
+static herr_t H5D__cache_dataspace_info(const H5D_t *dset);
+static herr_t H5D__init_space(H5F_t *file, const H5D_t *dset, const H5S_t *space);
+static herr_t H5D__update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset,
+ hid_t dapl_id);
+static herr_t H5D_build_extfile_prefix(const H5D_t *dset, hid_t dapl_id,
+ char **extfile_prefix);
+static herr_t H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id);
+static herr_t H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite,
+ hsize_t old_dim[]);
+static herr_t H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Define a "default" dataset transfer property list cache structure to use for default DXPLs */
+H5D_dxpl_cache_t H5D_def_dxpl_cache;
+
+/* Declare a free list to manage blocks of VL data */
+H5FL_BLK_DEFINE(vlen_vl_buf);
+
+/* Declare a free list to manage other blocks of VL data */
+H5FL_BLK_DEFINE(vlen_fl_buf);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5D_t and H5D_shared_t structs */
+H5FL_DEFINE_STATIC(H5D_t);
+H5FL_DEFINE_STATIC(H5D_shared_t);
+
+/* Declare the external PQ free list for the sieve buffer information */
+H5FL_BLK_EXTERN(sieve_buf);
+
+/* Declare the external free list to manage the H5D_chunk_info_t struct */
+H5FL_EXTERN(H5D_chunk_info_t);
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+/* Define a static "default" dataset structure to use to initialize new datasets */
+static H5D_shared_t H5D_def_dset;
+
+/* Dataset ID class */
+static const H5I_class_t H5I_DATASET_CLS[1] = {{
+ H5I_DATASET, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5D_close /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5D_top_package_initialize_s = FALSE;
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_init
+ *
+ * Purpose: Initialize the interface from some other layer.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 4, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_init() */
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5D__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5D__init_package()
+
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+NOTES
+ Care must be taken when using the H5P functions, since they can cause
+ a deadlock in the library when the library is attempting to terminate -QAK
+
+--------------------------------------------------------------------------*/
+herr_t
+H5D__init_package(void)
+{
+ H5P_genplist_t *def_dcpl; /* Default Dataset Creation Property list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Initialize the atom group for the dataset IDs */
+ if(H5I_register_type(H5I_DATASET_CLS) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Reset the "default dataset" information */
+ HDmemset(&H5D_def_dset, 0, sizeof(H5D_shared_t));
+
+ /* Get the default dataset creation property list values and initialize the
+ * default dataset with them.
+ */
+ if(NULL == (def_dcpl = (H5P_genplist_t *)H5I_object(H5P_LST_DATASET_CREATE_ID_g)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "can't get default dataset creation property list")
+
+ /* Get the default data storage layout */
+ if(H5P_get(def_dcpl, H5D_CRT_LAYOUT_NAME, &H5D_def_dset.layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve layout")
+
+ /* Get the default dataset creation properties */
+ if(H5P_get(def_dcpl, H5D_CRT_EXT_FILE_LIST_NAME, &H5D_def_dset.dcpl_cache.efl) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve external file list")
+ if(H5P_get(def_dcpl, H5D_CRT_FILL_VALUE_NAME, &H5D_def_dset.dcpl_cache.fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve fill value")
+ if(H5P_get(def_dcpl, H5O_CRT_PIPELINE_NAME, &H5D_def_dset.dcpl_cache.pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve pipeline filter")
+
+ /* Reset the "default DXPL cache" information */
+ HDmemset(&H5D_def_dxpl_cache, 0, sizeof(H5D_dxpl_cache_t));
+
+ /* Get the default DXPL cache information */
+ if(H5D__get_dxpl_cache_real(H5P_DATASET_XFER_DEFAULT, &H5D_def_dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve default DXPL info")
+
+ /* Mark "top" of interface as initialized, too */
+ H5D_top_package_initialize_s = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_top_term_package
+ *
+ * Purpose: Close the "top" of the interface, releasing IDs, etc.
+ *
+ * Return: Success: Positive if anything was done that might
+ * affect other interfaces; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, September 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5D_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5D_top_package_initialize_s) {
+ if(H5I_nmembers(H5I_DATASET) > 0) {
+ /* The dataset API uses the "force" flag set to true because it
+ * is using the "file objects" (H5FO) API functions to track open
+ * objects in the file. Using the H5FO code means that dataset
+ * IDs can have reference counts >1, when an existing dataset is
+ * opened more than once. However, the H5I code does not attempt
+ * to close objects with reference counts>1 unless the "force" flag
+ * is set to true.
+ *
+ * At some point (probably after the group and datatypes use the
+ * the H5FO code), the H5FO code might need to be switched around
+ * to storing pointers to the objects being tracked (H5D_t, H5G_t,
+ * etc) and reference count those itself instead of relying on the
+ * reference counting in the H5I layer. Then, the "force" flag can
+ * be put back to false.
+ *
+ * Setting the "force" flag to true for all the interfaces won't
+ * work because the "file driver" (H5FD) APIs use the H5I reference
+ * counting to avoid closing a file driver out from underneath an
+ * open file...
+ *
+ * QAK - 5/13/03
+ */
+ (void)H5I_clear_type(H5I_DATASET, TRUE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Mark closed */
+ if(0 == n)
+ H5D_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5D_top_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_term_package
+ *
+ * Purpose: Terminate this interface.
+ *
+ * Note: Finishes shutting down the interface, after
+ * H5D_top_term_package() is called
+ *
+ * Return: Success: Positive if anything was done that might
+ * affect other interfaces; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 20, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5D_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity checks */
+ HDassert(0 == H5I_nmembers(H5I_DATASET));
+ HDassert(FALSE == H5D_top_package_initialize_s);
+
+ /* Destroy the dataset object id group */
+ n += (H5I_dec_type_ref(H5I_DATASET) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5D_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__get_dxpl_cache_real
+ PURPOSE
+ Get all the values for the DXPL cache.
+ USAGE
+ herr_t H5D__get_dxpl_cache_real(dxpl_id, cache)
+ hid_t dxpl_id; IN: DXPL to query
+ H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Query all the values from a DXPL that are needed by internal routines
+ within the library.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5D__get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache)
+{
+ H5P_genplist_t *dx_plist; /* Data transfer property list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(cache);
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Get maximum temporary buffer size */
+ if(H5P_get(dx_plist, H5D_XFER_MAX_TEMP_BUF_NAME, &cache->max_temp_buf) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve maximum temporary buffer size")
+
+ /* Get temporary buffer pointer */
+ if(H5P_get(dx_plist, H5D_XFER_TCONV_BUF_NAME, &cache->tconv_buf) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve temporary buffer pointer")
+
+ /* Get background buffer pointer */
+ if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_NAME, &cache->bkgr_buf) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer pointer")
+
+ /* Get background buffer type */
+ if(H5P_get(dx_plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &cache->bkgr_buf_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve background buffer type")
+
+ /* Get B-tree split ratios */
+ if(H5P_get(dx_plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &cache->btree_split_ratio) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve B-tree split ratios")
+
+ /* Get I/O vector size */
+ if(H5P_get(dx_plist, H5D_XFER_HYPER_VECTOR_SIZE_NAME, &cache->vec_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve I/O vector size")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Collect Parallel I/O information for possible later use */
+ if(H5P_get(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &cache->xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve parallel transfer method")
+ if(H5P_get(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &cache->coll_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve collective transfer option")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Get error detection properties */
+ if(H5P_get(dx_plist, H5D_XFER_EDC_NAME, &cache->err_detect) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve error detection info")
+
+ /* Get filter callback function */
+ if(H5P_get(dx_plist, H5D_XFER_FILTER_CB_NAME, &cache->filter_cb) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve filter callback function")
+
+ /* Look at the data transform property */
+ /* (Note: 'peek', not 'get' - if this turns out to be a problem, we should
+ * add a H5D__free_dxpl_cache() routine. -QAK)
+ */
+ if(H5P_peek(dx_plist, H5D_XFER_XFORM_NAME, &cache->data_xform_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve data transform info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__get_dxpl_cache_real() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__get_dxpl_cache
+ PURPOSE
+ Get all the values for the DXPL cache.
+ USAGE
+ herr_t H5D__get_dxpl_cache(dxpl_id, cache)
+ hid_t dxpl_id; IN: DXPL to query
+ H5D_dxpl_cache_t *cache;IN/OUT: DXPL cache to fill with values
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Query all the values from a DXPL that are needed by internal routines
+ within the library.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The CACHE pointer should point at already allocated memory to place
+ non-default property list info. If a default property list is used, the
+ CACHE pointer will be changed to point at the default information.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(cache);
+
+ /* Check for the default DXPL */
+ if(dxpl_id==H5P_DATASET_XFER_DEFAULT)
+ *cache=&H5D_def_dxpl_cache;
+ else
+ if(H5D__get_dxpl_cache_real(dxpl_id,*cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "Can't retrieve DXPL values")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__get_dxpl_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__create_named
+ *
+ * Purpose: Internal routine to create a new dataset.
+ *
+ * Return: Success: Non-NULL, pointer to new dataset object.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5D_t *
+H5D__create_named(const H5G_loc_t *loc, const char *name, hid_t type_id,
+ const H5S_t *space, hid_t lcpl_id, hid_t dcpl_id, hid_t dapl_id,
+ hid_t dxpl_id)
+{
+ H5O_obj_create_t ocrt_info; /* Information for object creation */
+ H5D_obj_create_t dcrt_info; /* Information for dataset creation */
+ H5D_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(type_id != H5P_DEFAULT);
+ HDassert(space);
+ HDassert(lcpl_id != H5P_DEFAULT);
+ HDassert(dcpl_id != H5P_DEFAULT);
+ HDassert(dapl_id != H5P_DEFAULT);
+ HDassert(dxpl_id != H5P_DEFAULT);
+
+ /* Set up dataset creation info */
+ dcrt_info.type_id = type_id;
+ dcrt_info.space = space;
+ dcrt_info.dcpl_id = dcpl_id;
+ dcrt_info.dapl_id = dapl_id;
+
+ /* Set up object creation information */
+ ocrt_info.obj_type = H5O_TYPE_DATASET;
+ ocrt_info.crt_info = &dcrt_info;
+ ocrt_info.new_obj = NULL;
+
+ /* Create the new dataset and link it to its parent group */
+ if(H5L_link_object(loc, name, &ocrt_info, lcpl_id, dapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to create and link to dataset")
+ HDassert(ocrt_info.new_obj);
+
+ /* Set the return value */
+ ret_value = (H5D_t *)ocrt_info.new_obj;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__create_named() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__get_space_status
+ *
+ * Purpose: Returns the status of data space allocation.
+ *
+ * Return:
+ * Success: Non-negative
+ *
+ * Failture: Negative
+ *
+ * Programmer: Raymond Lu
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__get_space_status(H5D_t *dset, H5D_space_status_t *allocation, hid_t dxpl_id)
+{
+ hsize_t space_allocated; /* The number of bytes allocated for chunks */
+ hssize_t snelmts; /* Temporary holder for number of elements in dataspace */
+ hsize_t nelmts; /* Number of elements in dataspace */
+ size_t dt_size; /* Size of datatype */
+ hsize_t full_size; /* The number of bytes in the dataset when fully populated */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dset);
+
+ /* Check for chunked layout */
+ if(dset->shared->layout.type == H5D_CHUNKED) {
+ /* For chunked layout set the space status by the storage size */
+ /* Get the dataset's dataspace */
+ HDassert(dset->shared->space);
+
+ /* Get the total number of elements in dataset's dataspace */
+ if((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace")
+ nelmts = (hsize_t)snelmts;
+
+ /* Get the size of the dataset's datatype */
+ if(0 == (dt_size = H5T_GET_SIZE(dset->shared->type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype")
+
+ /* Compute the maximum size of the dataset in bytes */
+ full_size = nelmts * dt_size;
+
+ /* Check for overflow during multiplication */
+ if(nelmts != (full_size / dt_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed")
+
+ /* Difficult to error check, since the error value is 0 and 0 is a valid value... :-/ */
+ if(H5D__get_storage_size(dset, dxpl_id, &space_allocated) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get size of dataset's storage")
+
+ /* Decide on how much of the space is allocated */
+ if(space_allocated == 0)
+ *allocation = H5D_SPACE_STATUS_NOT_ALLOCATED;
+ else if(space_allocated == full_size)
+ *allocation = H5D_SPACE_STATUS_ALLOCATED;
+ else
+ *allocation = H5D_SPACE_STATUS_PART_ALLOCATED;
+ } /* end if */
+ else {
+ /* For non-chunked layouts set space status by result of is_space_alloc
+ * function */
+ if(dset->shared->layout.ops->is_space_alloc(&dset->shared->layout.storage))
+ *allocation = H5D_SPACE_STATUS_ALLOCATED;
+ else
+ *allocation = H5D_SPACE_STATUS_NOT_ALLOCATED;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__get_space_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__new
+ *
+ * Purpose: Creates a new, empty dataset structure
+ *
+ * Return: Success: Pointer to a new dataset descriptor.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 12, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5D_shared_t *
+H5D__new(hid_t dcpl_id, hbool_t creating, hbool_t vl_type)
+{
+ H5D_shared_t *new_dset = NULL; /* New dataset object */
+ H5P_genplist_t *plist; /* Property list created */
+ H5D_shared_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Allocate new shared dataset structure */
+ if(NULL == (new_dset = H5FL_MALLOC(H5D_shared_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the default dataset information */
+ HDmemcpy(new_dset, &H5D_def_dset, sizeof(H5D_shared_t));
+
+ /* If we are using the default dataset creation property list, during creation
+ * don't bother to copy it, just increment the reference count
+ */
+ if(!vl_type && creating && dcpl_id == H5P_DATASET_CREATE_DEFAULT) {
+ if(H5I_inc_ref(dcpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't increment default DCPL ID")
+ new_dset->dcpl_id = dcpl_id;
+ } /* end if */
+ else {
+ /* Get the property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property list")
+
+ new_dset->dcpl_id = H5P_copy_plist(plist, FALSE);
+ } /* end else */
+
+ /* Set return value */
+ ret_value = new_dset;
+
+done:
+ if(ret_value == NULL)
+ if(new_dset != NULL) {
+ if(new_dset->dcpl_id != 0 && H5I_dec_ref(new_dset->dcpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, NULL, "can't decrement temporary datatype ID")
+ new_dset = H5FL_FREE(H5D_shared_t, new_dset);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__init_type
+ *
+ * Purpose: Copy a datatype for a dataset's use, performing all the
+ * necessary adjustments, etc.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 24, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__init_type(H5F_t *file, const H5D_t *dset, hid_t type_id, const H5T_t *type)
+{
+ htri_t relocatable; /* Flag whether the type is relocatable */
+ htri_t immutable; /* Flag whether the type is immutable */
+ hbool_t use_latest_format; /* Flag indicating the 'latest datatype version support' is enabled */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checking */
+ HDassert(file);
+ HDassert(dset);
+ HDassert(type);
+
+ /* Check whether the datatype is relocatable */
+ if((relocatable = H5T_is_relocatable(type)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't check datatype?")
+
+ /* Check whether the datatype is immutable */
+ if((immutable = H5T_is_immutable(type)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't check datatype?")
+
+ /* Get the file's 'use the latest datatype version support' flag */
+ use_latest_format = H5F_USE_LATEST_FLAGS(file, H5F_LATEST_DATATYPE);
+
+ /* Copy the datatype if it's a custom datatype or if it'll change when it's location is changed */
+ if(!immutable || relocatable || use_latest_format) {
+ /* Copy datatype for dataset */
+ if((dset->shared->type = H5T_copy(type, H5T_COPY_ALL)) == NULL)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy datatype")
+
+ /* Convert a datatype (if committed) to a transient type if the committed datatype's file
+ location is different from the file location where the dataset will be created */
+ if(H5T_convert_committed_datatype(dset->shared->type, file) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't get shared datatype info")
+
+ /* Mark any datatypes as being on disk now */
+ if(H5T_set_loc(dset->shared->type, file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't set datatype location")
+
+ /* Set the latest format, if requested */
+ if(use_latest_format)
+ if(H5T_set_latest_version(dset->shared->type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set latest version of datatype")
+
+ /* Get a datatype ID for the dataset's datatype */
+ if((dset->shared->type_id = H5I_register(H5I_DATATYPE, dset->shared->type, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register type")
+ } /* end if */
+ /* Not a custom datatype, just use it directly */
+ else {
+ if(H5I_inc_ref(type_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, FAIL, "Can't increment datatype ID")
+
+ /* Use existing datatype */
+ dset->shared->type_id = type_id;
+ dset->shared->type = (H5T_t *)type; /* (Cast away const OK - QAK) */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__init_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__cache_dataspace_info
+ *
+ * Purpose: Cache dataspace info for a dataset
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, November 19, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__cache_dataspace_info(const H5D_t *dset)
+{
+ int sndims; /* Signed number of dimensions of dataspace rank */
+ unsigned u; /* Local index value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checking */
+ HDassert(dset);
+
+ /* Cache info for dataset's dataspace */
+ if((sndims = H5S_get_simple_extent_dims(dset->shared->space, dset->shared->curr_dims, dset->shared->max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't cache dataspace dimensions")
+ dset->shared->ndims = (unsigned)sndims;
+
+ /* Compute the inital 'power2up' values */
+ for(u = 0; u < dset->shared->ndims; u++)
+ dset->shared->curr_power2up[u] = H5VM_power2up(dset->shared->curr_dims[u]);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__cache_dataspace_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__init_space
+ *
+ * Purpose: Copy a dataspace for a dataset's use, performing all the
+ * necessary adjustments, etc.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 24, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__init_space(H5F_t *file, const H5D_t *dset, const H5S_t *space)
+{
+ hbool_t use_latest_format; /* Flag indicating the 'latest dataspace version support' is enabled */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checking */
+ HDassert(file);
+ HDassert(dset);
+ HDassert(space);
+
+ /* Get the file's 'use the latest dataspace version support' flag */
+ use_latest_format = H5F_USE_LATEST_FLAGS(file, H5F_LATEST_DATASPACE);
+
+ /* Copy dataspace for dataset */
+ if(NULL == (dset->shared->space = H5S_copy(space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dataspace")
+
+ /* Cache the dataset's dataspace info */
+ if(H5D__cache_dataspace_info(dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't cache dataspace info")
+
+ /* Set the latest format, if requested */
+ if(use_latest_format)
+ if(H5S_set_latest_version(dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set latest version of datatype")
+
+ /* Set the dataset's dataspace to 'all' selection */
+ if(H5S_select_all(dset->shared->space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set all selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__init_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__update_oh_info
+ *
+ * Purpose: Create and fill object header for dataset
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Bill Wendling
+ * Thursday, October 31, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset, hid_t dapl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to dataset's object header */
+ size_t ohdr_size = H5D_MINHDR_SIZE; /* Size of dataset's object header */
+ H5O_loc_t *oloc = NULL; /* Dataset's object location */
+ H5O_layout_t *layout; /* Dataset's layout information */
+ H5T_t *type; /* Dataset's datatype */
+ H5O_fill_t *fill_prop; /* Pointer to dataset's fill value information */
+ H5D_fill_value_t fill_status; /* Fill value status */
+ hbool_t fill_changed = FALSE; /* Flag indicating the fill value was changed */
+ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checking */
+ HDassert(file);
+ HDassert(dset);
+
+ /* Set some local variables, for convenience */
+ oloc = &dset->oloc;
+ layout = &dset->shared->layout;
+ type = dset->shared->type;
+ fill_prop = &dset->shared->dcpl_cache.fill;
+
+ /* Retrieve "defined" status of fill value */
+ if(H5P_is_fill_value_defined(fill_prop, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* Special case handling for variable-length types */
+ if(H5T_detect_class(type, H5T_VLEN, FALSE)) {
+ /* If the default fill value is chosen for variable-length types, always write it */
+ if(fill_prop->fill_time == H5D_FILL_TIME_IFSET && fill_status == H5D_FILL_VALUE_DEFAULT) {
+ /* Update dataset creation property */
+ fill_prop->fill_time = H5D_FILL_TIME_ALLOC;
+
+ /* Note that the fill value changed */
+ fill_changed = TRUE;
+ } /* end if */
+
+ /* Don't allow never writing fill values with variable-length types */
+ if(fill_prop->fill_time == H5D_FILL_TIME_NEVER)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Dataset doesn't support VL datatype when fill value is not defined")
+ } /* end if */
+
+ /* Determine whether fill value is defined or not */
+ if(fill_status == H5D_FILL_VALUE_DEFAULT || fill_status == H5D_FILL_VALUE_USER_DEFINED) {
+ /* Convert fill value buffer to dataset's datatype */
+ if(fill_prop->buf && fill_prop->size > 0 && H5O_fill_convert(fill_prop, type, &fill_changed, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert fill value to dataset type")
+
+ fill_prop->fill_defined = TRUE;
+ } else if(fill_status == H5D_FILL_VALUE_UNDEFINED) {
+ fill_prop->fill_defined = FALSE;
+ } else
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine if fill value is defined")
+
+ /* Check for invalid fill & allocation time setting */
+ if(fill_prop->fill_defined == FALSE && fill_prop->fill_time == H5D_FILL_TIME_ALLOC)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "fill value writing on allocation set, but no fill value defined")
+
+ /* Check if the fill value info changed */
+ if(fill_changed) {
+ H5P_genplist_t *dc_plist; /* Dataset's creation property list */
+
+ /* Get dataset's property list object */
+ HDassert(dset->shared->dcpl_id != H5P_DATASET_CREATE_DEFAULT);
+ if(NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dset->shared->dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list")
+
+ /* Update dataset creation property */
+ if(H5P_set(dc_plist, H5D_CRT_FILL_VALUE_NAME, fill_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value info")
+ } /* end if */
+
+ /* Add the dataset's raw data size to the size of the header, if the raw data will be stored as compact */
+ if(layout->type == H5D_COMPACT)
+ ohdr_size += layout->storage.u.compact.size;
+
+ /* Create an object header for the dataset */
+ if(H5O_create(file, dxpl_id, ohdr_size, (size_t)1, dset->shared->dcpl_id, oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset object header")
+ HDassert(file == dset->oloc.file);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(oloc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+
+ /* Write the dataspace header message */
+ if(H5S_append(file, dxpl_id, oh, dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update dataspace header message")
+
+ /* Write the datatype header message */
+ if(H5O_msg_append_oh(file, dxpl_id, oh, H5O_DTYPE_ID, H5O_MSG_FLAG_CONSTANT, 0, type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update datatype header message")
+
+ /* Write new fill value message */
+ if(H5O_msg_append_oh(file, dxpl_id, oh, H5O_FILL_NEW_ID, H5O_MSG_FLAG_CONSTANT, 0, fill_prop) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update new fill value header message")
+
+ /* If there is valid information for the old fill value struct, add it */
+ /* (only if we aren't trying to write the 'latest fill message version support') */
+ if(fill_prop->buf && !(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_FILL_MSG))) {
+ H5O_fill_t old_fill_prop; /* Copy of fill value property, for writing as "old" fill value */
+
+ /* Shallow copy the fill value property */
+ /* (we only want to make certain that the shared component isnt' modified) */
+ HDmemcpy(&old_fill_prop, fill_prop, sizeof(old_fill_prop));
+
+ /* Reset shared component info */
+ H5O_msg_reset_share(H5O_FILL_ID, &old_fill_prop);
+
+ /* Write old fill value */
+ if(H5O_msg_append_oh(file, dxpl_id, oh, H5O_FILL_ID, H5O_MSG_FLAG_CONSTANT, 0, &old_fill_prop) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update old fill value header message")
+ } /* end if */
+
+ /* Update/create the layout (and I/O pipeline & EFL) messages */
+ if(H5D__layout_oh_create(file, dxpl_id, oh, dset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update layout/pline/efl header message")
+
+ /* Indicate that the layout information was initialized */
+ layout_init = TRUE;
+
+#ifdef H5O_ENABLE_BOGUS
+{
+ H5P_genplist_t *dc_plist; /* Dataset's creation property list */
+
+ /* Get dataset's property list object */
+ if(NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dset->shared->dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list")
+
+ /* Check whether to add a "bogus" message */
+ if( (H5P_exist_plist(dc_plist, H5O_BOGUS_MSG_FLAGS_NAME) > 0) &&
+ (H5P_exist_plist(dc_plist, H5O_BOGUS_MSG_ID_NAME) > 0) ) {
+
+ uint8_t bogus_flags = 0; /* Flags for creating "bogus" message */
+ unsigned bogus_id; /* "bogus" ID */
+
+ /* Retrieve "bogus" message ID */
+ if(H5P_get(dc_plist, H5O_BOGUS_MSG_ID_NAME, &bogus_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get bogus ID options")
+ /* Retrieve "bogus" message flags */
+ if(H5P_get(dc_plist, H5O_BOGUS_MSG_FLAGS_NAME, &bogus_flags) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get bogus message options")
+
+ /* Add a "bogus" message (for error testing). */
+ if(H5O_bogus_oh(file, dxpl_id, oh, bogus_id, (unsigned)bogus_flags) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create 'bogus' message")
+ } /* end if */
+}
+#endif /* H5O_ENABLE_BOGUS */
+
+ /* Add a modification time message, if using older format. */
+ /* (If using the latest 'no modification time message' version support, the modification time is part of the object
+ * header and doesn't use a separate message -QAK)
+ */
+ if(!(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_NO_MOD_TIME_MSG)))
+ if(H5O_touch_oh(file, dxpl_id, oh, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update modification time message")
+
+done:
+ /* Release pointer to object header itself */
+ if(oh != NULL)
+ if(H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
+ /* Error cleanup */
+ if(ret_value < 0)
+ if(layout_init)
+ /* Destroy the layout information for the dataset */
+ if(dset->shared->layout.ops->dest && (dset->shared->layout.ops->dest)(dset, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__update_oh_info() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5D_build_extfile_prefix
+ *
+ * Purpose: Determine the external file prefix to be used and store
+ * it in extfile_prefix. Stores an empty string if no prefix
+ * should be used.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Steffen Kiess
+ * October 16, 2015
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5D_build_extfile_prefix(const H5D_t *dset, hid_t dapl_id, char **extfile_prefix /*out*/)
+{
+ char *prefix = NULL; /* prefix used to look for the file */
+ char *extpath = NULL; /* absolute path of directory the HDF5 file is in */
+ size_t extpath_len; /* length of extpath */
+ size_t prefix_len; /* length of prefix */
+ size_t extfile_prefix_len; /* length of expanded prefix */
+ H5P_genplist_t *plist = NULL; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(dset);
+ HDassert(dset->oloc.file);
+
+ extpath = H5F_EXTPATH(dset->oloc.file);
+ HDassert(extpath);
+
+ /* XXX: Future thread-safety note - getenv is not required
+ * to be reentrant.
+ */
+ prefix = HDgetenv("HDF5_EXTFILE_PREFIX");
+
+ if(prefix == NULL || *prefix == '\0') {
+ /* Set prefix to value of H5D_ACS_EFILE_PREFIX_NAME property */
+ if(NULL == (plist = H5P_object_verify(dapl_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+ if(H5P_peek(plist, H5D_ACS_EFILE_PREFIX_NAME, &prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file prefix")
+ } /* end if */
+
+ /* Prefix has to be checked for NULL / empty string again because the
+ * code above might have updated it.
+ */
+ if(prefix == NULL || *prefix == '\0' || HDstrcmp(prefix, ".") == 0) {
+ /* filename is interpreted as relative to the current directory,
+ * does not need to be expanded
+ */
+ if(NULL == (*extfile_prefix = (char *)H5MM_strdup("")))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end if */
+ else {
+ if (HDstrncmp(prefix, "${ORIGIN}", HDstrlen("${ORIGIN}")) == 0) {
+ /* Replace ${ORIGIN} at beginning of prefix by directory of HDF5 file */
+ extpath_len = HDstrlen(extpath);
+ prefix_len = HDstrlen(prefix);
+ extfile_prefix_len = extpath_len + prefix_len - HDstrlen("${ORIGIN}") + 1;
+
+ if(NULL == (*extfile_prefix = (char *)H5MM_malloc(extfile_prefix_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate buffer")
+ HDsnprintf(*extfile_prefix, extfile_prefix_len, "%s%s", extpath, prefix + HDstrlen("${ORIGIN}"));
+ } /* end if */
+ else {
+ if(NULL == (*extfile_prefix = (char *)H5MM_strdup(prefix)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D_build_extfile_prefix() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__create
+ *
+ * Purpose: Creates a new dataset with name NAME in file F and associates
+ * with it a datatype TYPE for each element as stored in the
+ * file, dimensionality information or dataspace SPACE, and
+ * other miscellaneous properties CREATE_PARMS. All arguments
+ * are deep-copied before being associated with the new dataset,
+ * so the caller is free to subsequently modify them without
+ * affecting the dataset.
+ *
+ * Return: Success: Pointer to a new dataset
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5D_t *
+H5D__create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id,
+ hid_t dapl_id, hid_t dxpl_id)
+{
+ const H5T_t *type; /* Datatype for dataset */
+ H5D_t *new_dset = NULL;
+ H5P_genplist_t *dc_plist = NULL; /* New Property list */
+ hbool_t has_vl_type = FALSE; /* Flag to indicate a VL-type for dataset */
+ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */
+ hbool_t layout_copied = FALSE; /* Flag to indicate that layout message was copied */
+ hbool_t fill_copied = FALSE; /* Flag to indicate that fill-value message was copied */
+ hbool_t pline_copied = FALSE; /* Flag to indicate that pipeline message was copied */
+ hbool_t efl_copied = FALSE; /* Flag to indicate that external file list message was copied */
+ H5G_loc_t dset_loc; /* Dataset location */
+ H5D_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(file);
+ HDassert(H5I_DATATYPE == H5I_get_type(type_id));
+ HDassert(space);
+ HDassert(H5I_GENPROP_LST == H5I_get_type(dcpl_id));
+ HDassert(H5I_GENPROP_LST == H5I_get_type(dxpl_id));
+
+ /* Get the dataset's datatype */
+ if(NULL == (type = (const H5T_t *)H5I_object(type_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a datatype")
+
+ /* Check if the datatype is "sensible" for use in a dataset */
+ if(H5T_is_sensible(type) != TRUE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "datatype is not sensible")
+
+ /* Check if the datatype is/contains a VL-type */
+ if(H5T_detect_class(type, H5T_VLEN, FALSE))
+ has_vl_type = TRUE;
+
+ /* Check if the dataspace has an extent set (or is NULL) */
+ if(!H5S_has_extent(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "dataspace extent has not been set.")
+
+ /* Initialize the dataset object */
+ if(NULL == (new_dset = H5FL_CALLOC(H5D_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set up & reset dataset location */
+ dset_loc.oloc = &(new_dset->oloc);
+ dset_loc.path = &(new_dset->path);
+ H5G_loc_reset(&dset_loc);
+
+ /* Initialize the shared dataset space */
+ if(NULL == (new_dset->shared = H5D__new(dcpl_id, TRUE, has_vl_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy & initialize datatype for dataset */
+ if(H5D__init_type(file, new_dset, type_id, type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't copy datatype")
+
+ /* Copy & initialize dataspace for dataset */
+ if(H5D__init_space(file, new_dset, space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't copy dataspace")
+
+ /* Set the dataset's checked_filters flag to enable writing */
+ new_dset->shared->checked_filters = TRUE;
+
+ /* Check if the dataset has a non-default DCPL & get important values, if so */
+ if(new_dset->shared->dcpl_id != H5P_DATASET_CREATE_DEFAULT) {
+ H5O_layout_t *layout; /* Dataset's layout information */
+ H5O_pline_t *pline; /* Dataset's I/O pipeline information */
+ H5O_fill_t *fill; /* Dataset's fill value info */
+ H5O_efl_t *efl; /* Dataset's external file list info */
+
+ /* Check if the filters in the DCPL can be applied to this dataset */
+ if(H5Z_can_apply(new_dset->shared->dcpl_id, new_dset->shared->type_id) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, NULL, "I/O filters can't operate on this dataset")
+
+ /* Make the "set local" filter callbacks for this dataset */
+ if(H5Z_set_local(new_dset->shared->dcpl_id, new_dset->shared->type_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to set local filter parameters")
+
+ /* Get new dataset's property list object */
+ if(NULL == (dc_plist = (H5P_genplist_t *)H5I_object(new_dset->shared->dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "can't get dataset creation property list")
+
+ /* Retrieve the properties we need */
+ pline = &new_dset->shared->dcpl_cache.pline;
+ if(H5P_get(dc_plist, H5O_CRT_PIPELINE_NAME, pline) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't retrieve pipeline filter")
+ pline_copied = TRUE;
+ layout = &new_dset->shared->layout;
+ if(H5P_get(dc_plist, H5D_CRT_LAYOUT_NAME, layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't retrieve layout")
+ layout_copied = TRUE;
+ fill = &new_dset->shared->dcpl_cache.fill;
+ if(H5P_get(dc_plist, H5D_CRT_FILL_VALUE_NAME, fill) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't retrieve fill value info")
+ fill_copied = TRUE;
+ efl = &new_dset->shared->dcpl_cache.efl;
+ if(H5P_get(dc_plist, H5D_CRT_EXT_FILE_LIST_NAME, efl) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't retrieve external file list")
+ efl_copied = TRUE;
+
+ /* Check that chunked layout is used if filters are enabled */
+ if(pline->nused > 0 && H5D_CHUNKED != layout->type)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, "filters can only be used with chunked layout")
+
+ /* Check if the alloc_time is the default and error out */
+ if(fill->alloc_time == H5D_ALLOC_TIME_DEFAULT)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, "invalid space allocation state")
+
+ /* Don't allow compact datasets to allocate space later */
+ if(layout->type == H5D_COMPACT && fill->alloc_time != H5D_ALLOC_TIME_EARLY)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, "compact dataset must have early space allocation")
+
+ /* If MPI VFD is used, no filter support yet. */
+ if(H5F_HAS_FEATURE(file, H5FD_FEAT_HAS_MPI) && pline->nused > 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, "Parallel I/O does not support filters yet")
+ } /* end if */
+
+ /* Set the latest version of the layout, pline & fill messages, if requested */
+ if(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_DSET_MSG_FLAGS)) {
+ /* Set the latest version for the I/O pipeline message */
+ if(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_PLINE_MSG))
+ if(H5O_pline_set_latest_version(&new_dset->shared->dcpl_cache.pline) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest version of I/O filter pipeline")
+
+ /* Set the latest version for the fill message */
+ if(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_FILL_MSG))
+ /* Set the latest version for the fill value message */
+ if(H5O_fill_set_latest_version(&new_dset->shared->dcpl_cache.fill) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest version of fill value")
+
+ /* Set the latest version for the layout message */
+ if(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_LAYOUT_MSG))
+ /* Set the latest version for the layout message */
+ if(H5D__layout_set_latest_version(&new_dset->shared->layout, new_dset->shared->space, &new_dset->shared->dcpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest version of layout")
+ } /* end if */
+ else if(new_dset->shared->layout.version >= H5O_LAYOUT_VERSION_4) {
+ /* Use latest indexing type for layout message version >= 4 */
+ if(H5D__layout_set_latest_indexing(&new_dset->shared->layout, new_dset->shared->space, &new_dset->shared->dcpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, NULL, "can't set latest indexing")
+ } /* end if */
+
+ /* Check if this dataset is going into a parallel file and set space allocation time */
+ if(H5F_HAS_FEATURE(file, H5FD_FEAT_ALLOCATE_EARLY))
+ new_dset->shared->dcpl_cache.fill.alloc_time = H5D_ALLOC_TIME_EARLY;
+
+ /* Set the dataset's I/O operations */
+ if(H5D__layout_set_io_ops(new_dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize I/O operations")
+
+ /* Create the layout information for the new dataset */
+ if(new_dset->shared->layout.ops->construct && (new_dset->shared->layout.ops->construct)(file, new_dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to construct layout information")
+
+ /* Update the dataset's object header info. */
+ if(H5D__update_oh_info(file, dxpl_id, new_dset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't update the metadata cache")
+
+ /* Indicate that the layout information was initialized */
+ layout_init = TRUE;
+
+ /* Set up append flush parameters for the dataset */
+ if(H5D__append_flush_setup(new_dset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to set up flush append property")
+
+ /* Set the external file prefix */
+ if(H5D_build_extfile_prefix(new_dset, dapl_id, &new_dset->shared->extfile_prefix) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize external file prefix")
+
+ /* Add the dataset to the list of opened objects in the file */
+ if(H5FO_top_incr(new_dset->oloc.file, new_dset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't incr object ref. count")
+ if(H5FO_insert(new_dset->oloc.file, new_dset->oloc.addr, new_dset->shared, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, NULL, "can't insert dataset into list of open objects")
+ new_dset->shared->fo_count = 1;
+
+ /* Success */
+ ret_value = new_dset;
+
+done:
+ if(!ret_value && new_dset && new_dset->shared) {
+ if(new_dset->shared) {
+ if(layout_init)
+ if(new_dset->shared->layout.ops->dest && (new_dset->shared->layout.ops->dest)(new_dset, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, NULL, "unable to destroy layout info")
+ if(pline_copied)
+ if(H5O_msg_reset(H5O_PLINE_ID, &new_dset->shared->dcpl_cache.pline) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, NULL, "unable to reset I/O pipeline info")
+ if(layout_copied)
+ if(H5O_msg_reset(H5O_LAYOUT_ID, &new_dset->shared->layout) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, NULL, "unable to reset layout info")
+ if(fill_copied)
+ if(H5O_msg_reset(H5O_FILL_ID, &new_dset->shared->dcpl_cache.fill) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, NULL, "unable to reset fill-value info")
+ if(efl_copied)
+ if(H5O_msg_reset(H5O_EFL_ID, &new_dset->shared->dcpl_cache.efl) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, NULL, "unable to reset external file list info")
+ if(new_dset->shared->space && H5S_close(new_dset->shared->space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, NULL, "unable to release dataspace")
+ if(new_dset->shared->type && H5I_dec_ref(new_dset->shared->type_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, NULL, "unable to release datatype")
+ if(H5F_addr_defined(new_dset->oloc.addr)) {
+ if(H5O_dec_rc_by_loc(&(new_dset->oloc), dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, NULL, "unable to decrement refcount on newly created object")
+ if(H5O_close(&(new_dset->oloc), NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, NULL, "unable to release object header")
+ if(file) {
+ if(H5O_delete(file, dxpl_id, new_dset->oloc.addr) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDELETE, NULL, "unable to delete object header")
+ } /* end if */
+ } /* end if */
+ if(new_dset->shared->dcpl_id != 0 && H5I_dec_ref(new_dset->shared->dcpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, NULL, "unable to decrement ref count on property list")
+ new_dset->shared->extfile_prefix = (char *)H5MM_xfree(new_dset->shared->extfile_prefix);
+ new_dset->shared = H5FL_FREE(H5D_shared_t, new_dset->shared);
+ } /* end if */
+ new_dset->oloc.file = NULL;
+ new_dset = H5FL_FREE(H5D_t, new_dset);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__open_name
+ *
+ * Purpose: Opens an existing dataset by name.
+ *
+ * Return: Success: Ptr to a new dataset.
+ * Failure: NULL
+ *
+ * Programmer: Neil Fortner
+ * Friday, March 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+H5D_t *
+H5D__open_name(const H5G_loc_t *loc, const char *name, hid_t dapl_id,
+ hid_t dxpl_id)
+{
+ H5D_t *dset = NULL;
+ H5G_loc_t dset_loc; /* Object location of dataset */
+ H5G_name_t path; /* Dataset group hier. path */
+ H5O_loc_t oloc; /* Dataset object location */
+ H5O_type_t obj_type; /* Type of object at location */
+ hbool_t loc_found = FALSE; /* Location at 'name' found */
+ H5D_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Set up dataset location to fill in */
+ dset_loc.oloc = &oloc;
+ dset_loc.path = &path;
+ H5G_loc_reset(&dset_loc);
+
+ /* Find the dataset object */
+ if(H5G_loc_find(loc, name, &dset_loc, dapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, NULL, "not found")
+ loc_found = TRUE;
+
+ /* Check that the object found is the correct type */
+ if(H5O_obj_type(&oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, "can't get object type")
+ if(obj_type != H5O_TYPE_DATASET)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, NULL, "not a dataset")
+
+ /* Open the dataset */
+ if(NULL == (dset = H5D_open(&dset_loc, dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "can't open dataset")
+
+ /* Set return value */
+ ret_value = dset;
+
+done:
+ if(!ret_value)
+ if(loc_found && H5G_loc_free(&dset_loc) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, NULL, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__open_name() */
+
+
+/*
+ *-------------------------------------------------------------------------
+ * Function: H5D_open
+ *
+ * Purpose: Checks if dataset is already open, or opens a dataset for
+ * access.
+ *
+ * Return: Success: Dataset ID
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5D_t *
+H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id)
+{
+ H5D_shared_t *shared_fo = NULL;
+ H5D_t *dataset = NULL;
+ char *extfile_prefix = NULL; /* Expanded external file prefix */
+ H5D_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(loc);
+
+ /* Allocate the dataset structure */
+ if(NULL == (dataset = H5FL_CALLOC(H5D_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Shallow copy (take ownership) of the object location object */
+ if(H5O_loc_copy(&(dataset->oloc), loc->oloc, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, NULL, "can't copy object location")
+
+ /* Shallow copy (take ownership) of the group hier. path */
+ if(H5G_name_copy(&(dataset->path), loc->path, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, NULL, "can't copy path")
+
+ /* Get the external file prefix */
+ if(H5D_build_extfile_prefix(dataset, dapl_id, &extfile_prefix) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize external file prefix")
+
+ /* Check if dataset was already open */
+ if(NULL == (shared_fo = (H5D_shared_t *)H5FO_opened(dataset->oloc.file, dataset->oloc.addr))) {
+ /* Clear any errors from H5FO_opened() */
+ H5E_clear_stack(NULL);
+
+ /* Open the dataset object */
+ if(H5D__open_oid(dataset, dapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, NULL, "not found")
+
+ /* Add the dataset to the list of opened objects in the file */
+ if(H5FO_insert(dataset->oloc.file, dataset->oloc.addr, dataset->shared, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, NULL, "can't insert dataset into list of open objects")
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(dataset->oloc.file, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't increment object count")
+
+ /* We're the first dataset to use the the shared info */
+ dataset->shared->fo_count = 1;
+
+ /* Set the external file prefix */
+ dataset->shared->extfile_prefix = extfile_prefix;
+ /* Prevent string from being freed during done: */
+ extfile_prefix = NULL;
+
+ } /* end if */
+ else {
+ /* Point to shared info */
+ dataset->shared = shared_fo;
+
+ /* Increment # of datasets using shared information */
+ shared_fo->fo_count++;
+
+ /* Check whether the external file prefix of the already open dataset
+ * matches the new external file prefix
+ */
+ if(HDstrcmp(extfile_prefix, dataset->shared->extfile_prefix) != 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "new external file prefix does not match external file prefix of already open dataset")
+
+ /* Check if the object has been opened through the top file yet */
+ if(H5FO_top_count(dataset->oloc.file, dataset->oloc.addr) == 0) {
+ /* Open the object through this top file */
+ if(H5O_open(&(dataset->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "unable to open object header")
+ } /* end if */
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(dataset->oloc.file, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't increment object count")
+ } /* end else */
+
+ /* Set the dataset to return */
+ ret_value = dataset;
+
+done:
+ extfile_prefix = (char *)H5MM_xfree(extfile_prefix);
+
+ if(ret_value == NULL) {
+ /* Free the location--casting away const*/
+ if(dataset) {
+ if(shared_fo == NULL && dataset->shared) { /* Need to free shared fo */
+ dataset->shared->extfile_prefix = (char *)H5MM_xfree(dataset->shared->extfile_prefix);
+ dataset->shared = H5FL_FREE(H5D_shared_t, dataset->shared);
+ }
+
+ H5O_loc_free(&(dataset->oloc));
+ H5G_name_free(&(dataset->path));
+
+ dataset = H5FL_FREE(H5D_t, dataset);
+ } /* end if */
+ if(shared_fo)
+ shared_fo->fo_count--;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_open() */
+
+
+/*
+ *-------------------------------------------------------------------------
+ * Function: H5D__flush_append_setup
+ *
+ * Purpose: Set the append flush parameters for a dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Wednesday, January 8, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(dset);
+ HDassert(dset->shared);
+
+ /* Set default append flush values */
+ HDmemset(&dset->shared->append_flush, 0, sizeof(dset->shared->append_flush));
+
+ /* If the dataset is chunked and there is a non-default DAPL */
+ if(dapl_id != H5P_DATASET_ACCESS_DEFAULT && dset->shared->layout.type == H5D_CHUNKED) {
+ H5P_genplist_t *dapl; /* data access property list object pointer */
+
+ /* Get dataset access property list */
+ if(NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for dapl ID");
+
+ /* Check if append flush property exists */
+ if(H5P_exist_plist(dapl, H5D_ACS_APPEND_FLUSH_NAME) > 0) {
+ H5D_append_flush_t info;
+
+ /* Get append flush property */
+ if(H5P_get(dapl, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get append flush info")
+ if(info.ndims > 0) {
+ hsize_t curr_dims[H5S_MAX_RANK]; /* current dimension sizes */
+ hsize_t max_dims[H5S_MAX_RANK]; /* current dimension sizes */
+ int rank; /* dataspace # of dimensions */
+ unsigned u; /* local index variable */
+
+ /* Get dataset rank */
+ if((rank = H5S_get_simple_extent_dims(dset->shared->space, curr_dims, max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions")
+ if(info.ndims != (unsigned)rank)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "boundary dimension rank does not match dataset rank")
+
+ /* Validate boundary sizes */
+ for(u = 0; u < info.ndims; u++)
+ if(info.boundary[u] != 0) /* when a non-zero boundary is set */
+ /* the dimension is extendible? */
+ if(max_dims[u] != H5S_UNLIMITED && max_dims[u] == curr_dims[u])
+ break;
+
+ /* At least one boundary dimension is not extendible */
+ if(u != info.ndims)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "boundary dimension is not valid")
+
+ /* Copy append flush settings */
+ dset->shared->append_flush.ndims = info.ndims;
+ dset->shared->append_flush.func = info.func;
+ dset->shared->append_flush.udata = info.udata;
+ HDmemcpy(dset->shared->append_flush.boundary, info.boundary, sizeof(info.boundary));
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__append_flush_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__open_oid
+ *
+ * Purpose: Opens a dataset for access.
+ *
+ * Return: Dataset pointer on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 12, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_fill_t *fill_prop; /* Pointer to dataset's fill value info */
+ unsigned alloc_time_state; /* Allocation time state */
+ htri_t msg_exists; /* Whether a particular type of message exists */
+ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, dataset->oloc.addr, FAIL)
+
+ /* check args */
+ HDassert(dataset);
+
+ /* (Set the 'vl_type' parameter to FALSE since it doesn't matter from here) */
+ if(NULL == (dataset->shared = H5D__new(H5P_DATASET_CREATE_DEFAULT, FALSE, FALSE)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Open the dataset object */
+ if(H5O_open(&(dataset->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open")
+
+ /* Get the type and space */
+ if(NULL == (dataset->shared->type = (H5T_t *)H5O_msg_read(&(dataset->oloc), H5O_DTYPE_ID, NULL, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load type info from dataset header")
+
+ if(H5T_set_loc(dataset->shared->type, dataset->oloc.file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid datatype location")
+
+ if(NULL == (dataset->shared->space = H5S_read(&(dataset->oloc), dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load dataspace info from dataset header")
+
+ /* Cache the dataset's dataspace info */
+ if(H5D__cache_dataspace_info(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't cache dataspace info")
+
+ /* Get a datatype ID for the dataset's datatype */
+ if((dataset->shared->type_id = H5I_register(H5I_DATATYPE, dataset->shared->type, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register type")
+
+ /* Get dataset creation property list object */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dataset->shared->dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list")
+
+ /* Get the layout/pline/efl message information */
+ if(H5D__layout_oh_read(dataset, dxpl_id, dapl_id, plist) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get layout/pline/efl info")
+
+ /* Indicate that the layout information was initialized */
+ layout_init = TRUE;
+
+ /* Set up flush append property */
+ if(H5D__append_flush_setup(dataset, dapl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set up flush append property")
+
+ /* Point at dataset's copy, to cache it for later */
+ fill_prop = &dataset->shared->dcpl_cache.fill;
+
+ /* Try to get the new fill value message from the object header */
+ if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_FILL_NEW_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists")
+ if(msg_exists) {
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_NEW_ID, fill_prop, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message")
+ } /* end if */
+ else {
+ /* For backward compatibility, try to retrieve the old fill value message */
+ if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_FILL_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists")
+ if(msg_exists) {
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_FILL_ID, fill_prop, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message")
+ } /* end if */
+ else {
+ /* Set the space allocation time appropriately, based on the type of dataset storage */
+ switch(dataset->shared->layout.type) {
+ case H5D_COMPACT:
+ fill_prop->alloc_time = H5D_ALLOC_TIME_EARLY;
+ break;
+
+ case H5D_CONTIGUOUS:
+ fill_prop->alloc_time = H5D_ALLOC_TIME_LATE;
+ break;
+
+ case H5D_CHUNKED:
+ fill_prop->alloc_time = H5D_ALLOC_TIME_INCR;
+ break;
+
+ case H5D_VIRTUAL:
+ fill_prop->alloc_time = H5D_ALLOC_TIME_INCR;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "not implemented yet")
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+ } /* end else */
+
+ /* If "old" fill value size is 0 (undefined), map it to -1 */
+ if(fill_prop->size == 0)
+ fill_prop->size = (ssize_t)-1;
+ } /* end if */
+ alloc_time_state = 0;
+ if((dataset->shared->layout.type == H5D_COMPACT && fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY)
+ || (dataset->shared->layout.type == H5D_CONTIGUOUS && fill_prop->alloc_time == H5D_ALLOC_TIME_LATE)
+ || (dataset->shared->layout.type == H5D_CHUNKED && fill_prop->alloc_time == H5D_ALLOC_TIME_INCR)
+ || (dataset->shared->layout.type == H5D_VIRTUAL && fill_prop->alloc_time == H5D_ALLOC_TIME_INCR))
+ alloc_time_state = 1;
+
+ /* Set revised fill value properties, if they are different from the defaults */
+ if(H5P_fill_value_cmp(&H5D_def_dset.dcpl_cache.fill, fill_prop, sizeof(H5O_fill_t))) {
+ if(H5P_set(plist, H5D_CRT_FILL_VALUE_NAME, fill_prop) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set fill value")
+ if(H5P_set(plist, H5D_CRT_ALLOC_TIME_STATE_NAME, &alloc_time_state) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set allocation time state")
+ } /* end if */
+
+ /*
+ * Make sure all storage is properly initialized.
+ * This is important only for parallel I/O where the space must
+ * be fully allocated before I/O can happen.
+ */
+ if((H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR)
+ && !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)
+ && H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_ALLOCATE_EARLY)) {
+ H5D_io_info_t io_info;
+
+ io_info.dset = dataset;
+ io_info.raw_dxpl_id = H5AC_rawdata_dxpl_id;
+ io_info.md_dxpl_id = dxpl_id;
+
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_OPEN, FALSE, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file storage")
+ } /* end if */
+
+done:
+ if(ret_value < 0) {
+ if(H5F_addr_defined(dataset->oloc.addr) && H5O_close(&(dataset->oloc), NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release object header")
+ if(dataset->shared) {
+ if(layout_init)
+ if(dataset->shared->layout.ops->dest && (dataset->shared->layout.ops->dest)(dataset, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+ if(dataset->shared->space && H5S_close(dataset->shared->space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+ if(dataset->shared->type) {
+ if(dataset->shared->type_id > 0) {
+ if(H5I_dec_ref(dataset->shared->type_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+ } /* end if */
+ else {
+ if(H5T_close(dataset->shared->type) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+ } /* end else */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__open_oid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_close
+ *
+ * Purpose: Insures that all data has been saved to the file, closes the
+ * dataset object header, and frees all resources used by the
+ * descriptor.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_close(H5D_t *dataset)
+{
+ hbool_t free_failed = FALSE; /* Set if freeing sub-components failed */
+ hbool_t corked; /* Whether the dataset is corked or not */
+ hbool_t file_closed = TRUE; /* H5O_close also closed the file? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file && dataset->shared);
+ HDassert(dataset->shared->fo_count > 0);
+
+ /* Dump debugging info */
+#ifdef H5D_CHUNK_DEBUG
+ H5D__chunk_stats(dataset, FALSE);
+#endif /* H5D_CHUNK_DEBUG */
+
+ dataset->shared->fo_count--;
+ if(dataset->shared->fo_count == 0) {
+
+ /* Flush the dataset's information. Continue to close even if it fails. */
+ if(H5D__flush_real(dataset, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info")
+
+ /* Set a flag to indicate the dataset is closing, before we start freeing things */
+ /* (Avoids problems with flushing datasets twice, when one is holding
+ * the file open and it iterates through dataset to flush them -QAK)
+ */
+ dataset->shared->closing = TRUE;
+
+ /* Free cached information for each kind of dataset */
+ switch(dataset->shared->layout.type) {
+ case H5D_CONTIGUOUS:
+ /* Free the data sieve buffer, if it's been allocated */
+ if(dataset->shared->cache.contig.sieve_buf)
+ dataset->shared->cache.contig.sieve_buf = (unsigned char *)H5FL_BLK_FREE(sieve_buf,dataset->shared->cache.contig.sieve_buf);
+ break;
+
+ case H5D_CHUNKED:
+ /* Check for skip list for iterating over chunks during I/O to close */
+ if(dataset->shared->cache.chunk.sel_chunks) {
+ HDassert(H5SL_count(dataset->shared->cache.chunk.sel_chunks) == 0);
+ H5SL_close(dataset->shared->cache.chunk.sel_chunks);
+ dataset->shared->cache.chunk.sel_chunks = NULL;
+ } /* end if */
+
+ /* Check for cached single chunk dataspace */
+ if(dataset->shared->cache.chunk.single_space) {
+ (void)H5S_close(dataset->shared->cache.chunk.single_space);
+ dataset->shared->cache.chunk.single_space = NULL;
+ } /* end if */
+
+ /* Check for cached single element chunk info */
+ if(dataset->shared->cache.chunk.single_chunk_info) {
+ dataset->shared->cache.chunk.single_chunk_info = H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info);
+ dataset->shared->cache.chunk.single_chunk_info = NULL;
+ } /* end if */
+ break;
+
+ case H5D_COMPACT:
+ /* Nothing special to do (info freed in the layout destroy) */
+ break;
+
+ case H5D_VIRTUAL:
+ {
+ size_t i, j;
+
+ HDassert(dataset->shared->layout.storage.u.virt.list || (dataset->shared->layout.storage.u.virt.list_nused == 0));
+
+ /* Close source datasets */
+ for(i = 0; i < dataset->shared->layout.storage.u.virt.list_nused; i++) {
+ /* Close source dataset */
+ if(dataset->shared->layout.storage.u.virt.list[i].source_dset.dset) {
+ HDassert(dataset->shared->layout.storage.u.virt.list[i].source_dset.dset != dataset);
+ if(H5D_close(dataset->shared->layout.storage.u.virt.list[i].source_dset.dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
+ dataset->shared->layout.storage.u.virt.list[i].source_dset.dset = NULL;
+ } /* end if */
+
+ /* Close sub datasets */
+ for(j = 0; j < dataset->shared->layout.storage.u.virt.list[i].sub_dset_nused; j++)
+ if(dataset->shared->layout.storage.u.virt.list[i].sub_dset[j].dset) {
+ HDassert(dataset->shared->layout.storage.u.virt.list[i].sub_dset[j].dset != dataset);
+ if(H5D_close(dataset->shared->layout.storage.u.virt.list[i].sub_dset[j].dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
+ dataset->shared->layout.storage.u.virt.list[i].sub_dset[j].dset = NULL;
+ } /* end if */
+ } /* end for */
+ } /* end block */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert("not implemented yet" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout")
+#endif /* NDEBUG */
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+ /* Destroy any cached layout information for the dataset */
+ if(dataset->shared->layout.ops->dest && (dataset->shared->layout.ops->dest)(dataset, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+
+ /* Free the external file prefix */
+ dataset->shared->extfile_prefix = (char *)H5MM_xfree(dataset->shared->extfile_prefix);
+
+ /* Release layout, fill-value, efl & pipeline messages */
+ if(dataset->shared->dcpl_id != H5P_DATASET_CREATE_DEFAULT)
+ free_failed |= (H5O_msg_reset(H5O_PLINE_ID, &dataset->shared->dcpl_cache.pline) < 0) ||
+ (H5O_msg_reset(H5O_LAYOUT_ID, &dataset->shared->layout) < 0) ||
+ (H5O_msg_reset(H5O_FILL_ID, &dataset->shared->dcpl_cache.fill) < 0) ||
+ (H5O_msg_reset(H5O_EFL_ID, &dataset->shared->dcpl_cache.efl) < 0);
+
+ /* Uncork cache entries with object address tag */
+ if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__GET_CORKED, &corked) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status")
+ if(corked)
+ if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__UNCORK, NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNCORK, FAIL, "unable to uncork an object")
+
+ /*
+ * Release datatype, dataspace and creation property list -- there isn't
+ * much we can do if one of these fails, so we just continue.
+ */
+ free_failed |= (H5I_dec_ref(dataset->shared->type_id) < 0) ||
+ (H5S_close(dataset->shared->space) < 0) ||
+ (H5I_dec_ref(dataset->shared->dcpl_id) < 0);
+
+ /* Remove the dataset from the list of opened objects in the file */
+ if(H5FO_top_decr(dataset->oloc.file, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+ if(H5FO_delete(dataset->oloc.file, H5AC_ind_read_dxpl_id, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't remove dataset from list of open objects")
+
+ /* Close the dataset object */
+ /* (This closes the file, if this is the last object open) */
+ if(H5O_close(&(dataset->oloc), &file_closed) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release object header")
+
+ /* Evict dataset metadata if evicting on close */
+ if(!file_closed && H5F_SHARED(dataset->oloc.file) && H5F_EVICT_ON_CLOSE(dataset->oloc.file)) {
+ if(H5AC_flush_tagged_metadata(dataset->oloc.file, dataset->oloc.addr, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
+ if(H5AC_evict_tagged_metadata(dataset->oloc.file, dataset->oloc.addr, FALSE, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict tagged metadata")
+ } /* end if */
+
+ /*
+ * Free memory. Before freeing the memory set the file pointer to NULL.
+ * We always check for a null file pointer in other H5D functions to be
+ * sure we're not accessing an already freed dataset (see the HDassert()
+ * above).
+ */
+ dataset->oloc.file = NULL;
+ dataset->shared = H5FL_FREE(H5D_shared_t, dataset->shared);
+
+ } /* end if */
+ else {
+ /* Decrement the ref. count for this object in the top file */
+ if(H5FO_top_decr(dataset->oloc.file, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+
+ /* Check reference count for this object in the top file */
+ if(H5FO_top_count(dataset->oloc.file, dataset->oloc.addr) == 0) {
+ if(H5O_close(&(dataset->oloc), NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close")
+ } /* end if */
+ else
+ /* Free object location (i.e. "unhold" the file if appropriate) */
+ if(H5O_loc_free(&(dataset->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "problem attempting to free location")
+ } /* end else */
+
+ /* Release the dataset's path info */
+ if(H5G_name_free(&(dataset->path)) < 0)
+ free_failed = TRUE;
+
+ /* Free the dataset's memory structure */
+ dataset = H5FL_FREE(H5D_t, dataset);
+
+ /* Check if anything failed in the middle... */
+ if(free_failed)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't free a component of the dataset, but the dataset was freed anyway.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_mult_refresh_close
+ *
+ * Purpose: Closing down the needed information when the dataset has
+ * multiple opens. (From H5O_refresh_metadata_close())
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * 12/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_mult_refresh_close(hid_t dset_id, hid_t dxpl_id)
+{
+ H5D_t *dataset; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(NULL == (dataset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file && dataset->shared);
+ HDassert(dataset->shared->fo_count > 0);
+
+ if(dataset->shared->fo_count > 1) {
+ /* Free cached information for each kind of dataset */
+ switch(dataset->shared->layout.type) {
+ case H5D_CONTIGUOUS:
+ /* Free the data sieve buffer, if it's been allocated */
+ if(dataset->shared->cache.contig.sieve_buf)
+ dataset->shared->cache.contig.sieve_buf = (unsigned char *)H5FL_BLK_FREE(sieve_buf,dataset->shared->cache.contig.sieve_buf);
+ break;
+
+ case H5D_CHUNKED:
+ /* Check for skip list for iterating over chunks during I/O to close */
+ if(dataset->shared->cache.chunk.sel_chunks) {
+ HDassert(H5SL_count(dataset->shared->cache.chunk.sel_chunks) == 0);
+ H5SL_close(dataset->shared->cache.chunk.sel_chunks);
+ dataset->shared->cache.chunk.sel_chunks = NULL;
+ } /* end if */
+
+ /* Check for cached single chunk dataspace */
+ if(dataset->shared->cache.chunk.single_space) {
+ (void)H5S_close(dataset->shared->cache.chunk.single_space);
+ dataset->shared->cache.chunk.single_space = NULL;
+ } /* end if */
+
+ /* Check for cached single element chunk info */
+ if(dataset->shared->cache.chunk.single_chunk_info) {
+ dataset->shared->cache.chunk.single_chunk_info = H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info);
+ dataset->shared->cache.chunk.single_chunk_info = NULL;
+ } /* end if */
+ break;
+
+ case H5D_COMPACT:
+ case H5D_VIRTUAL:
+ /* Nothing special to do (info freed in the layout destroy) */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert("not implemented yet" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout")
+#endif /* NDEBUG */
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+ /* Destroy any cached layout information for the dataset */
+ if(dataset->shared->layout.ops->dest && (dataset->shared->layout.ops->dest)(dataset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_mult_refresh_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_mult_refresh_reopen
+ *
+ * Purpose: Re-initialize the needed info when the dataset has multiple
+ * opens. (From H5O_refresh_metadata_reopen())
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * 12/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_mult_refresh_reopen(H5D_t *dataset, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file && dataset->shared);
+ HDassert(dataset->shared->fo_count > 0);
+
+ if(dataset->shared->fo_count > 1) {
+ /* Release dataspace info */
+ if(H5S_close(dataset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+
+ /* Re-load dataspace info */
+ if(NULL == (dataset->shared->space = H5S_read(&(dataset->oloc), dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load dataspace info from dataset header")
+
+ /* Cache the dataset's dataspace info */
+ if(H5D__cache_dataspace_info(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't cache dataspace info")
+
+ /* Release layout info */
+ if(H5O_msg_reset(H5O_LAYOUT_ID, &dataset->shared->layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset layout info")
+
+ /* Re-load layout message info */
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_LAYOUT_ID, &(dataset->shared->layout), dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read data layout message")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D_mult_refresh_reopen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_oloc
+ *
+ * Purpose: Returns a pointer to the object location for a dataset.
+ *
+ * Return: Success: Ptr to location
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, April 24, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_loc_t *
+H5D_oloc(H5D_t *dataset)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(dataset ? &(dataset->oloc) : (H5O_loc_t *)NULL)
+} /* end H5D_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_nameof
+ *
+ * Purpose: Returns a pointer to the group hier. path for a dataset.
+ *
+ * Return: Success: Ptr to entry
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_name_t *
+H5D_nameof(H5D_t *dataset)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(dataset ? &(dataset->path) : (H5G_name_t *)NULL)
+} /* end H5D_nameof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_typeof
+ *
+ * Purpose: Returns a pointer to the dataset's datatype. The datatype
+ * is not copied.
+ *
+ * Return: Success: Ptr to the dataset's datatype, uncopied.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5D_typeof(const H5D_t *dset)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(dset);
+ HDassert(dset->shared);
+ HDassert(dset->shared->type);
+
+ FUNC_LEAVE_NOAPI(dset->shared->type)
+} /* end H5D_typeof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__alloc_storage
+ *
+ * Purpose: Allocate storage for the raw data of a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc,
+ hbool_t full_overwrite, hsize_t old_dim[])
+{
+ const H5D_t *dset = io_info->dset; /* The dataset object */
+ H5F_t *f = dset->oloc.file; /* The dataset's file pointer */
+ H5O_layout_t *layout; /* The dataset's layout information */
+ hbool_t must_init_space = FALSE; /* Flag to indicate that space should be initialized */
+ hbool_t addr_set = FALSE; /* Flag to indicate that the dataset's storage address was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(dset);
+ HDassert(f);
+
+ /* If the data is stored in external files, don't set an address for the layout
+ * We assume that external storage is already
+ * allocated by the caller, or at least will be before I/O is performed.
+ */
+ if(!(H5S_NULL == H5S_GET_EXTENT_TYPE(dset->shared->space) || dset->shared->dcpl_cache.efl.nused > 0)) {
+ /* Get a pointer to the dataset's layout information */
+ layout = &(dset->shared->layout);
+
+ switch(layout->type) {
+ case H5D_CONTIGUOUS:
+ if(!(*dset->shared->layout.ops->is_space_alloc)(&dset->shared->layout.storage)) {
+ /* Check if we have a zero-sized dataset */
+ if(layout->storage.u.contig.size > 0) {
+ /* Reserve space in the file for the entire array */
+ if(H5D__contig_alloc(f, io_info->md_dxpl_id, &layout->storage.u.contig/*out*/) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to initialize contiguous storage")
+
+ /* Indicate that we should initialize storage space */
+ must_init_space = TRUE;
+ } /* end if */
+ else
+ layout->storage.u.contig.addr = HADDR_UNDEF;
+
+ /* Indicate that we set the storage addr */
+ addr_set = TRUE;
+ } /* end if */
+ break;
+
+ case H5D_CHUNKED:
+ if(!(*dset->shared->layout.ops->is_space_alloc)(&dset->shared->layout.storage)) {
+ /* Create the root of the index that manages chunked storage */
+ if(H5D__chunk_create(dset /*in,out*/, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+
+ /* Indicate that we set the storage addr */
+ addr_set = TRUE;
+
+ /* Indicate that we should initialize storage space */
+ must_init_space = TRUE;
+ } /* end if */
+
+ /* If space allocation is set to 'early' and we are extending
+ * the dataset, indicate that space should be allocated, so the
+ * index gets expanded. -QAK
+ */
+ if(dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_EARLY
+ && time_alloc == H5D_ALLOC_EXTEND)
+ must_init_space = TRUE;
+ break;
+
+ case H5D_COMPACT:
+ /* Check if space is already allocated */
+ if(NULL == layout->storage.u.compact.buf) {
+ /* Reserve space in layout header message for the entire array.
+ * Starting from the 1.8.7 release, we allow dataspace to have
+ * zero dimension size. So the storage size can be zero.
+ * SLU 2011/4/4 */
+ if(layout->storage.u.compact.size > 0) {
+ if(NULL == (layout->storage.u.compact.buf = H5MM_malloc(layout->storage.u.compact.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for compact dataset")
+ if(!full_overwrite)
+ HDmemset(layout->storage.u.compact.buf, 0, layout->storage.u.compact.size);
+ layout->storage.u.compact.dirty = TRUE;
+
+ /* Indicate that we should initialize storage space */
+ must_init_space = TRUE;
+ } else {
+ layout->storage.u.compact.dirty = FALSE;
+ must_init_space = FALSE;
+ }
+ } /* end if */
+ break;
+
+ case H5D_VIRTUAL:
+ /* No-op, as the raw data is stored elsewhere and the global
+ * heap object containing the mapping information is created
+ * when the layout message is encoded. We may wish to move the
+ * creation of the global heap object here at some point, but we
+ * will have to make sure is it always created before the
+ * dataset is closed. */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert("not implemented yet" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout")
+#endif /* NDEBUG */
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+ /* Check if we need to initialize the space */
+ if(must_init_space) {
+ if(layout->type == H5D_CHUNKED) {
+ /* If we are doing incremental allocation and the index got
+ * created during a H5Dwrite call, don't initialize the storage
+ * now, wait for the actual writes to each block and let the
+ * low-level chunking routines handle initialize the fill-values.
+ * Otherwise, pass along the space initialization call and let
+ * the low-level chunking routines sort out whether to write
+ * fill values to the chunks they allocate space for. Yes,
+ * this is icky. -QAK
+ */
+ if(!(dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_INCR && time_alloc == H5D_ALLOC_WRITE))
+ if(H5D__init_storage(io_info, full_overwrite, old_dim) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize dataset with fill value")
+ } /* end if */
+ else {
+ H5D_fill_value_t fill_status; /* The fill value status */
+
+ /* Check the dataset's fill-value status */
+ if(H5P_is_fill_value_defined(&dset->shared->dcpl_cache.fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* If we are filling the dataset on allocation or "if set" and
+ * the fill value _is_ set, do that now */
+ if(dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC ||
+ (dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET && fill_status == H5D_FILL_VALUE_USER_DEFINED))
+ if(H5D__init_storage(io_info, full_overwrite, old_dim) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize dataset with fill value")
+ } /* end else */
+ } /* end if */
+
+ /* If we set the address (and aren't in the middle of creating the
+ * dataset), mark the layout header message for later writing to
+ * the file. (this improves forward compatibility).
+ */
+ /* (The layout message is already in the dataset's object header, this
+ * operation just sets the address and makes it constant)
+ */
+ if(time_alloc != H5D_ALLOC_CREATE && addr_set)
+ /* Mark the layout as dirty, for later writing to the file */
+ if(H5D__mark(dset, io_info->md_dxpl_id, H5D_MARK_LAYOUT) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__alloc_storage() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__init_storage
+ *
+ * Purpose: Initialize the data for a new dataset. If a selection is
+ * defined for SPACE then initialize only that part of the
+ * dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, October 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[])
+{
+ const H5D_t *dset = io_info->dset; /* dataset pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(dset);
+
+ switch (dset->shared->layout.type) {
+ case H5D_COMPACT:
+ /* If we will be immediately overwriting the values, don't bother to clear them */
+ if(!full_overwrite) {
+ /* Fill the compact dataset storage */
+ if(H5D__compact_fill(dset, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize compact dataset storage")
+ } /* end if */
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Don't write default fill values to external files */
+ /* If we will be immediately overwriting the values, don't bother to clear them */
+ if((dset->shared->dcpl_cache.efl.nused == 0 || dset->shared->dcpl_cache.fill.buf) && !full_overwrite)
+ if(H5D__contig_fill(io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to allocate all chunks of dataset")
+ break;
+
+ case H5D_CHUNKED:
+ /*
+ * Allocate file space
+ * for all chunks now and initialize each chunk with the fill value.
+ */
+ {
+ hsize_t zero_dim[H5O_LAYOUT_NDIMS] = {0};
+
+ /* Use zeros for old dimensions if not specified */
+ if(old_dim == NULL)
+ old_dim = zero_dim;
+
+ if(H5D__chunk_allocate(io_info, full_overwrite, old_dim) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to allocate all chunks of dataset")
+ break;
+ } /* end block */
+
+ case H5D_VIRTUAL:
+ /* No-op, as the raw data is stored elsewhere */
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert("not implemented yet" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout")
+#endif /* NDEBUG */
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__init_storage() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__get_storage_size
+ *
+ * Purpose: Determines how much space has been reserved to store the raw
+ * data of a dataset.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 21, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__get_storage_size(H5D_t *dset, hid_t dxpl_id, hsize_t *storage_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ switch(dset->shared->layout.type) {
+ case H5D_CHUNKED:
+ if((*dset->shared->layout.ops->is_space_alloc)(&dset->shared->layout.storage)) {
+ if(H5D__chunk_allocated(dset, dxpl_id, storage_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve chunked dataset allocated size")
+ } /* end if */
+ else
+ *storage_size = 0;
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Datasets which are not allocated yet are using no space on disk */
+ if((*dset->shared->layout.ops->is_space_alloc)(&dset->shared->layout.storage))
+ *storage_size = dset->shared->layout.storage.u.contig.size;
+ else
+ *storage_size = 0;
+ break;
+
+ case H5D_COMPACT:
+ *storage_size = dset->shared->layout.storage.u.compact.size;
+ break;
+
+ case H5D_VIRTUAL:
+ /* Just set to 0, as virtual datasets do not actually store raw data
+ */
+ *storage_size = 0;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset type")
+ } /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, 0)
+} /* end H5D__get_storage_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__get_offset
+ *
+ * Purpose: Private function for H5D__get_offset. Returns the address
+ * of dataset in file.
+ *
+ * Return: Success: the address of dataset
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Raymond Lu
+ * November 6, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5D__get_offset(const H5D_t *dset)
+{
+ haddr_t ret_value = HADDR_UNDEF;
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dset);
+
+ switch(dset->shared->layout.type) {
+ case H5D_VIRTUAL:
+ case H5D_CHUNKED:
+ case H5D_COMPACT:
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* If dataspace hasn't been allocated or dataset is stored in
+ * an external file, the value will be HADDR_UNDEF. */
+ if(dset->shared->dcpl_cache.efl.nused == 0 || H5F_addr_defined(dset->shared->layout.storage.u.contig.addr))
+ /* Return the absolute dataset offset from the beginning of file. */
+ ret_value = dset->shared->layout.storage.u.contig.addr + H5F_BASE_ADDR(dset->oloc.file);
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, HADDR_UNDEF, "unknown dataset layout type")
+ } /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__get_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_vlen_reclaim
+ *
+ * Purpose: Frees the buffers allocated for storing variable-length data
+ * in memory. Only frees the VL data in the selection defined in the
+ * dataspace. The dataset transfer property list is required to find the
+ * correct allocation/free methods for the VL data in the buffer.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 22, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_vlen_reclaim(hid_t type_id, H5S_t *space, hid_t plist_id, void *buf)
+{
+ H5T_t *type; /* Datatype */
+ H5S_sel_iter_op_t dset_op; /* Operator for iteration */
+ H5T_vlen_alloc_info_t _vl_alloc_info; /* VL allocation info buffer */
+ H5T_vlen_alloc_info_t *vl_alloc_info = &_vl_alloc_info; /* VL allocation info */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(H5I_DATATYPE == H5I_get_type(type_id));
+ HDassert(space);
+ HDassert(H5P_isa_class(plist_id, H5P_DATASET_XFER));
+ HDassert(buf);
+
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+
+ /* Get the allocation info */
+ if(H5T_vlen_get_alloc_info(plist_id,&vl_alloc_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve VL allocation info")
+
+ /* Call H5S_select_iterate with args, etc. */
+ dset_op.op_type = H5S_SEL_ITER_OP_APP;
+ dset_op.u.app_op.op = H5T_vlen_reclaim;
+ dset_op.u.app_op.type_id = type_id;
+
+ ret_value = H5S_select_iterate(buf, type, space, &dset_op, vl_alloc_info);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_vlen_reclaim() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__vlen_get_buf_size_alloc
+ *
+ * Purpose: This routine makes certain there is enough space in the temporary
+ * buffer for the new data to read in. All the VL data read in is actually
+ * placed in this buffer, overwriting the previous data. Needless to say,
+ * this data is not actually usable.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 17, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5D__vlen_get_buf_size_alloc(size_t size, void *info)
+{
+ H5D_vlen_bufsize_t *vlen_bufsize = (H5D_vlen_bufsize_t *)info;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Get a temporary pointer to space for the VL data */
+ if((vlen_bufsize->vl_tbuf = H5FL_BLK_REALLOC(vlen_vl_buf, vlen_bufsize->vl_tbuf, size)) != NULL)
+ vlen_bufsize->size += size;
+
+ /* Set return value */
+ ret_value = vlen_bufsize->vl_tbuf;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__vlen_get_buf_size_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__vlen_get_buf_size
+ *
+ * Purpose: This routine checks the number of bytes required to store a single
+ * element from a dataset in memory, creating a selection with just the
+ * single element selected to read in the element and using a custom memory
+ * allocator for any VL data encountered.
+ * The *size value is modified according to how many bytes are
+ * required to store the element in memory.
+ *
+ * Implementation: This routine actually performs the read with a custom
+ * memory manager which basically just counts the bytes requested and
+ * uses a temporary memory buffer (through the H5FL API) to make certain
+ * enough space is available to perform the read. Then the temporary
+ * buffer is released and the number of bytes allocated is returned.
+ * Kinda kludgy, but easier than the other method of trying to figure out
+ * the sizes without actually reading the data in... - QAK
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 17, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__vlen_get_buf_size(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned H5_ATTR_UNUSED ndim, const hsize_t *point, void *op_data)
+{
+ H5D_vlen_bufsize_t *vlen_bufsize = (H5D_vlen_bufsize_t *)op_data;
+ H5T_t *dt; /* Datatype for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(op_data);
+ HDassert(H5I_DATATYPE == H5I_get_type(type_id));
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object(type_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Make certain there is enough fixed-length buffer available */
+ if(NULL == (vlen_bufsize->fl_tbuf = H5FL_BLK_REALLOC(vlen_fl_buf, vlen_bufsize->fl_tbuf, H5T_get_size(dt))))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't resize tbuf")
+
+ /* Select point to read in */
+ if(H5S_select_elements(vlen_bufsize->fspace, H5S_SELECT_SET, (size_t)1, point) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't select point")
+
+ /* Read in the point (with the custom VL memory allocator) */
+ if(H5D__read(vlen_bufsize->dset, type_id, vlen_bufsize->mspace, vlen_bufsize->fspace, vlen_bufsize->xfer_pid, vlen_bufsize->fl_tbuf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read point")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__vlen_get_buf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__check_filters
+ *
+ * Purpose: Check if the filters have be initialized for the dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, October 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__check_filters(H5D_t *dataset)
+{
+ H5O_fill_t *fill; /* Dataset's fill value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dataset);
+
+ /* Check if the filters in the DCPL will need to encode, and if so, can they?
+ *
+ * Filters need encoding if fill value is defined and a fill policy is set
+ * that requires writing on an extend.
+ */
+ fill = &dataset->shared->dcpl_cache.fill;
+ if(!dataset->shared->checked_filters) {
+ H5D_fill_value_t fill_status; /* Whether the fill value is defined */
+
+ /* Retrieve the "defined" status of the fill value */
+ if(H5P_is_fill_value_defined(fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Couldn't retrieve fill value from dataset.")
+
+ /* See if we can check the filter status */
+ if(fill_status == H5D_FILL_VALUE_DEFAULT || fill_status == H5D_FILL_VALUE_USER_DEFINED) {
+ if(fill->fill_time == H5D_FILL_TIME_ALLOC ||
+ (fill->fill_time == H5D_FILL_TIME_IFSET && fill_status == H5D_FILL_VALUE_USER_DEFINED)) {
+ /* Filters must have encoding enabled. Ensure that all filters can be applied */
+ if(H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")
+
+ dataset->shared->checked_filters = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__check_filters() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__set_extent
+ *
+ * Purpose: Based on H5D_extend, allows change to a lower dimension,
+ * calls H5S_set_extent and H5D__chunk_prune_by_extent instead
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * April 9, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__set_extent(H5D_t *dset, const hsize_t *size, hid_t dxpl_id)
+{
+ hsize_t curr_dims[H5S_MAX_RANK]; /* Current dimension sizes */
+ htri_t changed; /* Whether the dataspace changed size */
+ size_t u, v; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ /* Check args */
+ HDassert(dset);
+ HDassert(size);
+
+ /* Check if we are allowed to modify this file */
+ if(0 == (H5F_INTENT(dset->oloc.file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Check if we are allowed to modify the space; only datasets with chunked and external storage are allowed to be modified */
+ if(H5D_COMPACT == dset->shared->layout.type)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "dataset has compact storage")
+ if(H5D_CONTIGUOUS == dset->shared->layout.type && 0 == dset->shared->dcpl_cache.efl.nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "dataset has contiguous storage")
+
+ /* Check if the filters in the DCPL will need to encode, and if so, can they? */
+ if(H5D__check_filters(dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't apply filters")
+
+ /* Keep the current dataspace dimensions for later */
+ HDcompile_assert(sizeof(curr_dims) == sizeof(dset->shared->curr_dims));
+ HDmemcpy(curr_dims, dset->shared->curr_dims, H5S_MAX_RANK * sizeof(curr_dims[0]));
+
+ /* Modify the size of the dataspace */
+ if((changed = H5S_set_extent(dset->shared->space, size)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of dataspace")
+
+ /* Don't bother updating things, unless they've changed */
+ if(changed) {
+ hbool_t shrink = FALSE; /* Flag to indicate a dimension has shrank */
+ hbool_t expand = FALSE; /* Flag to indicate a dimension has grown */
+ hbool_t update_chunks = FALSE; /* Flag to indicate chunk cache update is needed */
+
+ /* Determine if we are shrinking and/or expanding any dimensions */
+ for(u = 0; u < (size_t)dset->shared->ndims; u++) {
+ /* Check for various status changes */
+ if(size[u] < curr_dims[u])
+ shrink = TRUE;
+ if(size[u] > curr_dims[u])
+ expand = TRUE;
+
+ /* Chunked storage specific checks */
+ if(H5D_CHUNKED == dset->shared->layout.type && dset->shared->ndims > 1) {
+ hsize_t scaled; /* Scaled value */
+
+ /* Compute the scaled dimension size value */
+ scaled = size[u] / dset->shared->layout.u.chunk.dim[u];
+
+ /* Check if scaled dimension size changed */
+ if(scaled != dset->shared->cache.chunk.scaled_dims[u]) {
+ hsize_t scaled_power2up; /* Scaled value, rounded to next power of 2 */
+
+ /* Update the scaled dimension size value for the current dimension */
+ dset->shared->cache.chunk.scaled_dims[u] = scaled;
+
+ /* Check if algorithm for computing hash values will change */
+ if((scaled > dset->shared->cache.chunk.nslots &&
+ dset->shared->cache.chunk.scaled_dims[u] <= dset->shared->cache.chunk.nslots)
+ || (scaled <= dset->shared->cache.chunk.nslots &&
+ dset->shared->cache.chunk.scaled_dims[u] > dset->shared->cache.chunk.nslots))
+ update_chunks = TRUE;
+
+ /* Check if the number of bits required to encode the scaled size value changed */
+ if(dset->shared->cache.chunk.scaled_power2up[u] != (scaled_power2up = H5VM_power2up(scaled))) {
+ /* Update the 'power2up' & 'encode_bits' values for the current dimension */
+ dset->shared->cache.chunk.scaled_power2up[u] = scaled_power2up;
+ dset->shared->cache.chunk.scaled_encode_bits[u] = H5VM_log2_gen(scaled_power2up);
+
+ /* Indicate that the cached chunk indices need to be updated */
+ update_chunks = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Update the cached copy of the dataset's dimensions */
+ dset->shared->curr_dims[u] = size[u];
+ } /* end for */
+
+ /*-------------------------------------------------------------------------
+ * Modify the dataset storage
+ *-------------------------------------------------------------------------
+ */
+ /* Update the index values for the cached chunks for this dataset */
+ if(H5D_CHUNKED == dset->shared->layout.type) {
+ /* Set the cached chunk info */
+ if(H5D__chunk_set_info(dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to update # of chunks")
+
+ /* Check if updating the chunk cache indices is necessary */
+ if(update_chunks)
+ /* Update the chunk cache indices */
+ if(H5D__chunk_update_cache(dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to update cached chunk indices")
+ } /* end if */
+
+ /* Operations for virtual datasets */
+ if(H5D_VIRTUAL == dset->shared->layout.type) {
+ /* Check that the dimensions of the VDS are large enough */
+ if(H5D_virtual_check_min_dims(dset) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual dataset dimensions not large enough to contain all limited dimensions in all selections")
+
+ /* Patch the virtual selection dataspaces */
+ for(u = 0; u < dset->shared->layout.storage.u.virt.list_nused; u++) {
+ /* Patch extent */
+ if(H5S_set_extent(dset->shared->layout.storage.u.virt.list[u].source_dset.virtual_select, size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ dset->shared->layout.storage.u.virt.list[u].virtual_space_status = H5O_VIRTUAL_STATUS_CORRECT;
+
+ /* Patch sub-source datasets */
+ for(v = 0; v < dset->shared->layout.storage.u.virt.list[u].sub_dset_nalloc; v++)
+ if(H5S_set_extent(dset->shared->layout.storage.u.virt.list[u].sub_dset[v].virtual_select, size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ } /* end for */
+
+ /* Mark virtual datasets as not fully initialized so internal
+ * selections are recalculated (at next I/O operation) */
+ dset->shared->layout.storage.u.virt.init = FALSE;
+ } /* end if */
+
+ /* Allocate space for the new parts of the dataset, if appropriate */
+ if(expand && dset->shared->dcpl_cache.fill.alloc_time == H5D_ALLOC_TIME_EARLY) {
+ H5D_io_info_t io_info;
+
+ io_info.dset = dset;
+ io_info.raw_dxpl_id = H5AC_rawdata_dxpl_id;
+ io_info.md_dxpl_id = dxpl_id;
+
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_EXTEND, FALSE, curr_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to extend dataset storage")
+ }
+ /*-------------------------------------------------------------------------
+ * Remove chunk information in the case of chunked datasets
+ * This removal takes place only in case we are shrinking the dateset
+ * and if the chunks are written
+ *-------------------------------------------------------------------------
+ */
+ if(H5D_CHUNKED == dset->shared->layout.type) {
+ if(shrink && (*dset->shared->layout.ops->is_space_alloc)(&dset->shared->layout.storage))
+ /* Remove excess chunks */
+ if(H5D__chunk_prune_by_extent(dset, dxpl_id, curr_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to remove chunks")
+
+ /* Update chunks that are no longer edge chunks as a result of
+ * expansion */
+ if(expand && (dset->shared->layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS)
+ && (dset->shared->dcpl_cache.pline.nused > 0))
+ if(H5D__chunk_update_old_edge_chunks(dset, dxpl_id, curr_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to do update old edge chunks")
+ } /* end if */
+
+ /* Mark the dataspace as dirty, for later writing to the file */
+ if(H5D__mark(dset, dxpl_id, H5D_MARK_SPACE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__set_extent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__flush_sieve_buf
+ *
+ * Purpose: Flush any dataset sieve buffer info cached in memory
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__flush_sieve_buf(H5D_t *dataset, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dataset);
+
+ /* Flush the raw data buffer, if we have a dirty one */
+ if(dataset->shared->cache.contig.sieve_buf && dataset->shared->cache.contig.sieve_dirty) {
+ HDassert(dataset->shared->layout.type != H5D_COMPACT); /* We should never have a sieve buffer for compact storage */
+
+ /* Write dirty data sieve buffer to file */
+ if(H5F_block_write(dataset->oloc.file, H5FD_MEM_DRAW, dataset->shared->cache.contig.sieve_loc,
+ dataset->shared->cache.contig.sieve_size, dxpl_id, dataset->shared->cache.contig.sieve_buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed")
+
+ /* Reset sieve buffer dirty flag */
+ dataset->shared->cache.contig.sieve_dirty = FALSE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__flush_sieve_buf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__flush_real
+ *
+ * Purpose: Flush any dataset information cached in memory
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * December 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__flush_real(H5D_t *dataset, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL)
+
+ /* Check args */
+ HDassert(dataset);
+ HDassert(dataset->shared);
+
+ /* Avoid flushing the dataset (again) if it's closing */
+ if(!dataset->shared->closing) {
+ /* Flush cached raw data for each kind of dataset layout */
+ if(dataset->shared->layout.ops->flush &&
+ (dataset->shared->layout.ops->flush)(dataset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush raw data")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__flush_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__format_convert
+ *
+ * Purpose: For chunked: downgrade the chunk indexing type to version 1 B-tree
+ * For compact/contiguous: downgrade layout version to 3
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__format_convert(H5D_t *dataset, hid_t dxpl_id)
+{
+ H5D_chk_idx_info_t new_idx_info; /* Index info for the new layout */
+ H5D_chk_idx_info_t idx_info; /* Index info for the current layout */
+ H5O_layout_t newlayout; /* The new layout */
+ hbool_t init_new_index = FALSE; /* Indicate that the new chunk index is initialized */
+ hbool_t delete_old_layout = FALSE; /* Indicate that the old layout message is deleted */
+ hbool_t add_new_layout = FALSE; /* Indicate that the new layout message is added */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL)
+
+ /* Check args */
+ HDassert(dataset);
+
+ switch(dataset->shared->layout.type) {
+ case H5D_CHUNKED:
+ HDassert(dataset->shared->layout.u.chunk.idx_type != H5D_CHUNK_IDX_BTREE);
+
+ /* Set up the current index info */
+ idx_info.f = dataset->oloc.file;
+ idx_info.dxpl_id = dxpl_id;
+ idx_info.pline = &dataset->shared->dcpl_cache.pline;
+ idx_info.layout = &dataset->shared->layout.u.chunk;
+ idx_info.storage = &dataset->shared->layout.storage.u.chunk;
+
+ /* Copy the current layout info to the new layout */
+ HDmemcpy(&newlayout, &dataset->shared->layout, sizeof(H5O_layout_t));
+
+ /* Set up info for version 1 B-tree in the new layout */
+ newlayout.version = H5O_LAYOUT_VERSION_3;
+ newlayout.storage.u.chunk.idx_type = H5D_CHUNK_IDX_BTREE;
+ newlayout.storage.u.chunk.idx_addr = HADDR_UNDEF;
+ newlayout.storage.u.chunk.ops = H5D_COPS_BTREE;
+ newlayout.storage.u.chunk.u.btree.shared = NULL;
+
+ /* Set up the index info to version 1 B-tree */
+ new_idx_info.f = dataset->oloc.file;
+ new_idx_info.dxpl_id = dxpl_id;
+ new_idx_info.pline = &dataset->shared->dcpl_cache.pline;
+ new_idx_info.layout = &newlayout.u.chunk;
+ new_idx_info.storage = &newlayout.storage.u.chunk;
+
+ /* Initialize version 1 B-tree */
+ if(new_idx_info.storage->ops->init &&
+ (new_idx_info.storage->ops->init)(&new_idx_info, dataset->shared->space, dataset->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize indexing information")
+ init_new_index = TRUE;
+
+ /* If the current chunk index exists */
+ if(H5F_addr_defined(idx_info.storage->idx_addr)) {
+
+ /* Create v1 B-tree chunk index */
+ if((new_idx_info.storage->ops->create)(&new_idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create chunk index")
+
+ /* Iterate over the chunks in the current index and insert the chunk addresses
+ * into the version 1 B-tree chunk index */
+ if(H5D__chunk_format_convert(dataset, &idx_info, &new_idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to iterate/convert chunk index")
+ } /* end if */
+
+ /* Delete the old "current" layout message */
+ if(H5O_msg_remove(&dataset->oloc, H5O_LAYOUT_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete layout message")
+
+ delete_old_layout = TRUE;
+
+ /* Append the new layout message to the object header */
+ if(H5O_msg_create(&dataset->oloc, H5O_LAYOUT_ID, 0, H5O_UPDATE_TIME, &newlayout, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update layout header message")
+
+ add_new_layout = TRUE;
+
+ /* Release the old (current) chunk index */
+ if(idx_info.storage->ops->dest && (idx_info.storage->ops->dest)(&idx_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
+
+ /* Copy the new layout to the dataset's layout */
+ HDmemcpy(&dataset->shared->layout, &newlayout, sizeof(H5O_layout_t));
+
+ break;
+
+ case H5D_CONTIGUOUS:
+ case H5D_COMPACT:
+ HDassert(dataset->shared->layout.version > H5O_LAYOUT_VERSION_DEFAULT);
+ dataset->shared->layout.version = H5O_LAYOUT_VERSION_DEFAULT;
+ if(H5O_msg_write(&(dataset->oloc), H5O_LAYOUT_ID, 0, H5O_UPDATE_TIME, &(dataset->shared->layout), dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update layout message")
+ break;
+
+ case H5D_VIRTUAL:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "virtual dataset layout not supported")
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset layout type")
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown dataset layout type")
+ } /* end switch */
+
+done:
+ if(ret_value < 0 && dataset->shared->layout.type == H5D_CHUNKED) {
+ /* Remove new layout message */
+ if(add_new_layout)
+ if(H5O_msg_remove(&dataset->oloc, H5O_LAYOUT_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete layout message")
+
+ /* Add back old layout message */
+ if(delete_old_layout)
+ if(H5O_msg_create(&dataset->oloc, H5O_LAYOUT_ID, 0, H5O_UPDATE_TIME, &dataset->shared->layout, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to add layout header message")
+
+ /* Clean up v1 b-tree chunk index */
+ if(init_new_index) {
+ if(H5F_addr_defined(new_idx_info.storage->idx_addr)) {
+ /* Check for valid address i.e. tag */
+ if(!H5F_addr_defined(dataset->oloc.addr))
+ HDONE_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "address undefined")
+
+ /* Expunge from cache all v1 B-tree type entries associated with tag */
+ if(H5AC_expunge_tag_type_metadata(dataset->oloc.file, dxpl_id, dataset->oloc.addr, H5AC_BT_ID, H5AC__NO_FLAGS_SET))
+ HDONE_ERROR(H5E_DATASET, H5E_CANTEXPUNGE, FAIL, "unable to expunge index metadata")
+ } /* end if */
+
+ /* Delete v1 B-tree chunk index */
+ if(new_idx_info.storage->ops->dest && (new_idx_info.storage->ops->dest)(&new_idx_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to release chunk index info")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__format_convert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mark
+ *
+ * Purpose: Mark some aspect of a dataset as dirty
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * July 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__mark(const H5D_t *dataset, hid_t H5_ATTR_UNUSED dxpl_id, unsigned flags)
+{
+ H5O_t *oh = NULL; /* Pointer to dataset's object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(dataset);
+ HDassert(!(flags & (unsigned)~(H5D_MARK_SPACE | H5D_MARK_LAYOUT)));
+
+ /* Mark aspects of the dataset as dirty */
+ if(flags) {
+ unsigned update_flags = H5O_UPDATE_TIME; /* Modification time flag */
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(&dataset->oloc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header")
+
+ /* Update the layout on disk, if it's been changed */
+ if(flags & H5D_MARK_LAYOUT) {
+ if(H5D__layout_oh_write(dataset, dxpl_id, oh, update_flags) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to update layout info")
+
+ /* Reset the "update the modification time" flag, so we only do it once */
+ update_flags = 0;
+ } /* end if */
+
+ /* Update the dataspace on disk, if it's been changed */
+ if(flags & H5D_MARK_SPACE) {
+ if(H5S_write(dataset->oloc.file, dxpl_id, oh, update_flags, dataset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to update file with new dataspace")
+
+ /* Reset the "update the modification time" flag, so we only do it once */
+ update_flags = 0;
+ } /* end if */
+
+ /* _Somebody_ should have update the modification time! */
+ HDassert(update_flags == 0);
+ } /* end if */
+
+done:
+ /* Release pointer to object header */
+ if(oh != NULL)
+ if(H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTUNPIN, FAIL, "unable to unpin dataset object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__mark() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__flush_cb
+ *
+ * Purpose: Flush any dataset information cached in memory
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__flush_cb(void *_dataset, hid_t H5_ATTR_UNUSED id, void *_udata)
+{
+ H5D_t *dataset = (H5D_t *)_dataset; /* Dataset pointer */
+ H5D_flush_ud_t *udata = (H5D_flush_ud_t *)_udata; /* User data for callback */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(dataset);
+
+ /* Check for dataset in same file */
+ if(udata->f == dataset->oloc.file) {
+ /* Flush the dataset's information */
+ if(H5D__flush_real(dataset, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, H5_ITER_ERROR, "unable to flush cached dataset info")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__flush_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_flush
+ *
+ * Purpose: Flush any dataset information cached in memory
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Ray Lu
+ * August 14, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_flush(const H5F_t *f, hid_t dxpl_id)
+{
+ H5D_flush_ud_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+
+ /* Set user data for callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+
+ /* Iterate over all the open datasets */
+ if(H5I_iterate(H5I_DATASET, H5D__flush_cb, &udata, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to flush cached dataset info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_get_create_plist
+ *
+ * Purpose: Private function for H5Dget_create_plist
+ *
+ * Return: Success: ID for a copy of the dataset creation
+ * property list. The template should be
+ * released by calling H5P_close().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, February 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5D_get_create_plist(H5D_t *dset)
+{
+ H5P_genplist_t *dcpl_plist; /* Dataset's DCPL */
+ H5P_genplist_t *new_plist; /* Copy of dataset's DCPL */
+ H5O_layout_t copied_layout; /* Layout to tweak */
+ H5O_fill_t copied_fill; /* Fill value to tweak */
+ H5O_efl_t copied_efl; /* External file list to tweak */
+ hid_t new_dcpl_id = FAIL;
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(NULL == (dcpl_plist = (H5P_genplist_t *)H5I_object(dset->shared->dcpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Copy the creation property list */
+ if((new_dcpl_id = H5P_copy_plist(dcpl_plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to copy the creation property list")
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(new_dcpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Retrieve any object creation properties */
+ if(H5O_get_create_plist(&dset->oloc, H5AC_ind_read_dxpl_id, new_plist) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get object creation info")
+
+ /* Get the layout property */
+ if(H5P_peek(new_plist, H5D_CRT_LAYOUT_NAME, &copied_layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get layout")
+
+ /* Reset layout values set when dataset is created */
+ copied_layout.ops = NULL;
+ switch(copied_layout.type) {
+ case H5D_COMPACT:
+ copied_layout.storage.u.compact.buf = H5MM_xfree(copied_layout.storage.u.compact.buf);
+ HDmemset(&copied_layout.storage.u.compact, 0, sizeof(copied_layout.storage.u.compact));
+ break;
+
+ case H5D_CONTIGUOUS:
+ copied_layout.storage.u.contig.addr = HADDR_UNDEF;
+ copied_layout.storage.u.contig.size = 0;
+ break;
+
+ case H5D_CHUNKED:
+ /* Reset chunk size */
+ copied_layout.u.chunk.size = 0;
+
+ /* Reset index info, if the chunk ops are set */
+ if(copied_layout.storage.u.chunk.ops)
+ /* Reset address and pointer of the array struct for the chunked storage index */
+ if(H5D_chunk_idx_reset(&copied_layout.storage.u.chunk, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to reset chunked storage index in dest")
+
+ /* Reset chunk index ops */
+ copied_layout.storage.u.chunk.ops = NULL;
+ break;
+
+ case H5D_VIRTUAL:
+ copied_layout.storage.u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
+ copied_layout.storage.u.virt.serial_list_hobjid.idx = 0;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert(0 && "Unknown layout type!");
+ } /* end switch */
+
+ /* Set back the (possibly modified) layout property to property list */
+ if(H5P_poke(new_plist, H5D_CRT_LAYOUT_NAME, &copied_layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set layout")
+
+ /* Get the fill value property */
+ if(H5P_peek(new_plist, H5D_CRT_FILL_VALUE_NAME, &copied_fill) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Check if there is a fill value, but no type yet */
+ if(copied_fill.buf != NULL && copied_fill.type == NULL) {
+ H5T_path_t *tpath; /* Conversion information*/
+
+ /* Copy the dataset type into the fill value message */
+ if(NULL == (copied_fill.type = H5T_copy(dset->shared->type, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy dataset datatype for fill value")
+
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(dset->shared->type, copied_fill.type, NULL, NULL, H5AC_noio_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types")
+
+ /* Convert disk form of fill value into memory form */
+ if(!H5T_path_noop(tpath)) {
+ hid_t dst_id, src_id; /* Source & destination datatypes for type conversion */
+ uint8_t *bkg_buf = NULL; /* Background conversion buffer */
+ size_t bkg_size; /* Size of background buffer */
+
+ /* Wrap copies of types to convert */
+ dst_id = H5I_register(H5I_DATATYPE, H5T_copy(copied_fill.type, H5T_COPY_TRANSIENT), FALSE);
+ if(dst_id < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy/register datatype")
+ src_id = H5I_register(H5I_DATATYPE, H5T_copy(dset->shared->type, H5T_COPY_ALL), FALSE);
+ if(src_id < 0) {
+ H5I_dec_ref(dst_id);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy/register datatype")
+ } /* end if */
+
+ /* Allocate a background buffer */
+ bkg_size = MAX(H5T_GET_SIZE(copied_fill.type), H5T_GET_SIZE(dset->shared->type));
+ if(H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size))) {
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ } /* end if */
+
+ /* Convert fill value */
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, copied_fill.buf, bkg_buf, H5AC_noio_dxpl_id) < 0) {
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
+ } /* end if */
+
+ /* Release local resources */
+ if(H5I_dec_ref(src_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(H5I_dec_ref(dst_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to close temporary object")
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ } /* end if */
+ } /* end if */
+
+ /* Set back the (possibly modified) fill value property to property list */
+ if(H5P_poke(new_plist, H5D_CRT_FILL_VALUE_NAME, &copied_fill) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set fill value")
+
+ /* Get the fill value property */
+ if(H5P_peek(new_plist, H5D_CRT_EXT_FILE_LIST_NAME, &copied_efl) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get external file list")
+
+ /* Reset efl name_offset and heap_addr, these are the values when the dataset is created */
+ if(copied_efl.slot) {
+ unsigned u;
+
+ copied_efl.heap_addr = HADDR_UNDEF;
+ for(u = 0; u < copied_efl.nused; u++)
+ copied_efl.slot[u].name_offset = 0;
+ } /* end if */
+
+ /* Set back the (possibly modified) external file list property to property list */
+ if(H5P_poke(new_plist, H5D_CRT_EXT_FILE_LIST_NAME, &copied_efl) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to set external file list")
+
+ /* Set the return value */
+ ret_value = new_dcpl_id;
+
+done:
+ if(ret_value < 0)
+ if(new_dcpl_id > 0)
+ if(H5I_dec_app_ref(new_dcpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to close temporary object")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_get_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_get_access_plist
+ *
+ * Purpose: Returns a copy of the dataset access property list.
+ *
+ * Return: Success: ID for a copy of the dataset access
+ * property list.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Mohamad Chaarawi
+ * March, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5D_get_access_plist(H5D_t *dset)
+{
+ H5P_genplist_t *old_plist; /* Default DAPL */
+ H5P_genplist_t *new_plist; /* New DAPL */
+ hid_t new_dapl_id = FAIL;
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Make a copy of the default dataset access property list */
+ if(NULL == (old_plist = (H5P_genplist_t *)H5I_object(H5P_LST_DATASET_ACCESS_ID_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if((new_dapl_id = H5P_copy_plist(old_plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, "can't copy dataset access property list")
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(new_dapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* If the dataset is chunked then copy the rdcc & append flush parameters */
+ if(dset->shared->layout.type == H5D_CHUNKED) {
+ if(H5P_set(new_plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(dset->shared->cache.chunk.nslots)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache number of slots")
+ if(H5P_set(new_plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(dset->shared->cache.chunk.nbytes_max)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache byte size")
+ if(H5P_set(new_plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &(dset->shared->cache.chunk.w0)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set preempt read chunks")
+ if(H5P_set(new_plist, H5D_ACS_APPEND_FLUSH_NAME, &dset->shared->append_flush) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set append flush property")
+ } /* end if */
+
+ /* Set the VDS view & printf gap options */
+ if(H5P_set(new_plist, H5D_ACS_VDS_VIEW_NAME, &(dset->shared->layout.storage.u.virt.view)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set VDS view")
+ if(H5P_set(new_plist, H5D_ACS_VDS_PRINTF_GAP_NAME, &(dset->shared->layout.storage.u.virt.printf_gap)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set VDS printf gap")
+
+ /* Set the external file prefix option */
+ if(H5P_set(new_plist, H5D_ACS_EFILE_PREFIX_NAME, &(dset->shared->extfile_prefix)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set external file prefix")
+
+ /* Set the return value */
+ ret_value = new_dapl_id;
+
+done:
+ if(ret_value < 0) {
+ if(new_dapl_id > 0)
+ if(H5I_dec_app_ref(new_dapl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "can't free")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_get_access_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_get_space
+ *
+ * Purpose: Returns and ID for the dataspace of the dataset.
+ *
+ * Return: Success: ID for dataspace
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Mohamad Chaarawi
+ * March, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5D_get_space(H5D_t *dset)
+{
+ H5S_t *space = NULL;
+ hid_t ret_value = H5I_INVALID_HID;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* If the layout is virtual, update the extent */
+ if(dset->shared->layout.type == H5D_VIRTUAL)
+ if(H5D__virtual_set_extent_unlim(dset, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update virtual dataset extent")
+
+ /* Read the data space message and return a data space object */
+ if(NULL == (space = H5S_copy(dset->shared->space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get data space")
+
+ /* Create an atom */
+ if((ret_value = H5I_register(H5I_DATASPACE, space, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace")
+
+done:
+ if(ret_value < 0)
+ if(space != NULL)
+ if(H5S_close(space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_get_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_get_type
+ *
+ * Purpose: Returns and ID for the datatype of the dataset.
+ *
+ * Return: Success: ID for datatype
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Mohamad Chaarawi
+ * March, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5D_get_type(H5D_t *dset)
+{
+ H5T_t *dt = NULL;
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Patch the datatype's "top level" file pointer */
+ if(H5T_patch_file(dset->shared->type, dset->oloc.file) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to patch datatype's file pointer")
+
+ /* Copy the dataset's datatype */
+ if(NULL == (dt = H5T_copy(dset->shared->type, H5T_COPY_REOPEN)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy datatype")
+
+ /* Mark any datatypes as being in memory now */
+ if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid datatype location")
+
+ /* Lock copied type */
+ if(H5T_lock(dt, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to lock transient datatype")
+
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ if(ret_value < 0) {
+ if(dt && H5T_close(dt) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_get_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__refresh
+ *
+ * Purpose: Refreshes all buffers associated with a dataset.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * November 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__refresh(hid_t dset_id, H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_virtual_held_file_t *head = NULL; /* Pointer to list of files held open */
+ hbool_t virt_dsets_held = FALSE; /* Whether virtual datasets' files are held open */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(dset);
+ HDassert(dset->shared);
+
+ /* If the layout is virtual... */
+ if(dset->shared->layout.type == H5D_VIRTUAL) {
+ /* Hold open the source datasets' files */
+ if(H5D__virtual_hold_source_dset_files(dset, &head) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, FAIL, "unable to hold VDS source files open")
+ virt_dsets_held = TRUE;
+
+ /* Refresh source datasets for virtual dataset */
+ if(H5D__virtual_refresh_source_dsets(dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh VDS source datasets")
+ } /* end if */
+
+ /* Refresh dataset object */
+ if((H5O_refresh_metadata(dset_id, dset->oloc, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh dataset")
+
+done:
+ /* Release hold on virtual datasets' files */
+ if(virt_dsets_held) {
+ /* Release the hold on source datasets' files */
+ if(H5D__virtual_release_source_dset_files(head) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't release VDS source files held open")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__refresh() */
+
diff --git a/src/H5Dio.c b/src/H5Dio.c
new file mode 100644
index 0000000..dfd3f17
--- /dev/null
+++ b/src/H5Dio.c
@@ -0,0 +1,1313 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Sprivate.h" /* Dataspace */
+
+#ifdef H5_HAVE_PARALLEL
+/* Remove this if H5R_DATASET_REGION is no longer used in this file */
+#include "H5Rpublic.h"
+#endif /*H5_HAVE_PARALLEL*/
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Internal I/O routines */
+static herr_t H5D__pre_write(H5D_t *dset, hbool_t direct_write, hid_t mem_type_id,
+ const H5S_t *mem_space, const H5S_t *file_space, hid_t dxpl_id, const void *buf);
+
+/* Setup/teardown routines */
+static herr_t H5D__ioinfo_init(H5D_t *dset,
+#ifndef H5_HAVE_PARALLEL
+const
+#endif /* H5_HAVE_PARALLEL */
+ H5D_dxpl_cache_t *dxpl_cache,
+ hid_t dxpl_id, const H5D_type_info_t *type_info, H5D_storage_t *store,
+ H5D_io_info_t *io_info);
+static herr_t H5D__typeinfo_init(const H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache,
+ hid_t dxpl_id, hid_t mem_type_id, hbool_t do_write,
+ H5D_type_info_t *type_info);
+#ifdef H5_HAVE_PARALLEL
+static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset,
+ hid_t dxpl_id, const H5S_t *file_space, const H5S_t *mem_space,
+ const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm);
+static herr_t H5D__ioinfo_term(H5D_io_info_t *io_info);
+#endif /* H5_HAVE_PARALLEL */
+static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage blocks of type conversion data */
+H5FL_BLK_DEFINE(type_conv);
+
+/* Declare a free list to manage the H5D_chunk_map_t struct */
+H5FL_DEFINE(H5D_chunk_map_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dread
+ *
+ * Purpose: Reads (part of) a DSET from the file into application
+ * memory BUF. The part of the dataset to read is defined with
+ * MEM_SPACE_ID and FILE_SPACE_ID. The data points are
+ * converted from their file type to the MEM_TYPE_ID specified.
+ * Additional miscellaneous data transfer properties can be
+ * passed to this function with the PLIST_ID argument.
+ *
+ * The FILE_SPACE_ID can be the constant H5S_ALL which indicates
+ * that the entire file data space is to be referenced.
+ *
+ * The MEM_SPACE_ID can be the constant H5S_ALL in which case
+ * the memory data space is the same as the file data space
+ * defined when the dataset was created.
+ *
+ * The number of elements in the memory data space must match
+ * the number of elements in the file data space.
+ *
+ * The PLIST_ID can be the constant H5P_DEFAULT in which
+ * case the default data transfer properties are used.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
+ hid_t file_space_id, hid_t plist_id, void *buf/*out*/)
+{
+ H5D_t *dset = NULL;
+ const H5S_t *mem_space = NULL;
+ const H5S_t *file_space = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iiiiix", dset_id, mem_type_id, mem_space_id, file_space_id,
+ plist_id, buf);
+
+ /* check arguments */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(NULL == dset->oloc.file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(mem_space_id < 0 || file_space_id < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ if(H5S_ALL != mem_space_id) {
+ if(NULL == (mem_space = (const H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Check for valid selection */
+ if(H5S_SELECT_VALID(mem_space) != TRUE)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent")
+ } /* end if */
+ if(H5S_ALL != file_space_id) {
+ if(NULL == (file_space = (const H5S_t *)H5I_object_verify(file_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Check for valid selection */
+ if(H5S_SELECT_VALID(file_space) != TRUE)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent")
+ } /* end if */
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if (H5P_DEFAULT == plist_id)
+ plist_id= H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms")
+
+ /* read raw data */
+ if(H5D__read(dset, mem_type_id, mem_space, file_space, plist_id, buf/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dread() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dwrite
+ *
+ * Purpose: Writes (part of) a DSET from application memory BUF to the
+ * file. The part of the dataset to write is defined with the
+ * MEM_SPACE_ID and FILE_SPACE_ID arguments. The data points
+ * are converted from their current type (MEM_TYPE_ID) to their
+ * file datatype. Additional miscellaneous data transfer
+ * properties can be passed to this function with the
+ * PLIST_ID argument.
+ *
+ * The FILE_SPACE_ID can be the constant H5S_ALL which indicates
+ * that the entire file data space is to be referenced.
+ *
+ * The MEM_SPACE_ID can be the constant H5S_ALL in which case
+ * the memory data space is the same as the file data space
+ * defined when the dataset was created.
+ *
+ * The number of elements in the memory data space must match
+ * the number of elements in the file data space.
+ *
+ * The PLIST_ID can be the constant H5P_DEFAULT in which
+ * case the default data transfer properties are used.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
+ hid_t file_space_id, hid_t dxpl_id, const void *buf)
+{
+ H5D_t *dset = NULL;
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5S_t *mem_space = NULL;
+ const H5S_t *file_space = NULL;
+ hbool_t direct_write = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iiiii*x", dset_id, mem_type_id, mem_space_id, file_space_id,
+ dxpl_id, buf);
+
+ /* check arguments */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(NULL == dset->oloc.file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id= H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms")
+
+ /* Get the dataset transfer property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Retrieve the 'direct write' flag */
+ if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_NAME, &direct_write) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting flag for direct chunk write")
+
+ /* Check dataspace selections if this is not a direct write */
+ if(!direct_write) {
+ if(mem_space_id < 0 || file_space_id < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ if(H5S_ALL != mem_space_id) {
+ if(NULL == (mem_space = (const H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Check for valid selection */
+ if(H5S_SELECT_VALID(mem_space) != TRUE)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "memory selection+offset not within extent")
+ } /* end if */
+ if(H5S_ALL != file_space_id) {
+ if(NULL == (file_space = (const H5S_t *)H5I_object_verify(file_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Check for valid selection */
+ if(H5S_SELECT_VALID(file_space) != TRUE)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "file selection+offset not within extent")
+ } /* end if */
+ }
+
+ if(H5D__pre_write(dset, direct_write, mem_type_id, mem_space, file_space, dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't prepare for writing data")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Dwrite() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__pre_write
+ *
+ * Purpose: Preparation for writing data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 2 November 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__pre_write(H5D_t *dset, hbool_t direct_write, hid_t mem_type_id,
+ const H5S_t *mem_space, const H5S_t *file_space,
+ hid_t dxpl_id, const void *buf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Direct chunk write */
+ if(direct_write) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ uint32_t direct_filters;
+ hsize_t *direct_offset;
+ uint32_t direct_datasize;
+ hsize_t internal_offset[H5O_LAYOUT_NDIMS];
+ unsigned u; /* Local index variable */
+
+ /* Get the dataset transfer property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ if(H5D_CHUNKED != dset->shared->layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a chunked dataset")
+
+ /* Retrieve parameters for direct chunk write */
+ if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_NAME, &direct_filters) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting filter info for direct chunk write")
+ if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_NAME, &direct_offset) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting offset info for direct chunk write")
+ if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_NAME, &direct_datasize) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting data size for direct chunk write")
+
+ /* The library's chunking code requires the offset terminates with a zero. So transfer the
+ * offset array to an internal offset array */
+ for(u = 0; u < dset->shared->ndims; u++) {
+ /* Make sure the offset doesn't exceed the dataset's dimensions */
+ if(direct_offset[u] > dset->shared->curr_dims[u])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset exceeds dimensions of dataset")
+
+ /* Make sure the offset fall right on a chunk's boundary */
+ if(direct_offset[u] % dset->shared->layout.u.chunk.dim[u])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset doesn't fall on chunks's boundary")
+
+ internal_offset[u] = direct_offset[u];
+ } /* end for */
+
+ /* Terminate the offset with a zero */
+ internal_offset[dset->shared->ndims] = 0;
+
+ /* write raw data */
+ if(H5D__chunk_direct_write(dset, dxpl_id, direct_filters, internal_offset, direct_datasize, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write chunk directly")
+ } /* end if */
+ else { /* Normal write */
+ /* write raw data */
+ if(H5D__write(dset, mem_type_id, mem_space, file_space, dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__pre_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__read
+ *
+ * Purpose: Reads (part of) a DATASET into application memory BUF. See
+ * H5Dread() for complete details.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space,
+ const H5S_t *file_space, hid_t dxpl_id, void *buf/*out*/)
+{
+ H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */
+ H5D_io_info_t io_info; /* Dataset I/O info */
+ H5D_type_info_t type_info; /* Datatype info for operation */
+ hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */
+ H5S_t * projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */
+ /* projection of the supplied mem_space to a new */
+ /* data space with rank equal to that of */
+ /* file_space. */
+ /* */
+ /* This field is only used if */
+ /* H5S_select_shape_same() returns TRUE when */
+ /* comparing the mem_space and the data_space, */
+ /* and the mem_space have different rank. */
+ /* */
+ /* Note that if this variable is used, the */
+ /* projected mem space must be discarded at the */
+ /* end of the function to avoid a memory leak. */
+ H5D_storage_t store; /*union of EFL and chunk pointer in file space */
+ hssize_t snelmts; /*total number of elmts (signed) */
+ hsize_t nelmts; /*total number of elmts */
+ hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */
+ hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ char fake_char; /* Temporary variable for NULL buffer pointers */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL)
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file);
+
+ if(!file_space)
+ file_space = dataset->shared->space;
+ if(!mem_space)
+ mem_space = file_space;
+ if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dst dataspace has invalid selection")
+ H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t);
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Set up datatype info for operation */
+ if(H5D__typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, FALSE, &type_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
+ type_info_init = TRUE;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Collective access is not permissible without a MPI based VFD */
+ if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE &&
+ !(H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI)))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only")
+#endif /*H5_HAVE_PARALLEL*/
+
+ /* Make certain that the number of elements in each selection is the same */
+ if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes")
+
+ /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */
+ if(NULL == buf) {
+ /* Check for any elements selected (which is invalid) */
+ if(nelmts > 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
+
+ /* If the buffer is nil, and 0 element is selected, make a fake buffer.
+ * This is for some MPI package like ChaMPIon on NCSA's tungsten which
+ * doesn't support this feature.
+ */
+ buf = &fake_char;
+ } /* end if */
+
+ /* Make sure that both selections have their extents set */
+ if(!(H5S_has_extent(file_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
+ if(!(H5S_has_extent(mem_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+
+ /* H5S_select_shape_same() has been modified to accept topologically identical
+ * selections with different rank as having the same shape (if the most
+ * rapidly changing coordinates match up), but the I/O code still has
+ * difficulties with the notion.
+ *
+ * To solve this, we check to see if H5S_select_shape_same() returns true,
+ * and if the ranks of the mem and file spaces are different. If the are,
+ * construct a new mem space that is equivalent to the old mem space, and
+ * use that instead.
+ *
+ * Note that in general, this requires us to touch up the memory buffer as
+ * well.
+ */
+ if(TRUE == H5S_select_shape_same(mem_space, file_space) &&
+ H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) {
+ void *adj_buf = NULL; /* Pointer to the location in buf corresponding */
+ /* to the beginning of the projected mem space. */
+
+ /* Attempt to construct projected dataspace for memory dataspace */
+ if(H5S_select_construct_projection(mem_space, &projected_mem_space,
+ (unsigned)H5S_GET_EXTENT_NDIMS(file_space), buf, (const void **)&adj_buf, type_info.dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
+ HDassert(projected_mem_space);
+ HDassert(adj_buf);
+
+ /* Switch to using projected memory dataspace & adjusted buffer */
+ mem_space = projected_mem_space;
+ buf = adj_buf;
+ } /* end if */
+
+
+ /* Retrieve dataset properties */
+ /* <none needed in the general case> */
+
+ /* If space hasn't been allocated and not using external storage,
+ * return fill value to buffer if fill time is upon allocation, or
+ * do nothing if fill time is never. If the dataset is compact and
+ * fill time is NEVER, there is no way to tell whether part of data
+ * has been overwritten. So just proceed in reading.
+ */
+ if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 &&
+ !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)) {
+ H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */
+
+ /* Retrieve dataset's fill-value properties */
+ if(H5P_is_fill_value_defined(&dataset->shared->dcpl_cache.fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* Should be impossible, but check anyway... */
+ if(fill_status == H5D_FILL_VALUE_UNDEFINED &&
+ (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET))
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "read failed: dataset doesn't exist, no data can be read")
+
+ /* If we're never going to fill this dataset, just leave the junk in the user's buffer */
+ if(dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_NEVER)
+ HGOTO_DONE(SUCCEED)
+
+ /* Go fill the user's selection with the dataset's fill value */
+ if(H5D__fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf,
+ type_info.mem_type, mem_space, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed")
+ else
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Set up I/O operation */
+ io_info.op_type = H5D_IO_OP_READ;
+ io_info.u.rbuf = buf;
+ if(H5D__ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation")
+ io_info_init = TRUE;
+
+ /* Sanity check that space is allocated, if there are elements */
+ if(nelmts > 0)
+ HDassert((*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)
+ || dataset->shared->dcpl_cache.efl.nused > 0
+ || dataset->shared->layout.type == H5D_COMPACT);
+
+ /* Allocate the chunk map */
+ if(NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map")
+
+ /* Call storage method's I/O initialization routine */
+ if(io_info.layout_ops.io_init && (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ io_op_init = TRUE;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Adjust I/O info for any parallel I/O */
+ if(H5D__ioinfo_adjust(&io_info, dataset, dxpl_id, file_space, mem_space, &type_info, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
+#endif /*H5_HAVE_PARALLEL*/
+
+ /* Invoke correct "high level" I/O routine */
+ if((*io_info.io_ops.multi_read)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
+
+done:
+ /* Shut down the I/O op information */
+ if(io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
+ if(fm)
+ fm = H5FL_FREE(H5D_chunk_map_t, fm);
+
+ if(io_info_init) {
+#ifdef H5_DEBUG_BUILD
+ /* release the metadata dxpl that was copied in the init function */
+ if(H5I_dec_ref(io_info.md_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't close metadata dxpl")
+#endif /* H5_DEBUG_BUILD */
+#ifdef H5_HAVE_PARALLEL
+ /* Shut down io_info struct */
+ if(H5D__ioinfo_term(&io_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't shut down io_info")
+#endif /*H5_HAVE_PARALLEL*/
+ }
+
+ /* Shut down datatype info for operation */
+ if(type_info_init && H5D__typeinfo_term(&type_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")
+
+ /* discard projected mem space if it was created */
+ if(NULL != projected_mem_space)
+ if(H5S_close(projected_mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__write
+ *
+ * Purpose: Writes (part of) a DATASET to a file from application memory
+ * BUF. See H5Dwrite() for complete details.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space,
+ const H5S_t *file_space, hid_t dxpl_id, const void *buf)
+{
+ H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */
+ H5D_io_info_t io_info; /* Dataset I/O info */
+ H5D_type_info_t type_info; /* Datatype info for operation */
+ hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */
+ H5S_t * projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */
+ /* projection of the supplied mem_space to a new */
+ /* data space with rank equal to that of */
+ /* file_space. */
+ /* */
+ /* This field is only used if */
+ /* H5S_select_shape_same() returns TRUE when */
+ /* comparing the mem_space and the data_space, */
+ /* and the mem_space have different rank. */
+ /* */
+ /* Note that if this variable is used, the */
+ /* projected mem space must be discarded at the */
+ /* end of the function to avoid a memory leak. */
+ H5D_storage_t store; /*union of EFL and chunk pointer in file space */
+ hssize_t snelmts; /*total number of elmts (signed) */
+ hsize_t nelmts; /*total number of elmts */
+ hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */
+ hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ char fake_char; /* Temporary variable for NULL buffer pointers */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL)
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file);
+
+ /* All filters in the DCPL must have encoding enabled. */
+ if(!dataset->shared->checked_filters) {
+ if(H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")
+
+ dataset->shared->checked_filters = TRUE;
+ } /* end if */
+
+ /* Check if we are allowed to write to this file */
+ if(0 == (H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Set up datatype info for operation */
+ if(H5D__typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, TRUE, &type_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
+ type_info_init = TRUE;
+
+ /* Various MPI based checks */
+#ifdef H5_HAVE_PARALLEL
+ if H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI) {
+ /* If MPI based VFD is used, no VL datatype support yet. */
+ /* This is because they use the global heap in the file and we don't */
+ /* support parallel access of that yet */
+ if(H5T_detect_class(type_info.mem_type, H5T_VLEN, FALSE) > 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing VL datatypes yet")
+
+ /* If MPI based VFD is used, no VL datatype support yet. */
+ /* This is because they use the global heap in the file and we don't */
+ /* support parallel access of that yet */
+ /* We should really use H5T_detect_class() here, but it will be difficult
+ * to detect the type of the reference if it is nested... -QAK
+ */
+ if(H5T_get_class(type_info.mem_type, TRUE) == H5T_REFERENCE &&
+ H5T_get_ref_type(type_info.mem_type) == H5R_DATASET_REGION)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing region reference datatypes yet")
+
+ /* Can't write to chunked datasets with filters, in parallel */
+ if(dataset->shared->layout.type == H5D_CHUNKED &&
+ dataset->shared->dcpl_cache.pline.nused > 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot write to chunked storage with filters in parallel")
+ } /* end if */
+ else {
+ /* Collective access is not permissible without a MPI based VFD */
+ if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only")
+ } /* end else */
+#endif /*H5_HAVE_PARALLEL*/
+
+ /* Initialize dataspace information */
+ if(!file_space)
+ file_space = dataset->shared->space;
+ if(!mem_space)
+ mem_space = file_space;
+
+ if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection")
+ H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t);
+
+ /* Make certain that the number of elements in each selection is the same */
+ if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes")
+
+ /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */
+ if(NULL == buf) {
+ /* Check for any elements selected (which is invalid) */
+ if(nelmts > 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")
+
+ /* If the buffer is nil, and 0 element is selected, make a fake buffer.
+ * This is for some MPI package like ChaMPIon on NCSA's tungsten which
+ * doesn't support this feature.
+ */
+ buf = &fake_char;
+ } /* end if */
+
+ /* Make sure that both selections have their extents set */
+ if(!(H5S_has_extent(file_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
+ if(!(H5S_has_extent(mem_space)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")
+
+ /* H5S_select_shape_same() has been modified to accept topologically
+ * identical selections with different rank as having the same shape
+ * (if the most rapidly changing coordinates match up), but the I/O
+ * code still has difficulties with the notion.
+ *
+ * To solve this, we check to see if H5S_select_shape_same() returns
+ * true, and if the ranks of the mem and file spaces are different.
+ * If the are, construct a new mem space that is equivalent to the
+ * old mem space, and use that instead.
+ *
+ * Note that in general, this requires us to touch up the memory buffer
+ * as well.
+ */
+ if(TRUE == H5S_select_shape_same(mem_space, file_space) &&
+ H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) {
+ void *adj_buf = NULL; /* Pointer to the location in buf corresponding */
+ /* to the beginning of the projected mem space. */
+
+ /* Attempt to construct projected dataspace for memory dataspace */
+ if(H5S_select_construct_projection(mem_space, &projected_mem_space,
+ (unsigned)H5S_GET_EXTENT_NDIMS(file_space), buf, (const void **)&adj_buf, type_info.src_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
+ HDassert(projected_mem_space);
+ HDassert(adj_buf);
+
+ /* Switch to using projected memory dataspace & adjusted buffer */
+ mem_space = projected_mem_space;
+ buf = adj_buf;
+ } /* end if */
+
+ /* Retrieve dataset properties */
+ /* <none needed currently> */
+
+ /* Set up I/O operation */
+ io_info.op_type = H5D_IO_OP_WRITE;
+ io_info.u.wbuf = buf;
+ if(H5D__ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation")
+ io_info_init = TRUE;
+
+ /* Allocate data space and initialize it if it hasn't been. */
+ if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 &&
+ !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)) {
+ hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */
+ hbool_t full_overwrite; /* Whether we are over-writing all the elements */
+
+ /* Get the number of elements in file dataset's dataspace */
+ if((file_nelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset")
+
+ /* Always allow fill values to be written if the dataset has a VL datatype */
+ if(H5T_detect_class(dataset->shared->type, H5T_VLEN, FALSE))
+ full_overwrite = FALSE;
+ else
+ full_overwrite = (hbool_t)((hsize_t)file_nelmts == nelmts ? TRUE : FALSE);
+
+ /* Allocate storage */
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
+ } /* end if */
+
+ /* Allocate the chunk map */
+ if(NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map")
+
+ /* Call storage method's I/O initialization routine */
+ if(io_info.layout_ops.io_init && (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
+ io_op_init = TRUE;
+
+#ifdef H5_HAVE_PARALLEL
+ /* Adjust I/O info for any parallel I/O */
+ if(H5D__ioinfo_adjust(&io_info, dataset, dxpl_id, file_space, mem_space, &type_info, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
+#endif /*H5_HAVE_PARALLEL*/
+
+ /* Invoke correct "high level" I/O routine */
+ if((*io_info.io_ops.multi_write)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
+
+#ifdef OLD_WAY
+/*
+ * This was taken out because it can be called in a parallel program with
+ * independent access, causing the metadata cache to get corrupted. Its been
+ * disabled for all types of access (serial as well as parallel) to make the
+ * modification time consistent for all programs. -QAK
+ *
+ * We should set a value in the dataset's shared information instead and flush
+ * it to the file when the dataset is being closed. -QAK
+ */
+ /*
+ * Update modification time. We have to do this explicitly because
+ * writing to a dataset doesn't necessarily change the object header.
+ */
+ if(H5O_touch(&(dataset->oloc), FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update modification time")
+#endif /* OLD_WAY */
+
+done:
+ /* Shut down the I/O op information */
+ if(io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
+ if(fm)
+ fm = H5FL_FREE(H5D_chunk_map_t, fm);
+
+ if(io_info_init) {
+#ifdef H5_DEBUG_BUILD
+ /* release the metadata dxpl that was copied in the init function */
+ if(H5I_dec_ref(io_info.md_dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't close metadata dxpl")
+#endif /* H5_DEBUG_BUILD */
+#ifdef H5_HAVE_PARALLEL
+ /* Shut down io_info struct */
+ if(H5D__ioinfo_term(&io_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't shut down io_info")
+#endif /*H5_HAVE_PARALLEL*/
+ }
+
+ /* Shut down datatype info for operation */
+ if(type_info_init && H5D__typeinfo_term(&type_info) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")
+
+ /* discard projected mem space if it was created */
+ if(NULL != projected_mem_space)
+ if(H5S_close(projected_mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__ioinfo_init
+ *
+ * Purpose: Routine for determining correct I/O operations for
+ * each I/O action.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_init(H5D_t *dset,
+#ifndef H5_HAVE_PARALLEL
+const
+#endif /* H5_HAVE_PARALLEL */
+ H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id,
+ const H5D_type_info_t *type_info, H5D_storage_t *store, H5D_io_info_t *io_info)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(dset);
+ HDassert(dset->oloc.file);
+ HDassert(type_info);
+ HDassert(type_info->tpath);
+ HDassert(io_info);
+
+ /* init both dxpls to the original one */
+ io_info->md_dxpl_id = dxpl_id;
+ io_info->raw_dxpl_id = dxpl_id;
+
+ /* set the dxpl IO type for sanity checking at the FD layer */
+#ifdef H5_DEBUG_BUILD
+ if(H5D_set_io_info_dxpls(io_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't set metadata and raw data dxpls")
+#endif /* H5_DEBUG_BUILD */
+
+ /* Set up "normal" I/O fields */
+ io_info->dset = dset;
+ io_info->dxpl_cache = dxpl_cache;
+ io_info->store = store;
+
+ /* Set I/O operations to initial values */
+ io_info->layout_ops = *dset->shared->layout.ops;
+
+ /* Set the "high-level" I/O operations for the dataset */
+ io_info->io_ops.multi_read = dset->shared->layout.ops->ser_read;
+ io_info->io_ops.multi_write = dset->shared->layout.ops->ser_write;
+
+ /* Set the I/O operations for reading/writing single blocks on disk */
+ if(type_info->is_xform_noop && type_info->is_conv_noop) {
+ /*
+ * If there is no data transform or type conversion then read directly into
+ * the application's buffer. This saves at least one mem-to-mem copy.
+ */
+ io_info->io_ops.single_read = H5D__select_read;
+ io_info->io_ops.single_write = H5D__select_write;
+ } /* end if */
+ else {
+ /*
+ * This is the general case (type conversion, usually).
+ */
+ io_info->io_ops.single_read = H5D__scatgath_read;
+ io_info->io_ops.single_write = H5D__scatgath_write;
+ } /* end else */
+
+#ifdef H5_HAVE_PARALLEL
+ /* Determine if the file was opened with an MPI VFD */
+ io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI);
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__ioinfo_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__typeinfo_init
+ *
+ * Purpose: Routine for determining correct datatype information for
+ * each I/O action.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__typeinfo_init(const H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache,
+ hid_t dxpl_id, hid_t mem_type_id, hbool_t do_write,
+ H5D_type_info_t *type_info)
+{
+ const H5T_t *src_type; /* Source datatype */
+ const H5T_t *dst_type; /* Destination datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(type_info);
+ HDassert(dset);
+
+ /* Patch the top level file pointer for dt->shared->u.vlen.f if needed */
+ if(H5T_patch_vlen_file(dset->shared->type, dset->oloc.file) < 0 )
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch VL datatype file pointer")
+
+ /* Initialize type info safely */
+ HDmemset(type_info, 0, sizeof(*type_info));
+
+ /* Get the memory & dataset datatypes */
+ if(NULL == (type_info->mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ type_info->dset_type = dset->shared->type;
+
+ if(do_write) {
+ src_type = type_info->mem_type;
+ dst_type = dset->shared->type;
+ type_info->src_type_id = mem_type_id;
+ type_info->dst_type_id = dset->shared->type_id;
+ } /* end if */
+ else {
+ src_type = dset->shared->type;
+ dst_type = type_info->mem_type;
+ type_info->src_type_id = dset->shared->type_id;
+ type_info->dst_type_id = mem_type_id;
+ } /* end else */
+
+ /*
+ * Locate the type conversion function and data space conversion
+ * functions, and set up the element numbering information. If a data
+ * type conversion is necessary then register datatype atoms. Data type
+ * conversion is necessary if the user has set the `need_bkg' to a high
+ * enough value in xfer_parms since turning off datatype conversion also
+ * turns off background preservation.
+ */
+ if(NULL == (type_info->tpath = H5T_path_find(src_type, dst_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype")
+
+ /* Precompute some useful information */
+ type_info->src_type_size = H5T_get_size(src_type);
+ type_info->dst_type_size = H5T_get_size(dst_type);
+ type_info->max_type_size = MAX(type_info->src_type_size, type_info->dst_type_size);
+ type_info->is_conv_noop = H5T_path_noop(type_info->tpath);
+ type_info->is_xform_noop = H5Z_xform_noop(dxpl_cache->data_xform_prop);
+ if(type_info->is_xform_noop && type_info->is_conv_noop) {
+ type_info->cmpd_subset = NULL;
+ type_info->need_bkg = H5T_BKG_NO;
+ } /* end if */
+ else {
+ size_t target_size; /* Desired buffer size */
+
+ /* Check if the datatypes are compound subsets of one another */
+ type_info->cmpd_subset = H5T_path_compound_subset(type_info->tpath);
+
+ /* Check if we need a background buffer */
+ if(do_write && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE))
+ type_info->need_bkg = H5T_BKG_YES;
+ else {
+ H5T_bkg_t path_bkg; /* Type conversion's background info */
+
+ if((path_bkg = H5T_path_bkg(type_info->tpath))) {
+ /* Retrieve the bkgr buffer property */
+ type_info->need_bkg = dxpl_cache->bkgr_buf_type;
+ type_info->need_bkg = MAX(path_bkg, type_info->need_bkg);
+ } /* end if */
+ else
+ type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
+ } /* end else */
+
+
+ /* Set up datatype conversion/background buffers */
+
+ /* Get buffer size from DXPL */
+ target_size = dxpl_cache->max_temp_buf;
+
+ /* If the buffer is too small to hold even one element, try to make it bigger */
+ if(target_size < type_info->max_type_size) {
+ hbool_t default_buffer_info; /* Whether the buffer information are the defaults */
+
+ /* Detect if we have all default settings for buffers */
+ default_buffer_info = (hbool_t)((H5D_TEMP_BUF_SIZE == dxpl_cache->max_temp_buf)
+ && (NULL == dxpl_cache->tconv_buf) && (NULL == dxpl_cache->bkgr_buf));
+
+ /* Check if we are using the default buffer info */
+ if(default_buffer_info)
+ /* OK to get bigger for library default settings */
+ target_size = type_info->max_type_size;
+ else
+ /* Don't get bigger than the application has requested */
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
+ } /* end if */
+
+ /* Compute the number of elements that will fit into buffer */
+ type_info->request_nelmts = target_size / type_info->max_type_size;
+
+ /* Sanity check elements in temporary buffer */
+ if(type_info->request_nelmts == 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
+
+ /*
+ * Get a temporary buffer for type conversion unless the app has already
+ * supplied one through the xfer properties. Instead of allocating a
+ * buffer which is the exact size, we allocate the target size. The
+ * malloc() is usually less resource-intensive if we allocate/free the
+ * same size over and over.
+ */
+ if(NULL == (type_info->tconv_buf = (uint8_t *)dxpl_cache->tconv_buf)) {
+ /* Allocate temporary buffer */
+ if(NULL == (type_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ type_info->tconv_buf_allocated = TRUE;
+ } /* end if */
+ if(type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)dxpl_cache->bkgr_buf)) {
+ size_t bkg_size; /* Desired background buffer size */
+
+ /* Compute the background buffer size */
+ /* (don't try to use buffers smaller than the default size) */
+ bkg_size = type_info->request_nelmts * type_info->dst_type_size;
+ if(bkg_size < dxpl_cache->max_temp_buf)
+ bkg_size = dxpl_cache->max_temp_buf;
+
+ /* Allocate background buffer */
+ /* (Need calloc()-like call since memory needs to be initialized) */
+ if(NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for background conversion")
+ type_info->bkg_buf_allocated = TRUE;
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__typeinfo_init() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__ioinfo_adjust
+ *
+ * Purpose: Adjust operation's I/O info for any parallel I/O
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 27, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, hid_t dxpl_id,
+ const H5S_t *file_space, const H5S_t *mem_space,
+ const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm)
+{
+ H5P_genplist_t *dx_plist; /* Data transer property list */
+ H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode; /* performed chunk optimization */
+ H5D_mpio_actual_io_mode_t actual_io_mode; /* performed io mode */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(dset);
+ HDassert(dset->oloc.file);
+ HDassert(mem_space);
+ HDassert(file_space);
+ HDassert(type_info);
+ HDassert(type_info->tpath);
+ HDassert(io_info);
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Reset the actual io mode properties to the default values in case
+ * the dxpl was previously used in a collective I/O operation.
+ */
+ actual_chunk_opt_mode = H5D_MPIO_NO_CHUNK_OPTIMIZATION;
+ actual_io_mode = H5D_MPIO_NO_COLLECTIVE;
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, &actual_chunk_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual chunk opt mode property")
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property")
+
+ /* Make any parallel I/O adjustments */
+ if(io_info->using_mpi_vfd) {
+ htri_t opt; /* Flag whether a selection is optimizable */
+
+ /* Record the original state of parallel I/O transfer options */
+ io_info->orig.xfer_mode = io_info->dxpl_cache->xfer_mode;
+ io_info->orig.coll_opt_mode = io_info->dxpl_cache->coll_opt_mode;
+ io_info->orig.io_ops.single_read = io_info->io_ops.single_read;
+ io_info->orig.io_ops.single_write = io_info->io_ops.single_write;
+
+ /* Get MPI communicator */
+ if(MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset->oloc.file)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator")
+
+ /* Check if we can set direct MPI-IO read/write functions */
+ if((opt = H5D__mpio_opt_possible(io_info, file_space, mem_space, type_info, fm, dx_plist)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ")
+
+ /* Check if we can use the optimized parallel I/O routines */
+ if(opt == TRUE) {
+ /* Override the I/O op pointers to the MPI-specific routines */
+ io_info->io_ops.multi_read = dset->shared->layout.ops->par_read;
+ io_info->io_ops.multi_write = dset->shared->layout.ops->par_write;
+ io_info->io_ops.single_read = H5D__mpio_select_read;
+ io_info->io_ops.single_write = H5D__mpio_select_write;
+ } /* end if */
+ else {
+ /* If we won't be doing collective I/O, but the user asked for
+ * collective I/O, change the request to use independent I/O, but
+ * mark it so that we remember to revert the change.
+ */
+ if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) {
+ /* Change the xfer_mode to independent for handling the I/O */
+ io_info->dxpl_cache->xfer_mode = H5FD_MPIO_INDEPENDENT;
+ if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__ioinfo_adjust() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__ioinfo_term
+ *
+ * Purpose: Common logic for terminating an I/O info object
+ * (Only used for restoring MPI transfer mode currently)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 6, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_term(H5D_io_info_t *io_info)
+{
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check if we used the MPI VFD for the I/O */
+ if(io_info->using_mpi_vfd) {
+ /* Check if we need to revert the change to the xfer mode */
+ if(io_info->orig.xfer_mode != io_info->dxpl_cache->xfer_mode) {
+ H5P_genplist_t *dx_plist; /* Data transer property list */
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Restore the original parallel I/O mode */
+ if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->orig.xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode")
+ } /* end if */
+
+ /* Check if we need to revert the change to the collective opt mode */
+ if(io_info->orig.coll_opt_mode != io_info->dxpl_cache->coll_opt_mode) {
+ H5P_genplist_t *dx_plist; /* Data transer property list */
+
+ /* Get the dataset transfer property list */
+ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Restore the original parallel I/O mode */
+ if(H5P_set(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &io_info->orig.coll_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set collective option mode")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__ioinfo_term() */
+
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__typeinfo_term
+ *
+ * Purpose: Common logic for terminating a type info object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 6, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__typeinfo_term(const H5D_type_info_t *type_info)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check for releasing datatype conversion & background buffers */
+ if(type_info->tconv_buf_allocated) {
+ HDassert(type_info->tconv_buf);
+ (void)H5FL_BLK_FREE(type_conv, type_info->tconv_buf);
+ } /* end if */
+ if(type_info->bkg_buf_allocated) {
+ HDassert(type_info->bkg_buf);
+ (void)H5FL_BLK_FREE(type_conv, type_info->bkg_buf);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__typeinfo_term() */
+
+#ifdef H5_DEBUG_BUILD
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_set_io_info_dxpls
+ *
+ * Purpose: Set the metadata and raw data dxpls in an io_info struct
+ * for sanity checking at the H5FD layer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * January 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_set_io_info_dxpls(H5D_io_info_t *io_info, hid_t dxpl_id)
+{
+ H5P_genplist_t *xfer_plist = NULL; /* Dataset transfer property list object */
+ H5FD_dxpl_type_t dxpl_type; /* Property indicating the type of the internal dxpl */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADATOM, FAIL, "can't get new property list object")
+
+ /* create the metadata dxpl */
+ if((io_info->md_dxpl_id = H5P_copy_plist(xfer_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dxpl")
+
+ /* Set the dxpl type property */
+ dxpl_type = H5FD_RAWDATA_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set dxpl type property")
+
+ /* Get the property list object */
+ if (NULL == (xfer_plist = (H5P_genplist_t *)H5I_object(io_info->md_dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADATOM, FAIL, "can't get new property list object")
+
+ /* Set the dxpl type property */
+ dxpl_type = H5FD_METADATA_DXPL;
+ if(H5P_set(xfer_plist, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set dxpl type property")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_set_io_info_dxpls */
+#endif /* H5_DEBUG_BUILD */
diff --git a/src/H5Dlayout.c b/src/H5Dlayout.c
new file mode 100644
index 0000000..c2fb5c2
--- /dev/null
+++ b/src/H5Dlayout.c
@@ -0,0 +1,703 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HLprivate.h" /* Local heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_set_io_ops
+ *
+ * Purpose: Set the I/O operation function pointers for a dataset,
+ * according to the dataset's layout
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_set_io_ops(const H5D_t *dataset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(dataset);
+
+ /* Set the I/O functions for each layout type */
+ switch(dataset->shared->layout.type) {
+ case H5D_CONTIGUOUS:
+ if(dataset->shared->dcpl_cache.efl.nused > 0)
+ dataset->shared->layout.ops = H5D_LOPS_EFL;
+ else
+ dataset->shared->layout.ops = H5D_LOPS_CONTIG;
+ break;
+
+ case H5D_CHUNKED:
+ dataset->shared->layout.ops = H5D_LOPS_CHUNK;
+
+ /* Set the chunk operations */
+ switch(dataset->shared->layout.u.chunk.idx_type) {
+ case H5D_CHUNK_IDX_BTREE:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_BTREE;
+ break;
+
+ case H5D_CHUNK_IDX_NONE:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_NONE;
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_SINGLE;
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_FARRAY;
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_EARRAY;
+ break;
+
+ case H5D_CHUNK_IDX_BT2:
+ dataset->shared->layout.storage.u.chunk.ops = H5D_COPS_BT2;
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HDassert(0 && "Unknown chunk index method!");
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown chunk index method")
+ } /* end switch */
+ break;
+
+ case H5D_COMPACT:
+ dataset->shared->layout.ops = H5D_LOPS_COMPACT;
+ break;
+
+ case H5D_VIRTUAL:
+ dataset->shared->layout.ops = H5D_LOPS_VIRTUAL;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown storage method")
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_set_io_ops() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_meta_size
+ *
+ * Purpose: Returns the size of the raw message in bytes except raw data
+ * part for compact dataset. This function doesn't take into
+ * account message alignment.
+ *
+ * Return: Success: Message data size in bytes
+ * Failure: 0
+ *
+ * Programmer: Raymond Lu
+ * August 14, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5D__layout_meta_size(const H5F_t *f, const H5O_layout_t *layout, hbool_t include_compact_data)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(f);
+ HDassert(layout);
+
+ ret_value = 1 + /* Version number */
+ 1; /* layout class type */
+
+ switch(layout->type) {
+ case H5D_COMPACT:
+ /* This information only present in older versions of message */
+ /* Size of raw data */
+ ret_value += 2;
+ if(include_compact_data)
+ ret_value += layout->storage.u.compact.size; /* data for compact dataset */
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* This information only present in older versions of message */
+ ret_value += H5F_SIZEOF_ADDR(f); /* Address of data */
+ ret_value += H5F_SIZEOF_SIZE(f); /* Length of data */
+ break;
+
+ case H5D_CHUNKED:
+ if(layout->version < H5O_LAYOUT_VERSION_4) {
+ /* Number of dimensions (1 byte) */
+ HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ ret_value++;
+
+ /* B-tree address */
+ ret_value += H5F_SIZEOF_ADDR(f); /* Address of data */
+
+ /* Dimension sizes */
+ ret_value += layout->u.chunk.ndims * 4;
+ } /* end if */
+ else {
+ /* Chunked layout feature flags */
+ ret_value++;
+
+ /* Number of dimensions (1 byte) */
+ HDassert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ ret_value++;
+
+ /* Encoded # of bytes for each chunk dimension */
+ HDassert(layout->u.chunk.enc_bytes_per_dim > 0 && layout->u.chunk.enc_bytes_per_dim <= 8);
+ ret_value++;
+
+ /* Dimension sizes */
+ ret_value += layout->u.chunk.ndims * layout->u.chunk.enc_bytes_per_dim;
+
+ /* Type of chunk index */
+ ret_value++;
+
+ switch(layout->u.chunk.idx_type) {
+ case H5D_CHUNK_IDX_BTREE:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, 0, "v1 B-tree index type found for layout message >v3")
+
+ case H5D_CHUNK_IDX_NONE:
+ /* nothing */
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE:
+ /* Possible filter information */
+ if(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
+ ret_value += H5F_SIZEOF_SIZE(f); /* Size of chunk (in file) */
+ ret_value += 4; /* Filter mask for chunk */
+ } /* end if */
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ /* Fixed array creation parameters */
+ ret_value += H5D_FARRAY_CREATE_PARAM_SIZE;
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ /* Extensible array creation parameters */
+ ret_value += H5D_EARRAY_CREATE_PARAM_SIZE;
+ break;
+
+ case H5D_CHUNK_IDX_BT2:
+ /* v2 B-tree creation parameters */
+ ret_value += H5D_BT2_CREATE_PARAM_SIZE;
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, 0, "Invalid chunk index type")
+ } /* end switch */
+
+ /* Chunk index address */
+ ret_value += H5F_SIZEOF_ADDR(f);
+ } /* end else */
+ break;
+
+ case H5D_VIRTUAL:
+ ret_value += H5F_SIZEOF_ADDR(f); /* Address of global heap */
+ ret_value += 4; /* Global heap index */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, 0, "Invalid layout class")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_meta_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_set_latest_version
+ *
+ * Purpose: Set the encoding for a layout to the latest version.
+ * Part of the coding in this routine is moved to
+ * H5D__layout_set_latest_indexing().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_set_latest_version(H5O_layout_t *layout, const H5S_t *space,
+ const H5D_dcpl_cache_t *dcpl_cache)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(layout);
+ HDassert(space);
+ HDassert(dcpl_cache);
+
+ /* Set encoding of layout to latest version */
+ layout->version = H5O_LAYOUT_VERSION_LATEST;
+
+ /* Set the latest indexing type for the layout message */
+ if(H5D__layout_set_latest_indexing(layout, space, dcpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set latest indexing type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_set_latest_version() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_set_latest_indexing
+ *
+ * Purpose: Set the latest indexing type for a layout message
+ * This is moved from H5D_layout_set_latest_version().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_set_latest_indexing(H5O_layout_t *layout, const H5S_t *space,
+ const H5D_dcpl_cache_t *dcpl_cache)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(layout);
+ HDassert(space);
+ HDassert(dcpl_cache);
+
+ /* The indexing methods only apply to chunked datasets (currently) */
+ if(layout->type == H5D_CHUNKED) {
+ int sndims; /* Rank of dataspace */
+ unsigned ndims; /* Rank of dataspace */
+
+ /* Query the dimensionality of the dataspace */
+ if((sndims = H5S_GET_EXTENT_NDIMS(space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "invalid dataspace rank")
+ ndims = (unsigned)sndims;
+
+ /* Avoid scalar/null dataspace */
+ if(ndims > 0) {
+ hsize_t max_dims[H5O_LAYOUT_NDIMS]; /* Maximum dimension sizes */
+ hsize_t cur_dims[H5O_LAYOUT_NDIMS]; /* Current dimension sizes */
+ unsigned unlim_count = 0; /* Count of unlimited max. dimensions */
+ hbool_t single = TRUE; /* Fulfill single chunk indexing */
+ unsigned u; /* Local index variable */
+
+ /* Query the dataspace's dimensions */
+ if(H5S_get_simple_extent_dims(space, cur_dims, max_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace max. dimensions")
+
+ /* Spin through the max. dimensions, looking for unlimited dimensions */
+ for(u = 0; u < ndims; u++) {
+ if(max_dims[u] == H5S_UNLIMITED)
+ unlim_count++;
+ if(cur_dims[u] != max_dims[u] || cur_dims[u] != layout->u.chunk.dim[u])
+ single = FALSE;
+ } /* end for */
+
+ /* Chunked datasets with unlimited dimension(s) */
+ if(unlim_count) { /* dataset with unlimited dimension(s) must be chunked */
+ if(1 == unlim_count) { /* Chunked dataset with only 1 unlimited dimension */
+ /* Set the chunk index type to an extensible array */
+ layout->u.chunk.idx_type = H5D_CHUNK_IDX_EARRAY;
+ layout->storage.u.chunk.idx_type = H5D_CHUNK_IDX_EARRAY;
+ layout->storage.u.chunk.ops = H5D_COPS_EARRAY;
+
+ /* Set the extensible array creation parameters */
+ /* (use hard-coded defaults for now, until we give applications
+ * control over this with a property list - QAK)
+ */
+ layout->u.chunk.u.earray.cparam.max_nelmts_bits = H5D_EARRAY_MAX_NELMTS_BITS;
+ layout->u.chunk.u.earray.cparam.idx_blk_elmts = H5D_EARRAY_IDX_BLK_ELMTS;
+ layout->u.chunk.u.earray.cparam.sup_blk_min_data_ptrs = H5D_EARRAY_SUP_BLK_MIN_DATA_PTRS;
+ layout->u.chunk.u.earray.cparam.data_blk_min_elmts = H5D_EARRAY_DATA_BLK_MIN_ELMTS;
+ layout->u.chunk.u.earray.cparam.max_dblk_page_nelmts_bits = H5D_EARRAY_MAX_DBLOCK_PAGE_NELMTS_BITS;
+ } /* end if */
+ else { /* Chunked dataset with > 1 unlimited dimensions */
+ /* Set the chunk index type to v2 B-tree */
+ layout->u.chunk.idx_type = H5D_CHUNK_IDX_BT2;
+ layout->storage.u.chunk.idx_type = H5D_CHUNK_IDX_BT2;
+ layout->storage.u.chunk.ops = H5D_COPS_BT2;
+
+ /* Set the v2 B-tree creation parameters */
+ /* (use hard-coded defaults for now, until we give applications
+ * control over this with a property list - QAK)
+ */
+ layout->u.chunk.u.btree2.cparam.node_size = H5D_BT2_NODE_SIZE;
+ layout->u.chunk.u.btree2.cparam.split_percent = H5D_BT2_SPLIT_PERC;
+ layout->u.chunk.u.btree2.cparam.merge_percent = H5D_BT2_MERGE_PERC;
+ } /* end else */
+ } /* end if */
+ else { /* Chunked dataset with fixed dimensions */
+ /* Check for correct condition for using "single chunk" chunk index */
+ if(single) {
+ layout->u.chunk.idx_type = H5D_CHUNK_IDX_SINGLE;
+ layout->storage.u.chunk.idx_type = H5D_CHUNK_IDX_SINGLE;
+ layout->storage.u.chunk.ops = H5D_COPS_SINGLE;
+ } /* end if */
+ else if(!dcpl_cache->pline.nused &&
+ dcpl_cache->fill.alloc_time == H5D_ALLOC_TIME_EARLY) {
+
+ /* Set the chunk index type to "none" Index */
+ layout->u.chunk.idx_type = H5D_CHUNK_IDX_NONE;
+ layout->storage.u.chunk.idx_type = H5D_CHUNK_IDX_NONE;
+ layout->storage.u.chunk.ops = H5D_COPS_NONE;
+ } /* end else-if */
+ else {
+ /* Set the chunk index type to Fixed Array */
+ layout->u.chunk.idx_type = H5D_CHUNK_IDX_FARRAY;
+ layout->storage.u.chunk.idx_type = H5D_CHUNK_IDX_FARRAY;
+ layout->storage.u.chunk.ops = H5D_COPS_FARRAY;
+
+ /* Set the fixed array creation parameters */
+ /* (use hard-coded defaults for now, until we give applications
+ * control over this with a property list - QAK)
+ */
+ layout->u.chunk.u.farray.cparam.max_dblk_page_nelmts_bits = H5D_FARRAY_MAX_DBLK_PAGE_NELMTS_BITS;
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_set_latest_indexing() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_oh_create
+ *
+ * Purpose: Create layout/pline/efl information for dataset
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_oh_create(H5F_t *file, hid_t dxpl_id, H5O_t *oh, H5D_t *dset,
+ hid_t dapl_id)
+{
+ H5O_layout_t *layout; /* Dataset's layout information */
+ const H5O_fill_t *fill_prop; /* Pointer to dataset's fill value information */
+ unsigned layout_mesg_flags; /* Flags for inserting layout message */
+ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, dset->oloc.addr, FAIL)
+
+ /* Sanity checking */
+ HDassert(file);
+ HDassert(oh);
+ HDassert(dset);
+
+ /* Set some local variables, for convenience */
+ layout = &dset->shared->layout;
+ fill_prop = &dset->shared->dcpl_cache.fill;
+
+ /* Update the filters message, if this is a chunked dataset */
+ if(layout->type == H5D_CHUNKED) {
+ H5O_pline_t *pline; /* Dataset's I/O pipeline information */
+
+ pline = &dset->shared->dcpl_cache.pline;
+ if(pline->nused > 0 && H5O_msg_append_oh(file, dxpl_id, oh, H5O_PLINE_ID, H5O_MSG_FLAG_CONSTANT, 0, pline) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update filter header message")
+ } /* end if */
+
+ /* Initialize the layout information for the new dataset */
+ if(dset->shared->layout.ops->init && (dset->shared->layout.ops->init)(file, dxpl_id, dset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize layout information")
+
+ /* Indicate that the layout information was initialized */
+ layout_init = TRUE;
+
+ /*
+ * Allocate storage if space allocate time is early; otherwise delay
+ * allocation until later.
+ */
+ if(fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY) {
+ H5D_io_info_t io_info;
+
+ io_info.dset = dset;
+ io_info.raw_dxpl_id = H5AC_rawdata_dxpl_id;
+ io_info.md_dxpl_id = dxpl_id;
+
+ if(H5D__alloc_storage(&io_info, H5D_ALLOC_CREATE, FALSE, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
+ }
+ /* Update external storage message, if it's used */
+ if(dset->shared->dcpl_cache.efl.nused > 0) {
+ H5O_efl_t *efl = &dset->shared->dcpl_cache.efl; /* Dataset's external file list */
+ H5HL_t *heap; /* Pointer to local heap for EFL file names */
+ size_t heap_size = H5HL_ALIGN(1);
+ size_t u;
+
+ /* Determine size of heap needed to stored the file names */
+ for(u = 0; u < efl->nused; ++u)
+ heap_size += H5HL_ALIGN(HDstrlen(efl->slot[u].name) + 1);
+
+ /* Create the heap for the EFL file names */
+ if(H5HL_create(file, dxpl_id, heap_size, &efl->heap_addr/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create EFL file name heap")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(file, dxpl_id, efl->heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect EFL file name heap")
+
+ /* Insert "empty" name first */
+ if(UFAIL == H5HL_insert(file, dxpl_id, heap, (size_t)1, "")) {
+ H5HL_unprotect(heap);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert file name into heap")
+ } /* end if */
+
+ for(u = 0; u < efl->nused; ++u) {
+ size_t offset; /* Offset of file name in heap */
+
+ /* Insert file name into heap */
+ if(UFAIL == (offset = H5HL_insert(file, dxpl_id, heap,
+ HDstrlen(efl->slot[u].name) + 1, efl->slot[u].name))) {
+ H5HL_unprotect(heap);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert file name into heap")
+ } /* end if */
+
+ /* Store EFL file name offset */
+ efl->slot[u].name_offset = offset;
+ } /* end for */
+
+ /* Release the heap */
+ if(H5HL_unprotect(heap) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to unprotect EFL file name heap")
+ heap = NULL;
+
+ /* Insert EFL message into dataset object header */
+ if(H5O_msg_append_oh(file, dxpl_id, oh, H5O_EFL_ID, H5O_MSG_FLAG_CONSTANT, 0, efl) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update external file list message")
+ } /* end if */
+
+ /* Create layout message */
+ /* (Don't make layout message constant unless allocation time is early and non-filtered, since space may not be allocated) */
+ /* (Note: this is relying on H5D__alloc_storage not calling H5O_msg_write during dataset creation) */
+ if(fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY && H5D_COMPACT != layout->type
+ && !dset->shared->dcpl_cache.pline.nused)
+ layout_mesg_flags = H5O_MSG_FLAG_CONSTANT;
+ else
+ layout_mesg_flags = 0;
+ if(H5O_msg_append_oh(file, dxpl_id, oh, H5O_LAYOUT_ID, layout_mesg_flags, 0, layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update layout")
+
+done:
+ /* Error cleanup */
+ if(ret_value < 0)
+ if(layout_init)
+ /* Destroy any cached layout information for the dataset */
+ if(dset->shared->layout.ops->dest && (dset->shared->layout.ops->dest)(dset, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5D__layout_oh_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_oh_read
+ *
+ * Purpose: Read layout/pline/efl information for dataset
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_oh_read(H5D_t *dataset, hid_t dxpl_id, hid_t dapl_id, H5P_genplist_t *plist)
+{
+ htri_t msg_exists; /* Whether a particular type of message exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checking */
+ HDassert(dataset);
+ HDassert(plist);
+
+ /* Get the optional filters message */
+ if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_PLINE_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists")
+ if(msg_exists) {
+ /* Retrieve the I/O pipeline message */
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_PLINE_ID, &dataset->shared->dcpl_cache.pline, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message")
+
+ /* Set the I/O pipeline info in the property list */
+ if(H5P_set(plist, H5O_CRT_PIPELINE_NAME, &dataset->shared->dcpl_cache.pline) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set pipeline")
+ } /* end if */
+
+ /*
+ * Get the raw data layout info. It's actually stored in two locations:
+ * the storage message of the dataset (dataset->storage) and certain
+ * values are copied to the dataset create plist so the user can query
+ * them.
+ */
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_LAYOUT_ID, &(dataset->shared->layout), dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read data layout message")
+
+ /* Check for external file list message (which might not exist) */
+ if((msg_exists = H5O_msg_exists(&(dataset->oloc), H5O_EFL_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if message exists")
+ if(msg_exists) {
+ /* Retrieve the EFL message */
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_EFL_ID, &dataset->shared->dcpl_cache.efl, dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve message")
+
+ /* Set the EFL info in the property list */
+ if(H5P_set(plist, H5D_CRT_EXT_FILE_LIST_NAME, &dataset->shared->dcpl_cache.efl) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set external file list")
+
+ /* Set the dataset's I/O operations */
+ dataset->shared->layout.ops = H5D_LOPS_EFL;
+ } /* end if */
+
+ /* Sanity check that the layout operations are set up */
+ HDassert(dataset->shared->layout.ops);
+
+ /* Initialize the layout information for the dataset */
+ if(dataset->shared->layout.ops->init && (dataset->shared->layout.ops->init)(dataset->oloc.file, dxpl_id, dataset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize layout information")
+
+ /* Adjust chunk dimensions to omit datatype size (in last dimension) for creation property */
+ if(H5D_CHUNKED == dataset->shared->layout.type)
+ dataset->shared->layout.u.chunk.ndims--;
+
+ /* Copy layout to the DCPL */
+ if(H5P_set(plist, H5D_CRT_LAYOUT_NAME, &dataset->shared->layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set layout")
+
+ /* Set chunk sizes */
+ if(H5D__chunk_set_sizes(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to set chunk sizes")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_oh_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__layout_oh_write
+ *
+ * Purpose: Write layout information for dataset
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__layout_oh_write(H5D_t *dataset, hid_t dxpl_id, H5O_t *oh, unsigned update_flags)
+{
+ htri_t msg_exists; /* Whether the layout message exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checking */
+ HDassert(dataset);
+ HDassert(oh);
+
+ /* Check if the layout message has been added to the dataset's header */
+ if((msg_exists = H5O_msg_exists_oh(oh, H5O_LAYOUT_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to check if layout message exists")
+ if(msg_exists) {
+ /* Write the layout message to the dataset's header */
+ if(H5O_msg_write_oh(dataset->oloc.file, dxpl_id, oh, H5O_LAYOUT_ID, 0, update_flags, &dataset->shared->layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to update layout message")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__layout_oh_write() */
+
diff --git a/src/H5Dmodule.h b/src/H5Dmodule.h
new file mode 100644
index 0000000..b259b69
--- /dev/null
+++ b/src/H5Dmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5D package. Including this header means that the source file
+ * is part of the H5D package.
+ */
+#ifndef _H5Dmodule_H
+#define _H5Dmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5D_MODULE
+#define H5_MY_PKG H5D
+#define H5_MY_PKG_ERR H5E_DATASET
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Dmodule_H */
+
diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c
new file mode 100644
index 0000000..0389c72
--- /dev/null
+++ b/src/H5Dmpio.c
@@ -0,0 +1,1839 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: rky 980813
+ * KY 2005 revised the code and made the change to support and optimize
+ * collective IO support.
+ * Purpose: Functions to read/write directly between app buffer and file.
+ *
+ * Beware of the ifdef'ed print statements.
+ * I didn't make them portable.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5VMprivate.h" /* Vector */
+
+#ifdef H5_HAVE_PARALLEL
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Macros to represent different IO options */
+#define H5D_ONE_LINK_CHUNK_IO 0
+#define H5D_MULTI_CHUNK_IO 1
+#define H5D_ONE_LINK_CHUNK_IO_MORE_OPT 2
+#define H5D_MULTI_CHUNK_IO_MORE_OPT 3
+
+/***** Macros for One linked collective IO case. *****/
+/* The default value to do one linked collective IO for all chunks.
+ If the average number of chunks per process is greater than this value,
+ the library will create an MPI derived datatype to link all chunks to do collective IO.
+ The user can set this value through an API. */
+
+/* Macros to represent options on how to obtain chunk address for one linked-chunk IO case */
+#define H5D_OBTAIN_ONE_CHUNK_ADDR_IND 0
+#define H5D_OBTAIN_ALL_CHUNK_ADDR_COL 2
+
+/* Macros to define the default ratio of obtaining all chunk addresses for one linked-chunk IO case */
+#define H5D_ALL_CHUNK_ADDR_THRES_COL 30
+#define H5D_ALL_CHUNK_ADDR_THRES_COL_NUM 10000
+
+/***** Macros for multi-chunk collective IO case. *****/
+/* The default value of the threshold to do collective IO for this chunk.
+ If the average number of processes per chunk is greater than the default value,
+ collective IO is done for this chunk.
+*/
+
+/* Macros to represent different IO modes(NONE, Independent or collective)for multiple chunk IO case */
+#define H5D_CHUNK_IO_MODE_IND 0
+#define H5D_CHUNK_IO_MODE_COL 1
+
+/* Macros to represent the regularity of the selection for multiple chunk IO case. */
+#define H5D_CHUNK_SELECT_REG 1
+#define H5D_CHUNK_SELECT_IRREG 2
+#define H5D_CHUNK_SELECT_NONE 0
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+/* Combine chunk address and chunk info into a struct for better performance. */
+typedef struct H5D_chunk_addr_info_t {
+ haddr_t chunk_addr;
+ H5D_chunk_info_t chunk_info;
+} H5D_chunk_addr_info_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5D__chunk_collective_io(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, H5D_chunk_map_t *fm);
+static herr_t H5D__multi_chunk_collective_io(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, H5D_chunk_map_t *fm,
+ H5P_genplist_t *dx_plist);
+static herr_t H5D__link_chunk_collective_io(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, H5D_chunk_map_t *fm, int sum_chunk,
+ H5P_genplist_t *dx_plist);
+static herr_t H5D__inter_collective_io(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, const H5S_t *file_space,
+ const H5S_t *mem_space);
+static herr_t H5D__final_collective_io(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, MPI_Datatype *mpi_file_type,
+ MPI_Datatype *mpi_buf_type);
+static herr_t H5D__sort_chunk(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm,
+ H5D_chunk_addr_info_t chunk_addr_info_array[], int many_chunk_opt);
+static herr_t H5D__obtain_mpio_mode(H5D_io_info_t *io_info, H5D_chunk_map_t *fm,
+ H5P_genplist_t *dx_plist, uint8_t assign_io_mode[], haddr_t chunk_addr[]);
+static herr_t H5D__ioinfo_xfer_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist,
+ H5FD_mpio_xfer_t xfer_mode);
+static herr_t H5D__ioinfo_coll_opt_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist,
+ H5FD_mpio_collective_opt_t coll_opt_mode);
+static herr_t H5D__mpio_get_min_chunk(const H5D_io_info_t *io_info,
+ const H5D_chunk_map_t *fm, int *min_chunkf);
+static herr_t H5D__mpio_get_sum_chunk(const H5D_io_info_t *io_info,
+ const H5D_chunk_map_t *fm, int *sum_chunkf);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mpio_opt_possible
+ *
+ * Purpose: Checks if an direct I/O transfer is possible between memory and
+ * the file.
+ *
+ * Return: Sauccess: Non-negative: TRUE or FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, April 3, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space,
+ const H5S_t *mem_space, const H5D_type_info_t *type_info,
+ const H5D_chunk_map_t *fm, H5P_genplist_t *dx_plist)
+{
+ int local_cause = 0; /* Local reason(s) for breaking collective mode */
+ int global_cause = 0; /* Global reason(s) for breaking collective mode */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+ HDassert(type_info);
+
+
+ /* For independent I/O, get out quickly and don't try to form consensus */
+ if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_INDEPENDENT)
+ local_cause |= H5D_MPIO_SET_INDEPENDENT;
+
+ /* Optimized MPI types flag must be set */
+ /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */
+ if(!H5FD_mpi_opt_types_g)
+ local_cause |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED;
+
+ /* Don't allow collective operations if datatype conversions need to happen */
+ if(!type_info->is_conv_noop)
+ local_cause |= H5D_MPIO_DATATYPE_CONVERSION;
+
+ /* Don't allow collective operations if data transform operations should occur */
+ if(!type_info->is_xform_noop)
+ local_cause |= H5D_MPIO_DATA_TRANSFORMS;
+
+ /* Check whether these are both simple or scalar dataspaces */
+ if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space))
+ && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space))))
+ local_cause |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES;
+
+ /* Dataset storage must be contiguous or chunked */
+ if(!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS ||
+ io_info->dset->shared->layout.type == H5D_CHUNKED))
+ local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET;
+
+ /* check if external-file storage is used */
+ if(io_info->dset->shared->dcpl_cache.efl.nused > 0)
+ local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET;
+
+ /* The handling of memory space is different for chunking and contiguous
+ * storage. For contiguous storage, mem_space and file_space won't change
+ * when it it is doing disk IO. For chunking storage, mem_space will
+ * change for different chunks. So for chunking storage, whether we can
+ * use collective IO will defer until each chunk IO is reached.
+ */
+
+ /* Don't allow collective operations if filters need to be applied */
+ if(io_info->dset->shared->layout.type == H5D_CHUNKED &&
+ io_info->dset->shared->dcpl_cache.pline.nused > 0)
+ local_cause |= H5D_MPIO_FILTERS;
+
+ /* Check for independent I/O */
+ if(local_cause & H5D_MPIO_SET_INDEPENDENT)
+ global_cause = local_cause;
+ else {
+ int mpi_code; /* MPI error code */
+
+ /* Form consensus opinion among all processes about whether to perform
+ * collective I/O
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 1, MPI_INT, MPI_BOR, io_info->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code)
+ } /* end else */
+
+ /* Write the local value of no-collective-cause to the DXPL. */
+ if(H5P_set(dx_plist, H5D_MPIO_LOCAL_NO_COLLECTIVE_CAUSE_NAME, &local_cause) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set local no collective cause property")
+
+ /* Write the global value of no-collective-cause to the DXPL. */
+ if(H5P_set(dx_plist, H5D_MPIO_GLOBAL_NO_COLLECTIVE_CAUSE_NAME, &global_cause) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set global no collective cause property")
+
+ /* Set the return value, based on the global cause */
+ ret_value = global_cause > 0 ? FALSE : TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__mpio_opt_possible() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mpio_select_read
+ *
+ * Purpose: MPI-IO function to read directly from app buffer to file.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__mpio_select_read(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+ hsize_t mpi_buf_count, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space)
+{
+ const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t);
+ if(H5F_block_read(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->raw_dxpl_id, io_info->u.rbuf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "can't finish collective parallel read")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__mpio_select_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mpio_select_write
+ *
+ * Purpose: MPI-IO function to write directly from app buffer to file.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__mpio_select_write(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info,
+ hsize_t mpi_buf_count, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space)
+{
+ const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /*OKAY: CAST DISCARDS CONST QUALIFIER*/
+ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t);
+ if(H5F_block_write(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->raw_dxpl_id, io_info->u.wbuf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "can't finish collective parallel write")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__mpio_select_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__ioinfo_xfer_mode
+ *
+ * Purpose: Switch to between collective & independent MPI I/O
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_xfer_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist,
+ H5FD_mpio_xfer_t xfer_mode)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Change the xfer_mode */
+ io_info->dxpl_cache->xfer_mode = xfer_mode;
+ if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode")
+
+ /* Change the "single I/O" function pointers */
+ if(xfer_mode == H5FD_MPIO_INDEPENDENT) {
+ /* Set the pointers to the original, non-MPI-specific routines */
+ io_info->io_ops.single_read = io_info->orig.io_ops.single_read;
+ io_info->io_ops.single_write = io_info->orig.io_ops.single_write;
+ } /* end if */
+ else {
+ HDassert(xfer_mode == H5FD_MPIO_COLLECTIVE);
+
+ /* Set the pointers to the MPI-specific routines */
+ io_info->io_ops.single_read = H5D__mpio_select_read;
+ io_info->io_ops.single_write = H5D__mpio_select_write;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__ioinfo_xfer_mode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__ioinfo_coll_opt_mode
+ *
+ * Purpose: Switch between using collective & independent MPI I/O w/file
+ * set view
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: MuQun Yang
+ * Oct. 5th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__ioinfo_coll_opt_mode(H5D_io_info_t *io_info, H5P_genplist_t *dx_plist,
+ H5FD_mpio_collective_opt_t coll_opt_mode)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Change the optimal xfer_mode */
+ io_info->dxpl_cache->coll_opt_mode = coll_opt_mode;
+ if(H5P_set(dx_plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &io_info->dxpl_cache->coll_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__ioinfo_coll_opt_mode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mpio_get_min_chunk
+ *
+ * Purpose: Routine for obtaining minimum number of chunks to cover
+ * hyperslab selection selected by all processors.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__mpio_get_min_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm,
+ int *min_chunkf)
+{
+ int num_chunkf; /* Number of chunks to iterate over */
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Get the number of chunks to perform I/O on */
+ num_chunkf = H5SL_count(fm->sel_chunks);
+
+ /* Determine the minimum # of chunks for all processes */
+ if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, min_chunkf, 1, MPI_INT, MPI_MIN, io_info->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__mpio_get_min_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__mpio_get_sum_chunk
+ *
+ * Purpose: Routine for obtaining total number of chunks to cover
+ * hyperslab selection selected by all processors.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__mpio_get_sum_chunk(const H5D_io_info_t *io_info, const H5D_chunk_map_t *fm,
+ int *sum_chunkf)
+{
+ int num_chunkf; /* Number of chunks to iterate over */
+ size_t ori_num_chunkf;
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Get the number of chunks to perform I/O on */
+ num_chunkf = 0;
+ ori_num_chunkf = H5SL_count(fm->sel_chunks);
+ H5_CHECKED_ASSIGN(num_chunkf, int, ori_num_chunkf, size_t);
+
+ /* Determine the summation of number of chunks for all processes */
+ if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&num_chunkf, sum_chunkf, 1, MPI_INT, MPI_SUM, io_info->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__mpio_get_sum_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_collective_read
+ *
+ * Purpose: Reads directly from contiguous data in file into application
+ * memory using collective I/O.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CONTIGUOUS_COLLECTIVE;
+ H5P_genplist_t *dx_plist; /* Pointer to DXPL */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(H5FD_MPIO == H5F_DRIVER_ID(io_info->dset->oloc.file));
+ HDassert(TRUE == H5P_isa_class(io_info->raw_dxpl_id, H5P_DATASET_XFER));
+
+ /* Call generic internal collective I/O routine */
+ if(H5D__inter_collective_io(io_info, type_info, file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't finish shared collective MPI-IO")
+
+ /* Obtain the data transfer properties */
+ if(NULL == (dx_plist = H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+
+ /* Set the actual I/O mode property. internal_collective_io will not break to
+ * independent I/O, so we set it here.
+ */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_collective_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__contig_collective_write
+ *
+ * Purpose: Write directly to contiguous data in file from application
+ * memory using collective I/O.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__contig_collective_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CONTIGUOUS_COLLECTIVE;
+ H5P_genplist_t *dx_plist; /* Pointer to DXPL */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(H5FD_MPIO == H5F_DRIVER_ID(io_info->dset->oloc.file));
+ HDassert(TRUE == H5P_isa_class(io_info->raw_dxpl_id, H5P_DATASET_XFER));
+
+ /* Call generic internal collective I/O routine */
+ if(H5D__inter_collective_io(io_info, type_info, file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "couldn't finish shared collective MPI-IO")
+
+ /* Obtain the data transfer properties */
+ if(NULL == (dx_plist = H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+
+ /* Set the actual I/O mode property. internal_collective_io will not break to
+ * independent I/O, so we set it here.
+ */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__contig_collective_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_collective_io
+ *
+ * Purpose: Routine for
+ * 1) choose an IO option:
+ * a) One collective IO defined by one MPI derived datatype to link through all chunks
+ * or b) multiple chunk IOs,to do MPI-IO for each chunk, the IO mode may be adjusted
+ * due to the selection pattern for each chunk.
+ * For option a)
+ * 1. Sort the chunk address, obtain chunk info according to the sorted chunk address
+ * 2. Build up MPI derived datatype for each chunk
+ * 3. Build up the final MPI derived datatype
+ * 4. Set up collective IO property list
+ * 5. Do IO
+ * For option b)
+ * 1. Use MPI_gather and MPI_Bcast to obtain information of *collective/independent/none*
+ * IO mode for each chunk of the selection
+ * 2. Depending on whether the IO mode is collective or independent or none,
+ * Create either MPI derived datatype for each chunk to do collective IO or
+ * just do independent IO or independent IO with file set view
+ * 3. Set up collective IO property list for collective mode
+ * 4. DO IO
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ * Modification:
+ * - Refctore to remove multi-chunk-without-opimization feature and update for
+ * multi-chunk-io accordingly
+ * Programmer: Jonathan Kim
+ * Date: 2012-10-10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ H5D_chunk_map_t *fm)
+{
+ H5P_genplist_t *dx_plist; /* Pointer to DXPL */
+ H5FD_mpio_chunk_opt_t chunk_opt_mode;
+ int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT;
+ int sum_chunk = -1;
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+ htri_t temp_not_link_io = FALSE;
+#endif
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(io_info);
+ HDassert(io_info->using_mpi_vfd);
+ HDassert(type_info);
+ HDassert(fm);
+
+ /* Obtain the data transfer properties */
+ if(NULL == (dx_plist = H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* Check the optional property list on what to do with collective chunk IO. */
+ if(H5P_get(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME, &chunk_opt_mode) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't get chunk optimization option")
+ if(H5FD_MPIO_CHUNK_ONE_IO == chunk_opt_mode)
+ io_option = H5D_ONE_LINK_CHUNK_IO; /*no opt*/
+ /* direct request to multi-chunk-io */
+ else if(H5FD_MPIO_CHUNK_MULTI_IO == chunk_opt_mode)
+ io_option = H5D_MULTI_CHUNK_IO;
+ /* via default path. branch by num threshold */
+ else {
+ unsigned one_link_chunk_io_threshold; /* Threshhold to use single collective I/O for all chunks */
+ int mpi_size; /* Number of processes in MPI job */
+
+ if(H5D__mpio_get_sum_chunk(io_info, fm, &sum_chunk) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the total chunk number of all processes");
+ if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size")
+
+ /* Get the chunk optimization option */
+ if(H5P_get(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME, &one_link_chunk_io_threshold) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't get chunk optimization option")
+
+ /* step 1: choose an IO option */
+ /* If the average number of chunk per process is greater than a threshold, we will do one link chunked IO. */
+ if((unsigned)sum_chunk / mpi_size >= one_link_chunk_io_threshold)
+ io_option = H5D_ONE_LINK_CHUNK_IO_MORE_OPT;
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+ else
+ temp_not_link_io = TRUE;
+#endif
+ } /* end else */
+
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ htri_t check_prop;
+ int new_value;
+
+ /* Get the dataset transfer property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_IO, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /*** Test collective chunk user-input optimization APIs. ***/
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME);
+ if(check_prop > 0) {
+ if(H5D_ONE_LINK_CHUNK_IO == io_option) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value")
+ } /* end if */
+ } /* end if */
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME);
+ if(check_prop > 0) {
+ if(H5D_MULTI_CHUNK_IO == io_option) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value")
+ } /* end if */
+ } /* end if */
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME);
+ if(check_prop > 0) {
+ if(H5D_ONE_LINK_CHUNK_IO_MORE_OPT == io_option) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value")
+ } /* end if */
+ } /* end if */
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME);
+ if(check_prop > 0) {
+ if(temp_not_link_io) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value")
+ } /* end if */
+ } /* end if */
+}
+#endif
+
+ /* step 2: Go ahead to do IO.*/
+ if(H5D_ONE_LINK_CHUNK_IO == io_option || H5D_ONE_LINK_CHUNK_IO_MORE_OPT == io_option) {
+ if(H5D__link_chunk_collective_io(io_info, type_info, fm, sum_chunk, dx_plist) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish linked chunk MPI-IO")
+ } /* end if */
+ /* direct request to multi-chunk-io */
+ else if(H5D_MULTI_CHUNK_IO == io_option) {
+ if(H5D__multi_chunk_collective_io(io_info, type_info, fm, dx_plist) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish optimized multiple chunk MPI-IO")
+ } /* end if */
+ else { /* multiple chunk IO via threshold */
+ if(H5D__multi_chunk_collective_io(io_info, type_info, fm, dx_plist) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish optimized multiple chunk MPI-IO")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_collective_io */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_collective_read
+ *
+ * Purpose: Reads directly from chunks in file into application memory
+ * using collective I/O.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_collective_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t *fm)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Call generic selection operation */
+ if(H5D__chunk_collective_io(io_info, type_info, fm) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_collective_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__chunk_collective_write
+ *
+ * Purpose: Write directly to chunks in file from application memory
+ * using collective I/O.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 4, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__chunk_collective_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space,
+ H5D_chunk_map_t *fm)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Call generic selection operation */
+ if(H5D__chunk_collective_io(io_info, type_info, fm) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__chunk_collective_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__link_chunk_collective_io
+ *
+ * Purpose: Routine for one collective IO with one MPI derived datatype to link with all chunks
+ *
+ * 1. Sort the chunk address and chunk info
+ * 2. Build up MPI derived datatype for each chunk
+ * 3. Build up the final MPI derived datatype
+ * 4. Use common collective IO routine to do MPI-IO
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ * Modification:
+ * - Set H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME and H5D_MPIO_ACTUAL_IO_MODE_NAME
+ * dxpl in this.
+ * Programmer: Jonathan Kim
+ * Date: 2012-10-10
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__link_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ H5D_chunk_map_t *fm, int sum_chunk, H5P_genplist_t *dx_plist)
+{
+ H5D_chunk_addr_info_t *chunk_addr_info_array = NULL;
+ MPI_Datatype chunk_final_mtype; /* Final memory MPI datatype for all chunks with seletion */
+ hbool_t chunk_final_mtype_is_derived = FALSE;
+ MPI_Datatype chunk_final_ftype; /* Final file MPI datatype for all chunks with seletion */
+ hbool_t chunk_final_ftype_is_derived = FALSE;
+ H5D_storage_t ctg_store; /* Storage info for "fake" contiguous dataset */
+ size_t total_chunks;
+ haddr_t *total_chunk_addr_array = NULL;
+ MPI_Datatype *chunk_mtype = NULL;
+ MPI_Datatype *chunk_ftype = NULL;
+ MPI_Aint *chunk_disp_array = NULL;
+ MPI_Aint *chunk_mem_disp_array = NULL;
+ hbool_t *chunk_mft_is_derived_array = NULL; /* Flags to indicate each chunk's MPI file datatype is derived */
+ hbool_t *chunk_mbt_is_derived_array = NULL; /* Flags to indicate each chunk's MPI memory datatype is derived */
+ int *chunk_mpi_file_counts = NULL; /* Count of MPI file datatype for each chunk */
+ int *chunk_mpi_mem_counts = NULL; /* Count of MPI memory datatype for each chunk */
+ int mpi_code; /* MPI return code */
+ H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode = H5D_MPIO_LINK_CHUNK;
+ H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_CHUNK_COLLECTIVE;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Set the actual-chunk-opt-mode property. */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, &actual_chunk_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual chunk opt mode property")
+
+ /* Set the actual-io-mode property.
+ * Link chunk I/O does not break to independent, so can set right away */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property")
+
+ /* Get the sum # of chunks, if not already available */
+ if(sum_chunk < 0) {
+ if(H5D__mpio_get_sum_chunk(io_info, fm, &sum_chunk) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the total chunk number of all processes");
+ } /* end if */
+
+ /* Retrieve total # of chunks in dataset */
+ H5_CHECKED_ASSIGN(total_chunks, size_t, fm->layout->u.chunk.nchunks, hsize_t);
+
+ /* Handle special case when dataspace dimensions only allow one chunk in
+ * the dataset. [This sometimes is used by developers who want the
+ * equivalent of compressed contiguous datasets - QAK]
+ */
+ if(total_chunks == 1) {
+ H5SL_node_t *chunk_node; /* Pointer to chunk node for selection */
+ H5S_t *fspace; /* Dataspace describing chunk & selection in it */
+ H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */
+
+ /* Check for this process having selection in this chunk */
+ chunk_node = H5SL_first(fm->sel_chunks);
+
+ if(chunk_node == NULL) {
+ /* Set the dataspace info for I/O to NULL, this process doesn't have any I/O to perform */
+ fspace = mspace = NULL;
+
+ /* Initialize chunk address */
+ ctg_store.contig.dset_addr = 0;
+ } /* end if */
+ else {
+ H5D_chunk_ud_t udata; /* User data for querying chunk info */
+ H5D_chunk_info_t *chunk_info; /* Info for chunk in skiplist */
+
+ /* Get the chunk info, for the selection in the chunk */
+ if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_item(chunk_node)))
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skip list")
+
+ /* Set the dataspace info for I/O */
+ fspace = chunk_info->fspace;
+ mspace = chunk_info->mspace;
+
+ /* Look up address of chunk */
+ if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk address")
+ ctg_store.contig.dset_addr = udata.chunk_block.offset;
+ } /* end else */
+
+ /* Set up the base storage address for this chunk */
+ io_info->store = &ctg_store;
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before inter_collective_io for total chunk = 1 \n");
+#endif
+
+ /* Perform I/O */
+ if(H5D__inter_collective_io(io_info, type_info, fspace, mspace) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO")
+ } /* end if */
+ else {
+ hsize_t mpi_buf_count; /* Number of MPI types */
+ size_t num_chunk; /* Number of chunks for this process */
+ size_t u; /* Local index variable */
+
+ /* Get the number of chunks with a selection */
+ num_chunk = H5SL_count(fm->sel_chunks);
+ H5_CHECK_OVERFLOW(num_chunk, size_t, int);
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"total_chunks = %Zu, num_chunk = %Zu\n", total_chunks, num_chunk);
+#endif
+
+ /* Set up MPI datatype for chunks selected */
+ if(num_chunk) {
+ /* Allocate chunking information */
+ if(NULL == (chunk_addr_info_array = (H5D_chunk_addr_info_t *)H5MM_malloc(num_chunk * sizeof(H5D_chunk_addr_info_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk array buffer")
+ if(NULL == (chunk_mtype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory datatype buffer")
+ if(NULL == (chunk_ftype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file datatype buffer")
+ if(NULL == (chunk_disp_array = (MPI_Aint *)H5MM_malloc(num_chunk * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file displacement buffer")
+ if(NULL == (chunk_mem_disp_array = (MPI_Aint *)H5MM_calloc(num_chunk * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory displacement buffer")
+ if(NULL == (chunk_mpi_mem_counts = (int *)H5MM_calloc(num_chunk * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory counts buffer")
+ if(NULL == (chunk_mpi_file_counts = (int *)H5MM_calloc(num_chunk * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file counts buffer")
+ if(NULL == (chunk_mbt_is_derived_array = (hbool_t *)H5MM_calloc(num_chunk * sizeof(hbool_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory is derived datatype flags buffer")
+ if(NULL == (chunk_mft_is_derived_array = (hbool_t *)H5MM_calloc(num_chunk * sizeof(hbool_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file is derived datatype flags buffer")
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before sorting the chunk address \n");
+#endif
+ /* Sort the chunk address */
+ if(H5D__sort_chunk(io_info, fm, chunk_addr_info_array, sum_chunk) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to sort chunk address")
+ ctg_store.contig.dset_addr = chunk_addr_info_array[0].chunk_addr;
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"after sorting the chunk address \n");
+#endif
+
+ /* Obtain MPI derived datatype from all individual chunks */
+ for(u = 0; u < num_chunk; u++) {
+ hsize_t *permute_map = NULL; /* array that holds the mapping from the old,
+ out-of-order displacements to the in-order
+ displacements of the MPI datatypes of the
+ point selection of the file space */
+ hbool_t is_permuted = FALSE;
+
+ /* Obtain disk and memory MPI derived datatype */
+ /* NOTE: The permute_map array can be allocated within H5S_mpio_space_type
+ * and will be fed into the next call to H5S_mpio_space_type
+ * where it will be freed.
+ */
+ if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.fspace,
+ type_info->src_type_size,
+ &chunk_ftype[u], /* OUT: datatype created */
+ &chunk_mpi_file_counts[u], /* OUT */
+ &(chunk_mft_is_derived_array[u]), /* OUT */
+ TRUE, /* this is a file space,
+ so permute the
+ datatype if the point
+ selections are out of
+ order */
+ &permute_map,/* OUT: a map to indicate the
+ permutation of points
+ selected in case they
+ are out of order */
+ &is_permuted /* OUT */) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type")
+ /* Sanity check */
+ if(is_permuted)
+ HDassert(permute_map);
+ if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.mspace,
+ type_info->dst_type_size, &chunk_mtype[u],
+ &chunk_mpi_mem_counts[u],
+ &(chunk_mbt_is_derived_array[u]),
+ FALSE, /* this is a memory
+ space, so if the file
+ space is not
+ permuted, there is no
+ need to permute the
+ datatype if the point
+ selections are out of
+ order*/
+ &permute_map, /* IN: the permutation map
+ generated by the
+ file_space selection
+ and applied to the
+ memory selection */
+ &is_permuted /* IN */) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI buf type")
+ /* Sanity check */
+ if(is_permuted)
+ HDassert(!permute_map);
+
+ /* Chunk address relative to the first chunk */
+ chunk_addr_info_array[u].chunk_addr -= ctg_store.contig.dset_addr;
+
+ /* Assign chunk address to MPI displacement */
+ /* (assume MPI_Aint big enough to hold it) */
+ chunk_disp_array[u] = (MPI_Aint)chunk_addr_info_array[u].chunk_addr;
+ } /* end for */
+
+ /* Create final MPI derived datatype for the file */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_file_counts, chunk_disp_array, chunk_ftype, &chunk_final_ftype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_ftype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+ chunk_final_ftype_is_derived = TRUE;
+
+ /* Create final MPI derived datatype for memory */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_mem_counts, chunk_mem_disp_array, chunk_mtype, &chunk_final_mtype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_mtype)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+ chunk_final_mtype_is_derived = TRUE;
+
+ /* Free the file & memory MPI datatypes for each chunk */
+ for(u = 0; u < num_chunk; u++) {
+ if(chunk_mbt_is_derived_array[u])
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_mtype + u)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+ if(chunk_mft_is_derived_array[u])
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_ftype + u)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ } /* end for */
+
+ /* We have a single, complicated MPI datatype for both memory & file */
+ mpi_buf_count = (hsize_t)1;
+ } /* end if */
+ else { /* no selection at all for this process */
+ /* Allocate chunking information */
+ if(NULL == (total_chunk_addr_array = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * total_chunks)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate total chunk address arraybuffer")
+
+ /* Retrieve chunk address map */
+ if(H5D__chunk_addrmap(io_info, total_chunk_addr_array) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+
+ /* Get chunk with lowest address */
+ ctg_store.contig.dset_addr = HADDR_MAX;
+ for(u = 0; u < total_chunks; u++)
+ if(total_chunk_addr_array[u] < ctg_store.contig.dset_addr)
+ ctg_store.contig.dset_addr = total_chunk_addr_array[u];
+ HDassert(ctg_store.contig.dset_addr != HADDR_MAX);
+
+ /* Set the MPI datatype */
+ chunk_final_ftype = MPI_BYTE;
+ chunk_final_mtype = MPI_BYTE;
+
+ /* No chunks selected for this process */
+ mpi_buf_count = (hsize_t)0;
+ } /* end else */
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before coming to final collective IO\n");
+#endif
+
+ /* Set up the base storage address for this chunk */
+ io_info->store = &ctg_store;
+
+ /* Perform final collective I/O operation */
+ if(H5D__final_collective_io(io_info, type_info, mpi_buf_count, &chunk_final_ftype, &chunk_final_mtype) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish MPI-IO")
+ } /* end else */
+
+done:
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before freeing memory inside H5D_link_collective_io ret_value = %d\n", ret_value);
+#endif
+ /* Release resources */
+ if(total_chunk_addr_array)
+ H5MM_xfree(total_chunk_addr_array);
+ if(chunk_addr_info_array)
+ H5MM_xfree(chunk_addr_info_array);
+ if(chunk_mtype)
+ H5MM_xfree(chunk_mtype);
+ if(chunk_ftype)
+ H5MM_xfree(chunk_ftype);
+ if(chunk_disp_array)
+ H5MM_xfree(chunk_disp_array);
+ if(chunk_mem_disp_array)
+ H5MM_xfree(chunk_mem_disp_array);
+ if(chunk_mpi_mem_counts)
+ H5MM_xfree(chunk_mpi_mem_counts);
+ if(chunk_mpi_file_counts)
+ H5MM_xfree(chunk_mpi_file_counts);
+ if(chunk_mbt_is_derived_array)
+ H5MM_xfree(chunk_mbt_is_derived_array);
+ if(chunk_mft_is_derived_array)
+ H5MM_xfree(chunk_mft_is_derived_array);
+
+ /* Free the MPI buf and file types, if they were derived */
+ if(chunk_final_mtype_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_mtype)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ if(chunk_final_ftype_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_ftype)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__link_chunk_collective_io */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__multi_chunk_collective_io
+ *
+ * Purpose: To do IO per chunk according to IO mode(collective/independent/none)
+ *
+ * 1. Use MPI_gather and MPI_Bcast to obtain IO mode in each chunk(collective/independent/none)
+ * 2. Depending on whether the IO mode is collective or independent or none,
+ * Create either MPI derived datatype for each chunk or just do independent IO
+ * 3. Use common collective IO routine to do MPI-IO
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ * Modification:
+ * - Set H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME dxpl in this to go along with
+ * setting H5D_MPIO_ACTUAL_IO_MODE_NAME dxpl at the bottom.
+ * Programmer: Jonathan Kim
+ * Date: 2012-10-10
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ H5D_chunk_map_t *fm, H5P_genplist_t *dx_plist)
+{
+ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */
+ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */
+ H5D_io_info_t cpt_io_info; /* Compact I/O info object */
+ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */
+ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */
+ uint8_t *chunk_io_option = NULL;
+ haddr_t *chunk_addr = NULL;
+ H5D_storage_t store; /* union of EFL and chunk pointer in file space */
+ H5FD_mpio_xfer_t last_xfer_mode = H5FD_MPIO_COLLECTIVE; /* Last parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */
+ H5FD_mpio_collective_opt_t last_coll_opt_mode = H5FD_MPIO_COLLECTIVE_IO; /* Last parallel transfer with independent IO or collective IO with this mode */
+ size_t total_chunk; /* Total # of chunks in dataset */
+#ifdef H5Dmpio_DEBUG
+ int mpi_rank;
+#endif
+ size_t u; /* Local index variable */
+ H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode = H5D_MPIO_MULTI_CHUNK; /* actual chunk optimization mode */
+ H5D_mpio_actual_io_mode_t actual_io_mode = H5D_MPIO_NO_COLLECTIVE; /* Local variable for tracking the I/O mode used. */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Set the actual chunk opt mode property */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, &actual_chunk_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual chunk opt mode property")
+
+#ifdef H5Dmpio_DEBUG
+ mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file);
+#endif
+
+ /* Retrieve total # of chunks in dataset */
+ H5_CHECKED_ASSIGN(total_chunk, size_t, fm->layout->u.chunk.nchunks, hsize_t);
+ HDassert(total_chunk != 0);
+
+ /* Allocate memories */
+ chunk_io_option = (uint8_t *)H5MM_calloc(total_chunk);
+ chunk_addr = (haddr_t *)H5MM_calloc(total_chunk * sizeof(haddr_t));
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D), "total_chunk %Zu\n", total_chunk);
+#endif
+
+ /* Obtain IO option for each chunk */
+ if(H5D__obtain_mpio_mode(io_info, fm, dx_plist, chunk_io_option, chunk_addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRECV, FAIL, "unable to obtain MPIO mode")
+
+ /* Set up contiguous I/O info object */
+ HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info));
+ ctg_io_info.store = &ctg_store;
+ ctg_io_info.layout_ops = *H5D_LOPS_CONTIG;
+
+ /* Initialize temporary contiguous storage info */
+ ctg_store.contig.dset_size = (hsize_t)io_info->dset->shared->layout.u.chunk.size;
+
+ /* Set up compact I/O info object */
+ HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info));
+ cpt_io_info.store = &cpt_store;
+ cpt_io_info.layout_ops = *H5D_LOPS_COMPACT;
+
+ /* Initialize temporary compact storage info */
+ cpt_store.compact.dirty = &cpt_dirty;
+
+ /* Set dataset storage for I/O info */
+ io_info->store = &store;
+
+ /* Loop over _all_ the chunks */
+ for(u = 0; u < total_chunk; u++) {
+ H5D_chunk_info_t *chunk_info; /* Chunk info for current chunk */
+ H5S_t *fspace; /* Dataspace describing chunk & selection in it */
+ H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u);
+#endif
+ /* Get the chunk info for this chunk, if there are elements selected */
+ chunk_info = fm->select_chunk[u];
+
+ /* Set the storage information for chunks with selections */
+ if(chunk_info) {
+ HDassert(chunk_info->index == u);
+
+ /* Pass in chunk's coordinates in a union. */
+ store.chunk.scaled = chunk_info->scaled;
+ } /* end if */
+
+ /* Collective IO for this chunk,
+ * Note: even there is no selection for this process, the process still
+ * needs to contribute MPI NONE TYPE.
+ */
+ if(chunk_io_option[u] == H5D_CHUNK_IO_MODE_COL) {
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"inside collective chunk IO mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u);
+#endif
+
+ /* Set the file & memory dataspaces */
+ if(chunk_info) {
+ fspace = chunk_info->fspace;
+ mspace = chunk_info->mspace;
+
+ /* Update the local variable tracking the dxpl's actual io mode property.
+ *
+ * Note: H5D_MPIO_COLLECTIVE_MULTI | H5D_MPIO_INDEPENDENT = H5D_MPIO_MIXED
+ * to ease switching between to mixed I/O without checking the current
+ * value of the property. You can see the definition in H5Ppublic.h
+ */
+ actual_io_mode = actual_io_mode | H5D_MPIO_CHUNK_COLLECTIVE;
+
+ } /* end if */
+ else {
+ fspace = mspace = NULL;
+ } /* end else */
+
+ /* Switch back to collective I/O */
+ if(last_xfer_mode != H5FD_MPIO_COLLECTIVE) {
+ if(H5D__ioinfo_xfer_mode(io_info, dx_plist, H5FD_MPIO_COLLECTIVE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O")
+ last_xfer_mode = H5FD_MPIO_COLLECTIVE;
+ } /* end if */
+ if(last_coll_opt_mode != H5FD_MPIO_COLLECTIVE_IO) {
+ if(H5D__ioinfo_coll_opt_mode(io_info, dx_plist, H5FD_MPIO_COLLECTIVE_IO) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to collective I/O")
+ last_coll_opt_mode = H5FD_MPIO_COLLECTIVE_IO;
+ } /* end if */
+
+ /* Initialize temporary contiguous storage address */
+ ctg_store.contig.dset_addr = chunk_addr[u];
+
+ /* Perform the I/O */
+ if(H5D__inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO")
+ } /* end if */
+ else { /* possible independent IO for this chunk */
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"inside independent IO mpi_rank = %d, chunk index = %Zu\n", mpi_rank, u);
+#endif
+
+ HDassert(chunk_io_option[u] == 0);
+
+ /* Set the file & memory dataspaces */
+ if(chunk_info) {
+ fspace = chunk_info->fspace;
+ mspace = chunk_info->mspace;
+
+ /* Update the local variable tracking the dxpl's actual io mode. */
+ actual_io_mode = actual_io_mode | H5D_MPIO_CHUNK_INDEPENDENT;
+ } /* end if */
+ else {
+ fspace = mspace = NULL;
+ } /* end else */
+
+ /* Using independent I/O with file setview.*/
+ if(last_coll_opt_mode != H5FD_MPIO_INDIVIDUAL_IO) {
+ if(H5D__ioinfo_coll_opt_mode(io_info, dx_plist, H5FD_MPIO_INDIVIDUAL_IO) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't switch to individual I/O")
+ last_coll_opt_mode = H5FD_MPIO_INDIVIDUAL_IO;
+ } /* end if */
+
+ /* Initialize temporary contiguous storage address */
+ ctg_store.contig.dset_addr = chunk_addr[u];
+
+ /* Perform the I/O */
+ if(H5D__inter_collective_io(&ctg_io_info, type_info, fspace, mspace) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish shared collective MPI-IO")
+#ifdef H5D_DEBUG
+ if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"after inter collective IO\n");
+#endif
+ } /* end else */
+ } /* end for */
+
+ /* Write the local value of actual io mode to the DXPL. */
+ if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property")
+
+done:
+ if(chunk_io_option)
+ H5MM_xfree(chunk_io_option);
+ if(chunk_addr)
+ H5MM_xfree(chunk_addr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__multi_chunk_collective_io */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__inter_collective_io
+ *
+ * Purpose: Routine for the shared part of collective IO between multiple chunk
+ * collective IO and contiguous collective IO
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__inter_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ const H5S_t *file_space, const H5S_t *mem_space)
+{
+ int mpi_buf_count; /* # of MPI types */
+ hbool_t mbt_is_derived = FALSE;
+ hbool_t mft_is_derived = FALSE;
+ MPI_Datatype mpi_file_type, mpi_buf_type;
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_STATIC
+
+ if((file_space != NULL) && (mem_space != NULL)) {
+ int mpi_file_count; /* Number of file "objects" to transfer */
+ hsize_t *permute_map = NULL; /* array that holds the mapping from the old,
+ out-of-order displacements to the in-order
+ displacements of the MPI datatypes of the
+ point selection of the file space */
+ hbool_t is_permuted = FALSE;
+
+ /* Obtain disk and memory MPI derived datatype */
+ /* NOTE: The permute_map array can be allocated within H5S_mpio_space_type
+ * and will be fed into the next call to H5S_mpio_space_type
+ * where it will be freed.
+ */
+ if(H5S_mpio_space_type(file_space, type_info->src_type_size,
+ &mpi_file_type, &mpi_file_count, &mft_is_derived, /* OUT: datatype created */
+ TRUE, /* this is a file space, so
+ permute the datatype if the
+ point selection is out of
+ order */
+ &permute_map, /* OUT: a map to indicate
+ the permutation of
+ points selected in
+ case they are out of
+ order */
+ &is_permuted /* OUT */) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type")
+ /* Sanity check */
+ if(is_permuted)
+ HDassert(permute_map);
+ if(H5S_mpio_space_type(mem_space, type_info->src_type_size,
+ &mpi_buf_type, &mpi_buf_count, &mbt_is_derived, /* OUT: datatype created */
+ FALSE, /* this is a memory space, so if
+ the file space is not
+ permuted, there is no need to
+ permute the datatype if the
+ point selections are out of
+ order*/
+ &permute_map /* IN: the permutation map
+ generated by the
+ file_space selection
+ and applied to the
+ memory selection */,
+ &is_permuted /* IN */) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI buffer type")
+ /* Sanity check */
+ if(is_permuted)
+ HDassert(!permute_map);
+ } /* end if */
+ else {
+ /* For non-selection, participate with a none MPI derived datatype, the count is 0. */
+ mpi_buf_type = MPI_BYTE;
+ mpi_file_type = MPI_BYTE;
+ mpi_buf_count = 0;
+ mbt_is_derived = FALSE;
+ mft_is_derived = FALSE;
+ } /* end else */
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before final collective IO \n");
+#endif
+
+ /* Perform final collective I/O operation */
+ if(H5D__final_collective_io(io_info, type_info, (hsize_t)mpi_buf_count, &mpi_file_type, &mpi_buf_type) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish collective MPI-IO")
+
+done:
+ /* Free the MPI buf and file types, if they were derived */
+ if(mbt_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&mpi_buf_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ if(mft_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&mpi_file_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"before leaving inter_collective_io ret_value = %d\n",ret_value);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__inter_collective_io() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__final_collective_io
+ *
+ * Purpose: Routine for the common part of collective IO with different storages.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__final_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t mpi_buf_count, MPI_Datatype *mpi_file_type, MPI_Datatype *mpi_buf_type)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Pass buf type, file type to the file driver. */
+ if(H5FD_mpi_setup_collective(io_info->raw_dxpl_id, mpi_buf_type, mpi_file_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O properties")
+
+ if(io_info->op_type == H5D_IO_OP_WRITE) {
+ if((io_info->io_ops.single_write)(io_info, type_info, mpi_buf_count, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed")
+ } /* end if */
+ else {
+ if((io_info->io_ops.single_read)(io_info, type_info, mpi_buf_count, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed")
+ } /* end else */
+
+done:
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D),"ret_value before leaving final_collective_io=%d\n",ret_value);
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__final_collective_io */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__cmp_chunk_addr
+ *
+ * Purpose: Routine to compare chunk addresses
+ *
+ * Description: Callback for qsort() to compare chunk addresses
+ *
+ * Return: -1, 0, 1
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2)
+{
+ haddr_t addr1, addr2;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ addr1 = ((const H5D_chunk_addr_info_t *)chunk_addr_info1)->chunk_addr;
+ addr2 = ((const H5D_chunk_addr_info_t *)chunk_addr_info2)->chunk_addr;
+
+ FUNC_LEAVE_NOAPI(H5F_addr_cmp(addr1, addr2))
+} /* end H5D__cmp_chunk_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__sort_chunk
+ *
+ * Purpose: Routine to sort chunks in increasing order of chunk address
+ * Each chunk address is also obtained.
+ *
+ * Description:
+ * For most cases, the chunk address has already been sorted in increasing order.
+ * The special sorting flag is used to optimize this common case.
+ * quick sort is used for necessary sorting.
+ *
+ * Parameters:
+ * Input: H5D_io_info_t* io_info,
+ * H5D_chunk_map_t *fm(global chunk map struct)
+ * Input/Output: H5D_chunk_addr_info_t chunk_addr_info_array[] : array to store chunk address and information
+ * many_chunk_opt : flag to optimize the way to obtain chunk addresses
+ * for many chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__sort_chunk(H5D_io_info_t *io_info, const H5D_chunk_map_t *fm,
+ H5D_chunk_addr_info_t chunk_addr_info_array[], int sum_chunk)
+{
+ H5SL_node_t *chunk_node; /* Current node in chunk skip list */
+ H5D_chunk_info_t *chunk_info; /* Current chunking info. of this node. */
+ haddr_t chunk_addr; /* Current chunking address of this node */
+ haddr_t *total_chunk_addr_array = NULL; /* The array of chunk address for the total number of chunk */
+ hbool_t do_sort = FALSE; /* Whether the addresses need to be sorted */
+ int bsearch_coll_chunk_threshold;
+ int many_chunk_opt = H5D_OBTAIN_ONE_CHUNK_ADDR_IND;
+ int mpi_size; /* Number of MPI processes */
+ int mpi_code; /* MPI return code */
+ int i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Retrieve # of MPI processes */
+ if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size")
+
+ /* Calculate the actual threshold to obtain all chunk addresses collectively
+ * The bigger this number is, the more possible the use of obtaining chunk
+ * address collectively.
+ */
+ /* For non-optimization one-link IO, actual bsearch threshold is always
+ * 0, we would always want to obtain the chunk addresses individually
+ * for each process.
+ */
+ bsearch_coll_chunk_threshold = (sum_chunk * 100) / ((int)fm->layout->u.chunk.nchunks * mpi_size);
+ if((bsearch_coll_chunk_threshold > H5D_ALL_CHUNK_ADDR_THRES_COL)
+ && ((sum_chunk / mpi_size) >= H5D_ALL_CHUNK_ADDR_THRES_COL_NUM))
+ many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_COL;
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D), "many_chunk_opt= %d\n", many_chunk_opt);
+#endif
+
+ /* If we need to optimize the way to obtain the chunk address */
+ if(many_chunk_opt != H5D_OBTAIN_ONE_CHUNK_ADDR_IND) {
+ int mpi_rank;
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D), "Coming inside H5D_OBTAIN_ALL_CHUNK_ADDR_COL\n");
+#endif
+ /* Allocate array for chunk addresses */
+ if(NULL == (total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t) * (size_t)fm->layout->u.chunk.nchunks)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory chunk address array")
+
+ /* Retrieve all the chunk addresses with process 0 */
+ if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank")
+
+ if(mpi_rank == 0) {
+ if(H5D__chunk_addrmap(io_info, total_chunk_addr_array) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+ } /* end if */
+
+ /* Broadcasting the MPI_IO option info. and chunk address info. */
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(total_chunk_addr_array, (int)(sizeof(haddr_t) * fm->layout->u.chunk.nchunks), MPI_BYTE, (int)0, io_info->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code)
+ } /* end if */
+
+ /* Start at first node in chunk skip list */
+ i = 0;
+ if(NULL == (chunk_node = H5SL_first(fm->sel_chunks)))
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk node from skipped list")
+
+ /* Iterate over all chunks for this process */
+ while(chunk_node) {
+ if(NULL == (chunk_info = H5SL_item(chunk_node)))
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get chunk info from skipped list")
+
+ if(many_chunk_opt == H5D_OBTAIN_ONE_CHUNK_ADDR_IND) {
+ H5D_chunk_ud_t udata; /* User data for querying chunk info */
+
+ /* Get address of chunk */
+ if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0)
+ HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skipped list")
+ chunk_addr = udata.chunk_block.offset;
+ } /* end if */
+ else
+ chunk_addr = total_chunk_addr_array[chunk_info->index];
+
+ /* Check if chunk addresses are not in increasing order in the file */
+ if(i > 0 && chunk_addr < chunk_addr_info_array[i - 1].chunk_addr)
+ do_sort = TRUE;
+
+ /* Set the address & info for this chunk */
+ chunk_addr_info_array[i].chunk_addr = chunk_addr;
+ chunk_addr_info_array[i].chunk_info = *chunk_info;
+
+ /* Advance to next chunk in list */
+ i++;
+ chunk_node = H5SL_next(chunk_node);
+ } /* end while */
+
+#ifdef H5D_DEBUG
+if(H5DEBUG(D))
+ HDfprintf(H5DEBUG(D), "before Qsort\n");
+#endif
+ if(do_sort) {
+ size_t num_chunks = H5SL_count(fm->sel_chunks);
+
+ HDqsort(chunk_addr_info_array, num_chunks, sizeof(chunk_addr_info_array[0]), H5D__cmp_chunk_addr);
+ } /* end if */
+
+done:
+ if(total_chunk_addr_array)
+ H5MM_xfree(total_chunk_addr_array);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__sort_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__obtain_mpio_mode
+ *
+ * Purpose: Routine to obtain each io mode(collective,independent or none) for each chunk;
+ * Each chunk address is also obtained.
+ *
+ * Description:
+ *
+ * 1) Each process provides two piece of information for all chunks having selection
+ * a) chunk index
+ * b) wheather this chunk is regular(for MPI derived datatype not working case)
+ *
+ * 2) Gather all the information to the root process
+ *
+ * 3) Root process will do the following:
+ * a) Obtain chunk addresses for all chunks in this data space
+ * b) With the consideration of the user option, calculate IO mode for each chunk
+ * c) Build MPI derived datatype to combine "chunk address" and "assign_io" information
+ * in order to do MPI Bcast only once
+ * d) MPI Bcast the IO mode and chunk address information for each chunk.
+ * 4) Each process then retrieves IO mode and chunk address information to assign_io_mode and chunk_addr.
+ *
+ * Parameters:
+ *
+ * Input: H5D_io_info_t* io_info,
+ * H5D_chunk_map_t *fm,(global chunk map struct)
+ * Output: uint8_t assign_io_mode[], : IO mode, collective, independent or none
+ * haddr_t chunk_addr[], : chunk address array for each chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Muqun Yang
+ * Monday, Feb. 13th, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__obtain_mpio_mode(H5D_io_info_t* io_info, H5D_chunk_map_t *fm,
+ H5P_genplist_t *dx_plist, uint8_t assign_io_mode[], haddr_t chunk_addr[])
+{
+ int total_chunks;
+ unsigned percent_nproc_per_chunk, threshold_nproc_per_chunk;
+ uint8_t* io_mode_info = NULL;
+ uint8_t* recv_io_mode_info = NULL;
+ uint8_t* mergebuf = NULL;
+ uint8_t* tempbuf;
+ H5SL_node_t* chunk_node;
+ H5D_chunk_info_t* chunk_info;
+ int mpi_size, mpi_rank;
+ MPI_Comm comm;
+ int ic, root;
+ int mpi_code;
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+ int new_value;
+ htri_t check_prop;
+#endif
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Assign the rank 0 to the root */
+ root = 0;
+ comm = io_info->comm;
+
+ /* Obtain the number of process and the current rank of the process */
+ if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank")
+ if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size")
+
+ /* Setup parameters */
+ H5_CHECKED_ASSIGN(total_chunks, int, fm->layout->u.chunk.nchunks, hsize_t);
+ if(H5P_get(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME, &percent_nproc_per_chunk) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't get percent nproc per chunk")
+ /* if ratio is 0, perform collective io */
+ if(0 == percent_nproc_per_chunk) {
+ if(H5D__chunk_addrmap(io_info, chunk_addr) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address");
+ for(ic = 0; ic < total_chunks; ic++)
+ assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL;
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+ threshold_nproc_per_chunk = mpi_size * percent_nproc_per_chunk/100;
+
+ /* Allocate memory */
+ if(NULL == (io_mode_info = (uint8_t *)H5MM_calloc(total_chunks)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate I/O mode info buffer")
+ if(NULL == (mergebuf = H5MM_malloc((sizeof(haddr_t) + 1) * total_chunks)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate mergebuf buffer")
+ tempbuf = mergebuf + total_chunks;
+ if(mpi_rank == root)
+ if(NULL == (recv_io_mode_info = (uint8_t *)H5MM_malloc(total_chunks * mpi_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate recv I/O mode info buffer")
+
+ /* Obtain the regularity and selection information for all chunks in this process. */
+ chunk_node = H5SL_first(fm->sel_chunks);
+ while(chunk_node) {
+ chunk_info = H5SL_item(chunk_node);
+
+ io_mode_info[chunk_info->index] = H5D_CHUNK_SELECT_REG; /* this chunk is selected and is "regular" */
+ chunk_node = H5SL_next(chunk_node);
+ } /* end while */
+
+ /* Gather all the information */
+ if(MPI_SUCCESS != (mpi_code = MPI_Gather(io_mode_info, total_chunks, MPI_BYTE, recv_io_mode_info, total_chunks, MPI_BYTE, root, comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Gather failed", mpi_code)
+
+ /* Calculate the mode for IO(collective, independent or none) at root process */
+ if(mpi_rank == root) {
+ int nproc;
+ int* nproc_per_chunk;
+
+ /* pre-computing: calculate number of processes and
+ regularity of the selection occupied in each chunk */
+ if(NULL == (nproc_per_chunk = (int*)H5MM_calloc(total_chunks * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate nproc_per_chunk buffer")
+
+ /* calculating the chunk address */
+ if(H5D__chunk_addrmap(io_info, chunk_addr) < 0) {
+ H5MM_free(nproc_per_chunk);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get chunk address")
+ } /* end if */
+
+ /* checking for number of process per chunk and regularity of the selection*/
+ for(nproc = 0; nproc < mpi_size; nproc++) {
+ uint8_t *tmp_recv_io_mode_info = recv_io_mode_info + (nproc * total_chunks);
+
+ /* Calculate the number of process per chunk and adding irregular selection option */
+ for(ic = 0; ic < total_chunks; ic++, tmp_recv_io_mode_info++) {
+ if(*tmp_recv_io_mode_info != 0) {
+ nproc_per_chunk[ic]++;
+ } /* end if */
+ } /* end for */
+ } /* end for */
+
+ /* Calculating MPIO mode for each chunk (collective, independent, none) */
+ for(ic = 0; ic < total_chunks; ic++) {
+ if(nproc_per_chunk[ic] > MAX(1, threshold_nproc_per_chunk)) {
+ assign_io_mode[ic] = H5D_CHUNK_IO_MODE_COL;
+ } /* end if */
+ } /* end for */
+
+
+ /* merge buffer io_mode info and chunk addr into one */
+ HDmemcpy(mergebuf, assign_io_mode, total_chunks);
+ HDmemcpy(tempbuf, chunk_addr, sizeof(haddr_t) * total_chunks);
+
+ H5MM_free(nproc_per_chunk);
+ } /* end if */
+
+ /* Broadcasting the MPI_IO option info. and chunk address info. */
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(mergebuf, ((sizeof(haddr_t) + 1) * total_chunks), MPI_BYTE, root, comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code)
+
+ HDmemcpy(assign_io_mode, mergebuf, total_chunks);
+ HDmemcpy(chunk_addr, tempbuf, sizeof(haddr_t) * total_chunks);
+
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the dataset transfer property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(io_info->raw_dxpl_id)))
+ HGOTO_ERROR(H5E_IO, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME);
+ if(check_prop > 0) {
+ for(ic = 0; ic < total_chunks; ic++) {
+ if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value")
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ check_prop = H5P_exist_plist(plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME);
+ if(check_prop > 0) {
+ int temp_count = 0;
+
+ for(ic = 0; ic < total_chunks; ic++) {
+ if(assign_io_mode[ic] == H5D_CHUNK_IO_MODE_COL) {
+ temp_count++;
+ break;
+ } /* end if */
+ } /* end for */
+ if(temp_count == 0) {
+ new_value = 0;
+ if(H5P_set(plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, &new_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "unable to set property value")
+ } /* end if */
+ } /* end if */
+}
+#endif
+
+done:
+ if(io_mode_info)
+ H5MM_free(io_mode_info);
+ if(mergebuf)
+ H5MM_free(mergebuf);
+ if(recv_io_mode_info) {
+ HDassert(mpi_rank == root);
+ H5MM_free(recv_io_mode_info);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__obtain_mpio_mode() */
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5Dnone.c b/src/H5Dnone.c
new file mode 100644
index 0000000..97ec5d6
--- /dev/null
+++ b/src/H5Dnone.c
@@ -0,0 +1,495 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Vailin Choi <vchoi@hdfgroup.org>
+ * September 2010
+ *
+ * Purpose: Implicit (Non Index) chunked I/O functions.
+ * This is used when the dataset is:
+ * extendible but with fixed max. dims
+ * with early allocation
+ * without filter
+ * The chunk coordinate is mapped into the actual disk addresses
+ * for the chunk without indexing.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Non Index chunking I/O ops */
+static herr_t H5D__none_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__none_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__none_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static int H5D__none_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__none_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__none_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__none_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__none_idx_size(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *size);
+static herr_t H5D__none_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__none_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Non Index chunk I/O ops */
+const H5D_chunk_ops_t H5D_COPS_NONE[1] = {{
+ FALSE, /* Non-indexed chunking don't current support SWMR access */
+ NULL, /* init */
+ H5D__none_idx_create, /* create */
+ H5D__none_idx_is_space_alloc, /* is_space_alloc */
+ NULL, /* insert */
+ H5D__none_idx_get_addr, /* get_addr */
+ NULL, /* resize */
+ H5D__none_idx_iterate, /* iterate */
+ H5D__none_idx_remove, /* remove */
+ H5D__none_idx_delete, /* delete */
+ H5D__none_idx_copy_setup, /* copy_setup */
+ NULL, /* copy_shutdown */
+ H5D__none_idx_size, /* size */
+ H5D__none_idx_reset, /* reset */
+ H5D__none_idx_dump, /* dump */
+ NULL /* dest */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_create
+ *
+ * Purpose: Allocate memory for the maximum # of chunks in the dataset.
+ *
+ * Return: Non-negative on success
+ * Negative on failure.
+ *
+ * Programmer: Vailin Choi; September 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ hsize_t nbytes; /* Total size of dataset chunks */
+ haddr_t addr; /* The address of dataset chunks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->pline->nused == 0); /* Shouldn't have filter defined on entering here */
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(idx_info->layout->max_nchunks);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr)); /* address of data shouldn't be defined */
+
+ /* Calculate size of max dataset chunks */
+ nbytes = idx_info->layout->max_nchunks * idx_info->layout->size;
+
+ /* Allocate space for max dataset chunks */
+ addr = H5MF_alloc(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, nbytes);
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "file allocation failed")
+
+ /* This is the address of the dataset chunks */
+ idx_info->storage->idx_addr = addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__none_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_is_space_alloc
+ *
+ * Purpose: Query if space for the dataset chunks is allocated
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; September 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__none_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__none_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk.
+ * Save the retrieved information in the udata supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->pline->nused == 0);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(udata);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+
+ /* Calculate the index of this chunk */
+ udata->chunk_idx = H5VM_array_offset_pre((idx_info->layout->ndims - 1), idx_info->layout->max_down_chunks, udata->common.scaled);
+
+ /* Calculate the address of the chunk */
+ udata->chunk_block.offset = idx_info->storage->idx_addr + udata->chunk_idx * idx_info->layout->size;
+
+ /* Update the other (constant) information for the chunk */
+ udata->chunk_block.length = idx_info->layout->size;
+ udata->filter_mask = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__none_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_iterate
+ *
+ * Purpose: Iterate over the chunks in an index, making a callback
+ * for each one.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; September 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__none_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5D_chunk_rec_t chunk_rec; /* generic chunk record */
+ unsigned ndims; /* Rank of chunk */
+ unsigned u; /* Local index variable */
+ int curr_dim; /* Current rank */
+ hsize_t idx; /* Array index of chunk */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(!idx_info->pline->nused);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+
+ /* Initialize generic chunk record */
+ HDmemset(&chunk_rec, 0, sizeof(chunk_rec));
+ chunk_rec.nbytes = idx_info->layout->size;
+ chunk_rec.filter_mask = 0;
+
+ ndims = idx_info->layout->ndims - 1;
+ HDassert(ndims > 0);
+
+ /* Iterate over all the chunks in the dataset's dataspace */
+ for(u = 0; u < idx_info->layout->nchunks; u++) {
+ /* Calculate the index of this chunk */
+ idx = H5VM_array_offset_pre(ndims, idx_info->layout->max_down_chunks, chunk_rec.scaled);
+
+ /* Calculate the address of the chunk */
+ chunk_rec.chunk_addr = idx_info->storage->idx_addr + idx * idx_info->layout->size;
+
+ /* Make "generic chunk" callback */
+ if((ret_value = (*chunk_cb)(&chunk_rec, chunk_udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ /* Update coordinates of chunk in dataset */
+ curr_dim = (int)(ndims - 1);
+ while(curr_dim >= 0) {
+ /* Increment coordinate in current dimension */
+ chunk_rec.scaled[curr_dim]++;
+
+ /* Check if we went off the end of the current dimension */
+ if(chunk_rec.scaled[curr_dim] >= idx_info->layout->chunks[curr_dim]) {
+ /* Reset coordinate & move to next faster dimension */
+ chunk_rec.scaled[curr_dim] = 0;
+ curr_dim--;
+ } /* end if */
+ else
+ break;
+ } /* end while */
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__none_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_remove
+ *
+ * Purpose: Remove chunk from index.
+ *
+ * Note: Chunks can't be removed (or added) to datasets with this
+ * form of index - all the space for all the chunks is always
+ * allocated in the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_remove(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info, H5D_chunk_common_ud_t H5_ATTR_UNUSED *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* NO OP */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__none_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_delete
+ *
+ * Purpose: Delete raw data storage for entire dataset (i.e. all chunks)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ hsize_t nbytes; /* Size of all chunks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(!idx_info->pline->nused); /* Shouldn't have filter defined on entering here */
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); /* should be defined */
+
+ /* chunk size * max # of chunks */
+ nbytes = idx_info->layout->max_nchunks * idx_info->layout->size;
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, idx_info->storage->idx_addr, nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free dataset chunks")
+
+ idx_info->storage->idx_addr = HADDR_UNDEF;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__none_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying chunks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(!idx_info_src->pline->nused);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+ HDassert(H5F_addr_defined(idx_info_src->storage->idx_addr));
+
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(!idx_info_dst->pline->nused);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Allocate dataset chunks in the dest. file */
+ if(H5D__none_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__none_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_size(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info, hsize_t *index_size)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(index_size);
+
+ *index_size = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__none_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr)
+ storage->idx_addr = HADDR_UNDEF;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__none_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__none_idx_dump
+ *
+ * Purpose: Dump
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; September 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__none_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__none_idx_dump() */
+
diff --git a/src/H5Doh.c b/src/H5Doh.c
new file mode 100644
index 0000000..9abbdff
--- /dev/null
+++ b/src/H5Doh.c
@@ -0,0 +1,467 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Object headers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static void *H5O__dset_get_copy_file_udata(void);
+static void H5O__dset_free_copy_file_udata(void *);
+static htri_t H5O__dset_isa(H5O_t *loc);
+static hid_t H5O__dset_open(const H5G_loc_t *obj_loc, hid_t lapl_id,
+ hid_t dxpl_id, hbool_t app_ref);
+static void *H5O__dset_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc,
+ hid_t dxpl_id);
+static H5O_loc_t *H5O__dset_get_oloc(hid_t obj_id);
+static herr_t H5O__dset_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh,
+ H5_ih_info_t *bh_info);
+static herr_t H5O__dset_flush(void *_obj_ptr, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* This message derives from H5O object class */
+const H5O_obj_class_t H5O_OBJ_DATASET[1] = {{
+ H5O_TYPE_DATASET, /* object type */
+ "dataset", /* object name, for debugging */
+ H5O__dset_get_copy_file_udata, /* get 'copy file' user data */
+ H5O__dset_free_copy_file_udata, /* free 'copy file' user data */
+ H5O__dset_isa, /* "isa" message */
+ H5O__dset_open, /* open an object of this class */
+ H5O__dset_create, /* create an object of this class */
+ H5O__dset_get_oloc, /* get an object header location for an object */
+ H5O__dset_bh_info, /* get the index & heap info for an object */
+ H5O__dset_flush /* flush an opened object of this class */
+}};
+
+/* Declare a free list to manage the H5D_copy_file_ud_t struct */
+H5FL_DEFINE(H5D_copy_file_ud_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_get_copy_file_udata
+ *
+ * Purpose: Allocates the user data needed for copying a dataset's
+ * object header from file to file.
+ *
+ * Return: Success: Non-NULL pointer to user data
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__dset_get_copy_file_udata(void)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Allocate space for the 'copy file' user data for copying datasets */
+ if(NULL == (ret_value = H5FL_CALLOC(H5D_copy_file_ud_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_get_copy_file_udata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_free_copy_file_udata
+ *
+ * Purpose: Release the user data needed for copying a dataset's
+ * object header from file to file.
+ *
+ * Return: <none>
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5O__dset_free_copy_file_udata(void *_udata)
+{
+ H5D_copy_file_ud_t *udata = (H5D_copy_file_ud_t *)_udata;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(udata);
+
+ /* Release copy of dataset's dataspace extent, if it was set */
+ if(udata->src_space_extent)
+ H5O_msg_free(H5O_SDSPACE_ID, udata->src_space_extent);
+
+ /* Release copy of dataset's datatype, if it was set */
+ if(udata->src_dtype)
+ H5T_close(udata->src_dtype);
+
+ /* Release copy of dataset's filter pipeline, if it was set */
+ if(udata->common.src_pline)
+ H5O_msg_free(H5O_PLINE_ID, udata->common.src_pline);
+
+ /* Release space for 'copy file' user data */
+ udata = H5FL_FREE(H5D_copy_file_ud_t, udata);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5O__dset_free_copy_file_udata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_isa
+ *
+ * Purpose: Determines if an object has the requisite messages for being
+ * a dataset.
+ *
+ * Return: Success: TRUE if the required dataset messages are
+ * present; FALSE otherwise.
+ *
+ * Failure: FAIL if the existence of certain messages
+ * cannot be determined.
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O__dset_isa(H5O_t *oh)
+{
+ htri_t exists; /* Flag if header message of interest exists */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(oh);
+
+ /* Datatype */
+ if((exists = H5O_msg_exists_oh(oh, H5O_DTYPE_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header")
+ else if(!exists)
+ HGOTO_DONE(FALSE)
+
+ /* Layout */
+ if((exists = H5O_msg_exists_oh(oh, H5O_SDSPACE_ID)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header")
+ else if(!exists)
+ HGOTO_DONE(FALSE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_isa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_open
+ *
+ * Purpose: Open a dataset at a particular location
+ *
+ * Return: Success: Open object identifier
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hid_t
+H5O__dset_open(const H5G_loc_t *obj_loc, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref)
+{
+ H5D_t *dset = NULL; /* Dataset opened */
+ htri_t isdapl; /* lapl_id is a dapl */
+ hid_t dapl_id; /* dapl to use to open this dataset */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(obj_loc);
+
+ /* If the lapl passed in is a dapl, use it. Otherwise, use the default dapl */
+ if(lapl_id == H5P_DEFAULT)
+ isdapl = FALSE;
+ else
+ if((isdapl = H5P_isa_class(lapl_id, H5P_DATASET_ACCESS)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOMPARE, FAIL, "unable to compare property list classes")
+
+ if(isdapl)
+ dapl_id = lapl_id;
+ else
+ dapl_id = H5P_DATASET_ACCESS_DEFAULT;
+
+ /* Open the dataset */
+ if(NULL == (dset = H5D_open(obj_loc, dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
+
+ /* Register an ID for the dataset */
+ if((ret_value = H5I_register(H5I_DATASET, dset, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataset")
+
+done:
+ if(ret_value < 0)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_create
+ *
+ * Purpose: Create a dataset in a file
+ *
+ * Return: Success: Pointer to the dataset data structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, April 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__dset_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ H5D_obj_create_t *crt_info = (H5D_obj_create_t *)_crt_info; /* Dataset creation parameters */
+ H5D_t *dset = NULL; /* New dataset created */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(crt_info);
+ HDassert(obj_loc);
+
+ /* Create the the dataset */
+ if(NULL == (dset = H5D__create(f, crt_info->type_id, crt_info->space, crt_info->dcpl_id, crt_info->dapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to create dataset")
+
+ /* Set up the new dataset's location */
+ if(NULL == (obj_loc->oloc = H5D_oloc(dset)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get object location of dataset")
+ if(NULL == (obj_loc->path = H5D_nameof(dset)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get path of dataset")
+
+ /* Set the return value */
+ ret_value = dset;
+
+done:
+ if(ret_value == NULL)
+ if(dset && H5D_close(dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, NULL, "unable to release dataset")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_get_oloc
+ *
+ * Purpose: Retrieve the object header location for an open object
+ *
+ * Return: Success: Pointer to object header location
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_loc_t *
+H5O__dset_get_oloc(hid_t obj_id)
+{
+ H5D_t *dset; /* Dataset opened */
+ H5O_loc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the dataset */
+ if(NULL == (dset = (H5D_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADATOM, NULL, "couldn't get object from ID")
+
+ /* Get the dataset's object header location */
+ if(NULL == (ret_value = H5D_oloc(dset)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_get_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_bh_info
+ *
+ * Purpose: Returns the amount of btree storage that is used for chunked
+ * dataset.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * July 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__dset_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info)
+{
+ H5O_layout_t layout; /* Data storage layout message */
+ H5O_efl_t efl; /* External File List message */
+ hbool_t layout_read = FALSE; /* Whether the layout message was read */
+ hbool_t efl_read = FALSE; /* Whether the external file list message was read */
+ htri_t exists; /* Flag if header message of interest exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(oh);
+ HDassert(bh_info);
+
+ /* Get the layout message from the object header */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_LAYOUT_ID, &layout))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find layout message")
+ layout_read = TRUE;
+
+ /* Check for chunked dataset storage */
+ if(layout.type == H5D_CHUNKED && H5D__chunk_is_space_alloc(&layout.storage)) {
+ /* Get size of chunk index */
+ if(H5D__chunk_bh_info(loc, dxpl_id, oh, &layout, &(bh_info->index_size)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't determine chunked dataset btree info")
+ } /* end if */
+ else if(layout.type == H5D_VIRTUAL
+ && (layout.storage.u.virt.serial_list_hobjid.addr != HADDR_UNDEF)) {
+ size_t virtual_heap_size;
+
+ /* Get size of global heap object for virtual dataset */
+ if(H5HG_get_obj_size(loc->file, dxpl_id, &(layout.storage.u.virt.serial_list_hobjid), &virtual_heap_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get global heap size for virtual dataset mapping")
+
+ /* Return heap size */
+ bh_info->heap_size = (hsize_t)virtual_heap_size;
+ } /* end if */
+
+ /* Check for External File List message in the object header */
+ if((exists = H5O_msg_exists_oh(oh, H5O_EFL_ID)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "unable to check for EFL message")
+
+ if(exists && H5D__efl_is_space_alloc(&layout.storage)) {
+ /* Start with clean EFL info */
+ HDmemset(&efl, 0, sizeof(efl));
+
+ /* Get External File List message from the object header */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_EFL_ID, &efl))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find EFL message")
+ efl_read = TRUE;
+
+ /* Get size of local heap for EFL message's file list */
+ if(H5D__efl_bh_info(loc->file, dxpl_id, &efl, &(bh_info->heap_size)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't determine EFL heap info")
+ } /* end if */
+
+done:
+ /* Free messages, if they've been read in */
+ if(layout_read && H5O_msg_reset(H5O_LAYOUT_ID, &layout) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset data storage layout message")
+ if(efl_read && H5O_msg_reset(H5O_EFL_ID, &efl) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset external file list message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_bh_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dset_flush
+ *
+ * Purpose: To flush any dataset information cached in memory
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * February 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__dset_flush(void *_obj_ptr, hid_t dxpl_id)
+{
+ H5D_t *dset = (H5D_t *)_obj_ptr; /* Pointer to dataset object */
+ H5O_type_t obj_type; /* Type of object at location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(dset);
+ HDassert(&dset->oloc);
+
+ /* Check that the object found is the correct type */
+ if(H5O_obj_type(&dset->oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get object type")
+ if(obj_type != H5O_TYPE_DATASET)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(H5D__flush_real(dset, dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dset_flush() */
+
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h
new file mode 100644
index 0000000..8a4711f
--- /dev/null
+++ b/src/H5Dpkg.h
@@ -0,0 +1,783 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, April 14, 2003
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5D package. Source files outside the H5D package should
+ * include H5Dprivate.h instead.
+ */
+#if !(defined H5D_FRIEND || defined H5D_MODULE)
+#error "Do not include this file outside the H5D package!"
+#endif
+
+#ifndef _H5Dpkg_H
+#define _H5Dpkg_H
+
+/* Get package's private header */
+#include "H5Dprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5B2private.h" /* v2 B-trees */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gprivate.h" /* Groups */
+#include "H5SLprivate.h" /* Skip lists */
+#include "H5Tprivate.h" /* Datatypes */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Set the minimum object header size to create objects with */
+#define H5D_MINHDR_SIZE 256
+
+/* [Simple] Macro to construct a H5D_io_info_t from it's components */
+#define H5D_BUILD_IO_INFO_WRT(io_info, ds, dxpl_c, dxpl_m, dxpl_r, str, buf) \
+ (io_info)->dset = ds; \
+ (io_info)->dxpl_cache = dxpl_c; \
+ (io_info)->raw_dxpl_id = dxpl_r; \
+ (io_info)->md_dxpl_id = dxpl_m; \
+ (io_info)->store = str; \
+ (io_info)->op_type = H5D_IO_OP_WRITE; \
+ (io_info)->u.wbuf = buf
+#define H5D_BUILD_IO_INFO_RD(io_info, ds, dxpl_c, dxpl_m, dxpl_r, str, buf) \
+ (io_info)->dset = ds; \
+ (io_info)->dxpl_cache = dxpl_c; \
+ (io_info)->raw_dxpl_id = dxpl_r; \
+ (io_info)->md_dxpl_id = dxpl_m; \
+ (io_info)->store = str; \
+ (io_info)->op_type = H5D_IO_OP_READ; \
+ (io_info)->u.rbuf = buf
+
+/* Flags for marking aspects of a dataset dirty */
+#define H5D_MARK_SPACE 0x01
+#define H5D_MARK_LAYOUT 0x02
+
+/* Default creation parameters for chunk index data structures */
+/* See H5O_layout_chunk_t */
+
+/* Fixed array creation values */
+#define H5D_FARRAY_CREATE_PARAM_SIZE 1 /* Size of the creation parameters in bytes */
+#define H5D_FARRAY_MAX_DBLK_PAGE_NELMTS_BITS 10 /* i.e. 1024 elements per data block page */
+
+/* Extensible array creation values */
+#define H5D_EARRAY_CREATE_PARAM_SIZE 5 /* Size of the creation parameters in bytes */
+#define H5D_EARRAY_MAX_NELMTS_BITS 32 /* i.e. 4 giga-elements */
+#define H5D_EARRAY_IDX_BLK_ELMTS 4
+#define H5D_EARRAY_SUP_BLK_MIN_DATA_PTRS 4
+#define H5D_EARRAY_DATA_BLK_MIN_ELMTS 16
+#define H5D_EARRAY_MAX_DBLOCK_PAGE_NELMTS_BITS 10 /* i.e. 1024 elements per data block page */
+
+/* v2 B-tree creation values for raw meta_size */
+#define H5D_BT2_CREATE_PARAM_SIZE 6 /* Size of the creation parameters in bytes */
+#define H5D_BT2_NODE_SIZE 2048
+#define H5D_BT2_SPLIT_PERC 100
+#define H5D_BT2_MERGE_PERC 40
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Typedef for datatype information for raw data I/O operation */
+typedef struct H5D_type_info_t {
+ /* Initial values */
+ const H5T_t *mem_type; /* Pointer to memory datatype */
+ const H5T_t *dset_type; /* Pointer to dataset datatype */
+ H5T_path_t *tpath; /* Datatype conversion path */
+ hid_t src_type_id; /* Source datatype ID */
+ hid_t dst_type_id; /* Destination datatype ID */
+
+ /* Computed/derived values */
+ size_t src_type_size; /* Size of source type */
+ size_t dst_type_size; /* Size of destination type */
+ size_t max_type_size; /* Size of largest source/destination type */
+ hbool_t is_conv_noop; /* Whether the type conversion is a NOOP */
+ hbool_t is_xform_noop; /* Whether the data transform is a NOOP */
+ const H5T_subset_info_t *cmpd_subset; /* Info related to the compound subset conversion functions */
+ H5T_bkg_t need_bkg; /* Type of background buf needed */
+ size_t request_nelmts; /* Requested strip mine */
+ uint8_t *tconv_buf; /* Datatype conv buffer */
+ hbool_t tconv_buf_allocated; /* Whether the type conversion buffer was allocated */
+ uint8_t *bkg_buf; /* Background buffer */
+ hbool_t bkg_buf_allocated; /* Whether the background buffer was allocated */
+} H5D_type_info_t;
+
+/* Forward declaration of structs used below */
+struct H5D_io_info_t;
+struct H5D_chunk_map_t;
+
+/* Function pointers for I/O on particular types of dataset layouts */
+typedef herr_t (*H5D_layout_construct_func_t)(H5F_t *f, H5D_t *dset);
+typedef herr_t (*H5D_layout_init_func_t)(H5F_t *f, hid_t dxpl_id, const H5D_t *dset,
+ hid_t dapl_id);
+typedef hbool_t (*H5D_layout_is_space_alloc_func_t)(const H5O_storage_t *storage);
+typedef herr_t (*H5D_layout_io_init_func_t)(const struct H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ struct H5D_chunk_map_t *cm);
+typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, struct H5D_chunk_map_t *fm);
+typedef herr_t (*H5D_layout_write_func_t)(struct H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, struct H5D_chunk_map_t *fm);
+typedef ssize_t (*H5D_layout_readvv_func_t)(const struct H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]);
+typedef herr_t (*H5D_layout_flush_func_t)(H5D_t *dataset, hid_t dxpl_id);
+typedef herr_t (*H5D_layout_io_term_func_t)(const struct H5D_chunk_map_t *cm);
+typedef herr_t (*H5D_layout_dest_func_t)(H5D_t *dataset, hid_t dxpl_id);
+
+/* Typedef for grouping layout I/O routines */
+typedef struct H5D_layout_ops_t {
+ H5D_layout_construct_func_t construct; /* Layout constructor for new datasets */
+ H5D_layout_init_func_t init; /* Layout initializer for dataset */
+ H5D_layout_is_space_alloc_func_t is_space_alloc; /* Query routine to determine if storage is allocated */
+ H5D_layout_io_init_func_t io_init; /* I/O initialization routine */
+ H5D_layout_read_func_t ser_read; /* High-level I/O routine for reading data in serial */
+ H5D_layout_write_func_t ser_write; /* High-level I/O routine for writing data in serial */
+#ifdef H5_HAVE_PARALLEL
+ H5D_layout_read_func_t par_read; /* High-level I/O routine for reading data in parallel */
+ H5D_layout_write_func_t par_write; /* High-level I/O routine for writing data in parallel */
+#endif /* H5_HAVE_PARALLEL */
+ H5D_layout_readvv_func_t readvv; /* Low-level I/O routine for reading data */
+ H5D_layout_writevv_func_t writevv; /* Low-level I/O routine for writing data */
+ H5D_layout_flush_func_t flush; /* Low-level I/O routine for flushing raw data */
+ H5D_layout_io_term_func_t io_term; /* I/O shutdown routine */
+ H5D_layout_dest_func_t dest; /* Destroy layout info */
+} H5D_layout_ops_t;
+
+/* Function pointers for either multiple or single block I/O access */
+typedef herr_t (*H5D_io_single_read_func_t)(const struct H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+typedef herr_t (*H5D_io_single_write_func_t)(const struct H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+/* Typedef for raw data I/O framework info */
+typedef struct H5D_io_ops_t {
+ H5D_layout_read_func_t multi_read; /* High-level I/O routine for reading data */
+ H5D_layout_write_func_t multi_write; /* High-level I/O routine for writing data */
+ H5D_io_single_read_func_t single_read; /* I/O routine for reading single block */
+ H5D_io_single_write_func_t single_write; /* I/O routine for writing single block */
+} H5D_io_ops_t;
+
+/* Typedefs for dataset storage information */
+typedef struct {
+ haddr_t dset_addr; /* Address of dataset in file */
+ hsize_t dset_size; /* Total size of dataset in file */
+} H5D_contig_storage_t;
+
+typedef struct {
+ hsize_t *scaled; /* Scaled coordinates for a chunk */
+} H5D_chunk_storage_t;
+
+typedef struct {
+ void *buf; /* Buffer for compact dataset */
+ hbool_t *dirty; /* Pointer to dirty flag to mark */
+} H5D_compact_storage_t;
+
+typedef union H5D_storage_t {
+ H5D_contig_storage_t contig; /* Contiguous information for dataset */
+ H5D_chunk_storage_t chunk; /* Chunk information for dataset */
+ H5D_compact_storage_t compact; /* Compact information for dataset */
+ H5O_efl_t efl; /* External file list information for dataset */
+} H5D_storage_t;
+
+/* Typedef for raw data I/O operation info */
+typedef enum H5D_io_op_type_t {
+ H5D_IO_OP_READ, /* Read operation */
+ H5D_IO_OP_WRITE /* Write operation */
+} H5D_io_op_type_t;
+
+typedef struct H5D_io_info_t {
+ const H5D_t *dset; /* Pointer to dataset being operated on */
+#ifndef H5_HAVE_PARALLEL
+ const
+#endif /* H5_HAVE_PARALLEL */
+ H5D_dxpl_cache_t *dxpl_cache; /* Pointer to cached DXPL info */
+ hid_t raw_dxpl_id; /* Original DXPL ID */
+ hid_t md_dxpl_id; /* metadata dxpl needed for parallel HDF5 */
+#ifdef H5_HAVE_PARALLEL
+ MPI_Comm comm; /* MPI communicator for file */
+ hbool_t using_mpi_vfd; /* Whether the file is using an MPI-based VFD */
+ struct {
+ H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */
+ H5FD_mpio_collective_opt_t coll_opt_mode; /* Parallel transfer with independent IO or collective IO with this mode */
+ H5D_io_ops_t io_ops; /* I/O operation function pointers */
+ } orig;
+#endif /* H5_HAVE_PARALLEL */
+ H5D_storage_t *store; /* Dataset storage info */
+ H5D_layout_ops_t layout_ops; /* Dataset layout I/O operation function pointers */
+ H5D_io_ops_t io_ops; /* I/O operation function pointers */
+ H5D_io_op_type_t op_type;
+ union {
+ void *rbuf; /* Pointer to buffer for read */
+ const void *wbuf; /* Pointer to buffer to write */
+ } u;
+} H5D_io_info_t;
+
+
+/******************/
+/* Chunk typedefs */
+/******************/
+
+/* Typedef for chunked dataset index operation info */
+typedef struct H5D_chk_idx_info_t {
+ H5F_t *f; /* File pointer for operation */
+ hid_t dxpl_id; /* DXPL ID for operation */
+ const H5O_pline_t *pline; /* I/O pipeline info */
+ H5O_layout_chunk_t *layout; /* Chunk layout description */
+ H5O_storage_chunk_t *storage; /* Chunk storage description */
+} H5D_chk_idx_info_t;
+
+/*
+ * "Generic" chunk record. Each chunk is keyed by the minimum logical
+ * N-dimensional coordinates and the datatype size of the chunk.
+ * The fastest-varying dimension is assumed to reference individual bytes of
+ * the array, so a 100-element 1-D array of 4-byte integers would really be a
+ * 2-D array with the slow varying dimension of size 100 and the fast varying
+ * dimension of size 4 (the storage dimensionality has very little to do with
+ * the real dimensionality).
+ *
+ * The chunk's file address, filter mask and size on disk are not key values.
+ */
+typedef struct H5D_chunk_rec_t {
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Logical offset to start */
+ uint32_t nbytes; /* Size of stored data */
+ uint32_t filter_mask; /* Excluded filters */
+ haddr_t chunk_addr; /* Address of chunk in file */
+} H5D_chunk_rec_t;
+
+/*
+ * Common data exchange structure for indexed storage nodes. This structure is
+ * passed through the indexing layer to the methods for the objects
+ * to which the index points.
+ */
+typedef struct H5D_chunk_common_ud_t {
+ const H5O_layout_chunk_t *layout; /* Chunk layout description */
+ const H5O_storage_chunk_t *storage; /* Chunk storage description */
+ const hsize_t *scaled; /* Scaled coordinates for a chunk */
+} H5D_chunk_common_ud_t;
+
+/* B-tree callback info for various operations */
+typedef struct H5D_chunk_ud_t {
+ /* Downward */
+ H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */
+
+ /* Upward */
+ unsigned idx_hint; /* Index of chunk in cache, if present */
+ H5F_block_t chunk_block; /* Offset/length of chunk in file */
+ unsigned filter_mask; /* Excluded filters */
+ hbool_t new_unfilt_chunk; /* Whether the chunk just became unfiltered */
+ hsize_t chunk_idx; /* Chunk index for EA, FA indexing */
+} H5D_chunk_ud_t;
+
+/* Typedef for "generic" chunk callbacks */
+typedef int (*H5D_chunk_cb_func_t)(const H5D_chunk_rec_t *chunk_rec,
+ void *udata);
+
+/* Typedefs for chunk operations */
+typedef herr_t (*H5D_chunk_init_func_t)(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+typedef herr_t (*H5D_chunk_create_func_t)(const H5D_chk_idx_info_t *idx_info);
+typedef hbool_t (*H5D_chunk_is_space_alloc_func_t)(const H5O_storage_chunk_t *storage);
+typedef herr_t (*H5D_chunk_insert_func_t)(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+typedef herr_t (*H5D_chunk_get_addr_func_t)(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+typedef herr_t (*H5D_chunk_resize_func_t)(H5O_layout_chunk_t *layout);
+typedef int (*H5D_chunk_iterate_func_t)(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+typedef herr_t (*H5D_chunk_remove_func_t)(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+typedef herr_t (*H5D_chunk_delete_func_t)(const H5D_chk_idx_info_t *idx_info);
+typedef herr_t (*H5D_chunk_copy_setup_func_t)(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+typedef herr_t (*H5D_chunk_copy_shutdown_func_t)(H5O_storage_chunk_t *storage_src,
+ H5O_storage_chunk_t *storage_dst, hid_t dxpl_id);
+typedef herr_t (*H5D_chunk_size_func_t)(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *idx_size);
+typedef herr_t (*H5D_chunk_reset_func_t)(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+typedef herr_t (*H5D_chunk_dump_func_t)(const H5O_storage_chunk_t *storage,
+ FILE *stream);
+typedef herr_t (*H5D_chunk_dest_func_t)(const H5D_chk_idx_info_t *idx_info);
+
+/* Typedef for grouping chunk I/O routines */
+typedef struct H5D_chunk_ops_t {
+ hbool_t can_swim; /* Flag to indicate that the index supports SWMR access */
+ H5D_chunk_init_func_t init; /* Routine to initialize indexing information in memory */
+ H5D_chunk_create_func_t create; /* Routine to create chunk index */
+ H5D_chunk_is_space_alloc_func_t is_space_alloc; /* Query routine to determine if storage/index is allocated */
+ H5D_chunk_insert_func_t insert; /* Routine to insert a chunk into an index */
+ H5D_chunk_get_addr_func_t get_addr; /* Routine to retrieve address of chunk in file */
+ H5D_chunk_resize_func_t resize; /* Routine to update chunk index info after resizing dataset */
+ H5D_chunk_iterate_func_t iterate; /* Routine to iterate over chunks */
+ H5D_chunk_remove_func_t remove; /* Routine to remove a chunk from an index */
+ H5D_chunk_delete_func_t idx_delete; /* Routine to delete index & all chunks from file*/
+ H5D_chunk_copy_setup_func_t copy_setup; /* Routine to perform any necessary setup for copying chunks */
+ H5D_chunk_copy_shutdown_func_t copy_shutdown; /* Routine to perform any necessary shutdown for copying chunks */
+ H5D_chunk_size_func_t size; /* Routine to get size of indexing information */
+ H5D_chunk_reset_func_t reset; /* Routine to reset indexing information */
+ H5D_chunk_dump_func_t dump; /* Routine to dump indexing information */
+ H5D_chunk_dest_func_t dest; /* Routine to destroy indexing information in memory */
+} H5D_chunk_ops_t;
+
+/* Structure holding information about a chunk's selection for mapping */
+typedef struct H5D_chunk_info_t {
+ hsize_t index; /* "Index" of chunk in dataset */
+ uint32_t chunk_points; /* Number of elements selected in chunk */
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled coordinates of chunk (in file dataset's dataspace) */
+ H5S_t *fspace; /* Dataspace describing chunk & selection in it */
+ hbool_t fspace_shared; /* Indicate that the file space for a chunk is shared and shouldn't be freed */
+ H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */
+ hbool_t mspace_shared; /* Indicate that the memory space for a chunk is shared and shouldn't be freed */
+} H5D_chunk_info_t;
+
+/* Main structure holding the mapping between file chunks and memory */
+typedef struct H5D_chunk_map_t {
+ H5O_layout_t *layout; /* Dataset layout information*/
+ hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */
+
+ const H5S_t *file_space; /* Pointer to the file dataspace */
+ unsigned f_ndims; /* Number of dimensions for file dataspace */
+
+ const H5S_t *mem_space; /* Pointer to the memory dataspace */
+ H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */
+ H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */
+ unsigned m_ndims; /* Number of dimensions for memory dataspace */
+ H5S_sel_type msel_type; /* Selection type in memory */
+ H5S_sel_type fsel_type; /* Selection type in file */
+
+ H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */
+
+ H5S_t *single_space; /* Dataspace for single chunk */
+ H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */
+ hbool_t use_single; /* Whether I/O is on a single element */
+
+ hsize_t last_index; /* Index of last chunk operated on */
+ H5D_chunk_info_t *last_chunk_info; /* Pointer to last chunk's info */
+
+ hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */
+
+#ifdef H5_HAVE_PARALLEL
+ H5D_chunk_info_t **select_chunk; /* Store the information about whether this chunk is selected or not */
+#endif /* H5_HAVE_PARALLEL */
+} H5D_chunk_map_t;
+
+/* Cached information about a particular chunk */
+typedef struct H5D_chunk_cached_t {
+ hbool_t valid; /*whether cache info is valid*/
+ hsize_t scaled[H5O_LAYOUT_NDIMS]; /*scaled offset of chunk*/
+ haddr_t addr; /*file address of chunk */
+ uint32_t nbytes; /*size of stored data */
+ hsize_t chunk_idx; /*index of chunk in dataset */
+ unsigned filter_mask; /*excluded filters */
+} H5D_chunk_cached_t;
+
+/****************************/
+/* Virtual dataset typedefs */
+/****************************/
+
+/* List of files held open during refresh operations */
+typedef struct H5D_virtual_held_file_t {
+ H5F_t *file; /* Pointer to file held open */
+ struct H5D_virtual_held_file_t *next; /* Pointer to next node in list */
+} H5D_virtual_held_file_t;
+
+/* The raw data chunk cache */
+struct H5D_rdcc_ent_t; /* Forward declaration of struct used below */
+typedef struct H5D_rdcc_t {
+ struct {
+ unsigned ninits; /* Number of chunk creations */
+ unsigned nhits; /* Number of cache hits */
+ unsigned nmisses;/* Number of cache misses */
+ unsigned nflushes;/* Number of cache flushes */
+ } stats;
+ size_t nbytes_max; /* Maximum cached raw data in bytes */
+ size_t nslots; /* Number of chunk slots allocated */
+ double w0; /* Chunk preemption policy */
+ struct H5D_rdcc_ent_t *head; /* Head of doubly linked list */
+ struct H5D_rdcc_ent_t *tail; /* Tail of doubly linked list */
+ struct H5D_rdcc_ent_t *tmp_head; /* Head of temporary doubly linked list. Chunks on this list are not in the hash table (slot). The head entry is a sentinel (does not refer to an actual chunk). */
+ size_t nbytes_used; /* Current cached raw data in bytes */
+ int nused; /* Number of chunk slots in use */
+ H5D_chunk_cached_t last; /* Cached copy of last chunk information */
+ struct H5D_rdcc_ent_t **slot; /* Chunk slots, each points to a chunk*/
+ H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */
+ H5S_t *single_space; /* Dataspace for single element I/O on chunks */
+ H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */
+
+ /* Cached information about scaled dataspace dimensions */
+ hsize_t scaled_dims[H5S_MAX_RANK]; /* The scaled dim sizes */
+ hsize_t scaled_power2up[H5S_MAX_RANK]; /* The scaled dim sizes, rounded up to next power of 2 */
+ unsigned scaled_encode_bits[H5S_MAX_RANK]; /* The number of bits needed to encode the scaled dim sizes */
+} H5D_rdcc_t;
+
+/* The raw data contiguous data cache */
+typedef struct H5D_rdcdc_t {
+ unsigned char *sieve_buf; /* Buffer to hold data sieve buffer */
+ haddr_t sieve_loc; /* File location (offset) of the data sieve buffer */
+ size_t sieve_size; /* Size of the data sieve buffer used (in bytes) */
+ size_t sieve_buf_size; /* Size of the data sieve buffer allocated (in bytes) */
+ hbool_t sieve_dirty; /* Flag to indicate that the data sieve buffer is dirty */
+} H5D_rdcdc_t;
+
+/*
+ * A dataset is made of two layers, an H5D_t struct that is unique to
+ * each instance of an opened datset, and a shared struct that is only
+ * created once for a given dataset. Thus, if a dataset is opened twice,
+ * there will be two IDs and two H5D_t structs, both sharing one H5D_shared_t.
+ */
+typedef struct H5D_shared_t {
+ size_t fo_count; /* Reference count */
+ hbool_t closing; /* Flag to indicate dataset is closing */
+ hid_t type_id; /* ID for dataset's datatype */
+ H5T_t *type; /* Datatype for this dataset */
+ H5S_t *space; /* Dataspace of this dataset */
+ hid_t dcpl_id; /* Dataset creation property id */
+ H5D_dcpl_cache_t dcpl_cache; /* Cached DCPL values */
+ H5O_layout_t layout; /* Data layout */
+ hbool_t checked_filters;/* TRUE if dataset passes can_apply check */
+
+ /* Cached dataspace info */
+ unsigned ndims; /* The dataset's dataspace rank */
+ hsize_t curr_dims[H5S_MAX_RANK]; /* The curr. size of dataset dimensions */
+ hsize_t curr_power2up[H5S_MAX_RANK]; /* The curr. dim sizes, rounded up to next power of 2 */
+ hsize_t max_dims[H5S_MAX_RANK]; /* The max. size of dataset dimensions */
+
+ /* Buffered/cached information for types of raw data storage*/
+ struct {
+ H5D_rdcdc_t contig; /* Information about contiguous data */
+ /* (Note that the "contig" cache
+ * information can be used by a chunked
+ * dataset in certain circumstances)
+ */
+ H5D_rdcc_t chunk; /* Information about chunked data */
+ } cache;
+
+ H5D_append_flush_t append_flush; /* Append flush property information */
+ char *extfile_prefix; /* expanded external file prefix */
+} H5D_shared_t;
+
+struct H5D_t {
+ H5O_loc_t oloc; /* Object header location */
+ H5G_name_t path; /* Group hierarchy path */
+ H5D_shared_t *shared; /* cached information from file */
+};
+
+/* Enumerated type for allocating dataset's storage */
+typedef enum {
+ H5D_ALLOC_CREATE, /* Dataset is being created */
+ H5D_ALLOC_OPEN, /* Dataset is being opened */
+ H5D_ALLOC_EXTEND, /* Dataset's dataspace is being extended */
+ H5D_ALLOC_WRITE /* Dataset is being extended */
+} H5D_time_alloc_t;
+
+
+/* Typedef for dataset creation operation */
+typedef struct {
+ hid_t type_id; /* Datatype for dataset */
+ const H5S_t *space; /* Dataspace for dataset */
+ hid_t dcpl_id; /* Dataset creation property list */
+ hid_t dapl_id; /* Dataset access property list */
+} H5D_obj_create_t;
+
+/* Typedef for filling a buffer with a fill value */
+typedef struct H5D_fill_buf_info_t {
+ H5MM_allocate_t fill_alloc_func; /* Routine to call for allocating fill buffer */
+ void *fill_alloc_info; /* Extra info for allocation routine */
+ H5MM_free_t fill_free_func; /* Routine to call for freeing fill buffer */
+ void *fill_free_info; /* Extra info for free routine */
+ H5T_path_t *fill_to_mem_tpath; /* Datatype conversion path for converting the fill value to the memory buffer */
+ H5T_path_t *mem_to_dset_tpath; /* Datatype conversion path for converting the memory buffer to the dataset elements */
+ const H5O_fill_t *fill; /* Pointer to fill value */
+ void *fill_buf; /* Fill buffer */
+ size_t fill_buf_size; /* Size of fill buffer */
+ hbool_t use_caller_fill_buf; /* Whether the caller provided the fill buffer */
+ void *bkg_buf; /* Background conversion buffer */
+ size_t bkg_buf_size; /* Size of background buffer */
+ H5T_t *mem_type; /* Pointer to memory datatype */
+ const H5T_t *file_type; /* Pointer to file datatype */
+ hid_t mem_tid; /* ID for memory version of disk datatype */
+ hid_t file_tid; /* ID for disk datatype */
+ size_t mem_elmt_size, file_elmt_size; /* Size of element in memory and on disk */
+ size_t max_elmt_size; /* Max. size of memory or file datatype */
+ size_t elmts_per_buf; /* # of elements that fit into a buffer */
+ hbool_t has_vlen_fill_type; /* Whether the datatype for the fill value has a variable-length component */
+} H5D_fill_buf_info_t;
+
+/* Internal data structure for computing variable-length dataset's total size */
+typedef struct {
+ H5D_t *dset; /* Dataset for operation */
+ H5S_t *fspace; /* Dataset's dataspace for operation */
+ H5S_t *mspace; /* Memory dataspace for operation */
+ void *fl_tbuf; /* Ptr to the temporary buffer we are using for fixed-length data */
+ void *vl_tbuf; /* Ptr to the temporary buffer we are using for VL data */
+ hid_t xfer_pid; /* ID of the dataset xfer property list */
+ hsize_t size; /* Accumulated number of bytes for the selection */
+} H5D_vlen_bufsize_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+extern H5D_dxpl_cache_t H5D_def_dxpl_cache;
+
+/* Storage layout class I/O operations */
+H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_CONTIG[1];
+H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_EFL[1];
+H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_COMPACT[1];
+H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_CHUNK[1];
+H5_DLLVAR const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1];
+
+/* Chunked layout operations */
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_BTREE[1];
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_NONE[1];
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_SINGLE[1];
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_EARRAY[1];
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_FARRAY[1];
+H5_DLLVAR const H5D_chunk_ops_t H5D_COPS_BT2[1];
+
+/* The v2 B-tree class for indexing chunked datasets with >1 unlimited dimensions */
+H5_DLLVAR const H5B2_class_t H5D_BT2[1];
+H5_DLLVAR const H5B2_class_t H5D_BT2_FILT[1];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+H5_DLL H5D_t *H5D__create(H5F_t *file, hid_t type_id, const H5S_t *space,
+ hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id);
+H5_DLL H5D_t *H5D__create_named(const H5G_loc_t *loc, const char *name,
+ hid_t type_id, const H5S_t *space, hid_t lcpl_id, hid_t dcpl_id,
+ hid_t dapl_id, hid_t dxpl_id);
+H5_DLL H5D_t *H5D__open_name(const H5G_loc_t *loc, const char *name,
+ hid_t dapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5D__get_space_status(H5D_t *dset, H5D_space_status_t *allocation,
+ hid_t dxpl_id);
+H5_DLL herr_t H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc,
+ hbool_t full_overwrite, hsize_t old_dim[]);
+H5_DLL herr_t H5D__get_storage_size(H5D_t *dset, hid_t dxpl_id, hsize_t *storage_size);
+H5_DLL haddr_t H5D__get_offset(const H5D_t *dset);
+H5_DLL void *H5D__vlen_get_buf_size_alloc(size_t size, void *info);
+H5_DLL herr_t H5D__vlen_get_buf_size(void *elem, hid_t type_id, unsigned ndim,
+ const hsize_t *point, void *op_data);
+H5_DLL herr_t H5D__check_filters(H5D_t *dataset);
+H5_DLL herr_t H5D__set_extent(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id);
+H5_DLL herr_t H5D__get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache);
+H5_DLL herr_t H5D__flush_sieve_buf(H5D_t *dataset, hid_t dxpl_id);
+H5_DLL herr_t H5D__flush_real(H5D_t *dataset, hid_t dxpl_id);
+H5_DLL herr_t H5D__mark(const H5D_t *dataset, hid_t dxpl_id, unsigned flags);
+H5_DLL herr_t H5D__refresh(hid_t dset_id, H5D_t *dataset, hid_t dxpl_id);
+#ifdef H5_DEBUG_BUILD
+H5_DLL herr_t H5D_set_io_info_dxpls(H5D_io_info_t *io_info, hid_t dxpl_id);
+#endif /* H5_DEBUG_BUILD */
+
+/* To convert a dataset's chunk indexing type to v1 B-tree */
+H5_DLL herr_t H5D__format_convert(H5D_t *dataset, hid_t dxpl_id);
+
+/* Internal I/O routines */
+H5_DLL herr_t H5D__read(H5D_t *dataset, hid_t mem_type_id,
+ const H5S_t *mem_space, const H5S_t *file_space, hid_t dset_xfer_plist,
+ void *buf/*out*/);
+H5_DLL herr_t H5D__write(H5D_t *dataset, hid_t mem_type_id,
+ const H5S_t *mem_space, const H5S_t *file_space, hid_t dset_xfer_plist,
+ const void *buf);
+
+/* Functions that perform direct serial I/O operations */
+H5_DLL herr_t H5D__select_read(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+H5_DLL herr_t H5D__select_write(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+/* Functions that perform scatter-gather serial I/O operations */
+H5_DLL herr_t H5D__scatter_mem(const void *_tscat_buf,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ const H5D_dxpl_cache_t *dxpl_cache, void *_buf);
+H5_DLL herr_t H5D__scatgath_read(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+H5_DLL herr_t H5D__scatgath_write(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+/* Functions that operate on dataset's layout information */
+H5_DLL herr_t H5D__layout_set_io_ops(const H5D_t *dataset);
+H5_DLL size_t H5D__layout_meta_size(const H5F_t *f, const H5O_layout_t *layout,
+ hbool_t include_compact_data);
+H5_DLL herr_t H5D__layout_set_latest_version(H5O_layout_t *layout,
+ const H5S_t *space, const H5D_dcpl_cache_t *dcpl_cache);
+H5_DLL herr_t H5D__layout_set_latest_indexing(H5O_layout_t *layout,
+ const H5S_t *space, const H5D_dcpl_cache_t *dcpl_cache);
+H5_DLL herr_t H5D__layout_oh_create(H5F_t *file, hid_t dxpl_id, H5O_t *oh,
+ H5D_t *dset, hid_t dapl_id);
+H5_DLL herr_t H5D__layout_oh_read(H5D_t *dset, hid_t dxpl_id, hid_t dapl_id,
+ H5P_genplist_t *plist);
+H5_DLL herr_t H5D__layout_oh_write(H5D_t *dataset, hid_t dxpl_id, H5O_t *oh,
+ unsigned update_flags);
+
+/* Functions that operate on contiguous storage */
+H5_DLL herr_t H5D__contig_alloc(H5F_t *f, hid_t dxpl_id,
+ H5O_storage_contig_t *storage);
+H5_DLL hbool_t H5D__contig_is_space_alloc(const H5O_storage_t *storage);
+H5_DLL herr_t H5D__contig_fill(const H5D_io_info_t *io_info);
+H5_DLL herr_t H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm);
+H5_DLL herr_t H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm);
+H5_DLL herr_t H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src,
+ H5F_t *f_dst, H5O_storage_contig_t *storage_dst, H5T_t *src_dtype,
+ H5O_copy_t *cpy_info, hid_t dxpl_id);
+H5_DLL herr_t H5D__contig_delete(H5F_t *f, hid_t dxpl_id,
+ const H5O_storage_t *store);
+
+/* Functions that operate on chunked dataset storage */
+H5_DLL htri_t H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr,
+ hbool_t write_op);
+H5_DLL herr_t H5D__chunk_create(const H5D_t *dset /*in,out*/, hid_t dxpl_id);
+H5_DLL herr_t H5D__chunk_set_info(const H5D_t *dset);
+H5_DLL hbool_t H5D__chunk_is_space_alloc(const H5O_storage_t *storage);
+H5_DLL herr_t H5D__chunk_lookup(const H5D_t *dset, hid_t dxpl_id,
+ const hsize_t *scaled, H5D_chunk_ud_t *udata);
+H5_DLL herr_t H5D__chunk_allocated(H5D_t *dset, hid_t dxpl_id, hsize_t *nbytes);
+H5_DLL herr_t H5D__chunk_allocate(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[]);
+H5_DLL herr_t H5D__chunk_update_old_edge_chunks(H5D_t *dset, hid_t dxpl_id,
+ hsize_t old_dim[]);
+H5_DLL herr_t H5D__chunk_prune_by_extent(H5D_t *dset, hid_t dxpl_id,
+ const hsize_t *old_dim);
+H5_DLL herr_t H5D__chunk_set_sizes(H5D_t *dset);
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[]);
+#endif /* H5_HAVE_PARALLEL */
+H5_DLL herr_t H5D__chunk_update_cache(H5D_t *dset, hid_t dxpl_id);
+H5_DLL herr_t H5D__chunk_copy(H5F_t *f_src, H5O_storage_chunk_t *storage_src,
+ H5O_layout_chunk_t *layout_src, H5F_t *f_dst, H5O_storage_chunk_t *storage_dst,
+ const H5S_extent_t *ds_extent_src, const H5T_t *dt_src,
+ const H5O_pline_t *pline_src, H5O_copy_t *cpy_info, hid_t dxpl_id);
+H5_DLL herr_t H5D__chunk_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh,
+ H5O_layout_t *layout, hsize_t *btree_size);
+H5_DLL herr_t H5D__chunk_dump_index(H5D_t *dset, hid_t dxpl_id, FILE *stream);
+H5_DLL herr_t H5D__chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ H5O_storage_t *store);
+H5_DLL herr_t H5D__chunk_direct_write(const H5D_t *dset, hid_t dxpl_id, uint32_t filters,
+ hsize_t *offset, uint32_t data_size, const void *buf);
+#ifdef H5D_CHUNK_DEBUG
+H5_DLL herr_t H5D__chunk_stats(const H5D_t *dset, hbool_t headers);
+#endif /* H5D_CHUNK_DEBUG */
+
+/* format convert */
+H5_DLL herr_t H5D__chunk_format_convert(H5D_t *dset, H5D_chk_idx_info_t *idx_info, H5D_chk_idx_info_t *new_idx_info);
+
+/* Functions that operate on compact dataset storage */
+H5_DLL herr_t H5D__compact_fill(const H5D_t *dset, hid_t dxpl_id);
+H5_DLL herr_t H5D__compact_copy(H5F_t *f_src, H5O_storage_compact_t *storage_src,
+ H5F_t *f_dst, H5O_storage_compact_t *storage_dst, H5T_t *src_dtype,
+ H5O_copy_t *cpy_info, hid_t dxpl_id);
+
+/* Functions that operate on virtual dataset storage */
+H5_DLL herr_t H5D__virtual_copy_layout(H5O_layout_t *layout);
+H5_DLL herr_t H5D__virtual_set_extent_unlim(const H5D_t *dset, hid_t dxpl_id);
+H5_DLL herr_t H5D__virtual_reset_layout(H5O_layout_t *layout);
+H5_DLL herr_t H5D__virtual_delete(H5F_t *f, hid_t dxpl_id, H5O_storage_t *storage);
+H5_DLL herr_t H5D__virtual_copy(H5F_t *f_src, H5O_layout_t *layout_dst,
+ hid_t dxpl_id);
+H5_DLL herr_t H5D__virtual_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset,
+ hid_t dapl_id);
+H5_DLL hbool_t H5D__virtual_is_space_alloc(const H5O_storage_t *storage);
+H5_DLL herr_t H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head);
+H5_DLL herr_t H5D__virtual_refresh_source_dsets(H5D_t *dset, hid_t dxpl_id);
+H5_DLL herr_t H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head);
+
+/* Functions that operate on EFL (External File List)*/
+H5_DLL hbool_t H5D__efl_is_space_alloc(const H5O_storage_t *storage);
+H5_DLL herr_t H5D__efl_bh_info(H5F_t *f, hid_t dxpl_id, H5O_efl_t *efl,
+ hsize_t *heap_size);
+
+/* Functions that perform fill value operations on datasets */
+H5_DLL herr_t H5D__fill(const void *fill, const H5T_t *fill_type, void *buf,
+ const H5T_t *buf_type, const H5S_t *space, hid_t dxpl_id);
+H5_DLL herr_t H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf,
+ H5MM_allocate_t alloc_func, void *alloc_info,
+ H5MM_free_t free_func, void *free_info,
+ const H5O_fill_t *fill, const H5T_t *dset_type, hid_t dset_type_id,
+ size_t nelmts, size_t min_buf_size, hid_t dxpl_id);
+H5_DLL herr_t H5D__fill_refill_vl(H5D_fill_buf_info_t *fb_info, size_t nelmts, hid_t dxpl_id);
+H5_DLL herr_t H5D__fill_term(H5D_fill_buf_info_t *fb_info);
+
+#ifdef H5_HAVE_PARALLEL
+
+#ifdef H5S_DEBUG
+#ifndef H5Dmpio_DEBUG
+#define H5Dmpio_DEBUG
+#endif /*H5Dmpio_DEBUG*/
+#endif/*H5S_DEBUG*/
+/* MPI-IO function to read, it will select either regular or irregular read */
+H5_DLL herr_t H5D__mpio_select_read(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+/* MPI-IO function to write, it will select either regular or irregular read */
+H5_DLL herr_t H5D__mpio_select_write(const H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+/* MPI-IO functions to handle contiguous collective IO */
+H5_DLL herr_t H5D__contig_collective_read(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+H5_DLL herr_t H5D__contig_collective_write(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+
+/* MPI-IO functions to handle chunked collective IO */
+H5_DLL herr_t H5D__chunk_collective_read(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+H5_DLL herr_t H5D__chunk_collective_write(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+
+/* MPI-IO function to check if a direct I/O transfer is possible between
+ * memory and the file */
+H5_DLL htri_t H5D__mpio_opt_possible(const H5D_io_info_t *io_info,
+ const H5S_t *file_space, const H5S_t *mem_space,
+ const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm,
+ H5P_genplist_t *dx_plist);
+
+#endif /* H5_HAVE_PARALLEL */
+
+/* Testing functions */
+#ifdef H5D_TESTING
+H5_DLL herr_t H5D__layout_version_test(hid_t did, unsigned *version);
+H5_DLL herr_t H5D__layout_contig_size_test(hid_t did, hsize_t *size);
+H5_DLL herr_t H5D__layout_idx_type_test(hid_t did, H5D_chunk_index_t *idx_type);
+H5_DLL herr_t H5D__layout_type_test(hid_t did, H5D_layout_t *layout_type);
+H5_DLL herr_t H5D__current_cache_size_test(hid_t did, size_t *nbytes_used, int *nused);
+#endif /* H5D_TESTING */
+
+#endif /*_H5Dpkg_H*/
+
diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h
new file mode 100644
index 0000000..5d565bb
--- /dev/null
+++ b/src/H5Dprivate.h
@@ -0,0 +1,209 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5D module
+ */
+#ifndef _H5Dprivate_H
+#define _H5Dprivate_H
+
+/* Include package's public header */
+#include "H5Dpublic.h"
+
+/* Private headers needed by this file */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5Zprivate.h" /* Data filters */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/*
+ * Feature: Define H5D_DEBUG on the compiler command line if you want to
+ * debug dataset I/O. NDEBUG must not be defined in order for this
+ * to have any effect.
+ */
+#ifdef NDEBUG
+# undef H5D_DEBUG
+#endif
+
+/* ======== Dataset creation property names ======== */
+#define H5D_CRT_LAYOUT_NAME "layout" /* Storage layout */
+#define H5D_CRT_FILL_VALUE_NAME "fill_value" /* Fill value */
+#define H5D_CRT_ALLOC_TIME_STATE_NAME "alloc_time_state" /* Space allocation time state */
+#define H5D_CRT_EXT_FILE_LIST_NAME "efl" /* External file list */
+
+/* ======== Dataset access property names ======== */
+#define H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME "rdcc_nslots" /* Size of raw data chunk cache(slots) */
+#define H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME "rdcc_nbytes" /* Size of raw data chunk cache(bytes) */
+#define H5D_ACS_PREEMPT_READ_CHUNKS_NAME "rdcc_w0" /* Preemption read chunks first */
+#define H5D_ACS_VDS_VIEW_NAME "vds_view" /* VDS view option */
+#define H5D_ACS_VDS_PRINTF_GAP_NAME "vds_printf_gap" /* VDS printf gap size */
+#define H5D_ACS_APPEND_FLUSH_NAME "append_flush" /* Append flush actions */
+#define H5D_ACS_EFILE_PREFIX_NAME "external file prefix" /* External file prefix */
+
+/* ======== Data transfer properties ======== */
+#define H5D_XFER_MAX_TEMP_BUF_NAME "max_temp_buf" /* Maximum temp buffer size */
+#define H5D_XFER_TCONV_BUF_NAME "tconv_buf" /* Type conversion buffer */
+#define H5D_XFER_BKGR_BUF_NAME "bkgr_buf" /* Background buffer */
+#define H5D_XFER_BKGR_BUF_TYPE_NAME "bkgr_buf_type" /* Background buffer type */
+#define H5D_XFER_BTREE_SPLIT_RATIO_NAME "btree_split_ratio" /* B-tree node splitting ratio */
+#define H5D_XFER_VLEN_ALLOC_NAME "vlen_alloc" /* Vlen allocation function */
+#define H5D_XFER_VLEN_ALLOC_INFO_NAME "vlen_alloc_info" /* Vlen allocation info */
+#define H5D_XFER_VLEN_FREE_NAME "vlen_free" /* Vlen free function */
+#define H5D_XFER_VLEN_FREE_INFO_NAME "vlen_free_info" /* Vlen free info */
+#define H5D_XFER_VFL_ID_NAME "vfl_id" /* File driver ID */
+#define H5D_XFER_VFL_INFO_NAME "vfl_info" /* File driver info */
+#define H5D_XFER_HYPER_VECTOR_SIZE_NAME "vec_size" /* Hyperslab vector size */
+#define H5D_XFER_IO_XFER_MODE_NAME "io_xfer_mode" /* I/O transfer mode */
+#define H5D_XFER_MPIO_COLLECTIVE_OPT_NAME "mpio_collective_opt" /* Optimization of MPI-IO transfer mode */
+#define H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME "mpio_chunk_opt_hard"
+#define H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME "mpio_chunk_opt_num"
+#define H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME "mpio_chunk_opt_ratio"
+#define H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME "actual_chunk_opt_mode"
+#define H5D_MPIO_ACTUAL_IO_MODE_NAME "actual_io_mode"
+#define H5D_MPIO_LOCAL_NO_COLLECTIVE_CAUSE_NAME "local_no_collective_cause" /* cause of broken collective I/O in each process */
+#define H5D_MPIO_GLOBAL_NO_COLLECTIVE_CAUSE_NAME "global_no_collective_cause" /* cause of broken collective I/O in all processes */
+#define H5D_XFER_EDC_NAME "err_detect" /* EDC */
+#define H5D_XFER_FILTER_CB_NAME "filter_cb" /* Filter callback function */
+#define H5D_XFER_CONV_CB_NAME "type_conv_cb" /* Type conversion callback function */
+#define H5D_XFER_XFORM_NAME "data_transform" /* Data transform */
+#ifdef H5_HAVE_INSTRUMENTED_LIBRARY
+/* Collective chunk instrumentation properties */
+#define H5D_XFER_COLL_CHUNK_LINK_HARD_NAME "coll_chunk_link_hard"
+#define H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME "coll_chunk_multi_hard"
+#define H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME "coll_chunk_link_true"
+#define H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME "coll_chunk_link_false"
+#define H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME "coll_chunk_multi_coll"
+#define H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME "coll_chunk_multi_ind"
+
+/* Definitions for all collective chunk instrumentation properties */
+#define H5D_XFER_COLL_CHUNK_SIZE sizeof(unsigned)
+#define H5D_XFER_COLL_CHUNK_DEF 1
+#define H5D_XFER_COLL_CHUNK_FIX 0
+#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */
+
+/* Default temporary buffer size */
+#define H5D_TEMP_BUF_SIZE (1024 * 1024)
+
+/* Default I/O vector size */
+#define H5D_IO_VECTOR_SIZE 1024
+
+/* Default VL allocation & free info */
+#define H5D_VLEN_ALLOC NULL
+#define H5D_VLEN_ALLOC_INFO NULL
+#define H5D_VLEN_FREE NULL
+#define H5D_VLEN_FREE_INFO NULL
+
+/* Default virtual dataset list size */
+#define H5D_VIRTUAL_DEF_LIST_SIZE 8
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Typedef for dataset in memory (defined in H5Dpkg.h) */
+typedef struct H5D_t H5D_t;
+
+/* Typedef for cached dataset transfer property list information */
+typedef struct H5D_dxpl_cache_t {
+ size_t max_temp_buf; /* Maximum temporary buffer size (H5D_XFER_MAX_TEMP_BUF_NAME) */
+ void *tconv_buf; /* Temporary conversion buffer (H5D_XFER_TCONV_BUF_NAME) */
+ void *bkgr_buf; /* Background conversion buffer (H5D_XFER_BKGR_BUF_NAME) */
+ H5T_bkg_t bkgr_buf_type; /* Background buffer type (H5D_XFER_BKGR_BUF_NAME) */
+ H5Z_EDC_t err_detect; /* Error detection info (H5D_XFER_EDC_NAME) */
+ double btree_split_ratio[3];/* B-tree split ratios (H5D_XFER_BTREE_SPLIT_RATIO_NAME) */
+ size_t vec_size; /* Size of hyperslab vector (H5D_XFER_HYPER_VECTOR_SIZE_NAME) */
+#ifdef H5_HAVE_PARALLEL
+ H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request (H5D_XFER_IO_XFER_MODE_NAME) */
+ H5FD_mpio_collective_opt_t coll_opt_mode; /* Parallel transfer with independent IO or collective IO with this mode */
+#endif /*H5_HAVE_PARALLEL*/
+ H5Z_cb_t filter_cb; /* Filter callback function (H5D_XFER_FILTER_CB_NAME) */
+ H5Z_data_xform_t *data_xform_prop; /* Data transform prop (H5D_XFER_XFORM_NAME) */
+} H5D_dxpl_cache_t;
+
+/* Typedef for cached dataset creation property list information */
+typedef struct H5D_dcpl_cache_t {
+ H5O_fill_t fill; /* Fill value info (H5D_CRT_FILL_VALUE_NAME) */
+ H5O_pline_t pline; /* I/O pipeline info (H5O_CRT_PIPELINE_NAME) */
+ H5O_efl_t efl; /* External file list info (H5D_CRT_EXT_FILE_LIST_NAME) */
+} H5D_dcpl_cache_t;
+
+/* Callback information for copying datasets */
+typedef struct H5D_copy_file_ud_t {
+ H5O_copy_file_ud_common_t common; /* Shared information (must be first) */
+ struct H5S_extent_t *src_space_extent; /* Copy of dataspace extent for dataset */
+ H5T_t *src_dtype; /* Copy of datatype for dataset */
+} H5D_copy_file_ud_t;
+
+/* Structure for dataset append flush property (H5Pset_append_flush) */
+typedef struct H5D_append_flush_t {
+ unsigned ndims; /* The # of dimensions for "boundary" */
+ hsize_t boundary[H5S_MAX_RANK]; /* The dimension sizes for determining boundary */
+ H5D_append_cb_t func; /* The callback function */
+ void *udata; /* User data */
+} H5D_append_flush_t;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Library Private Prototypes */
+/******************************/
+
+H5_DLL herr_t H5D_init(void);
+H5_DLL H5D_t *H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5D_close(H5D_t *dataset);
+H5_DLL herr_t H5D_mult_refresh_close(hid_t dset_id, hid_t dxpl_id);
+H5_DLL herr_t H5D_mult_refresh_reopen(H5D_t *dataset, hid_t dxpl_id);
+H5_DLL H5O_loc_t *H5D_oloc(H5D_t *dataset);
+H5_DLL H5G_name_t *H5D_nameof(H5D_t *dataset);
+H5_DLL H5T_t *H5D_typeof(const H5D_t *dset);
+H5_DLL herr_t H5D_flush(const H5F_t *f, hid_t dxpl_id);
+H5_DLL hid_t H5D_get_create_plist(H5D_t *dset);
+H5_DLL hid_t H5D_get_access_plist(H5D_t *dset);
+H5_DLL hid_t H5D_get_space(H5D_t *dset);
+H5_DLL hid_t H5D_get_type(H5D_t *dset);
+
+/* Functions that operate on vlen data */
+H5_DLL herr_t H5D_vlen_reclaim(hid_t type_id, H5S_t *space, hid_t plist_id,
+ void *buf);
+
+/* Functions that operate on chunked storage */
+H5_DLL herr_t H5D_chunk_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+
+/* Functions that operate on virtual storage */
+H5_DLL herr_t H5D_virtual_check_mapping_pre(const H5S_t *vspace,
+ const H5S_t *src_space, H5O_virtual_space_status_t space_status);
+H5_DLL herr_t H5D_virtual_check_mapping_post(
+ const H5O_storage_virtual_ent_t *ent);
+H5_DLL herr_t H5D_virtual_check_min_dims(const H5D_t *dset);
+H5_DLL herr_t H5D_virtual_update_min_dims(H5O_layout_t *layout, size_t idx);
+H5_DLL herr_t H5D_virtual_parse_source_name(const char *source_name,
+ H5O_storage_virtual_name_seg_t **parsed_name, size_t *static_strlen,
+ size_t *nsubs);
+H5_DLL herr_t H5D_virtual_free_parsed_name(H5O_storage_virtual_name_seg_t *name_seg);
+
+/* Functions that operate on indexed storage */
+H5_DLL herr_t H5D_btree_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream,
+ int indent, int fwidth, unsigned ndims, const uint32_t *dim);
+
+#endif /* _H5Dprivate_H */
+
diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h
new file mode 100644
index 0000000..fe408b2
--- /dev/null
+++ b/src/H5Dpublic.h
@@ -0,0 +1,198 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5D module.
+ */
+#ifndef _H5Dpublic_H
+#define _H5Dpublic_H
+
+/* System headers needed by this file */
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Ipublic.h"
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Macros used to "unset" chunk cache configuration parameters */
+#define H5D_CHUNK_CACHE_NSLOTS_DEFAULT ((size_t) -1)
+#define H5D_CHUNK_CACHE_NBYTES_DEFAULT ((size_t) -1)
+#define H5D_CHUNK_CACHE_W0_DEFAULT (-1.0f)
+
+/* Bit flags for the H5Pset_chunk_opts() and H5Pget_chunk_opts() */
+#define H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS (0x0002u)
+
+/* Property names for H5LTDdirect_chunk_write */
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_NAME "direct_chunk_flag"
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_NAME "direct_chunk_filters"
+#define H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_NAME "direct_chunk_offset"
+#define H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_NAME "direct_chunk_datasize"
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/* Values for the H5D_LAYOUT property */
+typedef enum H5D_layout_t {
+ H5D_LAYOUT_ERROR = -1,
+
+ H5D_COMPACT = 0, /*raw data is very small */
+ H5D_CONTIGUOUS = 1, /*the default */
+ H5D_CHUNKED = 2, /*slow and fancy */
+ H5D_VIRTUAL = 3, /*actual data is stored in other datasets */
+ H5D_NLAYOUTS = 4 /*this one must be last! */
+} H5D_layout_t;
+
+/* Types of chunk index data structures */
+typedef enum H5D_chunk_index_t {
+ H5D_CHUNK_IDX_BTREE = 0, /* v1 B-tree index (default) */
+ H5D_CHUNK_IDX_SINGLE = 1, /* Single Chunk index (cur dims[]=max dims[]=chunk dims[]; filtered & non-filtered) */
+ H5D_CHUNK_IDX_NONE = 2, /* Implicit: No Index (H5D_ALLOC_TIME_EARLY, non-filtered, fixed dims) */
+ H5D_CHUNK_IDX_FARRAY = 3, /* Fixed array (for 0 unlimited dims) */
+ H5D_CHUNK_IDX_EARRAY = 4, /* Extensible array (for 1 unlimited dim) */
+ H5D_CHUNK_IDX_BT2 = 5, /* v2 B-tree index (for >1 unlimited dims) */
+ H5D_CHUNK_IDX_NTYPES /* This one must be last! */
+} H5D_chunk_index_t;
+
+/* Values for the space allocation time property */
+typedef enum H5D_alloc_time_t {
+ H5D_ALLOC_TIME_ERROR = -1,
+ H5D_ALLOC_TIME_DEFAULT = 0,
+ H5D_ALLOC_TIME_EARLY = 1,
+ H5D_ALLOC_TIME_LATE = 2,
+ H5D_ALLOC_TIME_INCR = 3
+} H5D_alloc_time_t;
+
+/* Values for the status of space allocation */
+typedef enum H5D_space_status_t {
+ H5D_SPACE_STATUS_ERROR = -1,
+ H5D_SPACE_STATUS_NOT_ALLOCATED = 0,
+ H5D_SPACE_STATUS_PART_ALLOCATED = 1,
+ H5D_SPACE_STATUS_ALLOCATED = 2
+} H5D_space_status_t;
+
+/* Values for time of writing fill value property */
+typedef enum H5D_fill_time_t {
+ H5D_FILL_TIME_ERROR = -1,
+ H5D_FILL_TIME_ALLOC = 0,
+ H5D_FILL_TIME_NEVER = 1,
+ H5D_FILL_TIME_IFSET = 2
+} H5D_fill_time_t;
+
+/* Values for fill value status */
+typedef enum H5D_fill_value_t {
+ H5D_FILL_VALUE_ERROR =-1,
+ H5D_FILL_VALUE_UNDEFINED =0,
+ H5D_FILL_VALUE_DEFAULT =1,
+ H5D_FILL_VALUE_USER_DEFINED =2
+} H5D_fill_value_t;
+
+/* Values for VDS bounds option */
+typedef enum H5D_vds_view_t {
+ H5D_VDS_ERROR = -1,
+ H5D_VDS_FIRST_MISSING = 0,
+ H5D_VDS_LAST_AVAILABLE = 1
+} H5D_vds_view_t;
+
+/* Callback for H5Pset_append_flush() in a dataset access property list */
+typedef herr_t (*H5D_append_cb_t)(hid_t dataset_id, hsize_t *cur_dims, void *op_data);
+
+/********************/
+/* Public Variables */
+/********************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Define the operator function pointer for H5Diterate() */
+typedef herr_t (*H5D_operator_t)(void *elem, hid_t type_id, unsigned ndim,
+ const hsize_t *point, void *operator_data);
+
+/* Define the operator function pointer for H5Dscatter() */
+typedef herr_t (*H5D_scatter_func_t)(const void **src_buf/*out*/,
+ size_t *src_buf_bytes_used/*out*/,
+ void *op_data);
+
+/* Define the operator function pointer for H5Dgather() */
+typedef herr_t (*H5D_gather_func_t)(const void *dst_buf,
+ size_t dst_buf_bytes_used, void *op_data);
+
+H5_DLL hid_t H5Dcreate2(hid_t loc_id, const char *name, hid_t type_id,
+ hid_t space_id, hid_t lcpl_id, hid_t dcpl_id, hid_t dapl_id);
+H5_DLL hid_t H5Dcreate_anon(hid_t file_id, hid_t type_id, hid_t space_id,
+ hid_t plist_id, hid_t dapl_id);
+H5_DLL hid_t H5Dopen2(hid_t file_id, const char *name, hid_t dapl_id);
+H5_DLL herr_t H5Dclose(hid_t dset_id);
+H5_DLL hid_t H5Dget_space(hid_t dset_id);
+H5_DLL herr_t H5Dget_space_status(hid_t dset_id, H5D_space_status_t *allocation);
+H5_DLL hid_t H5Dget_type(hid_t dset_id);
+H5_DLL hid_t H5Dget_create_plist(hid_t dset_id);
+H5_DLL hid_t H5Dget_access_plist(hid_t dset_id);
+H5_DLL hsize_t H5Dget_storage_size(hid_t dset_id);
+H5_DLL haddr_t H5Dget_offset(hid_t dset_id);
+H5_DLL herr_t H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
+ hid_t file_space_id, hid_t plist_id, void *buf/*out*/);
+H5_DLL herr_t H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id,
+ hid_t file_space_id, hid_t plist_id, const void *buf);
+H5_DLL herr_t H5Diterate(void *buf, hid_t type_id, hid_t space_id,
+ H5D_operator_t op, void *operator_data);
+H5_DLL herr_t H5Dvlen_reclaim(hid_t type_id, hid_t space_id, hid_t plist_id, void *buf);
+H5_DLL herr_t H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_id, hsize_t *size);
+H5_DLL herr_t H5Dfill(const void *fill, hid_t fill_type, void *buf,
+ hid_t buf_type, hid_t space);
+H5_DLL herr_t H5Dset_extent(hid_t dset_id, const hsize_t size[]);
+H5_DLL herr_t H5Dflush(hid_t dset_id);
+H5_DLL herr_t H5Drefresh(hid_t dset_id);
+H5_DLL herr_t H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id,
+ hid_t dst_space_id, void *dst_buf);
+H5_DLL herr_t H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id,
+ size_t dst_buf_size, void *dst_buf, H5D_gather_func_t op, void *op_data);
+H5_DLL herr_t H5Ddebug(hid_t dset_id);
+
+/* Internal API routines */
+H5_DLL herr_t H5Dformat_convert(hid_t dset_id);
+H5_DLL herr_t H5Dget_chunk_index_type(hid_t did, H5D_chunk_index_t *idx_type);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+#define H5D_CHUNK_BTREE H5D_CHUNK_IDX_BTREE
+
+
+/* Typedefs */
+
+
+/* Function prototypes */
+H5_DLL hid_t H5Dcreate1(hid_t file_id, const char *name, hid_t type_id,
+ hid_t space_id, hid_t dcpl_id);
+H5_DLL hid_t H5Dopen1(hid_t file_id, const char *name);
+H5_DLL herr_t H5Dextend(hid_t dset_id, const hsize_t size[]);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Dpublic_H */
+
diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c
new file mode 100644
index 0000000..4625c7a
--- /dev/null
+++ b/src/H5Dscatgath.c
@@ -0,0 +1,1106 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5D__scatter_file(const H5D_io_info_t *io_info,
+ const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts,
+ const void *buf);
+static size_t H5D__gather_file(const H5D_io_info_t *io_info,
+ const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts,
+ void *buf);
+static size_t H5D__gather_mem(const void *_buf,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ const H5D_dxpl_cache_t *dxpl_cache, void *_tgath_buf/*out*/);
+static herr_t H5D__compound_opt_read(size_t nelmts, const H5S_t *mem_space,
+ H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache,
+ const H5D_type_info_t *type_info, void *user_buf/*out*/);
+static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
+/* Declare extern free list to manage sequences of size_t */
+H5FL_SEQ_EXTERN(size_t);
+
+/* Declare extern free list to manage sequences of hsize_t */
+H5FL_SEQ_EXTERN(hsize_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__scatter_file
+ *
+ * Purpose: Scatters dataset elements from the type conversion buffer BUF
+ * to the file F where the data points are arranged according to
+ * the file dataspace FILE_SPACE and stored according to
+ * LAYOUT and EFL. Each element is ELMT_SIZE bytes.
+ * The caller is requesting that NELMTS elements are copied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__scatter_file(const H5D_io_info_t *_io_info,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ const void *_buf)
+{
+ H5D_io_info_t tmp_io_info; /* Temporary I/O info object */
+ hsize_t *off = NULL; /* Pointer to sequence offsets */
+ hsize_t mem_off; /* Offset in memory */
+ size_t mem_curr_seq; /* "Current sequence" in memory */
+ size_t dset_curr_seq; /* "Current sequence" in dataset */
+ size_t *len = NULL; /* Array to store sequence lengths */
+ size_t orig_mem_len, mem_len; /* Length of sequence in memory */
+ size_t nseq; /* Number of sequences generated */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t vec_size; /* Vector length */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(_io_info);
+ HDassert(space);
+ HDassert(iter);
+ HDassert(nelmts > 0);
+ HDassert(_buf);
+
+ /* Set up temporary I/O info object */
+ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
+ tmp_io_info.op_type = H5D_IO_OP_WRITE;
+ tmp_io_info.u.wbuf = _buf;
+
+ /* Allocate the vector I/O arrays */
+ if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = tmp_io_info.dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
+
+ /* Loop until all elements are written */
+ while(nelmts > 0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Reset the current sequence information */
+ mem_curr_seq = dset_curr_seq = 0;
+ orig_mem_len = mem_len = nelem * iter->elmt_size;
+ mem_off = 0;
+
+ /* Write sequence list out */
+ if((*tmp_io_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq,
+ len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
+
+ /* Update buffer */
+ tmp_io_info.u.wbuf = (const uint8_t *)tmp_io_info.u.wbuf + orig_mem_len;
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__scatter_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__gather_file
+ *
+ * Purpose: Gathers data points from file F and accumulates them in the
+ * type conversion buffer BUF. The LAYOUT argument describes
+ * how the data is stored on disk and EFL describes how the data
+ * is organized in external files. ELMT_SIZE is the size in
+ * bytes of a datum which this function treats as opaque.
+ * FILE_SPACE describes the dataspace of the dataset on disk
+ * and the elements that have been selected for reading (via
+ * hyperslab, etc). This function will copy at most NELMTS
+ * elements.
+ *
+ * Return: Success: Number of elements copied.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 24, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5D__gather_file(const H5D_io_info_t *_io_info,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ void *_buf/*out*/)
+{
+ H5D_io_info_t tmp_io_info; /* Temporary I/O info object */
+ hsize_t *off = NULL; /* Pointer to sequence offsets */
+ hsize_t mem_off; /* Offset in memory */
+ size_t mem_curr_seq; /* "Current sequence" in memory */
+ size_t dset_curr_seq; /* "Current sequence" in dataset */
+ size_t *len = NULL; /* Pointer to sequence lengths */
+ size_t orig_mem_len, mem_len; /* Length of sequence in memory */
+ size_t nseq; /* Number of sequences generated */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t vec_size; /* Vector length */
+ size_t ret_value = nelmts; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(_io_info);
+ HDassert(_io_info->dset);
+ HDassert(_io_info->store);
+ HDassert(space);
+ HDassert(iter);
+ HDassert(nelmts > 0);
+ HDassert(_buf);
+
+ /* Set up temporary I/O info object */
+ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
+ tmp_io_info.op_type = H5D_IO_OP_READ;
+ tmp_io_info.u.rbuf = _buf;
+
+ /* Allocate the vector I/O arrays */
+ if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = tmp_io_info.dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array")
+
+ /* Loop until all elements are read */
+ while(nelmts > 0) {
+ /* Get list of sequences for selection to read */
+ if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
+
+ /* Reset the current sequence information */
+ mem_curr_seq = dset_curr_seq = 0;
+ orig_mem_len = mem_len = nelem * iter->elmt_size;
+ mem_off = 0;
+
+ /* Read sequence list in */
+ if((*tmp_io_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq,
+ len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error")
+
+ /* Update buffer */
+ tmp_io_info.u.rbuf = (uint8_t *)tmp_io_info.u.rbuf + orig_mem_len;
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__gather_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__scatter_mem
+ *
+ * Purpose: Scatters NELMTS data points from the scatter buffer
+ * TSCAT_BUF to the application buffer BUF. Each element is
+ * ELMT_SIZE bytes and they are organized in application memory
+ * according to SPACE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 8, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__scatter_mem (const void *_tscat_buf, const H5S_t *space,
+ H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache,
+ void *_buf/*out*/)
+{
+ uint8_t *buf = (uint8_t *)_buf; /* Get local copies for address arithmetic */
+ const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf;
+ hsize_t *off = NULL; /* Pointer to sequence offsets */
+ size_t *len = NULL; /* Pointer to sequence lengths */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t vec_size; /* Vector length */
+ herr_t ret_value = SUCCEED; /* Number of elements scattered */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(tscat_buf);
+ HDassert(space);
+ HDassert(iter);
+ HDassert(nelmts > 0);
+ HDassert(buf);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
+
+ /* Loop until all elements are written */
+ while(nelmts > 0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
+
+ /* Loop, while sequences left to process */
+ for(curr_seq = 0; curr_seq < nseq; curr_seq++) {
+ /* Get the number of bytes in sequence */
+ curr_len = len[curr_seq];
+
+ HDmemcpy(buf + off[curr_seq], tscat_buf, curr_len);
+
+ /* Advance offset in destination buffer */
+ tscat_buf += curr_len;
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__scatter_mem() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__gather_mem
+ *
+ * Purpose: Gathers dataset elements from application memory BUF and
+ * copies them into the gather buffer TGATH_BUF.
+ * Each element is ELMT_SIZE bytes and arranged in application
+ * memory according to SPACE.
+ * The caller is requesting that exactly NELMTS be gathered.
+ *
+ * Return: Success: Number of elements copied.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 24, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5D__gather_mem(const void *_buf, const H5S_t *space,
+ H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache,
+ void *_tgath_buf/*out*/)
+{
+ const uint8_t *buf = (const uint8_t *)_buf; /* Get local copies for address arithmetic */
+ uint8_t *tgath_buf = (uint8_t *)_tgath_buf;
+ hsize_t *off = NULL; /* Pointer to sequence offsets */
+ size_t *len = NULL; /* Pointer to sequence lengths */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t vec_size; /* Vector length */
+ size_t ret_value = nelmts; /* Number of elements gathered */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(buf);
+ HDassert(space);
+ HDassert(iter);
+ HDassert(nelmts > 0);
+ HDassert(tgath_buf);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array")
+
+ /* Loop until all elements are written */
+ while(nelmts > 0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
+
+ /* Loop, while sequences left to process */
+ for(curr_seq = 0; curr_seq < nseq; curr_seq++) {
+ /* Get the number of bytes in sequence */
+ curr_len = len[curr_seq];
+
+ HDmemcpy(tgath_buf, buf + off[curr_seq], curr_len);
+
+ /* Advance offset in gather buffer */
+ tgath_buf += curr_len;
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__gather_mem() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__scatgath_read
+ *
+ * Purpose: Perform scatter/gather ead from a contiguous [piece of a] dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 6, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space)
+{
+ const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */
+ void *buf = io_info->u.rbuf; /* Local pointer to application buffer */
+ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/
+ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */
+ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/
+ hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */
+ H5S_sel_iter_t *file_iter = NULL; /* File selection iteration info*/
+ hbool_t file_iter_init = FALSE; /* File selection iteration info has been initialized */
+ hsize_t smine_start; /* Strip mine start loc */
+ size_t smine_nelmts; /* Elements per strip */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+ HDassert(buf);
+
+ /* Check for NOOP read */
+ if(nelmts == 0)
+ HGOTO_DONE(SUCCEED)
+
+ /* Allocate the iterators */
+ if(NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator")
+ if(NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator")
+ if(NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator")
+
+ /* Figure out the strip mine size. */
+ if(H5S_select_iter_init(file_iter, file_space, type_info->src_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information")
+ file_iter_init = TRUE; /*file selection iteration info has been initialized */
+ if(H5S_select_iter_init(mem_iter, mem_space, type_info->dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information")
+ mem_iter_init = TRUE; /*file selection iteration info has been initialized */
+ if(H5S_select_iter_init(bkg_iter, mem_space, type_info->dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information")
+ bkg_iter_init = TRUE; /*file selection iteration info has been initialized */
+
+ /* Start strip mining... */
+ for(smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) {
+ size_t n; /* Elements operated on */
+
+ /* Go figure out how many elements to read from the file */
+ HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (nelmts - smine_start));
+ smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start));
+
+ /*
+ * Gather the data from disk into the datatype conversion
+ * buffer. Also gather data from application to background buffer
+ * if necessary.
+ */
+
+ /*
+ * Gather data
+ */
+ n = H5D__gather_file(io_info, file_space, file_iter, smine_nelmts, type_info->tconv_buf/*out*/);
+ if(n != smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
+
+ /* If the source and destination are compound types and subset of each other
+ * and no conversion is needed, copy the data directly into user's buffer and
+ * bypass the rest of steps.
+ */
+ if(type_info->cmpd_subset && H5T_SUBSET_FALSE != type_info->cmpd_subset->subset) {
+ if(H5D__compound_opt_read(smine_nelmts, mem_space, mem_iter, dxpl_cache, type_info, buf /*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ } /* end if */
+ else {
+ if(H5T_BKG_YES == type_info->need_bkg) {
+ n = H5D__gather_mem(buf, mem_space, bkg_iter, smine_nelmts, dxpl_cache, type_info->bkg_buf/*out*/);
+ if(n != smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed")
+ } /* end if */
+
+ /*
+ * Perform datatype conversion.
+ */
+ if(H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id,
+ smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf,
+ type_info->bkg_buf, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
+
+ /* Do the data transform after the conversion (since we're using type mem_type) */
+ if(!type_info->is_xform_noop)
+ if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform")
+
+ /*
+ * Scatter the data into memory.
+ */
+ if(H5D__scatter_mem(type_info->tconv_buf, mem_space, mem_iter, smine_nelmts, dxpl_cache, buf/*out*/) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed")
+ } /* end else */
+ } /* end for */
+
+done:
+ /* Release selection iterators */
+ if(file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(file_iter)
+ file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
+ if(mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(mem_iter)
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+ if(bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(bkg_iter)
+ bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__scatgath_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__scatgath_write
+ *
+ * Purpose: Perform scatter/gather write to a contiguous [piece of a] dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 6, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space)
+{
+ const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */
+ const void *buf = io_info->u.wbuf; /* Local pointer to application buffer */
+ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/
+ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */
+ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/
+ hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */
+ H5S_sel_iter_t *file_iter = NULL; /* File selection iteration info*/
+ hbool_t file_iter_init = FALSE; /* File selection iteration info has been initialized */
+ hsize_t smine_start; /* Strip mine start loc */
+ size_t smine_nelmts; /* Elements per strip */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+ HDassert(buf);
+
+ /* Check for NOOP write */
+ if(nelmts == 0)
+ HGOTO_DONE(SUCCEED)
+
+ /* Allocate the iterators */
+ if(NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator")
+ if(NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator")
+ if(NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator")
+
+ /* Figure out the strip mine size. */
+ if(H5S_select_iter_init(file_iter, file_space, type_info->dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information")
+ file_iter_init = TRUE; /*file selection iteration info has been initialized */
+ if(H5S_select_iter_init(mem_iter, mem_space, type_info->src_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information")
+ mem_iter_init = TRUE; /*file selection iteration info has been initialized */
+ if(H5S_select_iter_init(bkg_iter, file_space, type_info->dst_type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information")
+ bkg_iter_init = TRUE; /*file selection iteration info has been initialized */
+
+ /* Start strip mining... */
+ for(smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) {
+ size_t n; /* Elements operated on */
+
+ /* Go figure out how many elements to read from the file */
+ HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (nelmts - smine_start));
+ smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start));
+
+ /*
+ * Gather data from application buffer into the datatype conversion
+ * buffer. Also gather data from the file into the background buffer
+ * if necessary.
+ */
+ n = H5D__gather_mem(buf, mem_space, mem_iter, smine_nelmts, dxpl_cache, type_info->tconv_buf/*out*/);
+ if(n != smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed")
+
+ /* If the source and destination are compound types and the destination is
+ * is a subset of the source and no conversion is needed, copy the data
+ * directly into user's buffer and bypass the rest of steps. If the source
+ * is a subset of the destination, the optimization is done in conversion
+ * function H5T_conv_struct_opt to protect the background data.
+ */
+ if(type_info->cmpd_subset && H5T_SUBSET_DST == type_info->cmpd_subset->subset
+ && type_info->dst_type_size == type_info->cmpd_subset->copy_size) {
+ if(H5D__compound_opt_write(smine_nelmts, type_info) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ } /* end if */
+ else {
+ if(H5T_BKG_YES == type_info->need_bkg) {
+ n = H5D__gather_file(io_info, file_space, bkg_iter, smine_nelmts, type_info->bkg_buf/*out*/);
+ if(n != smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
+ } /* end if */
+
+ /* Do the data transform before the type conversion (since
+ * transforms must be done in the memory type). */
+ if(!type_info->is_xform_noop)
+ if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform")
+
+ /*
+ * Perform datatype conversion.
+ */
+ if(H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id,
+ smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf,
+ type_info->bkg_buf, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
+ } /* end else */
+
+ /*
+ * Scatter the data out to the file.
+ */
+ if(H5D__scatter_file(io_info, file_space, file_iter, smine_nelmts, type_info->tconv_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed")
+ } /* end for */
+
+done:
+ /* Release selection iterators */
+ if(file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(file_iter)
+ file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
+ if(mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(mem_iter)
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+ if(bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(bkg_iter)
+ bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__scatgath_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compound_opt_read
+ *
+ * Purpose: A special optimization case when the source and
+ * destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed.
+ * For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; <-- TYPE1 A;
+ * TYPE2 B; <-- TYPE2 B;
+ * TYPE3 C; <-- TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 11 June 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compound_opt_read(size_t nelmts, const H5S_t *space,
+ H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache,
+ const H5D_type_info_t *type_info, void *user_buf/*out*/)
+{
+ uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */
+ uint8_t *xdbuf; /* Pointer into dataset buffer */
+ hsize_t *off = NULL; /* Pointer to sequence offsets */
+ size_t *len = NULL; /* Pointer to sequence lengths */
+ size_t src_stride, dst_stride, copy_size;
+ size_t vec_size; /* Vector length */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(nelmts > 0);
+ HDassert(space);
+ HDassert(iter);
+ HDassert(dxpl_cache);
+ HDassert(type_info);
+ HDassert(type_info->cmpd_subset);
+ HDassert(H5T_SUBSET_SRC == type_info->cmpd_subset->subset ||
+ H5T_SUBSET_DST == type_info->cmpd_subset->subset);
+ HDassert(user_buf);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
+
+ /* Get source & destination strides */
+ src_stride = type_info->src_type_size;
+ dst_stride = type_info->dst_type_size;
+
+ /* Get the size, in bytes, to copy for each element */
+ copy_size = type_info->cmpd_subset->copy_size;
+
+ /* Loop until all elements are written */
+ xdbuf = type_info->tconv_buf;
+ while(nelmts > 0) {
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t elmtno; /* Element counter */
+
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &elmtno, off, len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
+
+ /* Loop, while sequences left to process */
+ for(curr_seq = 0; curr_seq < nseq; curr_seq++) {
+ size_t curr_off; /* Offset of bytes left to process in sequence */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t curr_nelmts; /* Number of elements to process in sequence */
+ uint8_t *xubuf;
+ size_t i; /* Local index variable */
+
+ /* Get the number of bytes and offset in sequence */
+ curr_len = len[curr_seq];
+ H5_CHECK_OVERFLOW(off[curr_seq], hsize_t, size_t);
+ curr_off = (size_t)off[curr_seq];
+
+ /* Decide the number of elements and position in the buffer. */
+ curr_nelmts = curr_len / dst_stride;
+ xubuf = ubuf + curr_off;
+
+ /* Copy the data into the right place. */
+ for(i = 0; i < curr_nelmts; i++) {
+ HDmemmove(xubuf, xdbuf, copy_size);
+
+ /* Update pointers */
+ xdbuf += src_stride;
+ xubuf += dst_stride;
+ } /* end for */
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= elmtno;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compound_opt_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__compound_opt_write
+ *
+ * Purpose: A special optimization case when the source and
+ * destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed.
+ * For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; <-- TYPE1 A;
+ * TYPE2 B; <-- TYPE2 B;
+ * TYPE3 C; <-- TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 11 June 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info)
+{
+ uint8_t *xsbuf, *xdbuf; /* Source & destination pointers into dataset buffer */
+ size_t src_stride, dst_stride; /* Strides through source & destination datatypes */
+ size_t i; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(nelmts > 0);
+ HDassert(type_info);
+
+ /* Initialize values for loop */
+ src_stride = type_info->src_type_size;
+ dst_stride = type_info->dst_type_size;
+
+ /* Loop until all elements are written */
+ xsbuf = (uint8_t *)type_info->tconv_buf;
+ xdbuf = (uint8_t *)type_info->tconv_buf;
+ for(i = 0; i < nelmts; i++) {
+ HDmemmove(xdbuf, xsbuf, dst_stride);
+
+ /* Update pointers */
+ xsbuf += src_stride;
+ xdbuf += dst_stride;
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__compound_opt_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dscatter
+ *
+ * Purpose: Scatters data provided by the callback op to the
+ * destination buffer dst_buf, where the dimensions of
+ * dst_buf and the selection to be scattered to are specified
+ * by the dataspace dst_space_id. The type of the data to be
+ * scattered is specified by type_id.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 14 Jan 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id,
+ hid_t dst_space_id, void *dst_buf)
+{
+ H5T_t *type; /* Datatype */
+ H5S_t *dst_space; /* Dataspace */
+ H5S_sel_iter_t *iter = NULL; /* Selection iteration info*/
+ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
+ const void *src_buf = NULL; /* Source (contiguous) data buffer */
+ size_t src_buf_nbytes = 0; /* Size of src_buf */
+ size_t type_size; /* Datatype element size */
+ hssize_t nelmts; /* Number of remaining elements in selection */
+ size_t nelmts_scatter = 0; /* Number of elements to scatter to dst_buf */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "x*xii*x", op, op_data, type_id, dst_space_id, dst_buf);
+
+ /* Check args */
+ if(op == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback function pointer")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(NULL == (dst_space= (H5S_t *)H5I_object_verify(dst_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(dst_buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided")
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(H5AC_noio_dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Get datatype element size */
+ if(0 == (type_size = H5T_GET_SIZE(type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size")
+
+ /* Get number of elements in dataspace */
+ if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(dst_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
+
+ /* Allocate the selection iterator */
+ if(NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+
+ /* Initialize selection iterator */
+ if(H5S_select_iter_init(iter, dst_space, type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information")
+ iter_init = TRUE;
+
+ /* Loop until all data has been scattered */
+ while(nelmts > 0) {
+ /* Make callback to retrieve data */
+ if(op(&src_buf, &src_buf_nbytes, op_data) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure")
+
+ /* Calculate number of elements */
+ nelmts_scatter = src_buf_nbytes / type_size;
+
+ /* Check callback results */
+ if(!src_buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback did not return a buffer")
+ if(src_buf_nbytes == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned a buffer size of 0")
+ if(src_buf_nbytes % type_size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buffer size is not a multiple of datatype size")
+ if(nelmts_scatter > (size_t)nelmts)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned more elements than in selection")
+
+ /* Scatter data */
+ if(H5D__scatter_mem(src_buf, dst_space, iter, nelmts_scatter, dxpl_cache, dst_buf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "scatter failed")
+
+ nelmts -= (hssize_t)nelmts_scatter;
+ } /* end while */
+
+done:
+ /* Release selection iterator */
+ if(iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(iter)
+ iter = H5FL_FREE(H5S_sel_iter_t, iter);
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dscatter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Dgather
+ *
+ * Purpose: Gathers data provided from the source buffer src_buf to
+ * contiguous buffer dst_buf, then calls the callback op.
+ * The dimensions of src_buf and the selection to be gathered
+ * are specified by the dataspace src_space_id. The type of
+ * the data to be gathered is specified by type_id.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * 16 Jan 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id,
+ size_t dst_buf_size, void *dst_buf, H5D_gather_func_t op, void *op_data)
+{
+ H5T_t *type; /* Datatype */
+ H5S_t *src_space; /* Dataspace */
+ H5S_sel_iter_t *iter = NULL; /* Selection iteration info*/
+ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
+ size_t type_size; /* Datatype element size */
+ hssize_t nelmts; /* Number of remaining elements in selection */
+ size_t dst_buf_nelmts; /* Number of elements that can fit in dst_buf */
+ size_t nelmts_gathered; /* Number of elements gathered from src_buf */
+ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */
+ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*xiz*xx*x", src_space_id, src_buf, type_id, dst_buf_size,
+ dst_buf, op, op_data);
+
+ /* Check args */
+ if(NULL == (src_space= (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(src_buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source buffer provided")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(dst_buf_size == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer size is 0")
+ if(dst_buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided")
+
+ /* Fill the DXPL cache values for later use */
+ if(H5D__get_dxpl_cache(H5AC_noio_dxpl_id, &dxpl_cache) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache")
+
+ /* Get datatype element size */
+ if(0 == (type_size = H5T_GET_SIZE(type)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size")
+
+ /* Get number of elements in dst_buf_size */
+ dst_buf_nelmts = dst_buf_size / type_size;
+ if(dst_buf_nelmts == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer is not large enough to hold one element")
+
+ /* Get number of elements in dataspace */
+ if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(src_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
+
+ /* If dst_buf is not large enough to hold all the elements, make sure there
+ * is a callback */
+ if(((size_t)nelmts > dst_buf_nelmts) && (op == NULL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback supplied and destination buffer too small")
+
+ /* Allocate the selection iterator */
+ if(NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+
+ /* Initialize selection iterator */
+ if(H5S_select_iter_init(iter, src_space, type_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information")
+ iter_init = TRUE;
+
+ /* Loop until all data has been scattered */
+ while(nelmts > 0) {
+ /* Gather data */
+ if(0 == (nelmts_gathered = H5D__gather_mem(src_buf, src_space, iter, MIN(dst_buf_nelmts, (size_t)nelmts), dxpl_cache, dst_buf)))
+ HGOTO_ERROR(H5E_IO, H5E_CANTCOPY, FAIL, "gather failed")
+ HDassert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts));
+
+ /* Make callback to process dst_buf */
+ if(op && op(dst_buf, nelmts_gathered * type_size, op_data) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure")
+
+ nelmts -= (hssize_t)nelmts_gathered;
+ HDassert(op || (nelmts == 0));
+ } /* end while */
+
+done:
+ /* Release selection iterator */
+ if(iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
+ if(iter)
+ iter = H5FL_FREE(H5S_sel_iter_t, iter);
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Dgather() */
+
diff --git a/src/H5Dselect.c b/src/H5Dselect.c
new file mode 100644
index 0000000..b4d0515
--- /dev/null
+++ b/src/H5Dselect.c
@@ -0,0 +1,314 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.ued>
+ * Thursday, September 30, 2004
+ *
+ * Purpose: Dataspace I/O functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size,
+ size_t nelmts, const H5S_t *file_space, const H5S_t *mem_space);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage sequences of size_t */
+H5FL_SEQ_DEFINE(size_t);
+
+/* Declare a free list to manage sequences of hsize_t */
+H5FL_SEQ_DEFINE(hsize_t);
+
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__select_io
+ *
+ * Purpose: Perform I/O directly from application memory and a file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 27, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size,
+ size_t nelmts, const H5S_t *file_space, const H5S_t *mem_space)
+{
+ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info */
+ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */
+ H5S_sel_iter_t *file_iter = NULL; /* File selection iteration info */
+ hbool_t file_iter_init = FALSE; /* File selection iteration info has been initialized */
+ hsize_t *mem_off = NULL; /* Pointer to sequence offsets in memory */
+ hsize_t *file_off = NULL; /* Pointer to sequence offsets in the file */
+ size_t *mem_len = NULL; /* Pointer to sequence lengths in memory */
+ size_t *file_len = NULL; /* Pointer to sequence lengths in the file */
+ size_t curr_mem_seq; /* Current memory sequence to operate on */
+ size_t curr_file_seq; /* Current file sequence to operate on */
+ size_t mem_nseq; /* Number of sequences generated in the file */
+ size_t file_nseq; /* Number of sequences generated in memory */
+ size_t vec_size; /* Vector length */
+ ssize_t tmp_file_len; /* Temporary number of bytes in file sequence */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(io_info);
+ HDassert(io_info->dset);
+ HDassert(io_info->store);
+ HDassert(TRUE == H5P_isa_class(io_info->raw_dxpl_id, H5P_DATASET_XFER));
+ HDassert(io_info->u.rbuf);
+
+ /* Allocate the vector I/O arrays */
+ if(io_info->dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE)
+ vec_size = io_info->dxpl_cache->vec_size;
+ else
+ vec_size = H5D_IO_VECTOR_SIZE;
+ if(NULL == (mem_len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
+ if(NULL == (mem_off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
+ if(NULL == (file_len = H5FL_SEQ_MALLOC(size_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
+ if(NULL == (file_off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
+
+ /* Check for only one element in selection */
+ if(nelmts == 1) {
+ /* Get offset of first element in selections */
+ if(H5S_SELECT_OFFSET(file_space, file_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve file selection offset")
+ if(H5S_SELECT_OFFSET(mem_space, mem_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve memory selection offset")
+
+ /* Set up necessary information for I/O operation */
+ file_nseq = mem_nseq = 1;
+ curr_mem_seq = curr_file_seq = 0;
+ *file_off *= elmt_size;
+ *mem_off *= elmt_size;
+ *file_len = *mem_len = elmt_size;
+
+ /* Perform I/O on memory and file sequences */
+ if(io_info->op_type == H5D_IO_OP_READ) {
+ if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error")
+ } /* end if */
+ else {
+ HDassert(io_info->op_type == H5D_IO_OP_WRITE);
+ if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
+ } /* end else */
+
+ /* Decrement number of elements left to process */
+ HDassert(((size_t)tmp_file_len % elmt_size) == 0);
+ } /* end if */
+ else {
+ size_t mem_nelem; /* Number of elements used in memory sequences */
+ size_t file_nelem; /* Number of elements used in file sequences */
+
+ /* Allocate the iterators */
+ if(NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator")
+ if(NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator")
+
+ /* Initialize file iterator */
+ if(H5S_select_iter_init(file_iter, file_space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ file_iter_init = 1; /* File selection iteration info has been initialized */
+
+ /* Initialize memory iterator */
+ if(H5S_select_iter_init(mem_iter, mem_space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ mem_iter_init = 1; /* Memory selection iteration info has been initialized */
+
+ /* Initialize sequence counts */
+ curr_mem_seq = curr_file_seq = 0;
+ mem_nseq = file_nseq = 0;
+
+ /* Loop, until all bytes are processed */
+ while(nelmts > 0) {
+ /* Check if more file sequences are needed */
+ if(curr_file_seq >= file_nseq) {
+ /* Get sequences for file selection */
+ if(H5S_SELECT_GET_SEQ_LIST(file_space, H5S_GET_SEQ_LIST_SORTED, file_iter, vec_size, nelmts, &file_nseq, &file_nelem, file_off, file_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Start at the beginning of the sequences again */
+ curr_file_seq = 0;
+ } /* end if */
+
+ /* Check if more memory sequences are needed */
+ if(curr_mem_seq >= mem_nseq) {
+ /* Get sequences for memory selection */
+ if(H5S_SELECT_GET_SEQ_LIST(mem_space, 0, mem_iter, vec_size, nelmts, &mem_nseq, &mem_nelem, mem_off, mem_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Start at the beginning of the sequences again */
+ curr_mem_seq = 0;
+ } /* end if */
+
+ /* Perform I/O on memory and file sequences */
+ if(io_info->op_type == H5D_IO_OP_READ) {
+ if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error")
+ } /* end if */
+ else {
+ HDassert(io_info->op_type == H5D_IO_OP_WRITE);
+ if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
+ } /* end else */
+
+ /* Decrement number of elements left to process */
+ HDassert(((size_t)tmp_file_len % elmt_size) == 0);
+ nelmts -= ((size_t)tmp_file_len / elmt_size);
+ } /* end while */
+ } /* end else */
+
+done:
+ /* Release selection iterators */
+ if(file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(file_iter)
+ file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
+ if(mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(mem_iter)
+ mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
+
+ /* Release vector arrays, if allocated */
+ if(file_len)
+ file_len = H5FL_SEQ_FREE(size_t, file_len);
+ if(file_off)
+ file_off = H5FL_SEQ_FREE(hsize_t, file_off);
+ if(mem_len)
+ mem_len = H5FL_SEQ_FREE(size_t, mem_len);
+ if(mem_off)
+ mem_off = H5FL_SEQ_FREE(hsize_t, mem_off);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__select_io() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__select_read
+ *
+ * Purpose: Reads directly from file into application memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 23, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__select_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Call generic selection operation */
+ H5_CHECK_OVERFLOW(nelmts, hsize_t, size_t);
+ if(H5D__select_io(io_info, type_info->src_type_size, (size_t)nelmts,
+ file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__select_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__select_write
+ *
+ * Purpose: Writes directly from application memory into a file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 23, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__select_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Call generic selection operation */
+ H5_CHECK_OVERFLOW(nelmts, hsize_t, size_t);
+ if(H5D__select_io(io_info, type_info->dst_type_size, (size_t)nelmts,
+ file_space, mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__select_write() */
+
diff --git a/src/H5Dsingle.c b/src/H5Dsingle.c
new file mode 100644
index 0000000..e999449
--- /dev/null
+++ b/src/H5Dsingle.c
@@ -0,0 +1,555 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Vailin Choi <vchoi@hdfgroup.org>
+ * May 2011; updated 10/2015
+ *
+ * Purpose: Single Chunk I/O functions.
+ * This is used when the dataset has only 1 chunk (with or without filter):
+ * cur_dims[] is equal to max_dims[] is equal to the chunk dims[]
+ * non-filter chunk record: [address of the chunk]
+ * filtered chunk record: [address of the chunk, chunk size, filter mask]
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Single Chunk Index chunking I/O ops */
+static herr_t H5D__single_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t *space, haddr_t dset_ohdr_addr);
+static herr_t H5D__single_idx_create(const H5D_chk_idx_info_t *idx_info);
+static hbool_t H5D__single_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
+static herr_t H5D__single_idx_insert(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata, const H5D_t *dset);
+static herr_t H5D__single_idx_get_addr(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_ud_t *udata);
+static int H5D__single_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata);
+static herr_t H5D__single_idx_remove(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_common_ud_t *udata);
+static herr_t H5D__single_idx_delete(const H5D_chk_idx_info_t *idx_info);
+static herr_t H5D__single_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst);
+static herr_t H5D__single_idx_size(const H5D_chk_idx_info_t *idx_info,
+ hsize_t *size);
+static herr_t H5D__single_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
+static herr_t H5D__single_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Non Index chunk I/O ops */
+const H5D_chunk_ops_t H5D_COPS_SINGLE[1] = {{
+ FALSE, /* Single Chunk indexing doesn't current support SWMR access */
+ H5D__single_idx_init, /* init */
+ H5D__single_idx_create, /* create */
+ H5D__single_idx_is_space_alloc, /* is_space_alloc */
+ H5D__single_idx_insert, /* insert */
+ H5D__single_idx_get_addr, /* get_addr */
+ NULL, /* resize */
+ H5D__single_idx_iterate, /* iterate */
+ H5D__single_idx_remove, /* remove */
+ H5D__single_idx_delete, /* delete */
+ H5D__single_idx_copy_setup, /* copy_setup */
+ NULL, /* copy_shutdown */
+ H5D__single_idx_size, /* size */
+ H5D__single_idx_reset, /* reset */
+ H5D__single_idx_dump, /* dump */
+ NULL /* destroy */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_init
+ *
+ * Purpose: Initialize the indexing information for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * July, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_init(const H5D_chk_idx_info_t *idx_info,
+ const H5S_t H5_ATTR_UNUSED *space, haddr_t H5_ATTR_UNUSED dset_ohdr_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ if(idx_info->pline->nused)
+ idx_info->layout->flags |= H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER;
+ else
+ idx_info->layout->flags = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__single_idx_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_create
+ *
+ * Purpose: Set up Single Chunk Index: filtered or non-filtered
+ *
+ * Return: Non-negative on success
+ * Negative on failure.
+ *
+ * Programmer: Vailin Choi; July 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_create(const H5D_chk_idx_info_t *idx_info)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(idx_info->layout->max_nchunks == idx_info->layout->nchunks);
+ HDassert(idx_info->layout->nchunks == 1);
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+
+ if(idx_info->pline->nused)
+ HDassert(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER);
+ else
+ HDassert(!(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__single_idx_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; July 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5D__single_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
+} /* end H5D__single_idx_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_insert
+ *
+ * Purpose: Allocate space for the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; July 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
+ const H5D_t *dset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(idx_info->layout->nchunks == 1);
+ HDassert(idx_info->layout->max_nchunks == 1);
+ HDassert(udata);
+
+ /* Set the address for the chunk */
+ HDassert(H5F_addr_defined(udata->chunk_block.offset));
+ idx_info->storage->idx_addr = udata->chunk_block.offset;
+
+ if(idx_info->pline->nused > 0) {
+ H5_CHECKED_ASSIGN(idx_info->storage->u.single.nbytes, uint32_t, udata->chunk_block.length, hsize_t);
+ idx_info->storage->u.single.filter_mask = udata->filter_mask;
+ } /* end if */
+
+ if(dset) {
+ if(dset->shared->dcpl_cache.fill.alloc_time != H5D_ALLOC_TIME_EARLY || idx_info->pline->nused > 0) {
+ /* Mark the layout dirty so that the address of the single chunk will be flushed later */
+ if(H5D__mark(dset, idx_info->dxpl_id, H5D_MARK_LAYOUT) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark layout as dirty")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__single_idx_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_get_addr
+ *
+ * Purpose: Get the file address of a chunk.
+ * Save the retrieved information in the udata supplied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; July 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(idx_info->layout->nchunks == 1);
+ HDassert(idx_info->layout->max_nchunks == 1);
+ HDassert(udata);
+
+ udata->chunk_block.offset = idx_info->storage->idx_addr;
+ if(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
+ udata->chunk_block.length = idx_info->storage->u.single.nbytes;
+ udata->filter_mask = idx_info->storage->u.single.filter_mask;
+ } /* end if */
+ else {
+ udata->chunk_block.length = idx_info->layout->size;
+ udata->filter_mask = 0;
+ } /* end else */
+ if(!H5F_addr_defined(udata->chunk_block.offset))
+ udata->chunk_block.length = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5D__single_idx_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_iterate
+ *
+ * Purpose: Make callback for the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; July 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5D__single_idx_iterate(const H5D_chk_idx_info_t *idx_info,
+ H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
+{
+ H5D_chunk_rec_t chunk_rec; /* generic chunk record */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(chunk_cb);
+ HDassert(chunk_udata);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+
+ /* Initialize generic chunk record */
+ HDmemset(&chunk_rec, 0, sizeof(chunk_rec));
+ chunk_rec.chunk_addr = idx_info->storage->idx_addr;
+
+ if(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
+ chunk_rec.nbytes = idx_info->storage->u.single.nbytes;
+ chunk_rec.filter_mask = idx_info->storage->u.single.filter_mask;
+ } /* end if */
+ else {
+ chunk_rec.nbytes = idx_info->layout->size;
+ chunk_rec.filter_mask = 0;
+ } /* end else */
+
+ /* Make "generic chunk" callback */
+ if((ret_value = (*chunk_cb)(&chunk_rec, chunk_udata)) < 0)
+ HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__single_idx_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_remove
+ *
+ * Purpose: Remove the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; July 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t H5_ATTR_UNUSED *udata)
+{
+ hsize_t nbytes; /* Size of all chunks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+ HDassert(H5F_addr_defined(idx_info->storage->idx_addr));
+
+ if(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER)
+ nbytes = idx_info->storage->u.single.nbytes;
+ else
+ nbytes = idx_info->layout->size;
+
+ if(H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->dxpl_id, idx_info->storage->idx_addr, nbytes) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free dataset chunks")
+
+ idx_info->storage->idx_addr = HADDR_UNDEF;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__single_idx_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_delete
+ *
+ * Purpose: Delete raw data storage for entire dataset (i.e. the only chunk)
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Sept 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_delete(const H5D_chk_idx_info_t *idx_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(idx_info);
+ HDassert(idx_info->f);
+ HDassert(idx_info->pline);
+ HDassert(idx_info->layout);
+ HDassert(idx_info->storage);
+
+ if(H5F_addr_defined(idx_info->storage->idx_addr))
+ ret_value = H5D__single_idx_remove(idx_info, NULL);
+ else
+ HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__single_idx_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_copy_setup
+ *
+ * Purpose: Set up any necessary information for copying the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
+ const H5D_chk_idx_info_t *idx_info_dst)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(idx_info_src);
+ HDassert(idx_info_src->f);
+ HDassert(idx_info_src->pline);
+ HDassert(idx_info_src->layout);
+ HDassert(idx_info_src->storage);
+ HDassert(H5F_addr_defined(idx_info_src->storage->idx_addr));
+
+ HDassert(idx_info_dst);
+ HDassert(idx_info_dst->f);
+ HDassert(idx_info_dst->pline);
+ HDassert(idx_info_dst->layout);
+ HDassert(idx_info_dst->storage);
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Set up information at the destination file */
+ if(H5D__single_idx_create(idx_info_dst) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__single_idx_copy_setup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_size
+ *
+ * Purpose: Retrieve the amount of index storage for the chunked dataset
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Sept 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_size(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info, hsize_t *index_size)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(index_size);
+
+ *index_size = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__single_idx_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_reset
+ *
+ * Purpose: Reset indexing information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+
+ /* Reset index info */
+ if(reset_addr)
+ storage->idx_addr = HADDR_UNDEF;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__single_idx_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__single_idx_dump
+ *
+ * Purpose: Dump the address of the single chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; September 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__single_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(storage);
+ HDassert(stream);
+
+ HDfprintf(stream, " Address: %a\n", storage->idx_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5D__single_idx_dump() */
+
diff --git a/src/H5Dtest.c b/src/H5Dtest.c
new file mode 100644
index 0000000..2fc71a0
--- /dev/null
+++ b/src/H5Dtest.c
@@ -0,0 +1,269 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, May 27, 2004
+ *
+ * Purpose: Dataset testing functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+#define H5D_TESTING /*suppress warning about H5D testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__layout_version_test
+ PURPOSE
+ Determine the storage layout version for a dataset's layout information
+ USAGE
+ herr_t H5D__layout_version_test(did, version)
+ hid_t did; IN: Dataset to query
+ unsigned *version; OUT: Pointer to location to place version info
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the version of the storage layout information for a dataset.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__layout_version_test(hid_t did, unsigned *version)
+{
+ H5D_t *dset; /* Pointer to dataset to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(version)
+ *version = dset->shared->layout.version;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__layout_version_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__layout_contig_size_test
+ PURPOSE
+ Determine the size of a contiguous layout for a dataset's layout information
+ USAGE
+ herr_t H5D__layout_contig_size_test(did, size)
+ hid_t did; IN: Dataset to query
+ hsize_t *size; OUT: Pointer to location to place size info
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the size of a contiguous dataset's storage.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__layout_contig_size_test(hid_t did, hsize_t *size)
+{
+ H5D_t *dset; /* Pointer to dataset to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(size) {
+ HDassert(dset->shared->layout.type == H5D_CONTIGUOUS);
+ *size = dset->shared->layout.storage.u.contig.size;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__layout_contig_size_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__layout_type_test
+ PURPOSE
+ Determine the storage layout type for a dataset
+ USAGE
+ herr_t H5D__layout_type_test(did, layout_type)
+ hid_t did; IN: Dataset to query
+ H5D_layout_t *layout_type; OUT: Pointer to location to place layout info
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the layout type for a dataset.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__layout_type_test(hid_t did, H5D_layout_t *layout_type)
+{
+ H5D_t *dset; /* Pointer to dataset to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(layout_type);
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(layout_type)
+ *layout_type = dset->shared->layout.type;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__layout_type_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__layout_idx_type_test
+ PURPOSE
+ Determine the storage layout index type for a dataset's layout information
+ USAGE
+ herr_t H5D__layout_idx_type_test(did, idx_type)
+ hid_t did; IN: Dataset to query
+ H5D_chunk_index_t *idx_type; OUT: Pointer to location to place index type info
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the index type of the storage layout information for a dataset.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__layout_idx_type_test(hid_t did, H5D_chunk_index_t *idx_type)
+{
+ H5D_t *dset; /* Pointer to dataset to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(dset->shared->layout.type != H5D_CHUNKED)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset is not chunked")
+
+ if(idx_type)
+ *idx_type = dset->shared->layout.u.chunk.idx_type;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__layout_idx_type_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5D__current_cache_size_test
+ PURPOSE
+ Determine current the size of the dataset's chunk cache
+ USAGE
+ herr_t H5D__current_cache_size_test(did, size)
+ hid_t did; IN: Dataset to query
+ hsize_t *size; OUT: Pointer to location to place size info
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the size of a contiguous dataset's storage.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5D__current_cache_size_test(hid_t did, size_t *nbytes_used, int *nused)
+{
+ H5D_t *dset; /* Pointer to dataset to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ if(nbytes_used) {
+ HDassert(dset->shared->layout.type == H5D_CHUNKED);
+ *nbytes_used = dset->shared->cache.chunk.nbytes_used;
+ } /* end if */
+
+ if(nused) {
+ HDassert(dset->shared->layout.type == H5D_CHUNKED);
+ *nused = dset->shared->cache.chunk.nused;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__current_cache_size_test() */
+
diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c
new file mode 100644
index 0000000..3be2353
--- /dev/null
+++ b/src/H5Dvirtual.c
@@ -0,0 +1,2945 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Neil Fortner <nfortne2@hdfgroup.org>
+ * Wednesday, January 28, 2015
+ *
+ * Purpose:
+ * Virtual Dataset (VDS) functions. Creates a layout type which allows
+ * definition of a virtual dataset, where the actual dataset is stored in
+ * other datasets (called source datasets). The mappings between the
+ * virtual and source datasets are specified by hyperslab or "all"
+ * dataspace selections. Point selections are not currently supported.
+ * Overlaps in the mappings in the virtual dataset result in undefined
+ * behaviour.
+ *
+ * Mapping selections may be unlimited, in which case the size of the
+ * virtual dataset is determined by the size of the source dataset(s).
+ * Names for the source datasets may also be generated procedurally, in
+ * which case the virtual selection should be unlimited with an unlimited
+ * count and the source selection should be limited with a size equal to
+ * that of the virtual selection with the unlimited count set to 1.
+ *
+ * Source datasets are opened lazily (only when needed for I/O or to
+ * determine the size of the virtual dataset), and are currently held open
+ * until the virtual dataset is closed.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Dmodule.h" /* This source code file is part of the H5D module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gprivate.h" /* Groups */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspaces */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Default size for sub_dset array */
+#define H5D_VIRTUAL_DEF_SUB_DSET_SIZE 128
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Layout operation callbacks */
+static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t
+ *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t *fm);
+static herr_t H5D__virtual_write(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space,
+ const H5S_t *mem_space, H5D_chunk_map_t *fm);
+static herr_t H5D__virtual_flush(H5D_t *dset, hid_t dxpl_id);
+
+/* Other functions */
+static herr_t H5D__virtual_open_source_dset(const H5D_t *vdset,
+ H5O_storage_virtual_ent_t *virtual_ent,
+ H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id);
+static herr_t H5D__virtual_reset_source_dset(
+ H5O_storage_virtual_ent_t *virtual_ent,
+ H5O_storage_virtual_srcdset_t *source_dset);
+static herr_t H5D__virtual_str_append(const char *src, size_t src_len, char **p,
+ char **buf, size_t *buf_size);
+static herr_t H5D__virtual_copy_parsed_name(
+ H5O_storage_virtual_name_seg_t **dst, H5O_storage_virtual_name_seg_t *src);
+static herr_t H5D__virtual_build_source_name(char *source_name,
+ const H5O_storage_virtual_name_seg_t *parsed_name, size_t static_strlen,
+ size_t nsubs, hsize_t blockno, char **built_name);
+static herr_t H5D__virtual_init_all(const H5D_t *dset, hid_t dxpl_id);
+static herr_t H5D__virtual_pre_io(H5D_io_info_t *io_info,
+ H5O_storage_virtual_t *storage, const H5S_t *file_space,
+ const H5S_t *mem_space, hsize_t *tot_nelmts);
+static herr_t H5D__virtual_post_io(H5O_storage_virtual_t *storage);
+static herr_t H5D__virtual_read_one(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, const H5S_t *file_space,
+ H5O_storage_virtual_srcdset_t *source_dset);
+static herr_t H5D__virtual_write_one(H5D_io_info_t *io_info,
+ const H5D_type_info_t *type_info, const H5S_t *file_space,
+ H5O_storage_virtual_srcdset_t *source_dset);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Contiguous storage layout I/O ops */
+const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1] = {{
+ NULL,
+ H5D__virtual_init,
+ H5D__virtual_is_space_alloc,
+ NULL,
+ H5D__virtual_read,
+ H5D__virtual_write,
+#ifdef H5_HAVE_PARALLEL
+ NULL,
+ NULL,
+#endif /* H5_HAVE_PARALLEL */
+ NULL,
+ NULL,
+ H5D__virtual_flush,
+ NULL,
+ NULL
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5O_storage_virtual_name_seg_t struct */
+H5FL_DEFINE(H5O_storage_virtual_name_seg_t);
+
+/* Declare a static free list to manage H5D_virtual_file_list_t structs */
+H5FL_DEFINE_STATIC(H5D_virtual_held_file_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_check_mapping_pre
+ *
+ * Purpose: Checks that the provided virtual and source selections are
+ * legal for use as a VDS mapping, prior to creating the rest
+ * of the mapping entry.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * August 12, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_check_mapping_pre(const H5S_t *vspace, const H5S_t *src_space,
+ H5O_virtual_space_status_t space_status)
+{
+ H5S_sel_type select_type; /* Selection type */
+ hsize_t nelmts_vs; /* Number of elements in virtual selection */
+ hsize_t nelmts_ss; /* Number of elements in source selection */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check for point selections (currently unsupported) */
+ if(H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(vspace)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type")
+ if(select_type == H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "point selections not currently supported with virtual datasets")
+ if(H5S_SEL_ERROR == (select_type = H5S_GET_SELECT_TYPE(src_space)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get selection type")
+ if(select_type == H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "point selections not currently supported with virtual datasets")
+
+ /* Get number of elements in spaces */
+ nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(vspace);
+ nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(src_space);
+
+ /* Check for unlimited vspace */
+ if(nelmts_vs == H5S_UNLIMITED) {
+ /* Check for unlimited src_space */
+ if(nelmts_ss == H5S_UNLIMITED) {
+ hsize_t nenu_vs; /* Number of elements in the non-unlimited dimensions of vspace */
+ hsize_t nenu_ss; /* Number of elements in the non-unlimited dimensions of src_space */
+
+ /* Non-printf unlimited selection. Make sure both selections have
+ * the same number of elements in the non-unlimited dimension. Note
+ * we can always check this even if the space status is invalid
+ * because unlimited selections are never dependent on the extent.
+ */
+ if(H5S_get_select_num_elem_non_unlim(vspace, &nenu_vs) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "can't get number of elements in non-unlimited dimension")
+ if(H5S_get_select_num_elem_non_unlim(src_space, &nenu_ss) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "can't get number of elements in non-unlimited dimension")
+ if(nenu_vs != nenu_ss)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "numbers of elemnts in the non-unlimited dimensions is different for source and virtual spaces")
+ } /* end if */
+ /* We will handle the printf case after parsing the source names */
+ } /* end if */
+ else if(space_status != H5O_VIRTUAL_STATUS_INVALID)
+ /* Limited selections. Check number of points is the same. */
+ if(nelmts_vs != nelmts_ss)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual and source space selections have different numbers of elements")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_check_mapping_pre() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_check_mapping_post
+ *
+ * Purpose: Checks that the provided virtual dataset mapping entry is
+ * legal, after the mapping is otherwise complete.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * August 12, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_check_mapping_post(const H5O_storage_virtual_ent_t *ent)
+{
+ hsize_t nelmts_vs; /* Number of elements in virtual selection */
+ hsize_t nelmts_ss; /* Number of elements in source selection */
+ H5S_t *tmp_space = NULL; /* Temporary dataspace */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get number of elements in spaces */
+ nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_dset.virtual_select);
+ nelmts_ss = (hsize_t)H5S_GET_SELECT_NPOINTS(ent->source_select);
+
+ /* Check for printf selection */
+ if((nelmts_vs == H5S_UNLIMITED) && (nelmts_ss != H5S_UNLIMITED)) {
+ /* Make sure there at least one %b substitution in the source file or
+ * dataset name */
+ if((ent->psfn_nsubs == 0) && (ent->psdn_nsubs == 0))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unlimited virtual selection, limited source selection, and no printf specifiers in source names")
+
+ /* Make sure virtual space uses hyperslab selection */
+ if(H5S_GET_SELECT_TYPE(ent->source_dset.virtual_select) != H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "virtual selection with printf mapping must be hyperslab")
+
+ /* Check that the number of elements in one block in the virtual
+ * selection matches the total number of elements in the source
+ * selection, if the source space status is not invalid (virtual space
+ * status does not matter here because it is unlimited) */
+ if(ent->source_space_status != H5O_VIRTUAL_STATUS_INVALID) {
+ /* Get first block in virtual selection */
+ if(NULL == (tmp_space = H5S_hyper_get_unlim_block(ent->source_dset.virtual_select, (hsize_t)0)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get first block in virtual selection")
+
+ /* Check number of points */
+ nelmts_vs = (hsize_t)H5S_GET_SELECT_NPOINTS(tmp_space);
+ if(nelmts_vs != nelmts_ss)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual (single block) and source space selections have different numbers of elements")
+ } /* end if */
+ } /* end if */
+ else
+ /* Make sure there are no printf substitutions */
+ if((ent->psfn_nsubs > 0) || (ent->psdn_nsubs > 0))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "printf specifier(s) in source name(s) without an unlimited virtual selection and limited source selection")
+
+done:
+ /* Free temporary space */
+ if(tmp_space)
+ if(H5S_close(tmp_space) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CLOSEERROR, FAIL, "can't close dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_check_mapping_post() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_update_min_dims
+ *
+ * Purpose: Updates the virtual layout's "min_dims" field to take into
+ * account the "idx"th entry in the mapping list. The entry
+ * must be complete, though top level field list_nused (and
+ * of course min_dims) does not need to take it into account.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_update_min_dims(H5O_layout_t *layout, size_t idx)
+{
+ H5S_sel_type sel_type;
+ int rank;
+ hsize_t bounds_start[H5S_MAX_RANK];
+ hsize_t bounds_end[H5S_MAX_RANK];
+ int i;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(layout);
+ HDassert(layout->type == H5D_VIRTUAL);
+ HDassert(idx < layout->storage.u.virt.list_nalloc);
+
+ /* Get type of selection */
+ if(H5S_SEL_ERROR == (sel_type = H5S_GET_SELECT_TYPE(layout->storage.u.virt.list[idx].source_dset.virtual_select)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection type")
+
+ /* Do not update min_dims for "all" or "none" selections */
+ if((sel_type == H5S_SEL_ALL) || (sel_type == H5S_SEL_NONE))
+ HGOTO_DONE(SUCCEED)
+
+ /* Get rank of vspace */
+ if((rank = H5S_GET_EXTENT_NDIMS(layout->storage.u.virt.list[idx].source_dset.virtual_select)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
+
+ /* Get selection bounds */
+ if(H5S_SELECT_BOUNDS(layout->storage.u.virt.list[idx].source_dset.virtual_select, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
+
+ /* Update min_dims */
+ for(i = 0; i < rank; i++)
+ /* Don't check unlimited dimensions in the selection */
+ if((i != layout->storage.u.virt.list[idx].unlim_dim_virtual)
+ && (bounds_end[i] >= layout->storage.u.virt.min_dims[i]))
+ layout->storage.u.virt.min_dims[i] = bounds_end[i] + (hsize_t)1;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_update_min_dims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_check_min_dims
+ *
+ * Purpose: Checks if the dataset's dimensions are at least the
+ * calculated minimum dimensions from the mappings.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * August 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_check_min_dims(const H5D_t *dset)
+{
+ int rank;
+ hsize_t dims[H5S_MAX_RANK];
+ int i;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dset);
+ HDassert(dset->shared);
+ HDassert(dset->shared->layout.type == H5D_VIRTUAL);
+
+ /* Get rank of dataspace */
+ if((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
+
+ /* Get VDS dimensions */
+ if(H5S_get_simple_extent_dims(dset->shared->space, dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
+
+ /* Verify that dimensions are larger than min_dims */
+ for(i = 0; i < rank; i++)
+ if(dims[i] < dset->shared->layout.storage.u.virt.min_dims[i])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual dataset dimensions not large enough to contain all limited dimensions in all selections")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_check_min_dims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_copy_layout
+ *
+ * Purpose: Deep copies virtual storage layout message in memory.
+ * This function assumes that the top-level struct has
+ * already been copied (so the source struct retains
+ * ownership of the fields passed to this function).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_copy_layout(H5O_layout_t *layout)
+{
+ H5O_storage_virtual_ent_t *orig_list = NULL;
+ hid_t orig_source_fapl;
+ hid_t orig_source_dapl;
+ H5P_genplist_t *plist;
+ size_t i;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(layout);
+ HDassert(layout->type == H5D_VIRTUAL);
+
+ /* Save original entry list and top-level property lists and reset in layout
+ * so the originals aren't closed on error */
+ orig_source_fapl = layout->storage.u.virt.source_fapl;
+ layout->storage.u.virt.source_fapl = -1;
+ orig_source_dapl = layout->storage.u.virt.source_dapl;
+ layout->storage.u.virt.source_dapl = -1;
+ orig_list = layout->storage.u.virt.list;
+ layout->storage.u.virt.list = NULL;
+
+ /* Copy entry list */
+ if(layout->storage.u.virt.list_nused > 0) {
+ HDassert(orig_list);
+
+ /* Allocate memory for the list */
+ if(NULL == (layout->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_calloc(layout->storage.u.virt.list_nused * sizeof(H5O_storage_virtual_ent_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory for virtual dataset entry list")
+ layout->storage.u.virt.list_nalloc = layout->storage.u.virt.list_nused;
+
+ /* Copy the list entries, though set source_dset.dset and sub_dset to
+ * NULL */
+ for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
+ /* Copy virtual selection */
+ if(NULL == (layout->storage.u.virt.list[i].source_dset.virtual_select
+ = H5S_copy(orig_list[i].source_dset.virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Copy original source names */
+ if(NULL == (layout->storage.u.virt.list[i].source_file_name
+ = H5MM_strdup(orig_list[i].source_file_name)))
+ HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name")
+ if(NULL == (layout->storage.u.virt.list[i].source_dset_name
+ = H5MM_strdup(orig_list[i].source_dset_name)))
+ HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name")
+
+ /* Copy source selection */
+ if(NULL == (layout->storage.u.virt.list[i].source_select
+ = H5S_copy(orig_list[i].source_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+
+ /* Initialize clipped selections */
+ if(orig_list[i].unlim_dim_virtual < 0) {
+ layout->storage.u.virt.list[i].source_dset.clipped_source_select = layout->storage.u.virt.list[i].source_select;
+ layout->storage.u.virt.list[i].source_dset.clipped_virtual_select = layout->storage.u.virt.list[i].source_dset.virtual_select;
+ } /* end if */
+
+ /* Copy parsed names */
+ if(H5D__virtual_copy_parsed_name(&layout->storage.u.virt.list[i].parsed_source_file_name, orig_list[i].parsed_source_file_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source file name")
+ layout->storage.u.virt.list[i].psfn_static_strlen = orig_list[i].psfn_static_strlen;
+ layout->storage.u.virt.list[i].psfn_nsubs = orig_list[i].psfn_nsubs;
+ if(H5D__virtual_copy_parsed_name(&layout->storage.u.virt.list[i].parsed_source_dset_name, orig_list[i].parsed_source_dset_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy parsed source dataset name")
+ layout->storage.u.virt.list[i].psdn_static_strlen = orig_list[i].psdn_static_strlen;
+ layout->storage.u.virt.list[i].psdn_nsubs = orig_list[i].psdn_nsubs;
+
+ /* Copy source names in source dset or add reference as appropriate
+ */
+ if(orig_list[i].source_dset.file_name) {
+ if(orig_list[i].source_dset.file_name
+ == orig_list[i].source_file_name)
+ layout->storage.u.virt.list[i].source_dset.file_name = layout->storage.u.virt.list[i].source_file_name;
+ else if(orig_list[i].parsed_source_file_name
+ && (orig_list[i].source_dset.file_name
+ != orig_list[i].parsed_source_file_name->name_segment)) {
+ HDassert(layout->storage.u.virt.list[i].parsed_source_file_name);
+ HDassert(layout->storage.u.virt.list[i].parsed_source_file_name->name_segment);
+ layout->storage.u.virt.list[i].source_dset.file_name = layout->storage.u.virt.list[i].parsed_source_file_name->name_segment;
+ } /* end if */
+ else
+ if(NULL == (layout->storage.u.virt.list[i].source_dset.file_name
+ = H5MM_strdup(orig_list[i].source_dset.file_name)))
+ HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source file name")
+ } /* end if */
+ if(orig_list[i].source_dset.dset_name) {
+ if(orig_list[i].source_dset.dset_name
+ == orig_list[i].source_dset_name)
+ layout->storage.u.virt.list[i].source_dset.dset_name = layout->storage.u.virt.list[i].source_dset_name;
+ else if(orig_list[i].parsed_source_dset_name
+ && (orig_list[i].source_dset.dset_name
+ != orig_list[i].parsed_source_dset_name->name_segment)) {
+ HDassert(layout->storage.u.virt.list[i].parsed_source_dset_name);
+ HDassert(layout->storage.u.virt.list[i].parsed_source_dset_name->name_segment);
+ layout->storage.u.virt.list[i].source_dset.dset_name = layout->storage.u.virt.list[i].parsed_source_dset_name->name_segment;
+ } /* end if */
+ else
+ if(NULL == (layout->storage.u.virt.list[i].source_dset.dset_name
+ = H5MM_strdup(orig_list[i].source_dset.dset_name)))
+ HGOTO_ERROR(H5E_DATASET, H5E_RESOURCE, FAIL, "unable to duplicate source dataset name")
+ } /* end if */
+
+ /* Copy other fields in entry */
+ layout->storage.u.virt.list[i].unlim_dim_source = orig_list[i].unlim_dim_source;
+ layout->storage.u.virt.list[i].unlim_dim_virtual = orig_list[i].unlim_dim_virtual;
+ layout->storage.u.virt.list[i].unlim_extent_source = orig_list[i].unlim_extent_source;
+ layout->storage.u.virt.list[i].unlim_extent_virtual = orig_list[i].unlim_extent_virtual;
+ layout->storage.u.virt.list[i].clip_size_source = orig_list[i].clip_size_source;
+ layout->storage.u.virt.list[i].clip_size_virtual = orig_list[i].clip_size_virtual;
+ layout->storage.u.virt.list[i].source_space_status = orig_list[i].source_space_status;
+ layout->storage.u.virt.list[i].virtual_space_status = orig_list[i].virtual_space_status;
+ } /* end for */
+ } /* end if */
+ else {
+ /* Zero out other fields related to list, just to be sure */
+ layout->storage.u.virt.list = NULL;
+ layout->storage.u.virt.list_nalloc = 0;
+ } /* end else */
+
+ /* Copy property lists */
+ if(orig_source_fapl >= 0) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_fapl, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if((layout->storage.u.virt.source_fapl = H5P_copy_plist(plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy fapl")
+ } /* end if */
+ if(orig_source_dapl >= 0) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(orig_source_dapl, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if((layout->storage.u.virt.source_dapl = H5P_copy_plist(plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl")
+ } /* end if */
+
+ /* New layout is not fully initialized */
+ layout->storage.u.virt.init = FALSE;
+
+done:
+ /* Release allocated resources on failure */
+ if(ret_value < 0)
+ if(H5D__virtual_reset_layout(layout) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset virtual layout")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_copy_layout() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_reset_layout
+ *
+ * Purpose: Frees internal structures in a virtual storage layout
+ * message in memory. This function is safe to use on
+ * incomplete structures (for recovery from failure) provided
+ * the internal structures are initialized with all bytes set
+ * to 0.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 11, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_reset_layout(H5O_layout_t *layout)
+{
+ size_t i, j;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(layout);
+ HDassert(layout->type == H5D_VIRTUAL);
+
+ /* Free the list entries. Note we always attempt to free everything even in
+ * the case of a failure. Because of this, and because we free the list
+ * afterwards, we do not need to zero out the memory in the list. */
+ for(i = 0; i < layout->storage.u.virt.list_nused; i++) {
+ /* Free source_dset */
+ if(H5D__virtual_reset_source_dset(&layout->storage.u.virt.list[i], &layout->storage.u.virt.list[i].source_dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset")
+
+ /* Free original source names */
+ (void)H5MM_xfree(layout->storage.u.virt.list[i].source_file_name);
+ (void)H5MM_xfree(layout->storage.u.virt.list[i].source_dset_name);
+
+ /* Free sub_dset */
+ for(j = 0; j < layout->storage.u.virt.list[i].sub_dset_nalloc; j++)
+ if(H5D__virtual_reset_source_dset(&layout->storage.u.virt.list[i], &layout->storage.u.virt.list[i].sub_dset[j]) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset source dataset")
+ layout->storage.u.virt.list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_xfree(layout->storage.u.virt.list[i].sub_dset);
+
+ /* Free source_select */
+ if(layout->storage.u.virt.list[i].source_select)
+ if(H5S_close(layout->storage.u.virt.list[i].source_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection")
+
+ /* Free parsed_source_file_name */
+ H5D_virtual_free_parsed_name(layout->storage.u.virt.list[i].parsed_source_file_name);
+
+ /* Free parsed_source_dset_name */
+ H5D_virtual_free_parsed_name(layout->storage.u.virt.list[i].parsed_source_dset_name);
+ } /* end for */
+
+ /* Free the list */
+ layout->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_xfree(layout->storage.u.virt.list);
+ layout->storage.u.virt.list_nalloc = (size_t)0;
+ layout->storage.u.virt.list_nused = (size_t)0;
+ (void)HDmemset(layout->storage.u.virt.min_dims, 0, sizeof(layout->storage.u.virt.min_dims));
+
+ /* Close access property lists */
+ if(layout->storage.u.virt.source_fapl >= 0) {
+ if(H5I_dec_ref(layout->storage.u.virt.source_fapl) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source fapl")
+ layout->storage.u.virt.source_fapl = -1;
+ } /* end if */
+ if(layout->storage.u.virt.source_dapl >= 0) {
+ if(H5I_dec_ref(layout->storage.u.virt.source_dapl) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close source dapl")
+ layout->storage.u.virt.source_dapl = -1;
+ } /* end if */
+
+ /* The list is no longer initialized */
+ layout->storage.u.virt.init = FALSE;
+
+ /* Note the lack of a done: label. This is because there are no HGOTO_ERROR
+ * calls. If one is added, a done: label must also be added */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_reset_layout() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_copy
+ *
+ * Purpose: Copy virtual storage raw data from SRC file to DST file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_copy(H5F_t H5_ATTR_UNUSED *f_dst, H5O_layout_t *layout_dst,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ herr_t ret_value = SUCCEED;
+
+#ifdef NOT_YET
+ FUNC_ENTER_PACKAGE
+#endif /* NOT_YET */
+ FUNC_ENTER_PACKAGE_NOERR
+
+#ifdef NOT_YET
+ /* Check for copy to the same file */
+ if(f_dst == f_src) {
+ /* Increase reference count on global heap object */
+ if((heap_rc = H5HG_link(f_dst, dxpl_id, (H5HG_t *)&(layout_dst->u.virt.serial_list_hobjid), 1)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap refence count")
+ } /* end if */
+ else
+#endif /* NOT_YET */
+ {
+ /* Reset global heap id so a new heap object is created when the message
+ * is flushed */
+ layout_dst->storage.u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
+ layout_dst->storage.u.virt.serial_list_hobjid.idx = (size_t)0;
+ } /* end block/else */
+
+#ifdef NOT_YET
+done:
+#endif /* NOT_YET */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_delete
+ *
+ * Purpose: Delete the file space for a virtual dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_delete(H5F_t *f, hid_t dxpl_id, H5O_storage_t *storage)
+{
+#ifdef NOT_YET
+ int heap_rc; /* Reference count of global heap object */
+#endif /* NOT_YET */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(f);
+ HDassert(storage);
+ HDassert(storage->type == H5D_VIRTUAL);
+
+ /* Check for global heap block */
+ if(storage->u.virt.serial_list_hobjid.addr != HADDR_UNDEF) {
+#ifdef NOT_YET
+ /* Unlink the global heap block */
+ if((heap_rc = H5HG_link(f, dxpl_id, (H5HG_t *)&(storage->u.virt.serial_list_hobjid), -1)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTMODIFY, FAIL, "unable to adjust global heap refence count")
+ if(heap_rc == 0)
+#endif /* NOT_YET */
+ /* Delete the global heap block */
+ if(H5HG_remove(f, dxpl_id, (H5HG_t *)&(storage->u.virt.serial_list_hobjid)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "unable to remove heap object")
+ } /* end if */
+
+ /* Clear global heap ID in storage */
+ storage->u.virt.serial_list_hobjid.addr = HADDR_UNDEF;
+ storage->u.virt.serial_list_hobjid.idx = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_delete */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_open_source_dset
+ *
+ * Purpose: Attempts to open a source dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * March 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_open_source_dset(const H5D_t *vdset,
+ H5O_storage_virtual_ent_t *virtual_ent,
+ H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id)
+{
+ H5F_t *src_file = NULL; /* Source file */
+ hbool_t src_file_open = FALSE; /* Whether we have opened and need to close src_file */
+ H5G_loc_t src_root_loc; /* Object location of source file root group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(vdset);
+ HDassert(source_dset);
+ HDassert(!source_dset->dset);
+ HDassert(source_dset->file_name);
+ HDassert(source_dset->dset_name);
+
+ /* Check if we need to open the source file */
+ if(HDstrcmp(source_dset->file_name, ".")) {
+ /* Open the source file */
+ if(NULL == (src_file = H5F_open(source_dset->file_name, H5F_INTENT(vdset->oloc.file) & (H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ), H5P_FILE_CREATE_DEFAULT, vdset->shared->layout.storage.u.virt.source_fapl, dxpl_id)))
+ H5E_clear_stack(NULL); /* Quick hack until proper support for H5Fopen with missing file is implemented */
+ else
+ src_file_open = TRUE;
+ } /* end if */
+ else
+ /* Source file is ".", use the virtual dataset's file */
+ src_file = vdset->oloc.file;
+
+ if(src_file) {
+ /* Set up the root group in the destination file */
+ if(NULL == (src_root_loc.oloc = H5G_oloc(H5G_rootof(src_file))))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (src_root_loc.path = H5G_nameof(H5G_rootof(src_file))))
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Open the source dataset */
+ if(NULL == (source_dset->dset = H5D__open_name(&src_root_loc, source_dset->dset_name, vdset->shared->layout.storage.u.virt.source_dapl, dxpl_id))) {
+ H5E_clear_stack(NULL); /* Quick hack until proper support for H5Dopen with missing file is implemented */
+
+ /* Dataset does not exist */
+ source_dset->dset_exists = FALSE;
+ } /* end if */
+ else {
+ /* Dataset exists */
+ source_dset->dset_exists = TRUE;
+
+ /* Patch the source selection if necessary */
+ if(virtual_ent->source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
+ if(H5S_extent_copy(virtual_ent->source_select, source_dset->dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
+ virtual_ent->source_space_status = H5O_VIRTUAL_STATUS_CORRECT;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Close source file */
+ if(src_file_open)
+ if(H5F_try_close(src_file, NULL) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "can't close source file")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_open_source_dset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_reset_source_dset
+ *
+ * Purpose: Frees space referenced by a source dataset struct.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 20, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t *virtual_ent,
+ H5O_storage_virtual_srcdset_t *source_dset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(source_dset);
+
+ /* Free dataset */
+ if(source_dset->dset) {
+ if(H5D_close(source_dset->dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
+ source_dset->dset = NULL;
+ } /* end if */
+
+ /* Free file name */
+ if(virtual_ent->parsed_source_file_name
+ && (source_dset->file_name
+ != virtual_ent->parsed_source_file_name->name_segment))
+ source_dset->file_name = (char *)H5MM_xfree(source_dset->file_name);
+ else
+ HDassert((source_dset->file_name == virtual_ent->source_file_name)
+ || (virtual_ent->parsed_source_file_name
+ && (source_dset->file_name
+ == virtual_ent->parsed_source_file_name->name_segment))
+ || !source_dset->file_name);
+
+ /* Free dataset name */
+ if(virtual_ent->parsed_source_dset_name
+ && (source_dset->dset_name
+ != virtual_ent->parsed_source_dset_name->name_segment))
+ source_dset->dset_name = (char *)H5MM_xfree(source_dset->dset_name);
+ else
+ HDassert((source_dset->dset_name == virtual_ent->source_dset_name)
+ || (virtual_ent->parsed_source_dset_name
+ && (source_dset->dset_name
+ == virtual_ent->parsed_source_dset_name->name_segment))
+ || !source_dset->dset_name);
+
+ /* Free clipped virtual selection */
+ if(source_dset->clipped_virtual_select) {
+ if(source_dset->clipped_virtual_select != source_dset->virtual_select)
+ if(H5S_close(source_dset->clipped_virtual_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual selection")
+ source_dset->clipped_virtual_select = NULL;
+ } /* end if */
+
+ /* Free virtual selection */
+ if(source_dset->virtual_select) {
+ if(H5S_close(source_dset->virtual_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release virtual selection")
+ source_dset->virtual_select = NULL;
+ } /* end if */
+
+ /* Free clipped source selection */
+ if(source_dset->clipped_source_select) {
+ if(source_dset->clipped_source_select != virtual_ent->source_select)
+ if(H5S_close(source_dset->clipped_source_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source selection")
+ source_dset->clipped_source_select = NULL;
+ } /* end if */
+
+ /* The projected memory space should never exist when this function is
+ * called */
+ HDassert(!source_dset->projected_mem_space);
+
+ /* Note the lack of a done: label. This is because there are no HGOTO_ERROR
+ * calls. If one is added, a done: label must also be added */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_reset_source_dset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_str_append
+ *
+ * Purpose: Appends src_len bytes of the string src to the position *p
+ * in the buffer *buf (allocating *buf if necessary).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 19, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_str_append(const char *src, size_t src_len, char **p, char **buf,
+ size_t *buf_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(src);
+ HDassert(src_len > 0);
+ HDassert(p);
+ HDassert(buf);
+ HDassert(*p >= *buf);
+ HDassert(buf_size);
+
+ /* Allocate or extend buffer if necessary */
+ if(!*buf) {
+ HDassert(!*p);
+ HDassert(*buf_size == 0);
+
+ /* Allocate buffer */
+ if(NULL == (*buf = (char *)H5MM_malloc(src_len + (size_t)1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
+ *buf_size = src_len + (size_t)1;
+ *p = *buf;
+ } /* end if */
+ else {
+ size_t p_offset = (size_t)(*p - *buf); /* Offset of p within buf */
+
+ /* Extend buffer if necessary */
+ if((p_offset + src_len + (size_t)1) > *buf_size) {
+ char *tmp_buf;
+ size_t tmp_buf_size;
+
+ /* Calculate new size of buffer */
+ tmp_buf_size = MAX(p_offset + src_len + (size_t)1,
+ *buf_size * (size_t)2);
+
+ /* Reallocate buffer */
+ if(NULL == (tmp_buf = (char *)H5MM_realloc(*buf, tmp_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to reallocate name segment buffer")
+ *buf = tmp_buf;
+ *buf_size = tmp_buf_size;
+ *p = *buf + p_offset;
+ } /* end if */
+ } /* end else */
+
+ /* Copy string to *p. Note that since src in not NULL terminated, we must
+ * use memcpy */
+ (void)HDmemcpy(*p, src, src_len);
+
+ /* Advance *p */
+ *p += src_len;
+
+ /* Add NULL terminator */
+ **p = '\0';
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5D__virtual_str_append() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_parse_source_name
+ *
+ * Purpose: Parses a source file or dataset name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 18, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_parse_source_name(const char *source_name,
+ H5O_storage_virtual_name_seg_t **parsed_name, size_t *static_strlen,
+ size_t *nsubs)
+{
+ H5O_storage_virtual_name_seg_t *tmp_parsed_name = NULL;
+ H5O_storage_virtual_name_seg_t **tmp_parsed_name_p = &tmp_parsed_name;
+ size_t tmp_static_strlen;
+ size_t tmp_strlen;
+ size_t tmp_nsubs = 0;
+ const char *p;
+ const char *pct;
+ char *name_seg_p = NULL;
+ size_t name_seg_size = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(source_name);
+ HDassert(parsed_name);
+ HDassert(static_strlen);
+ HDassert(nsubs);
+
+ /* Initialize p and tmp_static_strlen */
+ p = source_name;
+ tmp_static_strlen = tmp_strlen = HDstrlen(source_name);
+
+ /* Iterate over name */
+ /* Note this will not work with UTF-8! We should support this eventually
+ * -NAF 5/18/2015 */
+ while((pct = HDstrchr(p, '%'))) {
+ HDassert(pct >= p);
+
+ /* Allocate name segment struct if necessary */
+ if(!*tmp_parsed_name_p)
+ if(NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
+
+ /* Check for type of format specifier */
+ if(pct[1] == 'b') {
+ /* Check for blank string before specifier */
+ if(pct != p)
+ /* Append string to name segment */
+ if(H5D__virtual_str_append(p, (size_t)(pct - p), &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
+
+ /* Update other variables */
+ tmp_parsed_name_p = &(*tmp_parsed_name_p)->next;
+ tmp_static_strlen -= 2;
+ tmp_nsubs++;
+ name_seg_p = NULL;
+ name_seg_size = 0;
+ } /* end if */
+ else if(pct[1] == '%') {
+ /* Append string to name segment (include first '%') */
+ if(H5D__virtual_str_append(p, (size_t)(pct - p) + (size_t)1, &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
+
+ /* Update other variables */
+ tmp_static_strlen -= 1;
+ } /* end else */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid format specifier")
+
+ p = pct + 2;
+ } /* end while */
+
+ /* Copy last segment of name, if any, unless the parsed name was not
+ * allocated */
+ if(tmp_parsed_name) {
+ HDassert(p >= source_name);
+ if(*p == '\0')
+ HDassert((size_t)(p - source_name) == tmp_strlen);
+ else {
+ HDassert((size_t)(p - source_name) < tmp_strlen);
+
+ /* Allocate name segment struct if necessary */
+ if(!*tmp_parsed_name_p)
+ if(NULL == (*tmp_parsed_name_p = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
+
+ /* Append string to name segment */
+ if(H5D__virtual_str_append(p, tmp_strlen - (size_t)(p - source_name), &name_seg_p, &(*tmp_parsed_name_p)->name_segment, &name_seg_size) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to append name segment")
+ } /* end else */
+ } /* end if */
+
+ /* Set return values */
+ *parsed_name = tmp_parsed_name;
+ tmp_parsed_name = NULL;
+ *static_strlen = tmp_static_strlen;
+ *nsubs = tmp_nsubs;
+
+done:
+ if(tmp_parsed_name) {
+ HDassert(ret_value < 0);
+ H5D_virtual_free_parsed_name(tmp_parsed_name);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_parse_source_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_copy_parsed_name
+ *
+ * Purpose: Deep copies a parsed source file or dataset name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 19, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_copy_parsed_name(H5O_storage_virtual_name_seg_t **dst,
+ H5O_storage_virtual_name_seg_t *src)
+{
+ H5O_storage_virtual_name_seg_t *tmp_dst = NULL;
+ H5O_storage_virtual_name_seg_t *p_src = src;
+ H5O_storage_virtual_name_seg_t **p_dst = &tmp_dst;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dst);
+
+ /* Walk over parsed name, duplicating it */
+ while(p_src) {
+ /* Allocate name segment struct */
+ if(NULL == (*p_dst = H5FL_CALLOC(H5O_storage_virtual_name_seg_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name segment struct")
+
+ /* Duplicate name segment */
+ if(p_src->name_segment) {
+ if(NULL == ((*p_dst)->name_segment = H5MM_strdup(p_src->name_segment)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to duplicate name segment")
+ } /* end if */
+
+ /* Advance pointers */
+ p_src = p_src->next;
+ p_dst = &(*p_dst)->next;
+ } /* end while */
+
+ /* Set dst */
+ *dst = tmp_dst;
+ tmp_dst = NULL;
+
+done:
+ if(tmp_dst) {
+ HDassert(ret_value < 0);
+ H5D_virtual_free_parsed_name(tmp_dst);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_copy_parsed_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_virtual_free_parsed_name
+ *
+ * Purpose: Frees the provided parsed name.
+ *
+ * Return: void
+ *
+ * Programmer: Neil Fortner
+ * May 19, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_virtual_free_parsed_name(H5O_storage_virtual_name_seg_t *name_seg)
+{
+ H5O_storage_virtual_name_seg_t *next_seg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Walk name segments, freeing them */
+ while(name_seg) {
+ (void)H5MM_xfree(name_seg->name_segment);
+ next_seg = name_seg->next;
+ (void)H5FL_FREE(H5O_storage_virtual_name_seg_t, name_seg);
+ name_seg = next_seg;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_virtual_free_parsed_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_build_source_name
+ *
+ * Purpose: Builds a source file or dataset name from a parsed name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 18, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_build_source_name(char *source_name,
+ const H5O_storage_virtual_name_seg_t *parsed_name, size_t static_strlen,
+ size_t nsubs, hsize_t blockno, char **built_name)
+{
+ char *tmp_name = NULL; /* Name buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(source_name);
+ HDassert(built_name);
+
+ /* Check for static name */
+ if(nsubs == 0) {
+ if(parsed_name)
+ *built_name = parsed_name->name_segment;
+ else
+ *built_name = source_name;
+ } /* end if */
+ else {
+ const H5O_storage_virtual_name_seg_t *name_seg = parsed_name;
+ char *p;
+ hsize_t blockno_down = blockno;
+ size_t blockno_len = 1;
+ size_t name_len;
+ size_t name_len_rem;
+ size_t seg_len;
+ size_t nsubs_rem = nsubs;
+
+ HDassert(parsed_name);
+
+ /* Calculate length of printed block number */
+ do {
+ blockno_down /= (hsize_t)10;
+ if(blockno_down == 0)
+ break;
+ blockno_len++;
+ } while(1);
+
+ /* Calculate length of name buffer */
+ name_len_rem = name_len = static_strlen + (nsubs * blockno_len) + (size_t)1;
+
+ /* Allocate name buffer */
+ if(NULL == (tmp_name = (char *)H5MM_malloc(name_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate name buffer")
+ p = tmp_name;
+
+ /* Build name */
+ do {
+ /* Add name segment */
+ if(name_seg->name_segment) {
+ seg_len = HDstrlen(name_seg->name_segment);
+ HDassert(seg_len > 0);
+ HDassert(seg_len < name_len_rem);
+ HDstrncpy(p, name_seg->name_segment, name_len_rem);
+ name_len_rem -= seg_len;
+ p += seg_len;
+ } /* end if */
+
+ /* Add block number */
+ if(nsubs_rem > 0) {
+ HDassert(blockno_len < name_len_rem);
+ if(HDsnprintf(p, name_len_rem, "%llu", (long long unsigned)blockno) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write block number to string")
+ name_len_rem -= blockno_len;
+ p += blockno_len;
+ nsubs_rem--;
+ } /* end if */
+
+ /* Advance name_seg */
+ name_seg = name_seg->next;
+ } while(name_seg);
+
+ /* Assign built_name */
+ *built_name = tmp_name;
+ tmp_name = NULL;
+ } /* end else */
+
+done:
+ if(tmp_name) {
+ HDassert(ret_value < 0);
+ H5MM_free(tmp_name);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_build_source_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_set_extent_unlim
+ *
+ * Purpose: Sets the extent of the virtual dataset by checking the
+ * extents of source datasets where an unlimited selection
+ * matching. Dimensions that are not unlimited in any
+ * virtual mapping selections are not affected.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * April 22, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_set_extent_unlim(const H5D_t *dset, hid_t dxpl_id)
+{
+ H5O_storage_virtual_t *storage;
+ hsize_t new_dims[H5S_MAX_RANK];
+ hsize_t curr_dims[H5S_MAX_RANK];
+ hsize_t clip_size;
+ int rank;
+ hbool_t changed = FALSE; /* Whether the VDS extent changed */
+ size_t i, j;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+ HDassert(dset->shared->layout.storage.type == H5D_VIRTUAL);
+ storage = &dset->shared->layout.storage.u.virt;
+ HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
+
+ /* Get rank of VDS */
+ if((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
+
+ /* Initialize new_dims to HSIZE_UNDEF */
+ for(i = 0; i < (size_t)rank; i++)
+ new_dims[i] = HSIZE_UNDEF;
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for unlimited dimension */
+ if(storage->list[i].unlim_dim_virtual >= 0) {
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].unlim_dim_source >= 0 ) {
+ /* Non-printf mapping */
+ /* Open source dataset */
+ if(!storage->list[i].source_dset.dset)
+ if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+
+ /* Check if source dataset is open */
+ if(storage->list[i].source_dset.dset) {
+ /* Retrieve current source dataset extent and patch mapping
+ */
+ if(H5S_extent_copy(storage->list[i].source_select, storage->list[i].source_dset.dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
+
+ /* Get source space dimenstions */
+ if(H5S_get_simple_extent_dims(storage->list[i].source_select, curr_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions")
+
+ /* Check if the source extent in the unlimited dimension
+ * changed since the last time the VDS extent/mapping
+ * was updated */
+ if(curr_dims[storage->list[i].unlim_dim_source]
+ == storage->list[i].unlim_extent_source)
+ /* Use cached result for clip size */
+ clip_size = storage->list[i].clip_size_virtual;
+ else {
+ /* Get size that virtual selection would be clipped to
+ * to match size of source selection within source
+ * extent */
+ clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_dset.virtual_select, storage->list[i].source_select, curr_dims[storage->list[i].unlim_dim_source], storage->view == H5D_VDS_FIRST_MISSING);
+
+ /* If we are setting the extent by the last available
+ * data, clip virtual_select and source_select. Note
+ * that if we used the cached clip_size above or it
+ * happens to be the same, the virtual selection will
+ * already be clipped to the correct size. Likewise,
+ * if we used the cached clip_size the source selection
+ * will already be correct. */
+ if(storage->view == H5D_VDS_LAST_AVAILABLE) {
+ if(clip_size != storage->list[i].clip_size_virtual) {
+ /* Close previous clipped virtual selection, if
+ * any */
+ if(storage->list[i].source_dset.clipped_virtual_select) {
+ HDassert(storage->list[i].source_dset.clipped_virtual_select
+ != storage->list[i].source_dset.virtual_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
+ } /* end if */
+
+ /* Copy virtual selection */
+ if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Clip virtual selection */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, clip_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+ } /* end if */
+
+ /* Close previous clipped source selection, if any
+ */
+ if(storage->list[i].source_dset.clipped_source_select) {
+ HDassert(storage->list[i].source_dset.clipped_source_select
+ != storage->list[i].source_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
+ } /* end if */
+
+ /* Copy source selection */
+ if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+
+ /* Clip source selection */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, curr_dims[storage->list[i].unlim_dim_source]))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+ } /* end if */
+
+ /* Update cached values unlim_extent_source and
+ * clip_size_virtual */
+ storage->list[i].unlim_extent_source = curr_dims[storage->list[i].unlim_dim_source];
+ storage->list[i].clip_size_virtual = clip_size;
+ } /* end else */
+ } /* end if */
+ else
+ clip_size = 0;
+ } /* end if */
+ else {
+ /* printf mapping */
+ hsize_t first_missing = 0; /* First missing dataset in the current block of missing datasets */
+
+ /* Search for source datasets */
+ HDassert(storage->printf_gap != HSIZE_UNDEF);
+ for(j = 0; j <= (storage->printf_gap + first_missing); j++) {
+ /* Check for running out of space in sub_dset array */
+ if(j >= (hsize_t)storage->list[i].sub_dset_nalloc) {
+ if(storage->list[i].sub_dset_nalloc == 0) {
+ /* Allocate sub_dset */
+ if(NULL == (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(H5D_VIRTUAL_DEF_SUB_DSET_SIZE * sizeof(H5O_storage_virtual_srcdset_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate sub dataset array")
+ storage->list[i].sub_dset_nalloc = H5D_VIRTUAL_DEF_SUB_DSET_SIZE;
+ } /* end if */
+ else {
+ H5O_storage_virtual_srcdset_t *tmp_sub_dset;
+
+ /* Extend sub_dset */
+ if(NULL == (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(storage->list[i].sub_dset, 2 * storage->list[i].sub_dset_nalloc * sizeof(H5O_storage_virtual_srcdset_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend sub dataset array")
+ storage->list[i].sub_dset = tmp_sub_dset;
+
+ /* Clear new space in sub_dset */
+ (void)HDmemset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0, storage->list[i].sub_dset_nalloc * sizeof(H5O_storage_virtual_srcdset_t));
+
+ /* Update sub_dset_nalloc */
+ storage->list[i].sub_dset_nalloc *= 2;
+ } /* end else */
+ } /* end if */
+
+ /* Check if the dataset was already opened */
+ if(storage->list[i].sub_dset[j].dset_exists)
+ first_missing = j + 1;
+ else {
+ /* Resolve file name */
+ if(!storage->list[i].sub_dset[j].file_name)
+ if(H5D__virtual_build_source_name(storage->list[i].source_file_name, storage->list[i].parsed_source_file_name, storage->list[i].psfn_static_strlen, storage->list[i].psfn_nsubs, j, &storage->list[i].sub_dset[j].file_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source file name")
+
+ /* Resolve dset name */
+ if(!storage->list[i].sub_dset[j].dset_name)
+ if(H5D__virtual_build_source_name(storage->list[i].source_dset_name, storage->list[i].parsed_source_dset_name, storage->list[i].psdn_static_strlen, storage->list[i].psdn_nsubs, j, &storage->list[i].sub_dset[j].dset_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source dataset name")
+
+ /* Resolve virtual selection for block */
+ if(!storage->list[i].sub_dset[j].virtual_select)
+ if(NULL == (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(storage->list[i].source_dset.virtual_select, j)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get block in unlimited selection")
+
+ /* Initialize clipped selections */
+ if(!storage->list[i].sub_dset[j].clipped_source_select)
+ storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
+ if(!storage->list[i].sub_dset[j].clipped_virtual_select)
+ storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
+
+ /* Open source dataset */
+ if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j], dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+
+ if(storage->list[i].sub_dset[j].dset) {
+ /* Update first_missing */
+ first_missing = j + 1;
+
+ /* Close source dataset so we don't have huge
+ * numbers of datasets open */
+ if(H5D_close(storage->list[i].sub_dset[j].dset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to close source dataset")
+ storage->list[i].sub_dset[j].dset = NULL;
+ } /* end if */
+ } /* end else */
+ } /* end for */
+
+ /* Check if the size changed */
+ if((first_missing == (hsize_t)storage->list[i].sub_dset_nused)
+ && (storage->list[i].clip_size_virtual != HSIZE_UNDEF))
+ /* Use cached clip_size */
+ clip_size = storage->list[i].clip_size_virtual;
+ else {
+ /* Check for no datasets */
+ if(first_missing == 0)
+ /* Set clip size to 0 */
+ clip_size = (hsize_t)0;
+ else {
+ hsize_t bounds_start[H5S_MAX_RANK];
+ hsize_t bounds_end[H5S_MAX_RANK];
+
+ /* Get clip size from selection */
+ if(storage->view == H5D_VDS_LAST_AVAILABLE) {
+ /* Get bounds from last valid virtual selection */
+ if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[first_missing - (hsize_t)1].virtual_select, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
+
+ /* Set clip_size to bounds_end in unlimited
+ * dimension */
+ clip_size = bounds_end[storage->list[i].unlim_dim_virtual] + (hsize_t)1;
+ } /* end if */
+ else {
+ /* Get bounds from first missing virtual selection
+ */
+ if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[first_missing].virtual_select, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
+
+ /* Set clip_size to bounds_start in unlimited
+ * dimension */
+ clip_size = bounds_start[storage->list[i].unlim_dim_virtual];
+ } /* end else */
+ } /* end else */
+
+ /* Set sub_dset_nused and clip_size_virtual */
+ storage->list[i].sub_dset_nused = (size_t)first_missing;
+ storage->list[i].clip_size_virtual = clip_size;
+ } /* end else */
+ } /* end else */
+
+ /* Update new_dims */
+ if((new_dims[storage->list[i].unlim_dim_virtual] == HSIZE_UNDEF)
+ || (storage->view == H5D_VDS_FIRST_MISSING ? (clip_size < (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])
+ : (clip_size > (hsize_t)new_dims[storage->list[i].unlim_dim_virtual])))
+ new_dims[storage->list[i].unlim_dim_virtual] = clip_size;
+ } /* end if */
+
+ /* Get current VDS dimensions */
+ if(H5S_get_simple_extent_dims(dset->shared->space, curr_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
+
+ /* Calculate new extent */
+ for(i = 0; i < (size_t)rank; i++) {
+ if(new_dims[i] == HSIZE_UNDEF)
+ new_dims[i] = curr_dims[i];
+ else if(new_dims[i] < storage->min_dims[i])
+ new_dims[i] = storage->min_dims[i];
+ if(new_dims[i] != curr_dims[i])
+ changed = TRUE;
+ } /* end for */
+
+ /* Update extent if it changed */
+ if(changed) {
+ /* Update VDS extent */
+ if(H5S_set_extent(dset->shared->space, new_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+
+ /* Mark the space as dirty, for later writing to the file */
+ if(H5F_INTENT(dset->oloc.file) & H5F_ACC_RDWR)
+ if(H5D__mark(dset, dxpl_id, H5D_MARK_SPACE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark dataspace as dirty")
+ } /* end if */
+
+ /* If we did not change the VDS dimensions, there is nothing more to update
+ */
+ if(changed || (!storage->init && (storage->view == H5D_VDS_FIRST_MISSING))) {
+ /* Iterate over mappings again to update source selections and virtual
+ * mapping extents */
+ for(i = 0; i < storage->list_nused; i++) {
+ /* If there is an unlimited dimension, we are setting extent by the
+ * minimum of mappings, and the virtual extent in the unlimited
+ * dimension has changed since the last time the VDS extent/mapping
+ * was updated, we must adjust the selections */
+ if((storage->list[i].unlim_dim_virtual >= 0)
+ && (storage->view == H5D_VDS_FIRST_MISSING)
+ && (new_dims[storage->list[i].unlim_dim_virtual]
+ != storage->list[i].unlim_extent_virtual)) {
+ /* Check for "printf" style mapping */
+ if(storage->list[i].unlim_dim_source >= 0) {
+ /* Non-printf mapping */
+ /* Close previous clipped virtual selection, if any */
+ if(storage->list[i].source_dset.clipped_virtual_select) {
+ HDassert(storage->list[i].source_dset.clipped_virtual_select
+ != storage->list[i].source_dset.virtual_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
+ } /* end if */
+
+ /* Copy virtual selection */
+ if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Clip space to virtual extent */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, new_dims[storage->list[i].unlim_dim_source]))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* Get size that source selection will be clipped to to
+ * match size of virtual selection */
+ clip_size = H5S_hyper_get_clip_extent(storage->list[i].source_select, storage->list[i].source_dset.clipped_virtual_select, FALSE);
+
+ /* Check if the clip size changed */
+ if(clip_size != storage->list[i].clip_size_source) {
+ /* Close previous clipped source selection, if any */
+ if(storage->list[i].source_dset.clipped_source_select) {
+ HDassert(storage->list[i].source_dset.clipped_source_select
+ != storage->list[i].source_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
+ } /* end if */
+
+ /* Copy source selection */
+ if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+
+ /* Clip source selection */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, clip_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* Update cached value clip_size_source */
+ storage->list[i].clip_size_source = clip_size;
+ } /* end if */
+ } /* end if */
+ else {
+ /* printf mapping */
+ hsize_t first_inc_block;
+ hbool_t partial_block;
+
+ /* Get index of first incomplete block in virtual
+ * selection */
+ first_inc_block = H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, new_dims[storage->list[i].unlim_dim_virtual], &partial_block);
+
+ /* Iterate over sub datasets */
+ for(j = 0; j < storage->list[i].sub_dset_nalloc; j++) {
+ /* Close previous clipped source selection, if any */
+ if(storage->list[i].sub_dset[j].clipped_source_select
+ != storage->list[i].source_select) {
+ if(storage->list[i].sub_dset[j].clipped_source_select)
+ if(H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
+
+ /* Initialize clipped source selection to point to
+ * base source selection */
+ storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
+ } /* end if */
+
+ /* Close previous clipped virtual selection, if any */
+ if(storage->list[i].sub_dset[j].clipped_virtual_select
+ != storage->list[i].sub_dset[j].virtual_select) {
+ if(storage->list[i].sub_dset[j].clipped_virtual_select)
+ if(H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
+
+ /* Initialize clipped virtual selection to point to
+ * unclipped virtual selection */
+ storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
+ } /* end if */
+
+ /* Only initialize clipped selections if it is a
+ * complete block, for incomplete blocks defer to
+ * H5D__virtual_pre_io() as we may not have a valid
+ * source extent here. For unused blocks we will never
+ * need clipped selections (until the extent is
+ * recalculated in this function). */
+ if(j >= (size_t)first_inc_block) {
+ /* Clear clipped source and virtual selections */
+ storage->list[i].sub_dset[j].clipped_source_select = NULL;
+ storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
+ } /* end if */
+ } /* end for */
+ } /* end else */
+
+ /* Update cached value unlim_extent_virtual */
+ storage->list[i].unlim_extent_virtual = new_dims[storage->list[i].unlim_dim_virtual];
+ } /* end if */
+
+ /* Update top level virtual_select and clipped_virtual_select
+ * extents */
+ if(H5S_set_extent(storage->list[i].source_dset.virtual_select, new_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ if((storage->list[i].source_dset.clipped_virtual_select
+ != storage->list[i].source_dset.virtual_select)
+ && storage->list[i].source_dset.clipped_virtual_select)
+ if(H5S_set_extent(storage->list[i].source_dset.clipped_virtual_select, new_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+
+ /* Update sub dataset virtual_select and clipped_virtual_select
+ * extents */
+ for(j = 0; j < storage->list[i].sub_dset_nalloc; j++)
+ if(storage->list[i].sub_dset[j].virtual_select) {
+ if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, new_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ if((storage->list[i].sub_dset[j].clipped_virtual_select
+ != storage->list[i].sub_dset[j].virtual_select)
+ && storage->list[i].sub_dset[j].clipped_virtual_select)
+ if(H5S_set_extent(storage->list[i].sub_dset[j].clipped_virtual_select, new_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ } /* end if */
+ else
+ HDassert(!storage->list[i].sub_dset[j].clipped_virtual_select);
+ } /* end for */
+ } /* end if */
+
+ /* Mark layout as fully initialized */
+ storage->init = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_set_extent_unlim() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_init_all
+ *
+ * Purpose: Finishes initializing layout in preparation for I/O.
+ * Only necessary if H5D__virtual_set_extent_unlim() has not
+ * been called yet. Initializes clipped_virtual_select and
+ * clipped_source_select for all mappings in this layout.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * August 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_init_all(const H5D_t *dset, hid_t dxpl_id)
+{
+ H5O_storage_virtual_t *storage;
+ hsize_t virtual_dims[H5S_MAX_RANK];
+ hsize_t source_dims[H5S_MAX_RANK];
+ hsize_t clip_size;
+ size_t i, j;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset);
+ HDassert(dset->shared->layout.storage.type == H5D_VIRTUAL);
+ storage = &dset->shared->layout.storage.u.virt;
+ HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
+
+ /* Get current VDS dimensions */
+ if(H5S_get_simple_extent_dims(dset->shared->space, virtual_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for unlimited dimension */
+ if(storage->list[i].unlim_dim_virtual >= 0) {
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].unlim_dim_source >= 0 ) {
+ /* Non-printf mapping */
+ /* Open source dataset */
+ if(!storage->list[i].source_dset.dset)
+ if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+
+ /* Check if source dataset is open */
+ if(storage->list[i].source_dset.dset) {
+ /* Retrieve current source dataset extent and patch mapping
+ */
+ if(H5S_extent_copy(storage->list[i].source_select, storage->list[i].source_dset.dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy source dataspace extent")
+
+ /* Get source space dimenstions */
+ if(H5S_get_simple_extent_dims(storage->list[i].source_select, source_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get source space dimensions")
+
+ /* Get size that source selection would be clipped to to
+ * match size of virtual selection */
+ clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_select, storage->list[i].source_dset.virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual], FALSE);
+
+ /* Close previous clipped virtual selection, if any */
+ if(storage->list[i].source_dset.clipped_virtual_select) {
+ HDassert(storage->list[i].source_dset.clipped_virtual_select
+ != storage->list[i].source_dset.virtual_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_virtual_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
+ } /* end if */
+
+ /* Copy virtual selection */
+ if(NULL == (storage->list[i].source_dset.clipped_virtual_select = H5S_copy(storage->list[i].source_dset.virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Close previous clipped source selection, if any */
+ if(storage->list[i].source_dset.clipped_source_select) {
+ HDassert(storage->list[i].source_dset.clipped_source_select
+ != storage->list[i].source_select);
+ if(H5S_close(storage->list[i].source_dset.clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
+ } /* end if */
+
+ /* Copy source selection */
+ if(NULL == (storage->list[i].source_dset.clipped_source_select = H5S_copy(storage->list[i].source_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+
+ /* Check if the clip size is within the current extent of
+ * the source dataset */
+ if(clip_size <= source_dims[storage->list[i].unlim_dim_source]) {
+ /* Clip virtual selection to extent */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual]))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* Clip source selection to clip_size */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, clip_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+ } /* end if */
+ else {
+ /* Get size that virtual selection will be clipped to to
+ * match size of source selection within source extent
+ */
+ clip_size = H5S_hyper_get_clip_extent_match(storage->list[i].source_dset.virtual_select, storage->list[i].source_select, source_dims[storage->list[i].unlim_dim_source], FALSE);
+
+ /* Clip virtual selection to clip_size */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_virtual_select, clip_size))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* Clip source selection to extent */
+ if(H5S_hyper_clip_unlim(storage->list[i].source_dset.clipped_source_select, source_dims[storage->list[i].unlim_dim_source]))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+ } /* end else */
+ } /* end if */
+ else {
+ HDassert(!storage->list[i].source_dset.clipped_virtual_select);
+ HDassert(!storage->list[i].source_dset.clipped_source_select);
+ } /* end else */
+ } /* end if */
+ else {
+ /* printf mapping */
+ size_t sub_dset_max;
+ hbool_t partial_block;
+
+ /* Get number of sub-source datasets in current extent */
+ sub_dset_max = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual], &partial_block);
+ if(partial_block)
+ sub_dset_max++;
+
+ /* Allocate or grow the sub_dset array if necessary */
+ if(!storage->list[i].sub_dset) {
+ /* Allocate sub_dset array */
+ if(NULL == (storage->list[i].sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_calloc(sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate sub dataset array")
+
+ /* Update sub_dset_nalloc */
+ storage->list[i].sub_dset_nalloc = sub_dset_max;
+ } /* end if */
+ else if(sub_dset_max > storage->list[i].sub_dset_nalloc) {
+ H5O_storage_virtual_srcdset_t *tmp_sub_dset;
+
+ /* Extend sub_dset array */
+ if(NULL == (tmp_sub_dset = (H5O_storage_virtual_srcdset_t *)H5MM_realloc(storage->list[i].sub_dset, sub_dset_max * sizeof(H5O_storage_virtual_srcdset_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend sub dataset array")
+ storage->list[i].sub_dset = tmp_sub_dset;
+
+ /* Clear new space in sub_dset */
+ (void)HDmemset(&storage->list[i].sub_dset[storage->list[i].sub_dset_nalloc], 0, (sub_dset_max - storage->list[i].sub_dset_nalloc) * sizeof(H5O_storage_virtual_srcdset_t));
+
+ /* Update sub_dset_nalloc */
+ storage->list[i].sub_dset_nalloc = sub_dset_max;
+ } /* end if */
+
+ /* Iterate over sub dsets */
+ for(j = 0; j < sub_dset_max; j++) {
+ /* Resolve file name */
+ if(!storage->list[i].sub_dset[j].file_name)
+ if(H5D__virtual_build_source_name(storage->list[i].source_file_name, storage->list[i].parsed_source_file_name, storage->list[i].psfn_static_strlen, storage->list[i].psfn_nsubs, j, &storage->list[i].sub_dset[j].file_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source file name")
+
+ /* Resolve dset name */
+ if(!storage->list[i].sub_dset[j].dset_name)
+ if(H5D__virtual_build_source_name(storage->list[i].source_dset_name, storage->list[i].parsed_source_dset_name, storage->list[i].psdn_static_strlen, storage->list[i].psdn_nsubs, j, &storage->list[i].sub_dset[j].dset_name) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to build source dataset name")
+
+ /* Resolve virtual selection for block */
+ if(!storage->list[i].sub_dset[j].virtual_select)
+ if(NULL == (storage->list[i].sub_dset[j].virtual_select = H5S_hyper_get_unlim_block(storage->list[i].source_dset.virtual_select, j)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get block in unlimited selection")
+
+ /* Close previous clipped source selection, if any */
+ if(storage->list[i].sub_dset[j].clipped_source_select != storage->list[i].source_select) {
+ if(storage->list[i].sub_dset[j].clipped_source_select)
+ if(H5S_close(storage->list[i].sub_dset[j].clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped source dataspace")
+
+ /* Initialize clipped source selection to point to base
+ * source selection */
+ storage->list[i].sub_dset[j].clipped_source_select = storage->list[i].source_select;
+ } /* end if */
+
+ /* Close previous clipped virtual selection, if any */
+ if(storage->list[i].sub_dset[j].clipped_virtual_select != storage->list[i].sub_dset[j].virtual_select) {
+ if(storage->list[i].sub_dset[j].clipped_virtual_select)
+ if(H5S_close(storage->list[i].sub_dset[j].clipped_virtual_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release clipped virtual dataspace")
+
+ /* Initialize clipped virtual selection to point to
+ * unclipped virtual selection */
+ storage->list[i].sub_dset[j].clipped_virtual_select = storage->list[i].sub_dset[j].virtual_select;
+ } /* end if */
+
+ /* Clear clipped selections if this is a partial block,
+ * defer calculation of real clipped selections to
+ * H5D__virtual_pre_io() as we may not have a valid source
+ * extent here */
+ if((j == (sub_dset_max - 1)) && partial_block) {
+ /* Clear clipped source and virtual selections */
+ storage->list[i].sub_dset[j].clipped_source_select = NULL;
+ storage->list[i].sub_dset[j].clipped_virtual_select = NULL;
+ } /* end else */
+ /* Note we do not need to open the source file, this will
+ * happen later in H5D__virtual_pre_io() */
+ } /* end for */
+
+ /* Update sub_dset_nused */
+ storage->list[i].sub_dset_nused = sub_dset_max;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Limited mapping, just make sure the clipped selections were
+ * already set. Again, no need to open the source file. */
+ HDassert(storage->list[i].source_dset.clipped_virtual_select);
+ HDassert(storage->list[i].source_dset.clipped_source_select);
+ } /* end else */
+
+ /* Mark layout as fully initialized */
+ storage->init = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_init_all() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_init
+ *
+ * Purpose: Initialize the virtual layout information for a dataset.
+ * This is called when the dataset is initialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Thursday, April 30, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_init(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, const H5D_t *dset,
+ hid_t dapl_id)
+{
+ H5O_storage_virtual_t *storage; /* Convenience pointer */
+ H5P_genplist_t *dapl; /* Data access property list object pointer */
+ hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset (unused) */
+ size_t i; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+ storage = &dset->shared->layout.storage.u.virt;
+ HDassert(storage->list || (storage->list_nused == 0));
+
+ /* Check that the dimensions of the VDS are large enough */
+ if(H5D_virtual_check_min_dims(dset) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "virtual dataset dimensions not large enough to contain all limited dimensions in all selections")
+
+ /* Patch the virtual selection dataspaces. Note we always patch the space
+ * status because this layout could be from an old version held in the
+ * object header message code. We cannot update that held message because
+ * the layout message is constant, so just overwrite the values here (and
+ * invalidate other fields by setting storage->init to FALSE below). Also
+ * remove offset from selections. We only have to update
+ * source_space_status and virtual_space_status because others will be based
+ * on these and should therefore already have been normalized. */
+ for(i = 0; i < storage->list_nused; i++) {
+ HDassert(storage->list[i].sub_dset_nalloc == 0);
+
+ /* Patch extent */
+ if(H5S_extent_copy(storage->list[i].source_dset.virtual_select, dset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy virtual dataspace extent")
+ storage->list[i].virtual_space_status = H5O_VIRTUAL_STATUS_CORRECT;
+
+ /* Mark source extent as invalid */
+ storage->list[i].source_space_status = H5O_VIRTUAL_STATUS_INVALID;
+
+ /* Normalize offsets, toss out old offset values */
+ if(H5S_hyper_normalize_offset(storage->list[i].source_dset.virtual_select, old_offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
+ if(H5S_hyper_normalize_offset(storage->list[i].source_select, old_offset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset")
+ } /* end for */
+
+ /* Get dataset access property list */
+ if(NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for dapl ID")
+
+ /* Get view option */
+ if(H5P_get(dapl, H5D_ACS_VDS_VIEW_NAME, &storage->view) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual view option")
+
+ /* Get printf gap if view is H5D_VDS_LAST_AVAILABLE, otherwise set to 0 */
+ if(storage->view == H5D_VDS_LAST_AVAILABLE) {
+ if(H5P_get(dapl, H5D_ACS_VDS_PRINTF_GAP_NAME, &storage->printf_gap) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get virtual printf gap")
+ } /* end if */
+ else
+ storage->printf_gap = (hsize_t)0;
+
+ /* Retrieve VDS file FAPL to layout */
+ if(storage->source_fapl <= 0)
+ if((storage->source_fapl = H5F_get_access_plist(f, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fapl")
+
+ /* Copy DAPL to layout */
+ if(storage->source_dapl <= 0)
+ if((storage->source_dapl = H5P_copy_plist(dapl, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't copy dapl")
+
+ /* Mark layout as not fully initialized (must be done prior to I/O for
+ * unlimited/printf selections) */
+ storage->init = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_is_space_alloc
+ *
+ * Purpose: Query if space is allocated for layout
+ *
+ * Return: TRUE if space is allocated
+ * FALSE if it is not
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5D__virtual_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage)
+{
+ hbool_t ret_value; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Just return TRUE, since the global heap object containing the mappings is
+ * created when the layout message is encoded, and nothing else needs to be
+ * allocated for virtual datasets. This also ensures that the library never
+ * assumes (falsely) that no data is present in the dataset, causing errors.
+ */
+ ret_value = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_is_space_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_pre_io
+ *
+ * Purpose: Project all virtual mappings onto mem_space, with the
+ * results stored in projected_mem_space for each mapping.
+ * Opens all source datasets if possible. The total number
+ * of elements is stored in tot_nelmts.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * June 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_pre_io(H5D_io_info_t *io_info,
+ H5O_storage_virtual_t *storage, const H5S_t *file_space,
+ const H5S_t *mem_space, hsize_t *tot_nelmts)
+{
+ hssize_t select_nelmts; /* Number of elements in selection */
+ hsize_t bounds_start[H5S_MAX_RANK]; /* Selection bounds start */
+ hsize_t bounds_end[H5S_MAX_RANK]; /* Selection bounds end */
+ int rank;
+ hbool_t bounds_init = FALSE; /* Whether bounds_start, bounds_end, and rank are valid */
+ size_t i, j, k; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(storage);
+ HDassert(mem_space);
+ HDassert(file_space);
+ HDassert(tot_nelmts);
+
+ /* Initialize layout if necessary */
+ if(!storage->init)
+ if(H5D__virtual_init_all(io_info->dset, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout")
+
+ /* Initialize tot_nelmts */
+ *tot_nelmts = 0;
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++) {
+ /* Sanity check that the virtual space has been patched by now */
+ HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
+
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ hbool_t partial_block;
+
+ HDassert(storage->list[i].unlim_dim_virtual >= 0);
+
+ /* Get selection bounds if necessary */
+ if(!bounds_init) {
+ /* Get rank of VDS */
+ if((rank = H5S_GET_EXTENT_NDIMS(io_info->dset->shared->space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions")
+
+ /* Get selection bounds */
+ if(H5S_SELECT_BOUNDS(file_space, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
+
+ /* Adjust bounds_end to represent the extent just enclosing them
+ * (add 1) */
+ for(j = 0; j < (size_t)rank; j++)
+ bounds_end[j]++;
+
+ /* Bounds are now initialized */
+ bounds_init = TRUE;
+ } /* end if */
+
+ /* Get index of first block in virtual selection */
+ storage->list[i].sub_dset_io_start = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, bounds_start[storage->list[i].unlim_dim_virtual], NULL);
+
+ /* Get index of first block outside of virtual selection */
+ storage->list[i].sub_dset_io_end = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, bounds_end[storage->list[i].unlim_dim_virtual], &partial_block);
+ if(partial_block)
+ storage->list[i].sub_dset_io_end++;
+ if(storage->list[i].sub_dset_io_end > storage->list[i].sub_dset_nused)
+ storage->list[i].sub_dset_io_end = storage->list[i].sub_dset_nused;
+
+ /* Iterate over sub-source dsets */
+ for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) {
+ /* Check for clipped virtual selection */
+ if(!storage->list[i].sub_dset[j].clipped_virtual_select) {
+ hsize_t start[H5S_MAX_RANK];
+ /* This should only be NULL if this is a partial block */
+ HDassert((j == (storage->list[i].sub_dset_io_end - 1)) && partial_block);
+
+ /* If the source space status is not correct, we must try to
+ * open the source dataset to patch it */
+ if(storage->list[i].source_space_status != H5O_VIRTUAL_STATUS_CORRECT) {
+ HDassert(!storage->list[i].sub_dset[j].dset);
+ if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+ } /* end if */
+
+ /* If we obtained a valid source space, we must create
+ * clipped source and virtual selections, otherwise we
+ * cannot do this and we will leave them NULL. This doesn't
+ * hurt anything because we can't do I/O because the dataset
+ * must not have been found. */
+ if(storage->list[i].source_space_status == H5O_VIRTUAL_STATUS_CORRECT) {
+ hsize_t tmp_dims[H5S_MAX_RANK];
+ hsize_t vbounds_end[H5S_MAX_RANK];
+
+ /* Get bounds of virtual selection */
+ if(H5S_SELECT_BOUNDS(storage->list[i].sub_dset[j].virtual_select, tmp_dims, vbounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get selection bounds")
+
+ HDassert(bounds_init);
+
+ /* Convert bounds to extent (add 1) */
+ for(k = 0; k < (size_t)rank; k++)
+ vbounds_end[k]++;
+
+ /* Temporarily set extent of virtual selection to bounds */
+ if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, vbounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+
+ /* Get current VDS dimensions */
+ if(H5S_get_simple_extent_dims(io_info->dset->shared->space, tmp_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions")
+
+ /* Copy virtual selection */
+ if(NULL == (storage->list[i].sub_dset[j].clipped_virtual_select = H5S_copy(storage->list[i].sub_dset[j].virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Clip virtual selection to real virtual extent */
+ (void)HDmemset(start, 0, sizeof(start));
+ if(H5S_select_hyperslab(storage->list[i].sub_dset[j].clipped_virtual_select, H5S_SELECT_AND, start, NULL, tmp_dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to clip hyperslab")
+
+ /* Project intersection of virtual space and clipped
+ * virtual space onto source space (create
+ * clipped_source_select) */
+ if(H5S_select_project_intersection(storage->list[i].sub_dset[j].virtual_select, storage->list[i].source_select, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].clipped_source_select) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
+
+ /* Set extents of virtual_select and
+ * clipped_virtual_select to virtual extent */
+ if(H5S_set_extent(storage->list[i].sub_dset[j].virtual_select, tmp_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ if(H5S_set_extent(storage->list[i].sub_dset[j].clipped_virtual_select, tmp_dims) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space")
+ } /* end if */
+ } /* end if */
+
+ /* Only continue if we managed to obtain a
+ * clipped_virtual_select */
+ if(storage->list[i].sub_dset[j].clipped_virtual_select) {
+ /* Project intersection of file space and mapping virtual space
+ * onto memory space */
+ if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
+
+ /* Check number of elements selected */
+ if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(storage->list[i].sub_dset[j].projected_mem_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
+
+ /* Check if anything is selected */
+ if(select_nelmts > (hssize_t)0) {
+ /* Open source dataset */
+ if(!storage->list[i].sub_dset[j].dset)
+ /* Try to open dataset */
+ if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+
+ /* If the source dataset is not open, mark the selected
+ * elements as zero so projected_mem_space is freed */
+ if(!storage->list[i].sub_dset[j].dset)
+ select_nelmts = (hssize_t)0;
+ } /* end if */
+
+ /* If there are not elements selected in this mapping, free
+ * projected_mem_space, otherwise update tot_nelmts */
+ if(select_nelmts == (hssize_t)0) {
+ if(H5S_close(storage->list[i].sub_dset[j].projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space")
+ storage->list[i].sub_dset[j].projected_mem_space = NULL;
+ } /* end if */
+ else
+ *tot_nelmts += (hsize_t)select_nelmts;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else {
+ if(storage->list[i].source_dset.clipped_virtual_select) {
+ /* Project intersection of file space and mapping virtual space onto
+ * memory space */
+ if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].source_dset.clipped_virtual_select, &storage->list[i].source_dset.projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space")
+
+ /* Check number of elements selected, add to tot_nelmts */
+ if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(storage->list[i].source_dset.projected_mem_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
+
+ /* Check if anything is selected */
+ if(select_nelmts > (hssize_t)0) {
+ /* Open source dataset */
+ if(!storage->list[i].source_dset.dset)
+ /* Try to open dataset */
+ if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].source_dset, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset")
+
+ /* If the source dataset is not open, mark the selected elements
+ * as zero so projected_mem_space is freed */
+ if(!storage->list[i].source_dset.dset)
+ select_nelmts = (hssize_t)0;
+ } /* end if */
+
+ /* If there are not elements selected in this mapping, free
+ * projected_mem_space, otherwise update tot_nelmts */
+ if(select_nelmts == (hssize_t)0) {
+ if(H5S_close(storage->list[i].source_dset.projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected memory space")
+ storage->list[i].source_dset.projected_mem_space = NULL;
+ } /* end if */
+ else
+ *tot_nelmts += (hsize_t)select_nelmts;
+ } /* end if */
+ else {
+ /* If there is no clipped_dim_virtual, this must be an unlimited
+ * selection whose dataset was not found in the last call to
+ * H5Dget_space(). Do not attempt to open it as this might
+ * affect the extent and we are not going to recalculate it
+ * here. */
+ HDassert(storage->list[i].unlim_dim_virtual >= 0);
+ HDassert(!storage->list[i].source_dset.dset);
+ } /* end else */
+ } /* end else */
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_pre_io() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_post_io
+ *
+ * Purpose: Frees memory structures allocated by H5D__virtual_pre_io.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * June 4, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_post_io(H5O_storage_virtual_t *storage)
+{
+ size_t i, j; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(storage);
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ /* Iterate over sub-source dsets */
+ for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++)
+ /* Close projected memory space */
+ if(storage->list[i].sub_dset[j].projected_mem_space) {
+ if(H5S_close(storage->list[i].sub_dset[j].projected_mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space")
+ storage->list[i].sub_dset[j].projected_mem_space = NULL;
+ } /* end if */
+ } /* end if */
+ else
+ /* Close projected memory space */
+ if(storage->list[i].source_dset.projected_mem_space) {
+ if(H5S_close(storage->list[i].source_dset.projected_mem_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close temporary space")
+ storage->list[i].source_dset.projected_mem_space = NULL;
+ } /* end if */
+
+ /* Note the lack of a done: label. This is because there are no HGOTO_ERROR
+ * calls. If one is added, a done: label must also be added */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_post_io() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_read_one
+ *
+ * Purpose: Read from a singe source dataset in a virtual dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 15, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset)
+{
+ H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(source_dset);
+
+ /* Only perform I/O if there is a projected memory space, otherwise there
+ * were no elements in the projection or the source dataset could not be
+ * opened */
+ if(source_dset->projected_mem_space) {
+ HDassert(source_dset->dset);
+ HDassert(source_dset->clipped_source_select);
+
+ /* Project intersection of file space and mapping virtual space onto
+ * mapping source space */
+ if(H5S_select_project_intersection(source_dset->clipped_virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space")
+
+ /* Perform read on source dataset */
+ if(H5D__read(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->raw_dxpl_id, io_info->u.rbuf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset")
+
+ /* Close projected_src_space */
+ if(H5S_close(projected_src_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
+ projected_src_space = NULL;
+ } /* end if */
+
+done:
+ /* Release allocated resources on failure */
+ if(projected_src_space) {
+ HDassert(ret_value < 0);
+ if(H5S_close(projected_src_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_read_one() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_read
+ *
+ * Purpose: Read from a virtual dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */
+ H5S_t *fill_space = NULL; /* Space to fill with fill value */
+ size_t i, j; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.rbuf);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+
+ storage = &io_info->dset->shared->layout.storage.u.virt;
+ HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
+
+#ifdef H5_HAVE_PARALLEL
+ /* Parallel reads are not supported (yet) */
+ if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Prepare for I/O operation */
+ if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation")
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++) {
+ /* Sanity check that the virtual space has been patched by now */
+ HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
+
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ /* Iterate over sub-source dsets */
+ for(j = storage->list[i].sub_dset_io_start;
+ j < storage->list[i].sub_dset_io_end; j++)
+ if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset")
+ } /* end if */
+ else
+ /* Read from source dataset */
+ if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset")
+ } /* end for */
+
+ /* Fill unmapped part of buffer with fill value */
+ if(tot_nelmts < nelmts) {
+ H5D_fill_value_t fill_status; /* Fill value status */
+
+ /* Check the fill value status */
+ if(H5P_is_fill_value_defined(&io_info->dset->shared->dcpl_cache.fill, &fill_status) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if fill value defined")
+
+ /* Always write fill value to memory buffer unless it is undefined */
+ if(fill_status != H5D_FILL_VALUE_UNDEFINED) {
+ /* Start with fill space equal to memory space */
+ if(NULL == (fill_space = H5S_copy(mem_space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy memory selection")
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ /* Iterate over sub-source dsets */
+ for(j = storage->list[i].sub_dset_io_start;
+ j < storage->list[i].sub_dset_io_end; j++)
+ if(storage->list[i].sub_dset[j].projected_mem_space)
+ if(H5S_select_subtract(fill_space, storage->list[i].sub_dset[j].projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection")
+ } /* end if */
+ else
+ if(storage->list[i].source_dset.projected_mem_space)
+ /* Subtract projected memory space from fill space */
+ if(H5S_select_subtract(fill_space, storage->list[i].source_dset.projected_mem_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection")
+
+ /* Write fill values to memory buffer */
+ if(H5D__fill(io_info->dset->shared->dcpl_cache.fill.buf, io_info->dset->shared->type, io_info->u.rbuf,
+ type_info->mem_type, fill_space, io_info->md_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "filling buf failed")
+
+#ifndef NDEBUG
+ /* Make sure the total number of elements written (including fill
+ * values) >= nelmts */
+ {
+ hssize_t select_nelmts; /* Number of elements in selection */
+
+ /* Get number of elements in fill dataspace */
+ if((select_nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(fill_space)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
+
+ /* Verify number of elements is correct. Note that since we
+ * don't check for overlap we can't assert that these are equal
+ */
+ HDassert((tot_nelmts + (hsize_t)select_nelmts) >= nelmts);
+ } /* end block */
+#endif /* NDEBUG */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Cleanup I/O operation */
+ if(H5D__virtual_post_io(storage) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation")
+
+ /* Close fill space */
+ if(fill_space)
+ if(H5S_close(fill_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close fill space")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_write_one
+ *
+ * Purpose: Write to a singe source dataset in a virtual dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 15, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset)
+{
+ H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(source_dset);
+
+ /* Only perform I/O if there is a projected memory space, otherwise there
+ * were no elements in the projection */
+ if(source_dset->projected_mem_space) {
+ HDassert(source_dset->dset);
+ HDassert(source_dset->clipped_source_select);
+
+ /* In the future we may wish to extent this implementation to extend
+ * source datasets if a write to a virtual dataset goes past the current
+ * extent in the unlimited dimension. -NAF */
+ /* Project intersection of file space and mapping virtual space onto
+ * mapping source space */
+ if(H5S_select_project_intersection(source_dset->virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space")
+
+ /* Perform write on source dataset */
+ if(H5D__write(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->raw_dxpl_id, io_info->u.wbuf) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write to source dataset")
+
+ /* Close projected_src_space */
+ if(H5S_close(projected_src_space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
+ projected_src_space = NULL;
+ } /* end if */
+
+done:
+ /* Release allocated resources on failure */
+ if(projected_src_space) {
+ HDassert(ret_value < 0);
+ if(H5S_close(projected_src_space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close projected source space")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_write_one() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_write
+ *
+ * Purpose: Write to a virtual dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
+ hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
+ H5D_chunk_map_t H5_ATTR_UNUSED *fm)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */
+ size_t i, j; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(io_info);
+ HDassert(io_info->u.wbuf);
+ HDassert(type_info);
+ HDassert(mem_space);
+ HDassert(file_space);
+
+ storage = &io_info->dset->shared->layout.storage.u.virt;
+ HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE));
+
+#ifdef H5_HAVE_PARALLEL
+ /* Parallel writes are not supported (yet) */
+ if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Prepare for I/O operation */
+ if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation")
+
+ /* Fail if there are unmapped parts of the selection as they would not be
+ * written */
+ if(tot_nelmts != nelmts)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "write requested to unmapped portion of virtual dataset")
+
+ /* Iterate over mappings */
+ for(i = 0; i < storage->list_nused; i++) {
+ /* Sanity check that virtual space has been patched by now */
+ HDassert(storage->list[i].virtual_space_status == H5O_VIRTUAL_STATUS_CORRECT);
+
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ /* Iterate over sub-source dsets */
+ for(j = storage->list[i].sub_dset_io_start;
+ j < storage->list[i].sub_dset_io_end; j++)
+ if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset")
+ } /* end if */
+ else
+ /* Write to source dataset */
+ if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset")
+ } /* end for */
+
+done:
+ /* Cleanup I/O operation */
+ if(H5D__virtual_post_io(storage) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't cleanup I/O operation")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_flush
+ *
+ * Purpose: Writes all dirty data to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * February 6, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_flush(H5D_t *dset, hid_t dxpl_id)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ size_t i, j; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset);
+
+ storage = &dset->shared->layout.storage.u.virt;
+
+ /* Flush only open datasets */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ /* Iterate over sub-source dsets */
+ for(j = 0; j < storage->list[i].sub_dset_nused; j++)
+ if(storage->list[i].sub_dset[j].dset)
+ /* Flush source dataset */
+ if(H5D__flush_real(storage->list[i].sub_dset[j].dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush source dataset")
+ } /* end if */
+ else
+ if(storage->list[i].source_dset.dset)
+ /* Flush source dataset */
+ if(H5D__flush_real(storage->list[i].source_dset.dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to flush source dataset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_hold_source_dset_files
+ *
+ * Purpose: Hold open the source files that are open, during a refresh event
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ H5D_virtual_held_file_t *tmp; /* Temporary held file node */
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+ HDassert(head && NULL == *head);
+
+ /* Set the convenience pointer */
+ storage = &dset->shared->layout.storage.u.virt;
+
+ /* Hold only files for open datasets */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ size_t j; /* Local index variable */
+
+ /* Iterate over sub-source dsets */
+ for(j = 0; j < storage->list[i].sub_dset_nused; j++)
+ if(storage->list[i].sub_dset[j].dset) {
+ /* Hold open the file */
+ H5F_INCR_NOPEN_OBJS(storage->list[i].sub_dset[j].dset->oloc.file);
+
+ /* Allocate a node for this file */
+ if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
+
+ /* Set up node & connect to list */
+ tmp->file = storage->list[i].sub_dset[j].dset->oloc.file;
+ tmp->next = *head;
+ *head = tmp;
+ } /* end if */
+ } /* end if */
+ else
+ if(storage->list[i].source_dset.dset) {
+ /* Hold open the file */
+ H5F_INCR_NOPEN_OBJS(storage->list[i].source_dset.dset->oloc.file);
+
+ /* Allocate a node for this file */
+ if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
+
+ /* Set up node & connect to list */
+ tmp->file = storage->list[i].source_dset.dset->oloc.file;
+ tmp->next = *head;
+ *head = tmp;
+ } /* end if */
+
+done:
+ if(ret_value < 0) {
+ /* Release hold on files and delete list on error */
+ if(*head)
+ if(H5D__virtual_release_source_dset_files(*head) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release source datasets' files held open")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_hold_source_dset_files() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_refresh_source_dset
+ *
+ * Purpose: Refresh a source dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_refresh_source_dset(H5D_t **dset, hid_t dxpl_id)
+{
+ hid_t dset_id; /* Temporary dataset identifier */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset && *dset);
+
+ /* Get a temporary identifier for this source dataset */
+ if((dset_id = H5I_register(H5I_DATASET, *dset, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "can't register source dataset ID")
+
+ /* Refresh source dataset */
+ if(H5D__refresh(dset_id, *dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+
+ /* Discard the identifier & replace the dataset */
+ if(NULL == (*dset = (H5D_t *)H5I_remove(dset_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't unregister source dataset ID")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_refresh_source_dsets() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_refresh_source_dsets
+ *
+ * Purpose: Refresh the source datasets
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * November, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_refresh_source_dsets(H5D_t *dset, hid_t dxpl_id)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Set convenience pointer */
+ storage = &dset->shared->layout.storage.u.virt;
+
+ /* Refresh only open datasets */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ size_t j; /* Local index variable */
+
+ /* Iterate over sub-source datasets */
+ for(j = 0; j < storage->list[i].sub_dset_nused; j++)
+ /* Check if sub-source dataset is open */
+ if(storage->list[i].sub_dset[j].dset)
+ /* Refresh sub-source dataset */
+ if(H5D__virtual_refresh_source_dset(&storage->list[i].sub_dset[j].dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+ } /* end if */
+ else
+ /* Check if source dataset is open */
+ if(storage->list[i].source_dset.dset)
+ /* Refresh source dataset */
+ if(H5D__virtual_refresh_source_dset(&storage->list[i].source_dset.dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_refresh_source_dsets() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_release_source_dset_files
+ *
+ * Purpose: Release the hold on source files that are open, during a refresh event
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Release hold on files and delete list */
+ while(head) {
+ H5D_virtual_held_file_t *tmp = head->next; /* Temporary pointer to next node */
+
+ /* Release hold on file */
+ H5F_DECR_NOPEN_OBJS(head->file);
+
+ /* Attempt to close the file */
+ /* (Should always succeed, since the 'top' source file pointer is
+ * essentially "private" to the virtual dataset, since it wasn't
+ * opened through an API routine -QAK)
+ */
+ if(H5F_try_close(head->file, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
+
+ /* Delete node */
+ (void)H5FL_FREE(H5D_virtual_held_file_t, head);
+
+ /* Advance to next node */
+ head = tmp;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_release_source_dset_files() */
+
diff --git a/src/H5E.c b/src/H5E.c
new file mode 100644
index 0000000..741f0dd
--- /dev/null
+++ b/src/H5E.c
@@ -0,0 +1,1742 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Provides error handling in the form of a stack. The
+ * FUNC_ENTER() macro clears the error stack whenever an API
+ * function is entered. When an error is detected, an entry is
+ * pushed onto the stack. As the functions unwind additional
+ * entries are pushed onto the stack. The API function will
+ * return some indication that an error occurred and the
+ * application can print the error stack.
+ *
+ * Certain API functions in the H5E package (such as H5Eprint2())
+ * do not clear the error stack. Otherwise, any function which
+ * doesn't have an underscore immediately after the package name
+ * will clear the error stack. For instance, H5Fopen() clears
+ * the error stack while H5F_open() does not.
+ *
+ * An error stack has a fixed maximum size. If this size is
+ * exceeded then the stack will be truncated and only the
+ * inner-most functions will have entries on the stack. This is
+ * expected to be a rare condition.
+ *
+ * Each thread has its own error stack, but since
+ * multi-threading has not been added to the library yet, this
+ * package maintains a single error stack. The error stack is
+ * statically allocated to reduce the complexity of handling
+ * errors within the H5E package.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Emodule.h" /* This source code file is part of the H5E module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Epkg.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5MMprivate.h" /* Memory management */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* HDF5 error class */
+#define H5E_CLS_NAME "HDF5"
+#define H5E_CLS_LIB_NAME "HDF5"
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+/* Static function declarations */
+static herr_t H5E_set_default_auto(H5E_t *stk);
+static H5E_cls_t *H5E_register_class(const char *cls_name, const char *lib_name,
+ const char *version);
+static herr_t H5E_unregister_class(H5E_cls_t *cls);
+static ssize_t H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size);
+static int H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata);
+static herr_t H5E_close_msg(H5E_msg_t *err);
+static H5E_msg_t *H5E_create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg);
+static H5E_t *H5E_get_current_stack(void);
+static herr_t H5E_set_current_stack(H5E_t *estack);
+static herr_t H5E_close_stack(H5E_t *err_stack);
+static ssize_t H5E_get_num(const H5E_t *err_stack);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5E_t struct */
+H5FL_DEFINE_STATIC(H5E_t);
+
+/* Declare a free list to manage the H5E_cls_t struct */
+H5FL_DEFINE_STATIC(H5E_cls_t);
+
+/* Declare a free list to manage the H5E_msg_t struct */
+H5FL_DEFINE_STATIC(H5E_msg_t);
+
+/* Error class ID class */
+static const H5I_class_t H5I_ERRCLS_CLS[1] = {{
+ H5I_ERROR_CLASS, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5E_unregister_class /* Callback routine for closing objects of this class */
+}};
+
+/* Error message ID class */
+static const H5I_class_t H5I_ERRMSG_CLS[1] = {{
+ H5I_ERROR_MSG, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5E_close_msg /* Callback routine for closing objects of this class */
+}};
+
+/* Error stack ID class */
+static const H5I_class_t H5I_ERRSTK_CLS[1] = {{
+ H5I_ERROR_STACK, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5E_close_stack /* Callback routine for closing objects of this class */
+}};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_init
+ *
+ * Purpose: Initialize the interface from some other layer.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 29, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_init() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5E__init_package
+ *
+ * Purpose: Initialize interface-specific information
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5E__init_package(void)
+{
+ H5E_cls_t *cls; /* Pointer to error class */
+ H5E_msg_t *msg; /* Pointer to new error message */
+ char lib_vers[128]; /* Buffer to constructu library version within */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Initialize the atom group for the error class IDs */
+ if(H5I_register_type(H5I_ERRCLS_CLS) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group")
+
+ /* Initialize the atom group for the major error IDs */
+ if(H5I_register_type(H5I_ERRMSG_CLS) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group")
+
+ /* Initialize the atom group for the error stacks */
+ if(H5I_register_type(H5I_ERRSTK_CLS) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group")
+
+#ifndef H5_HAVE_THREADSAFE
+ H5E_stack_g[0].nused = 0;
+ H5E_set_default_auto(H5E_stack_g);
+#endif /* H5_HAVE_THREADSAFE */
+
+ /* Allocate the HDF5 error class */
+ HDassert(H5E_ERR_CLS_g == (-1));
+ HDsnprintf(lib_vers, sizeof(lib_vers), "%u.%u.%u%s", H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE, (HDstrlen(H5_VERS_SUBRELEASE) > 0 ? "-"H5_VERS_SUBRELEASE : ""));
+ if(NULL == (cls = H5E_register_class(H5E_CLS_NAME, H5E_CLS_LIB_NAME, lib_vers)))
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "class initialization failed")
+ if((H5E_ERR_CLS_g = H5I_register(H5I_ERROR_CLASS, cls, FALSE)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error class")
+
+ /* Include the automatically generated error code initialization */
+ #include "H5Einit.h"
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_term_package
+ *
+ * Purpose: Terminates the H5E interface
+ *
+ * Return: Success: Positive if anything is done that might
+ * affect other interfaces; zero otherwise.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, July 22, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5E_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ int64_t ncls, nmsg, nstk;
+
+ /* Check if there are any open error stacks, classes or messages */
+ ncls = H5I_nmembers(H5I_ERROR_CLASS);
+ nmsg = H5I_nmembers(H5I_ERROR_MSG);
+ nstk = H5I_nmembers(H5I_ERROR_STACK);
+
+ if((ncls + nmsg + nstk) > 0) {
+ /* Clear any outstanding error stacks */
+ if(nstk > 0)
+ (void)H5I_clear_type(H5I_ERROR_STACK, FALSE, FALSE);
+
+ /* Clear all the error classes */
+ if(ncls > 0) {
+ (void)H5I_clear_type(H5I_ERROR_CLASS, FALSE, FALSE);
+
+ /* Reset the HDF5 error class, if its been closed */
+ if(H5I_nmembers(H5I_ERROR_CLASS) == 0)
+ H5E_ERR_CLS_g = -1;
+ } /* end if */
+
+ /* Clear all the error messages */
+ if(nmsg > 0) {
+ (void)H5I_clear_type(H5I_ERROR_MSG, FALSE, FALSE);
+
+ /* Reset the HDF5 error messages, if they've been closed */
+ if(H5I_nmembers(H5I_ERROR_MSG) == 0) {
+ /* Include the automatically generated error code termination */
+ #include "H5Eterm.h"
+ } /* end if */
+ } /* end if */
+
+ n++; /*H5I*/
+ } /* end if */
+ else {
+ /* Destroy the error class, message, and stack id groups */
+ n += (H5I_dec_type_ref(H5I_ERROR_STACK) > 0);
+ n += (H5I_dec_type_ref(H5I_ERROR_CLASS) > 0);
+ n += (H5I_dec_type_ref(H5I_ERROR_MSG) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5E_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5E_set_default_auto
+ *
+ * Purpose: Initialize "automatic" error stack reporting info to library
+ * default
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 1, 2007
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5E_set_default_auto(H5E_t *stk)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+#ifdef H5_USE_16_API_DEFAULT
+ stk->auto_op.vers = 1;
+#else /* H5_USE_16_API */
+ stk->auto_op.vers = 2;
+#endif /* H5_USE_16_API_DEFAULT */
+
+ stk->auto_op.func1 = stk->auto_op.func1_default = (H5E_auto1_t)H5Eprint1;
+ stk->auto_op.func2 = stk->auto_op.func2_default = (H5E_auto2_t)H5Eprint2;
+ stk->auto_op.is_default = TRUE;
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+ stk->auto_op.func2 = (H5E_auto2_t)H5Eprint2;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ stk->auto_data = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_set_default_auto() */
+
+
+#ifdef H5_HAVE_THREADSAFE
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_stack
+ *
+ * Purpose: Support function for H5E_get_my_stack() to initialize and
+ * acquire per-thread error stack.
+ *
+ * Return: Success: error stack (H5E_t *)
+ *
+ * Failure: NULL
+ *
+ * Programmer: Chee Wai LEE
+ * April 24, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+H5E_t *
+H5E_get_stack(void)
+{
+ H5E_t *estack = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ estack = (H5E_t *)H5TS_get_thread_local_value(H5TS_errstk_key_g);
+
+ if(!estack) {
+ /* No associated value with current thread - create one */
+#ifdef H5_HAVE_WIN_THREADS
+ /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */
+ estack = (H5E_t *)LocalAlloc(LPTR, sizeof(H5E_t));
+#else
+ /* Use HDmalloc here since this has to match the HDfree in the
+ * destructor and we want to avoid the codestack there.
+ */
+ estack = (H5E_t *)HDmalloc(sizeof(H5E_t));
+#endif /* H5_HAVE_WIN_THREADS */
+ HDassert(estack);
+
+ /* Set the thread-specific info */
+ estack->nused = 0;
+ H5E_set_default_auto(estack);
+
+ /* (It's not necessary to release this in this API, it is
+ * released by the "key destructor" set up in the H5TS
+ * routines. See calls to pthread_key_create() in H5TS.c -QAK)
+ */
+ H5TS_set_thread_local_value(H5TS_errstk_key_g, (void *)estack);
+ } /* end if */
+
+ /* Set return value */
+ FUNC_LEAVE_NOAPI(estack)
+} /* end H5E_get_stack() */
+#endif /* H5_HAVE_THREADSAFE */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_free_class
+ *
+ * Purpose: Private function to free an error class.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 22, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_free_class(H5E_cls_t *cls)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(cls);
+
+ /* Free error class structure */
+ cls->cls_name = (char *)H5MM_xfree((void*)cls->cls_name);
+ cls->lib_name = (char *)H5MM_xfree((void*)cls->lib_name);
+ cls->lib_vers = (char *)H5MM_xfree((void*)cls->lib_vers);
+ cls = H5FL_FREE(H5E_cls_t, cls);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_free_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eregister_class
+ *
+ * Purpose: Registers an error class.
+ *
+ * Return: Non-negative value as class ID on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Eregister_class(const char *cls_name, const char *lib_name, const char *version)
+{
+ H5E_cls_t *cls; /* Pointer to error class */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "*s*s*s", cls_name, lib_name, version);
+
+ /* Check arguments */
+ if(cls_name == NULL || lib_name == NULL || version == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid string")
+
+ /* Create the new error class object */
+ if(NULL == (cls = H5E_register_class(cls_name, lib_name, version)))
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTCREATE, FAIL, "can't create error class")
+
+ /* Register the new error class to get an ID for it */
+ if((ret_value = H5I_register(H5I_ERROR_CLASS, cls, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error class")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eregister_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_register_class
+ *
+ * Purpose: Private function to register an error class.
+ *
+ * Return: Non-negative value as class ID on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5E_cls_t *
+H5E_register_class(const char *cls_name, const char *lib_name, const char *version)
+{
+ H5E_cls_t *cls = NULL; /* Pointer to error class */
+ H5E_cls_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(cls_name);
+ HDassert(lib_name);
+ HDassert(version);
+
+ /* Allocate space for new error class */
+ if(NULL == (cls = H5FL_CALLOC(H5E_cls_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Duplicate string information */
+ if(NULL == (cls->cls_name = H5MM_xstrdup(cls_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(NULL == (cls->lib_name = H5MM_xstrdup(lib_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(NULL == (cls->lib_vers = H5MM_xstrdup(version)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the return value */
+ ret_value = cls;
+
+done:
+ if(!ret_value)
+ if(cls && H5E_free_class(cls) < 0)
+ HDONE_ERROR(H5E_ERROR, H5E_CANTRELEASE, NULL, "unable to free error class")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_register_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eunregister_class
+ *
+ * Purpose: Closes an error class.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eunregister_class(hid_t class_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", class_id);
+
+ /* Check arguments */
+ if(H5I_ERROR_CLASS != H5I_get_type(class_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error class")
+
+ /*
+ * Decrement the counter on the dataset. It will be freed if the count
+ * reaches zero.
+ */
+ if(H5I_dec_app_ref(class_id) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error class")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eunregister_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_unregister_class
+ *
+ * Purpose: Private function to close an error class.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_unregister_class(H5E_cls_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(cls);
+
+ /* Iterate over all the messages and delete those in this error class */
+ if(H5I_iterate(H5I_ERROR_MSG, H5E_close_msg_cb, cls, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_BADITER, FAIL, "unable to free all messages in this error class")
+
+ /* Free error class structure */
+ if(H5E_free_class(cls) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "unable to free error class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_unregister_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_class_name
+ *
+ * Purpose: Retrieves error class name.
+ *
+ * Return: Non-negative for name length if succeeds(zero means no name);
+ * otherwise returns negative value.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Eget_class_name(hid_t class_id, char *name, size_t size)
+{
+ H5E_cls_t *cls; /* Pointer to error class */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*sz", class_id, name, size);
+
+ /* Get the error class */
+ if(NULL == (cls = (H5E_cls_t *)H5I_object_verify(class_id, H5I_ERROR_CLASS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error class ID")
+
+ /* Retrieve the class name */
+ if((ret_value = H5E_get_class_name(cls, name, size)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get error class name")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_class_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_class_name
+ *
+ * Purpose: Private function to retrieve error class name.
+ *
+ * Return: Non-negative for name length if succeeds(zero means no name);
+ * otherwise returns negative value.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size)
+{
+ ssize_t len = 0; /* Length of error class's name */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(cls);
+
+ /* Get the class's name */
+ len = (ssize_t)HDstrlen(cls->cls_name);
+
+ /* Set the user's buffer, if provided */
+ if(name) {
+ HDstrncpy(name, cls->cls_name, MIN((size_t)(len + 1), size));
+ if((size_t)len >= size)
+ name[size - 1] = '\0';
+ } /* end if */
+
+ /* Return the full length */
+ FUNC_LEAVE_NOAPI(len)
+} /* end H5E_get_class_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_close_msg_cb
+ *
+ * Purpose: H5I_iterate callback function to close error messages in the
+ * error class.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata)
+{
+ H5E_msg_t *err_msg = (H5E_msg_t*)obj_ptr;
+ H5E_cls_t *cls = (H5E_cls_t*)udata;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(err_msg);
+
+ /* Close the message if it is in the class being closed */
+ if(err_msg->cls == cls) {
+ if(H5E_close_msg(err_msg) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTCLOSEOBJ, FAIL, "unable to close error message")
+ if(NULL == H5I_remove(obj_id))
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREMOVE, FAIL, "unable to remove error message")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_close_msg_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eclose_msg
+ *
+ * Purpose: Closes a major or minor error.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eclose_msg(hid_t err_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", err_id);
+
+ /* Check arguments */
+ if(H5I_ERROR_MSG != H5I_get_type(err_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error class")
+
+ /* Decrement the counter. It will be freed if the count reaches zero. */
+ if(H5I_dec_app_ref(err_id) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eclose_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_close_msg
+ *
+ * Purpose: Private function to close an error messge.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_close_msg(H5E_msg_t *err)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(err);
+
+ /* Release message */
+ err->msg = (char *)H5MM_xfree((void *)err->msg);
+ /* Don't free err->cls here */
+ err = H5FL_FREE(H5E_msg_t, err);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_close_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ecreate_msg
+ *
+ * Purpose: Creates a major or minor error, returns an ID.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Ecreate_msg(hid_t class_id, H5E_type_t msg_type, const char *msg_str)
+{
+ H5E_cls_t *cls; /* Pointer to error class */
+ H5E_msg_t *msg; /* Pointer to new error message */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iEt*s", class_id, msg_type, msg_str);
+
+ /* Check arguments */
+ if(msg_type != H5E_MAJOR && msg_type != H5E_MINOR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid message type")
+ if(msg_str == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "message is NULL")
+
+ /* Get the error class */
+ if(NULL == (cls = (H5E_cls_t *)H5I_object_verify(class_id, H5I_ERROR_CLASS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error class ID")
+
+ /* Create the new error message object */
+ if(NULL == (msg = H5E_create_msg(cls, msg_type, msg_str)))
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTCREATE, FAIL, "can't create error message")
+
+ /* Register the new error class to get an ID for it */
+ if((ret_value = H5I_register(H5I_ERROR_MSG, msg, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ecreate_msg() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_create_msg
+ *
+ * Purpose: Private function to create a major or minor error.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5E_msg_t *
+H5E_create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg_str)
+{
+ H5E_msg_t *msg = NULL; /* Pointer to new error message */
+ H5E_msg_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(cls);
+ HDassert(msg_type == H5E_MAJOR || msg_type == H5E_MINOR);
+ HDassert(msg_str);
+
+ /* Allocate new message object */
+ if(NULL == (msg = H5FL_MALLOC(H5E_msg_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Fill new message object */
+ msg->cls = cls;
+ msg->type = msg_type;
+ if(NULL == (msg->msg = H5MM_xstrdup(msg_str)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set return value */
+ ret_value = msg;
+
+done:
+ if(!ret_value)
+ if(msg && H5E_close_msg(msg) < 0)
+ HDONE_ERROR(H5E_ERROR, H5E_CANTCLOSEOBJ, NULL, "unable to close error message")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_create_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_msg
+ *
+ * Purpose: Retrieves an error message.
+ *
+ * Return: Non-negative for message length if succeeds(zero means no message);
+ * otherwise returns negative value.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Eget_msg(hid_t msg_id, H5E_type_t *type, char *msg_str, size_t size)
+{
+ H5E_msg_t *msg; /* Pointer to error message */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "i*Et*sz", msg_id, type, msg_str, size);
+
+ /* Get the message object */
+ if(NULL == (msg = (H5E_msg_t *)H5I_object_verify(msg_id, H5I_ERROR_MSG)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error message ID")
+
+ /* Get the message's text */
+ if((ret_value = H5E_get_msg(msg, type, msg_str, size)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get error message text")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ecreate_stack
+ *
+ * Purpose: Creates a new, empty, error stack.
+ *
+ * Return: Non-negative value as stack ID on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Ecreate_stack(void)
+{
+ H5E_t *stk; /* Error stack */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE0("i","");
+
+ /* Allocate a new error stack */
+ if(NULL == (stk = H5FL_CALLOC(H5E_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set the "automatic" error reporting info to the library default */
+ H5E_set_default_auto(stk);
+
+ /* Register the stack */
+ if((ret_value = H5I_register(H5I_ERROR_STACK, stk, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't create error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ecreate_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_current_stack
+ *
+ * Purpose: Registers current error stack, returns object handle for it,
+ * clears it.
+ *
+ * Return: Non-negative value as stack ID on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Eget_current_stack(void)
+{
+ H5E_t *stk; /* Error stack */
+ hid_t ret_value; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE0("i","");
+
+ /* Get the current stack */
+ if(NULL == (stk = H5E_get_current_stack()))
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTCREATE, FAIL, "can't create error stack")
+
+ /* Register the stack */
+ if((ret_value = H5I_register(H5I_ERROR_STACK, stk, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't create error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_current_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_current_stack
+ *
+ * Purpose: Private function to register an error stack.
+ *
+ * Return: Non-negative value as class ID on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 11, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5E_t *
+H5E_get_current_stack(void)
+{
+ H5E_t *current_stack; /* Pointer to the current error stack */
+ H5E_t *estack_copy = NULL; /* Pointer to new error stack to return */
+ unsigned u; /* Local index variable */
+ H5E_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get a pointer to the current error stack */
+ if(NULL == (current_stack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get current error stack")
+
+ /* Allocate a new error stack */
+ if(NULL == (estack_copy = H5FL_CALLOC(H5E_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Make a copy of current error stack */
+ estack_copy->nused = current_stack->nused;
+ for(u = 0; u < current_stack->nused; u++) {
+ H5E_error2_t *current_error, *new_error; /* Pointers to errors on each stack */
+
+ /* Get pointers into the current error stack location */
+ current_error = &(current_stack->slot[u]);
+ new_error = &(estack_copy->slot[u]);
+
+ /* Increment the IDs to indicate that they are used in this stack */
+ if(H5I_inc_ref(current_error->cls_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, NULL, "unable to increment ref count on error class")
+ new_error->cls_id = current_error->cls_id;
+ if(H5I_inc_ref(current_error->maj_num, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, NULL, "unable to increment ref count on error message")
+ new_error->maj_num = current_error->maj_num;
+ if(H5I_inc_ref(current_error->min_num, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, NULL, "unable to increment ref count on error message")
+ new_error->min_num = current_error->min_num;
+ if(NULL == (new_error->func_name = H5MM_xstrdup(current_error->func_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(NULL == (new_error->file_name = H5MM_xstrdup(current_error->file_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ new_error->line = current_error->line;
+ if(NULL == (new_error->desc = H5MM_xstrdup(current_error->desc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ } /* end for */
+
+ /* Copy the "automatic" error reporting information */
+ estack_copy->auto_op = current_stack->auto_op;
+ estack_copy->auto_data = current_stack->auto_data;
+
+ /* Empty current error stack */
+ H5E_clear_stack(current_stack);
+
+ /* Set the return value */
+ ret_value = estack_copy;
+
+done:
+ if(ret_value == NULL)
+ if(estack_copy)
+ estack_copy = H5FL_FREE(H5E_t, estack_copy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_get_current_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eset_current_stack
+ *
+ * Purpose: Replaces current stack with specified stack. This closes the
+ * stack ID also.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 15, 2003
+ *
+ * Modification:
+ * Raymond Lu
+ * 7 September 2010
+ * Also closes the stack to avoid potential problem (bug 1799)
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eset_current_stack(hid_t err_stack)
+{
+ H5E_t *estack;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", err_stack);
+
+ if(err_stack != H5E_DEFAULT) {
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+
+ /* Set the current error stack */
+ if(H5E_set_current_stack(estack) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "unable to set error stack")
+
+ /*
+ * Decrement the counter on the error stack. It will be freed if the count
+ * reaches zero.
+ */
+ if(H5I_dec_app_ref(err_stack) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error stack")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eset_current_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_set_current_stack
+ *
+ * Purpose: Private function to replace an error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 15, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_set_current_stack(H5E_t *estack)
+{
+ H5E_t *current_stack; /* Default error stack */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(estack);
+
+ /* Get a pointer to the current error stack */
+ if(NULL == (current_stack = H5E_get_my_stack ())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Empty current error stack */
+ H5E_clear_stack(current_stack);
+
+ /* Copy new stack to current error stack */
+ current_stack->nused = estack->nused;
+ for(u = 0; u < current_stack->nused; u++) {
+ H5E_error2_t *current_error, *new_error; /* Pointers to errors on each stack */
+
+ /* Get pointers into the current error stack location */
+ current_error = &(current_stack->slot[u]);
+ new_error = &(estack->slot[u]);
+
+ /* Increment the IDs to indicate that they are used in this stack */
+ if(H5I_inc_ref(new_error->cls_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error class")
+ current_error->cls_id = new_error->cls_id;
+ if(H5I_inc_ref(new_error->maj_num, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error class")
+ current_error->maj_num = new_error->maj_num;
+ if(H5I_inc_ref(new_error->min_num, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error class")
+ current_error->min_num = new_error->min_num;
+ if(NULL == (current_error->func_name = H5MM_xstrdup(new_error->func_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (current_error->file_name = H5MM_xstrdup(new_error->file_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ current_error->line = new_error->line;
+ if(NULL == (current_error->desc = H5MM_xstrdup(new_error->desc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_set_current_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eclose_stack
+ *
+ * Purpose: Closes an error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eclose_stack(hid_t stack_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", stack_id);
+
+ if(H5E_DEFAULT != stack_id) {
+ /* Check arguments */
+ if(H5I_ERROR_STACK != H5I_get_type(stack_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+
+ /*
+ * Decrement the counter on the error stack. It will be freed if the count
+ * reaches zero.
+ */
+ if(H5I_dec_app_ref(stack_id) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error stack")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eclose_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_close_stack
+ *
+ * Purpose: Private function to close an error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_close_stack(H5E_t *estack)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(estack);
+
+ /* Release the stack's error information */
+ H5E_clear_stack(estack);
+
+ /* Free the stack structure */
+ estack = H5FL_FREE(H5E_t, estack);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_close_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_num
+ *
+ * Purpose: Retrieves the number of error message.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 15, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Eget_num(hid_t error_stack_id)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ ssize_t ret_value; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE1("Zs", "i", error_stack_id);
+
+ /* Need to check for errors */
+ if(error_stack_id == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ /* Get the error stack to operate on */
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(error_stack_id, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+ /* Get the number of errors on stack */
+ if((ret_value = H5E_get_num(estack)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get number of errors")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_num() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_num
+ *
+ * Purpose: Private function to retrieve number of errors in error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 15, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5E_get_num(const H5E_t *estack)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(estack);
+
+ FUNC_LEAVE_NOAPI((ssize_t)estack->nused)
+} /* end H5E_get_num() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Epop
+ *
+ * Purpose: Deletes some error messages from the top of error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Epop(hid_t err_stack, size_t count)
+{
+ H5E_t *estack;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE2("e", "iz", err_stack, count);
+
+ /* Need to check for errors */
+ if(err_stack == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ /* Get the error stack to operate on */
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+ /* Range limit the number of errors to pop off stack */
+ if(count > estack->nused)
+ count = estack->nused;
+
+ /* Pop the errors off the stack */
+ if(H5E_pop(estack, count) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "can't pop errors from stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Epop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Epush2
+ *
+ * Purpose: Pushes a new error record onto error stack for the current
+ * thread. The error has major and minor IDs MAJ_ID and
+ * MIN_ID, the name of a function where the error was detected,
+ * the name of the file where the error was detected, the
+ * line within that file, and an error description string. The
+ * function name, file name, and error description strings must
+ * be statically allocated.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 18, 1999
+ *
+ * Notes: Basically a new public API wrapper around the H5E_push_stack
+ * function.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Epush2(hid_t err_stack, const char *file, const char *func, unsigned line,
+ hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...)
+{
+ va_list ap; /* Varargs info */
+ H5E_t *estack; /* Pointer to error stack to modify */
+#ifndef H5_HAVE_VASPRINTF
+ int tmp_len; /* Current size of description buffer */
+ int desc_len; /* Actual length of description when formatted */
+#endif /* H5_HAVE_VASPRINTF */
+ char *tmp = NULL; /* Buffer to place formatted description in */
+ hbool_t va_started = FALSE; /* Whether the variable argument list is open */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE8("e", "i*s*sIuiii*s", err_stack, file, func, line, cls_id, maj_id,
+ min_id, fmt);
+
+ if(err_stack == H5E_DEFAULT)
+ estack = NULL;
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ /* Get the error stack to operate on */
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+/* Note that the variable-argument parsing for the format is identical in
+ * the H5E_printf_stack() routine - correct errors and make changes in both
+ * places. -QAK
+ */
+
+ /* Format the description */
+ va_start(ap, fmt);
+ va_started = TRUE;
+
+#ifdef H5_HAVE_VASPRINTF
+ /* Use the vasprintf() routine, since it does what we're trying to do below */
+ if(HDvasprintf(&tmp, fmt, ap) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+#else /* H5_HAVE_VASPRINTF */
+ /* Allocate space for the formatted description buffer */
+ tmp_len = 128;
+ if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* If the description doesn't fit into the initial buffer size, allocate more space and try again */
+ while((desc_len = HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) > (tmp_len - 1)) {
+ /* shutdown & restart the va_list */
+ va_end(ap);
+ va_start(ap, fmt);
+
+ /* Release the previous description, it's too small */
+ H5MM_xfree(tmp);
+
+ /* Allocate a description of the appropriate length */
+ tmp_len = desc_len + 1;
+ if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end while */
+#endif /* H5_HAVE_VASPRINTF */
+
+ /* Push the error on the stack */
+ if(H5E_push_stack(estack, file, func, line, cls_id, maj_id, min_id, tmp) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't push error on stack")
+
+done:
+ if(va_started)
+ va_end(ap);
+#ifdef H5_HAVE_VASPRINTF
+ /* Memory was allocated with HDvasprintf so it needs to be freed
+ * with HDfree
+ */
+ if(tmp)
+ HDfree(tmp);
+#else /* H5_HAVE_VASPRINTF */
+ if(tmp)
+ H5MM_xfree(tmp);
+#endif /* H5_HAVE_VASPRINTF */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Epush2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eclear2
+ *
+ * Purpose: Clears the error stack for the specified error stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, July 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eclear2(hid_t err_stack)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE1("e", "i", err_stack);
+
+ /* Need to check for errors */
+ if(err_stack == H5E_DEFAULT)
+ estack = NULL;
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+ /* Clear the error stack */
+ if(H5E_clear_stack(estack) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eclear2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eprint2
+ *
+ * Purpose: Prints the error stack in some default way. This is just a
+ * convenience function for H5Ewalk() with a function that
+ * prints error messages. Users are encouraged to write there
+ * own more specific error handlers.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eprint2(hid_t err_stack, FILE *stream)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ /*NO TRACE*/
+
+ /* Need to check for errors */
+ if(err_stack == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+ /* Print error stack */
+ if(H5E_print(estack, stream, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't display error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eprint2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ewalk2
+ *
+ * Purpose: Walks the error stack for the current thread and calls some
+ * function for each error along the way.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ewalk2(hid_t err_stack, H5E_direction_t direction, H5E_walk2_t stack_func, void *client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_walk_op_t op; /* Operator for walking error stack */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ /*NO TRACE*/
+
+ /* Need to check for errors */
+ if(err_stack == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else {
+ /* Only clear the error stack if it's not the default stack */
+ H5E_clear_stack(NULL);
+
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+ } /* end else */
+
+ /* Walk the error stack */
+ op.vers = 2;
+ op.u.func2 = stack_func;
+ if(H5E_walk(estack, direction, &op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ewalk2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_auto2
+ *
+ * Purpose: Returns the current settings for the automatic error stack
+ * traversal function and its data for specific error stack.
+ * Either (or both) arguments may be null in which case the
+ * value is not returned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Saturday, February 28, 1998
+ *
+ * Modification:Raymond Lu
+ * 4 October 2010
+ * If the printing function isn't the default H5Eprint1 or 2,
+ * and H5Eset_auto1 has been called to set the old style
+ * printing function, a call to H5Eget_auto2 should fail.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eget_auto2(hid_t estack_id, H5E_auto2_t *func, void **client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_auto_op_t op; /* Error stack function */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", estack_id, func, client_data);
+
+ if(estack_id == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(estack_id, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+
+ /* Get the automatic error reporting information */
+ if(H5E_get_auto(estack, &op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info")
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ /* Fail if the printing function isn't the default(user-set) and set through H5Eset_auto1 */
+ if(!op.is_default && op.vers == 1)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "wrong API function, H5Eset_auto1 has been called")
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ if(func)
+ *func = op.func2;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_auto2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eset_auto2
+ *
+ * Purpose: Turns on or off automatic printing of errors for certain
+ * error stack. When turned on (non-null FUNC pointer) any
+ * API function which returns an error indication will first
+ * call FUNC passing it CLIENT_DATA as an argument.
+ *
+ * The default values before this function is called are
+ * H5Eprint2() with client data being the standard error stream,
+ * stderr.
+ *
+ * Automatic stack traversal is always in the H5E_WALK_DOWNWARD
+ * direction.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ * Modification:Raymond Lu
+ * 4 October 2010
+ * If the FUNC is H5Eprint2, put the IS_DEFAULT flag on.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eset_auto2(hid_t estack_id, H5E_auto2_t func, void *client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_auto_op_t op; /* Error stack operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE3("e", "ix*x", estack_id, func, client_data);
+
+ if(estack_id == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(estack_id, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ /* Get the automatic error reporting information */
+ if(H5E_get_auto(estack, &op, NULL) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info")
+
+ /* Set the automatic error reporting information */
+ if(func != op.func2_default)
+ op.is_default = FALSE;
+ else
+ op.is_default = TRUE;
+
+ op.vers = 2;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ /* Set the automatic error reporting function */
+ op.func2 = func;
+
+ if(H5E_set_auto(estack, &op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't set automatic error info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eset_auto2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eauto_is_v2
+ *
+ * Purpose: Determines if the error auto reporting function for an
+ * error stack conforms to the H5E_auto_stack_t typedef
+ * or the H5E_auto_t typedef. The IS_STACK parameter is set
+ * to 1 for the first case and 0 for the latter case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 8, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eauto_is_v2(hid_t estack_id, unsigned *is_stack)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", estack_id, is_stack);
+
+ if(estack_id == H5E_DEFAULT) {
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+ } /* end if */
+ else
+ if(NULL == (estack = (H5E_t *)H5I_object_verify(estack_id, H5I_ERROR_STACK)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID")
+
+ /* Check if the error stack reporting function is the "newer" stack type */
+ if(is_stack)
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ *is_stack = estack->auto_op.vers > 1;
+#else
+ *is_stack = 1;
+#endif
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eauto_is_v2() */
+
diff --git a/src/H5EA.c b/src/H5EA.c
new file mode 100644
index 0000000..c524d49
--- /dev/null
+++ b/src/H5EA.c
@@ -0,0 +1,1066 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EA.c
+ * Jun 17 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implements an "extensible array" for storing elements
+ * in an array whose high bounds can extend and shrink.
+ *
+ * Please see the documentation in:
+ * doc/html/TechNotes/ExtensibleArray.html for a full
+ * description of how they work, etc.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for generically unprotecting an object */
+typedef herr_t (*H5EA__unprotect_func_t)(void *thing, hid_t dxpl_id,
+ unsigned cache_flags);
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t
+H5EA__lookup_elmt(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, hbool_t will_extend,
+ unsigned thing_acc, void **thing, uint8_t **thing_elmt_buf,
+ hsize_t *thing_elmt_idx, H5EA__unprotect_func_t *thing_unprot_func);
+static H5EA_t *H5EA__new(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr,
+ hbool_t from_open, void *ctx_udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Extensible array client ID to class mapping */
+
+/* Remember to add client ID to H5EA_cls_id_t in H5EAprivate.h when adding a new
+ * client class..
+ */
+const H5EA_class_t *const H5EA_client_class_g[] = {
+ H5EA_CLS_CHUNK, /* 0 - H5EA_CLS_CHUNK_ID */
+ H5EA_CLS_FILT_CHUNK, /* 1 - H5EA_CLS_FILT_CHUNK_ID */
+ H5EA_CLS_TEST, /* ? - H5EA_CLS_TEST_ID */
+};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_t struct */
+H5FL_DEFINE_STATIC(H5EA_t);
+
+/* Declare a PQ free list to manage the element */
+H5FL_BLK_DEFINE(ea_native_elmt);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__new
+ *
+ * Purpose: Allocate and initialize a new extensible array wrapper in memory
+ *
+ * Return: Pointer to earray wrapper success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 10 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+H5EA_t *, NULL, NULL,
+H5EA__new(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, hbool_t from_open, void *ctx_udata))
+
+ /* Local variables */
+ H5EA_t *ea = NULL; /* Pointer to new extensible array */
+ H5EA_hdr_t *hdr = NULL; /* The extensible array header information */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(ea_addr));
+
+ /* Allocate extensible array wrapper */
+ if(NULL == (ea = H5FL_CALLOC(H5EA_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array info")
+
+ /* Lock the array header into memory */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header")
+
+ /* Check for pending array deletion */
+ if(from_open && hdr->pending_delete)
+ H5E_THROW(H5E_CANTOPENOBJ, "can't open extensible array pending deletion")
+
+ /* Point extensible array wrapper at header and bump it's ref count */
+ ea->hdr = hdr;
+ if(H5EA__hdr_incr(ea->hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+
+ /* Increment # of files using this array header */
+ if(H5EA__hdr_fuse_incr(ea->hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment file reference count on shared array header")
+
+ /* Set file pointer for this array open context */
+ ea->f = f;
+
+ /* Set the return value */
+ ret_value = ea;
+
+CATCH
+
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+ if(!ret_value)
+ if(ea && H5EA_close(ea, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close extensible array")
+
+END_FUNC(STATIC) /* end H5EA__new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_create
+ *
+ * Purpose: Creates a new empty extensible array in the file.
+ *
+ * Return: Pointer to earray wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 17 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+H5EA_t *, NULL, NULL,
+H5EA_create(H5F_t *f, hid_t dxpl_id, const H5EA_create_t *cparam, void *ctx_udata))
+
+ /* Local variables */
+ H5EA_t *ea = NULL; /* Pointer to new extensible array */
+ haddr_t ea_addr; /* Array header address */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+ /* H5EA interface sanity check */
+ HDcompile_assert(H5EA_NUM_CLS_ID == NELMTS(H5EA_client_class_g));
+
+ /* Create extensible array header */
+ if(HADDR_UNDEF == (ea_addr = H5EA__hdr_create(f, dxpl_id, cparam, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "can't create extensible array header")
+
+ /* Allocate and initialize new extensible array wrapper */
+ if(NULL == (ea = H5EA__new(f, dxpl_id, ea_addr, FALSE, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "allocation and/or initialization failed for extensible array wrapper")
+
+ /* Set the return value */
+ ret_value = ea;
+
+CATCH
+
+ if(!ret_value)
+ if(ea && H5EA_close(ea, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close extensible array")
+
+END_FUNC(PRIV) /* end H5EA_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_open
+ *
+ * Purpose: Opens an existing extensible array in the file.
+ *
+ * Return: Pointer to array wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 28 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+H5EA_t *, NULL, NULL,
+H5EA_open(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata))
+
+ /* Local variables */
+ H5EA_t *ea = NULL; /* Pointer to new extensible array wrapper */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(ea_addr));
+
+ /* Allocate and initialize new extensible array wrapper */
+ if(NULL == (ea = H5EA__new(f, dxpl_id, ea_addr, TRUE, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "allocation and/or initialization failed for extensible array wrapper")
+
+ /* Set the return value */
+ ret_value = ea;
+
+CATCH
+
+ if(!ret_value)
+ if(ea && H5EA_close(ea, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close extensible array")
+
+END_FUNC(PRIV) /* end H5EA_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_get_nelmts
+ *
+ * Purpose: Query the current number of elements in array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 21 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5EA_get_nelmts(const H5EA_t *ea, hsize_t *nelmts))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(nelmts);
+
+ /* Retrieve the max. index set */
+ *nelmts = ea->hdr->stats.stored.max_idx_set;
+
+END_FUNC(PRIV) /* end H5EA_get_nelmts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_get_addr
+ *
+ * Purpose: Query the address of the array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 21 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5EA_get_addr(const H5EA_t *ea, haddr_t *addr))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(ea->hdr);
+ HDassert(addr);
+
+ /* Retrieve the address of the extensible array's header */
+ *addr = ea->hdr->addr;
+
+END_FUNC(PRIV) /* end H5EA_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__lookup_elmt
+ *
+ * Purpose: Retrieve the metadata object and the element buffer for a
+ * given element in the array.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__lookup_elmt(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, hbool_t will_extend,
+ unsigned thing_acc, void **thing, uint8_t **thing_elmt_buf,
+ hsize_t *thing_elmt_idx, H5EA__unprotect_func_t *thing_unprot_func))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
+ H5EA_iblock_t *iblock = NULL; /* Pointer to index block for EA */
+ H5EA_sblock_t *sblock = NULL; /* Pointer to super block for EA */
+ H5EA_dblock_t *dblock = NULL; /* Pointer to data block for EA */
+ H5EA_dblk_page_t *dblk_page = NULL; /* Pointer to data block page for EA */
+ unsigned iblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting index block */
+ unsigned sblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting super block */
+ hbool_t stats_changed = FALSE; /* Whether array statistics changed */
+ hbool_t hdr_dirty = FALSE; /* Whether the array header changed */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(hdr);
+ HDassert(thing);
+ HDassert(thing_elmt_buf);
+ HDassert(thing_unprot_func);
+
+ /* only the H5AC__READ_ONLY_FLAG may be set in thing_acc */
+ HDassert((thing_acc & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = ea->f;
+
+ /* Reset the pointers to the 'thing' info */
+ *thing = NULL;
+ *thing_elmt_buf = NULL;
+ *thing_elmt_idx = 0;
+ *thing_unprot_func = (H5EA__unprotect_func_t)NULL;
+
+ /* Check if we should create the index block */
+ if(!H5F_addr_defined(hdr->idx_blk_addr)) {
+ /* Check if we are allowed to create the thing */
+ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
+ /* Create the index block */
+ hdr->idx_blk_addr = H5EA__iblock_create(hdr, dxpl_id, &stats_changed);
+ if(!H5F_addr_defined(hdr->idx_blk_addr))
+ H5E_THROW(H5E_CANTCREATE, "unable to create index block")
+ hdr_dirty = TRUE;
+ } /* end if */
+ else
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+
+ /* Protect index block */
+ if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, thing_acc)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
+
+ /* Check if element is in index block */
+ if(idx < hdr->cparam.idx_blk_elmts) {
+ /* Set 'thing' info to refer to the index block */
+ *thing = iblock;
+ *thing_elmt_buf = (uint8_t *)iblock->elmts;
+ *thing_elmt_idx = idx;
+ *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__iblock_unprotect;
+ } /* end if */
+ else {
+ unsigned sblk_idx; /* Which superblock does this index fall in? */
+ size_t dblk_idx; /* Data block index */
+ hsize_t elmt_idx; /* Offset of element in super block */
+
+ /* Get super block index where element is located */
+ sblk_idx = H5EA__dblock_sblk_idx(hdr, idx);
+
+ /* Adjust index to offset in super block */
+ elmt_idx = idx - (hdr->cparam.idx_blk_elmts + hdr->sblk_info[sblk_idx].start_idx);
+
+ /* Check for data block containing element address in the index block */
+ if(sblk_idx < iblock->nsblks) {
+ /* Compute the data block index in index block */
+ dblk_idx = (size_t)(hdr->sblk_info[sblk_idx].start_dblk + (elmt_idx / hdr->sblk_info[sblk_idx].dblk_nelmts));
+ HDassert(dblk_idx < iblock->ndblk_addrs);
+
+ /* Check if the data block has been allocated on disk yet */
+ if(!H5F_addr_defined(iblock->dblk_addrs[dblk_idx])) {
+ /* Check if we are allowed to create the thing */
+ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
+ haddr_t dblk_addr; /* Address of data block created */
+ hsize_t dblk_off; /* Offset of data block in array */
+
+ /* Create data block */
+ dblk_off = hdr->sblk_info[sblk_idx].start_idx + (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts);
+ dblk_addr = H5EA__dblock_create(hdr, dxpl_id, iblock, &stats_changed, dblk_off, hdr->sblk_info[sblk_idx].dblk_nelmts);
+ if(!H5F_addr_defined(dblk_addr))
+ H5E_THROW(H5E_CANTCREATE, "unable to create extensible array data block")
+
+ /* Set data block address in index block */
+ iblock->dblk_addrs[dblk_idx] = dblk_addr;
+ iblock_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+
+ /* Protect data block */
+ if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, iblock, iblock->dblk_addrs[dblk_idx], hdr->sblk_info[sblk_idx].dblk_nelmts, thing_acc)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)iblock->dblk_addrs[dblk_idx])
+
+ /* Adjust index to offset in data block */
+ elmt_idx %= hdr->sblk_info[sblk_idx].dblk_nelmts;
+
+ /* Check if there is already a dependency on the header */
+ if(will_extend && !dblock->has_hdr_depend) {
+ if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, index = %llu", (unsigned long long)idx)
+ dblock->has_hdr_depend = TRUE;
+ } /* end if */
+
+ /* Set 'thing' info to refer to the data block */
+ *thing = dblock;
+ *thing_elmt_buf = (uint8_t *)dblock->elmts;
+ *thing_elmt_idx = elmt_idx;
+ *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect;
+ } /* end if */
+ else {
+ size_t sblk_off; /* Offset of super block in index block array of super blocks */
+
+ /* Calculate offset of super block in index block's array */
+ sblk_off = sblk_idx - iblock->nsblks;
+
+ /* Check if the super block has been allocated on disk yet */
+ if(!H5F_addr_defined(iblock->sblk_addrs[sblk_off])) {
+ /* Check if we are allowed to create the thing */
+ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
+ haddr_t sblk_addr; /* Address of data block created */
+
+ /* Create super block */
+ sblk_addr = H5EA__sblock_create(hdr, dxpl_id, iblock, &stats_changed, sblk_idx);
+ if(!H5F_addr_defined(sblk_addr))
+ H5E_THROW(H5E_CANTCREATE, "unable to create extensible array super block")
+
+ /* Set super block address in index block */
+ iblock->sblk_addrs[sblk_off] = sblk_addr;
+ iblock_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+
+ /* Protect super block */
+ if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, iblock, iblock->sblk_addrs[sblk_off], sblk_idx, thing_acc)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)iblock->sblk_addrs[sblk_off])
+
+ /* Compute the data block index in super block */
+ dblk_idx = (size_t)(elmt_idx / sblock->dblk_nelmts);
+ HDassert(dblk_idx < sblock->ndblks);
+
+ /* Check if the data block has been allocated on disk yet */
+ if(!H5F_addr_defined(sblock->dblk_addrs[dblk_idx])) {
+ /* Check if we are allowed to create the thing */
+ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
+ haddr_t dblk_addr; /* Address of data block created */
+ hsize_t dblk_off; /* Offset of data block in array */
+
+ /* Create data block */
+ dblk_off = hdr->sblk_info[sblk_idx].start_idx + (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts);
+ dblk_addr = H5EA__dblock_create(hdr, dxpl_id, sblock, &stats_changed, dblk_off, sblock->dblk_nelmts);
+ if(!H5F_addr_defined(dblk_addr))
+ H5E_THROW(H5E_CANTCREATE, "unable to create extensible array data block")
+
+ /* Set data block address in index block */
+ sblock->dblk_addrs[dblk_idx] = dblk_addr;
+ sblock_cache_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Create flush dependency on header, if extending the array and one doesn't already exist */
+ if(will_extend && !sblock->has_hdr_depend) {
+ if(H5EA__create_flush_depend((H5AC_info_t *)sblock->hdr, (H5AC_info_t *)sblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between super block and header, address = %llu", (unsigned long long)sblock->addr)
+ sblock->has_hdr_depend = TRUE;
+ } /* end if */
+ } /* end if */
+ else
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+
+ /* Adjust index to offset in data block */
+ elmt_idx %= sblock->dblk_nelmts;
+
+ /* Check if the data block is paged */
+ if(sblock->dblk_npages) {
+ haddr_t dblk_page_addr; /* Address of data block page */
+ size_t page_idx; /* Index of page within data block */
+ size_t page_init_idx; /* Index of 'page init' bit */
+
+ /* Compute page index */
+ page_idx = (size_t)elmt_idx / hdr->dblk_page_nelmts;
+
+ /* Compute 'page init' index */
+ page_init_idx = (dblk_idx * sblock->dblk_npages) + page_idx;
+
+ /* Adjust index to offset in data block page */
+ elmt_idx %= hdr->dblk_page_nelmts;
+
+ /* Compute data block page address */
+ dblk_page_addr = sblock->dblk_addrs[dblk_idx] +
+ H5EA_DBLOCK_PREFIX_SIZE(sblock) +
+ (page_idx * sblock->dblk_page_size);
+
+ /* Check if page has been initialized yet */
+ if(!H5VM_bit_get(sblock->page_init, page_init_idx)) {
+ /* Check if we are allowed to create the thing */
+ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */
+ /* Create the data block page */
+ if(H5EA__dblk_page_create(hdr, dxpl_id, sblock, dblk_page_addr) < 0)
+ H5E_THROW(H5E_CANTCREATE, "unable to create data block page")
+
+ /* Mark data block page as initialized in super block */
+ H5VM_bit_set(sblock->page_init, page_init_idx, TRUE);
+ sblock_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+
+ /* Protect data block page */
+ if(NULL == (dblk_page = H5EA__dblk_page_protect(hdr, dxpl_id, sblock, dblk_page_addr, thing_acc)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ /* Check if there is already a dependency on the header */
+ if(will_extend && !dblk_page->has_hdr_depend) {
+ if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblk_page) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block page and header, index = %llu", (unsigned long long)idx)
+ dblk_page->has_hdr_depend = TRUE;
+ } /* end if */
+
+ /* Set 'thing' info to refer to the data block page */
+ *thing = dblk_page;
+ *thing_elmt_buf = (uint8_t *)dblk_page->elmts;
+ *thing_elmt_idx = elmt_idx;
+ *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblk_page_unprotect;
+ } /* end if */
+ else {
+ /* Protect data block */
+ if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, sblock, sblock->dblk_addrs[dblk_idx], sblock->dblk_nelmts, thing_acc)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)sblock->dblk_addrs[dblk_idx])
+
+ /* Check if there is already a dependency on the header */
+ if(will_extend && !dblock->has_hdr_depend) {
+ if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, index = %llu", (unsigned long long)idx)
+ dblock->has_hdr_depend = TRUE;
+ } /* end if */
+
+ /* Set 'thing' info to refer to the data block */
+ *thing = dblock;
+ *thing_elmt_buf = (uint8_t *)dblock->elmts;
+ *thing_elmt_idx = elmt_idx;
+ *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect;
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+ /* Sanity checks */
+ HDassert(*thing != NULL);
+ HDassert(*thing_unprot_func != NULL);
+
+CATCH
+ /* Reset 'thing' info on error */
+ if(ret_value < 0) {
+ *thing = NULL;
+ *thing_elmt_buf = NULL;
+ *thing_elmt_idx = 0;
+ *thing_unprot_func = (H5EA__unprotect_func_t)NULL;
+ } /* end if */
+
+ /* Check for updating array statistics */
+ if(stats_changed)
+ hdr_dirty = TRUE;
+
+ /* Check for header modified */
+ if(hdr_dirty)
+ if(H5EA__hdr_modified(hdr) < 0)
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark extensible array header as modified")
+
+ /* Release resources */
+ if(iblock && *thing != iblock && H5EA__iblock_unprotect(iblock, dxpl_id, iblock_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block")
+ /* (Note: super blocks don't contain elements, so don't have a '*thing != sblock' check) */
+ if(sblock && H5EA__sblock_unprotect(sblock, dxpl_id, sblock_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array super block")
+ if(dblock && *thing != dblock && H5EA__dblock_unprotect(dblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block")
+ if(dblk_page && *thing != dblk_page && H5EA__dblk_page_unprotect(dblk_page, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block page")
+
+END_FUNC(STATIC) /* end H5EA__lookup_elmt() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_set
+ *
+ * Purpose: Set an element of an extensible array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_set(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, const void *elmt))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
+ void *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */
+ uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */
+ hsize_t thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */
+ H5EA__unprotect_func_t thing_unprot_func; /* Function pointer for unprotecting the array metadata */
+ hbool_t will_extend; /* Flag indicating if setting the element will extend the array */
+ unsigned thing_cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting array metadata */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(hdr);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = ea->f;
+
+ /* Look up the array metadata containing the element we want to set */
+ will_extend = (idx >= hdr->stats.stored.max_idx_set);
+ if(H5EA__lookup_elmt(ea, dxpl_id, idx, will_extend, H5AC__NO_FLAGS_SET, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0)
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata")
+
+ /* Sanity check */
+ HDassert(thing);
+ HDassert(thing_elmt_buf);
+ HDassert(thing_unprot_func);
+
+ /* Set element in thing's element buffer */
+ HDmemcpy(thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx), elmt, hdr->cparam.cls->nat_elmt_size);
+ thing_cache_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Update max. element set in array, if appropriate */
+ if(will_extend) {
+ /* Update the max index for the array */
+ hdr->stats.stored.max_idx_set = idx + 1;
+ if(H5EA__hdr_modified(hdr) < 0)
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark extensible array header as modified")
+ } /* end if */
+
+CATCH
+ /* Release resources */
+ if(thing && (thing_unprot_func)(thing, dxpl_id, thing_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array metadata")
+
+END_FUNC(PRIV) /* end H5EA_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_get
+ *
+ * Purpose: Get an element of an extensible array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_get(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, void *elmt))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
+ void *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */
+ H5EA__unprotect_func_t thing_unprot_func; /* Function pointer for unprotecting the array metadata */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(hdr);
+
+ /* Check for element beyond max. element in array */
+ if(idx >= hdr->stats.stored.max_idx_set) {
+ /* Call the class's 'fill' callback */
+ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set element to class's fill value")
+ } /* end if */
+ else {
+ uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */
+ hsize_t thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = ea->f;
+
+ /* Look up the array metadata containing the element we want to set */
+ if(H5EA__lookup_elmt(ea, dxpl_id, idx, FALSE, H5AC__READ_ONLY_FLAG, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0)
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata")
+
+ /* Check if the thing holding the element has been created yet */
+ if(NULL == thing) {
+ /* Call the class's 'fill' callback */
+ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set element to class's fill value")
+ } /* end if */
+ else
+ /* Get element from thing's element buffer */
+ HDmemcpy(elmt, thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx), hdr->cparam.cls->nat_elmt_size);
+ } /* end else */
+
+CATCH
+ /* Release thing */
+ if(thing && (thing_unprot_func)(thing, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array metadata")
+
+END_FUNC(PRIV) /* end H5EA_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_depend
+ *
+ * Purpose: Make a child flush dependency between the extensible array
+ * and another piece of metadata in the file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 27 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_depend(H5EA_t *ea, hid_t dxpl_id, H5AC_proxy_entry_t *parent))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(hdr);
+ HDassert(parent);
+
+ /*
+ * Check to see if a flush dependency between the extensible array
+ * and another data structure in the file has already been set up.
+ * If it hasn't, do so now.
+ */
+ if(NULL == hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = ea->f;
+
+ /* Add the extensible array as a child of the parent (proxy) */
+ if(H5AC_proxy_entry_add_child(parent, hdr->f, dxpl_id, hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array as child of proxy")
+ hdr->parent = parent;
+ } /* end if */
+
+CATCH
+
+END_FUNC(PRIV) /* end H5EA_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_close
+ *
+ * Purpose: Close an extensible array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 21 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_close(H5EA_t *ea, hid_t dxpl_id))
+
+ /* Local variables */
+ hbool_t pending_delete = FALSE; /* Whether the array is pending deletion */
+ haddr_t ea_addr = HADDR_UNDEF; /* Address of array (for deletion) */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+
+ /* Close the header, if it was set */
+ if(ea->hdr) {
+ /* Decrement file reference & check if this is the last open extensible array using the shared array header */
+ if(0 == H5EA__hdr_fuse_decr(ea->hdr)) {
+ /* Set the shared array header's file context for this operation */
+ ea->hdr->f = ea->f;
+
+ /* Shut down anything that can't be put in the header's 'flush' callback */
+
+ /* Check for pending array deletion */
+ if(ea->hdr->pending_delete) {
+ /* Set local info, so array deletion can occur after decrementing the
+ * header's ref count
+ */
+ pending_delete = TRUE;
+ ea_addr = ea->hdr->addr;
+ } /* end if */
+ } /* end if */
+
+ /* Check for pending array deletion */
+ if(pending_delete) {
+ H5EA_hdr_t *hdr; /* Another pointer to extensible array header */
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Header's status in the metadata cache */
+
+ /* Check the header's status in the metadata cache */
+ if(H5AC_get_entry_status(ea->f, ea_addr, &hdr_status) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to check metadata cache status for extensible array header")
+
+ /* Sanity checks on header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PINNED);
+ HDassert(!(hdr_status & H5AC_ES__IS_PROTECTED));
+}
+#endif /* NDEBUG */
+
+ /* Lock the array header into memory */
+ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */
+ if(NULL == (hdr = H5EA__hdr_protect(ea->f, dxpl_id, ea_addr, NULL, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTLOAD, "unable to load extensible array header")
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = ea->f;
+
+ /* Decrement the reference count on the array header */
+ /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted
+ * immediately -QAK)
+ */
+ if(H5EA__hdr_decr(ea->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+
+ /* Delete array, starting with header (unprotects header) */
+ if(H5EA__hdr_delete(hdr, dxpl_id) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array")
+ } /* end if */
+ else {
+ /* Decrement the reference count on the array header */
+ /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted
+ * immediately -QAK)
+ */
+ if(H5EA__hdr_decr(ea->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ } /* end else */
+ } /* end if */
+
+ /* Release the extensible array wrapper */
+ ea = (H5EA_t *)H5FL_FREE(H5EA_t, ea);
+
+CATCH
+
+END_FUNC(PRIV) /* end H5EA_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_delete
+ *
+ * Purpose: Delete an extensible array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 28 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_delete(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* The fractal heap header information */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(ea_addr));
+
+ /* Lock the array header into memory */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr)
+
+ /* Check for files using shared array header */
+ if(hdr->file_rc)
+ hdr->pending_delete = TRUE;
+ else {
+ /* Set the shared array header's file context for this operation */
+ hdr->f = f;
+
+ /* Delete array now, starting with header (unprotects header) */
+ if(H5EA__hdr_delete(hdr, dxpl_id) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array")
+ hdr = NULL;
+ } /* end if */
+
+CATCH
+
+ /* Unprotect the header, if an error occurred */
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PRIV) /* end H5EA_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_iterate
+ *
+ * Purpose: Iterate over the elements of an extensible array
+ * (copied and modified from FA_iterate() in H5FA.c)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; Feb 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA_iterate(H5EA_t *ea, hid_t dxpl_id, H5EA_operator_t op, void *udata))
+
+ /* Local variables */
+ uint8_t *elmt = NULL;
+ hsize_t u;
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(op);
+ HDassert(udata);
+
+ /* Allocate space for a native array element */
+ if(NULL == (elmt = H5FL_BLK_MALLOC(ea_native_elmt, ea->hdr->cparam.cls->nat_elmt_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array element")
+
+ /* Iterate over all elements in array */
+ for(u = 0; u < ea->hdr->stats.stored.max_idx_set; u++) {
+ int cb_ret; /* Return value from callback */
+
+ /* Get array element */
+ if(H5EA_get(ea, dxpl_id, u, elmt) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to delete fixed array")
+
+ /* Make callback */
+ if((cb_ret = (*op)(u, elmt, udata)) < 0) {
+ H5E_PRINTF(H5E_BADITER, "iterator function failed");
+ H5_LEAVE(cb_ret)
+ } /* end if */
+ } /* end for */
+
+CATCH
+
+ if(elmt)
+ elmt = H5FL_BLK_FREE(ea_native_elmt, elmt);
+
+END_FUNC(PRIV) /* end H5EA_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_patch_file
+ *
+ * Purpose: Patch the top-level file pointer contained in ea
+ * to point to idx_info->f if they are different.
+ * This is possible because the file pointer in ea can be
+ * closed out if ea remains open.
+ *
+ * Return: SUCCEED
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5EA_patch_file(H5EA_t *ea, H5F_t *f))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(f);
+
+ if(ea->f != f || ea->hdr->f != f)
+ ea->f = ea->hdr->f = f;
+
+END_FUNC(PRIV) /* end H5EA_patch_file() */
+
diff --git a/src/H5EAcache.c b/src/H5EAcache.c
new file mode 100644
index 0000000..def38af
--- /dev/null
+++ b/src/H5EAcache.c
@@ -0,0 +1,2226 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAcache.c
+ * Aug 26 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement extensible array metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Fractal heap format version #'s */
+#define H5EA_HDR_VERSION 0 /* Header */
+#define H5EA_IBLOCK_VERSION 0 /* Index block */
+#define H5EA_SBLOCK_VERSION 0 /* Super block */
+#define H5EA_DBLOCK_VERSION 0 /* Data block */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5EA__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5EA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5EA__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5EA__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5EA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5EA__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5EA__cache_hdr_free_icr(void *thing);
+
+static herr_t H5EA__cache_iblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5EA__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5EA__cache_iblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5EA__cache_iblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5EA__cache_iblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5EA__cache_iblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5EA__cache_iblock_free_icr(void *thing);
+
+static herr_t H5EA__cache_sblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5EA__cache_sblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5EA__cache_sblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5EA__cache_sblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5EA__cache_sblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5EA__cache_sblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5EA__cache_sblock_free_icr(void *thing);
+
+static herr_t H5EA__cache_dblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5EA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5EA__cache_dblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5EA__cache_dblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5EA__cache_dblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5EA__cache_dblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5EA__cache_dblock_free_icr(void *thing);
+static herr_t H5EA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size);
+
+static herr_t H5EA__cache_dblk_page_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5EA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5EA__cache_dblk_page_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5EA__cache_dblk_page_image_len(const void *thing,
+ size_t *image_len);
+static herr_t H5EA__cache_dblk_page_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5EA__cache_dblk_page_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5EA header inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_EARRAY_HDR[1] = {{
+ H5AC_EARRAY_HDR_ID, /* Metadata client ID */
+ "Extensible Array Header", /* Metadata client name (for debugging) */
+ H5FD_MEM_EARRAY_HDR, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5EA__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5EA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5EA__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5EA__cache_hdr_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5EA__cache_hdr_serialize, /* 'serialize' callback */
+ H5EA__cache_hdr_notify, /* 'notify' callback */
+ H5EA__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5EA index block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_EARRAY_IBLOCK[1] = {{
+ H5AC_EARRAY_IBLOCK_ID, /* Metadata client ID */
+ "Extensible Array Index Block", /* Metadata client name (for debugging) */
+ H5FD_MEM_EARRAY_IBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5EA__cache_iblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5EA__cache_iblock_verify_chksum, /* 'verify_chksum' callback */
+ H5EA__cache_iblock_deserialize, /* 'deserialize' callback */
+ H5EA__cache_iblock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5EA__cache_iblock_serialize, /* 'serialize' callback */
+ H5EA__cache_iblock_notify, /* 'notify' callback */
+ H5EA__cache_iblock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5EA super block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_EARRAY_SBLOCK[1] = {{
+ H5AC_EARRAY_SBLOCK_ID, /* Metadata client ID */
+ "Extensible Array Super Block", /* Metadata client name (for debugging) */
+ H5FD_MEM_EARRAY_SBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5EA__cache_sblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5EA__cache_sblock_verify_chksum, /* 'verify_chksum' callback */
+ H5EA__cache_sblock_deserialize, /* 'deserialize' callback */
+ H5EA__cache_sblock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5EA__cache_sblock_serialize, /* 'serialize' callback */
+ H5EA__cache_sblock_notify, /* 'notify' callback */
+ H5EA__cache_sblock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5EA data block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_EARRAY_DBLOCK[1] = {{
+ H5AC_EARRAY_DBLOCK_ID, /* Metadata client ID */
+ "Extensible Array Data Block", /* Metadata client name (for debugging) */
+ H5FD_MEM_EARRAY_DBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5EA__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5EA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */
+ H5EA__cache_dblock_deserialize, /* 'deserialize' callback */
+ H5EA__cache_dblock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5EA__cache_dblock_serialize, /* 'serialize' callback */
+ H5EA__cache_dblock_notify, /* 'notify' callback */
+ H5EA__cache_dblock_free_icr, /* 'free_icr' callback */
+ H5EA__cache_dblock_fsf_size, /* 'fsf_size' callback */
+}};
+
+/* H5EA data block page inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{
+ H5AC_EARRAY_DBLK_PAGE_ID, /* Metadata client ID */
+ "Extensible Array Data Block Page", /* Metadata client name (for debugging) */
+ H5FD_MEM_EARRAY_DBLK_PAGE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5EA__cache_dblk_page_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5EA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */
+ H5EA__cache_dblk_page_deserialize, /* 'deserialize' callback */
+ H5EA__cache_dblk_page_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5EA__cache_dblk_page_serialize, /* 'serialize' callback */
+ H5EA__cache_dblk_page_notify, /* 'notify' callback */
+ H5EA__cache_dblk_page_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 16, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata; /* User data for callback */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5EA_HEADER_SIZE_FILE(udata->f);
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5EA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 16, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__cache_hdr_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5EA_cls_id_t id; /* ID of extensible array class, as found in file */
+ H5EA_hdr_t *hdr = NULL; /* Extensible array info */
+ H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata;
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(H5F_addr_defined(udata->addr));
+
+ /* Allocate space for the extensible array data structure */
+ if(NULL == (hdr = H5EA__hdr_alloc(udata->f)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array shared header")
+
+ /* Set the extensible array header's address */
+ hdr->addr = udata->addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5EA_HDR_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong extensible array header version")
+
+ /* Extensible array class */
+ id = (H5EA_cls_id_t)*image++;
+ if(id >= H5EA_NUM_CLS_ID)
+ H5E_THROW(H5E_BADTYPE, "incorrect extensible array class")
+ hdr->cparam.cls = H5EA_client_class_g[id];
+
+ /* General array creation/configuration information */
+ hdr->cparam.raw_elmt_size = *image++; /* Element size in file (in bytes) */
+ hdr->cparam.max_nelmts_bits = *image++; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */
+ hdr->cparam.idx_blk_elmts = *image++; /* # of elements to store in index block */
+ hdr->cparam.data_blk_min_elmts = *image++; /* Min. # of elements per data block */
+ hdr->cparam.sup_blk_min_data_ptrs = *image++; /* Min. # of data block pointers for a super block */
+ hdr->cparam.max_dblk_page_nelmts_bits = *image++; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */
+
+ /* Array statistics */
+ hdr->stats.computed.hdr_size = len; /* Size of header in file */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.super_blk_size); /* Size of super blocks created */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.ndata_blks); /* Number of data blocks created */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.data_blk_size); /* Size of data blocks created */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.nelmts); /* Number of elements 'realized' */
+
+ /* Internal information */
+ H5F_addr_decode(udata->f, &image, &hdr->idx_blk_addr); /* Address of index block */
+
+ /* Index block statistics */
+ if(H5F_addr_defined(hdr->idx_blk_addr)) {
+ H5EA_iblock_t iblock; /* Fake index block for computing size */
+
+ /* Set index block count for file */
+ hdr->stats.computed.nindex_blks = 1;
+
+ /* Set up fake index block for computing size on disk */
+ iblock.hdr = hdr;
+ iblock.nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs);
+ iblock.ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1);
+ iblock.nsblk_addrs = hdr->nsblks - iblock.nsblks;
+
+ /* Compute size of index block in file */
+ hdr->stats.computed.index_blk_size = H5EA_IBLOCK_SIZE(&iblock);
+ } /* end if */
+ else {
+ hdr->stats.computed.nindex_blks = 0; /* Number of index blocks in file */
+ hdr->stats.computed.index_blk_size = 0; /* Size of index blocks in file */
+ } /* end else */
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM));
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == len);
+
+ /* Finish initializing extensible array header */
+ if(H5EA__hdr_init(hdr, udata->ctx_udata) < 0)
+ H5E_THROW(H5E_CANTINIT, "initialization failed for extensible array header")
+ HDassert(hdr->size == len);
+
+ /* Set return value */
+ ret_value = hdr;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(hdr && H5EA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header")
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 16, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_hdr_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5EA_hdr_t *hdr = (const H5EA_hdr_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = hdr->size;
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 16, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = (H5EA_hdr_t *)_thing; /* Pointer to the extensible array header */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5EA_HDR_VERSION;
+
+ /* Extensible array type */
+ *image++ = hdr->cparam.cls->id;
+
+ /* General array creation/configuration information */
+ *image++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */
+ *image++ = hdr->cparam.max_nelmts_bits; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */
+ *image++ = hdr->cparam.idx_blk_elmts; /* # of elements to store in index block */
+ *image++ = hdr->cparam.data_blk_min_elmts; /* Min. # of elements per data block */
+ *image++ = hdr->cparam.sup_blk_min_data_ptrs; /* Min. # of data block pointers for a super block */
+ *image++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */
+
+ /* Array statistics */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.super_blk_size); /* Size of super blocks created */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.ndata_blks); /* Number of data blocks created */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.data_blk_size); /* Size of data blocks created */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.nelmts); /* Number of elements 'realized' */
+
+ /* Internal information */
+ H5F_addr_encode(f, &image, hdr->idx_blk_addr); /* Address of index block */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 11/30/15
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_hdr_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = (H5EA_hdr_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(hdr->swmr_write) {
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* If hdr->parent != NULL, hdr->parent is used to destroy
+ * the flush dependency before the header is evicted.
+ */
+ if(hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Destroy flush dependency on object header proxy */
+ if(H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent, (void *)hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between extensible array and proxy")
+ hdr->parent = NULL;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between header and extensible array 'top' proxy")
+ /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == hdr->parent);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_hdr_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 16, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_hdr_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array header */
+ if(H5EA__hdr_dest((H5EA_hdr_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free extensible array header")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_iblock_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */
+ H5EA_iblock_t iblock; /* Fake index block for computing size */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(image_len);
+
+ /* Set up fake index block for computing size on disk */
+ HDmemset(&iblock, 0, sizeof(iblock));
+ iblock.hdr = (H5EA_hdr_t *)hdr; /* Casting away 'const' OK - QAK */
+ iblock.nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs);
+ iblock.ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1);
+ iblock.nsblk_addrs = hdr->nsblks - iblock.nsblks;
+
+ /* Set the image length size */
+ *image_len = (size_t)H5EA_IBLOCK_SIZE(&iblock);
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5EA__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__cache_iblock_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = NULL; /* Index block info */
+ H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ haddr_t arr_addr; /* Address of array header in the file */
+ size_t u; /* Local index variable */
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(hdr);
+
+ /* Allocate the extensible array index block */
+ if(NULL == (iblock = H5EA__iblock_alloc(hdr)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block")
+
+ /* Set the extensible array index block's address */
+ iblock->addr = hdr->idx_blk_addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array index block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5EA_IBLOCK_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong extensible array index block version")
+
+ /* Extensible array type */
+ if(*image++ != (uint8_t)hdr->cparam.cls->id)
+ H5E_THROW(H5E_BADTYPE, "incorrect extensible array class")
+
+ /* Address of header for array that owns this block (just for file integrity checks) */
+ H5F_addr_decode(hdr->f, &image, &arr_addr);
+ if(H5F_addr_ne(arr_addr, hdr->addr))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array header address")
+
+ /* Internal information */
+
+ /* Decode elements in index block */
+ if(hdr->cparam.idx_blk_elmts > 0) {
+ /* Convert from raw elements on disk into native elements in memory */
+ if((hdr->cparam.cls->decode)(image, iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts, hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTDECODE, "can't decode extensible array index elements")
+ image += (hdr->cparam.idx_blk_elmts * hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Decode data block addresses in index block */
+ if(iblock->ndblk_addrs > 0) {
+ /* Decode addresses of data blocks in index block */
+ for(u = 0; u < iblock->ndblk_addrs; u++)
+ H5F_addr_decode(hdr->f, &image, &iblock->dblk_addrs[u]);
+ } /* end if */
+
+ /* Decode super block addresses in index block */
+ if(iblock->nsblk_addrs > 0) {
+ /* Decode addresses of super blocks in index block */
+ for(u = 0; u < iblock->nsblk_addrs; u++)
+ H5F_addr_decode(hdr->f, &image, &iblock->sblk_addrs[u]);
+ } /* end if */
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM));
+
+ /* Save the index block's size */
+ iblock->size = len;
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size);
+
+ /* Set return value */
+ ret_value = iblock;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(iblock && H5EA__iblock_dest(iblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block")
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_iblock_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5EA_iblock_t *iblock = (const H5EA_iblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(iblock);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = iblock->size;
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_iblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = (H5EA_iblock_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(iblock);
+ HDassert(iblock->hdr);
+
+ /* Get temporary pointer to serialized info */
+
+ /* Magic number */
+ HDmemcpy(image, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5EA_IBLOCK_VERSION;
+
+ /* Extensible array type */
+ *image++ = iblock->hdr->cparam.cls->id;
+
+ /* Address of array header for array which owns this block */
+ H5F_addr_encode(f, &image, iblock->hdr->addr);
+
+ /* Internal information */
+
+ /* Encode elements in index block */
+ if(iblock->hdr->cparam.idx_blk_elmts > 0) {
+ /* Convert from native elements in memory into raw elements on disk */
+ if((iblock->hdr->cparam.cls->encode)(image, iblock->elmts, (size_t)iblock->hdr->cparam.idx_blk_elmts, iblock->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTENCODE, "can't encode extensible array index elements")
+ image += (iblock->hdr->cparam.idx_blk_elmts * iblock->hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Encode data block addresses in index block */
+ if(iblock->ndblk_addrs > 0) {
+ size_t u; /* Local index variable */
+
+ /* Encode addresses of data blocks in index block */
+ for(u = 0; u < iblock->ndblk_addrs; u++)
+ H5F_addr_encode(f, &image, iblock->dblk_addrs[u]);
+ } /* end if */
+
+ /* Encode data block addresses in index block */
+ if(iblock->nsblk_addrs > 0) {
+ size_t u; /* Local index variable */
+
+ /* Encode addresses of super blocks in index block */
+ for(u = 0; u < iblock->nsblk_addrs; u++)
+ H5F_addr_encode(f, &image, iblock->sblk_addrs[u]);
+ } /* end if */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_iblock_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = (H5EA_iblock_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on extensible array header */
+ if(H5EA__create_flush_depend((H5AC_info_t *)iblock->hdr, (H5AC_info_t *)iblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between index block and header, address = %llu", (unsigned long long)iblock->addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on extensible array header */
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)iblock->hdr, (H5AC_info_t *)iblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between index block and header, address = %llu", (unsigned long long)iblock->addr)
+
+ /* Detach from 'top' proxy for extensible array */
+ if(iblock->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(iblock->top_proxy, iblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between index block and extensible array 'top' proxy")
+ iblock->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_iblock_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_iblock_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array index block */
+ if(H5EA__iblock_dest((H5EA_iblock_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free extensible array index block")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_iblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_sblock_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */
+ H5EA_sblock_t sblock; /* Fake super block for computing size */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->sblk_idx > 0);
+ HDassert(H5F_addr_defined(udata->sblk_addr));
+ HDassert(image_len);
+
+ /* Set up fake super block for computing size on disk */
+ /* (Note: extracted from H5EA__sblock_alloc) */
+ HDmemset(&sblock, 0, sizeof(sblock));
+ sblock.hdr = udata->hdr;
+ sblock.ndblks = udata->hdr->sblk_info[udata->sblk_idx].ndblks;
+ sblock.dblk_nelmts = udata->hdr->sblk_info[udata->sblk_idx].dblk_nelmts;
+
+ /* Check if # of elements in data blocks requires paging */
+ if(sblock.dblk_nelmts > udata->hdr->dblk_page_nelmts) {
+ /* Compute # of pages in each data block from this super block */
+ sblock.dblk_npages = sblock.dblk_nelmts / udata->hdr->dblk_page_nelmts;
+
+ /* Sanity check that we have at least 2 pages in data block */
+ HDassert(sblock.dblk_npages > 1);
+
+ /* Sanity check for integer truncation */
+ HDassert((sblock.dblk_npages * udata->hdr->dblk_page_nelmts) == sblock.dblk_nelmts);
+
+ /* Compute size of buffer for each data block's 'page init' bitmask */
+ sblock.dblk_page_init_size = ((sblock.dblk_npages) + 7) / 8;
+ HDassert(sblock.dblk_page_init_size > 0);
+ } /* end if */
+
+ /* Set the image length size */
+ *image_len = (size_t)H5EA_SBLOCK_SIZE(&sblock);
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5EA__cache_sblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__cache_sblock_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = NULL; /* Super block info */
+ H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ haddr_t arr_addr; /* Address of array header in the file */
+ size_t u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->parent);
+ HDassert(udata->sblk_idx > 0);
+ HDassert(H5F_addr_defined(udata->sblk_addr));
+
+ /* Allocate the extensible array super block */
+ if(NULL == (sblock = H5EA__sblock_alloc(udata->hdr, udata->parent, udata->sblk_idx)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super block")
+
+ /* Set the extensible array super block's address */
+ sblock->addr = udata->sblk_addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array super block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5EA_SBLOCK_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong extensible array super block version")
+
+ /* Extensible array type */
+ if(*image++ != (uint8_t)udata->hdr->cparam.cls->id)
+ H5E_THROW(H5E_BADTYPE, "incorrect extensible array class")
+
+ /* Address of header for array that owns this block (just for file integrity checks) */
+ H5F_addr_decode(udata->hdr->f, &image, &arr_addr);
+ if(H5F_addr_ne(arr_addr, udata->hdr->addr))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array header address")
+
+ /* Offset of block within the array's address space */
+ UINT64DECODE_VAR(image, sblock->block_off, udata->hdr->arr_off_size);
+
+ /* Internal information */
+
+ /* Check for 'page init' bitmasks for this super block */
+ if(sblock->dblk_npages > 0) {
+ size_t tot_page_init_size = sblock->ndblks * sblock->dblk_page_init_size; /* Compute total size of 'page init' buffer */
+
+ /* Retrieve the 'page init' bitmasks */
+ HDmemcpy(sblock->page_init, image, tot_page_init_size);
+ image += tot_page_init_size;
+ } /* end if */
+
+ /* Decode data block addresses */
+ for(u = 0; u < sblock->ndblks; u++)
+ H5F_addr_decode(udata->hdr->f, &image, &sblock->dblk_addrs[u]);
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM));
+
+ /* Save the super block's size */
+ sblock->size = len;
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == sblock->size);
+
+ /* Set return value */
+ ret_value = sblock;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(sblock && H5EA__sblock_dest(sblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block")
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_sblock_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5EA_sblock_t *sblock = (const H5EA_sblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(sblock);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = sblock->size;
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_sblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = (H5EA_sblock_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ size_t u; /* Local index variable */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(sblock);
+ HDassert(sblock->hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5EA_SBLOCK_VERSION;
+
+ /* Extensible array type */
+ *image++ = sblock->hdr->cparam.cls->id;
+
+ /* Address of array header for array which owns this block */
+ H5F_addr_encode(f, &image, sblock->hdr->addr);
+
+ /* Offset of block in array */
+ UINT64ENCODE_VAR(image, sblock->block_off, sblock->hdr->arr_off_size);
+
+ /* Internal information */
+
+ /* Check for 'page init' bitmasks for this super block */
+ if(sblock->dblk_npages > 0) {
+ size_t tot_page_init_size = sblock->ndblks * sblock->dblk_page_init_size; /* Compute total size of 'page init' buffer */
+
+ /* Store the 'page init' bitmasks */
+ HDmemcpy(image, sblock->page_init, tot_page_init_size);
+ image += tot_page_init_size;
+ } /* end if */
+
+ /* Encode addresses of data blocks in super block */
+ for(u = 0; u < sblock->ndblks; u++)
+ H5F_addr_encode(f, &image, sblock->dblk_addrs[u]);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 31 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_sblock_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = (H5EA_sblock_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(sblock);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on index block */
+ if(H5EA__create_flush_depend((H5AC_info_t *)sblock->parent, (H5AC_info_t *)sblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between super block and index block, address = %llu", (unsigned long long)sblock->addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* Destroy flush dependency on extensible array header, if set */
+ if(sblock->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)sblock->hdr, (H5AC_info_t *)sblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between super block and header, address = %llu", (unsigned long long)sblock->addr)
+ sblock->has_hdr_depend = FALSE;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on index block */
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)sblock->parent, (H5AC_info_t *)sblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between super block and index block, address = %llu", (unsigned long long)sblock->addr)
+
+ /* Destroy flush dependency on extensible array header, if set */
+ if(sblock->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)sblock->hdr, (H5AC_info_t *)sblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between super block and header, address = %llu", (unsigned long long)sblock->addr)
+ sblock->has_hdr_depend = FALSE;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(sblock->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(sblock->top_proxy, sblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between super block and extensible array 'top' proxy")
+ sblock->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_sblock_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_sblock_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array super block */
+ if(H5EA__sblock_dest((H5EA_sblock_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free extensible array super block")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */
+ H5EA_dblock_t dblock; /* Fake data block for computing size */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->nelmts > 0);
+ HDassert(image_len);
+
+ /* Set up fake data block for computing size on disk */
+ /* (Note: extracted from H5EA__dblock_alloc) */
+ HDmemset(&dblock, 0, sizeof(dblock));
+
+ /* need to set:
+ *
+ * dblock.hdr
+ * dblock.npages
+ * dblock.nelmts
+ *
+ * before we invoke either H5EA_DBLOCK_PREFIX_SIZE() or
+ * H5EA_DBLOCK_SIZE().
+ */
+ dblock.hdr = udata->hdr;
+ dblock.nelmts = udata->nelmts;
+
+ if(udata->nelmts > udata->hdr->dblk_page_nelmts) {
+ /* Set the # of pages in the direct block */
+ dblock.npages = udata->nelmts / udata->hdr->dblk_page_nelmts;
+ HDassert(udata->nelmts==(dblock.npages * udata->hdr->dblk_page_nelmts));
+ } /* end if */
+
+ /* Set the image length size */
+ if(!dblock.npages)
+ *image_len = H5EA_DBLOCK_SIZE(&dblock);
+ else
+ *image_len = H5EA_DBLOCK_PREFIX_SIZE(&dblock);
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5EA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__cache_dblock_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = NULL; /* Data block info */
+ H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ haddr_t arr_addr; /* Address of array header in the file */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->parent);
+ HDassert(udata->nelmts > 0);
+ HDassert(H5F_addr_defined(udata->dblk_addr));
+
+ /* Allocate the extensible array data block */
+ if(NULL == (dblock = H5EA__dblock_alloc(udata->hdr, udata->parent, udata->nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block")
+
+ HDassert(((!dblock->npages) && (len == H5EA_DBLOCK_SIZE(dblock))) ||
+ (len == H5EA_DBLOCK_PREFIX_SIZE(dblock)));
+
+ /* Set the extensible array data block's information */
+ dblock->addr = udata->dblk_addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array data block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5EA_DBLOCK_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong extensible array data block version")
+
+ /* Extensible array type */
+ if(*image++ != (uint8_t)udata->hdr->cparam.cls->id)
+ H5E_THROW(H5E_BADTYPE, "incorrect extensible array class")
+
+ /* Address of header for array that owns this block (just for file integrity checks) */
+ H5F_addr_decode(udata->hdr->f, &image, &arr_addr);
+ if(H5F_addr_ne(arr_addr, udata->hdr->addr))
+ H5E_THROW(H5E_BADVALUE, "wrong extensible array header address")
+
+ /* Offset of block within the array's address space */
+ UINT64DECODE_VAR(image, dblock->block_off, udata->hdr->arr_off_size);
+
+ /* Internal information */
+
+ /* Only decode elements if the data block is not paged */
+ if(!dblock->npages) {
+ /* Decode elements in data block */
+ /* Convert from raw elements on disk into native elements in memory */
+ if((udata->hdr->cparam.cls->decode)(image, dblock->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTDECODE, "can't decode extensible array data elements")
+ image += (udata->nelmts * udata->hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM));
+
+ /* Set the data block's size */
+ /* (Note: This is not the same as the image length, for paged data blocks) */
+ dblock->size = H5EA_DBLOCK_SIZE(dblock);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == len);
+
+ /* Set return value */
+ ret_value = dblock;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(dblock && H5EA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block")
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_dblock_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5EA_dblock_t *dblock = (const H5EA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ if(!dblock->npages)
+ *image_len = dblock->size;
+ else
+ *image_len = (size_t)H5EA_DBLOCK_PREFIX_SIZE(dblock);
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = (H5EA_dblock_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(dblock);
+ HDassert(dblock->hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5EA_DBLOCK_VERSION;
+
+ /* Extensible array type */
+ *image++ = dblock->hdr->cparam.cls->id;
+
+ /* Address of array header for array which owns this block */
+ H5F_addr_encode(f, &image, dblock->hdr->addr);
+
+ /* Offset of block in array */
+ UINT64ENCODE_VAR(image, dblock->block_off, dblock->hdr->arr_off_size);
+
+ /* Internal information */
+
+ /* Only encode elements if the data block is not paged */
+ if(!dblock->npages) {
+ /* Encode elements in data block */
+
+ /* Convert from native elements in memory into raw elements on disk */
+ if((dblock->hdr->cparam.cls->encode)(image, dblock->elmts, dblock->nelmts, dblock->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements")
+ image += (dblock->nelmts * dblock->hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 31 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblock_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = (H5EA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5EA__create_flush_depend((H5AC_info_t *)dblock->parent, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and parent, address = %llu", (unsigned long long)dblock->addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* Destroy flush dependency on extensible array header, if set */
+ if(dblock->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between direct block and header, address = %llu", (unsigned long long)dblock->addr)
+ dblock->has_hdr_depend = FALSE;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblock->parent, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block and parent, address = %llu", (unsigned long long)dblock->addr)
+
+ /* Destroy flush dependency on extensible array header, if set */
+ if(dblock->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block and header, address = %llu", (unsigned long long)dblock->addr)
+ dblock->has_hdr_depend = FALSE;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(dblock->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(dblock->top_proxy, dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block and extensible array 'top' proxy")
+ dblock->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblock_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array data block */
+ if(H5EA__dblock_dest((H5EA_dblock_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free extensible array data block")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblock_fsf_size
+ *
+ * Purpose: Tell the metadata cache the actual amount of file space
+ * to free when a dblock entry is destroyed with the free
+ * file space block set.
+ *
+ * This function is needed when the data block is paged, as
+ * the datablock header and all its pages are allocated as a
+ * single contiguous chunk of file space, and must be
+ * deallocated the same way.
+ *
+ * The size of the chunk of memory in which the dblock
+ * header and all its pages is stored in the size field,
+ * so we simply pass that value back to the cache.
+ *
+ * If the datablock is not paged, then the size field of
+ * the cache_info contains the correct size. However this
+ * value will be the same as the size field, so we return
+ * the contents of the size field to the cache in this case
+ * as well.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 12/5/14
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_dblock_fsf_size(const void *_thing, size_t *fsf_size))
+
+ /* Local variables */
+ const H5EA_dblock_t *dblock = (const H5EA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_EARRAY_DBLOCK);
+ HDassert(fsf_size);
+
+ *fsf_size = dblock->size;
+
+END_FUNC(STATIC) /* end H5EA__cache_dblock_fsf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_dblk_page_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5EA_DBLK_PAGE_SIZE(udata->hdr);
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5EA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__cache_dblk_page_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = NULL; /* Data block page info */
+ H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+
+ /* Sanity check */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->parent);
+ HDassert(H5F_addr_defined(udata->dblk_page_addr));
+
+ /* Allocate the extensible array data block page */
+ if(NULL == (dblk_page = H5EA__dblk_page_alloc(udata->hdr, udata->parent)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block page")
+
+ /* Set the extensible array data block page's information */
+ dblk_page->addr = udata->dblk_page_addr;
+
+ /* Internal information */
+
+ /* Decode elements in data block page */
+ /* Convert from raw elements on disk into native elements in memory */
+ if((udata->hdr->cparam.cls->decode)(image, dblk_page->elmts, udata->hdr->dblk_page_nelmts, udata->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTDECODE, "can't decode extensible array data elements")
+ image += (udata->hdr->dblk_page_nelmts * udata->hdr->cparam.raw_elmt_size);
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM));
+
+ /* Set the data block page's size */
+ dblk_page->size = len;
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size);
+
+ /* Set return value */
+ ret_value = dblk_page;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(dblk_page && H5EA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page")
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__cache_dblk_page_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5EA_dblk_page_t *dblk_page = (const H5EA_dblk_page_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblk_page);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = dblk_page->size;
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblk_page_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = (H5EA_dblk_page_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(dblk_page);
+ HDassert(dblk_page->hdr);
+
+ /* Internal information */
+
+ /* Encode elements in data block page */
+
+ /* Convert from native elements in memory into raw elements on disk */
+ if((dblk_page->hdr->cparam.cls->encode)(image, dblk_page->elmts, dblk_page->hdr->dblk_page_nelmts, dblk_page->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements")
+ image += (dblk_page->hdr->dblk_page_nelmts * dblk_page->hdr->cparam.raw_elmt_size);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 31 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = (H5EA_dblk_page_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(dblk_page);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5EA__create_flush_depend((H5AC_info_t *)dblk_page->parent, (H5AC_info_t *)dblk_page) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block page and parent, address = %llu", (unsigned long long)dblk_page->addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* Destroy flush dependency on extensible array header, if set */
+ if(dblk_page->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblk_page->hdr, (H5AC_info_t *)dblk_page) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and header, address = %llu", (unsigned long long)dblk_page->addr)
+ dblk_page->has_hdr_depend = FALSE;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblk_page->parent, (H5AC_info_t *)dblk_page) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and parent, address = %llu", (unsigned long long)dblk_page->addr)
+
+ /* Destroy flush dependency on extensible array header, if set */
+ if(dblk_page->has_hdr_depend) {
+ if(H5EA__destroy_flush_depend((H5AC_info_t *)dblk_page->hdr, (H5AC_info_t *)dblk_page) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and header, address = %llu", (unsigned long long)dblk_page->addr)
+ dblk_page->has_hdr_depend = FALSE;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(dblk_page->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(dblk_page->top_proxy, dblk_page) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and extensible array 'top' proxy")
+ dblk_page->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__cache_dblk_page_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__cache_dblk_page_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array data block page */
+ if(H5EA__dblk_page_dest((H5EA_dblk_page_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free extensible array data block page")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__cache_dblk_page_free_icr() */
+
diff --git a/src/H5EAdbg.c b/src/H5EAdbg.c
new file mode 100644
index 0000000..e67a5a8
--- /dev/null
+++ b/src/H5EAdbg.c
@@ -0,0 +1,476 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAdbg.c
+ * Sep 11 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Dump debugging information about an extensible array.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_debug
+ *
+ * Purpose: Prints debugging info about a extensible array header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth, const H5EA_class_t *cls, haddr_t obj_addr))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Shared extensible array header */
+ void *dbg_ctx = NULL; /* Extensible array debugging context */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create fixed array debugging context")
+ } /* end if */
+
+ /* Load the extensible array header */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sExtensible Array Header...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Header size:",
+ hdr->size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Raw Element Size:",
+ (unsigned)hdr->cparam.raw_elmt_size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Native Element Size (on this platform):",
+ hdr->cparam.cls->nat_elmt_size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Log2(Max. # of elements in array):",
+ (unsigned)hdr->cparam.max_nelmts_bits);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "# of elements in index block:",
+ (unsigned)hdr->cparam.idx_blk_elmts);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Min. # of elements per data block:",
+ (unsigned)hdr->cparam.data_blk_min_elmts);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Min. # of data block pointers for a super block:",
+ (unsigned)hdr->cparam.sup_blk_min_data_ptrs);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Log2(Max. # of elements in data block page):",
+ (unsigned)hdr->cparam.max_dblk_page_nelmts_bits);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Highest element index stored (+1):",
+ hdr->stats.stored.max_idx_set);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of super blocks created:",
+ hdr->stats.stored.nsuper_blks);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of data blocks created:",
+ hdr->stats.stored.ndata_blks);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of elements 'realized':",
+ hdr->stats.stored.nelmts);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Index Block Address:",
+ hdr->idx_blk_addr);
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release extensible array debugging context")
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PKG) /* end H5EA__hdr_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_debug
+ *
+ * Purpose: Prints debugging info about a extensible array index block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, FILE *stream, int indent,
+ int fwidth, const H5EA_class_t *cls, haddr_t hdr_addr, haddr_t obj_addr))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Shared extensible array header */
+ H5EA_iblock_t *iblock = NULL; /* Extensible array index block */
+ void *dbg_ctx = NULL; /* Extensible array context */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create extensible array debugging context")
+ } /* end if */
+
+ /* Load the extensible array header */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header")
+
+ /* Sanity check */
+ HDassert(H5F_addr_eq(hdr->idx_blk_addr, addr));
+
+ /* Protect index block */
+ if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sExtensible Array Index Block...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Index Block size:",
+ iblock->size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "# of data block addresses in index block:",
+ iblock->ndblk_addrs);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "# of super block addresses in index block:",
+ iblock->nsblk_addrs);
+
+ /* Check if there are any elements in index block */
+ if(hdr->cparam.idx_blk_elmts > 0) {
+ unsigned u; /* Local index variable */
+
+ /* Print the elements in the index block */
+ HDfprintf(stream, "%*sElements in Index Block:\n", indent, "");
+ for(u = 0; u < hdr->cparam.idx_blk_elmts; u++) {
+ /* Call the class's 'debug' callback */
+ if((hdr->cparam.cls->debug)(stream, (indent + 3), MAX(0, (fwidth - 3)),
+ (hsize_t)u,
+ ((uint8_t *)iblock->elmts) + (hdr->cparam.cls->nat_elmt_size * u)) < 0)
+ H5E_THROW(H5E_CANTGET, "can't get element for debugging")
+ } /* end for */
+ } /* end if */
+
+ /* Check if there are any data block addresses in index block */
+ if(iblock->ndblk_addrs > 0) {
+ char temp_str[128]; /* Temporary string, for formatting */
+ unsigned u; /* Local index variable */
+
+ /* Print the data block addresses in the index block */
+ HDfprintf(stream, "%*sData Block Addresses in Index Block:\n", indent, "");
+ for(u = 0; u < iblock->ndblk_addrs; u++) {
+ /* Print address */
+ sprintf(temp_str, "Address #%u:", u);
+ HDfprintf(stream, "%*s%-*s %a\n", (indent + 3), "", MAX(0, (fwidth - 3)),
+ temp_str,
+ iblock->dblk_addrs[u]);
+ } /* end for */
+ } /* end if */
+
+ /* Check if there are any super block addresses in index block */
+ if(iblock->nsblk_addrs > 0) {
+ char temp_str[128]; /* Temporary string, for formatting */
+ unsigned u; /* Local index variable */
+
+ /* Print the super block addresses in the index block */
+ HDfprintf(stream, "%*sSuper Block Addresses in Index Block:\n", indent, "");
+ for(u = 0; u < iblock->nsblk_addrs; u++) {
+ /* Print address */
+ sprintf(temp_str, "Address #%u:", u);
+ HDfprintf(stream, "%*s%-*s %a\n", (indent + 3), "", MAX(0, (fwidth - 3)),
+ temp_str,
+ iblock->sblk_addrs[u]);
+ } /* end for */
+ } /* end if */
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release extensible array debugging context")
+ if(iblock && H5EA__iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block")
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PKG) /* end H5EA__iblock_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_debug
+ *
+ * Purpose: Prints debugging info about a extensible array super block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__sblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth, const H5EA_class_t *cls, haddr_t hdr_addr, unsigned sblk_idx, haddr_t obj_addr))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Shared extensible array header */
+ H5EA_sblock_t *sblock = NULL; /* Extensible array super block */
+ void *dbg_ctx = NULL; /* Extensible array context */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create extensible array debugging context")
+ } /* end if */
+
+ /* Load the extensible array header */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header")
+
+ /* Protect super block */
+ /* (Note: setting parent of super block to 'hdr' for this operation should be OK -QAK) */
+ if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, (H5EA_iblock_t *)hdr, addr, sblk_idx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)addr)
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sExtensible Array Super Block...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Super Block size:",
+ sblock->size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "# of data block addresses in super block:",
+ sblock->ndblks);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "# of elements in data blocks from this super block:",
+ sblock->dblk_nelmts);
+
+ /* Check if there are any data block addresses in super block */
+ if(sblock->ndblks > 0) {
+ char temp_str[128]; /* Temporary string, for formatting */
+ unsigned u; /* Local index variable */
+
+ /* Print the data block addresses in the super block */
+ HDfprintf(stream, "%*sData Block Addresses in Super Block:\n", indent, "");
+ for(u = 0; u < sblock->ndblks; u++) {
+ /* Print address */
+ sprintf(temp_str, "Address #%u:", u);
+ HDfprintf(stream, "%*s%-*s %a\n", (indent + 3), "", MAX(0, (fwidth - 3)),
+ temp_str,
+ sblock->dblk_addrs[u]);
+ } /* end for */
+ } /* end if */
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release extensible array debugging context")
+ if(sblock && H5EA__sblock_unprotect(sblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array super block")
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PKG) /* end H5EA__sblock_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_debug
+ *
+ * Purpose: Prints debugging info about a extensible array data block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 22 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth, const H5EA_class_t *cls, haddr_t hdr_addr, size_t dblk_nelmts, haddr_t obj_addr))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Shared extensible array header */
+ H5EA_dblock_t *dblock = NULL; /* Extensible array data block */
+ void *dbg_ctx = NULL; /* Extensible array context */
+ size_t u; /* Local index variable */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(dblk_nelmts > 0);
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create extensible array debugging context")
+ } /* end if */
+
+ /* Load the extensible array header */
+ if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header")
+
+ /* Protect data block */
+ /* (Note: setting parent of data block to 'hdr' for this operation should be OK -QAK) */
+ if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, hdr, addr, dblk_nelmts, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)addr)
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sExtensible Array data Block...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Data Block size:",
+ dblock->size);
+
+
+ /* Print the elements in the index block */
+ HDfprintf(stream, "%*sElements:\n", indent, "");
+ for(u = 0; u < dblk_nelmts; u++) {
+ /* Call the class's 'debug' callback */
+ if((hdr->cparam.cls->debug)(stream, (indent + 3), MAX(0, (fwidth - 3)),
+ (hsize_t)u,
+ ((uint8_t *)dblock->elmts) + (hdr->cparam.cls->nat_elmt_size * u)) < 0)
+ H5E_THROW(H5E_CANTGET, "can't get element for debugging")
+ } /* end for */
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release extensible array debugging context")
+ if(dblock && H5EA__dblock_unprotect(dblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block")
+ if(hdr && H5EA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PKG) /* end H5EA__dblock_debug() */
+
diff --git a/src/H5EAdblkpage.c b/src/H5EAdblkpage.c
new file mode 100644
index 0000000..2b07356
--- /dev/null
+++ b/src/H5EAdblkpage.c
@@ -0,0 +1,341 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAdblkpage.c
+ * Nov 20 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Data block page routines for extensible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_dblk_page_t struct */
+H5FL_DEFINE_STATIC(H5EA_dblk_page_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblk_page_alloc
+ *
+ * Purpose: Allocate extensible array data block page
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_dblk_page_t *, NULL, NULL,
+H5EA__dblk_page_alloc(H5EA_hdr_t *hdr, H5EA_sblock_t *parent))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = NULL; /* Extensible array data block page */
+
+ /* Check arguments */
+ HDassert(hdr);
+
+ /* Allocate memory for the data block */
+ if(NULL == (dblk_page = H5FL_CALLOC(H5EA_dblk_page_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block page")
+
+ /* Share common array information */
+ if(H5EA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ dblk_page->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ dblk_page->parent = parent;
+
+ /* Allocate buffer for elements in data block page */
+ if(NULL == (dblk_page->elmts = H5EA__hdr_alloc_elmts(hdr, hdr->dblk_page_nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block page element buffer")
+
+ /* Set the return value */
+ ret_value = dblk_page;
+
+CATCH
+ if(!ret_value)
+ if(dblk_page && H5EA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page")
+
+END_FUNC(PKG) /* end H5EA__dblk_page_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblk_page_create
+ *
+ * Purpose: Creates a new extensible array data block page in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblk_page_create(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_sblock_t *parent,
+ haddr_t addr))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = NULL; /* Extensible array data block page */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Allocate the data block page */
+ if(NULL == (dblk_page = H5EA__dblk_page_alloc(hdr, parent)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block page")
+
+ /* Set info about data block page on disk */
+ dblk_page->addr = addr;
+ dblk_page->size = H5EA_DBLK_PAGE_SIZE(hdr);
+
+ /* Clear any elements in data block page to fill value */
+ if((hdr->cparam.cls->fill)(dblk_page->elmts, (size_t)hdr->dblk_page_nelmts) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set extensible array data block page elements to class's fill value")
+
+ /* Cache the new extensible array data block page */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add extensible array data block page to cache")
+ inserted = TRUE;
+
+ /* Add data block page as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblk_page) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ dblk_page->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+CATCH
+ if(ret_value < 0)
+ if(dblk_page) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(dblk_page) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array data block page from cache")
+
+ /* Destroy data block page */
+ if(H5EA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__dblk_page_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblk_page_protect
+ *
+ * Purpose: Convenience wrapper around protecting extensible array data
+ * block page
+ *
+ * Return: Non-NULL pointer to data block page on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_dblk_page_t *, NULL, NULL,
+H5EA__dblk_page_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_sblock_t *parent,
+ haddr_t dblk_page_addr, unsigned flags))
+
+ /* Local variables */
+ H5EA_dblk_page_t *dblk_page = NULL; /* Extensible array data block page */
+ H5EA_dblk_page_cache_ud_t udata; /* Information needed for loading data block page */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblk_page_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG may be set */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data */
+ udata.hdr = hdr;
+ udata.parent = parent;
+ udata.dblk_page_addr = dblk_page_addr;
+
+ /* Protect the data block page */
+ if(NULL == (dblk_page = (H5EA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == dblk_page->top_proxy) {
+ /* Add data block page as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblk_page) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ dblk_page->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dblk_page;
+
+CATCH
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the data block page, if it was protected */
+ if(dblk_page && H5AC_unprotect(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array data block page, address = %llu", (unsigned long long)dblk_page->addr)
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__dblk_page_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblk_page_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting extensible array
+ * data block page
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblk_page_unprotect(H5EA_dblk_page_t *dblk_page, hid_t dxpl_id,
+ unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(dblk_page);
+
+ /* Unprotect the data block page */
+ if(H5AC_unprotect(dblk_page->hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array data block page, address = %llu", (unsigned long long)dblk_page->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__dblk_page_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblk_page_dest
+ *
+ * Purpose: Destroys an extensible array data block page in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblk_page_dest(H5EA_dblk_page_t *dblk_page))
+
+ /* Sanity check */
+ HDassert(dblk_page);
+ HDassert(!dblk_page->has_hdr_depend);
+
+ /* Check if header field has been initialized */
+ if(dblk_page->hdr) {
+ /* Check if buffer for data block page elements has been initialized */
+ if(dblk_page->elmts) {
+ /* Free buffer for data block page elements */
+ if(H5EA__hdr_free_elmts(dblk_page->hdr, dblk_page->hdr->dblk_page_nelmts, dblk_page->elmts) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to free extensible array data block element buffer")
+ dblk_page->elmts = NULL;
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5EA__hdr_decr(dblk_page->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ dblk_page->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == dblk_page->top_proxy);
+
+ /* Free the data block page itself */
+ dblk_page = H5FL_FREE(H5EA_dblk_page_t, dblk_page);
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__dblk_page_dest() */
+
diff --git a/src/H5EAdblock.c b/src/H5EAdblock.c
new file mode 100644
index 0000000..7df0ee9
--- /dev/null
+++ b/src/H5EAdblock.c
@@ -0,0 +1,485 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAdblock.c
+ * Sep 11 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Data block routines for extensible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_dblock_t struct */
+H5FL_DEFINE_STATIC(H5EA_dblock_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_alloc
+ *
+ * Purpose: Allocate extensible array data block
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_dblock_t *, NULL, NULL,
+H5EA__dblock_alloc(H5EA_hdr_t *hdr, void *parent, size_t nelmts))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = NULL; /* Extensible array data block */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(parent);
+ HDassert(nelmts > 0);
+
+ /* Allocate memory for the data block */
+ if(NULL == (dblock = H5FL_CALLOC(H5EA_dblock_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block")
+
+ /* Share common array information */
+ if(H5EA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ dblock->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ dblock->parent = parent;
+ dblock->nelmts = nelmts;
+
+ /* Check if the data block is not going to be paged */
+ if(nelmts > hdr->dblk_page_nelmts) {
+ /* Set the # of pages in the direct block */
+ dblock->npages = nelmts / hdr->dblk_page_nelmts;
+ HDassert(nelmts == (dblock->npages * hdr->dblk_page_nelmts));
+ } /* end if */
+ else {
+ /* Allocate buffer for elements in data block */
+ if(NULL == (dblock->elmts = H5EA__hdr_alloc_elmts(hdr, nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block element buffer")
+ } /* end else */
+
+ /* Set the return value */
+ ret_value = dblock;
+
+CATCH
+ if(!ret_value)
+ if(dblock && H5EA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block")
+
+END_FUNC(PKG) /* end H5EA__dblock_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_create
+ *
+ * Purpose: Creates a new extensible array data block in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5EA__dblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ hbool_t *stats_changed, hsize_t dblk_off, size_t nelmts))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = NULL; /* Extensible array data block */
+ haddr_t dblock_addr; /* Extensible array data block address */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(stats_changed);
+ HDassert(nelmts > 0);
+
+ /* Allocate the data block */
+ if(NULL == (dblock = H5EA__dblock_alloc(hdr, parent, nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block")
+
+ /* Set size of data block on disk */
+ dblock->size = H5EA_DBLOCK_SIZE(dblock);
+
+ /* Set offset of block in array's address space */
+ dblock->block_off = dblk_off;
+
+ /* Allocate space for the data block on disk */
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_DBLOCK, dxpl_id, (hsize_t)dblock->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array data block")
+ dblock->addr = dblock_addr;
+
+ /* Don't initialize elements if paged */
+ if(!dblock->npages)
+ /* Clear any elements in data block to fill value */
+ if((hdr->cparam.cls->fill)(dblock->elmts, (size_t)dblock->nelmts) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set extensible array data block elements to class's fill value")
+
+ /* Cache the new extensible array data block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add extensible array data block to cache")
+ inserted = TRUE;
+
+ /* Add data block as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ dblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Update extensible array data block statistics */
+ hdr->stats.stored.ndata_blks++;
+ hdr->stats.stored.data_blk_size += dblock->size;
+
+ /* Increment count of elements "realized" */
+ hdr->stats.stored.nelmts += nelmts;
+
+ /* Mark the statistics as changed */
+ *stats_changed = TRUE;
+
+ /* Set address of data block to return */
+ ret_value = dblock_addr;
+
+CATCH
+ if(!H5F_addr_defined(ret_value))
+ if(dblock) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(dblock) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array data block from cache")
+
+ /* Release data block's disk space */
+ if(H5F_addr_defined(dblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_DBLOCK, dxpl_id, dblock->addr, (hsize_t)dblock->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to release extensible array data block")
+
+ /* Destroy data block */
+ if(H5EA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__dblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_sblk_idx
+ *
+ * Purpose: Compute the index of the super block where the element is
+ * located.
+ *
+ * Return: Super block index on success/Can't fail
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+unsigned, 0, -,
+H5EA__dblock_sblk_idx(const H5EA_hdr_t *hdr, hsize_t idx))
+
+ /* Local variables */
+ unsigned sblk_idx; /* Which superblock does this index fall in? */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(idx >= hdr->cparam.idx_blk_elmts);
+
+ /* Adjust index for elements in index block */
+ idx -= hdr->cparam.idx_blk_elmts;
+
+ /* Determine the superblock information for the index */
+ H5_CHECK_OVERFLOW(idx, /*From:*/hsize_t, /*To:*/uint64_t);
+ sblk_idx = H5VM_log2_gen((uint64_t)((idx / hdr->cparam.data_blk_min_elmts) + 1));
+
+ /* Set return value */
+ ret_value = sblk_idx;
+
+END_FUNC(PKG) /* end H5EA__dblock_sblk_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_protect
+ *
+ * Purpose: Convenience wrapper around protecting extensible array data block
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 18 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_dblock_t *, NULL, NULL,
+H5EA__dblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ haddr_t dblk_addr, size_t dblk_nelmts, unsigned flags))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock; /* Extensible array data block */
+ H5EA_dblock_cache_ud_t udata; /* Information needed for loading data block */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblk_addr));
+ HDassert(dblk_nelmts);
+
+ /* only the H5AC__READ_ONLY_FLAG may be set */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data */
+ udata.hdr = hdr;
+ udata.parent = parent;
+ udata.nelmts = dblk_nelmts;
+ udata.dblk_addr = dblk_addr;
+
+ /* Protect the data block */
+ if(NULL == (dblock = (H5EA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblk_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)dblk_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == dblock->top_proxy) {
+ /* Add data block as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ dblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dblock;
+
+CATCH
+
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the data block, if it was protected */
+ if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblock->addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array data block, address = %llu", (unsigned long long)dblock->addr)
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__dblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting extensible array data block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblock_unprotect(H5EA_dblock_t *dblock, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(dblock);
+
+ /* Unprotect the data block */
+ if(H5AC_unprotect(dblock->hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblock->addr, dblock, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array data block, address = %llu", (unsigned long long)dblock->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__dblock_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_delete
+ *
+ * Purpose: Delete a data block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 22 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ haddr_t dblk_addr, size_t dblk_nelmts))
+
+ /* Local variables */
+ H5EA_dblock_t *dblock = NULL; /* Pointer to data block */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(parent);
+ HDassert(H5F_addr_defined(dblk_addr));
+ HDassert(dblk_nelmts > 0);
+
+ /* Protect data block */
+ if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, parent, dblk_addr, dblk_nelmts, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)dblk_addr)
+
+ /* Check if this is a paged data block */
+ if(dblk_nelmts > hdr->dblk_page_nelmts) {
+ size_t npages = dblk_nelmts / hdr->dblk_page_nelmts; /* Number of pages in data block */
+ haddr_t dblk_page_addr; /* Address of each data block page */
+ size_t dblk_page_size; /* Size of each data block page */
+ size_t u; /* Local index variable */
+
+ /* Set up initial state */
+ dblk_page_addr = dblk_addr + H5EA_DBLOCK_PREFIX_SIZE(dblock);
+ dblk_page_size = (hdr->dblk_page_nelmts * hdr->cparam.raw_elmt_size)
+ + H5EA_SIZEOF_CHKSUM;
+
+ /* Iterate over pages in data block */
+ for(u = 0; u < npages; u++) {
+ /* Evict the data block page from the metadata cache */
+ /* (OK to call if it doesn't exist in the cache) */
+ if(H5AC_expunge_entry(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page_addr, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTEXPUNGE, "unable to remove array data block page from metadata cache")
+
+ /* Advance to next page address */
+ dblk_page_addr += dblk_page_size;
+ } /* end for */
+ } /* end if */
+
+CATCH
+ /* Finished deleting data block in metadata cache */
+ if(dblock && H5EA__dblock_unprotect(dblock, dxpl_id, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block")
+
+END_FUNC(PKG) /* end H5EA__dblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__dblock_dest
+ *
+ * Purpose: Destroys an extensible array data block in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__dblock_dest(H5EA_dblock_t *dblock))
+
+ /* Sanity check */
+ HDassert(dblock);
+ HDassert(!dblock->has_hdr_depend);
+
+ /* Check if shared header field has been initialized */
+ if(dblock->hdr) {
+ /* Check if we've got elements in the data block */
+ if(dblock->elmts && !dblock->npages) {
+ /* Free buffer for data block elements */
+ HDassert(dblock->nelmts > 0);
+ if(H5EA__hdr_free_elmts(dblock->hdr, dblock->nelmts, dblock->elmts) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to free extensible array data block element buffer")
+ dblock->elmts = NULL;
+ dblock->nelmts = 0;
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5EA__hdr_decr(dblock->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ dblock->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == dblock->top_proxy);
+
+ /* Free the data block itself */
+ dblock = H5FL_FREE(H5EA_dblock_t, dblock);
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__dblock_dest() */
+
diff --git a/src/H5EAhdr.c b/src/H5EAhdr.c
new file mode 100644
index 0000000..92d7c4d
--- /dev/null
+++ b/src/H5EAhdr.c
@@ -0,0 +1,826 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAhdr.c
+ * Aug 26 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Array header routines for extensible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#ifndef NDEBUG
+/* Max. # of bits for max. nelmts index */
+#define H5EA_MAX_NELMTS_IDX_MAX 64
+#endif /* NDEBUG */
+
+/* # of elements in a data block for a particular super block */
+#define H5EA_SBLK_DBLK_NELMTS(s, m) \
+ (size_t)H5_EXP2(((s) + 1) / 2) * (m)
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Alias for pointer to factory, for use when allocating sequences of them */
+typedef H5FL_fac_head_t *H5FL_fac_head_ptr_t;
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_hdr_t struct */
+H5FL_DEFINE_STATIC(H5EA_hdr_t);
+
+/* Declare a free list to manage the H5FL_fac_head_ptr_t sequence information */
+H5FL_SEQ_DEFINE_STATIC(H5FL_fac_head_ptr_t);
+
+/* Declare a free list to manage the H5EA_sblk_info_t sequence information */
+H5FL_SEQ_DEFINE_STATIC(H5EA_sblk_info_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_alloc
+ *
+ * Purpose: Allocate shared extensible array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_hdr_t *, NULL, NULL,
+H5EA__hdr_alloc(H5F_t *f))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Shared extensible array header */
+
+ /* Check arguments */
+ HDassert(f);
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5FL_CALLOC(H5EA_hdr_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array shared header")
+
+ /* Set non-zero internal fields */
+ hdr->addr = HADDR_UNDEF;
+
+ /* Set the internal parameters for the array */
+ hdr->f = f;
+ hdr->swmr_write = (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) > 0;
+ hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
+
+ /* Set the return value */
+ ret_value = hdr;
+
+CATCH
+ if(!ret_value)
+ if(hdr && H5EA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header")
+
+END_FUNC(PKG) /* end H5EA__hdr_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_init
+ *
+ * Purpose: Compute useful information for extensible array, based on
+ * "creation" information.
+ *
+ * Notes: The equations for variables below are based on this information:
+ *
+ * <sblk idx> <# of dblks> <size of dblks> Range of elements in sblk
+ * ========== ============ =============== =========================
+ * 0 1 1 * <dblk min elmts> 0 * <dblk min elmts> <-> 1 * <dblk min elmts> - 1
+ * 1 1 2 * <dblk min elmts> 1 * <dblk min elmts> <-> 3 * <dblk min elmts> - 1
+ * 2 2 2 * <dblk min elmts> 3 * <dblk min elmts> <-> 7 * <dblk min elmts> - 1
+ * 3 2 4 * <dblk min elmts> 7 * <dblk min elmts> <-> 15 * <dblk min elmts> - 1
+ * 4 4 4 * <dblk min elmts> 15 * <dblk min elmts> <-> 31 * <dblk min elmts> - 1
+ * 5 4 8 * <dblk min elmts> 31 * <dblk min elmts> <-> 63 * <dblk min elmts> - 1
+ * 6 8 8 * <dblk min elmts> 63 * <dblk min elmts> <-> 127 * <dblk min elmts> - 1
+ * 7 8 16 * <dblk min elmts> 127 * <dblk min elmts> <-> 255 * <dblk min elmts> - 1
+ * . . . * <dblk min elmts> . * <dblk min elmts> <-> . * <dblk min elmts> - 1
+ * . . . * <dblk min elmts> . * <dblk min elmts> <-> . * <dblk min elmts> - 1
+ * . . . * <dblk min elmts> . * <dblk min elmts> <-> . * <dblk min elmts> - 1
+ *
+ * Therefore:
+ * <sblk idx>(<elmt idx>) = lg2((<elmt idx> / <dblk min elmts>) + 1)
+ * <# of dblks>(<sblk idx>) = 2 ^ (<sblk idx> / 2)
+ * <size of dblk>(<sblk idx>) = 2 ^ ((<sblk idx> + 1) / 2)
+ * <total # of sblks>(<max. # of elmts>) = 1 + (lg2(<max. # of elmts>) - lg2(<dblk min_elmts>))
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 18 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_init(H5EA_hdr_t *hdr, void *ctx_udata))
+
+ /* Local variables */
+ hsize_t start_idx; /* First element index for each super block */
+ hsize_t start_dblk; /* First data block index for each super block */
+ size_t u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->cparam.max_nelmts_bits);
+ HDassert(hdr->cparam.data_blk_min_elmts);
+ HDassert(hdr->cparam.sup_blk_min_data_ptrs);
+
+ /* Compute general information */
+ hdr->nsblks = 1 + (hdr->cparam.max_nelmts_bits - H5VM_log2_of2(hdr->cparam.data_blk_min_elmts));
+ hdr->dblk_page_nelmts = (size_t)1 << hdr->cparam.max_dblk_page_nelmts_bits;
+ hdr->arr_off_size = (unsigned char)H5EA_SIZEOF_OFFSET_BITS(hdr->cparam.max_nelmts_bits);
+
+ /* Allocate information for each super block */
+ if(NULL == (hdr->sblk_info = H5FL_SEQ_MALLOC(H5EA_sblk_info_t, hdr->nsblks)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for super block info array")
+
+ /* Compute information about each super block */
+ start_idx = 0;
+ start_dblk = 0;
+ for(u = 0; u < hdr->nsblks; u++) {
+ hdr->sblk_info[u].ndblks = (size_t)H5_EXP2(u / 2);
+ hdr->sblk_info[u].dblk_nelmts = H5EA_SBLK_DBLK_NELMTS(u, hdr->cparam.data_blk_min_elmts);
+ hdr->sblk_info[u].start_idx = start_idx;
+ hdr->sblk_info[u].start_dblk = start_dblk;
+
+ /* Advance starting indices for next super block */
+ start_idx += (hsize_t)hdr->sblk_info[u].ndblks * (hsize_t)hdr->sblk_info[u].dblk_nelmts;
+ start_dblk += (hsize_t)hdr->sblk_info[u].ndblks;
+ } /* end for */
+
+ /* Set size of header on disk (locally and in statistics) */
+ hdr->stats.computed.hdr_size = hdr->size = H5EA_HEADER_SIZE_HDR(hdr);
+
+ /* Create the callback context, if there's one */
+ if(hdr->cparam.cls->crt_context) {
+ if(NULL == (hdr->cb_ctx = (*hdr->cparam.cls->crt_context)(ctx_udata)))
+ H5E_THROW(H5E_CANTCREATE, "unable to create extensible array client callback context")
+ } /* end if */
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_alloc_elmts
+ *
+ * Purpose: Allocate extensible array data block elements
+ *
+ * Return: Non-NULL pointer to buffer for elements on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 16 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+void *, NULL, NULL,
+H5EA__hdr_alloc_elmts(H5EA_hdr_t *hdr, size_t nelmts))
+
+ /* Local variables */
+ void *elmts = NULL; /* Element buffer allocated */
+ unsigned idx; /* Index of element buffer factory in header */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(nelmts > 0);
+
+ /* Compute the index of the element buffer factory */
+ H5_CHECK_OVERFLOW(nelmts, /*From:*/size_t, /*To:*/uint32_t);
+ idx = H5VM_log2_of2((uint32_t)nelmts) - H5VM_log2_of2((uint32_t)hdr->cparam.data_blk_min_elmts);
+
+ /* Check for needing to increase size of array of factories */
+ if(idx >= hdr->elmt_fac.nalloc) {
+ H5FL_fac_head_t **new_fac; /* New array of element factories */
+ size_t new_nalloc = MAX3(1, (idx + 1), (2 * hdr->elmt_fac.nalloc)); /* New number of factories allocated */
+
+ /* Re-allocate array of element factories */
+ if(NULL == (new_fac = H5FL_SEQ_REALLOC(H5FL_fac_head_ptr_t, hdr->elmt_fac.fac, new_nalloc)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block data element buffer factory array")
+
+ /* Zero out new elements allocated */
+ HDmemset(new_fac + hdr->elmt_fac.nalloc, 0, (new_nalloc - hdr->elmt_fac.nalloc) * sizeof(H5FL_fac_head_ptr_t));
+
+ /* Update information about element factories in header */
+ hdr->elmt_fac.nalloc = new_nalloc;
+ hdr->elmt_fac.fac = new_fac;
+ } /* end if */
+
+ /* Check for un-initialized factory at index */
+ if(NULL == hdr->elmt_fac.fac[idx]) {
+ if(NULL == (hdr->elmt_fac.fac[idx] = H5FL_fac_init(nelmts * (size_t)hdr->cparam.cls->nat_elmt_size)))
+ H5E_THROW(H5E_CANTINIT, "can't create data block data element buffer factory")
+ } /* end if */
+
+ /* Allocate buffer for elements in index block */
+ if(NULL == (elmts = H5FL_FAC_MALLOC(hdr->elmt_fac.fac[idx])))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block data element buffer")
+
+ /* Set the return value */
+ ret_value = elmts;
+
+CATCH
+ if(!ret_value)
+ if(elmts)
+ elmts = H5FL_FAC_FREE(hdr->elmt_fac.fac[idx], elmts);
+
+END_FUNC(PKG) /* end H5EA__hdr_alloc_elmts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_free_elmts
+ *
+ * Purpose: Free extensible array data block elements
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 18 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+herr_t, SUCCEED, -,
+H5EA__hdr_free_elmts(H5EA_hdr_t *hdr, size_t nelmts, void *elmts))
+
+ /* Local variables */
+ unsigned idx; /* Index of element buffer factory in header */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(nelmts > 0);
+ HDassert(elmts);
+
+ /* Compute the index of the element buffer factory */
+ H5_CHECK_OVERFLOW(nelmts, /*From:*/size_t, /*To:*/uint32_t);
+ idx = H5VM_log2_of2((uint32_t)nelmts) - H5VM_log2_of2((uint32_t)hdr->cparam.data_blk_min_elmts);
+
+ /* Free buffer for elements in index block */
+ HDassert(idx < hdr->elmt_fac.nalloc);
+ HDassert(hdr->elmt_fac.fac[idx]);
+ elmts = H5FL_FAC_FREE(hdr->elmt_fac.fac[idx], elmts);
+
+END_FUNC(PKG) /* end H5EA__hdr_free_elmts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_create
+ *
+ * Purpose: Creates a new extensible array header in the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 17 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5EA__hdr_create(H5F_t *f, hid_t dxpl_id, const H5EA_create_t *cparam,
+ void *ctx_udata))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr = NULL; /* Extensible array header */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(cparam);
+
+#ifndef NDEBUG
+{
+ unsigned sblk_idx; /* Super block index for first "actual" super block */
+ size_t dblk_nelmts; /* Number of data block elements */
+ size_t dblk_page_nelmts; /* Number of elements in a data block page */
+
+ /* Check for valid parameters */
+ if(cparam->raw_elmt_size == 0)
+ H5E_THROW(H5E_BADVALUE, "element size must be greater than zero")
+ if(cparam->max_nelmts_bits == 0)
+ H5E_THROW(H5E_BADVALUE, "max. # of elements bits must be greater than zero")
+ if(cparam->max_nelmts_bits > H5EA_MAX_NELMTS_IDX_MAX)
+ H5E_THROW(H5E_BADVALUE, "max. # of elements bits must be <= %u", (unsigned)H5EA_MAX_NELMTS_IDX_MAX)
+ if(cparam->sup_blk_min_data_ptrs < 2)
+ H5E_THROW(H5E_BADVALUE, "min # of data block pointers in super block must be >= two")
+ if(!POWER_OF_TWO(cparam->sup_blk_min_data_ptrs))
+ H5E_THROW(H5E_BADVALUE, "min # of data block pointers in super block must be power of two")
+ if(!POWER_OF_TWO(cparam->data_blk_min_elmts))
+ H5E_THROW(H5E_BADVALUE, "min # of elements per data block must be power of two")
+ dblk_page_nelmts = (size_t)1 << cparam->max_dblk_page_nelmts_bits;
+ if(dblk_page_nelmts < cparam->idx_blk_elmts)
+ H5E_THROW(H5E_BADVALUE, "# of elements per data block page must be greater than # of elements in index block")
+
+ /* Compute the number of elements in data blocks for first actual super block */
+ sblk_idx = H5EA_SBLK_FIRST_IDX(cparam->sup_blk_min_data_ptrs);
+ dblk_nelmts = H5EA_SBLK_DBLK_NELMTS(sblk_idx, cparam->data_blk_min_elmts);
+ if(dblk_page_nelmts < dblk_nelmts)
+ H5E_THROW(H5E_BADVALUE, "max. # of elements per data block page bits must be > # of elements in first data block from super block")
+
+ if(cparam->max_dblk_page_nelmts_bits > cparam->max_nelmts_bits)
+ H5E_THROW(H5E_BADVALUE, "max. # of elements per data block page bits must be <= max. # of elements bits")
+}
+#endif /* NDEBUG */
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5EA__hdr_alloc(f)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array shared header")
+
+ /* Set the internal parameters for the array */
+ hdr->idx_blk_addr = HADDR_UNDEF;
+
+ /* Set the creation parameters for the array */
+ HDmemcpy(&hdr->cparam, cparam, sizeof(hdr->cparam));
+
+ /* Finish initializing extensible array header */
+ if(H5EA__hdr_init(hdr, ctx_udata) < 0)
+ H5E_THROW(H5E_CANTINIT, "initialization failed for extensible array header")
+
+ /* Allocate space for the header on disk */
+ if(HADDR_UNDEF == (hdr->addr = H5MF_alloc(f, H5FD_MEM_EARRAY_HDR, dxpl_id, (hsize_t)hdr->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array header")
+
+ /* Create 'top' proxy for extensible array entries */
+ if(hdr->swmr_write)
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ H5E_THROW(H5E_CANTCREATE, "can't create extensible array entry proxy")
+
+ /* Cache the new extensible array header */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_EARRAY_HDR, hdr->addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add extensible array header to cache")
+ inserted = TRUE;
+
+ /* Add header as child of 'top' proxy */
+ if(hdr->top_proxy)
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+
+ /* Set address of array header to return */
+ ret_value = hdr->addr;
+
+CATCH
+ if(!H5F_addr_defined(ret_value))
+ if(hdr) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array header from cache")
+
+ /* Release header's disk space */
+ if(H5F_addr_defined(hdr->addr) && H5MF_xfree(f, H5FD_MEM_EARRAY_HDR, dxpl_id, hdr->addr, (hsize_t)hdr->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to free extensible array header")
+
+ /* Destroy header */
+ if(H5EA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__hdr_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_incr
+ *
+ * Purpose: Increment component reference count on shared array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_incr(H5EA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Mark header as un-evictable when something is depending on it */
+ if(hdr->rc == 0)
+ if(H5AC_pin_protected_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTPIN, "unable to pin extensible array header")
+
+ /* Increment reference count on shared header */
+ hdr->rc++;
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_decr
+ *
+ * Purpose: Decrement component reference count on shared array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_decr(H5EA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->rc);
+
+ /* Decrement reference count on shared header */
+ hdr->rc--;
+
+ /* Mark header as evictable again when nothing depend on it */
+ if(hdr->rc == 0) {
+ HDassert(hdr->file_rc == 0);
+ if(H5AC_unpin_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTUNPIN, "unable to unpin extensible array header")
+ } /* end if */
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_fuse_incr
+ *
+ * Purpose: Increment file reference count on shared array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+herr_t, SUCCEED, -,
+H5EA__hdr_fuse_incr(H5EA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Increment file reference count on shared header */
+ hdr->file_rc++;
+
+END_FUNC(PKG) /* end H5EA__hdr_fuse_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_fuse_decr
+ *
+ * Purpose: Decrement file reference count on shared array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+size_t, 0, -,
+H5EA__hdr_fuse_decr(H5EA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->file_rc);
+
+ /* Decrement file reference count on shared header */
+ hdr->file_rc--;
+
+ /* Set return value */
+ ret_value = hdr->file_rc;
+
+END_FUNC(PKG) /* end H5EA__hdr_fuse_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_modified
+ *
+ * Purpose: Mark an extensible array as modified
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_modified(H5EA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->f);
+
+ /* Mark header as dirty in cache */
+ if(H5AC_mark_entry_dirty(hdr) < 0)
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark extensible array header as dirty")
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_modified() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_protect
+ *
+ * Purpose: Convenience wrapper around protecting extensible array header
+ *
+ * Return: Non-NULL pointer to header on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 31 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_hdr_t *, NULL, NULL,
+H5EA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata,
+ unsigned flags))
+
+ /* Local variables */
+ H5EA_hdr_t *hdr; /* Extensible array header */
+ H5EA_hdr_cache_ud_t udata; /* User data for cache callbacks */
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(ea_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data for cache callbacks */
+ udata.f = f;
+ udata.addr = ea_addr;
+ udata.ctx_udata = ctx_udata;
+
+ /* Protect the header */
+ if(NULL == (hdr = (H5EA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_EARRAY_HDR, ea_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr)
+ hdr->f = f; /* (Must be set again here, in case the header was already in the cache -QAK) */
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->swmr_write && NULL == hdr->top_proxy) {
+ /* Create 'top' proxy for extensible array entries */
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ H5E_THROW(H5E_CANTCREATE, "can't create extensible array entry proxy")
+
+ /* Add header as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = hdr;
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting extensible array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 1 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_unprotect(H5EA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Unprotect the header */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_EARRAY_HDR, hdr->addr, hdr, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array hdr, address = %llu", (unsigned long long)hdr->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_delete
+ *
+ * Purpose: Delete an extensible array, starting with the header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 26 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_delete(H5EA_hdr_t *hdr, hid_t dxpl_id))
+
+ /* Local variables */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting header */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(!hdr->file_rc);
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Array header's status in the metadata cache */
+
+ /* Check the array header's status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, hdr->addr, &hdr_status) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to check metadata cache status for array header")
+
+ /* Sanity checks on array header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PROTECTED);
+} /* end block */
+#endif /* NDEBUG */
+
+ /* Check for index block */
+ if(H5F_addr_defined(hdr->idx_blk_addr)) {
+ /* Delete index block */
+ if(H5EA__iblock_delete(hdr, dxpl_id) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array index block")
+ } /* end if */
+
+ /* Set flags to finish deleting header on unprotect */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+CATCH
+
+ /* Unprotect the header, deleting it if an error hasn't occurred */
+ if(H5EA__hdr_unprotect(hdr, dxpl_id, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header")
+
+END_FUNC(PKG) /* end H5EA__hdr_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__hdr_dest
+ *
+ * Purpose: Destroys an extensible array header in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__hdr_dest(H5EA_hdr_t *hdr))
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(hdr->rc == 0);
+
+ /* Destroy the callback context */
+ if(hdr->cb_ctx) {
+ if((*hdr->cparam.cls->dst_context)(hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to destroy extensible array client callback context")
+ } /* end if */
+ hdr->cb_ctx = NULL;
+
+ /* Check for data block element buffer factory info to free */
+ if(hdr->elmt_fac.fac) {
+ unsigned u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(hdr->elmt_fac.nalloc > 0);
+
+ /* Iterate over factories, shutting them down */
+ for(u = 0; u < hdr->elmt_fac.nalloc; u++) {
+ /* Check if this factory has been initialized */
+ if(hdr->elmt_fac.fac[u]) {
+ if(H5FL_fac_term(hdr->elmt_fac.fac[u]) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to destroy extensible array header factory")
+ hdr->elmt_fac.fac[u] = NULL;
+ } /* end if */
+ } /* end for */
+
+ /* Free factory array */
+ hdr->elmt_fac.fac = (H5FL_fac_head_t **)H5FL_SEQ_FREE(H5FL_fac_head_ptr_t, hdr->elmt_fac.fac);
+ } /* end if */
+
+ /* Free the super block info array */
+ if(hdr->sblk_info)
+ hdr->sblk_info = (H5EA_sblk_info_t *)H5FL_SEQ_FREE(H5EA_sblk_info_t, hdr->sblk_info);
+
+ /* Destroy the 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_dest(hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to destroy extensible array 'top' proxy")
+ hdr->top_proxy = NULL;
+ } /* end if */
+
+ /* Free the shared info itself */
+ hdr = H5FL_FREE(H5EA_hdr_t, hdr);
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_dest() */
+
diff --git a/src/H5EAiblock.c b/src/H5EAiblock.c
new file mode 100644
index 0000000..e25e3ef
--- /dev/null
+++ b/src/H5EAiblock.c
@@ -0,0 +1,514 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAiblock.c
+ * Sep 9 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Index block routines for extensible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_iblock_t struct */
+H5FL_DEFINE_STATIC(H5EA_iblock_t);
+
+/* Declare a free list to manage the index block elements */
+H5FL_BLK_DEFINE_STATIC(idx_blk_elmt_buf);
+
+/* Declare a free list to manage the haddr_t sequence information */
+H5FL_SEQ_DEFINE_STATIC(haddr_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_alloc
+ *
+ * Purpose: Allocate extensible array index block
+ *
+ * Return: Non-NULL pointer to index block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_iblock_t *, NULL, NULL,
+H5EA__iblock_alloc(H5EA_hdr_t *hdr))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = NULL; /* Extensible array index block */
+
+ /* Check arguments */
+ HDassert(hdr);
+
+ /* Allocate memory for the index block */
+ if(NULL == (iblock = H5FL_CALLOC(H5EA_iblock_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block")
+
+ /* Share common array information */
+ if(H5EA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ iblock->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ iblock->addr = HADDR_UNDEF;
+
+ /* Compute information */
+ iblock->nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs);
+ iblock->ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1);
+ iblock->nsblk_addrs = hdr->nsblks - iblock->nsblks;
+#ifdef QAK
+HDfprintf(stderr, "%s: iblock->nsblks = %u\n", FUNC, iblock->nsblks);
+HDfprintf(stderr, "%s: iblock->ndblk_addrs = %Zu\n", FUNC, iblock->ndblk_addrs);
+HDfprintf(stderr, "%s: iblock->nsblk_addrs = %Zu\n", FUNC, iblock->nsblk_addrs);
+#endif /* QAK */
+
+ /* Allocate buffer for elements in index block */
+ if(hdr->cparam.idx_blk_elmts > 0)
+ if(NULL == (iblock->elmts = H5FL_BLK_MALLOC(idx_blk_elmt_buf, (size_t)(hdr->cparam.idx_blk_elmts * hdr->cparam.cls->nat_elmt_size))))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data element buffer")
+
+ /* Allocate buffer for data block addresses in index block */
+ if(iblock->ndblk_addrs > 0)
+ if(NULL == (iblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->ndblk_addrs)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data block addresses")
+
+ /* Allocate buffer for super block addresses in index block */
+ if(iblock->nsblk_addrs > 0)
+ if(NULL == (iblock->sblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->nsblk_addrs)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block super block addresses")
+
+ /* Set the return value */
+ ret_value = iblock;
+
+CATCH
+ if(!ret_value)
+ if(iblock && H5EA__iblock_dest(iblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block")
+
+END_FUNC(PKG) /* end H5EA__iblock_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_create
+ *
+ * Purpose: Creates a new extensible array index block in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5EA__iblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, hbool_t *stats_changed))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = NULL; /* Extensible array index block */
+ haddr_t iblock_addr; /* Extensible array index block address */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(stats_changed);
+
+ /* Allocate the index block */
+ if(NULL == (iblock = H5EA__iblock_alloc(hdr)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block")
+
+ /* Set size of index block on disk */
+ iblock->size = H5EA_IBLOCK_SIZE(iblock);
+#ifdef QAK
+HDfprintf(stderr, "%s: iblock->size = %Zu\n", FUNC, iblock->size);
+#endif /* QAK */
+
+ /* Allocate space for the index block on disk */
+ if(HADDR_UNDEF == (iblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_IBLOCK, dxpl_id, (hsize_t)iblock->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array index block")
+ iblock->addr = iblock_addr;
+
+ /* Clear any elements in index block to fill value */
+ if(hdr->cparam.idx_blk_elmts > 0) {
+ /* Call the class's 'fill' callback */
+ if((hdr->cparam.cls->fill)(iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set extensible array index block elements to class's fill value")
+ } /* end if */
+
+ /* Reset any data block addresses in the index block */
+ if(iblock->ndblk_addrs > 0) {
+ haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */
+
+ /* Set all the data block addresses to "undefined" address value */
+ H5VM_array_fill(iblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->ndblk_addrs);
+ } /* end if */
+
+ /* Reset any super block addresses in the index block */
+ if(iblock->nsblk_addrs > 0) {
+ haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill super block addresses with */
+
+ /* Set all the super block addresses to "undefined" address value */
+ H5VM_array_fill(iblock->sblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->nsblk_addrs);
+ } /* end if */
+
+ /* Cache the new extensible array index block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, iblock_addr, iblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add extensible array index block to cache")
+ inserted = TRUE;
+
+ /* Add index block as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, iblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ iblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Update extensible array index block statistics */
+ HDassert(0 == hdr->stats.computed.nindex_blks);
+ HDassert(0 == hdr->stats.computed.index_blk_size);
+ hdr->stats.computed.nindex_blks = 1;
+ hdr->stats.computed.index_blk_size = iblock->size;
+
+ /* Increment count of elements "realized" */
+ hdr->stats.stored.nelmts += hdr->cparam.idx_blk_elmts;
+
+ /* Mark the statistics as changed */
+ *stats_changed = TRUE;
+
+ /* Set address of index block to return */
+ ret_value = iblock_addr;
+
+CATCH
+ if(!H5F_addr_defined(ret_value))
+ if(iblock) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(iblock) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array index block from cache")
+
+ /* Release index block's disk space */
+ if(H5F_addr_defined(iblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to release file space for extensible array index block")
+
+ /* Destroy index block */
+ if(H5EA__iblock_dest(iblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__iblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_protect
+ *
+ * Purpose: Convenience wrapper around protecting extensible array index block
+ *
+ * Return: Non-NULL pointer to index block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_iblock_t *, NULL, NULL,
+H5EA__iblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, unsigned flags))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = NULL; /* Pointer to index block */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* only the H5AC__READ_ONLY_FLAG may be set */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Protect the index block */
+ if(NULL == (iblock = (H5EA_iblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == iblock->top_proxy) {
+ /* Add index block as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, iblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ iblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = iblock;
+
+CATCH
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the index block, if it was protected */
+ if(iblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr)
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__iblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting extensible array index block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__iblock_unprotect(H5EA_iblock_t *iblock, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* Unprotect the index block */
+ if(H5AC_unprotect(iblock->hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__iblock_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_delete
+ *
+ * Purpose: Delete index block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__iblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id))
+
+ /* Local variables */
+ H5EA_iblock_t *iblock = NULL; /* Pointer to index block */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(hdr->idx_blk_addr));
+
+ /* Protect index block */
+ if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
+
+ /* Check for index block having data block pointers */
+ if(iblock->ndblk_addrs > 0) {
+ unsigned sblk_idx; /* Current super block index */
+ unsigned dblk_idx; /* Current data block index w/in super block */
+ size_t u; /* Local index variable */
+
+ /* Iterate over data blocks */
+ sblk_idx = dblk_idx = 0;
+ for(u = 0; u < iblock->ndblk_addrs; u++) {
+ /* Check for data block existing */
+ if(H5F_addr_defined(iblock->dblk_addrs[u])) {
+ /* Delete data block */
+ if(H5EA__dblock_delete(hdr, dxpl_id, iblock, iblock->dblk_addrs[u], hdr->sblk_info[sblk_idx].dblk_nelmts) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array data block")
+ iblock->dblk_addrs[u] = HADDR_UNDEF;
+ } /* end if */
+
+ /* Advance to next data block w/in super block */
+ dblk_idx++;
+
+ /* Check for moving to next super block */
+ if(dblk_idx >= hdr->sblk_info[sblk_idx].ndblks) {
+ sblk_idx++;
+ dblk_idx = 0;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Check for index block having data block pointers (not yet) */
+ if(iblock->nsblk_addrs > 0) {
+ size_t u; /* Local index variable */
+
+ /* Iterate over super blocks */
+ for(u = 0; u < iblock->nsblk_addrs; u++) {
+ /* Check for data block existing */
+ if(H5F_addr_defined(iblock->sblk_addrs[u])) {
+ /* Delete super block */
+ if(H5EA__sblock_delete(hdr, dxpl_id, iblock, iblock->sblk_addrs[u], (unsigned)(u + iblock->nsblks)) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array super block")
+ iblock->sblk_addrs[u] = HADDR_UNDEF;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+CATCH
+ /* Finished deleting index block in metadata cache */
+ if(iblock && H5EA__iblock_unprotect(iblock, dxpl_id, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block")
+
+END_FUNC(PKG) /* end H5EA__iblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__iblock_dest
+ *
+ * Purpose: Destroys an extensible array index block in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__iblock_dest(H5EA_iblock_t *iblock))
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* Check if shared header field has been initialized */
+ if(iblock->hdr) {
+ /* Check if we've got elements in the index block */
+ if(iblock->elmts) {
+ /* Free buffer for index block elements */
+ HDassert(iblock->hdr->cparam.idx_blk_elmts > 0);
+ iblock->elmts = H5FL_BLK_FREE(idx_blk_elmt_buf, iblock->elmts);
+ } /* end if */
+
+ /* Check if we've got data block addresses in the index block */
+ if(iblock->dblk_addrs) {
+ /* Free buffer for index block data block addresses */
+ HDassert(iblock->ndblk_addrs > 0);
+ iblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->dblk_addrs);
+ iblock->ndblk_addrs = 0;
+ } /* end if */
+
+ /* Check if we've got super block addresses in the index block */
+ if(iblock->sblk_addrs) {
+ /* Free buffer for index block super block addresses */
+ HDassert(iblock->nsblk_addrs > 0);
+ iblock->sblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->sblk_addrs);
+ iblock->nsblk_addrs = 0;
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5EA__hdr_decr(iblock->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ iblock->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == iblock->top_proxy);
+
+ /* Free the index block itself */
+ iblock = H5FL_FREE(H5EA_iblock_t, iblock);
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__iblock_dest() */
+
diff --git a/src/H5EAint.c b/src/H5EAint.c
new file mode 100644
index 0000000..2baf1f4
--- /dev/null
+++ b/src/H5EAint.c
@@ -0,0 +1,139 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAint.c
+ * Jun 17 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal routines for extnsible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__create_flush_depend
+ *
+ * Purpose: Create a flush dependency between two data structure components
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 26 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__create_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry))
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Create a flush dependency between parent and child entry */
+ if(H5AC_create_flush_dependency(parent_entry, child_entry) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency")
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__create_flush_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__destroy_flush_depend
+ *
+ * Purpose: Destroy a flush dependency between two data structure components
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 26 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__destroy_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry))
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Destroy a flush dependency between parent and child entry */
+ if(H5AC_destroy_flush_dependency(parent_entry, child_entry) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency")
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__destroy_flush_depend() */
+
diff --git a/src/H5EAmodule.h b/src/H5EAmodule.h
new file mode 100644
index 0000000..d3e06b7
--- /dev/null
+++ b/src/H5EAmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5EA package. Including this header means that the source file
+ * is part of the H5EA package.
+ */
+#ifndef _H5EAmodule_H
+#define _H5EAmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5EA_MODULE
+#define H5_MY_PKG H5EA
+#define H5_MY_PKG_ERR H5E_EARRAY
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5EAmodule_H */
+
diff --git a/src/H5EApkg.h b/src/H5EApkg.h
new file mode 100644
index 0000000..e162fab
--- /dev/null
+++ b/src/H5EApkg.h
@@ -0,0 +1,483 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, June 17, 2008
+ *
+ * Purpose: This file contains declarations which are visible only
+ * within the H5EA package. Source files outside the H5EA
+ * package should include H5EAprivate.h instead.
+ */
+#if !(defined(H5EA_FRIEND) | defined(H5EA_MODULE))
+#error "Do not include this file outside the H5EA package!"
+#endif
+
+#ifndef _H5EApkg_H
+#define _H5EApkg_H
+
+/* Get package's private header */
+#include "H5EAprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Fill value for extensible array test class */
+#ifdef H5EA_TESTING
+#define H5EA_TEST_FILL ((uint64_t)ULLONG_MAX)
+#endif /* H5EA_TESTING */
+
+/* Size of checksum information (on disk) */
+#define H5EA_SIZEOF_CHKSUM 4
+
+/* "Standard" size of prefix information for extensible array metadata */
+#define H5EA_METADATA_PREFIX_SIZE(c) ( \
+ H5_SIZEOF_MAGIC /* Signature */ \
+ + 1 /* Version */ \
+ + 1 /* Array type */ \
+ + ((c) ? H5EA_SIZEOF_CHKSUM : 0) /* Metadata checksum */ \
+ )
+
+/* Size of the extensible array header on disk */
+#define H5EA_HEADER_SIZE(sizeof_addr, sizeof_size) ( \
+ /* General metadata fields */ \
+ H5EA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* General array information */ \
+ + 1 /* Element Size */ \
+ + 1 /* Max. # of elements bits */ \
+ + 1 /* # of elements to store in index block */ \
+ + 1 /* Min. # elements per data block */ \
+ + 1 /* Min. # of data block pointers for a super block */ \
+ + 1 /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ \
+ \
+ /* Extensible Array statistics fields */ \
+ + (sizeof_size) /* Number of super blocks created */ \
+ + (sizeof_size) /* Size of super blocks created */ \
+ + (sizeof_size) /* Number of data blocks created */ \
+ + (sizeof_size) /* Size of data blocks created */ \
+ + (sizeof_size) /* Max. index set */ \
+ + (sizeof_size) /* Number of elements 'realized' */ \
+ \
+ /* Extensible Array Header specific fields */ \
+ + (sizeof_addr) /* File address of index block */ \
+ )
+
+/* Size of the extensible array header on disk (via file pointer) */
+#define H5EA_HEADER_SIZE_FILE(f) ( \
+ H5EA_HEADER_SIZE(H5F_SIZEOF_ADDR(f), H5F_SIZEOF_SIZE(f)) \
+ )
+
+/* Size of the extensible array header on disk (via extensible array header) */
+#define H5EA_HEADER_SIZE_HDR(h) ( \
+ H5EA_HEADER_SIZE((h)->sizeof_addr, (h)->sizeof_size) \
+ )
+
+/* Size of the extensible array index block on disk */
+#define H5EA_IBLOCK_SIZE(i) ( \
+ /* General metadata fields */ \
+ H5EA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Sanity-checking fields */ \
+ + (i)->hdr->sizeof_addr /* File address of array owning the block */ \
+ \
+ /* Extensible Array Index Block specific fields */ \
+ + ((size_t)(i)->hdr->cparam.idx_blk_elmts * (size_t)(i)->hdr->cparam.raw_elmt_size) /* Elements in index block */ \
+ + ((i)->ndblk_addrs * (i)->hdr->sizeof_addr) /* Data block addresses in index block */ \
+ + ((i)->nsblk_addrs * (i)->hdr->sizeof_addr) /* Super block addresses in index block */ \
+ )
+
+/* Size of the extensible array super block on disk */
+#define H5EA_SBLOCK_SIZE(s) ( \
+ /* General metadata fields */ \
+ H5EA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Sanity-checking fields */ \
+ + (s)->hdr->sizeof_addr /* File address of array owning the block */ \
+ + (s)->hdr->arr_off_size /* Offset of the block in the array */ \
+ \
+ /* Extensible Array Super Block specific fields */ \
+ + ((s)->ndblks * (s)->dblk_page_init_size) /* Data block 'page init' bitmasks in super block (can be 0 if no pages) */ \
+ + ((s)->ndblks * (s)->hdr->sizeof_addr) /* Data block addresses in super block */ \
+ )
+
+/* Size of the extensible array data block prefix on disk */
+#define H5EA_DBLOCK_PREFIX_SIZE(d) ( \
+ /* General metadata fields */ \
+ H5EA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Sanity-checking fields */ \
+ + (d)->hdr->sizeof_addr /* File address of array owning the block */ \
+ + (d)->hdr->arr_off_size /* Offset of the block in the array */ \
+ )
+
+/* Size of the extensible array data block on disk */
+#define H5EA_DBLOCK_SIZE(d) ( \
+ /* Data block prefix size */ \
+ H5EA_DBLOCK_PREFIX_SIZE(d) \
+ \
+ /* Extensible Array Data Block specific fields */ \
+ + ((d)->nelmts * (size_t)(d)->hdr->cparam.raw_elmt_size) /* Elements in data block */ \
+ + ((d)->npages * H5EA_SIZEOF_CHKSUM) /* Checksum for each page */ \
+ )
+
+/* Size of the extensible array data block page on disk */
+#define H5EA_DBLK_PAGE_SIZE(h) ( \
+ + ((h)->dblk_page_nelmts * (size_t)(h)->cparam.raw_elmt_size) /* Elements in data block page */ \
+ + H5EA_SIZEOF_CHKSUM /* Checksum for each page */ \
+ )
+
+/* Compute the # of bytes required to store an offset into a given buffer size */
+#define H5EA_SIZEOF_OFFSET_BITS(b) (((b) + 7) / 8)
+
+/* Compute the first super block index that will hold a certain # of data block pointers */
+#define H5EA_SBLK_FIRST_IDX(m) (2 * H5VM_log2_of2((uint32_t)m))
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Information for each super block in extensible array */
+typedef struct H5EA_sblk_info_t {
+ size_t ndblks; /* Number of data blocks for a super block */
+ size_t dblk_nelmts; /* Number of elements in each data block for super block */
+ hsize_t start_idx; /* Index of first element in super block */
+ hsize_t start_dblk; /* Index of first data block in super block */
+} H5EA_sblk_info_t;
+
+/* The extensible array header information */
+/* (Each extensible array header has certain information that is shared across
+ * all the blocks in that extensible array)
+ */
+typedef struct H5EA_hdr_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Extensible array configuration/creation parameters (stored in header) */
+ H5EA_create_t cparam; /* Creation parameters for extensible array */
+
+ /* Index block information (stored in header) */
+ haddr_t idx_blk_addr; /* Address of index block in header */
+
+ /* Statistics for array (stored in index block, actually) */
+ /* (header and index number/size fields not stored) */
+ H5EA_stat_t stats; /* Statistics for extensible array */
+
+ /* Data block element buffer factory info (not stored in header) */
+ struct {
+ size_t nalloc; /* Number of factories allocated */
+ H5FL_fac_head_t **fac; /* Array of factories for data block element buffers */
+ } elmt_fac;
+
+ /* Computed/cached values (not stored in header) */
+ size_t rc; /* Reference count of heap's components using heap header */
+ haddr_t addr; /* Address of header in file */
+ size_t size; /* Size of header in file */
+ H5F_t *f; /* Pointer to file for extensible array */
+ size_t file_rc; /* Reference count of files using array header */
+ hbool_t pending_delete; /* Array is pending deletion */
+ size_t sizeof_addr; /* Size of file addresses */
+ size_t sizeof_size; /* Size of file sizes */
+ unsigned char arr_off_size; /* Size of array offsets (in bytes) */
+
+ /* Super block information (not stored) */
+ size_t nsblks; /* Number of superblocks needed for array */
+ H5EA_sblk_info_t *sblk_info; /* Array of information for each super block */
+
+ /* Data block information (not stored) */
+ size_t dblk_page_nelmts; /* # of elements per data block page */
+
+ /* Client information (not stored) */
+ void *cb_ctx; /* Callback context */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t swmr_write; /* Flag indicating the file is opened with SWMR-write access */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all array entries */
+ void *parent; /* Pointer to 'top' proxy flush dependency
+ * parent, if it exists, otherwise NULL.
+ * If the extensible array is being used
+ * to index a chunked dataset and the
+ * dataset metadata is modified by a
+ * SWMR writer, this field will be set
+ * equal to the object header proxy
+ * that is the flush dependency parent
+ * of the extensible array header.
+ *
+ * The field is used to avoid duplicate
+ * setups of the flush dependency
+ * relationship, and to allow the
+ * extensible array header to destroy
+ * the flush dependency on receipt of
+ * an eviction notification from the
+ * metadata cache.
+ */
+} H5EA_hdr_t;
+
+/* The extensible array index block information */
+typedef struct H5EA_iblock_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Extensible array information (stored) */
+ void *elmts; /* Buffer for elements stored in index block */
+ haddr_t *dblk_addrs; /* Buffer for addresses of data blocks in index block */
+ haddr_t *sblk_addrs; /* Buffer for addresses of super blocks in index block */
+
+ /* Internal array information (not stored) */
+ H5EA_hdr_t *hdr; /* Shared array header info */
+ haddr_t addr; /* Address of this index block on disk */
+ size_t size; /* Size of index block on disk */
+
+ /* SWMR / Flush dependency information (not stored) */
+ H5AC_proxy_entry_t *top_proxy; /* "Top" proxy cache entry for all array entries */
+
+ /* Computed/cached values (not stored) */
+ size_t nsblks; /* # of super blocks whose data block addresses are in index block */
+ size_t ndblk_addrs; /* Number of pointers to data blocks in index block */
+ size_t nsblk_addrs; /* Number of pointers to super blocks in index block */
+} H5EA_iblock_t;
+
+/* The extensible array super block information */
+typedef struct H5EA_sblock_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Extensible array information (stored) */
+ hsize_t block_off; /* Offset of the block within the array's address space */
+ haddr_t *dblk_addrs; /* Addresses of data blocks in super block */
+ uint8_t *page_init; /* Bitmap of whether a data block page is initialized */
+
+ /* Internal array information (not stored) */
+ H5EA_hdr_t *hdr; /* Shared array header info */
+ haddr_t addr; /* Address of this index block on disk */
+ size_t size; /* Size of index block on disk */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t has_hdr_depend; /* Whether this object has a flush dependency on the header */
+ H5AC_proxy_entry_t *top_proxy; /* "Top" proxy cache entry for all array entries */
+ H5EA_iblock_t *parent; /* Parent object for super block (index block) */
+
+ /* Computed/cached values (not stored) */
+ unsigned idx; /* Super block index within the extensible array */
+ size_t ndblks; /* # of data block addresses that are in super block */
+ size_t dblk_nelmts; /* # of elements for data blocks reachable through this super block */
+ size_t dblk_npages; /* # of pages in each data block */
+ size_t dblk_page_init_size; /* Size of 'page init' bitmask for each data block */
+ size_t dblk_page_size; /* Size of a data block page */
+} H5EA_sblock_t;
+
+/* The extensible array data block information */
+typedef struct H5EA_dblock_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Extensible array information (stored) */
+ hsize_t block_off; /* Offset of the block within the array's address space */
+ void *elmts; /* Buffer for elements stored in data block */
+
+ /* Internal array information (not stored) */
+ H5EA_hdr_t *hdr; /* Shared array header info */
+ haddr_t addr; /* Address of this data block on disk */
+ size_t size; /* Size of data block on disk */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t has_hdr_depend; /* Whether this object has a flush dependency on the header */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all array entries */
+ void *parent; /* Parent object for data block (index or super block) */
+
+ /* Computed/cached values (not stored) */
+ size_t nelmts; /* Number of elements in block */
+ size_t npages; /* Nummber of pages in a block (zero if not paged) */
+} H5EA_dblock_t;
+
+/* The extensible array data block page information */
+typedef struct H5EA_dbk_page_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Extensible array information (stored) */
+ void *elmts; /* Buffer for elements stored in data block page */
+
+ /* Internal array information (not stored) */
+ H5EA_hdr_t *hdr; /* Shared array header info */
+ haddr_t addr; /* Address of this data block page on disk */
+ size_t size; /* Size of data block page on disk */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t has_hdr_depend; /* Whether this object has a flush dependency on the header */
+ H5AC_proxy_entry_t *top_proxy; /* "Top" proxy cache entry for all array entries */
+ H5EA_sblock_t *parent; /* Parent object for data block page (super block) */
+
+ /* Computed/cached values (not stored) */
+ /* <none> */
+} H5EA_dblk_page_t;
+
+/* Extensible array */
+struct H5EA_t {
+ H5EA_hdr_t *hdr; /* Pointer to internal extensible array header info */
+ H5F_t *f; /* Pointer to file for extensible array */
+};
+
+/* Metadata cache callback user data types */
+
+/* Info needed for loading header */
+typedef struct H5EA_hdr_cache_ud_t {
+ H5F_t *f; /* Pointer to file for extensible array */
+ haddr_t addr; /* Address of header on disk */
+ void *ctx_udata; /* User context for class */
+} H5EA_hdr_cache_ud_t;
+
+/* Info needed for loading super block */
+typedef struct H5EA_sblock_cache_ud_t {
+ H5EA_hdr_t *hdr; /* Shared extensible array information */
+ H5EA_iblock_t *parent; /* Pointer to parent object for super block (index block) */
+ unsigned sblk_idx; /* Index of super block */
+ haddr_t sblk_addr; /* Address of super block */
+} H5EA_sblock_cache_ud_t;
+
+/* Info needed for loading data block */
+typedef struct H5EA_dblock_cache_ud_t {
+ H5EA_hdr_t *hdr; /* Shared extensible array information */
+ void *parent; /* Pointer to parent object for data block (index or super block) */
+ size_t nelmts; /* Number of elements in data block */
+ haddr_t dblk_addr; /* Address of data block */
+} H5EA_dblock_cache_ud_t;
+
+/* Info needed for loading data block page */
+typedef struct H5EA_dblk_page_cache_ud_t {
+ H5EA_hdr_t *hdr; /* Shared extensible array information */
+ H5EA_sblock_t *parent; /* Pointer to parent object for data block page (super block) */
+ haddr_t dblk_page_addr; /* Address of data block page */
+} H5EA_dblk_page_cache_ud_t;
+
+#ifdef H5EA_TESTING
+typedef struct H5EA__ctx_cb_t {
+ herr_t (*encode)(const void *elmt, size_t nelmts, void *udata); /* Perform action during encode step */
+ void *udata; /* User data for encode action */
+} H5EA__ctx_cb_t;
+#endif /* H5EA_TESTING */
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Internal extensible array testing class */
+H5_DLLVAR const H5EA_class_t H5EA_CLS_TEST[1];
+
+/* Array of extensible array client ID -> client class mappings */
+H5_DLLVAR const H5EA_class_t *const H5EA_client_class_g[H5EA_NUM_CLS_ID];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Generic routines */
+H5_DLL herr_t H5EA__create_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+H5_DLL herr_t H5EA__destroy_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+
+/* Header routines */
+H5_DLL H5EA_hdr_t *H5EA__hdr_alloc(H5F_t *f);
+H5_DLL herr_t H5EA__hdr_init(H5EA_hdr_t *hdr, void *ctx_udata);
+H5_DLL haddr_t H5EA__hdr_create(H5F_t *f, hid_t dxpl_id, const H5EA_create_t *cparam,
+ void *ctx_udata);
+H5_DLL void *H5EA__hdr_alloc_elmts(H5EA_hdr_t *hdr, size_t nelmts);
+H5_DLL herr_t H5EA__hdr_free_elmts(H5EA_hdr_t *hdr, size_t nelmts, void *elmts);
+H5_DLL herr_t H5EA__hdr_incr(H5EA_hdr_t *hdr);
+H5_DLL herr_t H5EA__hdr_decr(H5EA_hdr_t *hdr);
+H5_DLL herr_t H5EA__hdr_fuse_incr(H5EA_hdr_t *hdr);
+H5_DLL size_t H5EA__hdr_fuse_decr(H5EA_hdr_t *hdr);
+H5_DLL herr_t H5EA__hdr_modified(H5EA_hdr_t *hdr);
+H5_DLL H5EA_hdr_t *H5EA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr,
+ void *ctx_udata, unsigned flags);
+H5_DLL herr_t H5EA__hdr_unprotect(H5EA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags);
+H5_DLL herr_t H5EA__hdr_delete(H5EA_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5EA__hdr_dest(H5EA_hdr_t *hdr);
+
+/* Index block routines */
+H5_DLL H5EA_iblock_t *H5EA__iblock_alloc(H5EA_hdr_t *hdr);
+H5_DLL haddr_t H5EA__iblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t *stats_changed);
+H5_DLL H5EA_iblock_t *H5EA__iblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ unsigned flags);
+H5_DLL herr_t H5EA__iblock_unprotect(H5EA_iblock_t *iblock, hid_t dxpl_id,
+ unsigned cache_flags);
+H5_DLL herr_t H5EA__iblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5EA__iblock_dest(H5EA_iblock_t *iblock);
+
+/* Super block routines */
+H5_DLL H5EA_sblock_t *H5EA__sblock_alloc(H5EA_hdr_t *hdr, H5EA_iblock_t *parent,
+ unsigned sblk_idx);
+H5_DLL haddr_t H5EA__sblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ H5EA_iblock_t *parent, hbool_t *stats_changed, unsigned sblk_idx);
+H5_DLL H5EA_sblock_t *H5EA__sblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx,
+ unsigned flags);
+H5_DLL herr_t H5EA__sblock_unprotect(H5EA_sblock_t *sblock, hid_t dxpl_id,
+ unsigned cache_flags);
+H5_DLL herr_t H5EA__sblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx);
+H5_DLL herr_t H5EA__sblock_dest(H5EA_sblock_t *sblock);
+
+/* Data block routines */
+H5_DLL H5EA_dblock_t *H5EA__dblock_alloc(H5EA_hdr_t *hdr, void *parent,
+ size_t nelmts);
+H5_DLL haddr_t H5EA__dblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ hbool_t *stats_changed, hsize_t dblk_off, size_t nelmts);
+H5_DLL unsigned H5EA__dblock_sblk_idx(const H5EA_hdr_t *hdr, hsize_t idx);
+H5_DLL H5EA_dblock_t *H5EA__dblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ void *parent, haddr_t dblk_addr, size_t dblk_nelmts, unsigned flags);
+H5_DLL herr_t H5EA__dblock_unprotect(H5EA_dblock_t *dblock, hid_t dxpl_id,
+ unsigned cache_flags);
+H5_DLL herr_t H5EA__dblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent,
+ haddr_t dblk_addr, size_t dblk_nelmts);
+H5_DLL herr_t H5EA__dblock_dest(H5EA_dblock_t *dblock);
+
+/* Data block page routines */
+H5_DLL H5EA_dblk_page_t *H5EA__dblk_page_alloc(H5EA_hdr_t *hdr, H5EA_sblock_t *parent);
+H5_DLL herr_t H5EA__dblk_page_create(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ H5EA_sblock_t *parent, haddr_t addr);
+H5_DLL H5EA_dblk_page_t *H5EA__dblk_page_protect(H5EA_hdr_t *hdr, hid_t dxpl_id,
+ H5EA_sblock_t *parent, haddr_t dblk_page_addr, unsigned flags);
+H5_DLL herr_t H5EA__dblk_page_unprotect(H5EA_dblk_page_t *dblk_page,
+ hid_t dxpl_id, unsigned cache_flags);
+H5_DLL herr_t H5EA__dblk_page_dest(H5EA_dblk_page_t *dblk_page);
+
+/* Debugging routines for dumping file structures */
+H5_DLL herr_t H5EA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5EA_class_t *cls, haddr_t obj_addr);
+H5_DLL herr_t H5EA__iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5EA_class_t *cls,
+ haddr_t hdr_addr, haddr_t obj_addr);
+H5_DLL herr_t H5EA__sblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5EA_class_t *cls,
+ haddr_t hdr_addr, unsigned sblk_idx, haddr_t obj_addr);
+H5_DLL herr_t H5EA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5EA_class_t *cls,
+ haddr_t hdr_addr, size_t dblk_nelmts, haddr_t obj_addr);
+
+/* Testing routines */
+#ifdef H5EA_TESTING
+H5_DLL herr_t H5EA_get_cparam_test(const H5EA_t *ea, H5EA_create_t *cparam);
+H5_DLL int H5EA_cmp_cparam_test(const H5EA_create_t *cparam1, const H5EA_create_t *cparam2);
+#endif /* H5EA_TESTING */
+
+#endif /* _H5EApkg_H */
+
diff --git a/src/H5EAprivate.h b/src/H5EAprivate.h
new file mode 100644
index 0000000..cda1d46
--- /dev/null
+++ b/src/H5EAprivate.h
@@ -0,0 +1,157 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAprivate.h
+ * Jun 17 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Private header for library accessible extensible
+ * array routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5EAprivate_H
+#define _H5EAprivate_H
+
+/* Include package's public header */
+#ifdef NOT_YET
+#include "H5EApublic.h"
+#endif /* NOT_YET */
+
+/* Private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Fprivate.h" /* File access */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Extensible array class IDs */
+typedef enum H5EA_cls_id_t {
+ H5EA_CLS_CHUNK_ID = 0, /* Extensible array is for indexing dataset chunks w/o filters */
+ H5EA_CLS_FILT_CHUNK_ID, /* Extensible array is for indexing dataset chunks w/filters */
+
+ /* Start real class IDs at 0 -QAK */
+ /* (keep these last) */
+ H5EA_CLS_TEST_ID, /* Extensible array is for testing (do not use for actual data) */
+ H5EA_NUM_CLS_ID /* Number of Extensible Array class IDs (must be last) */
+} H5EA_cls_id_t;
+
+/*
+ * Each type of element that can be stored in an extesible array has a
+ * variable of this type that contains class variables and methods.
+ */
+typedef struct H5EA_class_t {
+ H5EA_cls_id_t id; /* ID of Extensible Array class, as found in file */
+ const char *name; /* Name of class (for debugging) */
+ size_t nat_elmt_size; /* Size of native (memory) element */
+
+ /* Extensible array client callback methods */
+ void *(*crt_context)(void *udata); /* Create context for other callbacks */
+ herr_t (*dst_context)(void *ctx); /* Destroy context */
+ herr_t (*fill)(void *nat_blk, size_t nelmts); /* Fill array of elements with encoded form of "missing element" value */
+ herr_t (*encode)(void *raw, const void *elmt, size_t nelmts, void *ctx); /* Encode elements from native form to disk storage form */
+ herr_t (*decode)(const void *raw, void *elmt, size_t nelmts, void *ctx); /* Decode elements from disk storage form to native form */
+ herr_t (*debug)(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt); /* Print an element for debugging */
+ void *(*crt_dbg_ctx)(H5F_t *f, hid_t dxpl_id, haddr_t obj_addr); /* Create debugging context */
+ herr_t (*dst_dbg_ctx)(void *dbg_ctx); /* Destroy debugging context */
+} H5EA_class_t;
+
+/* Extensible array creation parameters */
+typedef struct H5EA_create_t {
+ const H5EA_class_t *cls; /* Class of extensible array to create */
+ uint8_t raw_elmt_size; /* Element size in file (in bytes) */
+ uint8_t max_nelmts_bits; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */
+ uint8_t idx_blk_elmts; /* # of elements to store in index block */
+ uint8_t data_blk_min_elmts; /* Min. # of elements per data block */
+ uint8_t sup_blk_min_data_ptrs; /* Min. # of data block pointers for a super block */
+ uint8_t max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */
+} H5EA_create_t;
+
+/* Extensible array metadata statistics info */
+/* (If these are ever exposed to applications, don't let the application see
+ * which fields are computed vs. which fields are stored. -QAK)
+ */
+typedef struct H5EA_stat_t {
+ /* Non-stored (i.e. computed) fields */
+ struct {
+ hsize_t hdr_size; /* Size of header */
+ hsize_t nindex_blks; /* # of index blocks (should be 0 or 1) */
+ hsize_t index_blk_size; /* Size of index blocks allocated */
+ } computed;
+
+ /* Stored fields */
+ struct {
+ hsize_t nsuper_blks; /* # of super blocks */
+ hsize_t super_blk_size; /* Size of super blocks allocated */
+ hsize_t ndata_blks; /* # of data blocks */
+ hsize_t data_blk_size; /* Size of data blocks allocated */
+ hsize_t max_idx_set; /* Highest element index stored (+1 - i.e. if element 0 has been set, this value with be '1', if no elements have been stored, this value will be '0') */
+ hsize_t nelmts; /* # of elements "realized" */
+ } stored;
+} H5EA_stat_t;
+
+/* Extensible array info (forward decl - defined in H5EApkg.h) */
+typedef struct H5EA_t H5EA_t;
+
+/* Define the operator callback function pointer for H5EA_iterate() */
+typedef int (*H5EA_operator_t)(hsize_t idx, const void *_elmt, void *_udata);
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+/* The Extensible Array class for dataset chunks w/o filters*/
+H5_DLLVAR const H5EA_class_t H5EA_CLS_CHUNK[1];
+
+/* The Extensible Array class for dataset chunks w/ filters*/
+H5_DLLVAR const H5EA_class_t H5EA_CLS_FILT_CHUNK[1];
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General routines */
+H5_DLL H5EA_t *H5EA_create(H5F_t *f, hid_t dxpl_id, const H5EA_create_t *cparam,
+ void *ctx_udata);
+H5_DLL H5EA_t *H5EA_open(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata);
+H5_DLL herr_t H5EA_get_nelmts(const H5EA_t *ea, hsize_t *nelmts);
+H5_DLL herr_t H5EA_get_addr(const H5EA_t *ea, haddr_t *addr);
+H5_DLL herr_t H5EA_set(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, const void *elmt);
+H5_DLL herr_t H5EA_get(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, void *elmt);
+H5_DLL herr_t H5EA_depend(H5EA_t *ea, hid_t dxpl_id, H5AC_proxy_entry_t *parent);
+H5_DLL herr_t H5EA_iterate(H5EA_t *fa, hid_t dxpl_id, H5EA_operator_t op, void *udata);
+H5_DLL herr_t H5EA_close(H5EA_t *ea, hid_t dxpl_id);
+H5_DLL herr_t H5EA_delete(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata);
+H5_DLL herr_t H5EA_patch_file(H5EA_t *fa, H5F_t *f);
+
+/* Statistics routines */
+H5_DLL herr_t H5EA_get_stats(const H5EA_t *ea, H5EA_stat_t *stats);
+
+/* Debugging routines */
+#ifdef H5EA_DEBUGGING
+#endif /* H5EA_DEBUGGING */
+
+#endif /* _H5EAprivate_H */
+
diff --git a/src/H5EAsblock.c b/src/H5EAsblock.c
new file mode 100644
index 0000000..4e291c0
--- /dev/null
+++ b/src/H5EAsblock.c
@@ -0,0 +1,451 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAsblock.c
+ * Sep 30 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Super block routines for extensible arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA_iblock_t struct */
+H5FL_DEFINE_STATIC(H5EA_sblock_t);
+
+/* Declare a free list to manage the haddr_t sequence information */
+H5FL_SEQ_DEFINE_STATIC(haddr_t);
+
+/* Declare a free list to manage blocks of 'page init' bitmasks */
+H5FL_BLK_DEFINE(page_init);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_alloc
+ *
+ * Purpose: Allocate extensible array super block
+ *
+ * Return: Non-NULL pointer to super block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_sblock_t *, NULL, NULL,
+H5EA__sblock_alloc(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, unsigned sblk_idx))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = NULL; /* Extensible array super block */
+
+ /* Check arguments */
+ HDassert(hdr);
+
+ /* Allocate memory for the index block */
+ if(NULL == (sblock = H5FL_CALLOC(H5EA_sblock_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super block")
+
+ /* Share common array information */
+ if(H5EA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ sblock->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ sblock->parent = parent;
+ sblock->addr = HADDR_UNDEF;
+
+ /* Compute/cache information */
+ sblock->idx = sblk_idx;
+ sblock->ndblks = hdr->sblk_info[sblk_idx].ndblks;
+ HDassert(sblock->ndblks);
+ sblock->dblk_nelmts = hdr->sblk_info[sblk_idx].dblk_nelmts;
+
+ /* Allocate buffer for data block addresses in super block */
+ if(NULL == (sblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, sblock->ndblks)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for super block data block addresses")
+
+ /* Check if # of elements in data blocks requires paging */
+ if(sblock->dblk_nelmts > hdr->dblk_page_nelmts) {
+ /* Compute # of pages in each data block from this super block */
+ sblock->dblk_npages = sblock->dblk_nelmts / hdr->dblk_page_nelmts;
+
+ /* Sanity check that we have at least 2 pages in data block */
+ HDassert(sblock->dblk_npages > 1);
+
+ /* Sanity check for integer truncation */
+ HDassert((sblock->dblk_npages * hdr->dblk_page_nelmts) == sblock->dblk_nelmts);
+
+ /* Compute size of buffer for each data block's 'page init' bitmask */
+ sblock->dblk_page_init_size = ((sblock->dblk_npages) + 7) / 8;
+ HDassert(sblock->dblk_page_init_size > 0);
+
+ /* Allocate buffer for all 'page init' bitmasks in super block */
+ if(NULL == (sblock->page_init = H5FL_BLK_CALLOC(page_init, sblock->ndblks * sblock->dblk_page_init_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for super block page init bitmask")
+
+ /* Compute data block page size */
+ sblock->dblk_page_size = (hdr->dblk_page_nelmts * hdr->cparam.raw_elmt_size)
+ + H5EA_SIZEOF_CHKSUM;
+ } /* end if */
+
+ /* Set the return value */
+ ret_value = sblock;
+
+CATCH
+ if(!ret_value)
+ if(sblock && H5EA__sblock_dest(sblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block")
+
+END_FUNC(PKG) /* end H5EA__sblock_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_create
+ *
+ * Purpose: Creates a new extensible array super block in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5EA__sblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_iblock_t *parent,
+ hbool_t *stats_changed, unsigned sblk_idx))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = NULL; /* Extensible array super block */
+ haddr_t sblock_addr; /* Extensible array super block address */
+ haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(stats_changed);
+
+ /* Allocate the super block */
+ if(NULL == (sblock = H5EA__sblock_alloc(hdr, parent, sblk_idx)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super block")
+
+ /* Set size of super block on disk */
+ sblock->size = H5EA_SBLOCK_SIZE(sblock);
+
+ /* Set offset of block in array's address space */
+ sblock->block_off = hdr->sblk_info[sblk_idx].start_idx;
+
+ /* Allocate space for the super block on disk */
+ if(HADDR_UNDEF == (sblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_SBLOCK, dxpl_id, (hsize_t)sblock->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array super block")
+ sblock->addr = sblock_addr;
+
+ /* Reset data block addresses to "undefined" address value */
+ H5VM_array_fill(sblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), sblock->ndblks);
+
+ /* Cache the new extensible array super block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblock_addr, sblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add extensible array super block to cache")
+ inserted = TRUE;
+
+ /* Add super block as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, sblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ sblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Update extensible array super block statistics */
+ hdr->stats.stored.nsuper_blks++;
+ hdr->stats.stored.super_blk_size += sblock->size;
+
+ /* Mark the statistics as changed */
+ *stats_changed = TRUE;
+
+ /* Set address of super block to return */
+ ret_value = sblock_addr;
+
+CATCH
+ if(!H5F_addr_defined(ret_value))
+ if(sblock) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(sblock) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array super block from cache")
+
+ /* Release super block's disk space */
+ if(H5F_addr_defined(sblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_SBLOCK, dxpl_id, sblock->addr, (hsize_t)sblock->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to release extensible array super block")
+
+ /* Destroy super block */
+ if(H5EA__sblock_dest(sblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__sblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_protect
+ *
+ * Purpose: Convenience wrapper around protecting extensible array super block
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5EA_sblock_t *, NULL, NULL,
+H5EA__sblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_iblock_t *parent,
+ haddr_t sblk_addr, unsigned sblk_idx, unsigned flags))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = NULL; /* Pointer to super block */
+ H5EA_sblock_cache_ud_t udata; /* Information needed for loading super block */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(sblk_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG may be set */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data */
+ udata.hdr = hdr;
+ udata.parent = parent;
+ udata.sblk_idx = sblk_idx;
+ udata.sblk_addr = sblk_addr;
+
+ /* Protect the super block */
+ if(NULL == (sblock = (H5EA_sblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblk_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == sblock->top_proxy) {
+ /* Add super block as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, sblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
+ sblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = sblock;
+
+CATCH
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the super block, if it was protected */
+ if(sblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array super block, address = %llu", (unsigned long long)sblock->addr)
+ } /* end if */
+
+END_FUNC(PKG) /* end H5EA__sblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting extensible array super block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__sblock_unprotect(H5EA_sblock_t *sblock, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(sblock);
+
+ /* Unprotect the super block */
+ if(H5AC_unprotect(sblock->hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array super block, address = %llu", (unsigned long long)sblock->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__sblock_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_delete
+ *
+ * Purpose: Delete a super block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__sblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_iblock_t *parent,
+ haddr_t sblk_addr, unsigned sblk_idx))
+
+ /* Local variables */
+ H5EA_sblock_t *sblock = NULL; /* Pointer to super block */
+ size_t u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(sblk_addr));
+
+ /* Protect super block */
+ if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, parent, sblk_addr, sblk_idx, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr)
+
+ /* Iterate over data blocks */
+ for(u = 0; u < sblock->ndblks; u++) {
+ /* Check for data block existing */
+ if(H5F_addr_defined(sblock->dblk_addrs[u])) {
+ /* Delete data block */
+ if(H5EA__dblock_delete(hdr, dxpl_id, sblock, sblock->dblk_addrs[u], sblock->dblk_nelmts) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array data block")
+ sblock->dblk_addrs[u] = HADDR_UNDEF;
+ } /* end if */
+ } /* end for */
+
+CATCH
+ /* Finished deleting super block in metadata cache */
+ if(sblock && H5EA__sblock_unprotect(sblock, dxpl_id, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array super block")
+
+END_FUNC(PKG) /* end H5EA__sblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__sblock_dest
+ *
+ * Purpose: Destroys an extensible array super block in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 30 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__sblock_dest(H5EA_sblock_t *sblock))
+
+ /* Sanity check */
+ HDassert(sblock);
+ HDassert(!sblock->has_hdr_depend);
+
+ /* Check if shared header field has been initialized */
+ if(sblock->hdr) {
+ /* Free buffer for super block data block addresses, if there are any */
+ if(sblock->dblk_addrs)
+ sblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, sblock->dblk_addrs);
+
+ /* Free buffer for super block 'page init' bitmask, if there is one */
+ if(sblock->page_init) {
+ HDassert(sblock->dblk_npages > 0);
+ sblock->page_init = H5FL_BLK_FREE(page_init, sblock->page_init);
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5EA__hdr_decr(sblock->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ sblock->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == sblock->top_proxy);
+
+ /* Free the super block itself */
+ sblock = H5FL_FREE(H5EA_sblock_t, sblock);
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__sblock_dest() */
+
diff --git a/src/H5EAstat.c b/src/H5EAstat.c
new file mode 100644
index 0000000..72c4d14
--- /dev/null
+++ b/src/H5EAstat.c
@@ -0,0 +1,114 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5EAstat.c
+ * Sep 11 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Extensible array metadata statistics functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_get_stats
+ *
+ * Purpose: Query the metadata stats of an array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 21 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5EA_get_stats(const H5EA_t *ea, H5EA_stat_t *stats))
+
+ /* Local variables */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(ea);
+ HDassert(stats);
+
+ /* Copy extensible array statistics */
+ HDmemcpy(stats, &ea->hdr->stats, sizeof(ea->hdr->stats));
+
+END_FUNC(PRIV) /* end H5EA_get_stats() */
+
diff --git a/src/H5EAtest.c b/src/H5EAtest.c
new file mode 100644
index 0000000..422ea68
--- /dev/null
+++ b/src/H5EAtest.c
@@ -0,0 +1,485 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, August 28, 2008
+ *
+ * Purpose: Extensible array testing functions.
+ *
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5EAmodule.h" /* This source code file is part of the H5EA module */
+#define H5EA_TESTING
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5EApkg.h" /* Extensible Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Sanity checking value for callback contexts */
+#define H5EA__TEST_BOGUS_VAL 42
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Callback context */
+typedef struct H5EA__test_ctx_t {
+ uint32_t bogus; /* Placeholder field to verify that context is working */
+ H5EA__ctx_cb_t *cb; /* Pointer to context's callback action */
+} H5EA__test_ctx_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Extensible array class callbacks */
+static void *H5EA__test_crt_context(void *udata);
+static herr_t H5EA__test_dst_context(void *ctx);
+static herr_t H5EA__test_fill(void *nat_blk, size_t nelmts);
+static herr_t H5EA__test_encode(void *raw, const void *elmt, size_t nelmts, void *ctx);
+static herr_t H5EA__test_decode(const void *raw, void *elmt, size_t nelmts, void *ctx);
+static herr_t H5EA__test_debug(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt);
+static void *H5EA__test_crt_dbg_context(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t H5_ATTR_UNUSED obj_addr);
+static herr_t H5EA__test_dst_dbg_context(void *_ctx);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Extensible array testing class information */
+const H5EA_class_t H5EA_CLS_TEST[1]={{
+ H5EA_CLS_TEST_ID, /* Type of Extensible array */
+ "Testing", /* Name of Extensible Array class */
+ sizeof(uint64_t), /* Size of native element */
+ H5EA__test_crt_context, /* Create context */
+ H5EA__test_dst_context, /* Destroy context */
+ H5EA__test_fill, /* Fill block of missing elements callback */
+ H5EA__test_encode, /* Element encoding callback */
+ H5EA__test_decode, /* Element decoding callback */
+ H5EA__test_debug, /* Element debugging callback */
+ H5EA__test_crt_dbg_context, /* Create debugging context */
+ H5EA__test_dst_dbg_context /* Destroy debugging context */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5EA__test_ctx_t struct */
+H5FL_DEFINE_STATIC(H5EA__test_ctx_t);
+
+/* Declare a free list to manage the H5EA__ctx_cb_t struct */
+H5FL_DEFINE_STATIC(H5EA__ctx_cb_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_crt_context
+ *
+ * Purpose: Create context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__test_crt_context(void *_udata))
+
+ /* Local variables */
+ H5EA__test_ctx_t *ctx; /* Context for callbacks */
+ H5EA__ctx_cb_t *udata = (H5EA__ctx_cb_t *)_udata; /* User data for context */
+
+ /* Sanity checks */
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5EA__test_ctx_t)))
+ H5E_THROW(H5E_CANTALLOC, "can't allocate extensible array client callback context")
+
+ /* Initialize the context */
+ ctx->bogus = H5EA__TEST_BOGUS_VAL;
+ ctx->cb = udata;
+
+ /* Set return value */
+ ret_value = ctx;
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__test_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_dst_context
+ *
+ * Purpose: Destroy context for callbacks
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__test_dst_context(void *_ctx))
+
+ /* Local variables */
+ H5EA__test_ctx_t *ctx = (H5EA__test_ctx_t *)_ctx; /* Callback context to destroy */
+
+ /* Sanity checks */
+ HDassert(H5EA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Release context structure */
+ ctx = H5FL_FREE(H5EA__test_ctx_t, ctx);
+
+END_FUNC(STATIC) /* end H5EA__test_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__test_fill(void *nat_blk, size_t nelmts))
+
+ /* Local variables */
+ uint64_t fill_val = H5EA_TEST_FILL; /* Value to fill elements with */
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+
+ H5VM_array_fill(nat_blk, &fill_val, sizeof(uint64_t), nelmts);
+
+END_FUNC(STATIC) /* end H5EA__test_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5EA__test_encode(void *raw, const void *_elmt, size_t nelmts, void *_ctx))
+
+ /* Local variables */
+ H5EA__test_ctx_t *ctx = (H5EA__test_ctx_t *)_ctx; /* Callback context to destroy */
+ const uint64_t *elmt = (const uint64_t *)_elmt; /* Convenience pointer to native elements */
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(H5EA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Check for callback action */
+ if(ctx->cb) {
+ if((*ctx->cb->encode)(elmt, nelmts, ctx->cb->udata) < 0)
+ H5E_THROW(H5E_BADVALUE, "extensible array testing callback action failed")
+ } /* end if */
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ UINT64ENCODE(raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__test_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__test_decode(const void *_raw, void *_elmt, size_t nelmts, void *_ctx))
+
+ /* Local variables */
+#ifndef NDEBUG
+ H5EA__test_ctx_t *ctx = (H5EA__test_ctx_t *)_ctx; /* Callback context to destroy */
+#endif /* NDEBUG */
+ uint64_t *elmt = (uint64_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(H5EA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ UINT64DECODE(raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+END_FUNC(STATIC) /* end H5EA__test_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__test_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *elmt))
+
+ /* Local variables */
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s %llu\n", indent, "", fwidth, temp_str,
+ (unsigned long long)*(const uint64_t *)elmt);
+
+END_FUNC(STATIC) /* end H5EA__test_debug() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_crt_dbg_context
+ *
+ * Purpose: Create context for debugging callback
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5EA__test_crt_dbg_context(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t H5_ATTR_UNUSED obj_addr))
+
+ /* Local variables */
+ H5EA__ctx_cb_t *ctx; /* Context for callbacks */
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5EA__ctx_cb_t)))
+ H5E_THROW(H5E_CANTALLOC, "can't allocate extensible array client callback context")
+
+ /* Set return value */
+ ret_value = ctx;
+
+CATCH
+
+END_FUNC(STATIC) /* end H5EA__test_crt_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA__test_dst_dbg_context
+ *
+ * Purpose: Destroy context for callbacks
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5EA__test_dst_dbg_context(void *_ctx))
+
+ /* Local variables */
+ H5EA__ctx_cb_t *ctx = (H5EA__ctx_cb_t *)_ctx; /* Callback context to destroy */
+
+ HDassert(_ctx);
+
+ /* Release context structure */
+ ctx = H5FL_FREE(H5EA__ctx_cb_t, ctx);
+
+END_FUNC(STATIC) /* end H5EA__test_dst_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_get_cparam_test
+ *
+ * Purpose: Retrieve the parameters used to create the extensible array
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5EA_get_cparam_test(const H5EA_t *ea, H5EA_create_t *cparam))
+
+ /* Check arguments. */
+ HDassert(ea);
+ HDassert(cparam);
+
+ /* Get extensible array creation parameters */
+ cparam->raw_elmt_size = ea->hdr->cparam.raw_elmt_size;
+ cparam->max_nelmts_bits = ea->hdr->cparam.max_nelmts_bits;
+ cparam->idx_blk_elmts = ea->hdr->cparam.idx_blk_elmts;
+ cparam->sup_blk_min_data_ptrs = ea->hdr->cparam.sup_blk_min_data_ptrs;
+ cparam->data_blk_min_elmts = ea->hdr->cparam.data_blk_min_elmts;
+ cparam->max_dblk_page_nelmts_bits = ea->hdr->cparam.max_dblk_page_nelmts_bits;
+
+END_FUNC(PRIV) /* end H5EA_get_cparam_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5EA_cmp_cparam_test
+ *
+ * Purpose: Compare the parameters used to create the extensible array
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 28, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERRCATCH,
+int, 0, -,
+H5EA_cmp_cparam_test(const H5EA_create_t *cparam1, const H5EA_create_t *cparam2))
+
+ /* Check arguments. */
+ HDassert(cparam1);
+ HDassert(cparam2);
+
+ /* Compare creation parameters for array */
+ if(cparam1->raw_elmt_size < cparam2->raw_elmt_size)
+ H5_LEAVE(-1)
+ else if(cparam1->raw_elmt_size > cparam2->raw_elmt_size)
+ H5_LEAVE(1)
+ if(cparam1->max_nelmts_bits < cparam2->max_nelmts_bits)
+ H5_LEAVE(-1)
+ else if(cparam1->max_nelmts_bits > cparam2->max_nelmts_bits)
+ H5_LEAVE(1)
+ if(cparam1->idx_blk_elmts < cparam2->idx_blk_elmts)
+ H5_LEAVE(-1)
+ else if(cparam1->idx_blk_elmts > cparam2->idx_blk_elmts)
+ H5_LEAVE(1)
+ if(cparam1->sup_blk_min_data_ptrs < cparam2->sup_blk_min_data_ptrs)
+ H5_LEAVE(-1)
+ else if(cparam1->sup_blk_min_data_ptrs > cparam2->sup_blk_min_data_ptrs)
+ H5_LEAVE(1)
+ if(cparam1->data_blk_min_elmts < cparam2->data_blk_min_elmts)
+ H5_LEAVE(-1)
+ else if(cparam1->data_blk_min_elmts > cparam2->data_blk_min_elmts)
+ H5_LEAVE(1)
+ if(cparam1->max_dblk_page_nelmts_bits < cparam2->max_dblk_page_nelmts_bits)
+ H5_LEAVE(-1)
+ else if(cparam1->max_dblk_page_nelmts_bits > cparam2->max_dblk_page_nelmts_bits)
+ H5_LEAVE(1)
+
+CATCH
+
+END_FUNC(PRIV) /* end H5EA_cmp_cparam_test() */
+
diff --git a/src/H5Edefin.h b/src/H5Edefin.h
new file mode 100644
index 0000000..b6eac17
--- /dev/null
+++ b/src/H5Edefin.h
@@ -0,0 +1,230 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_err -- do not edit */
+/* Add new errors to H5err.txt file */
+
+
+#ifndef _H5Edefin_H
+#define _H5Edefin_H
+
+/* Major error IDs */
+hid_t H5E_FUNC_g = FAIL; /* Function entry/exit */
+hid_t H5E_FILE_g = FAIL; /* File accessibilty */
+hid_t H5E_SOHM_g = FAIL; /* Shared Object Header Messages */
+hid_t H5E_SYM_g = FAIL; /* Symbol table */
+hid_t H5E_PLUGIN_g = FAIL; /* Plugin for dynamically loaded library */
+hid_t H5E_VFL_g = FAIL; /* Virtual File Layer */
+hid_t H5E_INTERNAL_g = FAIL; /* Internal error (too specific to document in detail) */
+hid_t H5E_BTREE_g = FAIL; /* B-Tree node */
+hid_t H5E_REFERENCE_g = FAIL; /* References */
+hid_t H5E_DATASPACE_g = FAIL; /* Dataspace */
+hid_t H5E_RESOURCE_g = FAIL; /* Resource unavailable */
+hid_t H5E_RS_g = FAIL; /* Reference Counted Strings */
+hid_t H5E_FARRAY_g = FAIL; /* Fixed Array */
+hid_t H5E_HEAP_g = FAIL; /* Heap */
+hid_t H5E_ATTR_g = FAIL; /* Attribute */
+hid_t H5E_IO_g = FAIL; /* Low-level I/O */
+hid_t H5E_EFL_g = FAIL; /* External file list */
+hid_t H5E_TST_g = FAIL; /* Ternary Search Trees */
+hid_t H5E_PAGEBUF_g = FAIL; /* Page Buffering */
+hid_t H5E_FSPACE_g = FAIL; /* Free Space Manager */
+hid_t H5E_DATASET_g = FAIL; /* Dataset */
+hid_t H5E_STORAGE_g = FAIL; /* Data storage */
+hid_t H5E_LINK_g = FAIL; /* Links */
+hid_t H5E_PLIST_g = FAIL; /* Property lists */
+hid_t H5E_DATATYPE_g = FAIL; /* Datatype */
+hid_t H5E_OHDR_g = FAIL; /* Object header */
+hid_t H5E_ATOM_g = FAIL; /* Object atom */
+hid_t H5E_NONE_MAJOR_g = FAIL; /* No error */
+hid_t H5E_SLIST_g = FAIL; /* Skip Lists */
+hid_t H5E_ARGS_g = FAIL; /* Invalid arguments to routine */
+hid_t H5E_EARRAY_g = FAIL; /* Extensible Array */
+hid_t H5E_PLINE_g = FAIL; /* Data filters */
+hid_t H5E_ERROR_g = FAIL; /* Error API */
+hid_t H5E_CACHE_g = FAIL; /* Object cache */
+
+/* Minor error IDs */
+
+/* Generic low-level file I/O errors */
+hid_t H5E_SEEKERROR_g = FAIL; /* Seek failed */
+hid_t H5E_READERROR_g = FAIL; /* Read failed */
+hid_t H5E_WRITEERROR_g = FAIL; /* Write failed */
+hid_t H5E_CLOSEERROR_g = FAIL; /* Close failed */
+hid_t H5E_OVERFLOW_g = FAIL; /* Address overflowed */
+hid_t H5E_FCNTL_g = FAIL; /* File control (fcntl) failed */
+
+/* Resource errors */
+hid_t H5E_NOSPACE_g = FAIL; /* No space available for allocation */
+hid_t H5E_CANTALLOC_g = FAIL; /* Can't allocate space */
+hid_t H5E_CANTCOPY_g = FAIL; /* Unable to copy object */
+hid_t H5E_CANTFREE_g = FAIL; /* Unable to free object */
+hid_t H5E_ALREADYEXISTS_g = FAIL; /* Object already exists */
+hid_t H5E_CANTLOCK_g = FAIL; /* Unable to lock object */
+hid_t H5E_CANTUNLOCK_g = FAIL; /* Unable to unlock object */
+hid_t H5E_CANTGC_g = FAIL; /* Unable to garbage collect */
+hid_t H5E_CANTGETSIZE_g = FAIL; /* Unable to compute size */
+hid_t H5E_OBJOPEN_g = FAIL; /* Object is already open */
+
+/* Heap errors */
+hid_t H5E_CANTRESTORE_g = FAIL; /* Can't restore condition */
+hid_t H5E_CANTCOMPUTE_g = FAIL; /* Can't compute value */
+hid_t H5E_CANTEXTEND_g = FAIL; /* Can't extend heap's space */
+hid_t H5E_CANTATTACH_g = FAIL; /* Can't attach object */
+hid_t H5E_CANTUPDATE_g = FAIL; /* Can't update object */
+hid_t H5E_CANTOPERATE_g = FAIL; /* Can't operate on object */
+
+/* Function entry/exit interface errors */
+hid_t H5E_CANTINIT_g = FAIL; /* Unable to initialize object */
+hid_t H5E_ALREADYINIT_g = FAIL; /* Object already initialized */
+hid_t H5E_CANTRELEASE_g = FAIL; /* Unable to release object */
+
+/* Property list errors */
+hid_t H5E_CANTGET_g = FAIL; /* Can't get value */
+hid_t H5E_CANTSET_g = FAIL; /* Can't set value */
+hid_t H5E_DUPCLASS_g = FAIL; /* Duplicate class name in parent class */
+hid_t H5E_SETDISALLOWED_g = FAIL; /* Disallowed operation */
+
+/* Free space errors */
+hid_t H5E_CANTMERGE_g = FAIL; /* Can't merge objects */
+hid_t H5E_CANTREVIVE_g = FAIL; /* Can't revive object */
+hid_t H5E_CANTSHRINK_g = FAIL; /* Can't shrink container */
+
+/* Object header related errors */
+hid_t H5E_LINKCOUNT_g = FAIL; /* Bad object header link count */
+hid_t H5E_VERSION_g = FAIL; /* Wrong version number */
+hid_t H5E_ALIGNMENT_g = FAIL; /* Alignment error */
+hid_t H5E_BADMESG_g = FAIL; /* Unrecognized message */
+hid_t H5E_CANTDELETE_g = FAIL; /* Can't delete message */
+hid_t H5E_BADITER_g = FAIL; /* Iteration failed */
+hid_t H5E_CANTPACK_g = FAIL; /* Can't pack messages */
+hid_t H5E_CANTRESET_g = FAIL; /* Can't reset object */
+hid_t H5E_CANTRENAME_g = FAIL; /* Unable to rename object */
+
+/* System level errors */
+hid_t H5E_SYSERRSTR_g = FAIL; /* System error message */
+
+/* I/O pipeline errors */
+hid_t H5E_NOFILTER_g = FAIL; /* Requested filter is not available */
+hid_t H5E_CALLBACK_g = FAIL; /* Callback failed */
+hid_t H5E_CANAPPLY_g = FAIL; /* Error from filter 'can apply' callback */
+hid_t H5E_SETLOCAL_g = FAIL; /* Error from filter 'set local' callback */
+hid_t H5E_NOENCODER_g = FAIL; /* Filter present but encoding disabled */
+hid_t H5E_CANTFILTER_g = FAIL; /* Filter operation failed */
+
+/* Group related errors */
+hid_t H5E_CANTOPENOBJ_g = FAIL; /* Can't open object */
+hid_t H5E_CANTCLOSEOBJ_g = FAIL; /* Can't close object */
+hid_t H5E_COMPLEN_g = FAIL; /* Name component is too long */
+hid_t H5E_PATH_g = FAIL; /* Problem with path to object */
+
+/* No error */
+hid_t H5E_NONE_MINOR_g = FAIL; /* No error */
+
+/* Plugin errors */
+hid_t H5E_OPENERROR_g = FAIL; /* Can't open directory or file */
+
+/* File accessibilty errors */
+hid_t H5E_FILEEXISTS_g = FAIL; /* File already exists */
+hid_t H5E_FILEOPEN_g = FAIL; /* File already open */
+hid_t H5E_CANTCREATE_g = FAIL; /* Unable to create file */
+hid_t H5E_CANTOPENFILE_g = FAIL; /* Unable to open file */
+hid_t H5E_CANTCLOSEFILE_g = FAIL; /* Unable to close file */
+hid_t H5E_NOTHDF5_g = FAIL; /* Not an HDF5 file */
+hid_t H5E_BADFILE_g = FAIL; /* Bad file ID accessed */
+hid_t H5E_TRUNCATED_g = FAIL; /* File has been truncated */
+hid_t H5E_MOUNT_g = FAIL; /* File mount error */
+
+/* Object atom related errors */
+hid_t H5E_BADATOM_g = FAIL; /* Unable to find atom information (already closed?) */
+hid_t H5E_BADGROUP_g = FAIL; /* Unable to find ID group information */
+hid_t H5E_CANTREGISTER_g = FAIL; /* Unable to register new atom */
+hid_t H5E_CANTINC_g = FAIL; /* Unable to increment reference count */
+hid_t H5E_CANTDEC_g = FAIL; /* Unable to decrement reference count */
+hid_t H5E_NOIDS_g = FAIL; /* Out of IDs for group */
+
+/* Cache related errors */
+hid_t H5E_CANTFLUSH_g = FAIL; /* Unable to flush data from cache */
+hid_t H5E_CANTUNSERIALIZE_g = FAIL; /* Unable to mark metadata as unserialized */
+hid_t H5E_CANTSERIALIZE_g = FAIL; /* Unable to serialize data from cache */
+hid_t H5E_CANTTAG_g = FAIL; /* Unable to tag metadata in the cache */
+hid_t H5E_CANTLOAD_g = FAIL; /* Unable to load metadata into cache */
+hid_t H5E_PROTECT_g = FAIL; /* Protected metadata error */
+hid_t H5E_NOTCACHED_g = FAIL; /* Metadata not currently cached */
+hid_t H5E_SYSTEM_g = FAIL; /* Internal error detected */
+hid_t H5E_CANTINS_g = FAIL; /* Unable to insert metadata into cache */
+hid_t H5E_CANTPROTECT_g = FAIL; /* Unable to protect metadata */
+hid_t H5E_CANTUNPROTECT_g = FAIL; /* Unable to unprotect metadata */
+hid_t H5E_CANTPIN_g = FAIL; /* Unable to pin cache entry */
+hid_t H5E_CANTUNPIN_g = FAIL; /* Unable to un-pin cache entry */
+hid_t H5E_CANTMARKDIRTY_g = FAIL; /* Unable to mark a pinned entry as dirty */
+hid_t H5E_CANTMARKCLEAN_g = FAIL; /* Unable to mark a pinned entry as clean */
+hid_t H5E_CANTMARKUNSERIALIZED_g = FAIL; /* Unable to mark an entry as unserialized */
+hid_t H5E_CANTMARKSERIALIZED_g = FAIL; /* Unable to mark an entry as serialized */
+hid_t H5E_CANTDIRTY_g = FAIL; /* Unable to mark metadata as dirty */
+hid_t H5E_CANTCLEAN_g = FAIL; /* Unable to mark metadata as clean */
+hid_t H5E_CANTEXPUNGE_g = FAIL; /* Unable to expunge a metadata cache entry */
+hid_t H5E_CANTRESIZE_g = FAIL; /* Unable to resize a metadata cache entry */
+hid_t H5E_CANTDEPEND_g = FAIL; /* Unable to create a flush dependency */
+hid_t H5E_CANTUNDEPEND_g = FAIL; /* Unable to destroy a flush dependency */
+hid_t H5E_CANTNOTIFY_g = FAIL; /* Unable to notify object about action */
+hid_t H5E_LOGFAIL_g = FAIL; /* Failure in the cache logging framework */
+hid_t H5E_CANTCORK_g = FAIL; /* Unable to cork an object */
+hid_t H5E_CANTUNCORK_g = FAIL; /* Unable to uncork an object */
+
+/* Link related errors */
+hid_t H5E_TRAVERSE_g = FAIL; /* Link traversal failure */
+hid_t H5E_NLINKS_g = FAIL; /* Too many soft links in path */
+hid_t H5E_NOTREGISTERED_g = FAIL; /* Link class not registered */
+hid_t H5E_CANTMOVE_g = FAIL; /* Can't move object */
+hid_t H5E_CANTSORT_g = FAIL; /* Can't sort objects */
+
+/* Parallel MPI errors */
+hid_t H5E_MPI_g = FAIL; /* Some MPI function failed */
+hid_t H5E_MPIERRSTR_g = FAIL; /* MPI Error String */
+hid_t H5E_CANTRECV_g = FAIL; /* Can't receive data */
+
+/* Dataspace errors */
+hid_t H5E_CANTCLIP_g = FAIL; /* Can't clip hyperslab region */
+hid_t H5E_CANTCOUNT_g = FAIL; /* Can't count elements */
+hid_t H5E_CANTSELECT_g = FAIL; /* Can't select hyperslab */
+hid_t H5E_CANTNEXT_g = FAIL; /* Can't move to next iterator location */
+hid_t H5E_BADSELECT_g = FAIL; /* Invalid selection */
+hid_t H5E_CANTCOMPARE_g = FAIL; /* Can't compare objects */
+hid_t H5E_CANTAPPEND_g = FAIL; /* Can't append object */
+
+/* Argument errors */
+hid_t H5E_UNINITIALIZED_g = FAIL; /* Information is uinitialized */
+hid_t H5E_UNSUPPORTED_g = FAIL; /* Feature is unsupported */
+hid_t H5E_BADTYPE_g = FAIL; /* Inappropriate type */
+hid_t H5E_BADRANGE_g = FAIL; /* Out of range */
+hid_t H5E_BADVALUE_g = FAIL; /* Bad value */
+
+/* B-tree related errors */
+hid_t H5E_NOTFOUND_g = FAIL; /* Object not found */
+hid_t H5E_EXISTS_g = FAIL; /* Object already exists */
+hid_t H5E_CANTENCODE_g = FAIL; /* Unable to encode value */
+hid_t H5E_CANTDECODE_g = FAIL; /* Unable to decode value */
+hid_t H5E_CANTSPLIT_g = FAIL; /* Unable to split node */
+hid_t H5E_CANTREDISTRIBUTE_g = FAIL; /* Unable to redistribute records */
+hid_t H5E_CANTSWAP_g = FAIL; /* Unable to swap records */
+hid_t H5E_CANTINSERT_g = FAIL; /* Unable to insert object */
+hid_t H5E_CANTLIST_g = FAIL; /* Unable to list node */
+hid_t H5E_CANTMODIFY_g = FAIL; /* Unable to modify record */
+hid_t H5E_CANTREMOVE_g = FAIL; /* Unable to remove object */
+
+/* Datatype conversion errors */
+hid_t H5E_CANTCONVERT_g = FAIL; /* Can't convert datatypes */
+hid_t H5E_BADSIZE_g = FAIL; /* Bad size for object */
+
+#endif /* H5Edefin_H */
diff --git a/src/H5Edeprec.c b/src/H5Edeprec.c
new file mode 100644
index 0000000..f579773
--- /dev/null
+++ b/src/H5Edeprec.c
@@ -0,0 +1,445 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Edeprec.c
+ * April 11 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5E interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Emodule.h" /* This source code file is part of the H5E module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Epkg.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_major
+ *
+ * Purpose: Retrieves a major error message.
+ *
+ * Return: Returns message if succeeds.
+ * otherwise returns NULL.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5Eget_major(H5E_major_t maj)
+{
+ H5E_msg_t *msg; /* Pointer to error message */
+ ssize_t size;
+ H5E_type_t type;
+ char *msg_str = NULL;
+ char *ret_value; /* Return value */
+
+ FUNC_ENTER_API_NOCLEAR(NULL)
+ H5TRACE1("*s", "i", maj);
+
+ /* Get the message object */
+ if(NULL == (msg = (H5E_msg_t *)H5I_object_verify(maj, H5I_ERROR_MSG)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a error message ID")
+
+ /* Get the size & type of the message's text */
+ if((size = H5E_get_msg(msg, &type, NULL, (size_t)0)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get error message text")
+ if(type != H5E_MAJOR)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "Error message isn't a major one")
+
+ /* Application will free this */
+ size++;
+ msg_str = (char *)H5MM_malloc((size_t)size);
+
+ /* Get the text for the message */
+ if(H5E_get_msg(msg, NULL, msg_str, (size_t)size) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get error message text")
+
+ ret_value = msg_str;
+
+done:
+ if(!ret_value)
+ msg_str = (char *)H5MM_xfree(msg_str);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_major() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_minor
+ *
+ * Purpose: Retrieves a minor error message.
+ *
+ * Return: Returns message if succeeds.
+ * otherwise returns NULL.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5Eget_minor(H5E_minor_t min)
+{
+ H5E_msg_t *msg; /* Pointer to error message */
+ ssize_t size;
+ H5E_type_t type;
+ char *msg_str = NULL;
+ char *ret_value; /* Return value */
+
+ FUNC_ENTER_API_NOCLEAR(NULL)
+ H5TRACE1("*s", "i", min);
+
+ /* Get the message object */
+ if(NULL == (msg = (H5E_msg_t *)H5I_object_verify(min, H5I_ERROR_MSG)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a error message ID")
+
+ /* Get the size & type of the message's text */
+ if((size = H5E_get_msg(msg, &type, NULL, (size_t)0)) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get error message text")
+ if(type != H5E_MINOR)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "Error message isn't a minor one")
+
+ /* Application will free this */
+ size++;
+ msg_str = (char *)H5MM_malloc((size_t)size);
+
+ /* Get the text for the message */
+ if(H5E_get_msg(msg, NULL, msg_str, (size_t)size) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get error message text")
+
+ ret_value = msg_str;
+
+done:
+ if(!ret_value)
+ msg_str = (char *)H5MM_xfree(msg_str);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_minor() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Epush1
+ *
+ * Purpose: This function definition is for backward compatibility only.
+ * It doesn't have error stack and error class as parameters.
+ * The old definition of major and minor is casted as HID_T
+ * in H5Epublic.h
+ *
+ * Notes: Basically a public API wrapper around the H5E_push2
+ * function. For backward compatibility, it maintains the
+ * same parameter as the old function, in contrary to
+ * H5Epush2.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Sep 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Epush1(const char *file, const char *func, unsigned line,
+ H5E_major_t maj, H5E_minor_t min, const char *str)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE6("e", "*s*sIuii*s", file, func, line, maj, min, str);
+
+ /* Push the error on the default error stack */
+ if(H5E_push_stack(NULL, file, func, line, H5E_ERR_CLS_g, maj, min, str) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't push error on stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Epush1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eclear1
+ *
+ * Purpose: This function is for backward compatbility.
+ * Clears the error stack for the specified error stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, July 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eclear1(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE0("e","");
+
+ /* Clear the default error stack */
+ if(H5E_clear_stack(NULL) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eclear1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eprint1
+ *
+ * Purpose: This function is for backward compatbility.
+ * Prints the error stack in some default way. This is just a
+ * convenience function for H5Ewalk() with a function that
+ * prints error messages. Users are encouraged to write there
+ * own more specific error handlers.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Sep 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eprint1(FILE *stream)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ /*NO TRACE*/
+
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Print error stack */
+ if(H5E_print(estack, stream, TRUE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't display error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eprint1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ewalk1
+ *
+ * Purpose: This function is for backward compatbility.
+ * Walks the error stack for the current thread and calls some
+ * function for each error along the way.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Sep 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ewalk1(H5E_direction_t direction, H5E_walk1_t func, void *client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_walk_op_t walk_op; /* Error stack walking callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ /*NO TRACE*/
+
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Walk the error stack */
+ walk_op.vers = 1;
+ walk_op.u.func1 = func;
+ if(H5E_walk(estack, direction, &walk_op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ewalk1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_auto1
+ *
+ * Purpose: This function is for backward compatbility.
+ * Returns the current settings for the automatic error stack
+ * traversal function and its data for specific error stack.
+ * Either (or both) arguments may be null in which case the
+ * value is not returned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Sep 16, 2003
+ *
+ * Modification:Raymond Lu
+ * 4 October 2010
+ * If the printing function isn't the default H5Eprint1 or 2,
+ * and H5Eset_auto2 has been called to set the new style
+ * printing function, a call to H5Eget_auto1 should fail.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eget_auto1(H5E_auto1_t *func, void **client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_auto_op_t auto_op; /* Error stack operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "*x**x", func, client_data);
+
+ /* Retrieve default error stack */
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Get the automatic error reporting information */
+ if(H5E_get_auto(estack, &auto_op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info")
+
+ /* Fail if the printing function isn't the default(user-set) and set through H5Eset_auto2 */
+ if(!auto_op.is_default && auto_op.vers == 2)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "wrong API function, H5Eset_auto2 has been called")
+
+ if(func)
+ *func = auto_op.func1;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eget_auto1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eset_auto1
+ *
+ * Purpose: This function is for backward compatbility.
+ * Turns on or off automatic printing of errors for certain
+ * error stack. When turned on (non-null FUNC pointer) any
+ * API function which returns an error indication will first
+ * call FUNC passing it CLIENT_DATA as an argument.
+ *
+ * The default values before this function is called are
+ * H5Eprint1() with client data being the standard error stream,
+ * stderr.
+ *
+ * Automatic stack traversal is always in the H5E_WALK_DOWNWARD
+ * direction.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Sep 16, 2003
+ *
+ * Modification:Raymond Lu
+ * 4 October 2010
+ * If the FUNC is H5Eprint2, put the IS_DEFAULT flag on.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eset_auto1(H5E_auto1_t func, void *client_data)
+{
+ H5E_t *estack; /* Error stack to operate on */
+ H5E_auto_op_t auto_op; /* Error stack operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Don't clear the error stack! :-) */
+ FUNC_ENTER_API_NOCLEAR(FAIL)
+ H5TRACE2("e", "x*x", func, client_data);
+
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Get the automatic error reporting information */
+ if(H5E_get_auto(estack, &auto_op, NULL) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info")
+
+ /* Set the automatic error reporting information */
+ auto_op.vers = 1;
+ if(func != auto_op.func1_default)
+ auto_op.is_default = FALSE;
+ else
+ auto_op.is_default = TRUE;
+ auto_op.func1 = func;
+
+ if(H5E_set_auto(estack, &auto_op, client_data) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't set automatic error info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Eset_auto1() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Einit.h b/src/H5Einit.h
new file mode 100644
index 0000000..94e76f0
--- /dev/null
+++ b/src/H5Einit.h
@@ -0,0 +1,888 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_err -- do not edit */
+/* Add new errors to H5err.txt file */
+
+
+#ifndef _H5Einit_H
+#define _H5Einit_H
+
+/*********************/
+/* Major error codes */
+/*********************/
+
+assert(H5E_FUNC_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Function entry/exit"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FUNC_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_FILE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "File accessibilty"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FILE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SOHM_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Shared Object Header Messages"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SOHM_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SYM_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Symbol table"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SYM_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PLUGIN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Plugin for dynamically loaded library"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PLUGIN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_VFL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Virtual File Layer"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_VFL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_INTERNAL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Internal error (too specific to document in detail)"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_INTERNAL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BTREE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "B-Tree node"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BTREE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_REFERENCE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "References"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_REFERENCE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_DATASPACE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Dataspace"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_DATASPACE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_RESOURCE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Resource unavailable"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_RESOURCE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_RS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Reference Counted Strings"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_RS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_FARRAY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Fixed Array"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FARRAY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_HEAP_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Heap"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_HEAP_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ATTR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Attribute"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ATTR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_IO_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Low-level I/O"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_IO_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_EFL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "External file list"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_EFL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_TST_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Ternary Search Trees"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_TST_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PAGEBUF_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Page Buffering"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PAGEBUF_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_FSPACE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Free Space Manager"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FSPACE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_DATASET_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Dataset"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_DATASET_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_STORAGE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Data storage"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_STORAGE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_LINK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Links"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_LINK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PLIST_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Property lists"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PLIST_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_DATATYPE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Datatype"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_DATATYPE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_OHDR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Object header"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_OHDR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ATOM_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Object atom"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ATOM_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NONE_MAJOR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "No error"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NONE_MAJOR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SLIST_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Skip Lists"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SLIST_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ARGS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Invalid arguments to routine"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ARGS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_EARRAY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Extensible Array"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_EARRAY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PLINE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Data filters"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PLINE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Error API"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CACHE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MAJOR, "Object cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CACHE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/*********************/
+/* Minor error codes */
+/*********************/
+
+
+/* Generic low-level file I/O errors */
+assert(H5E_SEEKERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Seek failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SEEKERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_READERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Read failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_READERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_WRITEERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Write failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_WRITEERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CLOSEERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Close failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CLOSEERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_OVERFLOW_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Address overflowed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_OVERFLOW_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_FCNTL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "File control (fcntl) failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FCNTL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Resource errors */
+assert(H5E_NOSPACE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "No space available for allocation"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOSPACE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTALLOC_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't allocate space"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTALLOC_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCOPY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to copy object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCOPY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTFREE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to free object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTFREE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ALREADYEXISTS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Object already exists"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ALREADYEXISTS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTLOCK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to lock object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTLOCK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNLOCK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to unlock object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNLOCK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTGC_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to garbage collect"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTGC_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTGETSIZE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to compute size"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTGETSIZE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_OBJOPEN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Object is already open"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_OBJOPEN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Heap errors */
+assert(H5E_CANTRESTORE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't restore condition"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRESTORE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCOMPUTE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't compute value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCOMPUTE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTEXTEND_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't extend heap's space"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTEXTEND_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTATTACH_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't attach object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTATTACH_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUPDATE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't update object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUPDATE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTOPERATE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't operate on object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTOPERATE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Function entry/exit interface errors */
+assert(H5E_CANTINIT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to initialize object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTINIT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ALREADYINIT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Object already initialized"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ALREADYINIT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTRELEASE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to release object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRELEASE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Property list errors */
+assert(H5E_CANTGET_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't get value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTGET_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSET_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't set value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSET_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_DUPCLASS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Duplicate class name in parent class"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_DUPCLASS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SETDISALLOWED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Disallowed operation"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SETDISALLOWED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Free space errors */
+assert(H5E_CANTMERGE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't merge objects"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMERGE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTREVIVE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't revive object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTREVIVE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSHRINK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't shrink container"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSHRINK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Object header related errors */
+assert(H5E_LINKCOUNT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Bad object header link count"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_LINKCOUNT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_VERSION_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Wrong version number"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_VERSION_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_ALIGNMENT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Alignment error"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_ALIGNMENT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADMESG_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unrecognized message"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADMESG_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTDELETE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't delete message"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTDELETE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADITER_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Iteration failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADITER_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTPACK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't pack messages"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTPACK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTRESET_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't reset object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRESET_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTRENAME_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to rename object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRENAME_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* System level errors */
+assert(H5E_SYSERRSTR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "System error message"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SYSERRSTR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* I/O pipeline errors */
+assert(H5E_NOFILTER_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Requested filter is not available"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOFILTER_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CALLBACK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Callback failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CALLBACK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANAPPLY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Error from filter 'can apply' callback"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANAPPLY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SETLOCAL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Error from filter 'set local' callback"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SETLOCAL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NOENCODER_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Filter present but encoding disabled"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOENCODER_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTFILTER_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Filter operation failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTFILTER_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Group related errors */
+assert(H5E_CANTOPENOBJ_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't open object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTOPENOBJ_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCLOSEOBJ_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't close object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCLOSEOBJ_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_COMPLEN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Name component is too long"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_COMPLEN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PATH_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Problem with path to object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PATH_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* No error */
+assert(H5E_NONE_MINOR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "No error"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NONE_MINOR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Plugin errors */
+assert(H5E_OPENERROR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't open directory or file"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_OPENERROR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* File accessibilty errors */
+assert(H5E_FILEEXISTS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "File already exists"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FILEEXISTS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_FILEOPEN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "File already open"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_FILEOPEN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCREATE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to create file"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCREATE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTOPENFILE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to open file"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTOPENFILE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCLOSEFILE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to close file"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCLOSEFILE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NOTHDF5_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Not an HDF5 file"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOTHDF5_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADFILE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Bad file ID accessed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADFILE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_TRUNCATED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "File has been truncated"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_TRUNCATED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_MOUNT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "File mount error"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_MOUNT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Object atom related errors */
+assert(H5E_BADATOM_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to find atom information (already closed?)"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADATOM_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADGROUP_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to find ID group information"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADGROUP_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTREGISTER_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to register new atom"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTREGISTER_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTINC_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to increment reference count"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTINC_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTDEC_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to decrement reference count"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTDEC_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NOIDS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Out of IDs for group"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOIDS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Cache related errors */
+assert(H5E_CANTFLUSH_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to flush data from cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTFLUSH_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNSERIALIZE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark metadata as unserialized"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNSERIALIZE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSERIALIZE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to serialize data from cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSERIALIZE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTTAG_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to tag metadata in the cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTTAG_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTLOAD_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to load metadata into cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTLOAD_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_PROTECT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Protected metadata error"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_PROTECT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NOTCACHED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Metadata not currently cached"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOTCACHED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SYSTEM_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Internal error detected"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SYSTEM_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTINS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to insert metadata into cache"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTINS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTPROTECT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to protect metadata"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTPROTECT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNPROTECT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to unprotect metadata"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNPROTECT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTPIN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to pin cache entry"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTPIN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNPIN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to un-pin cache entry"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNPIN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMARKDIRTY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark a pinned entry as dirty"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMARKDIRTY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMARKCLEAN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark a pinned entry as clean"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMARKCLEAN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMARKUNSERIALIZED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark an entry as unserialized"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMARKUNSERIALIZED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMARKSERIALIZED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark an entry as serialized"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMARKSERIALIZED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTDIRTY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark metadata as dirty"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTDIRTY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCLEAN_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to mark metadata as clean"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCLEAN_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTEXPUNGE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to expunge a metadata cache entry"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTEXPUNGE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTRESIZE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to resize a metadata cache entry"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRESIZE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTDEPEND_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to create a flush dependency"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTDEPEND_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNDEPEND_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to destroy a flush dependency"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNDEPEND_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTNOTIFY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to notify object about action"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTNOTIFY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_LOGFAIL_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Failure in the cache logging framework"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_LOGFAIL_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCORK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to cork an object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCORK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTUNCORK_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to uncork an object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTUNCORK_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Link related errors */
+assert(H5E_TRAVERSE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Link traversal failure"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_TRAVERSE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NLINKS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Too many soft links in path"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NLINKS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_NOTREGISTERED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Link class not registered"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOTREGISTERED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMOVE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't move object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMOVE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSORT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't sort objects"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSORT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Parallel MPI errors */
+assert(H5E_MPI_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Some MPI function failed"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_MPI_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_MPIERRSTR_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "MPI Error String"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_MPIERRSTR_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTRECV_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't receive data"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTRECV_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Dataspace errors */
+assert(H5E_CANTCLIP_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't clip hyperslab region"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCLIP_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCOUNT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't count elements"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCOUNT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSELECT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't select hyperslab"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSELECT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTNEXT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't move to next iterator location"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTNEXT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADSELECT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Invalid selection"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADSELECT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTCOMPARE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't compare objects"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCOMPARE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTAPPEND_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't append object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTAPPEND_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Argument errors */
+assert(H5E_UNINITIALIZED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Information is uinitialized"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_UNINITIALIZED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_UNSUPPORTED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Feature is unsupported"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_UNSUPPORTED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADTYPE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Inappropriate type"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADTYPE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADRANGE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Out of range"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADRANGE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADVALUE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Bad value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADVALUE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* B-tree related errors */
+assert(H5E_NOTFOUND_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Object not found"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_NOTFOUND_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_EXISTS_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Object already exists"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_EXISTS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTENCODE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to encode value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTENCODE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTDECODE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to decode value"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTDECODE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSPLIT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to split node"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSPLIT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTREDISTRIBUTE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to redistribute records"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTREDISTRIBUTE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTSWAP_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to swap records"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTSWAP_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTINSERT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to insert object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTINSERT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTLIST_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to list node"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTLIST_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTMODIFY_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to modify record"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTMODIFY_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_CANTREMOVE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to remove object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTREMOVE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+/* Datatype conversion errors */
+assert(H5E_CANTCONVERT_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't convert datatypes"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_CANTCONVERT_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_BADSIZE_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Bad size for object"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_BADSIZE_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+
+#endif /* H5Einit_H */
diff --git a/src/H5Eint.c b/src/H5Eint.c
new file mode 100644
index 0000000..110c6bb
--- /dev/null
+++ b/src/H5Eint.c
@@ -0,0 +1,1016 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Eint.c
+ * April 11 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: General use, "internal" routines for error handling.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Emodule.h" /* This source code file is part of the H5E module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Epkg.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Printing information */
+typedef struct H5E_print_t {
+ FILE *stream;
+ H5E_cls_t cls;
+} H5E_print_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+static herr_t H5E_walk1_cb(int n, H5E_error1_t *err_desc,
+ void *client_data);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+static herr_t H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc,
+ void *client_data);
+static herr_t H5E_clear_entries(H5E_t *estack, size_t nentries);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+#ifndef H5_HAVE_THREADSAFE
+/*
+ * The current error stack.
+ */
+H5E_t H5E_stack_g[1];
+#endif /* H5_HAVE_THREADSAFE */
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* HDF5 error class ID */
+hid_t H5E_ERR_CLS_g = FAIL;
+
+/*
+ * Predefined errors. These are initialized at runtime in H5E_init_interface()
+ * in this source file.
+ */
+/* Include the automatically generated error code definitions */
+#include "H5Edefin.h"
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+#ifdef H5_HAVE_PARALLEL
+/*
+ * variables used for MPI error reporting
+ */
+char H5E_mpi_error_str[MPI_MAX_ERROR_STRING];
+int H5E_mpi_error_str_len;
+#endif /* H5_HAVE_PARALLEL */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_msg
+ *
+ * Purpose: Private function to retrieve an error message.
+ *
+ * Return: Non-negative for name length if succeeds(zero means no name);
+ * otherwise returns negative value.
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 14, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5E_get_msg(const H5E_msg_t *msg, H5E_type_t *type, char *msg_str, size_t size)
+{
+ ssize_t len = -1; /* Length of error message */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(msg);
+
+ /* Get the length of the message string */
+ len = (ssize_t)HDstrlen(msg->msg);
+
+ /* Copy the message into the user's buffer, if given */
+ if(msg_str) {
+ HDstrncpy(msg_str, msg->msg, MIN((size_t)(len+1), size));
+ if((size_t)len >= size)
+ msg_str[size - 1] = '\0';
+ } /* end if */
+
+ /* Give the message type, if asked */
+ if(type)
+ *type = msg->type;
+
+ /* Set the return value to the full length of the message */
+ FUNC_LEAVE_NOAPI(len)
+} /* end H5E_get_msg() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_walk1_cb
+ *
+ * Purpose: This function is for backward compatibility.
+ * This is a default error stack traversal callback function
+ * that prints error messages to the specified output stream.
+ * This function is for backward compatibility with v1.6.
+ * It is not meant to be called directly but rather as an
+ * argument to the H5Ewalk() function. This function is called
+ * also by H5Eprint(). Application writers are encouraged to
+ * use this function as a model for their own error stack
+ * walking functions.
+ *
+ * N is a counter for how many times this function has been
+ * called for this particular traversal of the stack. It always
+ * begins at zero for the first error on the stack (either the
+ * top or bottom error, or even both, depending on the traversal
+ * direction and the size of the stack).
+ *
+ * ERR_DESC is an error description. It contains all the
+ * information about a particular error.
+ *
+ * CLIENT_DATA is the same pointer that was passed as the
+ * CLIENT_DATA argument of H5Ewalk(). It is expected to be a
+ * file pointer (or stderr if null).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Thursday, May 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_walk1_cb(int n, H5E_error1_t *err_desc, void *client_data)
+{
+ H5E_print_t *eprint = (H5E_print_t *)client_data;
+ FILE *stream; /* I/O stream to print output to */
+ H5E_cls_t *cls_ptr; /* Pointer to error class */
+ H5E_msg_t *maj_ptr; /* Pointer to major error info */
+ H5E_msg_t *min_ptr; /* Pointer to minor error info */
+ const char *maj_str = "No major description"; /* Major error description */
+ const char *min_str = "No minor description"; /* Minor error description */
+ unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(err_desc);
+
+ /* If no client data was passed, output to stderr */
+ if(!client_data)
+ stream = stderr;
+ else
+ stream = eprint->stream;
+
+ /* Get descriptions for the major and minor error numbers */
+ maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
+ min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
+
+ /* Check for bad pointer(s), but can't issue error, just leave */
+ if(!maj_ptr || !min_ptr)
+ HGOTO_DONE(FAIL)
+
+ if(maj_ptr->msg)
+ maj_str = maj_ptr->msg;
+ if(min_ptr->msg)
+ min_str = min_ptr->msg;
+
+ /* Get error class info */
+ cls_ptr = maj_ptr->cls;
+
+ /* Print error class header if new class */
+ if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
+ /* update to the new class information */
+ if(cls_ptr->cls_name)
+ eprint->cls.cls_name = cls_ptr->cls_name;
+ if(cls_ptr->lib_name)
+ eprint->cls.lib_name = cls_ptr->lib_name;
+ if(cls_ptr->lib_vers)
+ eprint->cls.lib_vers = cls_ptr->lib_vers;
+
+ fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
+ (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
+ (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
+ (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
+
+ /* try show the process or thread id in multiple processes cases*/
+#ifdef H5_HAVE_PARALLEL
+ {
+ int mpi_rank, mpi_initialized, mpi_finalized;
+
+ MPI_Initialized(&mpi_initialized);
+ MPI_Finalized(&mpi_finalized);
+
+ if(mpi_initialized && !mpi_finalized) {
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+ fprintf(stream, "MPI-process %d", mpi_rank);
+ } /* end if */
+ else
+ fprintf(stream, "thread 0");
+ } /* end block */
+#elif defined(H5_HAVE_THREADSAFE)
+ fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
+#else
+ fprintf(stream, "thread 0");
+#endif
+ fprintf(stream, ":\n");
+ } /* end if */
+
+ /* Check for "real" error description - used to format output more nicely */
+ if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
+ have_desc=0;
+
+ /* Print error message */
+ fprintf(stream, "%*s#%03d: %s line %u in %s()%s%s\n",
+ H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
+ err_desc->func_name, (have_desc ? ": " : ""),
+ (have_desc ? err_desc->desc : ""));
+ fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
+ fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_walk1_cb() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_walk2_cb
+ *
+ * Purpose: This is a default error stack traversal callback function
+ * that prints error messages to the specified output stream.
+ * It is not meant to be called directly but rather as an
+ * argument to the H5Ewalk2() function. This function is
+ * called also by H5Eprint2(). Application writers are
+ * encouraged to use this function as a model for their own
+ * error stack walking functions.
+ *
+ * N is a counter for how many times this function has been
+ * called for this particular traversal of the stack. It always
+ * begins at zero for the first error on the stack (either the
+ * top or bottom error, or even both, depending on the traversal
+ * direction and the size of the stack).
+ *
+ * ERR_DESC is an error description. It contains all the
+ * information about a particular error.
+ *
+ * CLIENT_DATA is the same pointer that was passed as the
+ * CLIENT_DATA argument of H5Ewalk(). It is expected to be a
+ * file pointer (or stderr if null).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data)
+{
+ H5E_print_t *eprint = (H5E_print_t *)client_data;
+ FILE *stream; /* I/O stream to print output to */
+ H5E_cls_t *cls_ptr; /* Pointer to error class */
+ H5E_msg_t *maj_ptr; /* Pointer to major error info */
+ H5E_msg_t *min_ptr; /* Pointer to minor error info */
+ const char *maj_str = "No major description"; /* Major error description */
+ const char *min_str = "No minor description"; /* Minor error description */
+ unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(err_desc);
+
+ /* If no client data was passed, output to stderr */
+ if(!client_data)
+ stream = stderr;
+ else
+ stream = eprint->stream;
+
+ /* Get descriptions for the major and minor error numbers */
+ maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
+ min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
+
+ /* Check for bad pointer(s), but can't issue error, just leave */
+ if(!maj_ptr || !min_ptr)
+ HGOTO_DONE(FAIL)
+
+ if(maj_ptr->msg)
+ maj_str = maj_ptr->msg;
+ if(min_ptr->msg)
+ min_str = min_ptr->msg;
+
+ /* Get error class info. Don't use the class of the major or minor error because
+ * they might be different. */
+ cls_ptr = (H5E_cls_t *)H5I_object_verify(err_desc->cls_id, H5I_ERROR_CLASS);
+
+ /* Check for bad pointer(s), but can't issue error, just leave */
+ if(!cls_ptr)
+ HGOTO_DONE(FAIL)
+
+ /* Print error class header if new class */
+ if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
+ /* update to the new class information */
+ if(cls_ptr->cls_name)
+ eprint->cls.cls_name = cls_ptr->cls_name;
+ if(cls_ptr->lib_name)
+ eprint->cls.lib_name = cls_ptr->lib_name;
+ if(cls_ptr->lib_vers)
+ eprint->cls.lib_vers = cls_ptr->lib_vers;
+
+ fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
+ (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
+ (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
+ (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
+
+ /* try show the process or thread id in multiple processes cases*/
+#ifdef H5_HAVE_PARALLEL
+ {
+ int mpi_rank, mpi_initialized, mpi_finalized;
+
+ MPI_Initialized(&mpi_initialized);
+ MPI_Finalized(&mpi_finalized);
+
+ if(mpi_initialized && !mpi_finalized) {
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+ fprintf(stream, "MPI-process %d", mpi_rank);
+ } /* end if */
+ else
+ fprintf(stream, "thread 0");
+ } /* end block */
+#elif defined(H5_HAVE_THREADSAFE)
+ fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
+#else
+ fprintf(stream, "thread 0");
+#endif
+ fprintf(stream, ":\n");
+ } /* end if */
+
+ /* Check for "real" error description - used to format output more nicely */
+ if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
+ have_desc = 0;
+
+ /* Print error message */
+ fprintf(stream, "%*s#%03u: %s line %u in %s()%s%s\n",
+ H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
+ err_desc->func_name, (have_desc ? ": " : ""),
+ (have_desc ? err_desc->desc : ""));
+ fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
+ fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_walk2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_print
+ *
+ * Purpose: Private function to print the error stack in some default
+ * way. This is just a convenience function for H5Ewalk() and
+ * H5Ewalk2() with a function that prints error messages.
+ * Users are encouraged to write there own more specific error
+ * handlers.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_print(const H5E_t *estack, FILE *stream, hbool_t bk_compatible)
+{
+ H5E_print_t eprint; /* Callback information to pass to H5E_walk() */
+ H5E_walk_op_t walk_op; /* Error stack walking callback */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(estack);
+
+ /* If no stream was given, use stderr */
+ if(!stream)
+ eprint.stream = stderr;
+ else
+ eprint.stream = stream;
+
+ /* Reset the original error class information */
+ HDmemset(&eprint.cls, 0, sizeof(H5E_cls_t));
+
+ /* Walk the error stack */
+ if(bk_compatible) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ walk_op.vers = 1;
+ walk_op.u.func1 = H5E_walk1_cb;
+ if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+ HDassert(0 && "version 1 error stack print without deprecated symbols!");
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ } /* end if */
+ else {
+ walk_op.vers = 2;
+ walk_op.u.func2 = H5E_walk2_cb;
+ if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_print() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_walk
+ *
+ * Purpose: Private function for H5Ewalk.
+ * Walks the error stack, calling the specified function for
+ * each error on the stack. The DIRECTION argument determines
+ * whether the stack is walked from the inside out or the
+ * outside in. The value H5E_WALK_UPWARD means begin with the
+ * most specific error and end at the API; H5E_WALK_DOWNWARD
+ * means to start at the API and end at the inner-most function
+ * where the error was first detected.
+ *
+ * The function pointed to by STACK_FUNC will be called for
+ * each error record in the error stack. It's arguments will
+ * include an index number (beginning at zero regardless of
+ * stack traversal direction), an error stack entry, and the
+ * CLIENT_DATA pointer passed to H5E_print.
+ *
+ * The function FUNC is also provided for backward compatibility.
+ * When BK_COMPATIBLE is set to be TRUE, FUNC is used to be
+ * compatible with older library. If BK_COMPATIBLE is FALSE,
+ * STACK_FUNC is used.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_walk(const H5E_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op,
+ void *client_data)
+{
+ int i; /* Local index variable */
+ herr_t status; /* Status from callback function */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(estack);
+ HDassert(op);
+
+ /* check args, but rather than failing use some default value */
+ if(direction != H5E_WALK_UPWARD && direction != H5E_WALK_DOWNWARD)
+ direction = H5E_WALK_UPWARD;
+
+ /* Walk the stack if a callback function was given */
+ if(op->vers == 1) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ if(op->u.func1) {
+ H5E_error1_t old_err;
+
+ status = SUCCEED;
+ if(H5E_WALK_UPWARD == direction) {
+ for(i = 0; i < (int)estack->nused && status >= 0; i++) {
+ /* Point to each error record on the stack and pass it to callback function.*/
+ old_err.maj_num = estack->slot[i].maj_num;
+ old_err.min_num = estack->slot[i].min_num;
+ old_err.func_name = estack->slot[i].func_name;
+ old_err.file_name = estack->slot[i].file_name;
+ old_err.desc = estack->slot[i].desc;
+ old_err.line = estack->slot[i].line;
+
+ status = (op->u.func1)(i, &old_err, client_data);
+ } /* end for */
+ } /* end if */
+ else {
+ H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
+ for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--) {
+ /* Point to each error record on the stack and pass it to callback function.*/
+ old_err.maj_num = estack->slot[i].maj_num;
+ old_err.min_num = estack->slot[i].min_num;
+ old_err.func_name = estack->slot[i].func_name;
+ old_err.file_name = estack->slot[i].file_name;
+ old_err.desc = estack->slot[i].desc;
+ old_err.line = estack->slot[i].line;
+
+ status = (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data);
+ } /* end for */
+ } /* end else */
+
+ if(status < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+ } /* end if */
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+ HDassert(0 && "version 1 error stack walk without deprecated symbols!");
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ } /* end if */
+ else {
+ HDassert(op->vers == 2);
+ if(op->u.func2) {
+ status = SUCCEED;
+ if(H5E_WALK_UPWARD == direction) {
+ for(i = 0; i < (int)estack->nused && status >= 0; i++)
+ status = (op->u.func2)((unsigned)i, estack->slot + i, client_data);
+ } /* end if */
+ else {
+ H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
+ for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--)
+ status = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)), estack->slot + i, client_data);
+ } /* end else */
+
+ if(status < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_walk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_get_auto
+ *
+ * Purpose: Private function to return the current settings for the
+ * automatic error stack traversal function and its data
+ * for specific error stack. Either (or both) arguments may
+ * be null in which case the value is not returned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * July 18, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_get_auto(const H5E_t *estack, H5E_auto_op_t *op, void **client_data)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(estack);
+
+ /* Retrieve the requested information */
+ if(op)
+ *op = estack->auto_op;
+ if(client_data)
+ *client_data = estack->auto_data;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_get_auto2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_set_auto
+ *
+ * Purpose: Private function to turn on or off automatic printing of
+ * errors for certain error stack. When turned on (non-null
+ * FUNC pointer) any API function which returns an error
+ * indication will first call FUNC passing it CLIENT_DATA
+ * as an argument.
+ *
+ * The default values before this function is called are
+ * H5Eprint2() with client data being the standard error stream,
+ * stderr.
+ *
+ * Automatic stack traversal is always in the H5E_WALK_DOWNWARD
+ * direction.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_set_auto(H5E_t *estack, const H5E_auto_op_t *op, void *client_data)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(estack);
+
+ /* Set the automatic error reporting info */
+ estack->auto_op = *op;
+ estack->auto_data = client_data;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5E_set_auto() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_printf_stack
+ *
+ * Purpose: Printf-like wrapper around H5E_push_stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
+ hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...)
+{
+ va_list ap; /* Varargs info */
+#ifndef H5_HAVE_VASPRINTF
+ int tmp_len; /* Current size of description buffer */
+ int desc_len; /* Actual length of description when formatted */
+#endif /* H5_HAVE_VASPRINTF */
+ char *tmp = NULL; /* Buffer to place formatted description in */
+ hbool_t va_started = FALSE; /* Whether the variable argument list is open */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /*
+ * WARNING: We cannot call HERROR() from within this function or else we
+ * could enter infinite recursion. Furthermore, we also cannot
+ * call any other HDF5 macro or function which might call
+ * HERROR(). HERROR() is called by HRETURN_ERROR() which could
+ * be called by FUNC_ENTER().
+ */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(cls_id > 0);
+ HDassert(maj_id > 0);
+ HDassert(min_id > 0);
+ HDassert(fmt);
+
+/* Note that the variable-argument parsing for the format is identical in
+ * the H5Epush2() routine - correct errors and make changes in both
+ * places. -QAK
+ */
+
+ /* Start the variable-argument parsing */
+ va_start(ap, fmt);
+ va_started = TRUE;
+
+#ifdef H5_HAVE_VASPRINTF
+ /* Use the vasprintf() routine, since it does what we're trying to do below */
+ if(HDvasprintf(&tmp, fmt, ap) < 0)
+ HGOTO_DONE(FAIL)
+#else /* H5_HAVE_VASPRINTF */
+ /* Allocate space for the formatted description buffer */
+ tmp_len = 128;
+ if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
+ HGOTO_DONE(FAIL)
+
+ /* If the description doesn't fit into the initial buffer size, allocate more space and try again */
+ while((desc_len = HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) > (tmp_len - 1)) {
+ /* shutdown & restart the va_list */
+ va_end(ap);
+ va_start(ap, fmt);
+
+ /* Release the previous description, it's too small */
+ H5MM_xfree(tmp);
+
+ /* Allocate a description of the appropriate length */
+ tmp_len = desc_len + 1;
+ if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
+ HGOTO_DONE(FAIL)
+ } /* end while */
+#endif /* H5_HAVE_VASPRINTF */
+
+ /* Push the error on the stack */
+ if(H5E_push_stack(estack, file, func, line, cls_id, maj_id, min_id, tmp) < 0)
+ HGOTO_DONE(FAIL)
+
+done:
+ if(va_started)
+ va_end(ap);
+#ifdef H5_HAVE_VASPRINTF
+ /* Memory was allocated with HDvasprintf so it needs to be freed
+ * with HDfree
+ */
+ if(tmp)
+ HDfree(tmp);
+#else /* H5_HAVE_VASPRINTF */
+ if(tmp)
+ H5MM_xfree(tmp);
+#endif /* H5_HAVE_VASPRINTF */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_printf_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_push_stack
+ *
+ * Purpose: Pushes a new error record onto error stack for the current
+ * thread. The error has major and minor IDs MAJ_ID and
+ * MIN_ID, the name of a function where the error was detected,
+ * the name of the file where the error was detected, the
+ * line within that file, and an error description string. The
+ * function name, file name, and error description strings must
+ * be statically allocated (the FUNC_ENTER() macro takes care of
+ * the function name and file name automatically, but the
+ * programmer is responsible for the description string).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_push_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
+ hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /*
+ * WARNING: We cannot call HERROR() from within this function or else we
+ * could enter infinite recursion. Furthermore, we also cannot
+ * call any other HDF5 macro or function which might call
+ * HERROR(). HERROR() is called by HRETURN_ERROR() which could
+ * be called by FUNC_ENTER().
+ */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(cls_id > 0);
+ HDassert(maj_id > 0);
+ HDassert(min_id > 0);
+
+ /* Check for 'default' error stack */
+ if(estack == NULL)
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_DONE(FAIL)
+
+ /*
+ * Don't fail if arguments are bad. Instead, substitute some default
+ * value.
+ */
+ if(!func)
+ func = "Unknown_Function";
+ if(!file)
+ file = "Unknown_File";
+ if(!desc)
+ desc = "No description given";
+
+ /*
+ * Push the error if there's room. Otherwise just forget it.
+ */
+ HDassert(estack);
+
+ if(estack->nused < H5E_NSLOTS) {
+ /* Increment the IDs to indicate that they are used in this stack */
+ if(H5I_inc_ref(cls_id, FALSE) < 0)
+ HGOTO_DONE(FAIL)
+ estack->slot[estack->nused].cls_id = cls_id;
+ if(H5I_inc_ref(maj_id, FALSE) < 0)
+ HGOTO_DONE(FAIL)
+ estack->slot[estack->nused].maj_num = maj_id;
+ if(H5I_inc_ref(min_id, FALSE) < 0)
+ HGOTO_DONE(FAIL)
+ estack->slot[estack->nused].min_num = min_id;
+ if(NULL == (estack->slot[estack->nused].func_name = H5MM_xstrdup(func)))
+ HGOTO_DONE(FAIL)
+ if(NULL == (estack->slot[estack->nused].file_name = H5MM_xstrdup(file)))
+ HGOTO_DONE(FAIL)
+ estack->slot[estack->nused].line = line;
+ if(NULL == (estack->slot[estack->nused].desc = H5MM_xstrdup(desc)))
+ HGOTO_DONE(FAIL)
+ estack->nused++;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_push_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_clear_entries
+ *
+ * Purpose: Private function to clear the error stack entries for the
+ * specified error stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5E_clear_entries(H5E_t *estack, size_t nentries)
+{
+ H5E_error2_t *error; /* Pointer to error stack entry to clear */
+ unsigned u; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(estack);
+ HDassert(estack->nused >= nentries);
+
+ /* Empty the error stack from the top down */
+ for(u = 0; nentries > 0; nentries--, u++) {
+ error = &(estack->slot[estack->nused - (u + 1)]);
+
+ /* Decrement the IDs to indicate that they are no longer used by this stack */
+ /* (In reverse order that they were incremented, so that reference counts work well) */
+ if(H5I_dec_ref(error->min_num) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
+ if(H5I_dec_ref(error->maj_num) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
+ if(H5I_dec_ref(error->cls_id) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error class")
+
+ /* Release strings */
+ if(error->func_name)
+ H5MM_xfree((void *)error->func_name); /* Casting away const OK - QAK */
+ if(error->file_name)
+ H5MM_xfree((void *)error->file_name); /* Casting away const OK - QAK */
+ if(error->desc)
+ H5MM_xfree((void *)error->desc); /* Casting away const OK - QAK */
+ } /* end for */
+
+ /* Decrement number of errors on stack */
+ estack->nused -= u;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_clear_entries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_clear_stack
+ *
+ * Purpose: Private function to clear the error stack for the
+ * specified error stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, July 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_clear_stack(H5E_t *estack)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check for 'default' error stack */
+ if(estack == NULL)
+ if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
+
+ /* Empty the error stack */
+ HDassert(estack);
+ if(estack->nused)
+ if(H5E_clear_entries(estack, estack->nused) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_clear_stack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_pop
+ *
+ * Purpose: Private function to delete some error messages from the top
+ * of error stack.
+ *
+ * Return: Non-negative value on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, July 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_pop(H5E_t *estack, size_t count)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(estack);
+ HDassert(estack->nused >= count);
+
+ /* Remove the entries from the error stack */
+ if(H5E_clear_entries(estack, count) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "can't remove errors from stack")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_pop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5E_dump_api_stack
+ *
+ * Purpose: Private function to dump the error stack during an error in
+ * an API function if a callback function is defined for the
+ * current error stack.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5E_dump_api_stack(hbool_t is_api)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Only dump the error stack during an API call */
+ if(is_api) {
+ H5E_t *estack = H5E_get_my_stack();
+
+ HDassert(estack);
+
+#ifdef H5_NO_DEPRECATED_SYMBOLS
+ if(estack->auto_op.func2)
+ (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+ if(estack->auto_op.vers == 1) {
+ if(estack->auto_op.func1)
+ (void)((estack->auto_op.func1)(estack->auto_data));
+ } /* end if */
+ else {
+ if(estack->auto_op.func2)
+ (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
+ } /* end else */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5E_dump_api_stack() */
+
diff --git a/src/H5Emodule.h b/src/H5Emodule.h
new file mode 100644
index 0000000..2d1bcd0
--- /dev/null
+++ b/src/H5Emodule.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5E package. Including this header means that the source file
+ * is part of the H5E package.
+ */
+#ifndef _H5Emodule_H
+#define _H5Emodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5E_MODULE
+#define H5_MY_PKG H5E
+#define H5_MY_PKG_ERR H5E_ERROR
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Emodule_H */
+
+
diff --git a/src/H5Epkg.h b/src/H5Epkg.h
new file mode 100644
index 0000000..90f4f80
--- /dev/null
+++ b/src/H5Epkg.h
@@ -0,0 +1,149 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Wednesday, April 11, 2007
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5E package. Source files outside the H5E package should
+ * include H5Eprivate.h instead.
+ */
+#if !(defined H5E_FRIEND || defined H5E_MODULE)
+#error "Do not include this file outside the H5E package!"
+#endif
+
+#ifndef _H5Epkg_H
+#define _H5Epkg_H
+
+/* Get package's private header */
+#include "H5Eprivate.h"
+
+/* Other private headers needed by this file */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Amount to indent each error */
+#define H5E_INDENT 2
+
+/* Number of slots in an error stack */
+#define H5E_NSLOTS 32
+
+#ifdef H5_HAVE_THREADSAFE
+/*
+ * The per-thread error stack. pthread_once() initializes a special
+ * key that will be used by all threads to create a stack specific to
+ * each thread individually. The association of stacks to threads will
+ * be handled by the pthread library.
+ *
+ * In order for this macro to work, H5E_get_my_stack() must be preceeded
+ * by "H5E_t *estack =".
+ */
+#define H5E_get_my_stack() H5E_get_stack()
+#else /* H5_HAVE_THREADSAFE */
+/*
+ * The current error stack.
+ */
+#define H5E_get_my_stack() (H5E_stack_g + 0)
+#endif /* H5_HAVE_THREADSAFE */
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Some syntactic sugar to make the compiler happy with two different kinds of callbacks */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+typedef struct {
+ unsigned vers; /* Which version callback to use */
+ hbool_t is_default; /* If the printing function is the library's own. */
+ H5E_auto1_t func1; /* Old-style callback, NO error stack param. */
+ H5E_auto2_t func2; /* New-style callback, with error stack param. */
+ H5E_auto1_t func1_default; /* The saved library's default function - old style. */
+ H5E_auto2_t func2_default; /* The saved library's default function - new style. */
+} H5E_auto_op_t;
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+typedef struct {
+ H5E_auto_t func2; /* Only the new style callback function is available. */
+} H5E_auto_op_t;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/* Some syntactic sugar to make the compiler happy with two different kinds of callbacks */
+typedef struct {
+ unsigned vers; /* Which version callback to use */
+ union {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ H5E_walk1_t func1; /* Old-style callback, NO error stack param. */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ H5E_walk2_t func2; /* New-style callback, with error stack param. */
+ }u;
+} H5E_walk_op_t;
+
+/* Error class */
+typedef struct H5E_cls_t {
+ char *cls_name; /* Name of error class */
+ char *lib_name; /* Name of library within class */
+ char *lib_vers; /* Version of library */
+} H5E_cls_t;
+
+/* Major or minor message */
+typedef struct H5E_msg_t {
+ char *msg; /* Message for error */
+ H5E_type_t type; /* Type of error (major or minor) */
+ H5E_cls_t *cls; /* Which error class this message belongs to */
+} H5E_msg_t;
+
+/* Error stack */
+struct H5E_t {
+ size_t nused; /* Num slots currently used in stack */
+ H5E_error2_t slot[H5E_NSLOTS]; /* Array of error records */
+ H5E_auto_op_t auto_op; /* Operator for 'automatic' error reporting */
+ void *auto_data; /* Callback data for 'automatic error reporting */
+};
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+#ifndef H5_HAVE_THREADSAFE
+/*
+ * The current error stack.
+ */
+H5_DLLVAR H5E_t H5E_stack_g[1];
+#endif /* H5_HAVE_THREADSAFE */
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+H5_DLL herr_t H5E__term_deprec_interface(void);
+#ifdef H5_HAVE_THREADSAFE
+H5_DLL H5E_t *H5E_get_stack(void);
+#endif /* H5_HAVE_THREADSAFE */
+H5_DLL ssize_t H5E_get_msg(const H5E_msg_t *msg_ptr, H5E_type_t *type,
+ char *msg, size_t size);
+H5_DLL herr_t H5E_print(const H5E_t *estack, FILE *stream, hbool_t bk_compat);
+H5_DLL herr_t H5E_walk(const H5E_t *estack, H5E_direction_t direction,
+ const H5E_walk_op_t *op, void *client_data);
+H5_DLL herr_t H5E_get_auto(const H5E_t *estack, H5E_auto_op_t *op,
+ void **client_data);
+H5_DLL herr_t H5E_set_auto(H5E_t *estack, const H5E_auto_op_t *op,
+ void *client_data);
+H5_DLL herr_t H5E_pop(H5E_t *err_stack, size_t count);
+
+#endif /* _H5Epkg_H */
+
diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h
new file mode 100644
index 0000000..57e7485
--- /dev/null
+++ b/src/H5Eprivate.h
@@ -0,0 +1,192 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Header file for error values, etc.
+ */
+#ifndef _H5Eprivate_H
+#define _H5Eprivate_H
+
+#include "H5Epublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h"
+
+/* Typedef for error stack (defined in H5Epkg.h) */
+typedef struct H5E_t H5E_t;
+
+/*
+ * HERROR macro, used to facilitate error reporting between a FUNC_ENTER()
+ * and a FUNC_LEAVE() within a function body. The arguments are the major
+ * error number, the minor error number, and a description of the error.
+ */
+#define HERROR(maj_id, min_id, ...) H5E_printf_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, maj_id, min_id, __VA_ARGS__)
+
+/*
+ * HCOMMON_ERROR macro, used by HDONE_ERROR and HGOTO_ERROR
+ * (Shouldn't need to be used outside this header file)
+ */
+#define HCOMMON_ERROR(maj, min, ...) \
+ HERROR(maj, min, __VA_ARGS__); \
+ err_occurred = TRUE; \
+ err_occurred = err_occurred; /* Shut GCC warnings up! */
+
+/*
+ * HDONE_ERROR macro, used to facilitate error reporting between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body, but _AFTER_ the
+ * "done:" label. The arguments are
+ * the major error number, the minor error number, a return value, and a
+ * description of the error.
+ * (This macro can also be used to push an error and set the return value
+ * without jumping to any labels)
+ */
+#define HDONE_ERROR(maj, min, ret_val, ...) { \
+ HCOMMON_ERROR(maj, min, __VA_ARGS__); \
+ ret_value = ret_val; \
+}
+
+/*
+ * HGOTO_ERROR macro, used to facilitate error reporting between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are
+ * the major error number, the minor error number, the return value, and an
+ * error string. The return value is assigned to a variable `ret_value' and
+ * control branches to the `done' label.
+ */
+#define HGOTO_ERROR(maj, min, ret_val, ...) { \
+ HCOMMON_ERROR(maj, min, __VA_ARGS__); \
+ HGOTO_DONE(ret_val) \
+}
+
+/*
+ * HGOTO_ERROR_TAG macro, used like HGOTO_ERROR between H5_BEGIN_TAG and
+ * H5_END_TAG statements. Resets the metadata tag before leaving the function.
+ */
+#define HGOTO_ERROR_TAG(maj, min, ret_val, ...) { \
+ if(H5AC_tag(my_dxpl_id, prv_tag, NULL) < 0) \
+ HERROR(H5E_CACHE, H5E_CANTTAG, "unable to apply metadata tag"); \
+ HCOMMON_ERROR(maj, min, __VA_ARGS__); \
+ HGOTO_DONE(ret_val) \
+}
+
+/*
+ * HGOTO_DONE macro, used to facilitate normal return between a FUNC_ENTER()
+ * and a FUNC_LEAVE() within a function body. The argument is the return
+ * value which is assigned to the `ret_value' variable. Control branches to
+ * the `done' label.
+ */
+#define HGOTO_DONE(ret_val) {ret_value = ret_val; goto done;}
+
+/*
+ * HGOTO_DONE_TAG macro, used like HGOTO_DONE between H5_BEGIN_TAG and
+ * H5_END_TAG statements. Resets the metadata tag before leaving the function.
+ */
+#define HGOTO_DONE_TAG(ret_val, err) { \
+ if(H5AC_tag(my_dxpl_id, prv_tag, NULL) < 0) \
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ HGOTO_DONE(ret_val) \
+}
+
+/*
+ * Macros handling system error messages as described in C standard.
+ * These macros assume errnum is a valid system error code.
+ */
+
+/* Retrieve the error code description string and push it onto the error
+ * stack.
+ */
+#define HSYS_DONE_ERROR(majorcode, minorcode, retcode, str) { \
+ int myerrno = errno; \
+ HDONE_ERROR(majorcode, minorcode, retcode, "%s, errno = %d, error message = '%s'", str, myerrno, HDstrerror(myerrno)); \
+}
+#define HSYS_GOTO_ERROR(majorcode, minorcode, retcode, str) { \
+ int myerrno = errno; \
+ HGOTO_ERROR(majorcode, minorcode, retcode, "%s, errno = %d, error message = '%s'", str, myerrno, HDstrerror(myerrno)); \
+}
+
+#ifdef H5_HAVE_PARALLEL
+/*
+ * MPI error handling macros.
+ */
+
+extern char H5E_mpi_error_str[MPI_MAX_ERROR_STRING];
+extern int H5E_mpi_error_str_len;
+
+#define HMPI_ERROR(mpierr){ \
+ MPI_Error_string(mpierr, H5E_mpi_error_str, &H5E_mpi_error_str_len); \
+ HERROR(H5E_INTERNAL, H5E_MPIERRSTR, "%s", H5E_mpi_error_str); \
+}
+#define HMPI_DONE_ERROR(retcode, str, mpierr){ \
+ HMPI_ERROR(mpierr); \
+ HDONE_ERROR(H5E_INTERNAL, H5E_MPI, retcode, str); \
+}
+#define HMPI_GOTO_ERROR(retcode, str, mpierr){ \
+ HMPI_ERROR(mpierr); \
+ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, retcode, str); \
+}
+#endif /* H5_HAVE_PARALLEL */
+
+
+/******************************************************************************/
+/* Revisions to Error Macros, to go with Revisions to FUNC_ENTER/LEAVE Macros */
+/******************************************************************************/
+
+/*
+ * H5E_PRINTF macro, used to facilitate error reporting between a BEGIN_FUNC()
+ * and an END_FUNC() within a function body. The arguments are the minor
+ * error number, a description of the error (as a printf-like format string),
+ * and an optional set of arguments for the printf format arguments.
+ */
+#define H5E_PRINTF(...) H5E_printf_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, H5_MY_PKG_ERR, __VA_ARGS__)
+
+/*
+ * H5_LEAVE macro, used to facilitate control flow between a
+ * BEGIN_FUNC() and an END_FUNC() within a function body. The argument is
+ * the return value.
+ * The return value is assigned to a variable `ret_value' and control branches
+ * to the `catch_except' label, if we're not already past it.
+ */
+#define H5_LEAVE(v) { \
+ ret_value = v; \
+ if(!past_catch) \
+ goto catch_except; \
+}
+
+/*
+ * H5E_THROW macro, used to facilitate error reporting between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are
+ * the minor error number, and an error string.
+ * The return value is assigned to a variable `ret_value' and control branches
+ * to the `catch_except' label, if we're not already past it.
+ */
+#define H5E_THROW(...) { \
+ H5E_PRINTF(__VA_ARGS__); \
+ H5_LEAVE(fail_value) \
+}
+
+/* Macro for "catching" flow of control when an error occurs. Note that the
+ * H5_LEAVE macro won't jump back here once it's past this point.
+ */
+#define CATCH catch_except:; past_catch = TRUE;
+
+
+/* Library-private functions defined in H5E package */
+H5_DLL herr_t H5E_init(void);
+H5_DLL herr_t H5E_push_stack(H5E_t *estack, const char *file, const char *func,
+ unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc);
+H5_DLL herr_t H5E_printf_stack(H5E_t *estack, const char *file, const char *func,
+ unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...)H5_ATTR_FORMAT(printf, 8, 9);
+H5_DLL herr_t H5E_clear_stack(H5E_t *estack);
+H5_DLL herr_t H5E_dump_api_stack(hbool_t is_api);
+
+#endif /* _H5Eprivate_H */
+
diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h
new file mode 100644
index 0000000..45bfbc6
--- /dev/null
+++ b/src/H5Epubgen.h
@@ -0,0 +1,406 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_err -- do not edit */
+/* Add new errors to H5err.txt file */
+
+
+#ifndef _H5Epubgen_H
+#define _H5Epubgen_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************/
+/* Major error codes */
+/*********************/
+
+#define H5E_FUNC (H5OPEN H5E_FUNC_g)
+#define H5E_FILE (H5OPEN H5E_FILE_g)
+#define H5E_SOHM (H5OPEN H5E_SOHM_g)
+#define H5E_SYM (H5OPEN H5E_SYM_g)
+#define H5E_PLUGIN (H5OPEN H5E_PLUGIN_g)
+#define H5E_VFL (H5OPEN H5E_VFL_g)
+#define H5E_INTERNAL (H5OPEN H5E_INTERNAL_g)
+#define H5E_BTREE (H5OPEN H5E_BTREE_g)
+#define H5E_REFERENCE (H5OPEN H5E_REFERENCE_g)
+#define H5E_DATASPACE (H5OPEN H5E_DATASPACE_g)
+#define H5E_RESOURCE (H5OPEN H5E_RESOURCE_g)
+#define H5E_RS (H5OPEN H5E_RS_g)
+#define H5E_FARRAY (H5OPEN H5E_FARRAY_g)
+#define H5E_HEAP (H5OPEN H5E_HEAP_g)
+#define H5E_ATTR (H5OPEN H5E_ATTR_g)
+#define H5E_IO (H5OPEN H5E_IO_g)
+#define H5E_EFL (H5OPEN H5E_EFL_g)
+#define H5E_TST (H5OPEN H5E_TST_g)
+#define H5E_PAGEBUF (H5OPEN H5E_PAGEBUF_g)
+#define H5E_FSPACE (H5OPEN H5E_FSPACE_g)
+#define H5E_DATASET (H5OPEN H5E_DATASET_g)
+#define H5E_STORAGE (H5OPEN H5E_STORAGE_g)
+#define H5E_LINK (H5OPEN H5E_LINK_g)
+#define H5E_PLIST (H5OPEN H5E_PLIST_g)
+#define H5E_DATATYPE (H5OPEN H5E_DATATYPE_g)
+#define H5E_OHDR (H5OPEN H5E_OHDR_g)
+#define H5E_ATOM (H5OPEN H5E_ATOM_g)
+#define H5E_NONE_MAJOR (H5OPEN H5E_NONE_MAJOR_g)
+#define H5E_SLIST (H5OPEN H5E_SLIST_g)
+#define H5E_ARGS (H5OPEN H5E_ARGS_g)
+#define H5E_EARRAY (H5OPEN H5E_EARRAY_g)
+#define H5E_PLINE (H5OPEN H5E_PLINE_g)
+#define H5E_ERROR (H5OPEN H5E_ERROR_g)
+#define H5E_CACHE (H5OPEN H5E_CACHE_g)
+H5_DLLVAR hid_t H5E_FUNC_g; /* Function entry/exit */
+H5_DLLVAR hid_t H5E_FILE_g; /* File accessibilty */
+H5_DLLVAR hid_t H5E_SOHM_g; /* Shared Object Header Messages */
+H5_DLLVAR hid_t H5E_SYM_g; /* Symbol table */
+H5_DLLVAR hid_t H5E_PLUGIN_g; /* Plugin for dynamically loaded library */
+H5_DLLVAR hid_t H5E_VFL_g; /* Virtual File Layer */
+H5_DLLVAR hid_t H5E_INTERNAL_g; /* Internal error (too specific to document in detail) */
+H5_DLLVAR hid_t H5E_BTREE_g; /* B-Tree node */
+H5_DLLVAR hid_t H5E_REFERENCE_g; /* References */
+H5_DLLVAR hid_t H5E_DATASPACE_g; /* Dataspace */
+H5_DLLVAR hid_t H5E_RESOURCE_g; /* Resource unavailable */
+H5_DLLVAR hid_t H5E_RS_g; /* Reference Counted Strings */
+H5_DLLVAR hid_t H5E_FARRAY_g; /* Fixed Array */
+H5_DLLVAR hid_t H5E_HEAP_g; /* Heap */
+H5_DLLVAR hid_t H5E_ATTR_g; /* Attribute */
+H5_DLLVAR hid_t H5E_IO_g; /* Low-level I/O */
+H5_DLLVAR hid_t H5E_EFL_g; /* External file list */
+H5_DLLVAR hid_t H5E_TST_g; /* Ternary Search Trees */
+H5_DLLVAR hid_t H5E_PAGEBUF_g; /* Page Buffering */
+H5_DLLVAR hid_t H5E_FSPACE_g; /* Free Space Manager */
+H5_DLLVAR hid_t H5E_DATASET_g; /* Dataset */
+H5_DLLVAR hid_t H5E_STORAGE_g; /* Data storage */
+H5_DLLVAR hid_t H5E_LINK_g; /* Links */
+H5_DLLVAR hid_t H5E_PLIST_g; /* Property lists */
+H5_DLLVAR hid_t H5E_DATATYPE_g; /* Datatype */
+H5_DLLVAR hid_t H5E_OHDR_g; /* Object header */
+H5_DLLVAR hid_t H5E_ATOM_g; /* Object atom */
+H5_DLLVAR hid_t H5E_NONE_MAJOR_g; /* No error */
+H5_DLLVAR hid_t H5E_SLIST_g; /* Skip Lists */
+H5_DLLVAR hid_t H5E_ARGS_g; /* Invalid arguments to routine */
+H5_DLLVAR hid_t H5E_EARRAY_g; /* Extensible Array */
+H5_DLLVAR hid_t H5E_PLINE_g; /* Data filters */
+H5_DLLVAR hid_t H5E_ERROR_g; /* Error API */
+H5_DLLVAR hid_t H5E_CACHE_g; /* Object cache */
+
+/*********************/
+/* Minor error codes */
+/*********************/
+
+/* Generic low-level file I/O errors */
+#define H5E_SEEKERROR (H5OPEN H5E_SEEKERROR_g)
+#define H5E_READERROR (H5OPEN H5E_READERROR_g)
+#define H5E_WRITEERROR (H5OPEN H5E_WRITEERROR_g)
+#define H5E_CLOSEERROR (H5OPEN H5E_CLOSEERROR_g)
+#define H5E_OVERFLOW (H5OPEN H5E_OVERFLOW_g)
+#define H5E_FCNTL (H5OPEN H5E_FCNTL_g)
+H5_DLLVAR hid_t H5E_SEEKERROR_g; /* Seek failed */
+H5_DLLVAR hid_t H5E_READERROR_g; /* Read failed */
+H5_DLLVAR hid_t H5E_WRITEERROR_g; /* Write failed */
+H5_DLLVAR hid_t H5E_CLOSEERROR_g; /* Close failed */
+H5_DLLVAR hid_t H5E_OVERFLOW_g; /* Address overflowed */
+H5_DLLVAR hid_t H5E_FCNTL_g; /* File control (fcntl) failed */
+
+/* Resource errors */
+#define H5E_NOSPACE (H5OPEN H5E_NOSPACE_g)
+#define H5E_CANTALLOC (H5OPEN H5E_CANTALLOC_g)
+#define H5E_CANTCOPY (H5OPEN H5E_CANTCOPY_g)
+#define H5E_CANTFREE (H5OPEN H5E_CANTFREE_g)
+#define H5E_ALREADYEXISTS (H5OPEN H5E_ALREADYEXISTS_g)
+#define H5E_CANTLOCK (H5OPEN H5E_CANTLOCK_g)
+#define H5E_CANTUNLOCK (H5OPEN H5E_CANTUNLOCK_g)
+#define H5E_CANTGC (H5OPEN H5E_CANTGC_g)
+#define H5E_CANTGETSIZE (H5OPEN H5E_CANTGETSIZE_g)
+#define H5E_OBJOPEN (H5OPEN H5E_OBJOPEN_g)
+H5_DLLVAR hid_t H5E_NOSPACE_g; /* No space available for allocation */
+H5_DLLVAR hid_t H5E_CANTALLOC_g; /* Can't allocate space */
+H5_DLLVAR hid_t H5E_CANTCOPY_g; /* Unable to copy object */
+H5_DLLVAR hid_t H5E_CANTFREE_g; /* Unable to free object */
+H5_DLLVAR hid_t H5E_ALREADYEXISTS_g; /* Object already exists */
+H5_DLLVAR hid_t H5E_CANTLOCK_g; /* Unable to lock object */
+H5_DLLVAR hid_t H5E_CANTUNLOCK_g; /* Unable to unlock object */
+H5_DLLVAR hid_t H5E_CANTGC_g; /* Unable to garbage collect */
+H5_DLLVAR hid_t H5E_CANTGETSIZE_g; /* Unable to compute size */
+H5_DLLVAR hid_t H5E_OBJOPEN_g; /* Object is already open */
+
+/* Heap errors */
+#define H5E_CANTRESTORE (H5OPEN H5E_CANTRESTORE_g)
+#define H5E_CANTCOMPUTE (H5OPEN H5E_CANTCOMPUTE_g)
+#define H5E_CANTEXTEND (H5OPEN H5E_CANTEXTEND_g)
+#define H5E_CANTATTACH (H5OPEN H5E_CANTATTACH_g)
+#define H5E_CANTUPDATE (H5OPEN H5E_CANTUPDATE_g)
+#define H5E_CANTOPERATE (H5OPEN H5E_CANTOPERATE_g)
+H5_DLLVAR hid_t H5E_CANTRESTORE_g; /* Can't restore condition */
+H5_DLLVAR hid_t H5E_CANTCOMPUTE_g; /* Can't compute value */
+H5_DLLVAR hid_t H5E_CANTEXTEND_g; /* Can't extend heap's space */
+H5_DLLVAR hid_t H5E_CANTATTACH_g; /* Can't attach object */
+H5_DLLVAR hid_t H5E_CANTUPDATE_g; /* Can't update object */
+H5_DLLVAR hid_t H5E_CANTOPERATE_g; /* Can't operate on object */
+
+/* Function entry/exit interface errors */
+#define H5E_CANTINIT (H5OPEN H5E_CANTINIT_g)
+#define H5E_ALREADYINIT (H5OPEN H5E_ALREADYINIT_g)
+#define H5E_CANTRELEASE (H5OPEN H5E_CANTRELEASE_g)
+H5_DLLVAR hid_t H5E_CANTINIT_g; /* Unable to initialize object */
+H5_DLLVAR hid_t H5E_ALREADYINIT_g; /* Object already initialized */
+H5_DLLVAR hid_t H5E_CANTRELEASE_g; /* Unable to release object */
+
+/* Property list errors */
+#define H5E_CANTGET (H5OPEN H5E_CANTGET_g)
+#define H5E_CANTSET (H5OPEN H5E_CANTSET_g)
+#define H5E_DUPCLASS (H5OPEN H5E_DUPCLASS_g)
+#define H5E_SETDISALLOWED (H5OPEN H5E_SETDISALLOWED_g)
+H5_DLLVAR hid_t H5E_CANTGET_g; /* Can't get value */
+H5_DLLVAR hid_t H5E_CANTSET_g; /* Can't set value */
+H5_DLLVAR hid_t H5E_DUPCLASS_g; /* Duplicate class name in parent class */
+H5_DLLVAR hid_t H5E_SETDISALLOWED_g; /* Disallowed operation */
+
+/* Free space errors */
+#define H5E_CANTMERGE (H5OPEN H5E_CANTMERGE_g)
+#define H5E_CANTREVIVE (H5OPEN H5E_CANTREVIVE_g)
+#define H5E_CANTSHRINK (H5OPEN H5E_CANTSHRINK_g)
+H5_DLLVAR hid_t H5E_CANTMERGE_g; /* Can't merge objects */
+H5_DLLVAR hid_t H5E_CANTREVIVE_g; /* Can't revive object */
+H5_DLLVAR hid_t H5E_CANTSHRINK_g; /* Can't shrink container */
+
+/* Object header related errors */
+#define H5E_LINKCOUNT (H5OPEN H5E_LINKCOUNT_g)
+#define H5E_VERSION (H5OPEN H5E_VERSION_g)
+#define H5E_ALIGNMENT (H5OPEN H5E_ALIGNMENT_g)
+#define H5E_BADMESG (H5OPEN H5E_BADMESG_g)
+#define H5E_CANTDELETE (H5OPEN H5E_CANTDELETE_g)
+#define H5E_BADITER (H5OPEN H5E_BADITER_g)
+#define H5E_CANTPACK (H5OPEN H5E_CANTPACK_g)
+#define H5E_CANTRESET (H5OPEN H5E_CANTRESET_g)
+#define H5E_CANTRENAME (H5OPEN H5E_CANTRENAME_g)
+H5_DLLVAR hid_t H5E_LINKCOUNT_g; /* Bad object header link count */
+H5_DLLVAR hid_t H5E_VERSION_g; /* Wrong version number */
+H5_DLLVAR hid_t H5E_ALIGNMENT_g; /* Alignment error */
+H5_DLLVAR hid_t H5E_BADMESG_g; /* Unrecognized message */
+H5_DLLVAR hid_t H5E_CANTDELETE_g; /* Can't delete message */
+H5_DLLVAR hid_t H5E_BADITER_g; /* Iteration failed */
+H5_DLLVAR hid_t H5E_CANTPACK_g; /* Can't pack messages */
+H5_DLLVAR hid_t H5E_CANTRESET_g; /* Can't reset object */
+H5_DLLVAR hid_t H5E_CANTRENAME_g; /* Unable to rename object */
+
+/* System level errors */
+#define H5E_SYSERRSTR (H5OPEN H5E_SYSERRSTR_g)
+H5_DLLVAR hid_t H5E_SYSERRSTR_g; /* System error message */
+
+/* I/O pipeline errors */
+#define H5E_NOFILTER (H5OPEN H5E_NOFILTER_g)
+#define H5E_CALLBACK (H5OPEN H5E_CALLBACK_g)
+#define H5E_CANAPPLY (H5OPEN H5E_CANAPPLY_g)
+#define H5E_SETLOCAL (H5OPEN H5E_SETLOCAL_g)
+#define H5E_NOENCODER (H5OPEN H5E_NOENCODER_g)
+#define H5E_CANTFILTER (H5OPEN H5E_CANTFILTER_g)
+H5_DLLVAR hid_t H5E_NOFILTER_g; /* Requested filter is not available */
+H5_DLLVAR hid_t H5E_CALLBACK_g; /* Callback failed */
+H5_DLLVAR hid_t H5E_CANAPPLY_g; /* Error from filter 'can apply' callback */
+H5_DLLVAR hid_t H5E_SETLOCAL_g; /* Error from filter 'set local' callback */
+H5_DLLVAR hid_t H5E_NOENCODER_g; /* Filter present but encoding disabled */
+H5_DLLVAR hid_t H5E_CANTFILTER_g; /* Filter operation failed */
+
+/* Group related errors */
+#define H5E_CANTOPENOBJ (H5OPEN H5E_CANTOPENOBJ_g)
+#define H5E_CANTCLOSEOBJ (H5OPEN H5E_CANTCLOSEOBJ_g)
+#define H5E_COMPLEN (H5OPEN H5E_COMPLEN_g)
+#define H5E_PATH (H5OPEN H5E_PATH_g)
+H5_DLLVAR hid_t H5E_CANTOPENOBJ_g; /* Can't open object */
+H5_DLLVAR hid_t H5E_CANTCLOSEOBJ_g; /* Can't close object */
+H5_DLLVAR hid_t H5E_COMPLEN_g; /* Name component is too long */
+H5_DLLVAR hid_t H5E_PATH_g; /* Problem with path to object */
+
+/* No error */
+#define H5E_NONE_MINOR (H5OPEN H5E_NONE_MINOR_g)
+H5_DLLVAR hid_t H5E_NONE_MINOR_g; /* No error */
+
+/* Plugin errors */
+#define H5E_OPENERROR (H5OPEN H5E_OPENERROR_g)
+H5_DLLVAR hid_t H5E_OPENERROR_g; /* Can't open directory or file */
+
+/* File accessibilty errors */
+#define H5E_FILEEXISTS (H5OPEN H5E_FILEEXISTS_g)
+#define H5E_FILEOPEN (H5OPEN H5E_FILEOPEN_g)
+#define H5E_CANTCREATE (H5OPEN H5E_CANTCREATE_g)
+#define H5E_CANTOPENFILE (H5OPEN H5E_CANTOPENFILE_g)
+#define H5E_CANTCLOSEFILE (H5OPEN H5E_CANTCLOSEFILE_g)
+#define H5E_NOTHDF5 (H5OPEN H5E_NOTHDF5_g)
+#define H5E_BADFILE (H5OPEN H5E_BADFILE_g)
+#define H5E_TRUNCATED (H5OPEN H5E_TRUNCATED_g)
+#define H5E_MOUNT (H5OPEN H5E_MOUNT_g)
+H5_DLLVAR hid_t H5E_FILEEXISTS_g; /* File already exists */
+H5_DLLVAR hid_t H5E_FILEOPEN_g; /* File already open */
+H5_DLLVAR hid_t H5E_CANTCREATE_g; /* Unable to create file */
+H5_DLLVAR hid_t H5E_CANTOPENFILE_g; /* Unable to open file */
+H5_DLLVAR hid_t H5E_CANTCLOSEFILE_g; /* Unable to close file */
+H5_DLLVAR hid_t H5E_NOTHDF5_g; /* Not an HDF5 file */
+H5_DLLVAR hid_t H5E_BADFILE_g; /* Bad file ID accessed */
+H5_DLLVAR hid_t H5E_TRUNCATED_g; /* File has been truncated */
+H5_DLLVAR hid_t H5E_MOUNT_g; /* File mount error */
+
+/* Object atom related errors */
+#define H5E_BADATOM (H5OPEN H5E_BADATOM_g)
+#define H5E_BADGROUP (H5OPEN H5E_BADGROUP_g)
+#define H5E_CANTREGISTER (H5OPEN H5E_CANTREGISTER_g)
+#define H5E_CANTINC (H5OPEN H5E_CANTINC_g)
+#define H5E_CANTDEC (H5OPEN H5E_CANTDEC_g)
+#define H5E_NOIDS (H5OPEN H5E_NOIDS_g)
+H5_DLLVAR hid_t H5E_BADATOM_g; /* Unable to find atom information (already closed?) */
+H5_DLLVAR hid_t H5E_BADGROUP_g; /* Unable to find ID group information */
+H5_DLLVAR hid_t H5E_CANTREGISTER_g; /* Unable to register new atom */
+H5_DLLVAR hid_t H5E_CANTINC_g; /* Unable to increment reference count */
+H5_DLLVAR hid_t H5E_CANTDEC_g; /* Unable to decrement reference count */
+H5_DLLVAR hid_t H5E_NOIDS_g; /* Out of IDs for group */
+
+/* Cache related errors */
+#define H5E_CANTFLUSH (H5OPEN H5E_CANTFLUSH_g)
+#define H5E_CANTUNSERIALIZE (H5OPEN H5E_CANTUNSERIALIZE_g)
+#define H5E_CANTSERIALIZE (H5OPEN H5E_CANTSERIALIZE_g)
+#define H5E_CANTTAG (H5OPEN H5E_CANTTAG_g)
+#define H5E_CANTLOAD (H5OPEN H5E_CANTLOAD_g)
+#define H5E_PROTECT (H5OPEN H5E_PROTECT_g)
+#define H5E_NOTCACHED (H5OPEN H5E_NOTCACHED_g)
+#define H5E_SYSTEM (H5OPEN H5E_SYSTEM_g)
+#define H5E_CANTINS (H5OPEN H5E_CANTINS_g)
+#define H5E_CANTPROTECT (H5OPEN H5E_CANTPROTECT_g)
+#define H5E_CANTUNPROTECT (H5OPEN H5E_CANTUNPROTECT_g)
+#define H5E_CANTPIN (H5OPEN H5E_CANTPIN_g)
+#define H5E_CANTUNPIN (H5OPEN H5E_CANTUNPIN_g)
+#define H5E_CANTMARKDIRTY (H5OPEN H5E_CANTMARKDIRTY_g)
+#define H5E_CANTMARKCLEAN (H5OPEN H5E_CANTMARKCLEAN_g)
+#define H5E_CANTMARKUNSERIALIZED (H5OPEN H5E_CANTMARKUNSERIALIZED_g)
+#define H5E_CANTMARKSERIALIZED (H5OPEN H5E_CANTMARKSERIALIZED_g)
+#define H5E_CANTDIRTY (H5OPEN H5E_CANTDIRTY_g)
+#define H5E_CANTCLEAN (H5OPEN H5E_CANTCLEAN_g)
+#define H5E_CANTEXPUNGE (H5OPEN H5E_CANTEXPUNGE_g)
+#define H5E_CANTRESIZE (H5OPEN H5E_CANTRESIZE_g)
+#define H5E_CANTDEPEND (H5OPEN H5E_CANTDEPEND_g)
+#define H5E_CANTUNDEPEND (H5OPEN H5E_CANTUNDEPEND_g)
+#define H5E_CANTNOTIFY (H5OPEN H5E_CANTNOTIFY_g)
+#define H5E_LOGFAIL (H5OPEN H5E_LOGFAIL_g)
+#define H5E_CANTCORK (H5OPEN H5E_CANTCORK_g)
+#define H5E_CANTUNCORK (H5OPEN H5E_CANTUNCORK_g)
+H5_DLLVAR hid_t H5E_CANTFLUSH_g; /* Unable to flush data from cache */
+H5_DLLVAR hid_t H5E_CANTUNSERIALIZE_g; /* Unable to mark metadata as unserialized */
+H5_DLLVAR hid_t H5E_CANTSERIALIZE_g; /* Unable to serialize data from cache */
+H5_DLLVAR hid_t H5E_CANTTAG_g; /* Unable to tag metadata in the cache */
+H5_DLLVAR hid_t H5E_CANTLOAD_g; /* Unable to load metadata into cache */
+H5_DLLVAR hid_t H5E_PROTECT_g; /* Protected metadata error */
+H5_DLLVAR hid_t H5E_NOTCACHED_g; /* Metadata not currently cached */
+H5_DLLVAR hid_t H5E_SYSTEM_g; /* Internal error detected */
+H5_DLLVAR hid_t H5E_CANTINS_g; /* Unable to insert metadata into cache */
+H5_DLLVAR hid_t H5E_CANTPROTECT_g; /* Unable to protect metadata */
+H5_DLLVAR hid_t H5E_CANTUNPROTECT_g; /* Unable to unprotect metadata */
+H5_DLLVAR hid_t H5E_CANTPIN_g; /* Unable to pin cache entry */
+H5_DLLVAR hid_t H5E_CANTUNPIN_g; /* Unable to un-pin cache entry */
+H5_DLLVAR hid_t H5E_CANTMARKDIRTY_g; /* Unable to mark a pinned entry as dirty */
+H5_DLLVAR hid_t H5E_CANTMARKCLEAN_g; /* Unable to mark a pinned entry as clean */
+H5_DLLVAR hid_t H5E_CANTMARKUNSERIALIZED_g; /* Unable to mark an entry as unserialized */
+H5_DLLVAR hid_t H5E_CANTMARKSERIALIZED_g; /* Unable to mark an entry as serialized */
+H5_DLLVAR hid_t H5E_CANTDIRTY_g; /* Unable to mark metadata as dirty */
+H5_DLLVAR hid_t H5E_CANTCLEAN_g; /* Unable to mark metadata as clean */
+H5_DLLVAR hid_t H5E_CANTEXPUNGE_g; /* Unable to expunge a metadata cache entry */
+H5_DLLVAR hid_t H5E_CANTRESIZE_g; /* Unable to resize a metadata cache entry */
+H5_DLLVAR hid_t H5E_CANTDEPEND_g; /* Unable to create a flush dependency */
+H5_DLLVAR hid_t H5E_CANTUNDEPEND_g; /* Unable to destroy a flush dependency */
+H5_DLLVAR hid_t H5E_CANTNOTIFY_g; /* Unable to notify object about action */
+H5_DLLVAR hid_t H5E_LOGFAIL_g; /* Failure in the cache logging framework */
+H5_DLLVAR hid_t H5E_CANTCORK_g; /* Unable to cork an object */
+H5_DLLVAR hid_t H5E_CANTUNCORK_g; /* Unable to uncork an object */
+
+/* Link related errors */
+#define H5E_TRAVERSE (H5OPEN H5E_TRAVERSE_g)
+#define H5E_NLINKS (H5OPEN H5E_NLINKS_g)
+#define H5E_NOTREGISTERED (H5OPEN H5E_NOTREGISTERED_g)
+#define H5E_CANTMOVE (H5OPEN H5E_CANTMOVE_g)
+#define H5E_CANTSORT (H5OPEN H5E_CANTSORT_g)
+H5_DLLVAR hid_t H5E_TRAVERSE_g; /* Link traversal failure */
+H5_DLLVAR hid_t H5E_NLINKS_g; /* Too many soft links in path */
+H5_DLLVAR hid_t H5E_NOTREGISTERED_g; /* Link class not registered */
+H5_DLLVAR hid_t H5E_CANTMOVE_g; /* Can't move object */
+H5_DLLVAR hid_t H5E_CANTSORT_g; /* Can't sort objects */
+
+/* Parallel MPI errors */
+#define H5E_MPI (H5OPEN H5E_MPI_g)
+#define H5E_MPIERRSTR (H5OPEN H5E_MPIERRSTR_g)
+#define H5E_CANTRECV (H5OPEN H5E_CANTRECV_g)
+H5_DLLVAR hid_t H5E_MPI_g; /* Some MPI function failed */
+H5_DLLVAR hid_t H5E_MPIERRSTR_g; /* MPI Error String */
+H5_DLLVAR hid_t H5E_CANTRECV_g; /* Can't receive data */
+
+/* Dataspace errors */
+#define H5E_CANTCLIP (H5OPEN H5E_CANTCLIP_g)
+#define H5E_CANTCOUNT (H5OPEN H5E_CANTCOUNT_g)
+#define H5E_CANTSELECT (H5OPEN H5E_CANTSELECT_g)
+#define H5E_CANTNEXT (H5OPEN H5E_CANTNEXT_g)
+#define H5E_BADSELECT (H5OPEN H5E_BADSELECT_g)
+#define H5E_CANTCOMPARE (H5OPEN H5E_CANTCOMPARE_g)
+#define H5E_CANTAPPEND (H5OPEN H5E_CANTAPPEND_g)
+H5_DLLVAR hid_t H5E_CANTCLIP_g; /* Can't clip hyperslab region */
+H5_DLLVAR hid_t H5E_CANTCOUNT_g; /* Can't count elements */
+H5_DLLVAR hid_t H5E_CANTSELECT_g; /* Can't select hyperslab */
+H5_DLLVAR hid_t H5E_CANTNEXT_g; /* Can't move to next iterator location */
+H5_DLLVAR hid_t H5E_BADSELECT_g; /* Invalid selection */
+H5_DLLVAR hid_t H5E_CANTCOMPARE_g; /* Can't compare objects */
+H5_DLLVAR hid_t H5E_CANTAPPEND_g; /* Can't append object */
+
+/* Argument errors */
+#define H5E_UNINITIALIZED (H5OPEN H5E_UNINITIALIZED_g)
+#define H5E_UNSUPPORTED (H5OPEN H5E_UNSUPPORTED_g)
+#define H5E_BADTYPE (H5OPEN H5E_BADTYPE_g)
+#define H5E_BADRANGE (H5OPEN H5E_BADRANGE_g)
+#define H5E_BADVALUE (H5OPEN H5E_BADVALUE_g)
+H5_DLLVAR hid_t H5E_UNINITIALIZED_g; /* Information is uinitialized */
+H5_DLLVAR hid_t H5E_UNSUPPORTED_g; /* Feature is unsupported */
+H5_DLLVAR hid_t H5E_BADTYPE_g; /* Inappropriate type */
+H5_DLLVAR hid_t H5E_BADRANGE_g; /* Out of range */
+H5_DLLVAR hid_t H5E_BADVALUE_g; /* Bad value */
+
+/* B-tree related errors */
+#define H5E_NOTFOUND (H5OPEN H5E_NOTFOUND_g)
+#define H5E_EXISTS (H5OPEN H5E_EXISTS_g)
+#define H5E_CANTENCODE (H5OPEN H5E_CANTENCODE_g)
+#define H5E_CANTDECODE (H5OPEN H5E_CANTDECODE_g)
+#define H5E_CANTSPLIT (H5OPEN H5E_CANTSPLIT_g)
+#define H5E_CANTREDISTRIBUTE (H5OPEN H5E_CANTREDISTRIBUTE_g)
+#define H5E_CANTSWAP (H5OPEN H5E_CANTSWAP_g)
+#define H5E_CANTINSERT (H5OPEN H5E_CANTINSERT_g)
+#define H5E_CANTLIST (H5OPEN H5E_CANTLIST_g)
+#define H5E_CANTMODIFY (H5OPEN H5E_CANTMODIFY_g)
+#define H5E_CANTREMOVE (H5OPEN H5E_CANTREMOVE_g)
+H5_DLLVAR hid_t H5E_NOTFOUND_g; /* Object not found */
+H5_DLLVAR hid_t H5E_EXISTS_g; /* Object already exists */
+H5_DLLVAR hid_t H5E_CANTENCODE_g; /* Unable to encode value */
+H5_DLLVAR hid_t H5E_CANTDECODE_g; /* Unable to decode value */
+H5_DLLVAR hid_t H5E_CANTSPLIT_g; /* Unable to split node */
+H5_DLLVAR hid_t H5E_CANTREDISTRIBUTE_g; /* Unable to redistribute records */
+H5_DLLVAR hid_t H5E_CANTSWAP_g; /* Unable to swap records */
+H5_DLLVAR hid_t H5E_CANTINSERT_g; /* Unable to insert object */
+H5_DLLVAR hid_t H5E_CANTLIST_g; /* Unable to list node */
+H5_DLLVAR hid_t H5E_CANTMODIFY_g; /* Unable to modify record */
+H5_DLLVAR hid_t H5E_CANTREMOVE_g; /* Unable to remove object */
+
+/* Datatype conversion errors */
+#define H5E_CANTCONVERT (H5OPEN H5E_CANTCONVERT_g)
+#define H5E_BADSIZE (H5OPEN H5E_BADSIZE_g)
+H5_DLLVAR hid_t H5E_CANTCONVERT_g; /* Can't convert datatypes */
+H5_DLLVAR hid_t H5E_BADSIZE_g; /* Bad size for object */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H5Epubgen_H */
diff --git a/src/H5Epublic.h b/src/H5Epublic.h
new file mode 100644
index 0000000..3eae2da
--- /dev/null
+++ b/src/H5Epublic.h
@@ -0,0 +1,226 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5E module.
+ */
+#ifndef _H5Epublic_H
+#define _H5Epublic_H
+
+#include <stdio.h> /*FILE arg of H5Eprint() */
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Ipublic.h"
+
+/* Value for the default error stack */
+#define H5E_DEFAULT (hid_t)0
+
+/* Different kinds of error information */
+typedef enum H5E_type_t {
+ H5E_MAJOR,
+ H5E_MINOR
+} H5E_type_t;
+
+/* Information about an error; element of error stack */
+typedef struct H5E_error2_t {
+ hid_t cls_id; /*class ID */
+ hid_t maj_num; /*major error ID */
+ hid_t min_num; /*minor error number */
+ unsigned line; /*line in file where error occurs */
+ const char *func_name; /*function in which error occurred */
+ const char *file_name; /*file in which error occurred */
+ const char *desc; /*optional supplied description */
+} H5E_error2_t;
+
+/* When this header is included from a private header, don't make calls to H5open() */
+#undef H5OPEN
+#ifndef _H5private_H
+#define H5OPEN H5open(),
+#else /* _H5private_H */
+#define H5OPEN
+#endif /* _H5private_H */
+
+/* HDF5 error class */
+#define H5E_ERR_CLS (H5OPEN H5E_ERR_CLS_g)
+H5_DLLVAR hid_t H5E_ERR_CLS_g;
+
+/* Include the automatically generated public header information */
+/* (This includes the list of major and minor error codes for the library) */
+#include "H5Epubgen.h"
+
+/*
+ * One often needs to temporarily disable automatic error reporting when
+ * trying something that's likely or expected to fail. The code to try can
+ * be nested between calls to H5Eget_auto() and H5Eset_auto(), but it's
+ * easier just to use this macro like:
+ * H5E_BEGIN_TRY {
+ * ...stuff here that's likely to fail...
+ * } H5E_END_TRY;
+ *
+ * Warning: don't break, return, or longjmp() from the body of the loop or
+ * the error reporting won't be properly restored!
+ *
+ * These two macros still use the old API functions for backward compatibility
+ * purpose.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+#define H5E_BEGIN_TRY { \
+ unsigned H5E_saved_is_v2; \
+ union { \
+ H5E_auto1_t efunc1; \
+ H5E_auto2_t efunc2; \
+ } H5E_saved; \
+ void *H5E_saved_edata; \
+ \
+ (void)H5Eauto_is_v2(H5E_DEFAULT, &H5E_saved_is_v2); \
+ if(H5E_saved_is_v2) { \
+ (void)H5Eget_auto2(H5E_DEFAULT, &H5E_saved.efunc2, &H5E_saved_edata); \
+ (void)H5Eset_auto2(H5E_DEFAULT, NULL, NULL); \
+ } else { \
+ (void)H5Eget_auto1(&H5E_saved.efunc1, &H5E_saved_edata); \
+ (void)H5Eset_auto1(NULL, NULL); \
+ }
+
+#define H5E_END_TRY \
+ if(H5E_saved_is_v2) \
+ (void)H5Eset_auto2(H5E_DEFAULT, H5E_saved.efunc2, H5E_saved_edata); \
+ else \
+ (void)H5Eset_auto1(H5E_saved.efunc1, H5E_saved_edata); \
+}
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+#define H5E_BEGIN_TRY { \
+ H5E_auto_t saved_efunc; \
+ void *H5E_saved_edata; \
+ \
+ (void)H5Eget_auto(H5E_DEFAULT, &saved_efunc, &H5E_saved_edata); \
+ (void)H5Eset_auto(H5E_DEFAULT, NULL, NULL);
+
+#define H5E_END_TRY \
+ (void)H5Eset_auto(H5E_DEFAULT, saved_efunc, H5E_saved_edata); \
+}
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/*
+ * Public API Convenience Macros for Error reporting - Documented
+ */
+/* Use the Standard C __FILE__ & __LINE__ macros instead of typing them in */
+#define H5Epush_sim(func, cls, maj, min, str) H5Epush2(H5E_DEFAULT, __FILE__, func, __LINE__, cls, maj, min, str)
+
+/*
+ * Public API Convenience Macros for Error reporting - Undocumented
+ */
+/* Use the Standard C __FILE__ & __LINE__ macros instead of typing them in */
+/* And return after pushing error onto stack */
+#define H5Epush_ret(func, cls, maj, min, str, ret) { \
+ H5Epush2(H5E_DEFAULT, __FILE__, func, __LINE__, cls, maj, min, str); \
+ return(ret); \
+}
+
+/* Use the Standard C __FILE__ & __LINE__ macros instead of typing them in
+ * And goto a label after pushing error onto stack.
+ */
+#define H5Epush_goto(func, cls, maj, min, str, label) { \
+ H5Epush2(H5E_DEFAULT, __FILE__, func, __LINE__, cls, maj, min, str); \
+ goto label; \
+}
+
+/* Error stack traversal direction */
+typedef enum H5E_direction_t {
+ H5E_WALK_UPWARD = 0, /*begin deep, end at API function */
+ H5E_WALK_DOWNWARD = 1 /*begin at API function, end deep */
+} H5E_direction_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Error stack traversal callback function pointers */
+typedef herr_t (*H5E_walk2_t)(unsigned n, const H5E_error2_t *err_desc,
+ void *client_data);
+typedef herr_t (*H5E_auto2_t)(hid_t estack, void *client_data);
+
+/* Public API functions */
+H5_DLL hid_t H5Eregister_class(const char *cls_name, const char *lib_name,
+ const char *version);
+H5_DLL herr_t H5Eunregister_class(hid_t class_id);
+H5_DLL herr_t H5Eclose_msg(hid_t err_id);
+H5_DLL hid_t H5Ecreate_msg(hid_t cls, H5E_type_t msg_type, const char *msg);
+H5_DLL hid_t H5Ecreate_stack(void);
+H5_DLL hid_t H5Eget_current_stack(void);
+H5_DLL herr_t H5Eclose_stack(hid_t stack_id);
+H5_DLL ssize_t H5Eget_class_name(hid_t class_id, char *name, size_t size);
+H5_DLL herr_t H5Eset_current_stack(hid_t err_stack_id);
+H5_DLL herr_t H5Epush2(hid_t err_stack, const char *file, const char *func, unsigned line,
+ hid_t cls_id, hid_t maj_id, hid_t min_id, const char *msg, ...);
+H5_DLL herr_t H5Epop(hid_t err_stack, size_t count);
+H5_DLL herr_t H5Eprint2(hid_t err_stack, FILE *stream);
+H5_DLL herr_t H5Ewalk2(hid_t err_stack, H5E_direction_t direction, H5E_walk2_t func,
+ void *client_data);
+H5_DLL herr_t H5Eget_auto2(hid_t estack_id, H5E_auto2_t *func, void **client_data);
+H5_DLL herr_t H5Eset_auto2(hid_t estack_id, H5E_auto2_t func, void *client_data);
+H5_DLL herr_t H5Eclear2(hid_t err_stack);
+H5_DLL herr_t H5Eauto_is_v2(hid_t err_stack, unsigned *is_stack);
+H5_DLL ssize_t H5Eget_msg(hid_t msg_id, H5E_type_t *type, char *msg,
+ size_t size);
+H5_DLL ssize_t H5Eget_num(hid_t error_stack_id);
+
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Typedefs */
+
+/* Alias major & minor error types to hid_t's, for compatibility with new
+ * error API in v1.8
+ */
+typedef hid_t H5E_major_t;
+typedef hid_t H5E_minor_t;
+
+/* Information about an error element of error stack. */
+typedef struct H5E_error1_t {
+ H5E_major_t maj_num; /*major error number */
+ H5E_minor_t min_num; /*minor error number */
+ const char *func_name; /*function in which error occurred */
+ const char *file_name; /*file in which error occurred */
+ unsigned line; /*line in file where error occurs */
+ const char *desc; /*optional supplied description */
+} H5E_error1_t;
+
+/* Error stack traversal callback function pointers */
+typedef herr_t (*H5E_walk1_t)(int n, H5E_error1_t *err_desc, void *client_data);
+typedef herr_t (*H5E_auto1_t)(void *client_data);
+
+/* Function prototypes */
+H5_DLL herr_t H5Eclear1(void);
+H5_DLL herr_t H5Eget_auto1(H5E_auto1_t *func, void **client_data);
+H5_DLL herr_t H5Epush1(const char *file, const char *func, unsigned line,
+ H5E_major_t maj, H5E_minor_t min, const char *str);
+H5_DLL herr_t H5Eprint1(FILE *stream);
+H5_DLL herr_t H5Eset_auto1(H5E_auto1_t func, void *client_data);
+H5_DLL herr_t H5Ewalk1(H5E_direction_t direction, H5E_walk1_t func,
+ void *client_data);
+H5_DLL char *H5Eget_major(H5E_major_t maj);
+H5_DLL char *H5Eget_minor(H5E_minor_t min);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end _H5Epublic_H */
+
diff --git a/src/H5Eterm.h b/src/H5Eterm.h
new file mode 100644
index 0000000..f0503c4
--- /dev/null
+++ b/src/H5Eterm.h
@@ -0,0 +1,232 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_err -- do not edit */
+/* Add new errors to H5err.txt file */
+
+
+#ifndef _H5Eterm_H
+#define _H5Eterm_H
+
+/* Reset major error IDs */
+
+H5E_FUNC_g=
+H5E_FILE_g=
+H5E_SOHM_g=
+H5E_SYM_g=
+H5E_PLUGIN_g=
+H5E_VFL_g=
+H5E_INTERNAL_g=
+H5E_BTREE_g=
+H5E_REFERENCE_g=
+H5E_DATASPACE_g=
+H5E_RESOURCE_g=
+H5E_RS_g=
+H5E_FARRAY_g=
+H5E_HEAP_g=
+H5E_ATTR_g=
+H5E_IO_g=
+H5E_EFL_g=
+H5E_TST_g=
+H5E_PAGEBUF_g=
+H5E_FSPACE_g=
+H5E_DATASET_g=
+H5E_STORAGE_g=
+H5E_LINK_g=
+H5E_PLIST_g=
+H5E_DATATYPE_g=
+H5E_OHDR_g=
+H5E_ATOM_g=
+H5E_NONE_MAJOR_g=
+H5E_SLIST_g=
+H5E_ARGS_g=
+H5E_EARRAY_g=
+H5E_PLINE_g=
+H5E_ERROR_g=
+H5E_CACHE_g= (-1);
+
+/* Reset minor error IDs */
+
+
+/* Generic low-level file I/O errors */
+H5E_SEEKERROR_g=
+H5E_READERROR_g=
+H5E_WRITEERROR_g=
+H5E_CLOSEERROR_g=
+H5E_OVERFLOW_g=
+H5E_FCNTL_g=
+
+/* Resource errors */
+H5E_NOSPACE_g=
+H5E_CANTALLOC_g=
+H5E_CANTCOPY_g=
+H5E_CANTFREE_g=
+H5E_ALREADYEXISTS_g=
+H5E_CANTLOCK_g=
+H5E_CANTUNLOCK_g=
+H5E_CANTGC_g=
+H5E_CANTGETSIZE_g=
+H5E_OBJOPEN_g=
+
+/* Heap errors */
+H5E_CANTRESTORE_g=
+H5E_CANTCOMPUTE_g=
+H5E_CANTEXTEND_g=
+H5E_CANTATTACH_g=
+H5E_CANTUPDATE_g=
+H5E_CANTOPERATE_g=
+
+/* Function entry/exit interface errors */
+H5E_CANTINIT_g=
+H5E_ALREADYINIT_g=
+H5E_CANTRELEASE_g=
+
+/* Property list errors */
+H5E_CANTGET_g=
+H5E_CANTSET_g=
+H5E_DUPCLASS_g=
+H5E_SETDISALLOWED_g=
+
+/* Free space errors */
+H5E_CANTMERGE_g=
+H5E_CANTREVIVE_g=
+H5E_CANTSHRINK_g=
+
+/* Object header related errors */
+H5E_LINKCOUNT_g=
+H5E_VERSION_g=
+H5E_ALIGNMENT_g=
+H5E_BADMESG_g=
+H5E_CANTDELETE_g=
+H5E_BADITER_g=
+H5E_CANTPACK_g=
+H5E_CANTRESET_g=
+H5E_CANTRENAME_g=
+
+/* System level errors */
+H5E_SYSERRSTR_g=
+
+/* I/O pipeline errors */
+H5E_NOFILTER_g=
+H5E_CALLBACK_g=
+H5E_CANAPPLY_g=
+H5E_SETLOCAL_g=
+H5E_NOENCODER_g=
+H5E_CANTFILTER_g=
+
+/* Group related errors */
+H5E_CANTOPENOBJ_g=
+H5E_CANTCLOSEOBJ_g=
+H5E_COMPLEN_g=
+H5E_PATH_g=
+
+/* No error */
+H5E_NONE_MINOR_g=
+
+/* Plugin errors */
+H5E_OPENERROR_g=
+
+/* File accessibilty errors */
+H5E_FILEEXISTS_g=
+H5E_FILEOPEN_g=
+H5E_CANTCREATE_g=
+H5E_CANTOPENFILE_g=
+H5E_CANTCLOSEFILE_g=
+H5E_NOTHDF5_g=
+H5E_BADFILE_g=
+H5E_TRUNCATED_g=
+H5E_MOUNT_g=
+
+/* Object atom related errors */
+H5E_BADATOM_g=
+H5E_BADGROUP_g=
+H5E_CANTREGISTER_g=
+H5E_CANTINC_g=
+H5E_CANTDEC_g=
+H5E_NOIDS_g=
+
+/* Cache related errors */
+H5E_CANTFLUSH_g=
+H5E_CANTUNSERIALIZE_g=
+H5E_CANTSERIALIZE_g=
+H5E_CANTTAG_g=
+H5E_CANTLOAD_g=
+H5E_PROTECT_g=
+H5E_NOTCACHED_g=
+H5E_SYSTEM_g=
+H5E_CANTINS_g=
+H5E_CANTPROTECT_g=
+H5E_CANTUNPROTECT_g=
+H5E_CANTPIN_g=
+H5E_CANTUNPIN_g=
+H5E_CANTMARKDIRTY_g=
+H5E_CANTMARKCLEAN_g=
+H5E_CANTMARKUNSERIALIZED_g=
+H5E_CANTMARKSERIALIZED_g=
+H5E_CANTDIRTY_g=
+H5E_CANTCLEAN_g=
+H5E_CANTEXPUNGE_g=
+H5E_CANTRESIZE_g=
+H5E_CANTDEPEND_g=
+H5E_CANTUNDEPEND_g=
+H5E_CANTNOTIFY_g=
+H5E_LOGFAIL_g=
+H5E_CANTCORK_g=
+H5E_CANTUNCORK_g=
+
+/* Link related errors */
+H5E_TRAVERSE_g=
+H5E_NLINKS_g=
+H5E_NOTREGISTERED_g=
+H5E_CANTMOVE_g=
+H5E_CANTSORT_g=
+
+/* Parallel MPI errors */
+H5E_MPI_g=
+H5E_MPIERRSTR_g=
+H5E_CANTRECV_g=
+
+/* Dataspace errors */
+H5E_CANTCLIP_g=
+H5E_CANTCOUNT_g=
+H5E_CANTSELECT_g=
+H5E_CANTNEXT_g=
+H5E_BADSELECT_g=
+H5E_CANTCOMPARE_g=
+H5E_CANTAPPEND_g=
+
+/* Argument errors */
+H5E_UNINITIALIZED_g=
+H5E_UNSUPPORTED_g=
+H5E_BADTYPE_g=
+H5E_BADRANGE_g=
+H5E_BADVALUE_g=
+
+/* B-tree related errors */
+H5E_NOTFOUND_g=
+H5E_EXISTS_g=
+H5E_CANTENCODE_g=
+H5E_CANTDECODE_g=
+H5E_CANTSPLIT_g=
+H5E_CANTREDISTRIBUTE_g=
+H5E_CANTSWAP_g=
+H5E_CANTINSERT_g=
+H5E_CANTLIST_g=
+H5E_CANTMODIFY_g=
+H5E_CANTREMOVE_g=
+
+/* Datatype conversion errors */
+H5E_CANTCONVERT_g=
+H5E_BADSIZE_g= (-1);
+
+#endif /* H5Eterm_H */
diff --git a/src/H5F.c b/src/H5F.c
new file mode 100644
index 0000000..78fce2a
--- /dev/null
+++ b/src/H5F.c
@@ -0,0 +1,2126 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Aprivate.h" /* Attributes */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+#include "H5Tprivate.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/* File ID class */
+static const H5I_class_t H5I_FILE_CLS[1] = {{
+ H5I_FILE, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5F_close /* Callback routine for closing objects of this class */
+}};
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5F__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5F__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t
+H5F__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Initialize the atom group for the file IDs.
+ */
+ if(H5I_register_type(H5I_FILE_CLS) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_term_package
+ *
+ * Purpose: Terminate this interface: free all memory and reset global
+ * variables to their initial values. Release all ID groups
+ * associated with this interface.
+ *
+ * Return: Success: Positive if anything was done that might
+ * have affected other interfaces; zero
+ * otherwise.
+ *
+ * Failure: Never fails.
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5F_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ if(H5I_nmembers(H5I_FILE) > 0) {
+ (void)H5I_clear_type(H5I_FILE, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+ else {
+ /* Make certain we've cleaned up all the shared file objects */
+ H5F_sfile_assert_num(0);
+
+ /* Destroy the file object id group */
+ n += (H5I_dec_type_ref(H5I_FILE) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5F_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_create_plist
+ *
+ * Purpose: Get an atom for a copy of the file-creation property list for
+ * this file. This function returns an atom with a copy of the
+ * properties used to create a file.
+ *
+ * Return: Success: template ID
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Fget_create_plist(hid_t file_id)
+{
+ H5F_t *file; /* File info */
+ H5P_genplist_t *plist; /* Property list */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", file_id);
+
+ /* check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(file->shared->fcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Create the property list object to return */
+ if((ret_value = H5P_copy_plist(plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, "unable to copy file creation properties")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_access_plist
+ *
+ * Purpose: Returns a copy of the file access property list of the
+ * specified file.
+ *
+ * NOTE: Make sure that, if you are going to overwrite
+ * information in the copied property list that was
+ * previously opened and assigned to the property list, then
+ * you must close it before overwriting the values.
+ *
+ * Return: Success: Object ID for a copy of the file access
+ * property list.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, February 18, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Fget_access_plist(hid_t file_id)
+{
+ H5F_t *f; /* File info */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", file_id);
+
+ /* Check args */
+ if(NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Retrieve the file's access property list */
+ if((ret_value = H5F_get_access_plist(f, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file access property list")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_access_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_obj_count
+ *
+ * Purpose: Public function returning the number of opened object IDs
+ * (files, datasets, groups and datatypes) in the same file.
+ *
+ * Return: Non-negative on success; negative on failure.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_obj_count(hid_t file_id, unsigned types)
+{
+ H5F_t *f = NULL; /* File to query */
+ size_t obj_count = 0; /* Number of opened objects */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("Zs", "iIu", file_id, types);
+
+ /* Check arguments */
+ if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
+ if(0 == (types & H5F_OBJ_ALL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type")
+
+ /* Perform the query */
+ if(H5F_get_obj_count(f, types, TRUE, &obj_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+
+ /* Set the return value */
+ ret_value = (ssize_t)obj_count;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_obj_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_object_ids
+ *
+ * Purpose: Public function to return a list of opened object IDs.
+ *
+ * Return: Non-negative on success; negative on failure.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ * Modification:
+ * Raymond Lu
+ * 24 September 2008
+ * Changed the return value to ssize_t and MAX_OBJTS to size_t to
+ * accommadate potential large number of objects.
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_obj_ids(hid_t file_id, unsigned types, size_t max_objs, hid_t *oid_list)
+{
+ H5F_t *f = NULL; /* File to query */
+ size_t obj_id_count = 0; /* Number of open objects */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "iIuz*i", file_id, types, max_objs, oid_list);
+
+ /* Check arguments */
+ if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
+ if(0 == (types & H5F_OBJ_ALL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type")
+ if(!oid_list)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "object ID list is NULL")
+
+ /* Perform the query */
+ if(H5F_get_obj_ids(f, types, max_objs, oid_list, TRUE, &obj_id_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed")
+
+ /* Set the return value */
+ ret_value = (ssize_t)obj_id_count;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_obj_ids() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_vfd_handle
+ *
+ * Purpose: Returns a pointer to the file handle of the low-level file
+ * driver.
+ *
+ * Return: Success: non-negative value.
+ * Failure: negative.
+ *
+ * Programmer: Raymond Lu
+ * Sep. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle)
+{
+ H5F_t *file; /* File to query */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii**x", file_id, fapl, file_handle);
+
+ /* Check args */
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file handle pointer")
+
+ /* Get the file */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
+
+ /* Retrieve the VFD handle for the file */
+ if(H5F_get_vfd_handle(file, fapl, file_handle) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve VFD handle")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_vfd_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fis_hdf5
+ *
+ * Purpose: Check the file signature to detect an HDF5 file.
+ *
+ * Bugs: This function is not robust: it only uses the default file
+ * driver when attempting to open the file when in fact it
+ * should use all known file drivers.
+ *
+ * Return: Success: TRUE/FALSE
+ *
+ * Failure: Negative
+ *
+ * Programmer: Unknown
+ *
+ * Modifications:
+ * Robb Matzke, 1999-08-02
+ * Rewritten to use the virtual file layer.
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Fis_hdf5(const char *name)
+{
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "*s", name);
+
+ /* Check args and all the boring stuff. */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "no file name specified")
+
+ /* call the private is_HDF5 function */
+ if((ret_value = H5F__is_hdf5(name, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_NOTHDF5, FAIL, "unable open file")
+
+done:
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fis_hdf5() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fcreate
+ *
+ * Purpose: This is the primary function for creating HDF5 files . The
+ * flags parameter determines whether an existing file will be
+ * overwritten or not. All newly created files are opened for
+ * both reading and writing. All flags may be combined with the
+ * bit-wise OR operator (`|') to change the behavior of the file
+ * create call.
+ *
+ * The more complex behaviors of a file's creation and access
+ * are controlled through the file-creation and file-access
+ * property lists. The value of H5P_DEFAULT for a template
+ * value indicates that the library should use the default
+ * values for the appropriate template.
+ *
+ * See also: H5Fpublic.h for the list of supported flags. H5Ppublic.h for
+ * the list of file creation and file access properties.
+ *
+ * Return: Success: A file ID
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id)
+{
+ hbool_t ci_load = FALSE; /* whether MDC ci load requested */
+ hbool_t ci_write = FALSE; /* whether MDC CI write requested */
+ H5F_t *new_file = NULL; /*file struct for new file */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /*dxpl used by library */
+ hid_t ret_value; /*return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("i", "*sIuii", filename, flags, fcpl_id, fapl_id);
+
+ /* Check/fix arguments */
+ if(!filename || !*filename)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file name")
+ /* In this routine, we only accept the following flags:
+ * H5F_ACC_EXCL, H5F_ACC_TRUNC and H5F_ACC_SWMR_WRITE
+ */
+ if(flags & ~(H5F_ACC_EXCL | H5F_ACC_TRUNC | H5F_ACC_SWMR_WRITE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
+ /* The H5F_ACC_EXCL and H5F_ACC_TRUNC flags are mutually exclusive */
+ if((flags & H5F_ACC_EXCL) && (flags & H5F_ACC_TRUNC))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mutually exclusive flags for file creation")
+
+ /* Check file creation property list */
+ if(H5P_DEFAULT == fcpl_id)
+ fcpl_id = H5P_FILE_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(fcpl_id, H5P_FILE_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not file create property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&fapl_id, H5P_CLS_FACC, &dxpl_id, H5I_INVALID_HID, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /*
+ * Adjust bit flags by turning on the creation bit and making sure that
+ * the EXCL or TRUNC bit is set. All newly-created files are opened for
+ * reading and writing.
+ */
+ if (0==(flags & (H5F_ACC_EXCL|H5F_ACC_TRUNC)))
+ flags |= H5F_ACC_EXCL; /*default*/
+ flags |= H5F_ACC_RDWR | H5F_ACC_CREAT;
+
+ /*
+ * Create a new file or truncate an existing file.
+ */
+ if(NULL == (new_file = H5F_open(filename, flags, fcpl_id, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to create file")
+
+ /* Check to see if both SWMR and cache image are requested. Fail if so */
+ if(H5C_cache_image_status(new_file, &ci_load, &ci_write) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MDC cache image status")
+ if((ci_load || ci_write) && (flags & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)))
+ HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and cache image")
+
+ /* Get an atom for the file */
+ if((ret_value = H5I_register(H5I_FILE, new_file, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file")
+
+ /* Keep this ID in file object structure */
+ new_file->file_id = ret_value;
+
+done:
+ if(ret_value < 0 && new_file && H5F_try_close(new_file, NULL) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fcreate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fopen
+ *
+ * Purpose: This is the primary function for accessing existing HDF5
+ * files. The FLAGS argument determines whether writing to an
+ * existing file will be allowed or not. All flags may be
+ * combined with the bit-wise OR operator (`|') to change the
+ * behavior of the file open call. The more complex behaviors
+ * of a file's access are controlled through the file-access
+ * property list.
+ *
+ * See Also: H5Fpublic.h for a list of possible values for FLAGS.
+ *
+ * Return: Success: A file ID
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Unknown
+ *
+ * Modifications:
+ * Robb Matzke, 1997-07-18
+ * File struct creation and destruction is through H5F_new() and
+ * H5F__dest(). Reading the root symbol table entry is done with
+ * H5G_decode().
+ *
+ * Robb Matzke, 1997-09-23
+ * Most of the work is now done by H5F_open() since H5Fcreate()
+ * and H5Fopen() originally contained almost identical code.
+ *
+ * Robb Matzke, 1998-02-18
+ * Added better error checking for the flags and the file access
+ * property list. It used to be possible to make the library
+ * dump core by passing an object ID that was not a file access
+ * property list.
+ *
+ * Robb Matzke, 1999-08-02
+ * The file access property list is passed to the H5F_open() as
+ * object IDs.
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Fopen(const char *filename, unsigned flags, hid_t fapl_id)
+{
+ hbool_t ci_load = FALSE; /* whether MDC ci load requested */
+ hbool_t ci_write = FALSE; /* whether MDC CI write requested */
+ H5F_t *new_file = NULL; /*file struct for new file */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /*dxpl used by library */
+ hid_t ret_value; /*return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "*sIui", filename, flags, fapl_id);
+
+ /* Check/fix arguments. */
+ if(!filename || !*filename)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file name")
+ /* Reject undefined flags (~H5F_ACC_PUBLIC_FLAGS) and the H5F_ACC_TRUNC & H5F_ACC_EXCL flags */
+ if((flags & ~H5F_ACC_PUBLIC_FLAGS) ||
+ (flags & H5F_ACC_TRUNC) || (flags & H5F_ACC_EXCL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+ /* Asking for SWMR write access on a read-only file is invalid */
+ if((flags & H5F_ACC_SWMR_WRITE) && 0 == (flags & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "SWMR write access on a file open for read-only access is not allowed")
+ /* Asking for SWMR read access on a non-read-only file is invalid */
+ if((flags & H5F_ACC_SWMR_READ) && (flags & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "SWMR read access on a file open for read-write access is not allowed")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&fapl_id, H5P_CLS_FACC, &dxpl_id, H5I_INVALID_HID, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the file */
+ if(NULL == (new_file = H5F_open(filename, flags, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to open file")
+
+ /* Check to see if both SWMR and cache image are requested. Fail if so */
+ if(H5C_cache_image_status(new_file, &ci_load, &ci_write) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MDC cache image status")
+ if((ci_load || ci_write) && (flags & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)))
+ HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and cache image")
+
+ /* Get an atom for the file */
+ if((ret_value = H5I_register(H5I_FILE, new_file, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle")
+
+ /* Keep this ID in file object structure */
+ new_file->file_id = ret_value;
+
+done:
+ if(ret_value < 0 && new_file && H5F_try_close(new_file, NULL) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fopen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fflush
+ *
+ * Purpose: Flushes all outstanding buffers of a file to disk but does
+ * not remove them from the cache. The OBJECT_ID can be a file,
+ * dataset, group, attribute, or named data type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fflush(hid_t object_id, H5F_scope_t scope)
+{
+ H5F_t *f = NULL; /* File to flush */
+ H5O_loc_t *oloc = NULL; /* Object location for ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iFs", object_id, scope);
+
+ switch(H5I_get_type(object_id)) {
+ case H5I_FILE:
+ if(NULL == (f = (H5F_t *)H5I_object(object_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier")
+ break;
+
+ case H5I_GROUP:
+ {
+ H5G_t *grp;
+
+ if(NULL == (grp = (H5G_t *)H5I_object(object_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid group identifier")
+ oloc = H5G_oloc(grp);
+ }
+ break;
+
+ case H5I_DATATYPE:
+ {
+ H5T_t *type;
+
+ if(NULL == (type = (H5T_t *)H5I_object(object_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid type identifier")
+ oloc = H5T_oloc(type);
+ }
+ break;
+
+ case H5I_DATASET:
+ {
+ H5D_t *dset;
+
+ if(NULL == (dset = (H5D_t *)H5I_object(object_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier")
+ oloc = H5D_oloc(dset);
+ }
+ break;
+
+ case H5I_ATTR:
+ {
+ H5A_t *attr;
+
+ if(NULL == (attr = (H5A_t *)H5I_object(object_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid attribute identifier")
+ oloc = H5A_oloc(attr);
+ }
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_DATASPACE:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file or file object")
+ } /* end switch */
+
+ if(!f) {
+ if(!oloc)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "object is not assocated with a file")
+ f = oloc->file;
+ } /* end if */
+ if(!f)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "object is not associated with a file")
+
+ /* Flush the file */
+ /*
+ * Nothing to do if the file is read only. This determination is
+ * made at the shared open(2) flags level, implying that opening a
+ * file twice, once for read-only and once for read-write, and then
+ * calling H5Fflush() with the read-only handle, still causes data
+ * to be flushed.
+ */
+ if(H5F_ACC_RDWR & H5F_INTENT(f)) {
+ /* Flush other files, depending on scope */
+ if(H5F_SCOPE_GLOBAL == scope) {
+ /* Call the flush routine for mounted file hierarchies */
+ if(H5F_flush_mounts(f, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush mounted file hierarchy")
+ } /* end if */
+ else {
+ /* Call the flush routine, for this file */
+ if(H5F__flush(f, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fflush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fclose
+ *
+ * Purpose: This function closes the file specified by FILE_ID by
+ * flushing all data to storage, and terminating access to the
+ * file through FILE_ID. If objects (e.g., datasets, groups,
+ * etc.) are open in the file then the underlying storage is not
+ * closed until those objects are closed; however, all data for
+ * the file and the open objects is flushed.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Saturday, February 20, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fclose(hid_t file_id)
+{
+ H5F_t *f = NULL;
+ int nref;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Check/fix arguments. */
+ if(H5I_FILE != H5I_get_type(file_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file ID")
+
+ /* Flush file if this is the last reference to this id and we have write
+ * intent, unless it will be flushed by the "shared" file being closed.
+ * This is only necessary to replicate previous behaviour, and could be
+ * disabled by an option/property to improve performance. */
+ if(NULL == (f = (H5F_t *)H5I_object(file_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier")
+ if((f->shared->nrefs > 1) && (H5F_INTENT(f) & H5F_ACC_RDWR)) {
+ if((nref = H5I_get_ref(file_id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count")
+ if(nref == 1)
+ if(H5F__flush(f, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
+ } /* end if */
+
+ /*
+ * Decrement reference count on atom. When it reaches zero the file will
+ * be closed.
+ */
+ if(H5I_dec_app_ref(file_id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEFILE, FAIL, "decrementing file ID failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Freopen
+ *
+ * Purpose: Reopen a file. The new file handle which is returned points
+ * to the same file as the specified file handle. Both handles
+ * share caches and other information. The only difference
+ * between the handles is that the new handle is not mounted
+ * anywhere and no files are mounted on it.
+ *
+ * Return: Success: New file ID
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Freopen(hid_t file_id)
+{
+ H5F_t *old_file = NULL;
+ H5F_t *new_file = NULL;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", file_id);
+
+ /* Check arguments */
+ if(NULL == (old_file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Get a new "top level" file struct, sharing the same "low level" file struct */
+ if(NULL == (new_file = H5F_new(old_file->shared, 0, H5P_FILE_CREATE_DEFAULT, H5P_FILE_ACCESS_DEFAULT, NULL)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to reopen file")
+
+ /* Duplicate old file's names */
+ new_file->open_name = H5MM_xstrdup(old_file->open_name);
+ new_file->actual_name = H5MM_xstrdup(old_file->actual_name);
+ new_file->extpath = H5MM_xstrdup(old_file->extpath);
+
+ if((ret_value = H5I_register(H5I_FILE, new_file, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle")
+
+ /* Keep this ID in file object structure */
+ new_file->file_id = ret_value;
+
+done:
+ if(ret_value < 0 && new_file)
+ if(H5F__dest(new_file, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, FALSE) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Freopen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_intent
+ *
+ * Purpose: Public API to retrieve the file's 'intent' flags passed
+ * during H5Fopen()
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * August 23, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_intent(hid_t file_id, unsigned *intent_flags)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", file_id, intent_flags);
+
+ /* If no intent flags were passed in, exit quietly */
+ if(intent_flags) {
+ H5F_t * file; /* Pointer to file structure */
+
+ /* Get the internal file structure */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* HDF5 uses some flags internally that users don't know about.
+ * Simplify things for them so that they only get either H5F_ACC_RDWR
+ * or H5F_ACC_RDONLY.
+ */
+ if(H5F_INTENT(file) & H5F_ACC_RDWR) {
+ *intent_flags = H5F_ACC_RDWR;
+
+ /* Check for SWMR write access on the file */
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_WRITE)
+ *intent_flags |= H5F_ACC_SWMR_WRITE;
+ } /* end if */
+ else {
+ *intent_flags = H5F_ACC_RDONLY;
+
+ /* Check for SWMR read access on the file */
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_READ)
+ *intent_flags |= H5F_ACC_SWMR_READ;
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_intent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_freespace
+ *
+ * Purpose: Retrieves the amount of free space in the file.
+ *
+ * Return: Success: Amount of free space for type
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hssize_t
+H5Fget_freespace(hid_t file_id)
+{
+ H5F_t *file; /* File object for file ID */
+ hsize_t tot_space; /* Amount of free space in the file */
+ hssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Hs", "i", file_id);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Go get the actual amount of free space in the file */
+ if(H5MF_get_freespace(file, H5AC_ind_read_dxpl_id, &tot_space, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to check free space for file")
+
+ ret_value = (hssize_t)tot_space;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_freespace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_filesize
+ *
+ * Purpose: Retrieves the file size of the HDF5 file. This function
+ * is called after an existing file is opened in order
+ * to learn the true size of the underlying file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: David Pitt
+ * david.pitt@bigpond.com
+ * Apr 27, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_filesize(hid_t file_id, hsize_t *size)
+{
+ H5F_t *file; /* File object for file ID */
+ haddr_t eof; /* End of file address */
+ haddr_t eoa; /* End of allocation address */
+ haddr_t max_eof_eoa; /* Maximum of the EOA & EOF */
+ haddr_t base_addr; /* Base address for the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", file_id, size);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Go get the actual file size */
+ eof = H5FD_get_eof(file->shared->lf, H5FD_MEM_DEFAULT);
+ eoa = H5FD_get_eoa(file->shared->lf, H5FD_MEM_DEFAULT);
+ max_eof_eoa = MAX(eof, eoa);
+ if(HADDR_UNDEF == max_eof_eoa)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "file get eof/eoa requests failed")
+ base_addr = H5FD_get_base_addr(file->shared->lf);
+
+ if(size)
+ *size = (hsize_t)(max_eof_eoa + base_addr); /* Convert relative base address for file to absolute address */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_filesize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_file_image
+ *
+ * Purpose: If a buffer is provided (via the buf_ptr argument) and is
+ * big enough (size in buf_len argument), load *buf_ptr with
+ * an image of the open file whose ID is provided in the
+ * file_id parameter, and return the number of bytes copied
+ * to the buffer.
+ *
+ * If the buffer exists, but is too small to contain an image
+ * of the indicated file, return a negative number.
+ *
+ * Finally, if no buffer is provided, return the size of the
+ * buffer needed. This value is simply the eoa of the target
+ * file.
+ *
+ * Note that any user block is skipped.
+ *
+ * Also note that the function may not be used on files
+ * opened with either the split/multi file driver or the
+ * family file driver.
+ *
+ * In the former case, the sparse address space makes the
+ * get file image operation impractical, due to the size of
+ * the image typically required.
+ *
+ * In the case of the family file driver, the problem is
+ * the driver message in the super block, which will prevent
+ * the image being opened with any driver other than the
+ * family file driver -- which negates the purpose of the
+ * operation. This can be fixed, but no resources for
+ * this now.
+ *
+ * Return: Success: Bytes copied / number of bytes needed.
+ * Failure: negative value
+ *
+ * Programmer: John Mainzer
+ * 11/15/11
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_file_image(hid_t file_id, void *buf_ptr, size_t buf_len)
+{
+ H5F_t *file; /* File object for file ID */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*xz", file_id, buf_ptr, buf_len);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* call private get_file_image function */
+ if((ret_value = H5F_get_file_image(file, buf_ptr, buf_len, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file image")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_file_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mdc_config
+ *
+ * Purpose: Retrieves the current automatic cache resize configuration
+ * from the metadata cache, and return it in *config_ptr.
+ *
+ * Note that the version field of *config_Ptr must be correctly
+ * filled in by the caller. This allows us to adapt for
+ * obsolete versions of the structure.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/24/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mdc_config(hid_t file_id, H5AC_cache_config_t *config_ptr)
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", file_id, config_ptr);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+ if((NULL == config_ptr) || (config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad config_ptr")
+
+ /* Go get the resize configuration */
+ if(H5AC_get_cache_auto_resize_config(file->shared->cache, config_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_get_cache_auto_resize_config() failed.")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_mdc_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fset_mdc_config
+ *
+ * Purpose: Sets the current metadata cache automatic resize
+ * configuration, using the contents of the instance of
+ * H5AC_cache_config_t pointed to by config_ptr.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/24/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fset_mdc_config(hid_t file_id, H5AC_cache_config_t *config_ptr)
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", file_id, config_ptr);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* set the resize configuration */
+ if(H5AC_set_cache_auto_resize_config(file->shared->cache, config_ptr) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "H5AC_set_cache_auto_resize_config() failed.")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fset_mdc_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mdc_hit_rate
+ *
+ * Purpose: Retrieves the current hit rate from the metadata cache.
+ * This rate is the overall hit rate since the last time
+ * the hit rate statistics were reset either manually or
+ * automatically.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/24/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mdc_hit_rate(hid_t file_id, double *hit_rate_ptr)
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*d", file_id, hit_rate_ptr);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ if(NULL == hit_rate_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL hit rate pointer")
+
+ /* Go get the current hit rate */
+ if(H5AC_get_cache_hit_rate(file->shared->cache, hit_rate_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_get_cache_hit_rate() failed.")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_mdc_hit_rate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mdc_size
+ *
+ * Purpose: Retrieves the maximum size, minimum clean size, current
+ * size, and current number of entries from the metadata
+ * cache associated with the specified file. If any of
+ * the ptr parameters are NULL, the associated datum is
+ * not returned.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/24/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mdc_size(hid_t file_id, size_t *max_size_ptr, size_t *min_clean_size_ptr,
+ size_t *cur_size_ptr, int *cur_num_entries_ptr)
+{
+ H5F_t *file; /* File object for file ID */
+ uint32_t cur_num_entries;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*z*z*z*Is", file_id, max_size_ptr, min_clean_size_ptr,
+ cur_size_ptr, cur_num_entries_ptr);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Go get the size data */
+ if(H5AC_get_cache_size(file->shared->cache, max_size_ptr,
+ min_clean_size_ptr, cur_size_ptr, &cur_num_entries) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_get_cache_size() failed.")
+
+ if(cur_num_entries_ptr != NULL)
+ *cur_num_entries_ptr = (int)cur_num_entries;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_mdc_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Freset_mdc_hit_rate_stats
+ *
+ * Purpose: Reset the hit rate statistic whose current value can
+ * be obtained via the H5Fget_mdc_hit_rate() call. Note
+ * that this statistic will also be reset once per epoch
+ * by the automatic cache resize code if it is enabled.
+ *
+ * It is probably a bad idea to call this function unless
+ * you are controlling cache size from your program instead
+ * of using our cache size control code.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 3/24/05
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Freset_mdc_hit_rate_stats(hid_t file_id)
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Reset the hit rate statistic */
+ if(H5AC_reset_cache_hit_rate_stats(file->shared->cache) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't reset cache hit rate")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Freset_mdc_hit_rate_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_name
+ *
+ * Purpose: Gets the name of the file to which object OBJ_ID belongs.
+ * If `name' is non-NULL then write up to `size' bytes into that
+ * buffer and always return the length of the entry name.
+ * Otherwise `size' is ignored and the function does not store the name,
+ * just returning the number of characters required to store the name.
+ * If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
+ * is unchanged and the function returns a negative value.
+ *
+ * Note: This routine returns the name that was used to open the file,
+ * not the actual name after resolving symlinks, etc.
+ *
+ * Return: Success: The length of the file name
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * June 29, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size)
+{
+ H5F_t *f; /* Top file in mount hierarchy */
+ size_t len;
+ ssize_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "ixz", obj_id, name, size);
+
+ /* For file IDs, get the file object directly */
+ /* (This prevents the H5G_loc() call from returning the file pointer for
+ * the top file in a mount hierarchy)
+ */
+ if(H5I_get_type(obj_id) == H5I_FILE ) {
+ if(NULL == (f = (H5F_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ } /* end if */
+ else {
+ H5G_loc_t loc; /* Object location */
+
+ /* Get symbol table entry */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID")
+ f = loc.oloc->file;
+ } /* end else */
+
+ len = HDstrlen(H5F_OPEN_NAME(f));
+
+ if(name) {
+ HDstrncpy(name, H5F_OPEN_NAME(f), MIN(len + 1,size));
+ if(len >= size)
+ name[size-1]='\0';
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (ssize_t)len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_info2
+ *
+ * Purpose: Gets general information about the file, including:
+ * 1. Get storage size for superblock extension if there is one.
+ * 2. Get the amount of btree and heap storage for entries
+ * in the SOHM table if there is one.
+ * 3. The amount of free space tracked in the file.
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * July 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_info2(hid_t obj_id, H5F_info2_t *finfo)
+{
+ H5F_t *f; /* Top file in mount hierarchy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", obj_id, finfo);
+
+ /* Check args */
+ if(!finfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* For file IDs, get the file object directly */
+ /* (This prevents the H5G_loc() call from returning the file pointer for
+ * the top file in a mount hierarchy)
+ */
+ if(H5I_get_type(obj_id) == H5I_FILE ) {
+ if(NULL == (f = (H5F_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ } /* end if */
+ else {
+ H5G_loc_t loc; /* Object location */
+
+ /* Get symbol table entry */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID")
+ f = loc.oloc->file;
+ } /* end else */
+ HDassert(f->shared);
+
+ /* Reset file info struct */
+ HDmemset(finfo, 0, sizeof(*finfo));
+
+ /* Get the size of the superblock and any superblock extensions */
+ if(H5F__super_size(f, H5AC_ind_read_dxpl_id, &finfo->super.super_size, &finfo->super.super_ext_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "Unable to retrieve superblock sizes")
+
+ /* Get the size of any persistent free space */
+ if(H5MF_get_freespace(f, H5AC_ind_read_dxpl_id, &finfo->free.tot_space, &finfo->free.meta_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "Unable to retrieve free space information")
+
+ /* Check for SOHM info */
+ if(H5F_addr_defined(f->shared->sohm_addr))
+ if(H5SM_ih_size(f, H5AC_ind_read_dxpl_id, &finfo->sohm.hdr_size, &finfo->sohm.msgs_info) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "Unable to retrieve SOHM index & heap storage info")
+
+ /* Set version # fields */
+ finfo->super.version = f->shared->sblock->super_vers;
+ finfo->sohm.version = f->shared->sohm_vers;
+ finfo->free.version = HDF5_FREESPACE_VERSION;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_info2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_metadata_read_retry_info
+ *
+ * Purpose: To retrieve the collection of read retries for metadata items with checksum.
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; October 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info)
+{
+ H5F_t *file; /* File object for file ID */
+ unsigned i, j; /* Local index variable */
+ size_t tot_size; /* Size of each retries[i] */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", file_id, info);
+
+ /* Check args */
+ if(!info)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Get the file pointer */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Copy the # of bins for "retries" array */
+ info->nbins = file->shared->retries_nbins;
+
+ /* Initialize the array of "retries" */
+ HDmemset(info->retries, 0, sizeof(info->retries));
+
+ /* Return if there are no bins -- no retries */
+ if(!info->nbins)
+ HGOTO_DONE(SUCCEED);
+
+ /* Calculate size for each retries[i] */
+ tot_size = info->nbins * sizeof(uint32_t);
+
+ /* Map and copy information to info's retries for metadata items with tracking for read retries */
+ j = 0;
+ for(i = 0; i < H5AC_NTYPES; i++) {
+ switch(i) {
+ case H5AC_OHDR_ID:
+ case H5AC_OHDR_CHK_ID:
+ case H5AC_BT2_HDR_ID:
+ case H5AC_BT2_INT_ID:
+ case H5AC_BT2_LEAF_ID:
+ case H5AC_FHEAP_HDR_ID:
+ case H5AC_FHEAP_DBLOCK_ID:
+ case H5AC_FHEAP_IBLOCK_ID:
+ case H5AC_FSPACE_HDR_ID:
+ case H5AC_FSPACE_SINFO_ID:
+ case H5AC_SOHM_TABLE_ID:
+ case H5AC_SOHM_LIST_ID:
+ case H5AC_EARRAY_HDR_ID:
+ case H5AC_EARRAY_IBLOCK_ID:
+ case H5AC_EARRAY_SBLOCK_ID:
+ case H5AC_EARRAY_DBLOCK_ID:
+ case H5AC_EARRAY_DBLK_PAGE_ID:
+ case H5AC_FARRAY_HDR_ID:
+ case H5AC_FARRAY_DBLOCK_ID:
+ case H5AC_FARRAY_DBLK_PAGE_ID:
+ case H5AC_SUPERBLOCK_ID:
+ HDassert(j < H5F_NUM_METADATA_READ_RETRY_TYPES);
+ if(file->shared->retries[i] != NULL) {
+ /* Allocate memory for retries[i]
+ *
+ * This memory should be released by the user with
+ * the H5free_memory() call.
+ */
+ if(NULL == (info->retries[j] = (uint32_t *)H5MM_malloc(tot_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy the information */
+ HDmemcpy(info->retries[j], file->shared->retries[i], tot_size);
+ } /* end if */
+
+ /* Increment location in info->retries[] array */
+ j++;
+ break;
+
+ default:
+ break;
+ } /* end switch */
+ } /* end for */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_metadata_read_retry_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_free_sections
+ *
+ * Purpose: To get free-space section information for free-space manager with
+ * TYPE that is associated with file FILE_ID.
+ * If SECT_INFO is null, this routine returns the total # of free-space
+ * sections.
+ *
+ * Return: Success: non-negative, the total # of free space sections
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; July 1st, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_free_sections(hid_t file_id, H5F_mem_t type, size_t nsects,
+ H5F_sect_info_t *sect_info/*out*/)
+{
+ H5F_t *file; /* Top file in mount hierarchy */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "iFmzx", file_id, type, nsects, sect_info);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+ if(sect_info && nsects == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "nsects must be > 0")
+
+ /* Go get the free-space section information in the file */
+ if((ret_value = H5MF_get_free_sections(file, H5AC_ind_read_dxpl_id, type, nsects, sect_info)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to check free space for file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_free_sections() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fclear_elink_file_cache
+ *
+ * Purpose: Releases the external file cache associated with the
+ * provided file, potentially closing any cached files
+ * unless they are held open from somewhere\ else.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Neil Fortner; December 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fclear_elink_file_cache(hid_t file_id)
+{
+ H5F_t *file; /* File */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Release the EFC */
+ if(file->shared->efc)
+ if(H5F_efc_release(file->shared->efc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release external file cache")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fclear_elink_file_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fstart_swmr_write
+ *
+ * Purpose: To enable SWMR writing mode for the file
+ * 1) Refresh opened objects: part 1
+ * 2) Flush & reset accumulator
+ * 3) Mark the file in SWMR writing mode
+ * 4) Set metadata read attempts and retries info
+ * 5) Disable accumulator
+ * 6) Evict all cache entries except the superblock
+ * 7) Refresh opened objects (part 2)
+ * 8) Unlock the file
+ *
+ * Pre-conditions:
+ * 1) The file being opened has v3 superblock
+ * 2) The file is opened with H5F_ACC_RDWR
+ * 3) The file is not already marked for SWMR writing
+ * 4) Current implementaion for opened objects:
+ * --only allow datasets and groups without attributes
+ * --disallow named datatype with/without attributes
+ * --disallow opened attributes attached to objects
+ * NOTE: Currently, only opened groups and datasets are allowed
+ * when enabling SWMR via H5Fstart_swmr_write().
+ * Will later implement a different approach--
+ * set up flush dependency/proxy even for file opened without
+ * SWMR to resolve issues with opened objects.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer:
+ * Vailin Choi; Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fstart_swmr_write(hid_t file_id)
+{
+ hbool_t ci_load = FALSE; /* whether MDC ci load requested */
+ hbool_t ci_write = FALSE; /* whether MDC CI write requested */
+ H5F_t *file = NULL; /* File info */
+ size_t grp_dset_count=0; /* # of open objects: groups & datasets */
+ size_t nt_attr_count=0; /* # of opened named datatypes + opened attributes */
+ hid_t *obj_ids=NULL; /* List of ids */
+ H5G_loc_t *obj_glocs=NULL; /* Group location of the object */
+ H5O_loc_t *obj_olocs=NULL; /* Object location */
+ H5G_name_t *obj_paths=NULL; /* Group hierarchy path */
+ size_t u; /* Local index variable */
+ hbool_t setup = FALSE; /* Boolean flag to indicate whether SWMR setting is enabled */
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Should have write permission */
+ if((H5F_INTENT(file) & H5F_ACC_RDWR) == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "no write intent on file")
+
+ if(file->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_3)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file superblock version should be at least 3")
+ HDassert(file->shared->latest_flags == H5F_LATEST_ALL_FLAGS);
+
+ /* Should not be marked for SWMR writing mode already */
+ if(file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file already in SWMR writing mode")
+
+ HDassert(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS);
+
+ /* Check to see if cache image is enabled. Fail if so */
+ if(H5C_cache_image_status(file, &ci_load, &ci_write) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MDC cache image status")
+ if(ci_load || ci_write )
+ HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and MDC cache image")
+
+ /* Flush data buffers */
+ if(H5F__flush(file, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+
+ /* Get the # of opened named datatypes and attributes */
+ if(H5F_get_obj_count(file, H5F_OBJ_DATATYPE|H5F_OBJ_ATTR, FALSE, &nt_attr_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+ if(nt_attr_count)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "named datatypes and/or attributes opened in the file")
+
+ /* Get the # of opened datasets and groups */
+ if(H5F_get_obj_count(file, H5F_OBJ_GROUP|H5F_OBJ_DATASET, FALSE, &grp_dset_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+
+ if(grp_dset_count) {
+ /* Allocate space for group and object locations */
+ if((obj_ids = (hid_t *) H5MM_malloc(grp_dset_count * sizeof(hid_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for hid_t")
+ if((obj_glocs = (H5G_loc_t *) H5MM_malloc(grp_dset_count * sizeof(H5G_loc_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5G_loc_t")
+ if((obj_olocs = (H5O_loc_t *) H5MM_malloc(grp_dset_count * sizeof(H5O_loc_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5O_loc_t")
+ if((obj_paths = (H5G_name_t *) H5MM_malloc(grp_dset_count * sizeof(H5G_name_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5G_name_t")
+
+ /* Get the list of opened object ids (groups & datasets) */
+ if(H5F_get_obj_ids(file, H5F_OBJ_GROUP|H5F_OBJ_DATASET, grp_dset_count, obj_ids, FALSE, &grp_dset_count) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5F_get_obj_ids failed")
+
+ /* Refresh opened objects (groups, datasets) in the file */
+ for(u = 0; u < grp_dset_count; u++) {
+ H5O_loc_t *oloc; /* object location */
+ H5G_loc_t tmp_loc;
+
+ /* Set up the id's group location */
+ obj_glocs[u].oloc = &obj_olocs[u];
+ obj_glocs[u].path = &obj_paths[u];
+ H5G_loc_reset(&obj_glocs[u]);
+
+ /* get the id's object location */
+ if((oloc = H5O_get_loc(obj_ids[u])) == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
+
+ /* Make deep local copy of object's location information */
+ H5G_loc(obj_ids[u], &tmp_loc);
+ H5G_loc_copy(&obj_glocs[u], &tmp_loc, H5_COPY_DEEP);
+
+ /* Close the object */
+ if(H5I_dec_ref(obj_ids[u]) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEOBJ, FAIL, "decrementing object ID failed")
+ } /* end for */
+ } /* end if */
+
+ /* Set up I/O info for operation */
+ fio_info.f = file;
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Flush and reset the accumulator */
+ if(H5F__accum_reset(&fio_info, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+
+ /* Turn on SWMR write in shared file open flags */
+ file->shared->flags |= H5F_ACC_SWMR_WRITE;
+
+ /* Mark the file in SWMR writing mode */
+ file->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS;
+
+ /* Set up metadata read attempts */
+ file->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS;
+
+ /* Initialize "retries" and "retries_nbins" */
+ if(H5F_set_retries(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins")
+
+ /* Turn off usage of accumulator */
+ file->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(file->shared->lf, file->shared->feature_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD")
+
+ setup = TRUE;
+
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Flush the superblock */
+ if(H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock")
+
+ /* Evict all flushed entries in the cache except the pinned superblock */
+ if(H5F__evict_cache_entries(file, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict file's cached information")
+
+ /* Refresh (reopen) the objects (groups & datasets) in the file */
+ for(u = 0; u < grp_dset_count; u++)
+ if(H5O_refresh_metadata_reopen(obj_ids[u], &obj_glocs[u], H5AC_ind_read_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't refresh-close object")
+
+ /* Unlock the file */
+ if(H5FD_unlock(file->shared->lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to unlock the file")
+
+done:
+ if(ret_value < 0 && setup) {
+ HDassert(file);
+
+ /* Re-enable accumulator */
+ file->shared->feature_flags |= (unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(file->shared->lf, file->shared->feature_flags) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD")
+
+ /* Reset the # of read attempts */
+ file->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS;
+ if(H5F_set_retries(file) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins")
+
+ /* Un-set H5F_ACC_SWMR_WRITE in shared open flags */
+ file->shared->flags &= ~H5F_ACC_SWMR_WRITE;
+
+ /* Unmark the file: not in SWMR writing mode */
+ file->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_SWMR_WRITE_ACCESS);
+
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(file) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Flush the superblock */
+ if(H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock")
+ } /* end if */
+
+ /* Free memory */
+ if(obj_ids)
+ H5MM_xfree(obj_ids);
+ if(obj_glocs)
+ H5MM_xfree(obj_glocs);
+ if(obj_olocs)
+ H5MM_xfree(obj_olocs);
+ if(obj_paths)
+ H5MM_xfree(obj_paths);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fstart_swmr_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fstart_mdc_logging
+ *
+ * Purpose: Start metadata cache logging operations for a file.
+ * - Logging must have been set up via the fapl.
+ *
+ * Return: Non-negative on success/Negative on errors
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fstart_mdc_logging(hid_t file_id)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Sanity check */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID")
+
+ /* Call mdc logging function */
+ if(H5C_start_logging(file->shared->cache) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_LOGFAIL, FAIL, "unable to start mdc logging")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fstart_mdc_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fstop_mdc_logging
+ *
+ * Purpose: Stop metadata cache logging operations for a file.
+ * - Does not close the log file.
+ * - Logging must have been set up via the fapl.
+ *
+ * Return: Non-negative on success/Negative on errors
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fstop_mdc_logging(hid_t file_id)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Sanity check */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID")
+
+ /* Call mdc logging function */
+ if(H5C_stop_logging(file->shared->cache) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_LOGFAIL, FAIL, "unable to stop mdc logging")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fstop_mdc_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mdc_logging_status
+ *
+ * Purpose: Get the logging flags. is_enabled determines if logging was
+ * set up via the fapl. is_currently_logging determines if
+ * log messages are being recorded at this time.
+ *
+ * Return: Non-negative on success/Negative on errors
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mdc_logging_status(hid_t file_id, hbool_t *is_enabled,
+ hbool_t *is_currently_logging)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*b*b", file_id, is_enabled, is_currently_logging);
+
+ /* Sanity check */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID")
+
+ /* Call mdc logging function */
+ if(H5C_get_logging_status(file->shared->cache, is_enabled, is_currently_logging) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_LOGFAIL, FAIL, "unable to get logging status")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_mdc_logging_status() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fset_latest_format
+ *
+ * Purpose: Enable switching the "latest format" flag while a file is open.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 21, 2015
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fset_latest_format(hid_t file_id, hbool_t latest_format)
+{
+ H5F_t *f; /* File */
+ unsigned latest_flags; /* Latest format flags for file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", file_id, latest_format);
+
+ /* Check args */
+ if(NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Check if the value is changing */
+ latest_flags = H5F_USE_LATEST_FLAGS(f, H5F_LATEST_ALL_FLAGS);
+ if(latest_format != (H5F_LATEST_ALL_FLAGS == latest_flags)) {
+ /* Call the flush routine, for this file */
+ if(H5F__flush(f, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+
+ /* Toggle the 'latest format' flag */
+ H5F_SET_LATEST_FLAGS(f, latest_format ? H5F_LATEST_ALL_FLAGS : 0);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fset_latest_format() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fformat_convert_super (Internal)
+ *
+ * Purpose: Downgrade the superblock version to v2 and
+ * downgrade persistent file space to non-persistent
+ * for 1.8 library.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Jan 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fformat_convert(hid_t fid)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", fid);
+
+ if(H5I_FILE == H5I_get_type(fid)) {
+ H5F_t *f; /* File to flush */
+ hbool_t mark_dirty = FALSE;
+
+ /* Get file object */
+ if(NULL == (f = (H5F_t *)H5I_object(fid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier")
+
+ /* Check if the superblock should be downgraded */
+ if(f->shared->sblock->super_vers > HDF5_SUPERBLOCK_VERSION_V18_LATEST) {
+ f->shared->sblock->super_vers = HDF5_SUPERBLOCK_VERSION_V18_LATEST;
+ mark_dirty = TRUE;
+ } /* end if */
+
+ /* Check for persistent freespace manager, which needs to be downgraded */
+ if(!(f->shared->fs_strategy == H5F_FILE_SPACE_STRATEGY_DEF &&
+ f->shared->fs_persist == H5F_FREE_SPACE_PERSIST_DEF &&
+ f->shared->fs_threshold == H5F_FREE_SPACE_THRESHOLD_DEF &&
+ f->shared->fs_page_size == H5F_FILE_SPACE_PAGE_SIZE_DEF)) {
+ /* Check to remove free-space manager info message from superblock extension */
+ if(H5F_addr_defined(f->shared->sblock->ext_addr))
+ if(H5F_super_ext_remove_msg(f, H5AC_ind_read_dxpl_id, H5O_FSINFO_ID) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "error in removing message from superblock extension")
+
+ /* Close freespace manager */
+ if(H5MF_try_close(f, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to free free-space address")
+
+ /* Set non-persistent freespace manager */
+ f->shared->fs_strategy = H5F_FILE_SPACE_STRATEGY_DEF;
+ f->shared->fs_persist = H5F_FREE_SPACE_PERSIST_DEF;
+ f->shared->fs_threshold = H5F_FREE_SPACE_THRESHOLD_DEF;
+ f->shared->fs_page_size = H5F_FILE_SPACE_PAGE_SIZE_DEF;
+
+ /* Indicate that the superblock should be marked dirty */
+ mark_dirty = TRUE;
+ } /* end if */
+
+ /* Check if we should mark the superblock dirty */
+ if(mark_dirty)
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file or file object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fformat_convert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Freset_page_buffering_stats
+ *
+ * Purpose: Resets statistics for the page buffer layer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Freset_page_buffering_stats(hid_t file_id)
+{
+ H5F_t *file; /* File to reset stats on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object(file_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier")
+ if(NULL == file->shared->page_buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "page buffering not enabled on file")
+
+ /* Reset the statistics */
+ if(H5PB_reset_stats(file->shared->page_buf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't reset stats for page buffering")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Freset_page_buffering_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_page_buffering_stats
+ *
+ * Purpose: Retrieves statistics for the page buffer layer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_page_buffering_stats(hid_t file_id, unsigned accesses[2], unsigned hits[2],
+ unsigned misses[2], unsigned evictions[2], unsigned bypasses[2])
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*Iu*Iu*Iu*Iu*Iu", file_id, accesses, hits, misses, evictions,
+ bypasses);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+ if(NULL == file->shared->page_buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "page buffering not enabled on file")
+ if(NULL == accesses || NULL == hits || NULL == misses || NULL == evictions || NULL == bypasses)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL input parameters for stats")
+
+ /* Get the statistics */
+ if(H5PB_get_stats(file->shared->page_buf, accesses, hits, misses, evictions, bypasses) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve stats for page buffering")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_page_buffering_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mdc_image_info
+ *
+ * Purpose: Retrieves the image_addr and image_len for the cache image in the file.
+ * image_addr: --base address of the on disk metadata cache image
+ * --HADDR_UNDEF if no cache image
+ * image_len: --size of the on disk metadata cache image
+ * --zero if no cache image
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; March 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_len)
+{
+ H5F_t *file; /* File object for file ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*a*h", file_id, image_addr, image_len);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+ if(NULL == image_addr || NULL == image_len)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL image addr or image len")
+
+ /* Go get the address and size of the cache image */
+ if(H5AC_get_mdc_image_info(file->shared->cache, image_addr, image_len) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't retrieve cache image info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_mdc_image_info() */
+
diff --git a/src/H5FA.c b/src/H5FA.c
new file mode 100644
index 0000000..d421eec
--- /dev/null
+++ b/src/H5FA.c
@@ -0,0 +1,814 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FA.c
+ * April 2009
+ * Vailin Choi <vchoi@hdfgroup.org>
+ *
+ * Purpose: Implements a Fixed Array for storing elements
+ * of datasets with fixed dimensions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static H5FA_t *H5FA__new(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr,
+ hbool_t from_open, void *ctx_udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Fixed array client ID to class mapping */
+
+/* Remember to add client ID to H5FA_cls_id_t in H5FAprivate.h when adding a new
+ * client class..
+ */
+const H5FA_class_t *const H5FA_client_class_g[] = {
+ H5FA_CLS_CHUNK, /* 0 - H5FA_CLS_CHUNK_ID */
+ H5FA_CLS_FILT_CHUNK, /* 1 - H5FA_CLS_FILT_CHUNK_ID */
+ H5FA_CLS_TEST, /* ? - H5FA_CLS_TEST_ID */
+};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FA_t struct */
+H5FL_DEFINE_STATIC(H5FA_t);
+
+/* Declare a PQ free list to manage the element */
+H5FL_BLK_DEFINE(fa_native_elmt);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__new
+ *
+ * Purpose: Allocate and initialize a new fixe array wrapper in memory
+ *
+ * Return: Pointer to farray wrapper success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 17 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+H5FA_t *, NULL, NULL,
+H5FA__new(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, hbool_t from_open, void *ctx_udata))
+
+ /* Local variables */
+ H5FA_t *fa = NULL; /* Pointer to new fixed array */
+ H5FA_hdr_t *hdr = NULL; /* The fixed array header information */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fa_addr));
+
+ /* Allocate fixed array wrapper */
+ if(NULL == (fa = H5FL_CALLOC(H5FA_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array info")
+
+ /* Lock the array header into memory */
+ if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header")
+
+ /* Check for pending array deletion */
+ if(from_open && hdr->pending_delete)
+ H5E_THROW(H5E_CANTOPENOBJ, "can't open fixed array pending deletion")
+
+ /* Point fixed array wrapper at header and bump it's ref count */
+ fa->hdr = hdr;
+ if(H5FA__hdr_incr(fa->hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+
+ /* Increment # of files using this array header */
+ if(H5FA__hdr_fuse_incr(fa->hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment file reference count on shared array header")
+
+ /* Set file pointer for this array open context */
+ fa->f = f;
+
+ /* Set the return value */
+ ret_value = fa;
+
+CATCH
+
+ if(hdr && H5FA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array header")
+ if(!ret_value)
+ if(fa && H5FA_close(fa, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close fixed array")
+
+END_FUNC(STATIC) /* end H5FA__new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_create
+ *
+ * Purpose: Creates a new fixed array (header) in the file.
+ *
+ * Return: Pointer to fixed array wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+H5FA_t *, NULL, NULL,
+H5FA_create(H5F_t *f, hid_t dxpl_id, const H5FA_create_t *cparam, void *ctx_udata))
+
+ /* Local variables */
+ H5FA_t *fa = NULL; /* Pointer to new fixed array */
+ haddr_t fa_addr; /* Fixed array header address */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+ /* H5FA interface sanity check */
+ HDcompile_assert(H5FA_NUM_CLS_ID == NELMTS(H5FA_client_class_g));
+
+ /* Create fixed array header */
+ if(HADDR_UNDEF == (fa_addr = H5FA__hdr_create(f, dxpl_id, cparam, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "can't create fixed array header")
+
+ /* Allocate and initialize new fixed array wrapper */
+ if(NULL == (fa = H5FA__new(f, dxpl_id, fa_addr, FALSE, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "allocation and/or initialization failed for fixed array wrapper")
+
+ /* Set the return value */
+ ret_value = fa;
+
+CATCH
+
+ if(!ret_value)
+ if(fa && H5FA_close(fa, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close fixed array")
+
+END_FUNC(PRIV) /* end H5FA_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_open
+ *
+ * Purpose: Opens an existing fixed array in the file.
+ *
+ * Return: Pointer to array wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+H5FA_t *, NULL, NULL,
+H5FA_open(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata))
+
+ /* Local variables */
+ H5FA_t *fa = NULL; /* Pointer to new fixed array wrapper */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fa_addr));
+
+ /* Allocate and initialize new fixed array wrapper */
+ if(NULL == (fa = H5FA__new(f, dxpl_id, fa_addr, TRUE, ctx_udata)))
+ H5E_THROW(H5E_CANTINIT, "allocation and/or initialization failed for fixed array wrapper")
+
+ /* Set the return value */
+ ret_value = fa;
+
+CATCH
+
+ if(!ret_value)
+ if(fa && H5FA_close(fa, dxpl_id) < 0)
+ H5E_THROW(H5E_CLOSEERROR, "unable to close fixed array")
+
+END_FUNC(PRIV) /* end H5FA_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_get_nelmts
+ *
+ * Purpose: Query the current number of elements in array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5FA_get_nelmts(const H5FA_t *fa, hsize_t *nelmts))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(nelmts);
+
+ /* Retrieve the current number of elements in the fixed array */
+ *nelmts = fa->hdr->stats.nelmts;
+
+END_FUNC(PRIV) /* end H5FA_get_nelmts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_get_addr
+ *
+ * Purpose: Query the address of the array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5FA_get_addr(const H5FA_t *fa, haddr_t *addr))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(fa->hdr);
+ HDassert(addr);
+
+ /* Retrieve the address of the fixed array's header */
+ *addr = fa->hdr->addr;
+
+END_FUNC(PRIV) /* end H5FA_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_set
+ *
+ * Purpose: Set an element of a fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_set(const H5FA_t *fa, hid_t dxpl_id, hsize_t idx, const void *elmt))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = fa->hdr; /* Header for fixed array */
+ H5FA_dblock_t *dblock = NULL; /* Pointer to fixed array Data block */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Pointer to fixed array Data block page */
+ unsigned dblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting fixed array Data block */
+ unsigned dblk_page_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting FIxed Array Data block page */
+ hbool_t hdr_dirty = FALSE; /* Whether header information changed */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(fa->hdr);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = fa->f;
+
+ /* Check if we need to create the fixed array data block */
+ if(!H5F_addr_defined(hdr->dblk_addr)) {
+ /* Create the data block */
+ hdr->dblk_addr = H5FA__dblock_create(hdr, dxpl_id, &hdr_dirty);
+ if(!H5F_addr_defined(hdr->dblk_addr))
+ H5E_THROW(H5E_CANTCREATE, "unable to create fixed array data block")
+ } /* end if */
+
+ HDassert(idx < hdr->cparam.nelmts);
+
+ /* Protect data block */
+ if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)hdr->dblk_addr)
+
+ /* Check for paging data block */
+ if(!dblock->npages) {
+ /* Set element in data block */
+ HDmemcpy(((uint8_t *)dblock->elmts) + (hdr->cparam.cls->nat_elmt_size * idx), elmt, hdr->cparam.cls->nat_elmt_size);
+ dblock_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else { /* paging */
+ size_t page_idx; /* Index of page within data block */
+ size_t dblk_page_nelmts; /* # of elements in a data block page */
+ size_t elmt_idx; /* Element index within the page */
+ haddr_t dblk_page_addr; /* Address of data block page */
+
+ /* Compute the page & element index */
+ page_idx = (size_t)(idx / dblock->dblk_page_nelmts);
+ elmt_idx = (size_t)(idx % dblock->dblk_page_nelmts);
+
+ /* Get the address of the data block page */
+ dblk_page_addr = dblock->addr + H5FA_DBLOCK_PREFIX_SIZE(dblock) +
+ ((hsize_t)page_idx * dblock->dblk_page_size);
+
+ /* Check for using last page, to set the number of elements on the page */
+ if((page_idx + 1) == dblock->npages)
+ dblk_page_nelmts = dblock->last_page_nelmts;
+ else
+ dblk_page_nelmts = dblock->dblk_page_nelmts;
+
+ /* Check if the page has been created yet */
+ if(!H5VM_bit_get(dblock->dblk_page_init, page_idx)) {
+ /* Create the data block page */
+ if(H5FA__dblk_page_create(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts) < 0)
+ H5E_THROW(H5E_CANTCREATE, "unable to create data block page")
+
+ /* Mark data block page as initialized in data block */
+ H5VM_bit_set(dblock->dblk_page_init, page_idx, TRUE);
+ dblock_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Protect the data block page */
+ if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ /* Set the element in the data block page */
+ HDmemcpy(((uint8_t *)dblk_page->elmts) + (hdr->cparam.cls->nat_elmt_size * elmt_idx), elmt, hdr->cparam.cls->nat_elmt_size);
+ dblk_page_cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end else */
+
+CATCH
+ /* Check for header modified */
+ if(hdr_dirty)
+ if(H5FA__hdr_modified(hdr) < 0)
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark fixed array header as modified")
+
+ /* Release resources */
+ if(dblock && H5FA__dblock_unprotect(dblock, dxpl_id, dblock_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block")
+ if(dblk_page && H5FA__dblk_page_unprotect(dblk_page, dxpl_id, dblk_page_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block page")
+
+END_FUNC(PRIV) /* end H5FA_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_get
+ *
+ * Purpose: Get an element of a fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_get(const H5FA_t *fa, hid_t dxpl_id, hsize_t idx, void *elmt))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = fa->hdr; /* Header for FA */
+ H5FA_dblock_t *dblock = NULL; /* Pointer to data block for FA */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Pointer to data block page for FA */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(fa->hdr);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = fa->f;
+
+ /* Check if the fixed array data block has been allocated on disk yet */
+ if(!H5F_addr_defined(hdr->dblk_addr)) {
+ /* Call the class's 'fill' callback */
+ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set element to class's fill value")
+ } /* end if */
+ else {
+ /* Get the data block */
+ HDassert(H5F_addr_defined(hdr->dblk_addr));
+ if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)hdr->dblk_addr)
+
+ /* Check for paged data block */
+ if(!dblock->npages)
+ /* Retrieve element from data block */
+ HDmemcpy(elmt, ((uint8_t *)dblock->elmts) + (hdr->cparam.cls->nat_elmt_size * idx), hdr->cparam.cls->nat_elmt_size);
+ else { /* paging */
+ size_t page_idx; /* Index of page within data block */
+
+ /* Compute the page index */
+ page_idx = (size_t)(idx / dblock->dblk_page_nelmts);
+
+ /* Check if the page is defined yet */
+ if(!H5VM_bit_get(dblock->dblk_page_init, page_idx)) {
+ /* Call the class's 'fill' callback */
+ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set element to class's fill value")
+
+ /* We've retrieved the value, leave now */
+ H5_LEAVE(SUCCEED)
+ } /* end if */
+ else { /* get the page */
+ size_t dblk_page_nelmts; /* # of elements in a data block page */
+ size_t elmt_idx; /* Element index within the page */
+ haddr_t dblk_page_addr; /* Address of data block page */
+
+ /* Compute the element index */
+ elmt_idx = (size_t)(idx % dblock->dblk_page_nelmts);
+
+ /* Compute the address of the data block */
+ dblk_page_addr = dblock->addr + H5FA_DBLOCK_PREFIX_SIZE(dblock) + ((hsize_t)page_idx * dblock->dblk_page_size);
+
+ /* Check for using last page, to set the number of elements on the page */
+ if((page_idx + 1) == dblock->npages)
+ dblk_page_nelmts = dblock->last_page_nelmts;
+ else
+ dblk_page_nelmts = dblock->dblk_page_nelmts;
+
+ /* Protect the data block page */
+ if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ /* Retrieve element from data block */
+ HDmemcpy(elmt, ((uint8_t *)dblk_page->elmts) + (hdr->cparam.cls->nat_elmt_size * elmt_idx), hdr->cparam.cls->nat_elmt_size);
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+CATCH
+ if(dblock && H5FA__dblock_unprotect(dblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block")
+ if(dblk_page && H5FA__dblk_page_unprotect(dblk_page, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block page")
+
+END_FUNC(PRIV) /* end H5FA_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_close
+ *
+ * Purpose: Close a fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_close(H5FA_t *fa, hid_t dxpl_id))
+
+ /* Local variables */
+ hbool_t pending_delete = FALSE; /* Whether the array is pending deletion */
+ haddr_t fa_addr = HADDR_UNDEF; /* Address of array (for deletion) */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+
+ /* Close the header, if it was set */
+ if(fa->hdr) {
+ /* Decrement file reference & check if this is the last open fixed array using the shared array header */
+ if(0 == H5FA__hdr_fuse_decr(fa->hdr)) {
+ /* Set the shared array header's file context for this operation */
+ fa->hdr->f = fa->f;
+
+ /* Shut down anything that can't be put in the header's 'flush' callback */
+
+ /* Check for pending array deletion */
+ if(fa->hdr->pending_delete) {
+ /* Set local info, so array deletion can occur after decrementing the
+ * header's ref count
+ */
+ pending_delete = TRUE;
+ fa_addr = fa->hdr->addr;
+ } /* end if */
+ } /* end if */
+
+ /* Check for pending array deletion */
+ if(pending_delete) {
+ H5FA_hdr_t *hdr; /* Another pointer to fixed array header */
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Header's status in the metadata cache */
+
+ /* Check the header's status in the metadata cache */
+ if(H5AC_get_entry_status(fa->f, fa_addr, &hdr_status) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to check metadata cache status for fixed array header")
+
+ /* Sanity checks on header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PINNED);
+ HDassert(!(hdr_status & H5AC_ES__IS_PROTECTED));
+}
+#endif /* NDEBUG */
+
+ /* Lock the array header into memory */
+ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */
+ if(NULL == (hdr = H5FA__hdr_protect(fa->f, dxpl_id, fa_addr, NULL, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTLOAD, "unable to load fixed array header")
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = fa->f;
+
+ /* Decrement the reference count on the array header */
+ /* (don't put in H5FA_hdr_fuse_decr() as the array header may be evicted
+ * immediately -QAK)
+ */
+ if(H5FA__hdr_decr(fa->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+
+ /* Delete array, starting with header (unprotects header) */
+ if(H5FA__hdr_delete(hdr, dxpl_id) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete fixed array")
+ } /* end if */
+ else {
+ /* Decrement the reference count on the array header */
+ /* (don't put in H5FA_hdr_fuse_decr() as the array header may be evicted
+ * immediately -QAK)
+ */
+ if(H5FA__hdr_decr(fa->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ } /* end else */
+ } /* end if */
+
+ /* Release the fixed array wrapper */
+ fa = H5FL_FREE(H5FA_t, fa);
+
+CATCH
+
+END_FUNC(PRIV) /* end H5FA_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_delete
+ *
+ * Purpose: Delete a fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_delete(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = NULL; /* The fixed array header information */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fa_addr));
+
+ /* Lock the array header into memory */
+ if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array header, address = %llu", (unsigned long long)fa_addr)
+
+ /* Check for files using shared array header */
+ if(hdr->file_rc)
+ hdr->pending_delete = TRUE;
+ else {
+ /* Set the shared array header's file context for this operation */
+ hdr->f = f;
+
+ /* Delete array now, starting with header (unprotects header) */
+ if(H5FA__hdr_delete(hdr, dxpl_id) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete fixed array")
+ hdr = NULL;
+ } /* end if */
+
+CATCH
+
+ /* Unprotect the header, if an error occurred */
+ if(hdr && H5FA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array header")
+
+END_FUNC(PRIV) /* end H5FA_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_iterate
+ *
+ * Purpose: Iterate over the elements of a fixed array
+ *
+ * Note: This is not very efficient, we should be iterating directly
+ * over the fixed array's direct block [pages].
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_iterate(H5FA_t *fa, hid_t dxpl_id, H5FA_operator_t op, void *udata))
+
+ /* Local variables */
+ uint8_t *elmt = NULL;
+ hsize_t u;
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(op);
+ HDassert(udata);
+
+ /* Allocate space for a native array element */
+ if(NULL == (elmt = H5FL_BLK_MALLOC(fa_native_elmt, fa->hdr->cparam.cls->nat_elmt_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array element")
+
+ /* Iterate over all elements in array */
+ for(u = 0; u < fa->hdr->stats.nelmts; u++) {
+ int cb_ret; /* Return value from callback */
+
+ /* Get array element */
+ if(H5FA_get(fa, dxpl_id, u, elmt) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to delete fixed array")
+
+ /* Make callback */
+ if((cb_ret = (*op)(u, elmt, udata)) < 0) {
+ H5E_PRINTF(H5E_BADITER, "iterator function failed");
+ H5_LEAVE(cb_ret)
+ } /* end if */
+ } /* end for */
+
+CATCH
+
+ if(elmt)
+ elmt = H5FL_BLK_FREE(fa_native_elmt, elmt);
+
+END_FUNC(PRIV) /* end H5FA_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_depend
+ *
+ * Purpose: Make a child flush dependency between the fixed array
+ * and another piece of metadata in the file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA_depend(H5FA_t *fa, hid_t dxpl_id, H5AC_proxy_entry_t *parent))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = fa->hdr; /* Header for FA */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(hdr);
+ HDassert(parent);
+
+ /*
+ * Check to see if a flush dependency between the fixed array
+ * and another data structure in the file has already been set up.
+ * If it hasn't, do so now.
+ */
+ if(NULL == hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Set the shared array header's file context for this operation */
+ hdr->f = fa->f;
+
+ /* Add the fixed array as a child of the parent (proxy) */
+ if(H5AC_proxy_entry_add_child(parent, hdr->f, dxpl_id, hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array as child of proxy")
+ hdr->parent = parent;
+ } /* end if */
+
+CATCH
+
+END_FUNC(PRIV) /* end H5FA_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_patch_file
+ *
+ * Purpose: Patch the top-level file pointer contained in fa
+ * to point to idx_info->f if they are different.
+ * This is possible because the file pointer in fa can be
+ * closed out if fa remains open.
+ *
+ * Return: SUCCEED
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5FA_patch_file(H5FA_t *fa, H5F_t *f))
+
+ /* Local variables */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(f);
+
+ if(fa->f != f || fa->hdr->f != f)
+ fa->f = fa->hdr->f = f;
+
+END_FUNC(PRIV) /* end H5FA_patch_file() */
diff --git a/src/H5FAcache.c b/src/H5FAcache.c
new file mode 100644
index 0000000..19fdb74
--- /dev/null
+++ b/src/H5FAcache.c
@@ -0,0 +1,1305 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAcache.c
+ * Jul 2 2009
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement fixed array metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Fixed Array format version #'s */
+#define H5FA_HDR_VERSION 0 /* Header */
+#define H5FA_DBLOCK_VERSION 0 /* Data block */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5FA__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5FA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5FA__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5FA__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5FA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5FA__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5FA__cache_hdr_free_icr(void *thing);
+
+static herr_t H5FA__cache_dblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5FA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5FA__cache_dblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5FA__cache_dblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5FA__cache_dblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5FA__cache_dblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5FA__cache_dblock_free_icr(void *thing);
+static herr_t H5FA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size);
+
+static herr_t H5FA__cache_dblk_page_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5FA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5FA__cache_dblk_page_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5FA__cache_dblk_page_image_len(const void *thing, size_t *image_len);
+static herr_t H5FA__cache_dblk_page_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5FA__cache_dblk_page_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5FA__cache_dblk_page_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5FA header inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FARRAY_HDR[1] = {{
+ H5AC_FARRAY_HDR_ID, /* Metadata client ID */
+ "Fixed-array Header", /* Metadata client name (for debugging) */
+ H5FD_MEM_FARRAY_HDR, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5FA__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5FA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5FA__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5FA__cache_hdr_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5FA__cache_hdr_serialize, /* 'serialize' callback */
+ H5FA__cache_hdr_notify, /* 'notify' callback */
+ H5FA__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5FA data block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FARRAY_DBLOCK[1] = {{
+ H5AC_FARRAY_DBLOCK_ID, /* Metadata client ID */
+ "Fixed Array Data Block", /* Metadata client name (for debugging) */
+ H5FD_MEM_FARRAY_DBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5FA__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5FA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */
+ H5FA__cache_dblock_deserialize, /* 'deserialize' callback */
+ H5FA__cache_dblock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5FA__cache_dblock_serialize, /* 'serialize' callback */
+ H5FA__cache_dblock_notify, /* 'notify' callback */
+ H5FA__cache_dblock_free_icr, /* 'free_icr' callback */
+ H5FA__cache_dblock_fsf_size, /* 'fsf_size' callback */
+}};
+
+/* H5FA data block page inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{
+ H5AC_FARRAY_DBLK_PAGE_ID, /* Metadata client ID */
+ "Fixed Array Data Block Page", /* Metadata client name (for debugging) */
+ H5FD_MEM_FARRAY_DBLK_PAGE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5FA__cache_dblk_page_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5FA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */
+ H5FA__cache_dblk_page_deserialize, /* 'deserialize' callback */
+ H5FA__cache_dblk_page_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5FA__cache_dblk_page_serialize, /* 'serialize' callback */
+ H5FA__cache_dblk_page_notify, /* 'notify' callback */
+ H5FA__cache_dblk_page_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 31, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata; /* User data for callback */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5FA_HEADER_SIZE_FILE(udata->f);
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5FA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new Fixed array
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 12, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5FA__cache_hdr_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5FA_cls_id_t id; /* ID of fixed array class, as found in file */
+ H5FA_hdr_t *hdr = NULL; /* Fixed array info */
+ H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata;
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(H5F_addr_defined(udata->addr));
+
+ /* Allocate space for the fixed array data structure */
+ if(NULL == (hdr = H5FA__hdr_alloc(udata->f)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array shared header")
+
+ /* Set the fixed array header's address */
+ hdr->addr = udata->addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong fixed array header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5FA_HDR_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong fixed array header version")
+
+ /* Fixed array class */
+ id = (H5FA_cls_id_t)*image++;
+ if(id >= H5FA_NUM_CLS_ID)
+ H5E_THROW(H5E_BADTYPE, "incorrect fixed array class")
+ hdr->cparam.cls = H5FA_client_class_g[id];
+
+ /* General array creation/configuration information */
+ hdr->cparam.raw_elmt_size = *image++; /* Element size in file (in bytes) */
+ hdr->cparam.max_dblk_page_nelmts_bits = *image++; /* Log2(Max. # of elements in data block page) -
+ i.e. # of bits needed to store max. # of
+ elements in data block page. */
+
+ /* Array statistics */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->cparam.nelmts); /* Number of elements */
+
+ /* Internal information */
+ H5F_addr_decode(udata->f, &image, &hdr->dblk_addr); /* Address of index block */
+
+ /* Check for data block */
+ if(H5F_addr_defined(hdr->dblk_addr)) {
+ H5FA_dblock_t dblock; /* Fake data block for computing size */
+ size_t dblk_page_nelmts; /* # of elements per data block page */
+
+ /* Set up fake data block for computing size on disk */
+ dblock.hdr = hdr;
+ dblock.dblk_page_init_size = 0;
+ dblock.npages = 0;
+ dblk_page_nelmts = (size_t)1 << hdr->cparam.max_dblk_page_nelmts_bits;
+ if(hdr->cparam.nelmts > dblk_page_nelmts) {
+ dblock.npages = (size_t)(((hdr->cparam.nelmts + dblk_page_nelmts) - 1) / dblk_page_nelmts);
+ dblock.dblk_page_init_size = (dblock.npages + 7) / 8;
+ } /* end if */
+
+ /* Compute Fixed Array data block size for hdr statistics */
+ hdr->stats.dblk_size = (size_t)H5FA_DBLOCK_SIZE(&dblock);
+ } /* end if */
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM));
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == len);
+
+ /* Finish initializing fixed array header */
+ if(H5FA__hdr_init(hdr, udata->ctx_udata) < 0)
+ H5E_THROW(H5E_CANTINIT, "initialization failed for fixed array header")
+ HDassert(hdr->size == len);
+
+ /* Set return value */
+ ret_value = hdr;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(hdr && H5FA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array header")
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 12, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_hdr_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5FA_hdr_t *hdr = (const H5FA_hdr_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = hdr->size;
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 12, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = (H5FA_hdr_t *)_thing; /* Pointer to the fixed array header */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5FA_HDR_VERSION;
+
+ /* Fixed array type */
+ *image++ = hdr->cparam.cls->id;
+
+ /* General array creation/configuration information */
+ *image++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */
+ *image++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */
+
+ /* Array statistics */
+ H5F_ENCODE_LENGTH(f, image, hdr->stats.nelmts); /* Number of elements for the fixed array */
+
+ /* Internal information */
+ H5F_addr_encode(f, &image, hdr->dblk_addr); /* Address of fixed array data block */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * December 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_hdr_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = (H5FA_hdr_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(hdr->swmr_write) {
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* If hdr->parent != NULL, hdr->parent is used to destroy
+ * the flush dependency before the header is evicted.
+ */
+ if(hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Destroy flush dependency on object header proxy */
+ if(H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent, (void *)hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between fixed array and proxy")
+ hdr->parent = NULL;
+ } /* end if */
+
+ /* Detach from 'top' proxy for fixed array */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between header and fixed array 'top' proxy")
+ /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == hdr->parent);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_hdr_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 12, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_hdr_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the extensible array header */
+ if(H5FA__hdr_dest((H5FA_hdr_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free fixed array header")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 12, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data */
+ H5FA_dblock_t dblock; /* Fake data block for computing size */
+ size_t dblk_page_nelmts; /* # of elements per data block page */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set up fake data block for computing size on disk */
+ /* (Note: extracted from H5FA__dblock_alloc) */
+ HDmemset(&dblock, 0, sizeof(dblock));
+
+ /* Set up fake data block for computing size on disk
+ *
+ * need: dblock->hdr
+ * dblock->npages
+ * dblock->dblk_page_init_size
+ */
+ dblock.hdr = udata->hdr;
+ dblk_page_nelmts = (size_t)1 << udata->hdr->cparam.max_dblk_page_nelmts_bits;
+ if(udata->hdr->cparam.nelmts > dblk_page_nelmts) {
+ dblock.npages = (size_t)(((udata->hdr->cparam.nelmts + dblk_page_nelmts) - 1) / dblk_page_nelmts);
+ dblock.dblk_page_init_size = (dblock.npages + 7) / 8;
+ } /* end if */
+
+ /* Set the image length size */
+ if(!dblock.npages)
+ *image_len = (size_t)H5FA_DBLOCK_SIZE(&dblock);
+ else
+ *image_len = (size_t)H5FA_DBLOCK_PREFIX_SIZE(&dblock);
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5FA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5FA__cache_dblock_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = NULL; /* Data block info */
+ H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data for loading data block */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ haddr_t arr_addr; /* Address of array header in the file */
+
+ /* Sanity check */
+ HDassert(udata);
+ HDassert(udata->hdr);
+
+ /* Allocate the fixed array data block */
+ if(NULL == (dblock = H5FA__dblock_alloc(udata->hdr)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block")
+
+ HDassert(((!dblock->npages) && (len == (size_t)H5FA_DBLOCK_SIZE(dblock)))
+ || (len == (size_t)H5FA_DBLOCK_PREFIX_SIZE(dblock)));
+
+ /* Set the fixed array data block's information */
+ dblock->addr = udata->dblk_addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ H5E_THROW(H5E_BADVALUE, "wrong fixed array data block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5FA_DBLOCK_VERSION)
+ H5E_THROW(H5E_VERSION, "wrong fixed array data block version")
+
+ /* Fixed array type */
+ if(*image++ != (uint8_t)udata->hdr->cparam.cls->id)
+ H5E_THROW(H5E_BADTYPE, "incorrect fixed array class")
+
+ /* Address of header for array that owns this block (just for file integrity checks) */
+ H5F_addr_decode(udata->hdr->f, &image, &arr_addr);
+ if(H5F_addr_ne(arr_addr, udata->hdr->addr))
+ H5E_THROW(H5E_BADVALUE, "wrong fixed array header address")
+
+ /* Page initialization flags */
+ if(dblock->npages > 0) {
+ HDmemcpy(dblock->dblk_page_init, image, dblock->dblk_page_init_size);
+ image += dblock->dblk_page_init_size;
+ } /* end if */
+
+ /* Only decode elements if the data block is not paged */
+ if(!dblock->npages) {
+ /* Decode elements in data block */
+ /* Convert from raw elements on disk into native elements in memory */
+ if((udata->hdr->cparam.cls->decode)(image, dblock->elmts, (size_t)udata->hdr->cparam.nelmts, udata->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTDECODE, "can't decode fixed array data elements")
+ image += (udata->hdr->cparam.nelmts * udata->hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM));
+
+ /* Set the data block's size */
+ dblock->size = H5FA_DBLOCK_SIZE(dblock);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == len);
+
+ /* Set return value */
+ ret_value = dblock;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(dblock && H5FA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block")
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_dblock_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5FA_dblock_t *dblock = (const H5FA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ if(!dblock->npages)
+ *image_len = (size_t)dblock->size;
+ else
+ *image_len = H5FA_DBLOCK_PREFIX_SIZE(dblock);
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(dblock);
+ HDassert(dblock->hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5FA_DBLOCK_VERSION;
+
+ /* Fixed array type */
+ *image++ = dblock->hdr->cparam.cls->id;
+
+ /* Address of array header for array which owns this block */
+ H5F_addr_encode(f, &image, dblock->hdr->addr);
+
+ /* Page init flags */
+ if(dblock->npages > 0) {
+ /* Store the 'page init' bitmasks */
+ HDmemcpy(image, dblock->dblk_page_init, dblock->dblk_page_init_size);
+ image += dblock->dblk_page_init_size;
+ } /* end if */
+
+ /* Only encode elements if the data block is not paged */
+ if(!dblock->npages) {
+ /* Encode elements in data block */
+
+ /* Convert from native elements in memory into raw elements on disk */
+ H5_CHECK_OVERFLOW(dblock->hdr->cparam.nelmts, /* From: */hsize_t, /* To: */size_t);
+ if((dblock->hdr->cparam.cls->encode)(image, dblock->elmts, (size_t)dblock->hdr->cparam.nelmts, dblock->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements")
+ image += (dblock->hdr->cparam.nelmts * dblock->hdr->cparam.raw_elmt_size);
+ } /* end if */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblock_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing;
+
+ /* Sanity check */
+ HDassert(dblock);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(dblock->hdr->swmr_write) {
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5FA__create_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, address = %llu", (unsigned long long)dblock->addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5FA__destroy_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency")
+
+ /* Detach from 'top' proxy for fixed array */
+ if(dblock->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(dblock->top_proxy, dblock) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block and fixed array 'top' proxy")
+ dblock->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_notify() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblock_free_icr(void *_thing))
+
+ H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+
+ /* Release the fixed array data block */
+ if(H5FA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free fixed array data block")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblock_fsf_size
+ *
+ * Purpose: Tell the metadata cache the actual amount of file space
+ * to free when a dblock entry is destroyed with the free
+ * file space block set.
+ *
+ * This function is needed when the data block is paged, as
+ * the datablock header and all its pages are allocted as a
+ * single contiguous chunk of file space, and must be
+ * deallocated the same way.
+ *
+ * The size of the chunk of memory in which the dblock
+ * header and all its pages is stored in the size field,
+ * so we simply pass that value back to the cache.
+ *
+ * If the datablock is not paged, then the size field of
+ * the cache_info contains the correct size. However this
+ * value will be the same as the size field, so we return
+ * the contents of the size field to the cache in this case
+ * as well.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 12/5/14
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_dblock_fsf_size(const void *_thing, size_t *fsf_size))
+
+ const H5FA_dblock_t *dblock = (const H5FA_dblock_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FARRAY_DBLOCK);
+ HDassert(fsf_size);
+
+ *fsf_size = dblock->size;
+
+END_FUNC(STATIC) /* end H5FA__cache_dblock_fsf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_dblk_page_get_initial_load_size(void *_udata, size_t *image_len))
+
+ /* Local variables */
+ H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data */
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->nelmts > 0);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5FA_DBLK_PAGE_SIZE(udata->hdr, udata->nelmts);
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+htri_t, TRUE, -,
+H5FA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata))
+
+ /* Local variables */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_deserialize
+ *
+ * Purpose: Loads a data structure from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5FA__cache_dblk_page_deserialize(const void *_image, size_t len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Data block page info */
+ H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+
+ /* Sanity check */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(udata->nelmts > 0);
+ HDassert(H5F_addr_defined(udata->dblk_page_addr));
+
+ /* Allocate the fixed array data block page */
+ if(NULL == (dblk_page = H5FA__dblk_page_alloc(udata->hdr, udata->nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block page")
+
+ /* Set the fixed array data block's information */
+ dblk_page->addr = udata->dblk_page_addr;
+
+ /* Internal information */
+
+ /* Decode elements in data block page */
+ /* Convert from raw elements on disk into native elements in memory */
+ if((udata->hdr->cparam.cls->decode)(image, dblk_page->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTDECODE, "can't decode fixed array data elements")
+ image += (udata->nelmts * udata->hdr->cparam.raw_elmt_size);
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM));
+
+ /* Set the data block page's size */
+ dblk_page->size = len;
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size);
+
+ /* Set return value */
+ ret_value = dblk_page;
+
+CATCH
+
+ /* Release resources */
+ if(!ret_value)
+ if(dblk_page && H5FA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page")
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__cache_dblk_page_image_len(const void *_thing, size_t *image_len))
+
+ /* Local variables */
+ const H5FA_dblk_page_t *dblk_page = (const H5FA_dblk_page_t *)_thing; /* Pointer to the object */
+
+ /* Check arguments */
+ HDassert(dblk_page);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = dblk_page->size;
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblk_page_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = (H5FA_dblk_page_t *)_thing; /* Pointer to the object to serialize */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(image);
+ HDassert(dblk_page);
+ HDassert(dblk_page->hdr);
+
+ /* Internal information */
+
+ /* Encode elements in data block page */
+
+ /* Convert from native elements in memory into raw elements on disk */
+ if((dblk_page->hdr->cparam.cls->encode)(image, dblk_page->elmts, dblk_page->nelmts, dblk_page->hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements")
+ image += (dblk_page->nelmts * dblk_page->hdr->cparam.raw_elmt_size);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 17 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblk_page_notify(H5AC_notify_action_t action, void *_thing))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = (H5FA_dblk_page_t *)_thing; /* Pointer to the object */
+
+ /* Sanity check */
+ HDassert(dblk_page);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Detach from 'top' proxy for fixed array */
+ if(dblk_page->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(dblk_page->top_proxy, dblk_page) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and fixed array 'top' proxy")
+ dblk_page->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ default:
+#ifdef NDEBUG
+ H5E_THROW(H5E_BADVALUE, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__cache_dblk_page_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__cache_dblk_page_free_icr(void *thing))
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Release the fixed array data block page */
+ if(H5FA__dblk_page_dest((H5FA_dblk_page_t *)thing) < 0)
+ H5E_THROW(H5E_CANTFREE, "can't free fixed array data block page")
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__cache_dblk_page_free_icr() */
+
diff --git a/src/H5FAdbg.c b/src/H5FAdbg.c
new file mode 100644
index 0000000..7444eae
--- /dev/null
+++ b/src/H5FAdbg.c
@@ -0,0 +1,283 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAdbg.c
+ *
+ * Purpose: Dump debugging information about a fixed array.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5Oprivate.h" /* Object Header */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_debug
+ *
+ * Purpose: Prints debugging info about a fixed array header.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth, const H5FA_class_t *cls, haddr_t obj_addr))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = NULL; /* Shared fixed array header */
+ void *dbg_ctx = NULL; /* Fixed array debugging context */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(H5F_addr_defined(obj_addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create fixed array debugging context")
+ } /* end if */
+
+ /* Load the fixed array header */
+ if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFixed Array Header...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Header size:",
+ hdr->size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Raw Element Size:",
+ (unsigned)hdr->cparam.raw_elmt_size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Native Element Size (on this platform):",
+ hdr->cparam.cls->nat_elmt_size);
+
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. # of elements in data block page:",
+ (unsigned)((size_t)1 << hdr->cparam.max_dblk_page_nelmts_bits));
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of elements in Fixed Array:", hdr->stats.nelmts);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Fixed Array Data Block Address:", hdr->dblk_addr);
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release fixed array debugging context")
+ if(hdr && H5FA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array header")
+
+END_FUNC(PKG) /* end H5FA__hdr_debug() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_debug
+ *
+ * Purpose: Prints debugging info about a fixed array data block.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth, const H5FA_class_t *cls, haddr_t hdr_addr, haddr_t obj_addr))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = NULL; /* Shared fixed array header */
+ H5FA_dblock_t *dblock = NULL; /* Fixed array data block */
+ void *dbg_ctx = NULL; /* Fixed array context */
+ size_t u; /* Local index variable */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(cls);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(H5F_addr_defined(obj_addr));
+
+ /* Check for debugging context callback available */
+ if(cls->crt_dbg_ctx) {
+ /* Create debugging context */
+ if(NULL == (dbg_ctx = cls->crt_dbg_ctx(f, dxpl_id, obj_addr)))
+ H5E_THROW(H5E_CANTGET, "unable to create fixed array debugging context")
+ } /* end if */
+
+ /* Load the fixed array header */
+ if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header")
+
+ /* Protect data block */
+ if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, addr, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)addr)
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFixed Array data Block...\n", indent, "");
+
+ /* Print the values */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Array class ID:", hdr->cparam.cls->name);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, "Address of Data Block:", dblock->addr);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth, "Data Block size:", dblock->size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of elements in Data Block:", hdr->cparam.nelmts);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of pages in Data Block:", dblock->npages);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of elements per Data Block page:", dblock->dblk_page_nelmts);
+
+ if(dblock->npages) { /* paging */
+ size_t dblk_page_nelmts; /* # of elements in a data block page */
+ haddr_t dblk_page_addr; /* Address of a data block page */
+ size_t page_idx; /* Page index within data block */
+
+ HDfprintf(stream, "%*sPaging:\n", indent, "");
+
+ /* Iterate over the pages */
+ dblk_page_addr = dblock->addr + H5FA_DBLOCK_PREFIX_SIZE(dblock);
+ dblk_page_nelmts = dblock->dblk_page_nelmts;
+
+ /* Read and print each page's elements in the data block */
+ for(page_idx = 0; page_idx < dblock->npages; page_idx++) {
+ if(!H5VM_bit_get(dblock->dblk_page_init, page_idx)) {
+ HDfprintf(stream, "%*s%-*s %Hu %s\n", indent, "", fwidth,
+ "Page %Zu:", page_idx, "empty");
+
+ } /* end if */
+ else { /* get the page */
+ H5FA_dblk_page_t *dblk_page; /* Pointer to a data block page */
+ hsize_t nelmts_left; /* Remaining elements in the last data block page */
+
+ /* Check for last page */
+ if(((page_idx + 1) == dblock->npages) && (nelmts_left = hdr->cparam.nelmts % dblock->dblk_page_nelmts))
+ dblk_page_nelmts = (size_t)nelmts_left;
+
+ if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ HDfprintf(stream, "%*sElements in page %Zu:\n", indent, "", page_idx);
+ for(u = 0; u < dblk_page_nelmts; u++) {
+ /* Call the class's 'debug' callback */
+ if((hdr->cparam.cls->debug)(stream, (indent + 3), MAX(0, (fwidth - 3)), (hsize_t)u, ((uint8_t *)dblk_page->elmts) + (hdr->cparam.cls->nat_elmt_size * u)) < 0)
+ H5E_THROW(H5E_CANTGET, "can't get element for debugging")
+ } /* end for */
+ if(H5FA__dblk_page_unprotect(dblk_page, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block page")
+
+ /* Advance to next page address */
+ dblk_page_addr += dblock->dblk_page_size;
+ } /* paging */
+ } /* end for npages */
+ } /* end if */
+ else { /* not paging */
+ /* Print the elements in the data block */
+ HDfprintf(stream, "%*sElements:\n", indent, "");
+ for(u = 0; u < hdr->cparam.nelmts; u++) {
+ /* Call the class's 'debug' callback */
+ if((hdr->cparam.cls->debug)(stream, (indent + 3), MAX(0, (fwidth - 3)), (hsize_t)u, ((uint8_t *)dblock->elmts) + (hdr->cparam.cls->nat_elmt_size * u)) < 0)
+ H5E_THROW(H5E_CANTGET, "can't get element for debugging")
+ } /* end for */
+ } /* end else */
+
+CATCH
+ if(dbg_ctx && cls->dst_dbg_ctx(dbg_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to release fixed array debugging context")
+ if(dblock && H5FA__dblock_unprotect(dblock, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block")
+ if(hdr && H5FA__hdr_unprotect(hdr, dxpl_id, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array header")
+
+END_FUNC(PKG) /* end H5FA__dblock_debug() */
+
diff --git a/src/H5FAdblkpage.c b/src/H5FAdblkpage.c
new file mode 100644
index 0000000..baf4286
--- /dev/null
+++ b/src/H5FAdblkpage.c
@@ -0,0 +1,349 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAdblkpage.c
+ *
+ * Purpose: Data block page routines for fixed array.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FA_dblk_page_t struct */
+H5FL_DEFINE_STATIC(H5FA_dblk_page_t);
+
+/* Declare a free list to manage the page elements */
+H5FL_BLK_DEFINE(page_elmts);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblk_page_alloc
+ *
+ * Purpose: Allocate fixed array data block page
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_dblk_page_t *, NULL, NULL,
+H5FA__dblk_page_alloc(H5FA_hdr_t *hdr, size_t nelmts))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Fixed array data block page */
+
+ /* Check arguments */
+ HDassert(hdr);
+
+ /* Allocate memory for the data block */
+ if(NULL == (dblk_page = H5FL_CALLOC(H5FA_dblk_page_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block page")
+
+ /* Share common array information */
+ if(H5FA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ dblk_page->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ dblk_page->nelmts = nelmts;
+
+ /* Allocate buffer for elements in data block page */
+ if(NULL == (dblk_page->elmts = H5FL_BLK_MALLOC(page_elmts, nelmts * hdr->cparam.cls->nat_elmt_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block page element buffer")
+
+ /* Set the return value */
+ ret_value = dblk_page;
+
+CATCH
+
+ if(!ret_value)
+ if(dblk_page && H5FA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page")
+
+END_FUNC(PKG) /* end H5FA__dblk_page_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblk_page_create
+ *
+ * Purpose: Creates a new fixed array data block page in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblk_page_create(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, size_t nelmts))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Fixed array data block page */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+#ifdef H5FA_DEBUG
+HDfprintf(stderr, "%s: Called, addr = %a\n", FUNC, addr);
+#endif /* H5FA_DEBUG */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Allocate the data block page */
+ if(NULL == (dblk_page = H5FA__dblk_page_alloc(hdr, nelmts)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block page")
+
+ /* Set info about data block page on disk */
+ dblk_page->addr = addr;
+ dblk_page->size = H5FA_DBLK_PAGE_SIZE(hdr, nelmts);
+#ifdef H5FA_DEBUG
+HDfprintf(stderr, "%s: dblk_page->size = %Zu\n", FUNC, dblk_page->size);
+#endif /* H5FA_DEBUG */
+
+ /* Clear any elements in data block page to fill value */
+ if((hdr->cparam.cls->fill)(dblk_page->elmts, nelmts) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set fixed array data block page elements to class's fill value")
+
+ /* Cache the new fixed array data block page */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add fixed array data block page to cache")
+ inserted = TRUE;
+
+ /* Add data block page as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblk_page) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+ dblk_page->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+CATCH
+ if(ret_value < 0)
+ if(dblk_page) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(dblk_page) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove fixed array data block page from cache")
+
+ /* Destroy data block page */
+ if(H5FA__dblk_page_dest(dblk_page) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5FA__dblk_page_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblk_page_protect
+ *
+ * Purpose: Convenience wrapper around protecting fixed array data
+ * block page
+ *
+ * Return: Non-NULL pointer to data block page on success/NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_dblk_page_t *, NULL, NULL,
+H5FA__dblk_page_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t dblk_page_addr,
+ size_t dblk_page_nelmts, unsigned flags))
+
+ /* Local variables */
+ H5FA_dblk_page_t *dblk_page = NULL; /* Fixed array data block page */
+ H5FA_dblk_page_cache_ud_t udata; /* Information needed for loading data block page */
+
+#ifdef H5FA_DEBUG
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* H5FA_DEBUG */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblk_page_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG is permitted */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data */
+ udata.hdr = hdr;
+ udata.nelmts = dblk_page_nelmts;
+ udata.dblk_page_addr = dblk_page_addr;
+
+ /* Protect the data block page */
+ if(NULL == (dblk_page = (H5FA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == dblk_page->top_proxy) {
+ /* Add data block page as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblk_page) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+ dblk_page->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dblk_page;
+
+CATCH
+
+ /* Clean up on error */
+ if(!ret_value) {
+ /* Release the data block page, if it was protected */
+ if(dblk_page && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect fixed array data block page, address = %llu", (unsigned long long)dblk_page->addr)
+ } /* end if */
+
+END_FUNC(PKG) /* end H5FA__dblk_page_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblk_page_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting fixed array
+ * data block page
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblk_page_unprotect(H5FA_dblk_page_t *dblk_page, hid_t dxpl_id,
+ unsigned cache_flags))
+
+ /* Local variables */
+
+#ifdef H5FA_DEBUG
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* H5FA_DEBUG */
+
+ /* Sanity check */
+ HDassert(dblk_page);
+
+ /* Unprotect the data block page */
+ if(H5AC_unprotect(dblk_page->hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page->addr, dblk_page, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect fixed array data block page, address = %llu", (unsigned long long)dblk_page->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__dblk_page_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblk_page_dest
+ *
+ * Purpose: Destroys a fixed array data block page in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblk_page_dest(H5FA_dblk_page_t *dblk_page))
+
+ /* Sanity check */
+ HDassert(dblk_page);
+
+ /* Check if header field has been initialized */
+ if(dblk_page->hdr) {
+ /* Check if buffer for data block page elements has been initialized */
+ if(dblk_page->elmts) {
+ /* Free buffer for data block page elements */
+ dblk_page->elmts = H5FL_BLK_FREE(page_elmts, dblk_page->elmts);
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5FA__hdr_decr(dblk_page->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ dblk_page->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == dblk_page->top_proxy);
+
+ /* Free the data block page itself */
+ dblk_page = H5FL_FREE(H5FA_dblk_page_t, dblk_page);
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__dblk_page_dest() */
+
diff --git a/src/H5FAdblock.c b/src/H5FAdblock.c
new file mode 100644
index 0000000..432bf58
--- /dev/null
+++ b/src/H5FAdblock.c
@@ -0,0 +1,450 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAdblock.c
+ *
+ * Purpose: Data block routines for fixed arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FA_dblock_t struct */
+H5FL_DEFINE_STATIC(H5FA_dblock_t);
+
+/* Declare a free list to manage the chunk elements */
+H5FL_BLK_DEFINE(chunk_elmts);
+
+/* Declare a free list to manage blocks of 'page init' bitmasks */
+H5FL_BLK_DEFINE(fa_page_init);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_alloc
+ *
+ * Purpose: Allocate fixed array data block
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_dblock_t *, NULL, NULL,
+H5FA__dblock_alloc(H5FA_hdr_t *hdr))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = NULL; /* fixed array data block */
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(hdr->cparam.nelmts > 0);
+
+ /* Allocate memory for the data block */
+ if(NULL == (dblock = H5FL_CALLOC(H5FA_dblock_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block")
+
+ /* Share common array information */
+ if(H5FA__hdr_incr(hdr) < 0)
+ H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
+ dblock->hdr = hdr;
+
+ /* Set non-zero internal fields */
+ dblock->dblk_page_nelmts = (size_t)1 << hdr->cparam.max_dblk_page_nelmts_bits;
+
+ /* Check if this data block should be paged */
+ if(hdr->cparam.nelmts > dblock->dblk_page_nelmts) {
+ /* Compute number of pages */
+ hsize_t npages = ((hdr->cparam.nelmts + dblock->dblk_page_nelmts) - 1) / dblock->dblk_page_nelmts;
+
+ /* Safely assign the number of pages */
+ H5_CHECKED_ASSIGN(dblock->npages, size_t, npages, hsize_t);
+
+ /* Sanity check that we have at least 1 page */
+ HDassert(dblock->npages > 0);
+
+ /* Compute size of 'page init' flag array, in bytes */
+ dblock->dblk_page_init_size = (dblock->npages + 7) / 8;
+ HDassert(dblock->dblk_page_init_size > 0);
+
+ /* Allocate space for 'page init' flags */
+ if(NULL == (dblock->dblk_page_init = H5FL_BLK_CALLOC(fa_page_init, dblock->dblk_page_init_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for page init bitmask")
+
+ /* Compute data block page size */
+ dblock->dblk_page_size = (dblock->dblk_page_nelmts * hdr->cparam.raw_elmt_size) + H5FA_SIZEOF_CHKSUM;
+
+ /* Compute the # of elements on last page */
+ if(0 == hdr->cparam.nelmts % dblock->dblk_page_nelmts)
+ dblock->last_page_nelmts = dblock->dblk_page_nelmts;
+ else
+ dblock->last_page_nelmts = (size_t)(hdr->cparam.nelmts % dblock->dblk_page_nelmts);
+ } /* end if */
+ else {
+ hsize_t dblk_size = hdr->cparam.nelmts * hdr->cparam.cls->nat_elmt_size;
+
+ /* Allocate buffer for elements in data block */
+ H5_CHECK_OVERFLOW(dblk_size, /* From: */hsize_t, /* To: */size_t);
+ if(NULL == (dblock->elmts = H5FL_BLK_MALLOC(chunk_elmts, (size_t)dblk_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for data block element buffer")
+ } /* end else */
+
+ /* Set the return value */
+ ret_value = dblock;
+
+CATCH
+
+ if(!ret_value)
+ if(dblock && H5FA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block")
+
+END_FUNC(PKG) /* end H5FA__dblock_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_create
+ *
+ * Purpose: Creates a fixed array data block in the file
+ *
+ * Return: Valid file address on success/HADDR_UNDEF on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5FA__dblock_create(H5FA_hdr_t *hdr, hid_t dxpl_id, hbool_t *hdr_dirty))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = NULL; /* Fixed array data block */
+ haddr_t dblock_addr; /* Fixed array data block address */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr_dirty);
+
+ /* Allocate the data block */
+ if(NULL == (dblock = H5FA__dblock_alloc(hdr)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block")
+
+ /* Set size of data block on disk */
+ hdr->stats.dblk_size = dblock->size = H5FA_DBLOCK_SIZE(dblock);
+
+ /* Allocate space for the data block on disk */
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_FARRAY_DBLOCK, dxpl_id, (hsize_t)dblock->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for fixed array data block")
+ dblock->addr = dblock_addr;
+
+ /* Don't initialize elements if paged */
+ if(!dblock->npages)
+ /* Clear any elements in data block to fill value */
+ if((hdr->cparam.cls->fill)(dblock->elmts, (size_t)hdr->cparam.nelmts) < 0)
+ H5E_THROW(H5E_CANTSET, "can't set fixed array data block elements to class's fill value")
+
+ /* Cache the new fixed array data block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add fixed array data block to cache")
+ inserted = TRUE;
+
+ /* Add data block as child of 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+ dblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Mark the header dirty (for updating statistics) */
+ *hdr_dirty = TRUE;
+
+ /* Set address of data block to return */
+ ret_value = dblock_addr;
+
+CATCH
+
+ if(!H5F_addr_defined(ret_value))
+ if(dblock) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(dblock) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove fixed array data block from cache")
+
+ /* Release data block's disk space */
+ if(H5F_addr_defined(dblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_FARRAY_DBLOCK, dxpl_id, dblock->addr, (hsize_t)dblock->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to release fixed array data block")
+
+ /* Destroy data block */
+ if(H5FA__dblock_dest(dblock) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5FA__dblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_protect
+ *
+ * Purpose: Convenience wrapper around protecting fixed array data block
+ *
+ * Return: Non-NULL pointer to data block on success/NULL on failure
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_dblock_t *, NULL, NULL,
+H5FA__dblock_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t dblk_addr,
+ unsigned flags))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock; /* Fixed array data block */
+ H5FA_dblock_cache_ud_t udata; /* Information needed for loading data block */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblk_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG flag is permitted */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data */
+ udata.hdr = hdr;
+ udata.dblk_addr = dblk_addr;
+
+ /* Protect the data block */
+ if(NULL == (dblock = (H5FA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblk_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)dblk_addr)
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->top_proxy && NULL == dblock->top_proxy) {
+ /* Add data block as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, dxpl_id, dblock) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+ dblock->top_proxy = hdr->top_proxy;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dblock;
+
+CATCH
+
+ /* Clean up on error */
+ if(!ret_value)
+ /* Release the data block, if it was protected */
+ if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblock->addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect fixed array data block, address = %llu", (unsigned long long)dblock->addr)
+
+END_FUNC(PKG) /* end H5FA__dblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting fixed array data block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblock_unprotect(H5FA_dblock_t *dblock, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(dblock);
+
+ /* Unprotect the data block */
+ if(H5AC_unprotect(dblock->hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblock->addr, dblock, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect fixed array data block, address = %llu", (unsigned long long)dblock->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__dblock_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_delete
+ *
+ * Purpose: Delete a data block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblock_delete(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t dblk_addr))
+
+ /* Local variables */
+ H5FA_dblock_t *dblock = NULL; /* Pointer to data block */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblk_addr));
+
+ /* Protect data block */
+ if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, dblk_addr, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)dblk_addr)
+
+ /* Check if data block is paged */
+ if(dblock->npages) {
+ haddr_t dblk_page_addr; /* Address of each data block page */
+ size_t u; /* Local index variable */
+
+ /* Set up initial state */
+ dblk_page_addr = dblk_addr + H5FA_DBLOCK_PREFIX_SIZE(dblock);
+
+ /* Iterate over pages in data block */
+ for(u = 0; u < dblock->npages; u++) {
+ /* Evict the data block page from the metadata cache */
+ /* (OK to call if it doesn't exist in the cache) */
+ if(H5AC_expunge_entry(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page_addr, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTEXPUNGE, "unable to remove array data block page from metadata cache")
+
+ /* Advance to next page address */
+ dblk_page_addr += dblock->dblk_page_size;
+ } /* end for */
+ } /* end if */
+
+CATCH
+
+ /* Finished deleting data block in metadata cache */
+ if(dblock && H5FA__dblock_unprotect(dblock, dxpl_id, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array data block")
+
+END_FUNC(PKG) /* end H5FA__dblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__dblock_dest
+ *
+ * Purpose: Destroys a fixed array data block in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__dblock_dest(H5FA_dblock_t *dblock))
+
+ /* Sanity check */
+ HDassert(dblock);
+
+ /* Check if shared header field has been initialized */
+ if(dblock->hdr) {
+ /* Check if we've got elements in the data block */
+ if(dblock->elmts && !dblock->npages) {
+ /* Free buffer for data block elements */
+ HDassert(dblock->hdr->cparam.nelmts > 0);
+ dblock->elmts = H5FL_BLK_FREE(chunk_elmts, dblock->elmts);
+ } /* end if */
+
+ /* Check if data block is paged */
+ if(dblock->npages) {
+ /* Free buffer for 'page init' bitmask, if there is one */
+ HDassert(dblock->dblk_page_init_size > 0);
+ if(dblock->dblk_page_init)
+ dblock->dblk_page_init = H5FL_BLK_FREE(fa_page_init, dblock->dblk_page_init);
+ } /* end if */
+
+ /* Decrement reference count on shared info */
+ if(H5FA__hdr_decr(dblock->hdr) < 0)
+ H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
+ dblock->hdr = NULL;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(NULL == dblock->top_proxy);
+
+ /* Free the data block itself */
+ dblock = H5FL_FREE(H5FA_dblock_t, dblock);
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__dblock_dest() */
+
diff --git a/src/H5FAhdr.c b/src/H5FAhdr.c
new file mode 100644
index 0000000..6809f02
--- /dev/null
+++ b/src/H5FAhdr.c
@@ -0,0 +1,594 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAhdr.c
+ *
+ * Purpose: Array header routines for Fixed Array.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FA_hdr_t struct */
+H5FL_DEFINE_STATIC(H5FA_hdr_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_alloc
+ *
+ * Purpose: Allocate shared Fixed Array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_hdr_t *, NULL, NULL,
+H5FA__hdr_alloc(H5F_t *f))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = NULL; /* Shared Fixed Array header */
+
+ /* Check arguments */
+ HDassert(f);
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5FL_CALLOC(H5FA_hdr_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for Fixed Array shared header")
+
+ /* Set non-zero internal fields */
+ hdr->addr = HADDR_UNDEF;
+
+ /* Set the internal parameters for the array */
+ hdr->f = f;
+ hdr->swmr_write = (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) > 0;
+ hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
+
+ /* Set the return value */
+ ret_value = hdr;
+
+CATCH
+
+ if(!ret_value)
+ if(hdr && H5FA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array header")
+
+END_FUNC(PKG) /* end H5FA__hdr_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_init
+ *
+ * Purpose: Initialize shared fixed array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, November 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_init(H5FA_hdr_t *hdr, void *ctx_udata))
+
+ /* Local variables */
+
+ /* Check arguments */
+ HDassert(hdr);
+
+ /* Set size of header on disk (locally and in statistics) */
+ hdr->stats.hdr_size = hdr->size = H5FA_HEADER_SIZE_HDR(hdr);
+
+ /* Set number of elements for Fixed Array in statistics */
+ hdr->stats.nelmts = hdr->cparam.nelmts;
+
+ /* Create the callback context, if there's one */
+ if(hdr->cparam.cls->crt_context) {
+ if(NULL == (hdr->cb_ctx = (*hdr->cparam.cls->crt_context)(ctx_udata)))
+ H5E_THROW(H5E_CANTCREATE, "unable to create fixed array client callback context")
+ } /* end if */
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_create
+ *
+ * Purpose: Creates a new Fixed Array header in the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+haddr_t, HADDR_UNDEF, HADDR_UNDEF,
+H5FA__hdr_create(H5F_t *f, hid_t dxpl_id, const H5FA_create_t *cparam,
+ void *ctx_udata))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr = NULL; /* Fixed array header */
+ hbool_t inserted = FALSE; /* Whether the header was inserted into cache */
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(cparam);
+
+#ifndef NDEBUG
+{
+ /* Check for valid parameters */
+ if(cparam->raw_elmt_size == 0)
+ H5E_THROW(H5E_BADVALUE, "element size must be greater than zero")
+ if(cparam->max_dblk_page_nelmts_bits == 0)
+ H5E_THROW(H5E_BADVALUE, "max. # of elements bits must be greater than zero")
+ if(cparam->nelmts == 0)
+ H5E_THROW(H5E_BADVALUE, "# of elements must be greater than zero")
+}
+#endif /* NDEBUG */
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5FA__hdr_alloc(f)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for Fixed Array shared header")
+
+ hdr->dblk_addr = HADDR_UNDEF;
+
+ /* Set the creation parameters for the array */
+ HDmemcpy(&hdr->cparam, cparam, sizeof(hdr->cparam));
+
+ /* Finish initializing fixed array header */
+ if(H5FA__hdr_init(hdr, ctx_udata) < 0)
+ H5E_THROW(H5E_CANTINIT, "initialization failed for fixed array header")
+
+ /* Allocate space for the header on disk */
+ if(HADDR_UNDEF == (hdr->addr = H5MF_alloc(f, H5FD_MEM_FARRAY_HDR, dxpl_id, (hsize_t)hdr->size)))
+ H5E_THROW(H5E_CANTALLOC, "file allocation failed for Fixed Array header")
+
+ /* Create 'top' proxy for extensible array entries */
+ if(hdr->swmr_write)
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ H5E_THROW(H5E_CANTCREATE, "can't create fixed array entry proxy")
+
+ /* Cache the new Fixed Array header */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FARRAY_HDR, hdr->addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ H5E_THROW(H5E_CANTINSERT, "can't add fixed array header to cache")
+ inserted = TRUE;
+
+ /* Add header as child of 'top' proxy */
+ if(hdr->top_proxy)
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+
+ /* Set address of array header to return */
+ ret_value = hdr->addr;
+
+CATCH
+
+ if(!H5F_addr_defined(ret_value))
+ if(hdr) {
+ /* Remove from cache, if inserted */
+ if(inserted)
+ if(H5AC_remove_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTREMOVE, "unable to remove fixed array header from cache")
+
+ /* Release header's disk space */
+ if(H5F_addr_defined(hdr->addr) && H5MF_xfree(f, H5FD_MEM_FARRAY_HDR, dxpl_id, hdr->addr, (hsize_t)hdr->size) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to free Fixed Array header")
+
+ /* Destroy header */
+ if(H5FA__hdr_dest(hdr) < 0)
+ H5E_THROW(H5E_CANTFREE, "unable to destroy Fixed Array header")
+ } /* end if */
+
+END_FUNC(PKG) /* end H5FA__hdr_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_incr
+ *
+ * Purpose: Increment component reference count on shared array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_incr(H5FA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Mark header as un-evictable when something is depending on it */
+ if(hdr->rc == 0)
+ if(H5AC_pin_protected_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTPIN, "unable to pin fixed array header")
+
+ /* Increment reference count on shared header */
+ hdr->rc++;
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_decr
+ *
+ * Purpose: Decrement component reference count on shared array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_decr(H5FA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->rc);
+
+ /* Decrement reference count on shared header */
+ hdr->rc--;
+
+ /* Mark header as evictable again when nothing depend on it */
+ if(hdr->rc == 0) {
+ HDassert(hdr->file_rc == 0);
+ if(H5AC_unpin_entry(hdr) < 0)
+ H5E_THROW(H5E_CANTUNPIN, "unable to unpin fixed array header")
+ } /* end if */
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_fuse_incr
+ *
+ * Purpose: Increment file reference count on shared array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+herr_t, SUCCEED, -,
+H5FA__hdr_fuse_incr(H5FA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Increment file reference count on shared header */
+ hdr->file_rc++;
+
+END_FUNC(PKG) /* end H5FA__hdr_fuse_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_fuse_decr
+ *
+ * Purpose: Decrement file reference count on shared array header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+size_t, 0, -,
+H5FA__hdr_fuse_decr(H5FA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->file_rc);
+
+ /* Decrement file reference count on shared header */
+ hdr->file_rc--;
+
+ /* Set return value */
+ ret_value = hdr->file_rc;
+
+END_FUNC(PKG) /* end H5FA__hdr_fuse_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_modified
+ *
+ * Purpose: Mark a fixed array as modified
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_modified(H5FA_hdr_t *hdr))
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Mark header as dirty in cache */
+ if(H5AC_mark_entry_dirty(hdr) < 0)
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark fixed array header as dirty")
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_modified() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_protect
+ *
+ * Purpose: Convenience wrapper around protecting fixed array header
+ *
+ * Return: Non-NULL pointer to header on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 12 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5FA_hdr_t *, NULL, NULL,
+H5FA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata,
+ unsigned flags))
+
+ /* Local variables */
+ H5FA_hdr_t *hdr; /* Fixed array header */
+ H5FA_hdr_cache_ud_t udata; /* User data for cache callbacks */
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fa_addr));
+
+ /* only the H5AC__READ_ONLY_FLAG is permitted */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up user data for cache callbacks */
+ udata.f = f;
+ udata.addr = fa_addr;
+ udata.ctx_udata = ctx_udata;
+
+ /* Protect the header */
+ if(NULL == (hdr = (H5FA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FARRAY_HDR, fa_addr, &udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array header, address = %llu", (unsigned long long)fa_addr)
+ hdr->f = f; /* (Must be set again here, in case the header was already in the cache -QAK) */
+
+ /* Create top proxy, if it doesn't exist */
+ if(hdr->swmr_write && NULL == hdr->top_proxy) {
+ /* Create 'top' proxy for fixed array entries */
+ if(NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
+ H5E_THROW(H5E_CANTCREATE, "can't create fixed array entry proxy")
+
+ /* Add header as child of 'top' proxy */
+ if(H5AC_proxy_entry_add_child(hdr->top_proxy, f, dxpl_id, hdr) < 0)
+ H5E_THROW(H5E_CANTSET, "unable to add fixed array entry as child of array proxy")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = hdr;
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_unprotect
+ *
+ * Purpose: Convenience wrapper around unprotecting fixed array header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 12 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_unprotect(H5FA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags))
+
+ /* Local variables */
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Unprotect the header */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FARRAY_HDR, hdr->addr, hdr, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect fixed array hdr, address = %llu", (unsigned long long)hdr->addr)
+
+CATCH
+
+END_FUNC(PKG) /* end H5EA__hdr_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_delete
+ *
+ * Purpose: Delete a fixed array, starting with the header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_delete(H5FA_hdr_t *hdr, hid_t dxpl_id))
+
+ /* Local variables */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting header */
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(!hdr->file_rc);
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Array header's status in the metadata cache */
+
+ /* Check the array header's status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, hdr->addr, &hdr_status) < 0)
+ H5E_THROW(H5E_CANTGET, "unable to check metadata cache status for array header")
+
+ /* Sanity checks on array header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PROTECTED);
+} /* end block */
+#endif /* NDEBUG */
+
+ /* Check for Fixed Array Data block */
+ if(H5F_addr_defined(hdr->dblk_addr)) {
+ /* Delete Fixed Array Data block */
+ if(H5FA__dblock_delete(hdr, dxpl_id, hdr->dblk_addr) < 0)
+ H5E_THROW(H5E_CANTDELETE, "unable to delete fixed array data block")
+ } /* end if */
+
+ /* Set flags to finish deleting header on unprotect */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+CATCH
+
+ /* Unprotect the header, deleting it if an error hasn't occurred */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FARRAY_HDR, hdr->addr, hdr, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release fixed array header")
+
+END_FUNC(PKG) /* end H5FA__hdr_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__hdr_dest
+ *
+ * Purpose: Destroys a fixed array header in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__hdr_dest(H5FA_hdr_t *hdr))
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(hdr->rc == 0);
+
+ /* Destroy the callback context */
+ if(hdr->cb_ctx) {
+ if((*hdr->cparam.cls->dst_context)(hdr->cb_ctx) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to destroy fixed array client callback context")
+ } /* end if */
+ hdr->cb_ctx = NULL;
+
+ /* Destroy the 'top' proxy */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_dest(hdr->top_proxy) < 0)
+ H5E_THROW(H5E_CANTRELEASE, "unable to destroy fixed array 'top' proxy")
+ hdr->top_proxy = NULL;
+ } /* end if */
+
+ /* Free the shared info itself */
+ hdr = H5FL_FREE(H5FA_hdr_t, hdr);
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__hdr_dest() */
+
diff --git a/src/H5FAint.c b/src/H5FAint.c
new file mode 100644
index 0000000..9d3bce8
--- /dev/null
+++ b/src/H5FAint.c
@@ -0,0 +1,137 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAint.c
+ * Fall 2012
+ * Dana Robinson <derobins@hdfgroup.org>
+ *
+ * Purpose: Internal routines for fixed arrays.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error Handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__create_flush_depend
+ *
+ * Purpose: Create a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__create_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry))
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Create a flush dependency between parent and child entry */
+ if(H5AC_create_flush_dependency(parent_entry, child_entry) < 0)
+ H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency")
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__create_flush_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__destroy_flush_depend
+ *
+ * Purpose: Destroy a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5FA__destroy_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry))
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Destroy a flush dependency between parent and child entry */
+ if(H5AC_destroy_flush_dependency(parent_entry, child_entry) < 0)
+ H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency")
+
+CATCH
+
+END_FUNC(PKG) /* end H5FA__destroy_flush_depend() */
+
diff --git a/src/H5FAmodule.h b/src/H5FAmodule.h
new file mode 100644
index 0000000..f675faf
--- /dev/null
+++ b/src/H5FAmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5FA package. Including this header means that the source file
+ * is part of the H5FA package.
+ */
+#ifndef _H5FAmodule_H
+#define _H5FAmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5FA_MODULE
+#define H5_MY_PKG H5FA
+#define H5_MY_PKG_ERR H5E_FARRAY
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5FAmodule_H */
+
diff --git a/src/H5FApkg.h b/src/H5FApkg.h
new file mode 100644
index 0000000..6f0a43a
--- /dev/null
+++ b/src/H5FApkg.h
@@ -0,0 +1,320 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer:
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5FA package. Source files outside the H5FA package should
+ * include H5FAprivate.h instead.
+ */
+#if !(defined(H5FA_FRIEND) | defined(H5FA_MODULE))
+#error "Do not include this file outside the H5FA package!"
+#endif
+
+#ifndef _H5FApkg_H
+#define _H5FApkg_H
+
+/* Get package's private header */
+#include "H5FAprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Define this to display debugging information for the Fixed Array layer */
+/* #define H5FA_DEBUG */
+
+
+/* Fill value for fixed array test class */
+#ifdef H5FA_TESTING
+#define H5FA_TEST_FILL ((uint64_t)ULLONG_MAX)
+#endif /* H5FA_TESTING */
+
+/* Size of checksum information (on disk) */
+#define H5FA_SIZEOF_CHKSUM 4
+
+/* "Standard" size of prefix information for fixed array metadata */
+#define H5FA_METADATA_PREFIX_SIZE(c) ( \
+ H5_SIZEOF_MAGIC /* Signature */ \
+ + 1 /* Version */ \
+ + 1 /* Array type */ \
+ + ((c) ? H5FA_SIZEOF_CHKSUM : 0) /* Metadata checksum */ \
+ )
+
+/* Size of the Fixed Array header on disk */
+#define H5FA_HEADER_SIZE(sizeof_addr, sizeof_size) ( \
+ /* General metadata fields */ \
+ H5FA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* General array information */ \
+ + 1 /* Element Size */ \
+ + 1 /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ \
+ \
+ /* Fixed Array statistics fields */ \
+ + (sizeof_size) /* # of elements in the fixed array */ \
+ \
+ /* Fixed Array Header specific fields */ \
+ + (sizeof_addr) /* File address of Fixed Array data block */ \
+ )
+
+/* Size of the fixed array header on disk (via file pointer) */
+#define H5FA_HEADER_SIZE_FILE(f) ( \
+ H5FA_HEADER_SIZE(H5F_SIZEOF_ADDR(f), H5F_SIZEOF_SIZE(f)) \
+ )
+
+/* Size of the fixed array header on disk (via fixed array header) */
+#define H5FA_HEADER_SIZE_HDR(h) ( \
+ H5FA_HEADER_SIZE((h)->sizeof_addr, (h)->sizeof_size) \
+ )
+
+/* Size of the Fixed Array data block prefix on disk */
+#define H5FA_DBLOCK_PREFIX_SIZE(d) ( \
+ /* General metadata fields */ \
+ H5FA_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Sanity-checking fields */ \
+ + (d)->hdr->sizeof_addr /* File address of Fixed Array header owning the data block */ \
+ \
+ /* Fixed Array Data Block specific fields */ \
+ + (d)->dblk_page_init_size /* Fixed array data block 'page init' bitmasks (can be 0 if no pages) */ \
+ )
+
+/* Size of the Fixed Array data block on disk */
+#define H5FA_DBLOCK_SIZE(d) ( \
+ /* Data block prefix size */ \
+ H5FA_DBLOCK_PREFIX_SIZE(d) \
+ \
+ /* Fixed Array Elements|Pages of Elements*/ \
+ + ((d)->hdr->cparam.nelmts * (size_t)(d)->hdr->cparam.raw_elmt_size) \
+ + ((d)->npages * H5FA_SIZEOF_CHKSUM) /* Checksum */ \
+ )
+
+/* Size of the Fixed Array data block page on disk */
+#define H5FA_DBLK_PAGE_SIZE(h, nelmts) ( \
+ /* Fixed Array Data Block Page */ \
+ + (nelmts * (size_t)(h)->cparam.raw_elmt_size) /* Elements in data block page */ \
+ + H5FA_SIZEOF_CHKSUM /* Checksum for each page */ \
+ )
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* The Fixed Array header information */
+typedef struct H5FA_hdr_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Fixed array configuration/creation parameters (stored in header) */
+ H5FA_create_t cparam; /* Creation parameters for Fixed Array */
+
+ /* Fixed Array data block information (stored in header) */
+ haddr_t dblk_addr; /* Address of Fixed Array Data block */
+
+ /* Statistics for Fixed Array (stored in header) */
+ H5FA_stat_t stats; /* Statistcs for Fixed Array */
+
+ /* Computed/cached values (not stored in header) */
+ size_t rc; /* Reference count of the header */
+ haddr_t addr; /* Address of header in file */
+ size_t size; /* Size of header in file */
+ H5F_t *f; /* Pointer to file for fixed array */
+ size_t file_rc; /* Reference count of files using array header */
+ hbool_t pending_delete; /* Array is pending deletion */
+ size_t sizeof_addr; /* Size of file addresses */
+ size_t sizeof_size; /* Size of file sizes */
+
+ /* Client information (not stored) */
+ void *cb_ctx; /* Callback context */
+
+ /* SWMR / Flush dependency information (not stored) */
+ hbool_t swmr_write; /* Flag indicating the file is opened with SWMR-write access */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all array entries */
+ void *parent; /* Pointer to 'top' proxy flush dependency
+ * parent, if it exists, otherwise NULL.
+ * If the fixed array is being used
+ * to index a chunked dataset and the
+ * dataset metadata is modified by a
+ * SWMR writer, this field will be set
+ * equal to the object header proxy
+ * that is the flush dependency parent
+ * of the fixed array header.
+ *
+ * The field is used to avoid duplicate
+ * setups of the flush dependency
+ * relationship, and to allow the
+ * fixed array header to destroy
+ * the flush dependency on receipt of
+ * an eviction notification from the
+ * metadata cache.
+ */
+} H5FA_hdr_t;
+
+/* The fixed array data block information */
+typedef struct H5FA_dblock_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Fixed array information (stored) */
+ uint8_t *dblk_page_init;/* Bitmap of whether a data block page is initialized */
+ void *elmts; /* Buffer for elements stored in data block */
+
+ /* Internal array information (not stored) */
+ H5FA_hdr_t *hdr; /* Shared array header info */
+
+ /* SWMR / Flush dependency information (not stored) */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all array entries */
+
+ /* Computed/cached values (not stored) */
+ haddr_t addr; /* Address of this data block on disk */
+ hsize_t size; /* Size of data block on disk */
+ size_t npages; /* Nummber of pages in data block (zero if not paged) */
+ size_t last_page_nelmts; /* Nummber of elements in last page, if paged */
+
+ /* Fixed Array data block information (not stored) */
+ size_t dblk_page_nelmts; /* # of elements per data block page */
+ size_t dblk_page_size; /* Size of a data block page */
+ size_t dblk_page_init_size; /* Size of 'page init' bitmask */
+} H5FA_dblock_t;
+
+/* The fixed array data block page information */
+typedef struct H5FA_dbk_page_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Fixed array information (stored) */
+ void *elmts; /* Buffer for elements stored in data block page */
+
+ /* Internal array information (not stored) */
+ H5FA_hdr_t *hdr; /* Shared array header info */
+
+ /* SWMR / Flush dependency information (not stored) */
+ H5AC_proxy_entry_t *top_proxy; /* 'Top' proxy cache entry for all array entries */
+
+ /* Computed/cached values (not stored) */
+ haddr_t addr; /* Address of this data block page on disk */
+ size_t size; /* Size of data block page on disk */
+ size_t nelmts; /* Number of elements in data block page */
+} H5FA_dblk_page_t;
+
+/* Fixed array */
+struct H5FA_t {
+ H5FA_hdr_t *hdr; /* Pointer to internal fixed array header info */
+ H5F_t *f; /* Pointer to file for fixed array */
+};
+
+
+/* Metadata cache callback user data types */
+
+/* Info needed for loading header */
+typedef struct H5FA_hdr_cache_ud_t {
+ H5F_t *f; /* Pointer to file for fixed array */
+ haddr_t addr; /* Address of header on disk */
+ void *ctx_udata; /* User context for class */
+} H5FA_hdr_cache_ud_t;
+
+/* Info needed for loading data block */
+typedef struct H5FA_dblock_cache_ud_t {
+ H5FA_hdr_t *hdr; /* Shared fixed array information */
+ haddr_t dblk_addr; /* Address of data block on disk */
+} H5FA_dblock_cache_ud_t;
+
+/* Info needed for loading data block page */
+typedef struct H5FA_dblk_page_cache_ud_t {
+ H5FA_hdr_t *hdr; /* Shared fixed array information */
+ size_t nelmts; /* Number of elements in data block page */
+ haddr_t dblk_page_addr; /* Address of data block page on disk */
+} H5FA_dblk_page_cache_ud_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Internal fixed array testing class */
+H5_DLLVAR const H5FA_class_t H5FA_CLS_TEST[1];
+
+/* Array of fixed array client ID -> client class mappings */
+H5_DLLVAR const H5FA_class_t *const H5FA_client_class_g[H5FA_NUM_CLS_ID];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Generic routines */
+H5_DLL herr_t H5FA__create_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+H5_DLL herr_t H5FA__destroy_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+
+/* Header routines */
+H5_DLL H5FA_hdr_t *H5FA__hdr_alloc(H5F_t *f);
+H5_DLL herr_t H5FA__hdr_init(H5FA_hdr_t *hdr, void *ctx_udata);
+H5_DLL haddr_t H5FA__hdr_create(H5F_t *f, hid_t dxpl_id, const H5FA_create_t *cparam, void *ctx_udata);
+H5_DLL void *H5FA__hdr_alloc_elmts(H5FA_hdr_t *hdr, size_t nelmts);
+H5_DLL herr_t H5FA__hdr_free_elmts(H5FA_hdr_t *hdr, size_t nelmts, void *elmts);
+H5_DLL herr_t H5FA__hdr_incr(H5FA_hdr_t *hdr);
+H5_DLL herr_t H5FA__hdr_decr(H5FA_hdr_t *hdr);
+H5_DLL herr_t H5FA__hdr_fuse_incr(H5FA_hdr_t *hdr);
+H5_DLL size_t H5FA__hdr_fuse_decr(H5FA_hdr_t *hdr);
+H5_DLL herr_t H5FA__hdr_modified(H5FA_hdr_t *hdr);
+H5_DLL H5FA_hdr_t *H5FA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr,
+ void *ctx_udata, unsigned flags);
+H5_DLL herr_t H5FA__hdr_unprotect(H5FA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags);
+H5_DLL herr_t H5FA__hdr_delete(H5FA_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5FA__hdr_dest(H5FA_hdr_t *hdr);
+
+/* Data block routines */
+H5_DLL H5FA_dblock_t *H5FA__dblock_alloc(H5FA_hdr_t *hdr);
+H5_DLL haddr_t H5FA__dblock_create(H5FA_hdr_t *hdr, hid_t dxpl_id, hbool_t *hdr_dirty);
+H5_DLL unsigned H5FA__dblock_sblk_idx(const H5FA_hdr_t *hdr, hsize_t idx);
+H5_DLL H5FA_dblock_t *H5FA__dblock_protect(H5FA_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t dblk_addr, unsigned flags);
+H5_DLL herr_t H5FA__dblock_unprotect(H5FA_dblock_t *dblock, hid_t dxpl_id,
+ unsigned cache_flags);
+H5_DLL herr_t H5FA__dblock_delete(H5FA_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t dblk_addr);
+H5_DLL herr_t H5FA__dblock_dest(H5FA_dblock_t *dblock);
+
+/* Data block page routines */
+H5_DLL herr_t H5FA__dblk_page_create(H5FA_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t addr, size_t nelmts);
+H5_DLL H5FA_dblk_page_t *H5FA__dblk_page_alloc(H5FA_hdr_t *hdr, size_t nelmts);
+H5_DLL H5FA_dblk_page_t *H5FA__dblk_page_protect(H5FA_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t dblk_page_addr, size_t dblk_page_nelmts, unsigned flags);
+H5_DLL herr_t H5FA__dblk_page_unprotect(H5FA_dblk_page_t *dblk_page,
+ hid_t dxpl_id, unsigned cache_flags);
+H5_DLL herr_t H5FA__dblk_page_dest(H5FA_dblk_page_t *dblk_page);
+
+/* Debugging routines for dumping file structures */
+H5_DLL herr_t H5FA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5FA_class_t *cls, haddr_t obj_addr);
+H5_DLL herr_t H5FA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, const H5FA_class_t *cls,
+ haddr_t hdr_addr, haddr_t obj_addr);
+
+/* Testing routines */
+#ifdef H5FA_TESTING
+H5_DLL herr_t H5FA_get_cparam_test(const H5FA_t *ea, H5FA_create_t *cparam);
+H5_DLL int H5FA_cmp_cparam_test(const H5FA_create_t *cparam1, const H5FA_create_t *cparam2);
+#endif /* H5FA_TESTING */
+
+#endif /* _H5FApkg_H */
+
diff --git a/src/H5FAprivate.h b/src/H5FAprivate.h
new file mode 100644
index 0000000..1e44126
--- /dev/null
+++ b/src/H5FAprivate.h
@@ -0,0 +1,142 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAprivate.h
+ *
+ * Purpose: Private header for library accessible Fixed
+ * Array routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5FAprivate_H
+#define _H5FAprivate_H
+
+/* Include package's public header */
+#ifdef NOT_YET
+#include "H5FApublic.h"
+#endif /* NOT_YET */
+
+/* Private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Fprivate.h" /* File access */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Fixed Array class IDs */
+typedef enum H5FA_cls_id_t {
+ H5FA_CLS_CHUNK_ID = 0, /* Fixed array is for indexing dataset chunks w/o filters */
+ H5FA_CLS_FILT_CHUNK_ID, /* Fixed array is for indexing dataset chunks w/filters */
+
+ /* Start real class IDs at 0 -QAK */
+ /* (keep these last) */
+ H5FA_CLS_TEST_ID, /* Fixed array is for testing (do not use for actual data) */
+ H5FA_NUM_CLS_ID /* Number of Fixed Array class IDs (must be last) */
+} H5FA_cls_id_t;
+
+/*
+ * Each type of element that can be stored in a Fixed Array has a
+ * variable of this type that contains class variables and methods.
+ */
+typedef struct H5FA_class_t {
+ H5FA_cls_id_t id; /* ID of Fixed Array class, as found in file */
+ const char *name; /* Name of class (for debugging) */
+ size_t nat_elmt_size; /* Size of native (memory) element */
+
+ /* Fixed array client callback methods */
+ void *(*crt_context)(void *udata); /* Create context for other callbacks */
+ herr_t (*dst_context)(void *ctx); /* Destroy context */
+ herr_t (*fill)(void *nat_blk, size_t nelmts); /* Fill array of elements with encoded form of "missing element" value */
+ herr_t (*encode)(void *raw, const void *elmt, size_t nelmts, void *ctx); /* Encode elements from native form to disk storage form */
+ herr_t (*decode)(const void *raw, void *elmt, size_t nelmts, void *ctx); /* Decode elements from disk storage form to native form */
+ herr_t (*debug)(FILE *stream, int indent, int fwidth, hsize_t idx, const void *elmt); /* Print an element for debugging */
+ void *(*crt_dbg_ctx)(H5F_t *f, hid_t dxpl_id, haddr_t obj_addr); /* Create debugging context */
+ herr_t (*dst_dbg_ctx)(void *dbg_ctx); /* Destroy debugging context */
+} H5FA_class_t;
+
+/* Fixed array creation parameters */
+typedef struct H5FA_create_t {
+ const H5FA_class_t *cls; /* Class of Fixed Array to create */
+ uint8_t raw_elmt_size; /* Element size in file (in bytes) */
+ uint8_t max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in a data block page) -
+ * i.e. # of bits needed to store max. # of elements
+ * in a data block page
+ */
+ hsize_t nelmts; /* # of elements in array */
+} H5FA_create_t;
+
+/* Fixed array metadata statistics info */
+typedef struct H5FA_stat_t {
+ /* Non-stored (i.e. computed) fields */
+ hsize_t hdr_size; /* Size of header */
+ hsize_t dblk_size; /* Size of data block */
+
+ /* Stored fields */
+ hsize_t nelmts; /* # of elements */
+} H5FA_stat_t;
+
+/* Fixed Array info (forward decl - defined in H5FApkg.h) */
+typedef struct H5FA_t H5FA_t;
+
+/* Define the operator callback function pointer for H5FA_iterate() */
+typedef int (*H5FA_operator_t)(hsize_t idx, const void *_elmt, void *_udata);
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+/* The Fixed Array class for dataset chunks w/o filters*/
+H5_DLLVAR const H5FA_class_t H5FA_CLS_CHUNK[1];
+
+/* The Fixed Array class for dataset chunks w/ filters*/
+H5_DLLVAR const H5FA_class_t H5FA_CLS_FILT_CHUNK[1];
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General routines */
+H5_DLL H5FA_t *H5FA_create(H5F_t *f, hid_t dxpl_id, const H5FA_create_t *cparam,
+ void *ctx_udata);
+H5_DLL H5FA_t *H5FA_open(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata);
+H5_DLL herr_t H5FA_get_nelmts(const H5FA_t *fa, hsize_t *nelmts);
+H5_DLL herr_t H5FA_get_addr(const H5FA_t *fa, haddr_t *addr);
+H5_DLL herr_t H5FA_set(const H5FA_t *fa, hid_t dxpl_id, hsize_t idx, const void *elmt);
+H5_DLL herr_t H5FA_get(const H5FA_t *fa, hid_t dxpl_id, hsize_t idx, void *elmt);
+H5_DLL herr_t H5FA_depend(H5FA_t *fa, hid_t dxpl_id, H5AC_proxy_entry_t *parent);
+H5_DLL herr_t H5FA_iterate(H5FA_t *fa, hid_t dxpl_id, H5FA_operator_t op, void *udata);
+H5_DLL herr_t H5FA_close(H5FA_t *fa, hid_t dxpl_id);
+H5_DLL herr_t H5FA_delete(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata);
+H5_DLL herr_t H5FA_patch_file(H5FA_t *fa, H5F_t *f);
+
+/* Statistics routines */
+H5_DLL herr_t H5FA_get_stats(const H5FA_t *ea, H5FA_stat_t *stats);
+
+/* Debugging routines */
+#ifdef H5FA_DEBUGGING
+#endif /* H5FA_DEBUGGING */
+
+#endif /* _H5FAprivate_H */
+
diff --git a/src/H5FAstat.c b/src/H5FAstat.c
new file mode 100644
index 0000000..3c06855
--- /dev/null
+++ b/src/H5FAstat.c
@@ -0,0 +1,111 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FAstat.c
+ *
+ * Purpose: Fixed array metadata statistics functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_get_stats
+ *
+ * Purpose: Query the metadata stats of an array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5FA_get_stats(const H5FA_t *fa, H5FA_stat_t *stats))
+
+ /* Local variables */
+
+#ifdef H5FA_DEBUG
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* H5FA_DEBUG */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fa);
+ HDassert(stats);
+
+ /* Copy fixed array statistics */
+ HDmemcpy(stats, &fa->hdr->stats, sizeof(fa->hdr->stats));
+
+END_FUNC(PRIV) /* end H5FA_get_stats() */
+
diff --git a/src/H5FAtest.c b/src/H5FAtest.c
new file mode 100644
index 0000000..3c6d8e4
--- /dev/null
+++ b/src/H5FAtest.c
@@ -0,0 +1,420 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Fixed array testing functions.
+ *
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FAmodule.h" /* This source code file is part of the H5FA module */
+#define H5FA_TESTING
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FApkg.h" /* Fixed Arrays */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Sanity checking value for callback contexts */
+#define H5FA__TEST_BOGUS_VAL 42
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Callback context */
+typedef struct H5FA__test_ctx_t {
+ uint32_t bogus; /* Placeholder field to verify that context is working */
+} H5FA__test_ctx_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Fixed array class callbacks */
+static void *H5FA__test_crt_context(void *udata);
+static herr_t H5FA__test_dst_context(void *ctx);
+static herr_t H5FA__test_fill(void *nat_blk, size_t nelmts);
+static herr_t H5FA__test_encode(void *raw, const void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5FA__test_decode(const void *raw, void *elmt, size_t nelmts,
+ void *ctx);
+static herr_t H5FA__test_debug(FILE *stream, int indent, int fwidth,
+ hsize_t idx, const void *elmt);
+static void *H5FA__test_crt_dbg_context(H5F_t *f, hid_t dxpl_id,
+ haddr_t obj_addr);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Fixed array testing class information */
+const H5FA_class_t H5FA_CLS_TEST[1]={{
+ H5FA_CLS_TEST_ID, /* Type of Fixed array */
+ "Testing", /* Name of fixed array class */
+ sizeof(uint64_t), /* Size of native element */
+ H5FA__test_crt_context, /* Create context */
+ H5FA__test_dst_context, /* Destroy context */
+ H5FA__test_fill, /* Fill block of missing elements callback */
+ H5FA__test_encode, /* Element encoding callback */
+ H5FA__test_decode, /* Element decoding callback */
+ H5FA__test_debug, /* Element debugging callback */
+ H5FA__test_crt_dbg_context, /* Create debugging context */
+ H5FA__test_dst_context /* Destroy debugging context */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FA__test_ctx_t struct */
+H5FL_DEFINE_STATIC(H5FA__test_ctx_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_crt_context
+ *
+ * Purpose: Create context for callbacks
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5FA__test_crt_context(void H5_ATTR_UNUSED *udata))
+
+ /* Local variables */
+ H5FA__test_ctx_t *ctx; /* Context for callbacks */
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5FA__test_ctx_t)))
+ H5E_THROW(H5E_CANTALLOC, "can't allocate fixed array client callback context")
+
+ /* Initialize the context */
+ ctx->bogus = H5FA__TEST_BOGUS_VAL;
+
+ /* Set return value */
+ ret_value = ctx;
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__test_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_dst_context
+ *
+ * Purpose: Destroy context for callbacks
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__test_dst_context(void *_ctx))
+
+ /* Local variables */
+ H5FA__test_ctx_t *ctx = (H5FA__test_ctx_t *)_ctx; /* Callback context to destroy */
+
+ /* Sanity checks */
+ HDassert(H5FA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Release context structure */
+ ctx = H5FL_FREE(H5FA__test_ctx_t, ctx);
+
+END_FUNC(STATIC) /* end H5FA__test_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_fill
+ *
+ * Purpose: Fill "missing elements" in block of elements
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__test_fill(void *nat_blk, size_t nelmts))
+
+ /* Local variables */
+ uint64_t fill_val = H5FA_TEST_FILL; /* Value to fill elements with */
+
+ /* Sanity checks */
+ HDassert(nat_blk);
+ HDassert(nelmts);
+
+ H5VM_array_fill(nat_blk, &fill_val, sizeof(uint64_t), nelmts);
+
+END_FUNC(STATIC) /* end H5FA__test_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_encode
+ *
+ * Purpose: Encode an element from "native" to "raw" form
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__test_encode(void *raw, const void *_elmt, size_t nelmts, void H5_ATTR_UNUSED *_ctx))
+
+ /* Local variables */
+#ifndef NDEBUG
+ H5FA__test_ctx_t *ctx = (H5FA__test_ctx_t *)_ctx; /* Callback context to destroy */
+#endif /* NDEBUG */
+ const uint64_t *elmt = (const uint64_t *)_elmt; /* Convenience pointer to native elements */
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(H5FA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Encode native elements into raw elements */
+ while(nelmts) {
+ /* Encode element */
+ /* (advances 'raw' pointer) */
+ UINT64ENCODE(raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to encode */
+ nelmts--;
+ } /* end while */
+
+END_FUNC(STATIC) /* end H5FA__test_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_decode
+ *
+ * Purpose: Decode an element from "raw" to "native" form
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__test_decode(const void *_raw, void *_elmt, size_t nelmts, void H5_ATTR_UNUSED *_ctx))
+
+ /* Local variables */
+#ifndef NDEBUG
+ H5FA__test_ctx_t *ctx = (H5FA__test_ctx_t *)_ctx; /* Callback context to destroy */
+#endif /* NDEBUG */
+ uint64_t *elmt = (uint64_t *)_elmt; /* Convenience pointer to native elements */
+ const uint8_t *raw = (const uint8_t *)_raw; /* Convenience pointer to raw elements */
+
+ /* Sanity checks */
+ HDassert(raw);
+ HDassert(elmt);
+ HDassert(nelmts);
+ HDassert(H5FA__TEST_BOGUS_VAL == ctx->bogus);
+
+ /* Decode raw elements into native elements */
+ while(nelmts) {
+ /* Decode element */
+ /* (advances 'raw' pointer) */
+ UINT64DECODE(raw, *elmt);
+
+ /* Advance native element pointer */
+ elmt++;
+
+ /* Decrement # of elements to decode */
+ nelmts--;
+ } /* end while */
+
+END_FUNC(STATIC) /* end H5FA__test_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_debug
+ *
+ * Purpose: Display an element for debugging
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+herr_t, SUCCEED, -,
+H5FA__test_debug(FILE *stream, int indent, int fwidth, hsize_t idx,
+ const void *elmt))
+
+ /* Local variables */
+ char temp_str[128]; /* Temporary string, for formatting */
+
+ /* Sanity checks */
+ HDassert(stream);
+ HDassert(elmt);
+
+ /* Print element */
+ sprintf(temp_str, "Element #%llu:", (unsigned long long)idx);
+ HDfprintf(stream, "%*s%-*s %llu\n", indent, "", fwidth, temp_str,
+ (unsigned long long)*(const uint64_t *)elmt);
+
+END_FUNC(STATIC) /* end H5FA__test_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA__test_crt_dbg_context
+ *
+ * Purpose: Create context for debugging callback
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 1, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+void *, NULL, NULL,
+H5FA__test_crt_dbg_context(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t H5_ATTR_UNUSED obj_addr))
+
+ /* Local variables */
+ H5FA__test_ctx_t *ctx; /* Context for callbacks */
+
+ /* Allocate new context structure */
+ if(NULL == (ctx = H5FL_MALLOC(H5FA__test_ctx_t)))
+ H5E_THROW(H5E_CANTALLOC, "can't allocate fixed array client callback context")
+
+ /* Initialize the context */
+ ctx->bogus = H5FA__TEST_BOGUS_VAL;
+
+ /* Set return value */
+ ret_value = ctx;
+
+CATCH
+
+END_FUNC(STATIC) /* end H5FA__test_crt_dbg_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_get_cparam_test
+ *
+ * Purpose: Retrieve the parameters used to create the fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+herr_t, SUCCEED, -,
+H5FA_get_cparam_test(const H5FA_t *fa, H5FA_create_t *cparam))
+
+ /* Check arguments. */
+ HDassert(fa);
+ HDassert(cparam);
+
+ /* Get fixed array creation parameters */
+ cparam->raw_elmt_size = fa->hdr->cparam.raw_elmt_size;
+ cparam->nelmts = fa->hdr->cparam.nelmts;
+
+END_FUNC(PRIV) /* end H5FA_get_cparam_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FA_cmp_cparam_test
+ *
+ * Purpose: Compare the parameters used to create the fixed array
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Thursday, April 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERRCATCH,
+int, 0, -,
+H5FA_cmp_cparam_test(const H5FA_create_t *cparam1, const H5FA_create_t *cparam2))
+
+ /* Check arguments. */
+ HDassert(cparam1);
+ HDassert(cparam2);
+
+ /* Compare creation parameters for array */
+ if(cparam1->raw_elmt_size < cparam2->raw_elmt_size)
+ H5_LEAVE(-1)
+ else if(cparam1->raw_elmt_size > cparam2->raw_elmt_size)
+ H5_LEAVE(1)
+
+CATCH
+
+END_FUNC(PRIV) /* end H5FA_cmp_cparam_test() */
+
diff --git a/src/H5FD.c b/src/H5FD.c
new file mode 100644
index 0000000..dcfaa6d
--- /dev/null
+++ b/src/H5FD.c
@@ -0,0 +1,2078 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, July 26, 1999
+ *
+ * Purpose: The Virtual File Layer as described in documentation.
+ * This is the greatest common denominator for all types of
+ * storage access whether a file, memory, network, etc. This
+ * layer usually just dispatches the request to an actual
+ * file driver layer.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDpkg.h" /* File Drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5FD_free_cls(H5FD_class_t *cls);
+static int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/);
+static int H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*
+ * Global count of the number of H5FD_t's handed out. This is used as a
+ * "serial number" for files that are currently open and is used for the
+ * 'fileno' field in H5O_info_t. However, if a VFL driver is not able
+ * to detect whether two files are the same, a file that has been opened
+ * by H5Fopen more than once with that VFL driver will have two different
+ * serial numbers. :-/
+ *
+ * Also, if a file is opened, the 'fileno' field is retrieved for an
+ * object and the file is closed and re-opened, the 'fileno' value will
+ * be different.
+ */
+static unsigned long H5FD_file_serial_no_g;
+
+/* File driver ID class */
+static const H5I_class_t H5I_VFL_CLS[1] = {{
+ H5I_VFL, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5FD_free_cls /* Callback routine for closing objects of this class */
+}};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initialize the virtual file layer.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 26, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ if(H5I_register_type(H5I_VFL_CLS) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Reset the file serial numbers */
+ H5FD_file_serial_no_g = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_term_package
+ *
+ * Purpose: Terminate this interface: free all memory and reset global
+ * variables to their initial values. Release all ID groups
+ * associated with this interface.
+ *
+ * Return: Success: Positive if anything was done that might
+ * have affected other interfaces; zero
+ * otherwise.
+ * Failure: Never fails.
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FD_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ if(H5I_nmembers(H5I_VFL) > 0) {
+ (void)H5I_clear_type(H5I_VFL, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+ else {
+ /* Destroy the VFL driver id group */
+ n += (H5I_dec_type_ref(H5I_VFL) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5FD_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_free_cls
+ *
+ * Purpose: Frees a file driver class struct and returns an indication of
+ * success. This function is used as the free callback for the
+ * virtual file layer object identifiers (cf H5FD__init_package).
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 26, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_free_cls(H5FD_class_t *cls)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(cls);
+
+ /* If the file driver has a terminate callback, call it to give the file
+ * driver a chance to free singletons or other resources which will become
+ * invalid once the class structure is freed.
+ */
+ if(cls->terminate && cls->terminate() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEOBJ, FAIL, "virtual file driver '%s' did not terminate cleanly", cls->name)
+
+ H5MM_xfree(cls);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_free_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDregister
+ *
+ * Purpose: Registers a new file driver as a member of the virtual file
+ * driver class. Certain fields of the class struct are
+ * required and that is checked here so it doesn't have to be
+ * checked every time the field is accessed.
+ *
+ * Return: Success: A file driver ID which is good until the
+ * library is closed or the driver is
+ * unregistered.
+ *
+ * Failure: A negative value.
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 26, 1999
+ *
+ * Modifications:
+ * Copied guts of function into H5FD_register
+ * Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FDregister(const H5FD_class_t *cls)
+{
+ hid_t ret_value;
+ H5FD_mem_t type;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "*x", cls);
+
+ /* Check arguments */
+ if(!cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, "null class pointer is disallowed")
+ if(!cls->open || !cls->close)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, "`open' and/or `close' methods are not defined")
+ if(!cls->get_eoa || !cls->set_eoa)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, "`get_eoa' and/or `set_eoa' methods are not defined")
+ if(!cls->get_eof)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, "`get_eof' method is not defined")
+ if(!cls->read || !cls->write)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, "`read' and/or `write' method is not defined")
+ for (type=H5FD_MEM_DEFAULT; type<H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t,type))
+ if(cls->fl_map[type]<H5FD_MEM_NOLIST || cls->fl_map[type]>=H5FD_MEM_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid free-list mapping")
+
+ /* Create the new class ID */
+ if((ret_value=H5FD_register(cls, sizeof(H5FD_class_t), TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register file driver ID")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_register
+ *
+ * Purpose: Registers a new file driver as a member of the virtual file
+ * driver class. Certain fields of the class struct are
+ * required and that is checked here so it doesn't have to be
+ * checked every time the field is accessed.
+ *
+ * Return: Success: A file driver ID which is good until the
+ * library is closed or the driver is
+ * unregistered.
+ *
+ * Failure: A negative value.
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 26, 1999
+ *
+ * Modifications:
+ * Broke into public and internal routines & added 'size'
+ * parameter to internal routine, which allows us to create
+ * sub-classes of H5FD_class_t for internal support (see the
+ * MPI drivers, etc.)
+ * Quincey Koziol
+ * January 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_register(const void *_cls, size_t size, hbool_t app_ref)
+{
+ const H5FD_class_t *cls = (const H5FD_class_t *)_cls;
+ H5FD_class_t *saved = NULL;
+ H5FD_mem_t type;
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ HDassert(cls);
+ HDassert(cls->open && cls->close);
+ HDassert(cls->get_eoa && cls->set_eoa);
+ HDassert(cls->get_eof);
+ HDassert(cls->read && cls->write);
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ HDassert(cls->fl_map[type] >= H5FD_MEM_NOLIST && cls->fl_map[type] < H5FD_MEM_NTYPES);
+
+ /* Copy the class structure so the caller can reuse or free it */
+ if(NULL == (saved = (H5FD_class_t *)H5MM_malloc(size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for file driver class struct")
+ HDmemcpy(saved, cls, size);
+
+ /* Create the new class ID */
+ if((ret_value = H5I_register(H5I_VFL, saved, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register file driver ID")
+
+done:
+ if(ret_value < 0)
+ if(saved)
+ H5MM_xfree(saved);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_register() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDunregister
+ *
+ * Purpose: Removes a driver ID from the library. This in no way affects
+ * file access property lists which have been defined to use
+ * this driver or files which are already opened under this
+ * driver.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 26, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDunregister(hid_t driver_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", driver_id);
+
+ /* Check arguments */
+ if(NULL == H5I_object_verify(driver_id, H5I_VFL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file driver")
+
+ /* The H5FD_class_t struct will be freed by this function */
+ if(H5I_dec_app_ref(driver_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "unable to unregister file driver")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDunregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_class
+ *
+ * Purpose: Obtains a pointer to the driver struct containing all the
+ * callback pointers, etc. The PLIST_ID argument can be a file
+ * access property list, a data transfer property list, or a
+ * file driver identifier.
+ *
+ * Return: Success: Ptr to the driver information. The pointer is
+ * only valid as long as the driver remains
+ * registered or some file or property list
+ * exists which references the driver.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 20, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FD_class_t *
+H5FD_get_class(hid_t id)
+{
+ H5FD_class_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(H5I_VFL == H5I_get_type(id))
+ ret_value = (H5FD_class_t *)H5I_object(id);
+ else {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "can't find object for ID")
+
+ if(TRUE == H5P_isa_class(id, H5P_FILE_ACCESS)) {
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+
+ if(H5P_peek(plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get driver ID & info")
+ ret_value = H5FD_get_class(driver_prop.driver_id);
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a driver id or file access property list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sb_size
+ *
+ * Purpose: Obtains the number of bytes required to store the driver file
+ * access data in the HDF5 superblock.
+ *
+ * Return: Success: Number of bytes required.
+ *
+ * Failure: 0 if an error occurs or if the driver has no
+ * data to store in the superblock.
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5FD_sb_size(H5FD_t *file)
+{
+ hsize_t ret_value=0;
+
+ FUNC_ENTER_NOAPI(0)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->sb_size)
+ ret_value = (file->cls->sb_size)(file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sb_encode
+ *
+ * Purpose: Encode driver-specific data into the output arguments. The
+ * NAME is a nine-byte buffer which should get an
+ * eight-character driver name and/or version followed by a null
+ * terminator. The BUF argument is a buffer to receive the
+ * encoded driver-specific data. The size of the BUF array is
+ * the size returned by the H5FD_sb_size() call.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_sb_encode(H5FD_t *file, char *name/*out*/, uint8_t *buf)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+ if(file->cls->sb_encode && (file->cls->sb_encode)(file, name/*out*/, buf/*out*/) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_encode request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sb_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__sb_decode
+ *
+ * Purpose: Decodes the driver information block.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__sb_decode(H5FD_t *file, const char *name, const uint8_t *buf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file && file->cls);
+
+ /* Decode driver information */
+ if(file->cls->sb_decode && (file->cls->sb_decode)(file, name, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_decode request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__sb_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sb_load
+ *
+ * Purpose: Validate and decode the driver information block.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, July 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_sb_load(H5FD_t *file, const char *name, const uint8_t *buf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ /* Check if driver matches driver information saved. Unfortunately, we can't push this
+ * function to each specific driver because we're checking if the driver is correct.
+ */
+ if(!HDstrncmp(name, "NCSAfami", (size_t)8) && HDstrcmp(file->cls->name, "family"))
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "family driver should be used")
+ if(!HDstrncmp(name, "NCSAmult", (size_t)8) && HDstrcmp(file->cls->name, "multi"))
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "multi driver should be used")
+
+ /* Decode driver information */
+ if(H5FD__sb_decode(file, name, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "unable to decode driver information")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sb_load() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_fapl_get
+ *
+ * Purpose: Gets the file access property list associated with a file.
+ * Usually the file will copy what it needs from the original
+ * file access property list when the file is created. The
+ * purpose of this function is to create a new file access
+ * property list based on the settings in the file, which may
+ * have been modified from the original file access property
+ * list.
+ *
+ * Return: Success: Pointer to a new file access property list
+ * with all members copied. If the file is
+ * closed then this property list lives on, and
+ * vice versa.
+ *
+ * Failure: NULL, including when the file has no
+ * properties.
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FD_fapl_get(H5FD_t *file)
+{
+ void *ret_value=NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(file);
+
+ if(file->cls->fapl_get)
+ ret_value = (file->cls->fapl_get)(file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_fapl_close
+ *
+ * Purpose: Closes a driver for a dataset transfer property list
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 3, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_fapl_close(hid_t driver_id, const void *driver_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(driver_id > 0) {
+ H5FD_class_t *driver;
+
+ /* Retrieve the driver for the ID */
+ if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a driver ID")
+
+ /* Allow driver to free info or do it ourselves */
+ if(driver_info) {
+ if(driver->fapl_free) {
+ if((driver->fapl_free)((void *)driver_info) < 0) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "driver free request failed")
+ } /* end if */
+ else
+ H5MM_xfree((void *)driver_info); /* Casting away const OK -QAK */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_fapl_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDopen
+ *
+ * Purpose: Opens a file named NAME for the type(s) of access described
+ * by the bit vector FLAGS according to a file access property
+ * list FAPL_ID (which may be the constant H5P_DEFAULT). The
+ * file should expect to handle format addresses in the range [0,
+ * MAXADDR] (if MAXADDR is the undefined address then the caller
+ * doesn't care about the address range).
+ *
+ * Possible values for the FLAGS bits are:
+ *
+ * H5F_ACC_RDWR: Open the file for read and write access. If
+ * this bit is not set then open the file for
+ * read only access. It is permissible to open a
+ * file for read and write access when only read
+ * access is requested by the library (the
+ * library will never attempt to write to a file
+ * which it opened with only read access).
+ *
+ * H5F_ACC_CREATE: Create the file if it doesn't already exist.
+ * However, see H5F_ACC_EXCL below.
+ *
+ * H5F_ACC_TRUNC: Truncate the file if it already exists. This
+ * is equivalent to deleting the file and then
+ * creating a new empty file.
+ *
+ * H5F_ACC_EXCL: When used with H5F_ACC_CREATE, if the file
+ * already exists then the open should fail.
+ * Note that this is unsupported/broken with
+ * some file drivers (e.g., sec2 across nfs) and
+ * will contain a race condition when used to
+ * perform file locking.
+ *
+ * The MAXADDR is the maximum address which will be requested by
+ * the library during an allocation operation. Usually this is
+ * the same value as the MAXADDR field of the class structure,
+ * but it can be smaller if the driver is being used under some
+ * other driver.
+ *
+ * Note that when the driver `open' callback gets control that
+ * the public part of the file struct (the H5FD_t part) will be
+ * incomplete and will be filled in after that callback returns.
+ *
+ * Return: Success: Pointer to a new file driver struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, July 27, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FD_t *
+H5FDopen(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ H5FD_t *ret_value=NULL;
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE4("*x", "*sIuia", name, flags, fapl_id, maxaddr);
+
+ /* Check arguments */
+ if(H5P_DEFAULT == fapl_id)
+ fapl_id = H5P_FILE_ACCESS_DEFAULT;
+ else
+ if(TRUE!=H5P_isa_class(fapl_id,H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+
+ if(NULL==(ret_value=H5FD_open(name, flags, fapl_id, maxaddr)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "unable to open file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_open
+ *
+ * Purpose: Private version of H5FDopen()
+ *
+ * Return: Success: Pointer to a new file driver struct
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FD_t *
+H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ H5FD_class_t *driver; /* VFD for file */
+ H5FD_t *file = NULL; /* VFD file struct */
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+ H5P_genplist_t *plist; /* Property list pointer */
+ unsigned long driver_flags = 0; /* File-inspecific driver feature flags */
+ H5FD_file_image_info_t file_image_info; /* Initial file image */
+ H5FD_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ if(0 == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "zero format address range")
+
+ /* Get file access property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+
+ /* Get the VFD to open the file with */
+ if(H5P_peek(plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get driver ID & info")
+
+ /* Get driver info */
+ if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_prop.driver_id)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "invalid driver ID in file access property list")
+ if(NULL == driver->open)
+ HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file driver has no `open' method")
+
+ /* Query driver flag */
+ H5FD_driver_query(driver, &driver_flags);
+
+ /* Get initial file image info */
+ if(H5P_peek(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file image info")
+
+ /* If an image is provided, make sure the driver supports this feature */
+ HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) ||
+ ((file_image_info.buffer == NULL) && (file_image_info.size == 0)));
+ if((file_image_info.buffer != NULL) && !(driver_flags & H5FD_FEAT_ALLOW_FILE_IMAGE))
+ HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file image set, but not supported.")
+
+ /* Dispatch to file driver */
+ if(HADDR_UNDEF == maxaddr)
+ maxaddr = driver->maxaddr;
+ if(NULL == (file = (driver->open)(name, flags, fapl_id, maxaddr)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "open failed")
+
+ /* Set the file access flags */
+ file->access_flags = flags;
+
+ /*
+ * Fill in public fields. We must increment the reference count on the
+ * driver ID to prevent it from being freed while this file is open.
+ */
+ file->driver_id = driver_prop.driver_id;
+ if(H5I_inc_ref(file->driver_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver")
+ file->cls = driver;
+ file->maxaddr = maxaddr;
+ if(H5P_get(plist, H5F_ACS_ALIGN_THRHD_NAME, &(file->threshold)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment threshold")
+ if(H5P_get(plist, H5F_ACS_ALIGN_NAME, &(file->alignment)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment")
+
+ /* Retrieve the VFL driver feature flags */
+ if(H5FD_query(file, &(file->feature_flags)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "unable to query file driver")
+
+ /* Increment the global serial number & assign it to this H5FD_t object */
+ if(++H5FD_file_serial_no_g == 0) {
+ /* (Just error out if we wrap around for now...) */
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "unable to get file serial number")
+ } /* end if */
+ file->fileno = H5FD_file_serial_no_g;
+
+ /* Start with base address set to 0 */
+ /* (This will be changed later, when the superblock is located) */
+ file->base_addr = 0;
+
+ /* Set return value */
+ ret_value = file;
+
+done:
+ /* Can't cleanup 'file' information, since we don't know what type it is */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDclose
+ *
+ * Purpose: Closes the file by calling the driver `close' callback, which
+ * should free all driver-private data and free the file struct.
+ * Note that the public part of the file struct (the H5FD_t part)
+ * will be all zero during the driver close callback like during
+ * the `open' callback.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, July 27, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDclose(H5FD_t *file)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*x", file);
+
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+
+ if(H5FD_close(file) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_close
+ *
+ * Purpose: Private version of H5FDclose()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_close(H5FD_t *file)
+{
+ const H5FD_class_t *driver;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(file && file->cls);
+
+ /* Prepare to close file by clearing all public fields */
+ driver = file->cls;
+ if(H5I_dec_ref(file->driver_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID")
+
+ /*
+ * Dispatch to the driver for actual close. If the driver fails to
+ * close the file then the file will be in an unusable state.
+ */
+ HDassert(driver->close);
+ if((driver->close)(file) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "close failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDcmp
+ *
+ * Purpose: Compare the keys of two files using the file driver callback
+ * if the files belong to the same driver, otherwise sort the
+ * files by driver class pointer value.
+ *
+ * Return: Success: A value like strcmp()
+ *
+ * Failure: Must never fail. If both file handles are
+ * invalid then they compare equal. If one file
+ * handle is invalid then it compares less than
+ * the other. If both files belong to the same
+ * driver and the driver doesn't provide a
+ * comparison callback then the file pointers
+ * themselves are compared.
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, July 27, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FDcmp(const H5FD_t *f1, const H5FD_t *f2)
+{
+ int ret_value;
+
+ FUNC_ENTER_API(-1) /*return value is arbitrary*/
+ H5TRACE2("Is", "*x*x", f1, f2);
+
+ ret_value = H5FD_cmp(f1, f2);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_cmp
+ *
+ * Purpose: Private version of H5FDcmp()
+ *
+ * Return: Success: A value like strcmp()
+ *
+ * Failure: Must never fail.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(-1) /*return value is arbitrary*/
+
+ if((!f1 || !f1->cls) && (!f2 || !f2->cls))
+ HGOTO_DONE(0)
+ if(!f1 || !f1->cls)
+ HGOTO_DONE(-1)
+ if(!f2 || !f2->cls)
+ HGOTO_DONE(1)
+ if(f1->cls < f2->cls)
+ HGOTO_DONE(-1)
+ if(f1->cls > f2->cls)
+ HGOTO_DONE(1)
+
+ /* Files are same driver; no cmp callback */
+ if(!f1->cls->cmp) {
+ if(f1<f2)
+ HGOTO_DONE(-1)
+ if(f1>f2)
+ HGOTO_DONE(1)
+ HGOTO_DONE(0)
+ }
+
+ ret_value = (f1->cls->cmp)(f1, f2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDquery
+ *
+ * Purpose: Query a VFL driver for its feature flags. (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FDquery(const H5FD_t *f, unsigned long *flags/*out*/)
+{
+ int ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("Is", "*xx", f, flags);
+
+ HDassert(f);
+ HDassert(flags);
+
+ ret_value = H5FD_query(f, flags);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_query
+ *
+ * Purpose: Private version of H5FDquery()
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(flags);
+
+ /* Check for query driver and call it */
+ if(f->cls->query)
+ ret_value = (f->cls->query)(f, flags);
+ else
+ *flags=0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_query() */
+
+
+/*-------------------------------------------------------------------------
+* Function: H5FD_driver_query
+*
+* Purpose: Similar to H5FD_query(), but intended for cases when we don't
+* have a file available (e.g. before one is opened). Since we
+* can't use the file to get the driver, the driver is passed in
+* as a parameter.
+*
+* Return: Success: non-negative
+* Failure: negative
+*
+* Programmer: Jacob Gruber
+* Wednesday, August 17, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static int
+H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(driver);
+ HDassert(flags);
+
+ /* Check for the driver to query and then query it */
+ if(driver->query)
+ ret_value = (driver->query)(NULL, flags);
+ else
+ *flags = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_driver_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDalloc
+ *
+ * Purpose: Allocates SIZE bytes of memory from the FILE. The memory will
+ * be used according to the allocation class TYPE. First we try
+ * to satisfy the request from one of the free lists, according
+ * to the free list map provided by the driver. The free list
+ * array has one entry for each request type and the value of
+ * that array element can be one of four possibilities:
+ *
+ * It can be the constant H5FD_MEM_DEFAULT (or zero) which
+ * indicates that the identity mapping is used. In other
+ * words, the request type maps to its own free list.
+ *
+ * It can be the request type itself, which has the same
+ * effect as the H5FD_MEM_DEFAULT value above.
+ *
+ * It can be the ID for another request type, which
+ * indicates that the free list for the specified type
+ * should be used instead.
+ *
+ * It can be the constant H5FD_MEM_NOLIST which means that
+ * no free list should be used for this type of request.
+ *
+ * If the request cannot be satisfied from a free list then
+ * either the driver's `alloc' callback is invoked (if one was
+ * supplied) or the end-of-address marker is extended. The
+ * `alloc' callback is always called with the same arguments as
+ * the H5FDalloc().
+ *
+ * Return: Success: The format address of the new file memory.
+ *
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, July 27, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FDalloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
+{
+ haddr_t ret_value = HADDR_UNDEF;
+
+ FUNC_ENTER_API(HADDR_UNDEF)
+ H5TRACE4("a", "*xMtih", file, type, dxpl_id, size);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "invalid file pointer")
+ if(type < H5FD_MEM_DEFAULT || type >= H5FD_MEM_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "invalid request type")
+ if(size == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "zero-size request")
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, HADDR_UNDEF, "not a data transfer property list")
+
+ /* Do the real work */
+ if(HADDR_UNDEF == (ret_value = H5FD_alloc_real(file, dxpl_id, type, size, NULL, NULL)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "unable to allocate file memory")
+
+ /* (Note compensating for base address subtraction in internal routine) */
+ ret_value += file->base_addr;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDalloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDfree
+ *
+ * Purpose: Frees format addresses starting with ADDR and continuing for
+ * SIZE bytes in the file FILE. The type of space being freed is
+ * specified by TYPE, which is mapped to a free list as
+ * described for the H5FDalloc() function above. If the request
+ * doesn't map to a free list then either the application `free'
+ * callback is invoked (if defined) or the memory is leaked.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, July 28, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDfree(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*xMtiah", file, type, dxpl_id, addr, size);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+ if(type < H5FD_MEM_DEFAULT || type >= H5FD_MEM_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid request type")
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+
+ /* Do the real work */
+ /* (Note compensating for base address addition in internal routine) */
+ if(H5FD_free_real(file, dxpl_id, type, addr - file->base_addr, size) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "file deallocation request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDfree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDget_eoa
+ *
+ * Purpose: Returns the address of the first byte after the last
+ * allocated memory in the file.
+ *
+ * Return: Success: First byte after allocated memory.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Friday, July 30, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FDget_eoa(H5FD_t *file, H5FD_mem_t type)
+{
+ haddr_t ret_value;
+
+ FUNC_ENTER_API(HADDR_UNDEF)
+ H5TRACE2("a", "*xMt", file, type);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "invalid file pointer")
+ if(type < H5FD_MEM_DEFAULT || type >= H5FD_MEM_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "invalid file type")
+
+ /* The real work */
+ if(HADDR_UNDEF == (ret_value = H5FD_get_eoa(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "file get eoa request failed")
+
+ /* (Note compensating for base address subtraction in internal routine) */
+ ret_value += file->base_addr;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDget_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDset_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. The ADDR is the
+ * address of the first byte past the last allocated byte of the
+ * file. This function is called from two places:
+ *
+ * It is called after an existing file is opened in order to
+ * "allocate" enough space to read the superblock and then
+ * to "allocate" the entire hdf5 file based on the contents
+ * of the superblock.
+ *
+ * It is called during file memory allocation if the
+ * allocation request cannot be satisfied from the free list
+ * and the driver didn't supply an allocation callback.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative, no side effect
+ *
+ * Programmer: Robb Matzke
+ * Friday, July 30, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDset_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "*xMta", file, type, addr);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+ if(type < H5FD_MEM_DEFAULT || type >= H5FD_MEM_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file type")
+ if(!H5F_addr_defined(addr) || addr > file->maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid end-of-address value")
+
+ /* The real work */
+ /* (Note compensating for base address addition in internal routine) */
+ if(H5FD_set_eoa(file, type, addr - file->base_addr) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "file set eoa request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDset_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDget_eof
+ *
+ * Purpose: Returns the end-of-file address, which is the greater of the
+ * end-of-format address and the actual EOF marker. This
+ * function is called after an existing file is opened in order
+ * for the library to learn the true size of the underlying file
+ * and to determine whether the hdf5 data has been truncated.
+ *
+ * It is also used when a file is first opened to learn whether
+ * the file is empty or not.
+ *
+ * It is permissible for the driver to return the maximum address
+ * for the file size if the file is not empty.
+ *
+ * Return: Success: The EOF address.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FDget_eof(H5FD_t *file, H5FD_mem_t type)
+{
+ haddr_t ret_value;
+
+ FUNC_ENTER_API(HADDR_UNDEF)
+ H5TRACE2("a", "*xMt", file, type);
+
+ /* Check arguments */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, "invalid file pointer")
+
+ /* The real work */
+ if(HADDR_UNDEF == (ret_value = H5FD_get_eof(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "file get eof request failed")
+
+ /* (Note compensating for base address subtraction in internal routine) */
+ ret_value += file->base_addr;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDget_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_maxaddr
+ *
+ * Purpose: Private version of H5FDget_eof()
+ *
+ * Return: Success: The maximum address allowed in the file.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 3, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_get_maxaddr(const H5FD_t *file)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ HDassert(file);
+
+ /* Set return value */
+ ret_value = file->maxaddr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_maxaddr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_feature_flags
+ *
+ * Purpose: Retrieve the feature flags for the VFD
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_feature_flags(const H5FD_t *file, unsigned long *feature_flags)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(feature_flags);
+
+ /* Set feature flags to return */
+ *feature_flags = file->feature_flags;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_get_feature_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_set_feature_flags
+ *
+ * Purpose: Set the feature flags for the VFD
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Oct 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_set_feature_flags(H5FD_t *file, unsigned long feature_flags)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+
+ /* Set the file's feature flags */
+ file->feature_flags = feature_flags;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_set_feature_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_fs_type_map
+ *
+ * Purpose: Retrieve the free space type mapping for the VFD
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 17, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_fs_type_map(const H5FD_t *file, H5FD_mem_t *type_map)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(file && file->cls);
+ HDassert(type_map);
+
+ /* Check for VFD class providing a type map retrieval rouine */
+ if(file->cls->get_type_map) {
+ /* Retrieve type mapping for this file */
+ if((file->cls->get_type_map)(file, type_map) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get type map failed")
+ } /* end if */
+ else
+ /* Copy class's default free space type mapping */
+ HDmemcpy(type_map, file->cls->fl_map, sizeof(file->cls->fl_map));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_fs_type_map() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDread
+ *
+ * Purpose: Reads SIZE bytes from FILE beginning at address ADDR
+ * according to the data transfer property list DXPL_ID (which may
+ * be the constant H5P_DEFAULT). The result is written into the
+ * buffer BUF.
+ *
+ * Return: Success: Non-negative. The read result is written into
+ * the BUF buffer which should be allocated by
+ * the caller.
+ *
+ * Failure: Negative. The contents of BUF is undefined.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDread(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
+ void *buf/*out*/)
+{
+ H5FD_io_info_t fdio_info; /* File driver I/O object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "*xMtiazx", file, type, dxpl_id, addr, size, buf);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ if(!buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null result buffer")
+
+ /* Set up the file driver I/O info object */
+ fdio_info.file = file;
+ if(H5FD_MEM_DRAW == type) {
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end if */
+ else {
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end else */
+
+ /* Do the real work */
+ /* (Note compensating for base address addition in internal routine) */
+ if(H5FD_read(&fdio_info, type, addr - file->base_addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file read request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDread() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDwrite
+ *
+ * Purpose: Writes SIZE bytes to FILE beginning at address ADDR according
+ * to the data transfer property list DXPL_ID (which may be the
+ * constant H5P_DEFAULT). The bytes to be written come from the
+ * buffer BUF.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDwrite(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
+ const void *buf)
+{
+ H5FD_io_info_t fdio_info; /* File driver I/O object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "*xMtiaz*x", file, type, dxpl_id, addr, size, buf);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+ /* Get the default dataset transfer property list if the user didn't provide one */
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+ if(!buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null buffer")
+
+ /* Set up the file driver I/O info object */
+ fdio_info.file = file;
+ if(H5FD_MEM_DRAW == type) {
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end if */
+ else {
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end else */
+
+ /* The real work */
+ /* (Note compensating for base address addition in internal routine) */
+ if(H5FD_write(&fdio_info, type, addr - file->base_addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file write request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDwrite() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDflush
+ *
+ * Purpose: Notify driver to flush all cached data. If the driver has no
+ * flush method then nothing happens.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ * Modifications:
+ * Quincey Koziol, May 20, 2002
+ * Added 'closing' parameter
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "*xib", file, dxpl_id, closing);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+
+ /* Do the real work */
+ if(H5FD_flush(file, dxpl_id, closing) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFLUSH, FAIL, "file flush request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_flush
+ *
+ * Purpose: Private version of H5FDflush()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_flush(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->flush && (file->cls->flush)(file, dxpl_id, closing) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver flush request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDtruncate
+ *
+ * Purpose: Notify driver to truncate the file back to the allocated size.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 31, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "*xib", file, dxpl_id, closing);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transfer property list")
+
+ /* Do the real work */
+ if(H5FD_truncate(file, dxpl_id, closing) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "file flush request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_truncate
+ *
+ * Purpose: Private version of H5FDtruncate()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 31, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_truncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->truncate && (file->cls->truncate)(file, dxpl_id, closing) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver truncate request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDlock
+ *
+ * Purpose: Set a file lock
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDlock(H5FD_t *file, hbool_t rw)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "*xb", file, rw);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+
+ /* The real work */
+ if(H5FD_lock(file, rw) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "file lock request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDlock() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_lock
+ *
+ * Purpose: Private version of H5FDlock()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_lock(H5FD_t *file, hbool_t rw)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->lock && (file->cls->lock)(file, rw) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver lock request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FDunlock
+ *
+ * Purpose: Remove a file lock
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FDunlock(H5FD_t *file)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*x", file);
+
+ /* Check args */
+ if(!file || !file->cls)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer")
+
+ /* The real work */
+ if(H5FD_unlock(file) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "file unlock request failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDunlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_unlock
+ *
+ * Purpose: Private version of H5FDunlock()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_unlock(H5FD_t *file)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->unlock && (file->cls->unlock)(file) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver unlock request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_unlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_fileno
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'fileno' value
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5FD_t data structure)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * March 27, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_fileno(const H5FD_t *file, unsigned long *filenum)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(filenum);
+
+ /* Retrieve the file's serial number */
+ *filenum = file->fileno;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_get_fileno() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FDget_vfd_handle
+ *
+ * Purpose: Returns a pointer to the file handle of low-level virtual
+ * file driver.
+ *
+ * Return: Non-negative if succeed; negative otherwise.
+ *
+ * Programmer: Raymond Lu
+ * Sep. 16, 2002
+ *
+ * Modifications:
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5FDget_vfd_handle(H5FD_t *file, hid_t fapl, void **file_handle)
+{
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "*xi**x", file, fapl, file_handle);
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file_handle);
+
+ ret_value = H5FD_get_vfd_handle(file, fapl, file_handle);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5FDget_vfd_handle() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_get_vfd_handle
+ *
+ * Purpose: Retrieve the file handle for file driver.
+ *
+ * Return: Non-negative if succeed; negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * Sep. 16, 2002
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl, void **file_handle)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file_handle);
+
+ if(NULL == file->cls->get_handle)
+ HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, FAIL, "file driver has no `get_vfd_handle' method")
+ if((file->cls->get_handle)(file, fapl, file_handle) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_vfd_handle() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_set_base_addr
+ *
+ * Purpose: Set the base address for the file
+ *
+ * Return: Non-negative if succeed; negative if fails.
+ *
+ * Programmer: Quincey Koziol
+ * Jan. 17, 2008
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5F_addr_defined(base_addr));
+
+ /* Set the file's base address */
+ file->base_addr = base_addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_set_base_addr() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_get_base_addr
+ *
+ * Purpose: Get the base address for the file
+ *
+ * Return: Success: The absolute base address of the file
+ * Failure: The undefined address (HADDR_UNDEF)
+ *
+ * Programmer: Quincey Koziol
+ * Sept. 10, 2009
+ *
+ *--------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_get_base_addr(const H5FD_t *file)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+
+ /* Return the file's base address */
+ FUNC_LEAVE_NOAPI(file->base_addr)
+} /* end H5FD_get_base_addr() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_set_paged_aggr
+ *
+ * Purpose: Set "paged_aggr" for the file.
+ *
+ * Return: Non-negative if succeed; negative if fails.
+ *
+ * Programmer: Vailin Choi; April 2013
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5FD_set_paged_aggr(H5FD_t *file, hbool_t paged)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+
+ /* Indicate whether paged aggregation for handling file space is enabled or not */
+ file->paged_aggr = paged;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_set_paged_aggr() */
diff --git a/src/H5FDcore.c b/src/H5FDcore.c
new file mode 100644
index 0000000..d100a8b
--- /dev/null
+++ b/src/H5FDcore.c
@@ -0,0 +1,1546 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Tuesday, August 10, 1999
+ *
+ * Purpose: A driver which stores the HDF5 data in main memory using
+ * only the HDF5 public API. This driver is useful for fast
+ * access to small, temporary hdf5 files.
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDcore.h" /* Core file driver */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SLprivate.h" /* Skip lists */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_CORE_g = 0;
+
+/* The skip list node type. Represents a region in the file. */
+typedef struct H5FD_core_region_t {
+ haddr_t start; /* Start address of the region */
+ haddr_t end; /* End address of the region */
+} H5FD_core_region_t;
+
+/* The description of a file belonging to this driver. The 'eoa' and 'eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying memory).
+ */
+typedef struct H5FD_core_t {
+ H5FD_t pub; /* public stuff, must be first */
+ char *name; /* for equivalence testing */
+ unsigned char *mem; /* the underlying memory */
+ haddr_t eoa; /* end of allocated region */
+ haddr_t eof; /* current allocated size */
+ size_t increment; /* multiples for mem allocation */
+ hbool_t backing_store; /* write to file name on flush */
+ size_t bstore_page_size; /* backing store page size */
+ int fd; /* backing store file descriptor */
+ /* Information for determining uniqueness of a file with a backing store */
+#ifndef H5_HAVE_WIN32_API
+ /* On most systems the combination of device and i-node number uniquely
+ * identify a file.
+ */
+ dev_t device; /*file device number */
+ ino_t inode; /*file i-node number */
+#else
+ /* Files in windows are uniquely identified by the volume serial
+ * number and the file index (both low and high parts).
+ *
+ * There are caveats where these numbers can change, especially
+ * on FAT file systems. On NTFS, however, a file should keep
+ * those numbers the same until renamed or deleted (though you
+ * can use ReplaceFile() on NTFS to keep the numbers the same
+ * while renaming).
+ *
+ * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
+ * more information.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
+ */
+ DWORD nFileIndexLow;
+ DWORD nFileIndexHigh;
+ DWORD dwVolumeSerialNumber;
+
+ HANDLE hFile; /* Native windows file handle */
+#endif /* H5_HAVE_WIN32_API */
+ hbool_t dirty; /* changes not saved? */
+ H5FD_file_image_callbacks_t fi_callbacks; /* file image callbacks */
+ H5SL_t *dirty_list; /* dirty parts of the file */
+} H5FD_core_t;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_core_fapl_t {
+ size_t increment; /* how much to grow memory */
+ hbool_t backing_store; /* write to file name on flush */
+} H5FD_core_fapl_t;
+
+/* Allocate memory in multiples of this size by default */
+#define H5FD_CORE_INCREMENT 8192
+
+/* These macros check for overflow of various quantities. These macros
+ * assume that file_offset_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely in memory.
+ */
+#define MAXADDR ((haddr_t)((~(size_t)0)-1))
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || (A) > (haddr_t)MAXADDR)
+#define SIZE_OVERFLOW(Z) ((Z) > (hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || \
+ (size_t)((A)+(Z))<(size_t)(A))
+
+/* Prototypes */
+static herr_t H5FD__core_add_dirty_region(H5FD_core_t *file, haddr_t start, haddr_t end);
+static herr_t H5FD__core_destroy_dirty_list(H5FD_core_t *file);
+static herr_t H5FD__core_write_to_bstore(H5FD_core_t *file, haddr_t addr, size_t size);
+static herr_t H5FD__core_term(void);
+static void *H5FD__core_fapl_get(H5FD_t *_file);
+static H5FD_t *H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+static herr_t H5FD__core_close(H5FD_t *_file);
+static int H5FD__core_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD__core_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD__core_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD__core_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD__core_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD__core_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD__core_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD__core_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD__core_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD__core_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_core_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_core_unlock(H5FD_t *_file);
+
+static const H5FD_class_t H5FD_core_g = {
+ "core", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD__core_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ sizeof(H5FD_core_fapl_t), /* fapl_size */
+ H5FD__core_fapl_get, /* fapl_get */
+ NULL, /* fapl_copy */
+ NULL, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD__core_open, /* open */
+ H5FD__core_close, /* close */
+ H5FD__core_cmp, /* cmp */
+ H5FD__core_query, /* query */
+ NULL, /* get_type_map */
+ NULL, /* alloc */
+ NULL, /* free */
+ H5FD__core_get_eoa, /* get_eoa */
+ H5FD__core_set_eoa, /* set_eoa */
+ H5FD__core_get_eof, /* get_eof */
+ H5FD__core_get_handle, /* get_handle */
+ H5FD__core_read, /* read */
+ H5FD__core_write, /* write */
+ H5FD__core_flush, /* flush */
+ H5FD__core_truncate, /* truncate */
+ H5FD_core_lock, /* lock */
+ H5FD_core_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+/* Define a free list to manage the region type */
+H5FL_DEFINE(H5FD_core_region_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_add_dirty_region
+ *
+ * Purpose: Add a new dirty region to the list for later flushing
+ * to the backing store.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_add_dirty_region(H5FD_core_t *file, haddr_t start, haddr_t end)
+{
+ H5FD_core_region_t *b_item = NULL;
+ H5FD_core_region_t *a_item = NULL;
+ H5FD_core_region_t *item = NULL;
+ haddr_t b_addr = 0;
+ haddr_t a_addr = 0;
+ hbool_t create_new_node = TRUE;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file);
+ HDassert(file->dirty_list);
+ HDassert(start <= end);
+
+ /* Adjust the dirty region to the nearest block boundaries */
+ if(start % file->bstore_page_size != 0)
+ start = (start / file->bstore_page_size) * file->bstore_page_size;
+
+ if(end % file->bstore_page_size != (file->bstore_page_size - 1)) {
+ end = (((end / file->bstore_page_size) + 1) * file->bstore_page_size) - 1;
+ if(end > file->eof)
+ end = file->eof - 1;
+ } /* end if */
+
+ /* Get the regions before and after the intended insertion point */
+ b_addr = start +1;
+ a_addr = end + 2;
+ b_item = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &b_addr);
+ a_item = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &a_addr);
+
+ /* Check to see if we need to extend the upper end of the NEW region */
+ if(a_item)
+ if(start < a_item->start && end < a_item->end) {
+ /* Extend the end of the NEW region to match the existing AFTER region */
+ end = a_item->end;
+ } /* end if */
+ /* Attempt to extend the PREV region */
+ if(b_item)
+ if(start <= b_item->end + 1) {
+
+ /* Need to set this for the delete algorithm */
+ start = b_item->start;
+
+ /* We won't need to insert a new node since we can
+ * just update an existing one instead.
+ */
+ create_new_node = FALSE;
+ } /* end if */
+
+ /* Remove any old nodes that are no longer needed */
+ while(a_item && a_item->start > start) {
+
+ H5FD_core_region_t *less;
+ haddr_t key = a_item->start - 1;
+
+ /* Save the previous node before we trash this one */
+ less = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &key);
+
+ /* Delete this node */
+ a_item = (H5FD_core_region_t *)H5SL_remove(file->dirty_list, &a_item->start);
+ a_item = H5FL_FREE(H5FD_core_region_t, a_item);
+
+ /* Set up to check the next node */
+ if(less)
+ a_item = less;
+ } /* end while */
+
+ /* Insert the new node */
+ if(create_new_node) {
+ if(NULL == (item = (H5FD_core_region_t *)H5SL_search(file->dirty_list, &start))) {
+ /* Ok to insert. No pre-existing node with that key. */
+ item = (H5FD_core_region_t *)H5FL_CALLOC(H5FD_core_region_t);
+ item->start = start;
+ item->end = end;
+ if(H5SL_insert(file->dirty_list, item, &item->start) < 0)
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTINSERT, FAIL, "can't insert new dirty region: (%llu, %llu)\n", (unsigned long long)start, (unsigned long long)end)
+ } /* end if */
+ else {
+ /* Store the new item endpoint if it's bigger */
+ item->end = (item->end < end) ? end : item->end;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Update the size of the before region */
+ if(b_item->end < end)
+ b_item->end = end;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_add_dirty_region() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_destroy_dirty_list
+ *
+ * Purpose: Completely destroy the dirty list.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_destroy_dirty_list(H5FD_core_t *file)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file);
+
+ /* Destroy the list, including any remaining list elements */
+ if(file->dirty_list) {
+ H5FD_core_region_t *region = NULL;
+
+ while(NULL != (region = (H5FD_core_region_t *)H5SL_remove_first(file->dirty_list)))
+ region = H5FL_FREE(H5FD_core_region_t, region);
+
+ if(H5SL_close(file->dirty_list) < 0)
+ HGOTO_ERROR(H5E_SLIST, H5E_CLOSEERROR, FAIL, "can't close core vfd dirty list")
+ file->dirty_list = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_destroy_dirty_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_write_to_bstore
+ *
+ * Purpose: Write data to the backing store.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_write_to_bstore(H5FD_core_t *file, haddr_t addr, size_t size)
+{
+ unsigned char *ptr = file->mem + addr; /* mutable pointer into the
+ * buffer (can't change mem)
+ */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Write to backing store */
+ if((off_t)addr != HDlseek(file->fd, (off_t)addr, SEEK_SET))
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "error seeking in backing store")
+
+ while (size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to write */
+ h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
+
+ /* Trying to write more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_wrote = HDwrite(file->fd, ptr, bytes_in);
+ } while(-1 == bytes_wrote && EINTR == errno);
+
+ if(-1 == bytes_wrote) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write to backing store failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', ptr = %p, total write size = %llu, bytes this sub-write = %llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), ptr, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)myoffset);
+ } /* end if */
+
+ HDassert(bytes_wrote > 0);
+ HDassert((size_t)bytes_wrote <= size);
+
+ size -= (size_t)bytes_wrote;
+ ptr = (unsigned char *)ptr + bytes_wrote;
+
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_write_to_bstore() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initializes any interface-specific data or routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(H5FD_core_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize core VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_core_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the core driver.
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_core_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5I_VFL != H5I_get_type(H5FD_CORE_g))
+ H5FD_CORE_g = H5FD_register(&H5FD_core_g, sizeof(H5FD_class_t), FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_CORE_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_core_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD__core_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_term(void)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Reset VFL ID */
+ H5FD_CORE_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD__core_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_core
+ *
+ * Purpose: Modify the file access property list to use the H5FD_CORE
+ * driver defined in this source file. The INCREMENT specifies
+ * how much to grow the memory each time we need more.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_core(hid_t fapl_id, size_t increment, hbool_t backing_store)
+{
+ H5FD_core_fapl_t fa;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "izb", fapl_id, increment, backing_store);
+
+ /* Check argument */
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ fa.increment = increment;
+ fa.backing_store = backing_store;
+
+ ret_value = H5P_set_driver(plist, H5FD_CORE, &fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_core() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_core
+ *
+ * Purpose: Queries properties set by the H5Pset_fapl_core() function.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 10, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_core(hid_t fapl_id, size_t *increment /*out*/, hbool_t *backing_store /*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5FD_core_fapl_t *fa;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", fapl_id, increment, backing_store);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ if(H5FD_CORE != H5P_peek_driver(plist))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ if(NULL == (fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+
+ if(increment)
+ *increment = fa->increment;
+ if(backing_store)
+ *backing_store = fa->backing_store;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fapl_core() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_fapl_get
+ *
+ * Purpose: Returns a copy of the file access properties.
+ *
+ * Return: Success: Ptr to new file access properties.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD__core_fapl_get(H5FD_t *_file)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ H5FD_core_fapl_t *fa;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(NULL == (fa = (H5FD_core_fapl_t *)H5MM_calloc(sizeof(H5FD_core_fapl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ fa->increment = file->increment;
+ fa->backing_store = (hbool_t)(file->fd >= 0);
+
+ /* Set return value */
+ ret_value = fa;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD___core_open
+ *
+ * Purpose: Create memory as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ int o_flags;
+ H5FD_core_t *file = NULL;
+ H5FD_core_fapl_t *fa = NULL;
+ H5P_genplist_t *plist; /* Property list pointer */
+#ifdef H5_HAVE_WIN32_API
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#endif
+ h5_stat_t sb;
+ int fd = -1;
+ H5FD_file_image_info_t file_image_info;
+ H5FD_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+ if(ADDR_OVERFLOW(maxaddr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "maxaddr overflow")
+ HDassert(H5P_DEFAULT != fapl_id);
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ if(NULL == (fa = (H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
+
+ /* Build the open flags */
+ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
+ if(H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC;
+ if(H5F_ACC_CREAT & flags) o_flags |= O_CREAT;
+ if(H5F_ACC_EXCL & flags) o_flags |= O_EXCL;
+
+ /* Retrieve initial file image info */
+ if(H5P_peek(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial file image info")
+
+ /* If the file image exists and this is an open, make sure the file doesn't exist */
+ HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) ||
+ ((file_image_info.buffer == NULL) && (file_image_info.size == 0)));
+ HDmemset(&sb, 0, sizeof(sb));
+ if((file_image_info.buffer != NULL) && !(H5F_ACC_CREAT & flags)) {
+ if(HDopen(name, o_flags, 0666) >= 0)
+ HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file already exists")
+
+ /* If backing store is requested, create and stat the file
+ * Note: We are forcing the O_CREAT flag here, even though this is
+ * technically an open.
+ */
+ if(fa->backing_store) {
+ if((fd = HDopen(name, o_flags | O_CREAT, 0666)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create file")
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+ } /* end if */
+ } /* end if */
+ /* Open backing store, and get stat() from file. The only case that backing
+ * store is off is when the backing_store flag is off and H5F_ACC_CREAT is
+ * on. */
+ else if(fa->backing_store || !(H5F_ACC_CREAT & flags)) {
+ if((fd = HDopen(name, o_flags, 0666)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+ } /* end if */
+
+ /* Create the new file struct */
+ if(NULL == (file = (H5FD_core_t *)H5MM_calloc(sizeof(H5FD_core_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+ file->fd = fd;
+ if(name && *name)
+ file->name = H5MM_xstrdup(name);
+
+ /* The increment comes from either the file access property list or the
+ * default value. But if the file access property list was zero then use
+ * the default value instead.
+ */
+ file->increment = (fa->increment > 0) ? fa->increment : H5FD_CORE_INCREMENT;
+
+ /* If save data in backing store. */
+ file->backing_store = fa->backing_store;
+
+ /* Save file image callbacks */
+ file->fi_callbacks = file_image_info.callbacks;
+
+ if(fd >= 0) {
+ /* Retrieve information for determining uniqueness of file */
+#ifdef H5_HAVE_WIN32_API
+ file->hFile = (HANDLE)_get_osfhandle(fd);
+ if(INVALID_HANDLE_VALUE == file->hFile)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
+
+ if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
+
+ file->nFileIndexHigh = fileinfo.nFileIndexHigh;
+ file->nFileIndexLow = fileinfo.nFileIndexLow;
+ file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
+#else /* H5_HAVE_WIN32_API */
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /* H5_HAVE_WIN32_API */
+ } /* end if */
+
+ /* If an existing file is opened, load the whole file into memory. */
+ if(!(H5F_ACC_CREAT & flags)) {
+ size_t size;
+
+ /* Retrieve file size */
+ if(file_image_info.buffer && file_image_info.size > 0)
+ size = file_image_info.size;
+ else
+ size = (size_t)sb.st_size;
+
+ /* Check if we should allocate the memory buffer and read in existing data */
+ if(size) {
+ /* Allocate memory for the file's data, using the file image callback if available. */
+ if(file->fi_callbacks.image_malloc) {
+ if(NULL == (file->mem = (unsigned char*)file->fi_callbacks.image_malloc(size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "image malloc callback failed")
+ } /* end if */
+ else {
+ if(NULL == (file->mem = (unsigned char*)H5MM_malloc(size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "unable to allocate memory block")
+ } /* end else */
+
+ /* Set up data structures */
+ file->eof = size;
+
+ /* If there is an initial file image, copy it, using the callback if possible */
+ if(file_image_info.buffer && file_image_info.size > 0) {
+ if(file->fi_callbacks.image_memcpy) {
+ if(file->mem != file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, NULL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(file->mem, file_image_info.buffer, size);
+ } /* end if */
+ /* Read in existing data from the file if there is no image */
+ else {
+ /* Read in existing data, being careful of interrupted system calls,
+ * partial results, and the end of the file.
+ */
+
+ uint8_t *mem = file->mem; /* memory pointer for writes */
+
+ while(size > 0) {
+ h5_posix_io_t bytes_in = 0; /* # of bytes to read */
+ h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
+
+ /* Trying to read more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_read = HDread(file->fd, mem, bytes_in);
+ } while(-1 == bytes_read && EINTR == errno);
+
+ if(-1 == bytes_read) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', file->mem = %p, total read size = %llu, bytes this sub-read = %llu, bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), file->mem, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)myoffset);
+ } /* end if */
+
+ HDassert(bytes_read >= 0);
+ HDassert((size_t)bytes_read <= size);
+
+ mem += bytes_read;
+ size -= (size_t)bytes_read;
+ } /* end while */
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ /* Set up write tracking if the backing store is on */
+ file->dirty_list = NULL;
+ if(fa->backing_store) {
+ hbool_t write_tracking_flag = FALSE; /* what the user asked for */
+ hbool_t use_write_tracking = FALSE; /* what we're actually doing */
+
+ /* Get the write tracking flag */
+ if(H5P_get(plist, H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME, &write_tracking_flag) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get core VFD write tracking flag");
+
+ /* Get the page size */
+ if(H5P_get(plist, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME, &(file->bstore_page_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get core VFD write tracking page size");
+
+ /* default is to have write tracking OFF for create (hence the check to see
+ * if the user explicitly set a page size) and ON with the default page size
+ * on open (when not read-only).
+ */
+ /* Only use write tracking if the file is open for writing */
+ use_write_tracking =
+ TRUE == write_tracking_flag /* user asked for write tracking */
+ && !(o_flags & O_RDONLY) /* file is open for writing (i.e. not read-only) */
+ && file->bstore_page_size != 0; /* page size is not zero */
+
+ /* initialize the dirty list */
+ if(use_write_tracking) {
+ if(NULL == (file->dirty_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, NULL, "can't create core vfd dirty region list");
+ } /* end if */
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (H5FD_t *)file;
+
+done:
+ if(!ret_value && file) {
+ if(file->fd >= 0)
+ HDclose(file->fd);
+ H5MM_xfree(file->name);
+ H5MM_xfree(file->mem);
+ H5MM_xfree(file);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_close
+ *
+ * Purpose: Closes the file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_close(H5FD_t *_file)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Flush any changed buffers */
+ if(H5FD__core_flush(_file, (hid_t)-1, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush core vfd backing store")
+
+ /* Destroy the dirty region list */
+ if(file->dirty_list)
+ if(H5FD__core_destroy_dirty_list(file) != SUCCEED)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "unable to free core vfd dirty region list")
+
+ /* Release resources */
+ if(file->fd >= 0)
+ HDclose(file->fd);
+ if(file->name)
+ H5MM_xfree(file->name);
+ if(file->mem) {
+ /* Use image callback if available */
+ if(file->fi_callbacks.image_free) {
+ if(file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE, file->fi_callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(file->mem);
+ } /* end if */
+ HDmemset(file, 0, sizeof(H5FD_core_t));
+ H5MM_xfree(file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_cmp
+ *
+ * Purpose: Compares two files belonging to this driver by name. If one
+ * file doesn't have a name then it is less than the other file.
+ * If neither file has a name then the comparison is by file
+ * address.
+ *
+ * Return: Success: A value like strcmp()
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD__core_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_core_t *f1 = (const H5FD_core_t*)_f1;
+ const H5FD_core_t *f2 = (const H5FD_core_t*)_f2;
+ int ret_value = 0;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(f1->fd >= 0 && f2->fd >= 0) {
+ /* Compare low level file information for backing store */
+#ifdef H5_HAVE_WIN32_API
+ if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1)
+ if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1)
+
+ if(f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1)
+ if(f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1)
+
+ if(f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1)
+ if(f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1)
+
+#else
+#ifdef H5_DEV_T_IS_SCALAR
+ if (f1->device < f2->device) HGOTO_DONE(-1)
+ if (f1->device > f2->device) HGOTO_DONE(1)
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) HGOTO_DONE(-1)
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) HGOTO_DONE(1)
+#endif /* H5_DEV_T_IS_SCALAR */
+
+ if (f1->inode < f2->inode) HGOTO_DONE(-1)
+ if (f1->inode > f2->inode) HGOTO_DONE(1)
+
+#endif /*H5_HAVE_WIN32_API*/
+ } /* end if */
+ else {
+ if (NULL==f1->name && NULL==f2->name) {
+ if (f1<f2)
+ HGOTO_DONE(-1)
+ if (f1>f2)
+ HGOTO_DONE(1)
+ HGOTO_DONE(0)
+ } /* end if */
+
+ if (NULL==f1->name)
+ HGOTO_DONE(-1)
+ if (NULL==f2->name)
+ HGOTO_DONE(1)
+
+ ret_value = HDstrcmp(f1->name, f2->name);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_query(const H5FD_t * _file, unsigned long *flags /* out */)
+{
+ const H5FD_core_t *file = (const H5FD_core_t*)_file;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_ALLOW_FILE_IMAGE; /* OK to use file image feature with this VFD */
+ *flags |= H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS; /* OK to use file image callbacks with this VFD */
+
+ /* If the backing store is open, a POSIX file handle is available */
+ if(file && file->fd >= 0 && file->backing_store)
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD__core_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: The end-of-address marker. (Can't fail)
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD__core_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_core_t *file = (const H5FD_core_t*)_file;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+} /* end H5FD__core_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(ADDR_OVERFLOW(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "address overflow")
+
+ file->eoa = addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the size of the underlying memory or the HDF5
+ * end-of-address markers.
+ *
+ * Return: End of file address, the first address past
+ * the end of the "file", either the memory
+ * or the HDF5 file. (Can't fail)
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD__core_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_core_t *file = (const H5FD_core_t*)_file;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eof)
+} /* end H5FD__core_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_get_handle
+ *
+ * Purpose: Gets the file handle of CORE file driver.
+ *
+ * Returns: SUCCEED/FAIL
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle)
+{
+ H5FD_core_t *file = (H5FD_core_t *)_file; /* core VFD info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+
+ /* Check for non-default FAPL */
+ if(H5P_FILE_ACCESS_DEFAULT != fapl && H5P_DEFAULT != fapl) {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the FAPL */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* Check if private property for retrieving the backing store POSIX
+ * file descriptor is set. (This should not be set except within the
+ * library) QAK - 2009/12/04
+ */
+ if(H5P_exist_plist(plist, H5F_ACS_WANT_POSIX_FD_NAME) > 0) {
+ hbool_t want_posix_fd; /* Setting for retrieving file descriptor from core VFD */
+
+ /* Get property */
+ if(H5P_get(plist, H5F_ACS_WANT_POSIX_FD_NAME, &want_posix_fd) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get property of retrieving file descriptor")
+
+ /* If property is set, pass back the file descriptor instead of the memory address */
+ if(want_posix_fd)
+ *file_handle = &(file->fd);
+ else
+ *file_handle = &(file->mem);
+ } /* end if */
+ else
+ *file_handle = &(file->mem);
+ } /* end if */
+ else
+ *file_handle = &(file->mem);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_get_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: SUCCEED. Result is stored in caller-supplied
+ * buffer BUF.
+ * Failure: FAIL, Contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if (HADDR_UNDEF == addr)
+ HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed")
+ if (REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed")
+
+ /* Read the part which is before the EOF marker */
+ if (addr < file->eof) {
+ size_t nbytes;
+#ifndef NDEBUG
+ hsize_t temp_nbytes;
+
+ temp_nbytes = file->eof-addr;
+ H5_CHECK_OVERFLOW(temp_nbytes,hsize_t,size_t);
+ nbytes = MIN(size,(size_t)temp_nbytes);
+#else /* NDEBUG */
+ nbytes = MIN(size,(size_t)(file->eof-addr));
+#endif /* NDEBUG */
+
+ HDmemcpy(buf, file->mem + addr, nbytes);
+ size -= nbytes;
+ addr += nbytes;
+ buf = (char *)buf + nbytes;
+ }
+
+ /* Read zeros for the part which is after the EOF markers */
+ if (size > 0)
+ HDmemset(buf, 0, size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed")
+
+ /*
+ * Allocate more memory if necessary, careful of overflow. Also, if the
+ * allocation fails then the file should remain in a usable state. Be
+ * careful of non-Posix realloc() that doesn't understand what to do when
+ * the first argument is null.
+ */
+ if(addr + size > file->eof) {
+ unsigned char *x;
+ size_t new_eof;
+
+ /* Determine new size of memory buffer */
+ H5_CHECKED_ASSIGN(new_eof, size_t, file->increment * ((addr + size) / file->increment), hsize_t);
+ if((addr + size) % file->increment)
+ new_eof += file->increment;
+
+ /* (Re)allocate memory for the file buffer, using callbacks if available */
+ if(file->fi_callbacks.image_realloc) {
+ if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes with callback", (unsigned long long)new_eof)
+ } /* end if */
+ else {
+ if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof)
+ } /* end else */
+
+ HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
+ file->mem = x;
+
+ file->eof = new_eof;
+ } /* end if */
+
+ /* Add the buffer region to the dirty list if using that optimization */
+ if(file->dirty_list) {
+ haddr_t start = addr;
+ haddr_t end = addr + (haddr_t)size - 1;
+
+ if(H5FD__core_add_dirty_region(file, start, end) != SUCCEED)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINSERT, FAIL, "unable to add core VFD dirty region during write call - addresses: start=%llu end=%llu", (unsigned long long)start, (unsigned long long)end)
+ }
+
+ /* Write from BUF to memory */
+ HDmemcpy(file->mem + addr, buf, size);
+
+ /* Mark memory buffer as modified */
+ file->dirty = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_flush
+ *
+ * Purpose: Flushes the file to backing store if there is any and if the
+ * dirty flag is set.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 15, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Write to backing store */
+ if (file->dirty && file->fd >= 0 && file->backing_store) {
+
+ /* Use the dirty list, if available */
+ if(file->dirty_list) {
+ H5FD_core_region_t *item = NULL;
+ size_t size;
+
+ while(NULL != (item = (H5FD_core_region_t *)H5SL_remove_first(file->dirty_list))) {
+
+ /* The file may have been truncated, so check for that
+ * and skip or adjust as necessary.
+ */
+ if(item->start < file->eof) {
+ if(item->end >= file->eof)
+ item->end = file->eof - 1;
+
+ size = (size_t)((item->end - item->start) + 1);
+
+ if(H5FD__core_write_to_bstore(file, item->start, size) != SUCCEED)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to write to backing store")
+ } /* end if */
+
+ item = H5FL_FREE(H5FD_core_region_t, item);
+ } /* end while */
+
+ } /* end if */
+ /* Otherwise, write the entire file out at once */
+ else {
+ if(H5FD__core_write_to_bstore(file, (haddr_t)0, (size_t)file->eof) != SUCCEED)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to write to backing store")
+ } /* end else */
+
+ file->dirty = FALSE;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__core_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Addendum -- 12/2/11
+ * For file images opened with the core file driver, it is
+ * necessary that we avoid reallocating the core file driver's
+ * buffer uneccessarily.
+ *
+ * To this end, I have made the following functional changes
+ * to this function.
+ *
+ * If we are closing, and there is no backing store, this
+ * function becomes a no-op.
+ *
+ * If we are closing, and there is backing store, we set the
+ * eof to equal the eoa, and truncate the backing store to
+ * the new eof
+ *
+ * If we are not closing, we realloc the buffer to size equal
+ * to the smallest multiple of the allocation increment that
+ * equals or exceeds the eoa and set the eof accordingly.
+ * Note that we no longer truncate the backing store to the
+ * new eof if applicable.
+ * -- JRM
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__core_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t closing)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file;
+ size_t new_eof; /* New size of memory buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(file);
+
+ /* if we are closing and not using backing store, do nothing */
+ if(!closing || file->backing_store) {
+ if(closing) /* set eof to eoa */
+ new_eof = file->eoa;
+ else { /* set eof to smallest multiple of increment that exceeds eoa */
+ /* Determine new size of memory buffer */
+ H5_CHECKED_ASSIGN(new_eof, size_t, file->increment * (file->eoa / file->increment), hsize_t);
+ if(file->eoa % file->increment)
+ new_eof += file->increment;
+ } /* end else */
+
+ /* Extend the file to make sure it's large enough */
+ if(!H5F_addr_eq(file->eof, (haddr_t)new_eof)) {
+ unsigned char *x; /* Pointer to new buffer for file data */
+
+ /* (Re)allocate memory for the file buffer, using callback if available */
+ if(file->fi_callbacks.image_realloc) {
+ if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate memory block with callback")
+ } /* end if */
+ else {
+ if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate memory block")
+ } /* end else */
+
+ if(file->eof < new_eof)
+ HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
+ file->mem = x;
+
+ /* Update backing store, if using it and if closing */
+ if(closing && (file->fd >= 0) && file->backing_store) {
+#ifdef H5_HAVE_WIN32_API
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#else /* H5_HAVE_WIN32_API */
+ if(-1 == HDftruncate(file->fd, (HDoff_t)new_eof))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#endif /* H5_HAVE_WIN32_API */
+
+ } /* end if */
+
+ /* Update the eof value */
+ file->eof = new_eof;
+ } /* end if */
+ } /* end if(file->eof < file->eoa) */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__core_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_core_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_core_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file; /* VFD file struct */
+ int lock_flags; /* file locking flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Only set the lock if there is a file descriptor. If no file
+ * descriptor, this is a no-op.
+ */
+ if(file->fd >= 0) {
+
+ /* Set exclusive or shared lock based on rw status */
+ lock_flags = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place a non-blocking lock on the file */
+ if(HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
+ } /* end if */
+
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_core_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_core_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_core_unlock(H5FD_t *_file)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(file->fd >= 0) {
+
+ if(HDflock(file->fd, LOCK_UN) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file")
+ } /* end if */
+
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_core_unlock() */
+
diff --git a/src/H5FDcore.h b/src/H5FDcore.h
new file mode 100644
index 0000000..5fe2912
--- /dev/null
+++ b/src/H5FDcore.h
@@ -0,0 +1,38 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the core driver.
+ */
+#ifndef H5FDcore_H
+#define H5FDcore_H
+
+#define H5FD_CORE (H5FD_core_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+H5_DLL hid_t H5FD_core_init(void);
+H5_DLL herr_t H5Pset_fapl_core(hid_t fapl_id, size_t increment,
+ hbool_t backing_store);
+H5_DLL herr_t H5Pget_fapl_core(hid_t fapl_id, size_t *increment/*out*/,
+ hbool_t *backing_store/*out*/);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c
new file mode 100644
index 0000000..1487cda
--- /dev/null
+++ b/src/H5FDdirect.c
@@ -0,0 +1,1387 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <slu@hdfgroup.uiuc.edu>
+ * Wednesday, 20 September 2006
+ *
+ * Purpose: The Direct I/O file driver forces the data to be written to
+ * the file directly without being copied into system kernel
+ * buffer. The main system support this feature is Linux.
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDdirect.h" /* Direct file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+#ifdef H5_HAVE_DIRECT
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_DIRECT_g = 0;
+
+/* File operations */
+#define OP_UNKNOWN 0
+#define OP_READ 1
+#define OP_WRITE 2
+
+/* Driver-specific file access properties */
+typedef struct H5FD_direct_fapl_t {
+ size_t mboundary; /* Memory boundary for alignment */
+ size_t fbsize; /* File system block size */
+ size_t cbsize; /* Maximal buffer size for copying user data */
+ hbool_t must_align; /* Decides if data alignment is required */
+} H5FD_direct_fapl_t;
+
+/*
+ * The description of a file belonging to this driver. The `eoa' and `eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying Unix file). The `pos'
+ * value is used to eliminate file position updates when they would be a
+ * no-op. Unfortunately we've found systems that use separate file position
+ * indicators for reading and writing so the lseek can only be eliminated if
+ * the current operation is the same as the previous operation. When opening
+ * a file the `eof' will be set to the current file size, `eoa' will be set
+ * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error
+ * occurs), and `op' will be set to H5F_OP_UNKNOWN.
+ */
+typedef struct H5FD_direct_t {
+ H5FD_t pub; /*public stuff, must be first */
+ int fd; /*the unix file */
+ haddr_t eoa; /*end of allocated region */
+ haddr_t eof; /*end of file; current file size*/
+ haddr_t pos; /*current file I/O position */
+ int op; /*last operation */
+ H5FD_direct_fapl_t fa; /*file access properties */
+#ifndef H5_HAVE_WIN32_API
+ /*
+ * On most systems the combination of device and i-node number uniquely
+ * identify a file.
+ */
+ dev_t device; /*file device number */
+ ino_t inode; /*file i-node number */
+#else
+ /*
+ * On H5_HAVE_WIN32_API the low-order word of a unique identifier associated with the
+ * file and the volume serial number uniquely identify a file. This number
+ * (which, both? -rpm) may change when the system is restarted or when the
+ * file is opened. After a process opens a file, the identifier is
+ * constant until the file is closed. An application can use this
+ * identifier and the volume serial number to determine whether two
+ * handles refer to the same file.
+ */
+ DWORD fileindexlo;
+ DWORD fileindexhi;
+#endif
+
+} H5FD_direct_t;
+
+/*
+ * These macros check for overflow of various quantities. These macros
+ * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely by the second
+ * argument of the file seek function.
+ */
+#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || \
+ ((A) & ~(haddr_t)MAXADDR))
+#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || \
+ (HDoff_t)((A)+(Z))<(HDoff_t)(A))
+
+/* Prototypes */
+static herr_t H5FD_direct_term(void);
+static void *H5FD_direct_fapl_get(H5FD_t *file);
+static void *H5FD_direct_fapl_copy(const void *_old_fa);
+static H5FD_t *H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+static herr_t H5FD_direct_close(H5FD_t *_file);
+static int H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_direct_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_direct_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_direct_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_direct_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_direct_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_direct_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD_direct_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD_direct_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_direct_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_direct_unlock(H5FD_t *_file);
+
+
+static const H5FD_class_t H5FD_direct_g = {
+ "direct", /*name */
+ MAXADDR, /*maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_direct_term, /*terminate */
+ NULL, /*sb_size */
+ NULL, /*sb_encode */
+ NULL, /*sb_decode */
+ sizeof(H5FD_direct_fapl_t), /*fapl_size */
+ H5FD_direct_fapl_get, /*fapl_get */
+ H5FD_direct_fapl_copy, /*fapl_copy */
+ NULL, /*fapl_free */
+ 0, /*dxpl_size */
+ NULL, /*dxpl_copy */
+ NULL, /*dxpl_free */
+ H5FD_direct_open, /*open */
+ H5FD_direct_close, /*close */
+ H5FD_direct_cmp, /*cmp */
+ H5FD_direct_query, /*query */
+ NULL, /*get_type_map */
+ NULL, /*alloc */
+ NULL, /*free */
+ H5FD_direct_get_eoa, /*get_eoa */
+ H5FD_direct_set_eoa, /*set_eoa */
+ H5FD_direct_get_eof, /*get_eof */
+ H5FD_direct_get_handle, /*get_handle */
+ H5FD_direct_read, /*read */
+ H5FD_direct_write, /*write */
+ NULL, /*flush */
+ H5FD_direct_truncate, /*truncate */
+ H5FD_direct_lock, /*lock */
+ H5FD_direct_unlock, /*unlock */
+ H5FD_FLMAP_DICHOTOMY /*fl_map */
+};
+
+/* Declare a free list to manage the H5FD_direct_t struct */
+H5FL_DEFINE_STATIC(H5FD_direct_t);
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5FD__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5FD__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines. (Just calls
+ H5FD_direct_init currently).
+
+--------------------------------------------------------------------------*/
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_direct_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize direct VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the direct driver.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_direct_init(void)
+{
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if (H5I_VFL!=H5I_get_type(H5FD_DIRECT_g))
+ H5FD_DIRECT_g = H5FD_register(&H5FD_direct_g,sizeof(H5FD_class_t),FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_DIRECT_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_direct_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: Non-negative on success or negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_DIRECT_g=0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_direct_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_direct
+ *
+ * Purpose: Modify the file access property list to use the H5FD_DIRECT
+ * driver defined in this source file. There are no driver
+ * specific properties.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_direct(hid_t fapl_id, size_t boundary, size_t block_size, size_t cbuf_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5FD_direct_fapl_t fa;
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "izzz", fapl_id, boundary, block_size, cbuf_size);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ if(boundary != 0)
+ fa.mboundary = boundary;
+ else
+ fa.mboundary = MBOUNDARY_DEF;
+ if(block_size != 0)
+ fa.fbsize = block_size;
+ else
+ fa.fbsize = FBSIZE_DEF;
+ if(cbuf_size != 0)
+ fa.cbsize = cbuf_size;
+ else
+ fa.cbsize = CBSIZE_DEF;
+
+ /* Set the default to be true for data alignment */
+ fa.must_align = TRUE;
+
+ /* Copy buffer size must be a multiple of file block size */
+ if(fa.cbsize % fa.fbsize != 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "copy buffer size must be a multiple of block size")
+
+ ret_value = H5P_set_driver(plist, H5FD_DIRECT, &fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_direct
+ *
+ * Purpose: Returns information about the direct file access property
+ * list though the function arguments.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, October 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_direct(hid_t fapl_id, size_t *boundary/*out*/, size_t *block_size/*out*/,
+ size_t *cbuf_size/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5FD_direct_fapl_t *fa;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "ixxx", fapl_id, boundary, block_size, cbuf_size);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ if(H5FD_DIRECT != H5P_peek_driver(plist))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ if(NULL == (fa = H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+ if(boundary)
+ *boundary = fa->mboundary;
+ if(block_size)
+ *block_size = fa->fbsize;
+ if (cbuf_size)
+ *cbuf_size = fa->cbsize;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fapl_direct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_fapl_get
+ *
+ * Purpose: Returns a file access property list which indicates how the
+ * specified file is being accessed. The return list could be
+ * used to access another file the same way.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * members copied from the file struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 18 October 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_direct_fapl_get(H5FD_t *_file)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set return value */
+ ret_value= H5FD_direct_fapl_copy(&(file->fa));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_fapl_copy
+ *
+ * Purpose: Copies the direct-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 18 October 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_direct_fapl_copy(const void *_old_fa)
+{
+ const H5FD_direct_fapl_t *old_fa = (const H5FD_direct_fapl_t*)_old_fa;
+ H5FD_direct_fapl_t *new_fa = H5MM_malloc(sizeof(H5FD_direct_fapl_t));
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(new_fa);
+
+ /* Copy the general information */
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_direct_fapl_t));
+
+ FUNC_LEAVE_NOAPI(new_fa)
+} /* end H5FD_direct_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_open
+ *
+ * Purpose: Create and/or opens a Unix file for direct I/O as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ int o_flags;
+ int fd=(-1);
+ H5FD_direct_t *file=NULL;
+ H5FD_direct_fapl_t *fa;
+#ifdef H5_HAVE_WIN32_API
+ HFILE filehandle;
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#endif
+ h5_stat_t sb;
+ H5P_genplist_t *plist; /* Property list */
+ int *buf1, *buf2;
+ H5FD_t *ret_value;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check on file offsets */
+ HDassert(sizeof(HDoff_t)>=sizeof(size_t));
+
+ /* Check arguments */
+ if (!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if (0==maxaddr || HADDR_UNDEF==maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+ if (ADDR_OVERFLOW(maxaddr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
+
+ /* Build the open flags */
+ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
+ if (H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC;
+ if (H5F_ACC_CREAT & flags) o_flags |= O_CREAT;
+ if (H5F_ACC_EXCL & flags) o_flags |= O_EXCL;
+
+ /* Flag for Direct I/O */
+ o_flags |= O_DIRECT;
+
+ /* Open the file */
+ if ((fd=HDopen(name, o_flags, 0666))<0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
+
+ if (HDfstat(fd, &sb)<0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+
+ /* Create the new file struct */
+ if (NULL==(file=H5FL_CALLOC(H5FD_direct_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+
+ /* Get the driver specific information */
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ if(NULL == (fa = (H5FD_direct_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
+
+ file->fd = fd;
+ H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t);
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+#ifdef H5_HAVE_WIN32_API
+ filehandle = _get_osfhandle(fd);
+ (void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo);
+ file->fileindexhi = fileinfo.nFileIndexHigh;
+ file->fileindexlo = fileinfo.nFileIndexLow;
+#else
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /*H5_HAVE_WIN32_API*/
+ file->fa.mboundary = fa->mboundary;
+ file->fa.fbsize = fa->fbsize;
+ file->fa.cbsize = fa->cbsize;
+
+ /* Try to decide if data alignment is required. The reason to check it here
+ * is to handle correctly the case that the file is in a different file system
+ * than the one where the program is running.
+ */
+ /* NOTE: Use HDmalloc and HDfree here to ensure compatibility with
+ * HDposix_memalign.
+ */
+ buf1 = (int *)HDmalloc(sizeof(int));
+ if(HDposix_memalign(&buf2, file->fa.mboundary, file->fa.fbsize) != 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "HDposix_memalign failed")
+
+ if(o_flags & O_CREAT) {
+ if(HDwrite(file->fd, (void*)buf1, sizeof(int))<0) {
+ if(HDwrite(file->fd, (void*)buf2, file->fa.fbsize)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, NULL, "file system may not support Direct I/O")
+ else
+ file->fa.must_align = TRUE;
+ } else {
+ file->fa.must_align = FALSE;
+ HDftruncate(file->fd, (HDoff_t)0);
+ }
+ } else {
+ if(HDread(file->fd, (void*)buf1, sizeof(int))<0) {
+ if(HDread(file->fd, (void*)buf2, file->fa.fbsize)<0)
+ HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "file system may not support Direct I/O")
+ else
+ file->fa.must_align = TRUE;
+ } else {
+ if(o_flags & O_RDWR) {
+ if(HDlseek(file->fd, (HDoff_t)0, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, NULL, "unable to seek to proper position")
+ if(HDwrite(file->fd, (void *)buf1, sizeof(int))<0)
+ file->fa.must_align = TRUE;
+ else
+ file->fa.must_align = FALSE;
+ } else
+ file->fa.must_align = FALSE;
+ }
+ }
+
+ if(buf1)
+ HDfree(buf1);
+ if(buf2)
+ HDfree(buf2);
+
+ /* Set return value */
+ ret_value=(H5FD_t*)file;
+
+done:
+ if(ret_value==NULL) {
+ if(fd>=0)
+ HDclose(fd);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_close
+ *
+ * Purpose: Closes the file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1, file not closed.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_close(H5FD_t *_file)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if (HDclose(file->fd)<0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+ H5FL_FREE(H5FD_direct_t,file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_cmp
+ *
+ * Purpose: Compares two files belonging to this driver using an
+ * arbitrary (but consistent) ordering.
+ *
+ * Return: Success: A value like strcmp()
+ *
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Raymond Lu
+ * Thursday, 21 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_direct_t *f1 = (const H5FD_direct_t*)_f1;
+ const H5FD_direct_t *f2 = (const H5FD_direct_t*)_f2;
+ int ret_value=0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_WIN32_API
+ if (f1->fileindexhi < f2->fileindexhi) HGOTO_DONE(-1)
+ if (f1->fileindexhi > f2->fileindexhi) HGOTO_DONE(1)
+
+ if (f1->fileindexlo < f2->fileindexlo) HGOTO_DONE(-1)
+ if (f1->fileindexlo > f2->fileindexlo) HGOTO_DONE(1)
+
+#else
+#ifdef H5_DEV_T_IS_SCALAR
+ if (f1->device < f2->device) HGOTO_DONE(-1)
+ if (f1->device > f2->device) HGOTO_DONE(1)
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) HGOTO_DONE(-1)
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) HGOTO_DONE(1)
+#endif /* H5_DEV_T_IS_SCALAR */
+
+ if (f1->inode < f2->inode) HGOTO_DONE(-1)
+ if (f1->inode > f2->inode) HGOTO_DONE(1)
+
+#endif
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * Thursday, 21 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_query(const H5FD_t H5_ATTR_UNUSED * _f, unsigned long *flags /* out */)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: Success: The end-of-address marker.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_direct_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_direct_t *file = (const H5FD_direct_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ file->eoa = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the Unix end-of-file or the HDF5 end-of-address
+ * markers.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the "file", either the Unix file
+ * or the HDF5 file.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, 20 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_direct_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_direct_t *file = (const H5FD_direct_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ FUNC_LEAVE_NOAPI(file->eof)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_diect_get_handle
+ *
+ * Purpose: Returns the file handle of direct file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * 21 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void** file_handle)
+{
+ H5FD_direct_t *file = (H5FD_direct_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+ *file_handle = &(file->fd);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero. Result is stored in caller-supplied
+ * buffer BUF.
+ *
+ * Failure: -1, Contents of buffer BUF are undefined.
+ *
+ * Programmer: Raymond Lu
+ * Thursday, 21 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+ ssize_t nbytes;
+ hbool_t _must_align = TRUE;
+ herr_t ret_value=SUCCEED; /* Return value */
+ size_t alloc_size;
+ void *copy_buf = NULL, *p2;
+ size_t _boundary;
+ size_t _fbsize;
+ size_t _cbsize;
+ haddr_t read_size; /* Size to read into copy buffer */
+ size_t copy_size = size; /* Size remaining to read when using copy buffer */
+ size_t copy_offset; /* Offset into copy buffer of the requested data */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if (HADDR_UNDEF==addr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined")
+ if (REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
+
+ /* If the system doesn't require data to be aligned, read the data in
+ * the same way as sec2 driver.
+ */
+ _must_align = file->fa.must_align;
+
+ /* Get the memory boundary for alignment, file system block size, and maximal
+ * copy buffer size.
+ */
+ _boundary = file->fa.mboundary;
+ _fbsize = file->fa.fbsize;
+ _cbsize = file->fa.cbsize;
+
+ /* if the data is aligned or the system doesn't require data to be aligned,
+ * read it directly from the file. If not, read a bigger
+ * and aligned data first, then copy the data into memory buffer.
+ */
+ if(!_must_align || ((addr%_fbsize==0) && (size%_fbsize==0) && ((size_t)buf%_boundary==0))) {
+ /* Seek to the correct location */
+ if ((addr!=file->pos || OP_READ!=file->op) &&
+ HDlseek(file->fd, (HDoff_t)addr, SEEK_SET)<0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ /* Read the aligned data in file first, being careful of interrupted
+ * system calls and partial results. */
+ while (size>0) {
+ do {
+ nbytes = HDread(file->fd, buf, size);
+ } while (-1==nbytes && EINTR==errno);
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+ if (0==nbytes) {
+ /* end of file but not end of format address space */
+ HDmemset(buf, 0, size);
+ break;
+ }
+ HDassert(nbytes>=0);
+ HDassert((size_t)nbytes<=size);
+ H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t);
+ size -= (size_t)nbytes;
+ H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t);
+ addr += (haddr_t)nbytes;
+ buf = (char*)buf + nbytes;
+ }
+ } else {
+ /* Calculate where we will begin copying from the copy buffer */
+ copy_offset = (size_t)(addr % _fbsize);
+
+ /* allocate memory needed for the Direct IO option up to the maximal
+ * copy buffer size. Make a bigger buffer for aligned I/O if size is
+ * smaller than maximal copy buffer. */
+ alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
+ if(alloc_size > _cbsize)
+ alloc_size = _cbsize;
+ HDassert(!(alloc_size % _fbsize));
+ if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
+
+ /* look for the aligned position for reading the data */
+ HDassert(!(((addr / _fbsize) * _fbsize) % _fbsize));
+ if(HDlseek(file->fd, (HDoff_t)((addr / _fbsize) * _fbsize),
+ SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+
+ /*
+ * Read the aligned data in file into aligned buffer first, then copy the data
+ * into the final buffer. If the data size is bigger than maximal copy buffer
+ * size, do the reading by segment (the outer while loop). If not, do one step
+ * reading.
+ */
+ do {
+ /* Read the aligned data in file first. Not able to handle interrupted
+ * system calls and partial results like sec2 driver does because the
+ * data may no longer be aligned. It's expecially true when the data in
+ * file is smaller than ALLOC_SIZE. */
+ HDmemset(copy_buf, 0, alloc_size);
+
+ /* Calculate how much data we have to read in this iteration
+ * (including unused parts of blocks) */
+ if((copy_size + copy_offset) < alloc_size)
+ read_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
+ * _fbsize;
+ else
+ read_size = alloc_size;
+
+ HDassert(!(read_size % _fbsize));
+ do {
+ nbytes = HDread(file->fd, copy_buf, read_size);
+ } while(-1==nbytes && EINTR==errno);
+
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+
+ /* Copy the needed data from the copy buffer to the output
+ * buffer, and update copy_size. If the copy buffer does not
+ * contain the rest of the data, just copy what's in the copy
+ * buffer and also update read_addr and copy_offset to read the
+ * next section of data. */
+ p2 = (unsigned char*)copy_buf + copy_offset;
+ if((copy_size + copy_offset) <= alloc_size) {
+ HDmemcpy(buf, p2, copy_size);
+ buf = (unsigned char *)buf + copy_size;
+ copy_size = 0;
+ } /* end if */
+ else {
+ HDmemcpy(buf, p2, alloc_size - copy_offset);
+ buf = (unsigned char*)buf + alloc_size - copy_offset;
+ copy_size -= alloc_size - copy_offset;
+ copy_offset = 0;
+ } /* end else */
+ } while (copy_size > 0);
+
+ /*Final step: update address*/
+ addr = (haddr_t)(((addr + size - 1) / _fbsize + 1) * _fbsize);
+
+ if(copy_buf) {
+ /* Free with HDfree since it came from posix_memalign */
+ HDfree(copy_buf);
+ copy_buf = NULL;
+ } /* end if */
+ }
+
+ /* Update current position */
+ file->pos = addr;
+ file->op = OP_READ;
+
+done:
+ if(ret_value<0) {
+ /* Free with HDfree since it came from posix_memalign */
+ if(copy_buf)
+ HDfree(copy_buf);
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Thursday, 21 September 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+ ssize_t nbytes;
+ hbool_t _must_align = TRUE;
+ herr_t ret_value=SUCCEED; /* Return value */
+ size_t alloc_size;
+ void *copy_buf = NULL, *p1;
+ const void *p3;
+ size_t _boundary;
+ size_t _fbsize;
+ size_t _cbsize;
+ haddr_t write_addr; /* Address to write copy buffer */
+ haddr_t write_size; /* Size to write from copy buffer */
+ haddr_t read_size; /* Size to read into copy buffer */
+ size_t copy_size = size; /* Size remaining to write when using copy buffer */
+ size_t copy_offset; /* Offset into copy buffer of the data to write */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if (HADDR_UNDEF==addr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined")
+ if (REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
+
+ /* If the system doesn't require data to be aligned, read the data in
+ * the same way as sec2 driver.
+ */
+ _must_align = file->fa.must_align;
+
+ /* Get the memory boundary for alignment, file system block size, and maximal
+ * copy buffer size.
+ */
+ _boundary = file->fa.mboundary;
+ _fbsize = file->fa.fbsize;
+ _cbsize = file->fa.cbsize;
+
+ /* if the data is aligned or the system doesn't require data to be aligned,
+ * write it directly to the file. If not, read a bigger and aligned data
+ * first, update buffer with user data, then write the data out.
+ */
+ if(!_must_align || ((addr%_fbsize==0) && (size%_fbsize==0) && ((size_t)buf%_boundary==0))) {
+ /* Seek to the correct location */
+ if ((addr!=file->pos || OP_WRITE!=file->op) &&
+ HDlseek(file->fd, (HDoff_t)addr, SEEK_SET)<0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+
+ while (size>0) {
+ do {
+ nbytes = HDwrite(file->fd, buf, size);
+ } while (-1==nbytes && EINTR==errno);
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+ HDassert(nbytes>0);
+ HDassert((size_t)nbytes<=size);
+ H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t);
+ size -= (size_t)nbytes;
+ H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t);
+ addr += (haddr_t)nbytes;
+ buf = (const char*)buf + nbytes;
+ }
+ } else {
+ /* Calculate where we will begin reading from (on disk) and where we
+ * will begin copying from the copy buffer */
+ write_addr = (addr / _fbsize) * _fbsize;
+ copy_offset = (size_t)(addr % _fbsize);
+
+ /* allocate memory needed for the Direct IO option up to the maximal
+ * copy buffer size. Make a bigger buffer for aligned I/O if size is
+ * smaller than maximal copy buffer.
+ */
+ alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
+ if(alloc_size > _cbsize)
+ alloc_size = _cbsize;
+ HDassert(!(alloc_size % _fbsize));
+
+ if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
+
+ /* look for the right position for reading or writing the data */
+ if(HDlseek(file->fd, (HDoff_t)write_addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+
+ p3 = buf;
+ do {
+ /* Calculate how much data we have to write in this iteration
+ * (including unused parts of blocks) */
+ if((copy_size + copy_offset) < alloc_size)
+ write_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
+ * _fbsize;
+ else
+ write_size = alloc_size;
+
+ /*
+ * Read the aligned data first if the aligned region doesn't fall
+ * entirely in the range to be writen. Not able to handle interrupted
+ * system calls and partial results like sec2 driver does because the
+ * data may no longer be aligned. It's expecially true when the data in
+ * file is smaller than ALLOC_SIZE. Only read the entire section if
+ * both ends are misaligned, otherwise only read the block on the
+ * misaligned end.
+ */
+ HDmemset(copy_buf, 0, _fbsize);
+
+ if(copy_offset > 0) {
+ if((write_addr + write_size) > (addr + size)) {
+ HDassert((write_addr + write_size) - (addr + size) < _fbsize);
+ read_size = write_size;
+ p1 = copy_buf;
+ } /* end if */
+ else {
+ read_size = _fbsize;
+ p1 = copy_buf;
+ } /* end else */
+ } /* end if */
+ else if((write_addr + write_size) > (addr + size)) {
+ HDassert((write_addr + write_size) - (addr + size) < _fbsize);
+ read_size = _fbsize;
+ p1 = (unsigned char *)copy_buf + write_size - _fbsize;
+
+ /* Seek to the last block, for reading */
+ HDassert(!((write_addr + write_size - _fbsize) % _fbsize));
+ if(HDlseek(file->fd,
+ (HDoff_t)(write_addr + write_size - _fbsize),
+ SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ } /* end if */
+ else
+ p1 = NULL;
+
+ if(p1) {
+ HDassert(!(read_size % _fbsize));
+ do {
+ nbytes = HDread(file->fd, p1, read_size);
+ } while (-1==nbytes && EINTR==errno);
+
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+ } /* end if */
+
+ /* look for the right position and append or copy the data to be written to
+ * the aligned buffer.
+ * Consider all possible situations here: file address is not aligned on
+ * file block size; the end of data address is not aligned; the end of data
+ * address is aligned; data size is smaller or bigger than maximal copy size.
+ */
+ p1 = (unsigned char *)copy_buf + copy_offset;
+ if((copy_size + copy_offset) <= alloc_size) {
+ HDmemcpy(p1, p3, copy_size);
+ copy_size = 0;
+ } /* end if */
+ else {
+ HDmemcpy(p1, p3, alloc_size - copy_offset);
+ p3 = (const unsigned char *)p3 + (alloc_size - copy_offset);
+ copy_size -= alloc_size - copy_offset;
+ copy_offset = 0;
+ } /* end else */
+
+ /*look for the aligned position for writing the data*/
+ HDassert(!(write_addr % _fbsize));
+ if(HDlseek(file->fd, (HDoff_t)write_addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+
+ /*
+ * Write the data. It doesn't truncate the extra data introduced by
+ * alignment because that step is done in H5FD_direct_flush.
+ */
+ HDassert(!(write_size % _fbsize));
+ do {
+ nbytes = HDwrite(file->fd, copy_buf, write_size);
+ } while (-1==nbytes && EINTR==errno);
+
+ if (-1==nbytes) /* error */
+ HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* update the write address */
+ write_addr += write_size;
+ } while (copy_size > 0);
+
+ /*Update the address and size*/
+ addr = write_addr;
+ buf = (const char*)buf + size;
+
+ if(copy_buf) {
+ /* Free with HDfree since it came from posix_memalign */
+ HDfree(copy_buf);
+ copy_buf = NULL;
+ } /* end if */
+ }
+
+ /* Update current position and eof */
+ file->pos = addr;
+ file->op = OP_WRITE;
+ if (file->pos>file->eof)
+ file->eof = file->pos;
+
+done:
+ if(ret_value<0) {
+ /* Free with HDfree since it came from posix_memalign */
+ if(copy_buf)
+ HDfree(copy_buf);
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Thursday, 21 September 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Extend the file to make sure it's large enough */
+ if (file->eoa!=file->eof) {
+#ifdef H5_HAVE_WIN32_API
+ HFILE filehandle; /* Windows file handle */
+ LARGE_INTEGER li; /* 64-bit integer for SetFilePointer() call */
+
+ /* Map the posix file handle to a Windows file handle */
+ filehandle = _get_osfhandle(file->fd);
+
+ /* Translate 64-bit integers into form Windows wants */
+ /* [This algorithm is from the Windows documentation for SetFilePointer()] */
+ li.QuadPart = (LONGLONG)file->eoa;
+ (void)SetFilePointer((HANDLE)filehandle,li.LowPart,&li.HighPart,FILE_BEGIN);
+ if(SetEndOfFile((HANDLE)filehandle)==0)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#else /* H5_HAVE_WIN32_API */
+ if (-1==HDftruncate(file->fd, (HDoff_t)file->eoa))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Update the eof value */
+ file->eof = file->eoa;
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ }
+ else if (file->fa.must_align){
+ /*Even though eof is equal to eoa, file is still truncated because Direct I/O
+ *write introduces some extra data for alignment.
+ */
+ if (-1==HDftruncate(file->fd, (HDoff_t)file->eof))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file; /* VFD file struct */
+ int lock; /* The type of lock */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Determine the type of lock */
+ int lock = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place the lock with non-blocking */
+ if(HDflock(file->fd, lock | LOCK_NB) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_unlock(H5FD_t *_file)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock (unlock) file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_unlock() */
+
+#endif /* H5_HAVE_DIRECT */
+
diff --git a/src/H5FDdirect.h b/src/H5FDdirect.h
new file mode 100644
index 0000000..805f3be
--- /dev/null
+++ b/src/H5FDdirect.h
@@ -0,0 +1,53 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <slu@hdfgroup.uiuc.edu>
+ * Wednesday, 20 September 2006
+ *
+ * Purpose: The public header file for the direct driver.
+ */
+#ifndef H5FDdirect_H
+#define H5FDdirect_H
+
+#ifdef H5_HAVE_DIRECT
+# define H5FD_DIRECT (H5FD_direct_init())
+#else
+# define H5FD_DIRECT (-1)
+#endif /* H5_HAVE_DIRECT */
+
+#ifdef H5_HAVE_DIRECT
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Default values for memory boundary, file block size, and maximal copy buffer size.
+ * Application can set these values through the function H5Pset_fapl_direct. */
+#define MBOUNDARY_DEF 4096
+#define FBSIZE_DEF 4096
+#define CBSIZE_DEF 16*1024*1024
+
+H5_DLL hid_t H5FD_direct_init(void);
+H5_DLL herr_t H5Pset_fapl_direct(hid_t fapl_id, size_t alignment, size_t block_size,
+ size_t cbuf_size);
+H5_DLL herr_t H5Pget_fapl_direct(hid_t fapl_id, size_t *boundary/*out*/,
+ size_t *block_size/*out*/, size_t *cbuf_size/*out*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H5_HAVE_DIRECT */
+
+#endif
+
diff --git a/src/H5FDdrvr_module.h b/src/H5FDdrvr_module.h
new file mode 100644
index 0000000..59a419e
--- /dev/null
+++ b/src/H5FDdrvr_module.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5FD driver package. Including this header means that the source file
+ * is part of the H5FD driver package.
+ */
+#ifndef _H5FDdrvr_module_H
+#define _H5FDdrvr_module_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5_MY_PKG H5FD
+#define H5_MY_PKG_ERR H5E_FILE
+#define H5_MY_PKG_INIT YES
+#define H5_PKG_SINGLE_SOURCE
+
+#endif /* _H5FDdrvr_module_H */
+
diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c
new file mode 100644
index 0000000..98ece84
--- /dev/null
+++ b/src/H5FDfamily.c
@@ -0,0 +1,1400 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, November 10, 1997
+ *
+ * Purpose: Implements a family of files that acts as a single hdf5
+ * file. The purpose is to be able to split a huge file on a
+ * 64-bit platform, transfer all the <2GB members to a 32-bit
+ * platform, and then access the entire huge file on the 32-bit
+ * platform.
+ *
+ * All family members are logically the same size although their
+ * physical sizes may vary. The logical member size is
+ * determined by looking at the physical size of the first member
+ * when the file is opened. When creating a file family, the
+ * first member is created with a predefined physical size
+ * (actually, this happens when the file family is flushed, and
+ * can be quite time consuming on file systems that don't
+ * implement holes, like nfs).
+ *
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDfamily.h" /* Family file driver */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/* The size of the member name buffers */
+#define H5FD_FAM_MEMB_NAME_BUF_SIZE 4096
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_FAMILY_g = 0;
+
+/* The description of a file belonging to this driver. */
+typedef struct H5FD_family_t {
+ H5FD_t pub; /*public stuff, must be first */
+ hid_t memb_fapl_id; /*file access property list for members */
+ hsize_t memb_size; /*actual size of each member file */
+ hsize_t pmem_size; /*member size passed in from property */
+ unsigned nmembs; /*number of family members */
+ unsigned amembs; /*number of member slots allocated */
+ H5FD_t **memb; /*dynamic array of member pointers */
+ haddr_t eoa; /*end of allocated addresses */
+ char *name; /*name generator printf format */
+ unsigned flags; /*flags for opening additional members */
+
+ /* Information from properties set by 'h5repart' tool */
+ hsize_t mem_newsize; /*new member size passed in as private
+ * property. It's used only by h5repart */
+ hbool_t repart_members; /* Whether to mark the superblock dirty
+ * when it is loaded, so that the family
+ * member sizes can be re-encoded */
+} H5FD_family_t;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_family_fapl_t {
+ hsize_t memb_size; /*size of each member */
+ hid_t memb_fapl_id; /*file access property list of each memb*/
+} H5FD_family_fapl_t;
+
+/* Callback prototypes */
+static herr_t H5FD_family_term(void);
+static void *H5FD_family_fapl_get(H5FD_t *_file);
+static void *H5FD_family_fapl_copy(const void *_old_fa);
+static herr_t H5FD_family_fapl_free(void *_fa);
+static hsize_t H5FD_family_sb_size(H5FD_t *_file);
+static herr_t H5FD_family_sb_encode(H5FD_t *_file, char *name/*out*/,
+ unsigned char *buf/*out*/);
+static herr_t H5FD_family_sb_decode(H5FD_t *_file, const char *name,
+ const unsigned char *buf);
+static H5FD_t *H5FD_family_open(const char *name, unsigned flags,
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_family_close(H5FD_t *_file);
+static int H5FD_family_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_family_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_family_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa);
+static haddr_t H5FD_family_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_family_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_family_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, void *_buf/*out*/);
+static herr_t H5FD_family_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, const void *_buf);
+static herr_t H5FD_family_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_family_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_family_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_family_unlock(H5FD_t *_file);
+
+/* The class struct */
+static const H5FD_class_t H5FD_family_g = {
+ "family", /*name */
+ HADDR_MAX, /*maxaddr */
+ H5F_CLOSE_WEAK, /*fc_degree */
+ H5FD_family_term, /*terminate */
+ H5FD_family_sb_size, /*sb_size */
+ H5FD_family_sb_encode, /*sb_encode */
+ H5FD_family_sb_decode, /*sb_decode */
+ sizeof(H5FD_family_fapl_t), /*fapl_size */
+ H5FD_family_fapl_get, /*fapl_get */
+ H5FD_family_fapl_copy, /*fapl_copy */
+ H5FD_family_fapl_free, /*fapl_free */
+ 0, /*dxpl_size */
+ NULL, /*dxpl_copy */
+ NULL, /*dxpl_free */
+ H5FD_family_open, /*open */
+ H5FD_family_close, /*close */
+ H5FD_family_cmp, /*cmp */
+ H5FD_family_query, /*query */
+ NULL, /*get_type_map */
+ NULL, /*alloc */
+ NULL, /*free */
+ H5FD_family_get_eoa, /*get_eoa */
+ H5FD_family_set_eoa, /*set_eoa */
+ H5FD_family_get_eof, /*get_eof */
+ H5FD_family_get_handle, /*get_handle */
+ H5FD_family_read, /*read */
+ H5FD_family_write, /*write */
+ H5FD_family_flush, /*flush */
+ H5FD_family_truncate, /*truncate */
+ H5FD_family_lock, /*lock */
+ H5FD_family_unlock, /*unlock */
+ H5FD_FLMAP_DICHOTOMY /*fl_map */
+};
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5FD__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5FD__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines. (Just calls
+ H5FD_family_init currently).
+
+--------------------------------------------------------------------------*/
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_family_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize family VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the family driver.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_family_init(void)
+{
+ hid_t ret_value = H5FD_FAMILY_g; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5I_VFL != H5I_get_type(H5FD_FAMILY_g))
+ H5FD_FAMILY_g = H5FD_register(&H5FD_family_g, sizeof(H5FD_class_t), FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_FAMILY_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD_family_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_family_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: Non-negative on success or negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_FAMILY_g=0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_family_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_family
+ *
+ * Purpose: Sets the file access property list FAPL_ID to use the family
+ * driver. The MEMB_SIZE is the size in bytes of each file
+ * member (used only when creating a new file) and the
+ * MEMB_FAPL_ID is a file access property list to be used for
+ * each family member.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_family(hid_t fapl_id, hsize_t msize, hid_t memb_fapl_id)
+{
+ herr_t ret_value;
+ H5FD_family_fapl_t fa={0, -1};
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ihi", fapl_id, msize, memb_fapl_id);
+
+ /* Check arguments */
+ if(TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ if(H5P_DEFAULT == memb_fapl_id)
+ memb_fapl_id = H5P_FILE_ACCESS_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(memb_fapl_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+
+ /* Initialize driver specific information. */
+ fa.memb_size = msize;
+ fa.memb_fapl_id = memb_fapl_id;
+
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ ret_value = H5P_set_driver(plist, H5FD_FAMILY, &fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_family
+ *
+ * Purpose: Returns information about the family file access property
+ * list though the function arguments.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_family(hid_t fapl_id, hsize_t *msize/*out*/, hid_t *memb_fapl_id/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5FD_family_fapl_t *fa;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", fapl_id, msize, memb_fapl_id);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ if(H5FD_FAMILY != H5P_peek_driver(plist))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ if(NULL == (fa = (const H5FD_family_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+ if(msize)
+ *msize = fa->memb_size;
+ if(memb_fapl_id) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fa->memb_fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ *memb_fapl_id = H5P_copy_plist(plist, TRUE);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_fapl_get
+ *
+ * Purpose: Gets a file access property list which could be used to
+ * create an identical file.
+ *
+ * Return: Success: Ptr to new file access property list.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_family_fapl_get(H5FD_t *_file)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ H5FD_family_fapl_t *fa = NULL;
+ H5P_genplist_t *plist; /* Property list pointer */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(NULL == (fa = (H5FD_family_fapl_t *)H5MM_calloc(sizeof(H5FD_family_fapl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ fa->memb_size = file->memb_size;
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(file->memb_fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ fa->memb_fapl_id = H5P_copy_plist(plist, FALSE);
+
+ /* Set return value */
+ ret_value=fa;
+
+done:
+ if(ret_value==NULL) {
+ if(fa!=NULL)
+ H5MM_xfree(fa);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_fapl_copy
+ *
+ * Purpose: Copies the family-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_family_fapl_copy(const void *_old_fa)
+{
+ const H5FD_family_fapl_t *old_fa = (const H5FD_family_fapl_t*)_old_fa;
+ H5FD_family_fapl_t *new_fa = NULL;
+ H5P_genplist_t *plist; /* Property list pointer */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(NULL == (new_fa = (H5FD_family_fapl_t *)H5MM_malloc(sizeof(H5FD_family_fapl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the fields of the structure */
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_family_fapl_t));
+
+ /* Deep copy the property list objects in the structure */
+ if(old_fa->memb_fapl_id==H5P_FILE_ACCESS_DEFAULT) {
+ if(H5I_inc_ref(new_fa->memb_fapl_id, FALSE)<0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver")
+ } /* end if */
+ else {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(old_fa->memb_fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ new_fa->memb_fapl_id = H5P_copy_plist(plist, FALSE);
+ } /* end else */
+
+ /* Set return value */
+ ret_value=new_fa;
+
+done:
+ if(ret_value==NULL) {
+ if(new_fa!=NULL)
+ H5MM_xfree(new_fa);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_fapl_free
+ *
+ * Purpose: Frees the family-specific file access properties.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_fapl_free(void *_fa)
+{
+ H5FD_family_fapl_t *fa = (H5FD_family_fapl_t*)_fa;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(H5I_dec_ref(fa->memb_fapl_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID")
+ H5MM_xfree(fa);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_sb_size
+ *
+ * Purpose: Returns the size of the private information to be stored in
+ * the superblock.
+ *
+ * Return: Success: The super block driver data size.
+ *
+ * Failure: never fails
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, May 10, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5FD_family_sb_size(H5FD_t H5_ATTR_UNUSED *_file)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* 8 bytes field for the size of member file size field should be
+ * enough for now. */
+ FUNC_LEAVE_NOAPI(8)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_sb_encode
+ *
+ * Purpose: Encode driver information for the superblock. The NAME
+ * argument is a nine-byte buffer which will be initialized with
+ * an eight-character name/version number and null termination.
+ *
+ * The encoding is the member file size and name template.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, May 10, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_sb_encode(H5FD_t *_file, char *name/*out*/, unsigned char *buf/*out*/)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Name and version number */
+ HDstrncpy(name, "NCSAfami", (size_t)9);
+ name[8] = '\0';
+
+ /* Store member file size. Use the member file size from the property here.
+ * This is to guarantee backward compatibility. If a file is created with
+ * v1.6 library and the driver info isn't saved in the superblock. We open
+ * it with v1.8, the FILE->MEMB_SIZE will be the actual size of the first
+ * member file (see H5FD_family_open). So it isn't safe to use FILE->MEMB_SIZE.
+ * If the file is created with v1.8, the correctness of FILE->PMEM_SIZE is
+ * checked in H5FD_family_sb_decode. SLU - 2009/3/21
+ */
+ UINT64ENCODE(buf, (uint64_t)file->pmem_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_family_sb_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_sb_decode
+ *
+ * Purpose: This function has 2 seperate purpose. One is to decodes the
+ * superblock information for this driver. The NAME argument is
+ * the eight-character (plus null termination) name stored in i
+ * the file. The FILE argument is updated according to the
+ * information in the superblock.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, May 10, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_sb_decode(H5FD_t *_file, const char H5_ATTR_UNUSED *name, const unsigned char *buf)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ uint64_t msize;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Read member file size. Skip name template for now although it's saved. */
+ UINT64DECODE(buf, msize);
+
+ /* For h5repart only. Private property of new member size is used to signal
+ * h5repart is being used to change member file size. h5repart will open
+ * files for read and write. When the files are closed, metadata will be
+ * flushed to the files and updated to this new size */
+ if(file->mem_newsize)
+ file->memb_size = file->pmem_size = file->mem_newsize;
+ else {
+ /* Default - use the saved member size */
+ if(file->pmem_size == H5F_FAMILY_DEFAULT)
+ file->pmem_size = msize;
+
+ /* Check if member size from file access property is correct */
+ if(msize != file->pmem_size)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "Family member size should be %lu. But the size from file access property is %lu", (unsigned long)msize, (unsigned long)file->pmem_size)
+
+ /* Update member file size to the size saved in the superblock.
+ * That's the size intended to be. */
+ file->memb_size = msize;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_sb_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_open
+ *
+ * Purpose: Creates and/or opens a family of files as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file dat structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_family_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr)
+{
+ H5FD_family_t *file = NULL;
+ char *memb_name = NULL, *temp = NULL;
+ hsize_t eof = HADDR_UNDEF;
+ unsigned t_flags = flags & ~H5F_ACC_CREAT;
+ H5FD_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+
+ /* Initialize file from file access properties */
+ if(NULL == (file = (H5FD_family_t *)H5MM_calloc(sizeof(H5FD_family_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+ if(H5P_FILE_ACCESS_DEFAULT == fapl_id) {
+ file->memb_fapl_id = H5P_FILE_ACCESS_DEFAULT;
+ if(H5I_inc_ref(file->memb_fapl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver")
+ file->memb_size = 1024 * 1024 * 1024; /*1GB. Actual member size to be updated later */
+ file->pmem_size = 1024 * 1024 * 1024; /*1GB. Member size passed in through property */
+ file->mem_newsize = 0; /*New member size used by h5repart only */
+ } /* end if */
+ else {
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5FD_family_fapl_t *fa;
+
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ if(NULL == (fa = (const H5FD_family_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
+
+ /* Check for new family file size. It's used by h5repart only. */
+ if(H5P_exist_plist(plist, H5F_ACS_FAMILY_NEWSIZE_NAME) > 0) {
+ /* Get the new family file size */
+ if(H5P_get(plist, H5F_ACS_FAMILY_NEWSIZE_NAME, &file->mem_newsize) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get new family member size")
+
+ /* Set flag for later */
+ file->repart_members = TRUE;
+ } /* end if */
+
+ if(fa->memb_fapl_id == H5P_FILE_ACCESS_DEFAULT) {
+ if(H5I_inc_ref(fa->memb_fapl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver")
+ file->memb_fapl_id = fa->memb_fapl_id;
+ } /* end if */
+ else {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fa->memb_fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ file->memb_fapl_id = H5P_copy_plist(plist, FALSE);
+ } /* end else */
+ file->memb_size = fa->memb_size; /* Actual member size to be updated later */
+ file->pmem_size = fa->memb_size; /* Member size passed in through property */
+ } /* end else */
+ file->name = H5MM_strdup(name);
+ file->flags = flags;
+
+ /* Allocate space for the string buffers */
+ if(NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate member name")
+ if(NULL == (temp = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate temporary member name")
+
+ /* Check that names are unique */
+ HDsnprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, 0);
+ HDsnprintf(temp, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, 1);
+ if(!HDstrcmp(memb_name, temp))
+ HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file names not unique")
+
+ /* Open all the family members */
+ while(1) {
+ HDsnprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, file->nmembs);
+
+ /* Enlarge member array */
+ if(file->nmembs >= file->amembs) {
+ unsigned n = MAX(64, 2 * file->amembs);
+ H5FD_t **x;
+
+ HDassert(n > 0);
+ if(NULL == (x = (H5FD_t **)H5MM_realloc(file->memb, n * sizeof(H5FD_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to reallocate members")
+ file->amembs = n;
+ file->memb = x;
+ } /* end if */
+
+ /*
+ * Attempt to open file. If the first file cannot be opened then fail;
+ * otherwise an open failure means that we've reached the last member.
+ * Allow H5F_ACC_CREAT only on the first family member.
+ */
+ H5E_BEGIN_TRY {
+ file->memb[file->nmembs] = H5FDopen(memb_name,
+ (0==file->nmembs ? flags : t_flags), file->memb_fapl_id, HADDR_UNDEF);
+ } H5E_END_TRY;
+ if (!file->memb[file->nmembs]) {
+ if (0==file->nmembs)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open member file")
+ H5E_clear_stack(NULL);
+ break;
+ }
+ file->nmembs++;
+ }
+
+ /* If the file is reopened and there's only one member file existing, this file maybe
+ * smaller than the size specified through H5Pset_fapl_family(). Update the actual
+ * member size.
+ */
+ if ((eof=H5FDget_eof(file->memb[0], H5FD_MEM_DEFAULT))) file->memb_size = eof;
+
+ ret_value=(H5FD_t *)file;
+
+done:
+ /* Release resources */
+ if(memb_name)
+ H5MM_xfree(memb_name);
+ if(temp)
+ H5MM_xfree(temp);
+
+ /* Cleanup and fail */
+ if(ret_value == NULL && file != NULL) {
+ unsigned nerrors = 0; /* Number of errors closing member files */
+ unsigned u; /* Local index variable */
+
+ /* Close as many members as possible. Use private function here to avoid clearing
+ * the error stack. We need the error message to indicate wrong member file size. */
+ for(u = 0; u < file->nmembs; u++)
+ if(file->memb[u])
+ if(H5FD_close(file->memb[u]) < 0)
+ nerrors++;
+ if(nerrors)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "unable to close member files")
+
+ if(file->memb)
+ H5MM_xfree(file->memb);
+ if(H5I_dec_ref(file->memb_fapl_id) < 0)
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, NULL, "can't close driver ID")
+ if(file->name)
+ H5MM_xfree(file->name);
+ H5MM_xfree(file);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_close
+ *
+ * Purpose: Closes a family of files.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative with as many members closed as
+ * possible. The only subsequent operation
+ * permitted on the file is a close operation.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_close(H5FD_t *_file)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ unsigned nerrors = 0; /* Number of errors while closing member files */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Close as many members as possible. Use private function here to avoid clearing
+ * the error stack. We need the error message to indicate wrong member file size. */
+ for(u = 0; u < file->nmembs; u++) {
+ if(file->memb[u]) {
+ if(H5FD_close(file->memb[u]) < 0)
+ nerrors++;
+ else
+ file->memb[u] = NULL;
+ } /* end if */
+ } /* end for */
+ if(nerrors)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close member files")
+
+ /* Clean up other stuff */
+ if(H5I_dec_ref(file->memb_fapl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID")
+ H5MM_xfree(file->memb);
+ H5MM_xfree(file->name);
+ H5MM_xfree(file);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_cmp
+ *
+ * Purpose: Compares two file families to see if they are the same. It
+ * does this by comparing the first member of the two families.
+ *
+ * Return: Success: like strcmp()
+ *
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_family_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_family_t *f1 = (const H5FD_family_t*)_f1;
+ const H5FD_family_t *f2 = (const H5FD_family_t*)_f2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f1->nmembs >= 1 && f1->memb[0]);
+ HDassert(f2->nmembs >= 1 && f2->memb[0]);
+
+ ret_value = H5FDcmp(f1->memb[0], f2->memb[0]);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_query(const H5FD_t * _file, unsigned long *flags /* out */)
+{
+ const H5FD_family_t *file = (const H5FD_family_t*)_file; /* Family VFD info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes. */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+
+ /* Check for flags that are set by h5repart */
+ if(file && file->repart_members)
+ *flags |= H5FD_FEAT_DIRTY_DRVRINFO_LOAD; /* Mark the superblock dirty when it is loaded (so the family member sizes are rewritten) */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_family_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_get_eoa
+ *
+ * Purpose: Returns the end-of-address marker for the file. The EOA
+ * marker is the first address past the last byte allocated in
+ * the format address space.
+ *
+ * Return: Success: The end-of-address-marker
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_family_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_family_t *file = (const H5FD_family_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t abs_eoa)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ haddr_t addr = abs_eoa;
+ char *memb_name = NULL;
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate space for the member name buffer */
+ if(NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate member name")
+
+ for(u = 0; addr || u < file->nmembs; u++) {
+
+ /* Enlarge member array */
+ if(u >= file->amembs) {
+ unsigned n = MAX(64, 2 * file->amembs);
+ H5FD_t **x = (H5FD_t **)H5MM_realloc(file->memb, n * sizeof(H5FD_t *));
+
+ if(!x)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block")
+ file->amembs = n;
+ file->memb = x;
+ file->nmembs = u;
+ } /* end if */
+
+ /* Create another file if necessary */
+ if(u >= file->nmembs || !file->memb[u]) {
+ file->nmembs = MAX(file->nmembs, u+1);
+ HDsnprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, file->name, u);
+ H5E_BEGIN_TRY {
+ H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t);
+ file->memb[u] = H5FDopen(memb_name, file->flags | H5F_ACC_CREAT,
+ file->memb_fapl_id, (haddr_t)file->memb_size);
+ } H5E_END_TRY;
+ if(NULL == file->memb[u])
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to open member file")
+ } /* end if */
+
+ /* Set the EOA marker for the member */
+ /* (Note compensating for base address addition in internal routine) */
+ H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t);
+ if(addr > (haddr_t)file->memb_size) {
+ if(H5FD_set_eoa(file->memb[u], type, ((haddr_t)file->memb_size - file->pub.base_addr)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set file eoa")
+ addr -= file->memb_size;
+ } /* end if */
+ else {
+ if(H5FD_set_eoa(file->memb[u], type, (addr - file->pub.base_addr)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set file eoa")
+ addr = 0;
+ } /* end else */
+ } /* end for */
+
+ file->eoa = abs_eoa;
+
+done:
+ /* Release resources */
+ if(memb_name)
+ H5MM_xfree(memb_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the total family size or the current EOA marker.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the family of files or the current
+ * EOA, whichever is larger.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_family_get_eof(const H5FD_t *_file, H5FD_mem_t type)
+{
+ const H5FD_family_t *file = (const H5FD_family_t*)_file;
+ haddr_t eof=0;
+ int i; /* Local index variable */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Find the last member that has a non-zero EOF and break out of the loop
+ * with `i' equal to that member. If all members have zero EOF then exit
+ * loop with i==0.
+ */
+ HDassert(file->nmembs > 0);
+ for(i = (int)file->nmembs - 1; i >= 0; --i) {
+ if((eof = H5FD_get_eof(file->memb[i], type)) != 0)
+ break;
+ if(0 == i)
+ break;
+ } /* end for */
+
+ /* Adjust for base address for file */
+ eof += file->pub.base_addr;
+
+ /*
+ * The file size is the number of members before the i'th member plus the
+ * size of the i'th member.
+ */
+ eof += ((unsigned)i)*file->memb_size;
+
+ /* Set return value */
+ ret_value = eof;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_get_handle
+ *
+ * Purpose: Returns the file handle of FAMILY file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle)
+{
+ H5FD_family_t *file = (H5FD_family_t *)_file;
+ H5P_genplist_t *plist;
+ hsize_t offset;
+ int memb;
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get the plist structure and family offset */
+ if(NULL == (plist = H5P_object_verify(fapl, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+ if(H5P_get(plist, H5F_ACS_FAMILY_OFFSET_NAME, &offset) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get offset for family driver")
+
+ if(offset > (file->memb_size * file->nmembs))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "offset is bigger than file size")
+ memb = (int)(offset/file->memb_size);
+
+ ret_value = H5FD_get_vfd_handle(file->memb[memb], fapl, file_handle);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero. Result is stored in caller-supplied
+ * buffer BUF.
+ *
+ * Failure: -1, contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
+ void *_buf/*out*/)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ unsigned char *buf = (unsigned char*)_buf;
+ haddr_t sub;
+ size_t req;
+ hsize_t tempreq;
+ unsigned u; /* Local index variable */
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Get the member data transfer property list. If the transfer property
+ * list does not belong to this driver then assume defaults
+ */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* Read from each member */
+ while(size > 0) {
+ H5_CHECKED_ASSIGN(u, unsigned, addr / file->memb_size, hsize_t);
+
+ sub = addr % file->memb_size;
+
+ /* This check is for mainly for IA32 architecture whose size_t's size
+ * is 4 bytes, to prevent overflow when user application is trying to
+ * write files bigger than 4GB. */
+ tempreq = file->memb_size-sub;
+ if(tempreq > SIZET_MAX)
+ tempreq = SIZET_MAX;
+ req = MIN(size, (size_t)tempreq);
+
+ HDassert(u<file->nmembs);
+
+ if (H5FDread(file->memb[u], type, dxpl_id, sub, req, buf)<0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "member file read failed")
+
+ addr += req;
+ buf += req;
+ size -= req;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
+ const void *_buf)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ const unsigned char *buf = (const unsigned char*)_buf;
+ haddr_t sub;
+ size_t req;
+ hsize_t tempreq;
+ unsigned u; /* Local index variable */
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Get the member data transfer property list. If the transfer property
+ * list does not belong to this driver then assume defaults.
+ */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* Write to each member */
+ while (size>0) {
+ H5_CHECKED_ASSIGN(u, unsigned, addr / file->memb_size, hsize_t);
+
+ sub = addr % file->memb_size;
+
+ /* This check is for mainly for IA32 architecture whose size_t's size
+ * is 4 bytes, to prevent overflow when user application is trying to
+ * write files bigger than 4GB. */
+ tempreq = file->memb_size-sub;
+ if(tempreq > SIZET_MAX)
+ tempreq = SIZET_MAX;
+ req = MIN(size, (size_t)tempreq);
+
+ HDassert(u<file->nmembs);
+
+ if (H5FDwrite(file->memb[u], type, dxpl_id, sub, req, buf)<0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "member file write failed")
+
+ addr += req;
+ buf += req;
+ size -= req;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_flush
+ *
+ * Purpose: Flushes all family members.
+ *
+ * Return: Success: 0
+ * Failure: -1, as many files flushed as possible.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ unsigned u, nerrors = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ for(u = 0; u < file->nmembs; u++)
+ if(file->memb[u] && H5FD_flush(file->memb[u], dxpl_id, closing) < 0)
+ nerrors++;
+
+ if(nerrors)
+ HGOTO_ERROR(H5E_IO, H5E_BADVALUE, FAIL, "unable to flush member files")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_truncate
+ *
+ * Purpose: Truncates all family members.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1, as many files truncated as possible.
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 23, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
+{
+ H5FD_family_t *file = (H5FD_family_t*)_file;
+ unsigned u, nerrors = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ for(u = 0; u < file->nmembs; u++)
+ if(file->memb[u] && H5FD_truncate(file->memb[u], dxpl_id, closing) < 0)
+ nerrors++;
+
+ if(nerrors)
+ HGOTO_ERROR(H5E_IO, H5E_BADVALUE, FAIL, "unable to flush member files")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_family_t *file = (H5FD_family_t *)_file; /* VFD file struct */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Place the lock on all the member files */
+ for(u = 0; u < file->nmembs; u++)
+ if(file->memb[u])
+ if(H5FD_lock(file->memb[u], rw) < 0)
+ break;
+
+ /* If one of the locks failed, try to unlock the locked member files
+ * in an attempt to return to a fully unlocked state.
+ */
+ if(u < file->nmembs) {
+ unsigned v; /* Local index variable */
+
+ for(v = 0; v < u; v++) {
+ if(H5FD_unlock(file->memb[v]) < 0)
+ /* Push error, but keep going */
+ HDONE_ERROR(H5E_IO, H5E_CANTUNLOCK, FAIL, "unable to unlock member files")
+ } /* end for */
+ HGOTO_ERROR(H5E_IO, H5E_CANTLOCK, FAIL, "unable to lock member files")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_family_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_family_unlock(H5FD_t *_file)
+{
+ H5FD_family_t *file = (H5FD_family_t *)_file; /* VFD file struct */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Remove the lock on the member files */
+ for(u = 0; u < file->nmembs; u++)
+ if(file->memb[u])
+ if(H5FD_unlock(file->memb[u]) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTUNLOCK, FAIL, "unable to unlock member files")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_family_unlock() */
+
diff --git a/src/H5FDfamily.h b/src/H5FDfamily.h
new file mode 100644
index 0000000..1584cf6
--- /dev/null
+++ b/src/H5FDfamily.h
@@ -0,0 +1,40 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 4, 1999
+ *
+ * Purpose: The public header file for the family driver.
+ */
+#ifndef H5FDfamily_H
+#define H5FDfamily_H
+
+#define H5FD_FAMILY (H5FD_family_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5_DLL hid_t H5FD_family_init(void);
+H5_DLL herr_t H5Pset_fapl_family(hid_t fapl_id, hsize_t memb_size,
+ hid_t memb_fapl_id);
+H5_DLL herr_t H5Pget_fapl_family(hid_t fapl_id, hsize_t *memb_size/*out*/,
+ hid_t *memb_fapl_id/*out*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5FDint.c b/src/H5FDint.c
new file mode 100644
index 0000000..bc322d6
--- /dev/null
+++ b/src/H5FDint.c
@@ -0,0 +1,435 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FDint.c
+ * Jan 17 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal routine for VFD operations
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDpkg.h" /* File Drivers */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_locate_signature
+ *
+ * Purpose: Finds the HDF5 superblock signature in a file. The
+ * signature can appear at address 0, or any power of two
+ * beginning with 512.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 7, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_locate_signature(H5FD_io_info_t *fdio_info, haddr_t *sig_addr)
+{
+ H5FD_t *file;
+ haddr_t addr, eoa, eof;
+ uint8_t buf[H5F_SIGNATURE_LEN];
+ unsigned n, maxpow;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(fdio_info);
+ file = fdio_info->file;
+ HDassert(file);
+
+ /* Find the least N such that 2^N is larger than the file size */
+ eof = H5FD_get_eof(file, H5FD_MEM_SUPER);
+ eoa = H5FD_get_eoa(file, H5FD_MEM_SUPER);
+ addr = MAX(eof, eoa);
+ if(HADDR_UNDEF == addr)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to obtain EOF/EOA value")
+ for(maxpow = 0; addr; maxpow++)
+ addr >>= 1;
+ maxpow = MAX(maxpow, 9);
+
+ /*
+ * Search for the file signature at format address zero followed by
+ * powers of two larger than 9.
+ */
+ for(n = 8; n < maxpow; n++) {
+ addr = (8 == n) ? 0 : (haddr_t)1 << n;
+ if(H5FD_set_eoa(file, H5FD_MEM_SUPER, addr + H5F_SIGNATURE_LEN) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to set EOA value for file signature")
+ if(H5FD_read(fdio_info, H5FD_MEM_SUPER, addr, (size_t)H5F_SIGNATURE_LEN, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to read file signature")
+ if(!HDmemcmp(buf, H5F_SIGNATURE, (size_t)H5F_SIGNATURE_LEN))
+ break;
+ } /* end for */
+
+ /*
+ * If the signature was not found then reset the EOA value and return
+ * HADDR_UNDEF.
+ */
+ if(n >= maxpow) {
+ if(H5FD_set_eoa(file, H5FD_MEM_SUPER, eoa) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to reset EOA value")
+ *sig_addr = HADDR_UNDEF;
+ } /* end if */
+ else
+ /* Set return value */
+ *sig_addr = addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_locate_signature() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_read
+ *
+ * Purpose: Private version of H5FDread()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_read(H5FD_io_info_t *fdio_info, H5FD_mem_t type, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5FD_t *file;
+ H5P_genplist_t *io_dxpl;
+ haddr_t eoa = HADDR_UNDEF;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fdio_info);
+ file = fdio_info->file;
+ HDassert(file && file->cls);
+ HDassert(TRUE == H5P_class_isa(H5P_CLASS(fdio_info->meta_dxpl), H5P_CLS_DATASET_XFER_g));
+ HDassert(TRUE == H5P_class_isa(H5P_CLASS(fdio_info->raw_dxpl), H5P_CLS_DATASET_XFER_g));
+ HDassert(buf);
+
+ /* Set up proper DXPL for I/O */
+ if(H5FD_MEM_DRAW == type)
+ io_dxpl = fdio_info->raw_dxpl;
+ else
+ io_dxpl = fdio_info->meta_dxpl;
+
+ /* Sanity check the dxpl type against the mem type */
+#ifdef H5_DEBUG_BUILD
+ {
+ H5FD_dxpl_type_t dxpl_type; /* Property indicating the type of the internal dxpl */
+
+ /* get the dxpl type */
+ if(H5P_get(io_dxpl, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't retrieve dxpl type")
+
+ /* we shouldn't be here if the dxpl is labeled with NO I/O */
+ HDassert(H5FD_NOIO_DXPL != dxpl_type);
+
+ if(H5FD_MEM_DRAW == type)
+ HDassert(H5FD_RAWDATA_DXPL == dxpl_type);
+ else
+ HDassert(H5FD_METADATA_DXPL == dxpl_type);
+ }
+#endif /* H5_DEBUG_BUILD */
+
+#ifndef H5_HAVE_PARALLEL
+ /* Do not return early for Parallel mode since the I/O could be a */
+ /* collective transfer. */
+ /* The no-op case */
+ if(0 == size)
+ HGOTO_DONE(SUCCEED)
+#endif /* H5_HAVE_PARALLEL */
+
+ if(HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+
+ /*
+ * If the file is open for SWMR read access, allow access to data past
+ * the end of the allocated space (the 'eoa'). This is done because the
+ * eoa stored in the file's superblock might be out of sync with the
+ * objects being written within the file by the application performing
+ * SWMR write operations.
+ */
+ if(!(file->access_flags & H5F_ACC_SWMR_READ) && ((addr + file->base_addr + size) > eoa))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu, eoa = %llu", (unsigned long long)(addr + file->base_addr), (unsigned long long)size, (unsigned long long)eoa)
+
+ /* Dispatch to driver */
+ if((file->cls->read)(file, type, H5P_PLIST_ID(io_dxpl), addr + file->base_addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_write
+ *
+ * Purpose: Private version of H5FDwrite()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_write(const H5FD_io_info_t *fdio_info, H5FD_mem_t type, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_t *file;
+ H5P_genplist_t *io_dxpl;
+ haddr_t eoa = HADDR_UNDEF;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fdio_info);
+ file = fdio_info->file;
+ HDassert(file && file->cls);
+ HDassert(TRUE == H5P_class_isa(H5P_CLASS(fdio_info->meta_dxpl), H5P_CLS_DATASET_XFER_g));
+ HDassert(TRUE == H5P_class_isa(H5P_CLASS(fdio_info->raw_dxpl), H5P_CLS_DATASET_XFER_g));
+ HDassert(buf);
+
+ /* Set up proper DXPL for I/O */
+ if(H5FD_MEM_DRAW == type)
+ io_dxpl = fdio_info->raw_dxpl;
+ else
+ io_dxpl = fdio_info->meta_dxpl;
+
+ /* Sanity check the dxpl type against the mem type */
+#ifdef H5_DEBUG_BUILD
+ {
+ H5FD_dxpl_type_t dxpl_type; /* Property indicating the type of the internal dxpl */
+
+ /* get the dxpl type */
+ if(H5P_get(io_dxpl, H5FD_DXPL_TYPE_NAME, &dxpl_type) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't retrieve dxpl type")
+
+ /* we shouldn't be here if the dxpl is labeled with NO I/O */
+ HDassert(H5FD_NOIO_DXPL != dxpl_type);
+
+ if(H5FD_MEM_DRAW == type)
+ HDassert(H5FD_RAWDATA_DXPL == dxpl_type);
+ else
+ HDassert(H5FD_METADATA_DXPL == dxpl_type);
+ }
+#endif /* H5_DEBUG_BUILD */
+
+#ifndef H5_HAVE_PARALLEL
+ /* Do not return early for Parallel mode since the I/O could be a */
+ /* collective transfer. */
+ /* The no-op case */
+ if(0 == size)
+ HGOTO_DONE(SUCCEED)
+#endif /* H5_HAVE_PARALLEL */
+
+ if(HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed")
+ if((addr + file->base_addr + size) > eoa)
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size=%llu, eoa=%llu",
+ (unsigned long long)(addr+ file->base_addr), (unsigned long long)size, (unsigned long long)eoa)
+
+ /* Dispatch to driver */
+ if((file->cls->write)(file, type, H5P_PLIST_ID(io_dxpl), addr + file->base_addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_set_eoa
+ *
+ * Purpose: Private version of H5FDset_eoa()
+ *
+ * This function expects the EOA is a RELATIVE address, i.e.
+ * relative to the base address. This is NOT the same as the
+ * EOA stored in the superblock, which is an absolute
+ * address. Object addresses are relative.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative, no side effect
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_set_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+ HDassert(H5F_addr_defined(addr) && addr <= file->maxaddr);
+
+ /* Dispatch to driver, convert to absolute address */
+ if((file->cls->set_eoa)(file, type, addr + file->base_addr) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver set_eoa request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_eoa
+ *
+ * Purpose: Private version of H5FDget_eoa()
+ *
+ * This function returns the EOA as a RELATIVE address, i.e.
+ * relative to the base address. This is NOT the same as the
+ * EOA stored in the superblock, which is an absolute
+ * address. Object addresses are relative.
+ *
+ * Return: Success: First byte after allocated memory.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_get_eoa(const H5FD_t *file, H5FD_mem_t type)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ HDassert(file && file->cls);
+
+ /* Dispatch to driver */
+ if(HADDR_UNDEF == (ret_value = (file->cls->get_eoa)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "driver get_eoa request failed")
+
+ /* Adjust for base address in file (convert to relative address) */
+ ret_value -= file->base_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_eof
+ *
+ * Purpose: Private version of H5FDget_eof()
+ *
+ * This function returns the EOF as a RELATIVE address, i.e.
+ * relative to the base address. This will be different
+ * from the end of the physical file if there is a user
+ * block.
+ *
+ * Return: Success: The EOF address.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_get_eof(const H5FD_t *file, H5FD_mem_t type)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ HDassert(file && file->cls);
+
+ /* Dispatch to driver */
+ if(file->cls->get_eof) {
+ if(HADDR_UNDEF == (ret_value = (file->cls->get_eof)(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, HADDR_UNDEF, "driver get_eof request failed")
+ } /* end if */
+ else
+ ret_value = file->maxaddr;
+
+ /* Adjust for base address in file (convert to relative address) */
+ ret_value -= file->base_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_eof() */
+
diff --git a/src/H5FDlog.c b/src/H5FDlog.c
new file mode 100644
index 0000000..75333c2
--- /dev/null
+++ b/src/H5FDlog.c
@@ -0,0 +1,1729 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Monday, April 17, 2000
+ *
+ * Purpose: The POSIX unbuffered file driver using only the HDF5 public
+ * API and with a few optimizations: the lseek() call is made
+ * only when the current file position is unknown or needs to be
+ * changed based on previous I/O through this driver (don't mix
+ * I/O from this driver with I/O from other parts of the
+ * application to the same file).
+ * With custom modifications...
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDlog.h" /* Logging file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_LOG_g = 0;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_log_fapl_t {
+ char *logfile; /* Allocated log file name */
+ unsigned long long flags; /* Flags for logging behavior */
+ size_t buf_size; /* Size of buffers for track flavor and number of times each byte is accessed */
+} H5FD_log_fapl_t;
+
+/* Define strings for the different file memory types
+ * These are defined in the H5F_mem_t enum from H5Fpublic.h
+ * Note that H5FD_MEM_NOLIST is not listed here since it has
+ * a negative value.
+ */
+static const char *flavors[]={
+ "H5FD_MEM_DEFAULT",
+ "H5FD_MEM_SUPER",
+ "H5FD_MEM_BTREE",
+ "H5FD_MEM_DRAW",
+ "H5FD_MEM_GHEAP",
+ "H5FD_MEM_LHEAP",
+ "H5FD_MEM_OHDR",
+};
+
+/* The description of a file belonging to this driver. The `eoa' and `eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying filesystem file). The
+ * `pos' value is used to eliminate file position updates when they would be a
+ * no-op. Unfortunately we've found systems that use separate file position
+ * indicators for reading and writing so the lseek can only be eliminated if
+ * the current operation is the same as the previous operation. When opening
+ * a file the `eof' will be set to the current file size, `eoa' will be set
+ * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error
+ * occurs), and `op' will be set to H5F_OP_UNKNOWN.
+ */
+typedef struct H5FD_log_t {
+ H5FD_t pub; /* public stuff, must be first */
+ int fd; /* the unix file */
+ haddr_t eoa; /* end of allocated region */
+ haddr_t eof; /* end of file; current file size */
+ haddr_t pos; /* current file I/O position */
+ H5FD_file_op_t op; /* last operation */
+ char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
+#ifndef H5_HAVE_WIN32_API
+ /* On most systems the combination of device and i-node number uniquely
+ * identify a file. Note that Cygwin, MinGW and other Windows POSIX
+ * environments have the stat function (which fakes inodes)
+ * and will use the 'device + inodes' scheme as opposed to the
+ * Windows code further below.
+ */
+ dev_t device; /* file device number */
+ ino_t inode; /* file i-node number */
+#else
+ /* Files in windows are uniquely identified by the volume serial
+ * number and the file index (both low and high parts).
+ *
+ * There are caveats where these numbers can change, especially
+ * on FAT file systems. On NTFS, however, a file should keep
+ * those numbers the same until renamed or deleted (though you
+ * can use ReplaceFile() on NTFS to keep the numbers the same
+ * while renaming).
+ *
+ * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
+ * more information.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
+ */
+ DWORD nFileIndexLow;
+ DWORD nFileIndexHigh;
+ DWORD dwVolumeSerialNumber;
+
+ HANDLE hFile; /* Native windows file handle */
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Information from properties set by 'h5repart' tool
+ *
+ * Whether to eliminate the family driver info and convert this file to
+ * a single file
+ */
+ hbool_t fam_to_sec2;
+
+ /* Fields for tracking I/O operations */
+ unsigned char *nread; /* Number of reads from a file location */
+ unsigned char *nwrite; /* Number of write to a file location */
+ unsigned char *flavor; /* Flavor of information written to file location */
+ unsigned long long total_read_ops; /* Total number of read operations */
+ unsigned long long total_write_ops; /* Total number of write operations */
+ unsigned long long total_seek_ops; /* Total number of seek operations */
+ unsigned long long total_truncate_ops; /* Total number of truncate operations */
+ double total_read_time; /* Total time spent in read operations */
+ double total_write_time; /* Total time spent in write operations */
+ double total_seek_time; /* Total time spent in seek operations */
+ double total_truncate_time; /* Total time spent in truncate operations */
+ size_t iosize; /* Size of I/O information buffers */
+ FILE *logfp; /* Log file pointer */
+ H5FD_log_fapl_t fa; /* Driver-specific file access properties */
+} H5FD_log_t;
+
+/*
+ * These macros check for overflow of various quantities. These macros
+ * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely by the second
+ * argument of the file seek function.
+ */
+#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
+#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || \
+ (HDoff_t)((A)+(Z))<(HDoff_t)(A))
+
+/* Prototypes */
+static herr_t H5FD_log_term(void);
+static void *H5FD_log_fapl_get(H5FD_t *file);
+static void *H5FD_log_fapl_copy(const void *_old_fa);
+static herr_t H5FD_log_fapl_free(void *_fa);
+static H5FD_t *H5FD_log_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+static herr_t H5FD_log_close(H5FD_t *_file);
+static int H5FD_log_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_log_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+static herr_t H5FD__log_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ hsize_t size);
+static haddr_t H5FD_log_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_log_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_log_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_log_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD_log_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD_log_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_log_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_log_unlock(H5FD_t *_file);
+
+static const H5FD_class_t H5FD_log_g = {
+ "log", /*name */
+ MAXADDR, /*maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_log_term, /*terminate */
+ NULL, /*sb_size */
+ NULL, /*sb_encode */
+ NULL, /*sb_decode */
+ sizeof(H5FD_log_fapl_t), /*fapl_size */
+ H5FD_log_fapl_get, /*fapl_get */
+ H5FD_log_fapl_copy, /*fapl_copy */
+ H5FD_log_fapl_free, /*fapl_free */
+ 0, /*dxpl_size */
+ NULL, /*dxpl_copy */
+ NULL, /*dxpl_free */
+ H5FD_log_open, /*open */
+ H5FD_log_close, /*close */
+ H5FD_log_cmp, /*cmp */
+ H5FD_log_query, /*query */
+ NULL, /*get_type_map */
+ H5FD_log_alloc, /*alloc */
+ H5FD__log_free, /*free */
+ H5FD_log_get_eoa, /*get_eoa */
+ H5FD_log_set_eoa, /*set_eoa */
+ H5FD_log_get_eof, /*get_eof */
+ H5FD_log_get_handle, /*get_handle */
+ H5FD_log_read, /*read */
+ H5FD_log_write, /*write */
+ NULL, /*flush */
+ H5FD_log_truncate, /*truncate */
+ H5FD_log_lock, /*lock */
+ H5FD_log_unlock, /*unlock */
+ H5FD_FLMAP_DICHOTOMY /*fl_map */
+};
+
+/* Declare a free list to manage the H5FD_log_t struct */
+H5FL_DEFINE_STATIC(H5FD_log_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initializes any interface-specific data or routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_log_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize log VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the log driver.
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_log_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5I_VFL != H5I_get_type(H5FD_LOG_g))
+ H5FD_LOG_g = H5FD_register(&H5FD_log_g, sizeof(H5FD_class_t), FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_LOG_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_log_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_LOG_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_log_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_log
+ *
+ * Purpose: Modify the file access property list to use the H5FD_LOG
+ * driver defined in this source file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_log(hid_t fapl_id, const char *logfile, unsigned long long flags, size_t buf_size)
+{
+ H5FD_log_fapl_t fa; /* File access property list information */
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*sULz", fapl_id, logfile, flags, buf_size);
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* This shallow copy is correct! The string will be properly
+ * copied deep down in the H5P code.
+ */
+ fa.logfile = (char *)logfile;
+
+ fa.flags = flags;
+ fa.buf_size = buf_size;
+ ret_value = H5P_set_driver(plist, H5FD_LOG, &fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_log() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_fapl_get
+ *
+ * Purpose: Returns a file access property list which indicates how the
+ * specified file is being accessed. The return list could be
+ * used to access another file the same way.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * members copied from the file struct.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 20, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_log_fapl_get(H5FD_t *_file)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = H5FD_log_fapl_copy(&(file->fa));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_fapl_copy
+ *
+ * Purpose: Copies the log-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 20, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_log_fapl_copy(const void *_old_fa)
+{
+ const H5FD_log_fapl_t *old_fa = (const H5FD_log_fapl_t*)_old_fa;
+ H5FD_log_fapl_t *new_fa = NULL; /* New FAPL info */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(old_fa);
+
+ /* Allocate the new FAPL info */
+ if(NULL == (new_fa = (H5FD_log_fapl_t *)H5MM_calloc(sizeof(H5FD_log_fapl_t))))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate log file FAPL")
+
+ /* Copy the general information */
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_log_fapl_t));
+
+ /* Deep copy the log file name */
+ if(old_fa->logfile != NULL)
+ if(NULL == (new_fa->logfile = H5MM_strdup(old_fa->logfile)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate log file name")
+
+ /* Set return value */
+ ret_value = new_fa;
+
+done:
+ if(NULL == ret_value)
+ if(new_fa) {
+ if(new_fa->logfile)
+ new_fa->logfile = (char *)H5MM_xfree(new_fa->logfile);
+ H5MM_free(new_fa);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_fapl_free
+ *
+ * Purpose: Frees the log-specific file access properties.
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 20, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_fapl_free(void *_fa)
+{
+ H5FD_log_fapl_t *fa = (H5FD_log_fapl_t*)_fa;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Free the fapl information */
+ if(fa->logfile)
+ fa->logfile = (char *)H5MM_xfree(fa->logfile);
+ H5MM_xfree(fa);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_log_fapl_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_open
+ *
+ * Purpose: Create and/or opens a file as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_log_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ H5FD_log_t *file = NULL;
+ H5P_genplist_t *plist; /* Property list */
+ const H5FD_log_fapl_t *fa; /* File access property list information */
+ int fd = -1; /* File descriptor */
+ int o_flags; /* Flags for open() call */
+#ifdef H5_HAVE_WIN32_API
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval timeval_start;
+ struct timeval open_timeval_diff;
+ struct timeval stat_timeval_diff;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ h5_stat_t sb;
+ H5FD_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check on file offsets */
+ HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t));
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+ if(ADDR_OVERFLOW(maxaddr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
+
+ /* Build the open flags */
+ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
+ if(H5F_ACC_TRUNC & flags)
+ o_flags |= O_TRUNC;
+ if(H5F_ACC_CREAT & flags)
+ o_flags |= O_CREAT;
+ if(H5F_ACC_EXCL & flags)
+ o_flags |= O_EXCL;
+
+ /* Get the driver specific information */
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ if(NULL == (fa = (const H5FD_log_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(fa->flags & H5FD_LOG_TIME_OPEN)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ /* Open the file */
+ if((fd = HDopen(name, o_flags, 0666)) < 0) {
+ int myerrno = errno;
+
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
+ } /* end if */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(fa->flags & H5FD_LOG_TIME_OPEN) {
+ struct timeval timeval_stop;
+
+ HDgettimeofday(&timeval_stop, NULL);
+
+ /* Calculate the elapsed gettimeofday time */
+ open_timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ open_timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(open_timeval_diff.tv_usec < 0) {
+ open_timeval_diff.tv_usec += 1000000;
+ open_timeval_diff.tv_sec--;
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(fa->flags & H5FD_LOG_TIME_STAT)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ /* Get the file stats */
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(fa->flags & H5FD_LOG_TIME_STAT) {
+ struct timeval timeval_stop;
+
+ HDgettimeofday(&timeval_stop, NULL);
+
+ /* Calculate the elapsed gettimeofday time */
+ stat_timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ stat_timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(stat_timeval_diff.tv_usec < 0) {
+ stat_timeval_diff.tv_usec += 1000000;
+ stat_timeval_diff.tv_sec--;
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Create the new file struct */
+ if(NULL == (file = H5FL_CALLOC(H5FD_log_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+
+ file->fd = fd;
+ H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t);
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+#ifdef H5_HAVE_WIN32_API
+ file->hFile = (HANDLE)_get_osfhandle(fd);
+ if(INVALID_HANDLE_VALUE == file->hFile)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
+
+ if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
+
+ file->nFileIndexHigh = fileinfo.nFileIndexHigh;
+ file->nFileIndexLow = fileinfo.nFileIndexLow;
+ file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
+#else /* H5_HAVE_WIN32_API */
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Retain a copy of the name used to open the file, for possible error reporting */
+ HDstrncpy(file->filename, name, sizeof(file->filename));
+ file->filename[sizeof(file->filename) - 1] = '\0';
+
+ /* Get the flags for logging */
+ file->fa.flags = fa->flags;
+ if(fa->logfile)
+ file->fa.logfile = H5MM_strdup(fa->logfile);
+ else
+ file->fa.logfile = NULL;
+ file->fa.buf_size = fa->buf_size;
+
+ /* Check if we are doing any logging at all */
+ if(file->fa.flags != 0) {
+ /* Allocate buffers for tracking file accesses and data "flavor" */
+ file->iosize = fa->buf_size;
+ if(file->fa.flags & H5FD_LOG_FILE_READ) {
+ file->nread = (unsigned char *)H5MM_calloc(file->iosize);
+ HDassert(file->nread);
+ } /* end if */
+ if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
+ file->nwrite = (unsigned char *)H5MM_calloc(file->iosize);
+ HDassert(file->nwrite);
+ } /* end if */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ file->flavor = (unsigned char *)H5MM_calloc(file->iosize);
+ HDassert(file->flavor);
+ } /* end if */
+
+ /* Set the log file pointer */
+ if(fa->logfile)
+ file->logfp = HDfopen(fa->logfile, "w");
+ else
+ file->logfp = stderr;
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_OPEN)
+ HDfprintf(file->logfp, "Open took: (%f s)\n", (double)open_timeval_diff.tv_sec + ((double)open_timeval_diff.tv_usec / (double)1000000.0f));
+ if(file->fa.flags & H5FD_LOG_TIME_STAT)
+ HDfprintf(file->logfp, "Stat took: (%f s)\n", (double)stat_timeval_diff.tv_sec + ((double)stat_timeval_diff.tv_usec / (double)1000000.0f));
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ } /* end if */
+
+ /* Check for non-default FAPL */
+ if(H5P_FILE_ACCESS_DEFAULT != fapl_id) {
+ /* This step is for h5repart tool only. If user wants to change file driver from
+ * family to sec2 while using h5repart, this private property should be set so that
+ * in the later step, the library can ignore the family driver information saved
+ * in the superblock.
+ */
+ if(H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SEC2_NAME) > 0)
+ if(H5P_get(plist, H5F_ACS_FAMILY_TO_SEC2_NAME, &file->fam_to_sec2) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to sec2")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (H5FD_t*)file;
+
+done:
+ if(NULL == ret_value) {
+ if(fd >= 0)
+ HDclose(fd);
+ if(file)
+ file = H5FL_FREE(H5FD_log_t, file);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_close
+ *
+ * Purpose: Closes an HDF5 file.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file not closed.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_close(H5FD_t *_file)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval timeval_start, timeval_stop;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(file);
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags&H5FD_LOG_TIME_CLOSE)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ /* Close the underlying file */
+ if(HDclose(file->fd) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags&H5FD_LOG_TIME_CLOSE)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Dump I/O information */
+ if(file->fa.flags != 0) {
+ haddr_t addr;
+ haddr_t last_addr;
+ unsigned char last_val;
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_CLOSE) {
+ struct timeval timeval_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ HDfprintf(file->logfp, "Close took: (%f s)\n", (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f));
+ } /* end if */
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Dump the total number of seek/read/write operations */
+ if(file->fa.flags & H5FD_LOG_NUM_READ)
+ HDfprintf(file->logfp, "Total number of read operations: %llu\n", file->total_read_ops);
+ if(file->fa.flags & H5FD_LOG_NUM_WRITE)
+ HDfprintf(file->logfp, "Total number of write operations: %llu\n", file->total_write_ops);
+ if(file->fa.flags & H5FD_LOG_NUM_SEEK)
+ HDfprintf(file->logfp, "Total number of seek operations: %llu\n", file->total_seek_ops);
+ if(file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
+ HDfprintf(file->logfp, "Total number of truncate operations: %llu\n", file->total_truncate_ops);
+
+ /* Dump the total time in seek/read/write */
+ if(file->fa.flags & H5FD_LOG_TIME_READ)
+ HDfprintf(file->logfp, "Total time in read operations: %f s\n", file->total_read_time);
+ if(file->fa.flags & H5FD_LOG_TIME_WRITE)
+ HDfprintf(file->logfp, "Total time in write operations: %f s\n", file->total_write_time);
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK)
+ HDfprintf(file->logfp, "Total time in seek operations: %f s\n", file->total_seek_time);
+ if(file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
+ HDfprintf(file->logfp, "Total time in truncate operations: %f s\n", file->total_truncate_time);
+
+ /* Dump the write I/O information */
+ if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
+ HDfprintf(file->logfp, "Dumping write I/O information:\n");
+ last_val = file->nwrite[0];
+ last_addr = 0;
+ addr = 1;
+ while(addr < file->eoa) {
+ if(file->nwrite[addr] != last_val) {
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
+ last_val = file->nwrite[addr];
+ last_addr = addr;
+ } /* end if */
+ addr++;
+ } /* end while */
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
+ } /* end if */
+
+ /* Dump the read I/O information */
+ if(file->fa.flags & H5FD_LOG_FILE_READ) {
+ HDfprintf(file->logfp, "Dumping read I/O information:\n");
+ last_val = file->nread[0];
+ last_addr = 0;
+ addr = 1;
+ while(addr < file->eoa) {
+ if(file->nread[addr] != last_val) {
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
+ last_val = file->nread[addr];
+ last_addr = addr;
+ } /* end if */
+ addr++;
+ } /* end while */
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
+ } /* end if */
+
+ /* Dump the I/O flavor information */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ HDfprintf(file->logfp, "Dumping I/O flavor information:\n");
+ last_val = file->flavor[0];
+ last_addr = 0;
+ addr = 1;
+ while(addr < file->eoa) {
+ if(file->flavor[addr] != last_val) {
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
+ last_val = file->flavor[addr];
+ last_addr = addr;
+ } /* end if */
+ addr++;
+ } /* end while */
+ HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
+ } /* end if */
+
+ /* Free the logging information */
+ if(file->fa.flags & H5FD_LOG_FILE_WRITE)
+ file->nwrite = (unsigned char *)H5MM_xfree(file->nwrite);
+ if(file->fa.flags & H5FD_LOG_FILE_READ)
+ file->nread = (unsigned char *)H5MM_xfree(file->nread);
+ if(file->fa.flags & H5FD_LOG_FLAVOR)
+ file->flavor = (unsigned char *)H5MM_xfree(file->flavor);
+ if(file->logfp != stderr)
+ HDfclose(file->logfp);
+ } /* end if */
+
+ if(file->fa.logfile)
+ file->fa.logfile = (char *)H5MM_xfree(file->fa.logfile);
+
+ /* Release the file info */
+ file = H5FL_FREE(H5FD_log_t, file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_cmp
+ *
+ * Purpose: Compares two files belonging to this driver using an
+ * arbitrary (but consistent) ordering.
+ *
+ * Return: Success: A value like strcmp()
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_log_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_log_t *f1 = (const H5FD_log_t *)_f1;
+ const H5FD_log_t *f2 = (const H5FD_log_t *)_f2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_WIN32_API
+ if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1)
+ if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1)
+
+ if(f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1)
+ if(f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1)
+
+ if(f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1)
+ if(f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1)
+#else
+#ifdef H5_DEV_T_IS_SCALAR
+ if(f1->device < f2->device) HGOTO_DONE(-1)
+ if(f1->device > f2->device) HGOTO_DONE(1)
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) HGOTO_DONE(-1)
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) HGOTO_DONE(1)
+#endif /* H5_DEV_T_IS_SCALAR */
+
+ if(f1->inode < f2->inode) HGOTO_DONE(-1)
+ if(f1->inode > f2->inode) HGOTO_DONE(1)
+
+#endif
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_query(const H5FD_t *_file, unsigned long *flags /* out */)
+{
+ const H5FD_log_t *file = (const H5FD_log_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
+ *flags |= H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */
+
+ /* Check for flags that are set by h5repart */
+ if(file && file->fam_to_sec2)
+ *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_log_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_alloc
+ *
+ * Purpose: Allocate file memory.
+ *
+ * Return: Success: Address of new memory
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 17, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, hsize_t size)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ haddr_t addr;
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Compute the address for the block to allocate */
+ addr = file->eoa;
+
+ /* Extend the end-of-allocated space address */
+ file->eoa = addr + size;
+
+ /* Retain the (first) flavor of the information written to the file */
+ if(file->fa.flags != 0) {
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ HDassert(addr < file->iosize);
+ H5_CHECK_OVERFLOW(size, hsize_t, size_t);
+ HDmemset(&file->flavor[addr], (int)type, (size_t)size);
+ } /* end if */
+
+ if(file->fa.flags & H5FD_LOG_ALLOC)
+ HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Allocated\n", addr, (addr + size) - 1, size, flavors[type]);
+ } /* end if */
+
+ /* Set return value */
+ ret_value = addr;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__log_free
+ *
+ * Purpose: Release file memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 28, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__log_free(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id,
+ haddr_t addr, hsize_t size)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(file->fa.flags != 0) {
+ /* Reset the flavor of the information in the file */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ HDassert(addr < file->iosize);
+ H5_CHECK_OVERFLOW(size, hsize_t, size_t);
+ HDmemset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size);
+ } /* end if */
+
+ /* Log the file memory freed */
+ if(file->fa.flags & H5FD_LOG_FREE)
+ HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Freed\n", addr, (addr + size) - 1, size, flavors[type]);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD__log_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: Success: The end-of-address marker.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_log_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_log_t *file = (const H5FD_log_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+} /* end H5FD_log_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(file->fa.flags != 0) {
+ /* Check for increasing file size */
+ if(H5F_addr_gt(addr, file->eoa) && H5F_addr_gt(addr, 0)) {
+ hsize_t size = addr - file->eoa;
+
+ /* Retain the flavor of the space allocated by the extension */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ HDassert(addr < file->iosize);
+ H5_CHECK_OVERFLOW(size, hsize_t, size_t);
+ HDmemset(&file->flavor[file->eoa], (int)type, (size_t)size);
+ } /* end if */
+
+ /* Log the extension like an allocation */
+ if(file->fa.flags & H5FD_LOG_ALLOC)
+ HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Allocated\n", file->eoa, addr, size, flavors[type]);
+ } /* end if */
+
+ /* Check for decreasing file size */
+ if(H5F_addr_lt(addr, file->eoa) && H5F_addr_gt(addr, 0)) {
+ hsize_t size = file->eoa - addr;
+
+ /* Reset the flavor of the space freed by the shrink */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ HDassert((addr + size) < file->iosize);
+ H5_CHECK_OVERFLOW(size, hsize_t, size_t);
+ HDmemset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size);
+ } /* end if */
+
+ /* Log the shrink like a free */
+ if(file->fa.flags & H5FD_LOG_FREE)
+ HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Freed\n", file->eoa, addr, size, flavors[type]);
+ } /* end if */
+ } /* end if */
+
+ file->eoa = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_log_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the filesystem end-of-file or the HDF5 end-of-address
+ * markers.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the "file", either the filesystem file
+ * or the HDF5 file.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_log_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_log_t *file = (const H5FD_log_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eof)
+} /* end H5FD_log_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_get_handle
+ *
+ * Purpose: Returns the file handle of LOG file driver.
+ *
+ * Returns: SUCCEED/FAIL
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void **file_handle)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+
+ *file_handle = &(file->fd);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_get_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: SUCCEED. Result is stored in caller-supplied
+ * buffer BUF.
+ * Failure: FAIL, Contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ size_t orig_size = size; /* Save the original size for later */
+ haddr_t orig_addr = addr;
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval timeval_start, timeval_stop;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
+
+ /* Log the I/O information about the read */
+ if(file->fa.flags != 0) {
+ size_t tmp_size = size;
+ haddr_t tmp_addr = addr;
+
+ /* Log information about the number of times these locations are read */
+ if(file->fa.flags & H5FD_LOG_FILE_READ) {
+ HDassert((addr + size) < file->iosize);
+ while(tmp_size-- > 0)
+ file->nread[tmp_addr++]++;
+ } /* end if */
+ } /* end if */
+
+ /* Seek to the correct location */
+ if(addr != file->pos || OP_READ != file->op) {
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Log information about the seek */
+ if(file->fa.flags & H5FD_LOG_NUM_SEEK)
+ file->total_seek_ops++;
+ if(file->fa.flags & H5FD_LOG_LOC_SEEK) {
+ HDfprintf(file->logfp, "Seek: From %10a To %10a", file->pos, addr);
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK) {
+ struct timeval timeval_diff;
+ double time_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
+ HDfprintf(file->logfp, " (%fs @ %.6lu.%.6llu)\n", time_diff, (unsigned long long)timeval_start.tv_sec, (unsigned long long)timeval_start.tv_usec);
+
+ /* Add to total seek time */
+ file->total_seek_time += time_diff;
+ } /* end if */
+ else
+ HDfprintf(file->logfp, "\n");
+#else /* H5_HAVE_GETTIMEOFDAY */
+ HDfprintf(file->logfp, "\n");
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ } /* end if */
+ } /* end if */
+
+ /*
+ * Read data, being careful of interrupted system calls, partial results,
+ * and the end of the file.
+ */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_READ)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to read */
+ h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
+
+ /* Trying to read more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_read = HDread(file->fd, buf, bytes_in);
+ } while(-1 == bytes_read && EINTR == errno);
+
+ if(-1 == bytes_read) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ if(file->fa.flags & H5FD_LOG_LOC_READ)
+ HDfprintf(file->logfp, "Error! Reading: %10a-%10a (%10Zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size);
+
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)myoffset);
+ } /* end if */
+
+ if(0 == bytes_read) {
+ /* end of file but not end of format address space */
+ HDmemset(buf, 0, size);
+ break;
+ } /* end if */
+
+ HDassert(bytes_read >= 0);
+ HDassert((size_t)bytes_read <= size);
+
+ size -= (size_t)bytes_read;
+ addr += (haddr_t)bytes_read;
+ buf = (char *)buf + bytes_read;
+
+ } /* end while */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_READ)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Log information about the read */
+ if(file->fa.flags & H5FD_LOG_NUM_READ)
+ file->total_read_ops++;
+ if(file->fa.flags & H5FD_LOG_LOC_READ) {
+ HDfprintf(file->logfp, "%10a-%10a (%10Zu bytes) (%s) Read", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]);
+
+ /* Verify that we are reading in the type of data we allocated in this location */
+ if(file->flavor) {
+ HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[orig_addr] || (H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT);
+ HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] || (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] == H5FD_MEM_DEFAULT);
+ } /* end if */
+
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_READ) {
+ struct timeval timeval_diff;
+ double time_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
+ HDfprintf(file->logfp, " (%fs @ %.6lu.%.6llu)\n", time_diff, (unsigned long long)timeval_start.tv_sec, (unsigned long long)timeval_start.tv_usec);
+
+ /* Add to total read time */
+ file->total_read_time += time_diff;
+ } /* end if */
+ else
+ HDfprintf(file->logfp, "\n");
+#else /* H5_HAVE_GETTIMEOFDAY */
+ HDfprintf(file->logfp, "\n");
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ } /* end if */
+
+ /* Update current position */
+ file->pos = addr;
+ file->op = OP_READ;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ size_t orig_size = size; /* Save the original size for later */
+ haddr_t orig_addr = addr;
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval timeval_start, timeval_stop;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(size > 0);
+ HDassert(buf);
+
+ /* Verify that we are writing out the type of data we allocated in this location */
+ if(file->flavor) {
+ HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[addr] || (H5FD_mem_t)file->flavor[addr] == H5FD_MEM_DEFAULT);
+ HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(addr + size) - 1] || (H5FD_mem_t)file->flavor[(addr + size) - 1] == H5FD_MEM_DEFAULT);
+ } /* end if */
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu", (unsigned long long)addr, (unsigned long long)size)
+
+ /* Log the I/O information about the write */
+ if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
+ size_t tmp_size = size;
+ haddr_t tmp_addr = addr;
+
+ /* Log information about the number of times these locations are read */
+ HDassert((addr + size) < file->iosize);
+ while(tmp_size-- > 0)
+ file->nwrite[tmp_addr++]++;
+ } /* end if */
+
+ /* Seek to the correct location */
+ if(addr != file->pos || OP_WRITE != file->op) {
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Log information about the seek */
+ if(file->fa.flags & H5FD_LOG_NUM_SEEK)
+ file->total_seek_ops++;
+ if(file->fa.flags & H5FD_LOG_LOC_SEEK) {
+ HDfprintf(file->logfp, "Seek: From %10a To %10a", file->pos, addr);
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_SEEK) {
+ struct timeval timeval_diff;
+ double time_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
+ HDfprintf(file->logfp, " (%fs @ %.6lu.%.6llu)\n", time_diff, (unsigned long long)timeval_start.tv_sec, (unsigned long long)timeval_start.tv_usec);
+
+ /* Add to total seek time */
+ file->total_seek_time += time_diff;
+ } /* end if */
+ else
+ HDfprintf(file->logfp, "\n");
+#else /* H5_HAVE_GETTIMEOFDAY */
+ HDfprintf(file->logfp, "\n");
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ } /* end if */
+ } /* end if */
+
+ /*
+ * Write the data, being careful of interrupted system calls and partial
+ * results
+ */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags&H5FD_LOG_TIME_WRITE)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to write */
+ h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
+
+ /* Trying to write more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_wrote = HDwrite(file->fd, buf, bytes_in);
+ } while(-1 == bytes_wrote && EINTR == errno);
+
+ if(-1 == bytes_wrote) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ if(file->fa.flags & H5FD_LOG_LOC_WRITE)
+ HDfprintf(file->logfp, "Error! Writing: %10a-%10a (%10Zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size);
+
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = %llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)myoffset);
+ } /* end if */
+
+ HDassert(bytes_wrote > 0);
+ HDassert((size_t)bytes_wrote <= size);
+
+ size -= (size_t)bytes_wrote;
+ addr += (haddr_t)bytes_wrote;
+ buf = (const char *)buf + bytes_wrote;
+ } /* end while */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_WRITE)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Log information about the write */
+ if(file->fa.flags & H5FD_LOG_NUM_WRITE)
+ file->total_write_ops++;
+ if(file->fa.flags & H5FD_LOG_LOC_WRITE) {
+ HDfprintf(file->logfp, "%10a-%10a (%10Zu bytes) (%s) Written", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]);
+
+ /* Check if this is the first write into a "default" section, grabbed by the metadata agregation algorithm */
+ if(file->fa.flags & H5FD_LOG_FLAVOR) {
+ if((H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT) {
+ HDmemset(&file->flavor[orig_addr], (int)type, orig_size);
+ HDfprintf(file->logfp, " (fresh)");
+ } /* end if */
+ } /* end if */
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_WRITE) {
+ struct timeval timeval_diff;
+ double time_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
+ HDfprintf(file->logfp, " (%fs @ %.6lu.%.6llu)\n", time_diff, (unsigned long long)timeval_start.tv_sec, (unsigned long long)timeval_start.tv_usec);
+
+ /* Add to total write time */
+ file->total_write_time += time_diff;
+ } /* end if */
+ else
+ HDfprintf(file->logfp, "\n");
+#else /* H5_HAVE_GETTIMEOFDAY */
+ HDfprintf(file->logfp, "\n");
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ } /* end if */
+
+ /* Update current position and eof */
+ file->pos = addr;
+ file->op = OP_WRITE;
+ if(file->pos > file->eof)
+ file->eof = file->pos;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Extend the file to make sure it's large enough */
+ if(!H5F_addr_eq(file->eoa, file->eof)) {
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval timeval_start, timeval_stop;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+#ifdef H5_HAVE_WIN32_API
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+#endif /* H5_HAVE_WIN32_API */
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
+ HDgettimeofday(&timeval_start, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+#ifdef H5_HAVE_WIN32_API
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#else /* H5_HAVE_WIN32_API */
+ if(-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#endif /* H5_HAVE_WIN32_API */
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
+ HDgettimeofday(&timeval_stop, NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ /* Log information about the truncate */
+ if(file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
+ file->total_truncate_ops++;
+ if(file->fa.flags & H5FD_LOG_TRUNCATE) {
+ HDfprintf(file->logfp, "Truncate: To %10a", file->eoa);
+#ifdef H5_HAVE_GETTIMEOFDAY
+ if(file->fa.flags & H5FD_LOG_TIME_TRUNCATE) {
+ struct timeval timeval_diff;
+ double time_diff;
+
+ /* Calculate the elapsed gettimeofday time */
+ timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
+ timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
+ if(timeval_diff.tv_usec < 0) {
+ timeval_diff.tv_usec += 1000000;
+ timeval_diff.tv_sec--;
+ } /* end if */
+ time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
+ HDfprintf(file->logfp, " (%fs @ %.6lu.%.6llu)\n", time_diff, (unsigned long long)timeval_start.tv_sec, (unsigned long long)timeval_start.tv_usec);
+
+ /* Add to total truncate time */
+ file->total_truncate_time += time_diff;
+ } /* end if */
+ else
+ HDfprintf(file->logfp, "\n");
+#else /* H5_HAVE_GETTIMEOFDAY */
+ HDfprintf(file->logfp, "\n");
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ } /* end if */
+
+ /* Update the eof value */
+ file->eof = file->eoa;
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_lock
+ *
+ * Purpose: Place a lock on the file
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file not locked.
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file; /* VFD file struct */
+ int lock_flags; /* file locking flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(file);
+
+ /* Set exclusive or shared lock based on rw status */
+ lock_flags = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place a non-blocking lock on the file */
+ if(HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_log_unlock
+ *
+ * Purpose: Remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_log_unlock(H5FD_t *_file)
+{
+ H5FD_log_t *file = (H5FD_log_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_log_unlock() */
+
diff --git a/src/H5FDlog.h b/src/H5FDlog.h
new file mode 100644
index 0000000..a69bb18
--- /dev/null
+++ b/src/H5FDlog.h
@@ -0,0 +1,72 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, April 17, 2000
+ *
+ * Purpose: The public header file for the log driver.
+ */
+#ifndef H5FDlog_H
+#define H5FDlog_H
+
+#define H5FD_LOG (H5FD_log_init())
+
+/* Flags for H5Pset_fapl_log() */
+/* Flags for tracking 'meta' operations (truncate) */
+#define H5FD_LOG_TRUNCATE 0x00000001
+#define H5FD_LOG_META_IO (H5FD_LOG_TRUNCATE)
+/* Flags for tracking where reads/writes/seeks occur */
+#define H5FD_LOG_LOC_READ 0x00000002
+#define H5FD_LOG_LOC_WRITE 0x00000004
+#define H5FD_LOG_LOC_SEEK 0x00000008
+#define H5FD_LOG_LOC_IO (H5FD_LOG_LOC_READ|H5FD_LOG_LOC_WRITE|H5FD_LOG_LOC_SEEK)
+/* Flags for tracking number of times each byte is read/written */
+#define H5FD_LOG_FILE_READ 0x00000010
+#define H5FD_LOG_FILE_WRITE 0x00000020
+#define H5FD_LOG_FILE_IO (H5FD_LOG_FILE_READ|H5FD_LOG_FILE_WRITE)
+/* Flag for tracking "flavor" (type) of information stored at each byte */
+#define H5FD_LOG_FLAVOR 0x00000040
+/* Flags for tracking total number of reads/writes/seeks/truncates */
+#define H5FD_LOG_NUM_READ 0x00000080
+#define H5FD_LOG_NUM_WRITE 0x00000100
+#define H5FD_LOG_NUM_SEEK 0x00000200
+#define H5FD_LOG_NUM_TRUNCATE 0x00000400
+#define H5FD_LOG_NUM_IO (H5FD_LOG_NUM_READ|H5FD_LOG_NUM_WRITE|H5FD_LOG_NUM_SEEK|H5FD_LOG_NUM_TRUNCATE)
+/* Flags for tracking time spent in open/stat/read/write/seek/truncate/close */
+#define H5FD_LOG_TIME_OPEN 0x00000800
+#define H5FD_LOG_TIME_STAT 0x00001000
+#define H5FD_LOG_TIME_READ 0x00002000
+#define H5FD_LOG_TIME_WRITE 0x00004000
+#define H5FD_LOG_TIME_SEEK 0x00008000
+#define H5FD_LOG_TIME_TRUNCATE 0x00010000
+#define H5FD_LOG_TIME_CLOSE 0x00020000
+#define H5FD_LOG_TIME_IO (H5FD_LOG_TIME_OPEN|H5FD_LOG_TIME_STAT|H5FD_LOG_TIME_READ|H5FD_LOG_TIME_WRITE|H5FD_LOG_TIME_SEEK|H5FD_LOG_TIME_TRUNCATE|H5FD_LOG_TIME_CLOSE)
+/* Flags for tracking allocation/release of space in file */
+#define H5FD_LOG_ALLOC 0x00040000
+#define H5FD_LOG_FREE 0x00080000
+#define H5FD_LOG_ALL (H5FD_LOG_FREE|H5FD_LOG_ALLOC|H5FD_LOG_TIME_IO|H5FD_LOG_NUM_IO|H5FD_LOG_FLAVOR|H5FD_LOG_FILE_IO|H5FD_LOG_LOC_IO|H5FD_LOG_META_IO)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5_DLL hid_t H5FD_log_init(void);
+H5_DLL herr_t H5Pset_fapl_log(hid_t fapl_id, const char *logfile, unsigned long long flags, size_t buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5FDmodule.h b/src/H5FDmodule.h
new file mode 100644
index 0000000..ea1a9fd
--- /dev/null
+++ b/src/H5FDmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5FD package. Including this header means that the source file
+ * is part of the H5FD package.
+ */
+#ifndef _H5FDmodule_H
+#define _H5FDmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5FD_MODULE
+#define H5_MY_PKG H5FD
+#define H5_MY_PKG_ERR H5E_VFL
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5FDmodule_H */
+
diff --git a/src/H5FDmpi.c b/src/H5FDmpi.c
new file mode 100644
index 0000000..16be455
--- /dev/null
+++ b/src/H5FDmpi.c
@@ -0,0 +1,518 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Friday, January 30, 2004
+ *
+ * Purpose: Common routines for all MPI-based VFL drivers.
+ *
+ */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDmpi.h" /* Common MPI file driver */
+#include "H5Pprivate.h" /* Property lists */
+
+#ifdef H5_HAVE_PARALLEL
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_get_rank
+ *
+ * Purpose: Retrieves the rank of an MPI process.
+ *
+ * Return: Success: The rank (non-negative)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FD_mpi_get_rank(const H5FD_t *file)
+{
+ const H5FD_class_mpi_t *cls;
+
+ int ret_value;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file);
+ cls = (const H5FD_class_mpi_t *)(file->cls);
+ HDassert(cls);
+ HDassert(cls->get_rank); /* All MPI drivers must implement this */
+
+ /* Dispatch to driver */
+ if ((ret_value=(cls->get_rank)(file))<0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_rank request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpi_get_rank() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_get_size
+ *
+ * Purpose: Retrieves the size of the communicator used for the file
+ *
+ * Return: Success: The communicator size (non-negative)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FD_mpi_get_size(const H5FD_t *file)
+{
+ const H5FD_class_mpi_t *cls;
+ int ret_value;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file);
+ cls = (const H5FD_class_mpi_t *)(file->cls);
+ HDassert(cls);
+ HDassert(cls->get_size); /* All MPI drivers must implement this */
+
+ /* Dispatch to driver */
+ if ((ret_value=(cls->get_size)(file))<0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_size request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpi_get_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_get_comm
+ *
+ * Purpose: Retrieves the file's communicator
+ *
+ * Return: Success: The communicator (non-negative)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+MPI_Comm
+H5FD_mpi_get_comm(const H5FD_t *file)
+{
+ const H5FD_class_mpi_t *cls;
+ MPI_Comm ret_value;
+
+ FUNC_ENTER_NOAPI(MPI_COMM_NULL)
+
+ HDassert(file);
+ cls = (const H5FD_class_mpi_t *)(file->cls);
+ HDassert(cls);
+ HDassert(cls->get_comm); /* All MPI drivers must implement this */
+
+ /* Dispatch to driver */
+ if ((ret_value=(cls->get_comm)(file))==MPI_COMM_NULL)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, MPI_COMM_NULL, "driver get_comm request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpi_get_comm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_mpi_info
+ *
+ * Purpose: Retrieves the file's mpi info
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: Negative
+ *
+ * Programmer: John Mainzer
+ * 4/4/17
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_mpi_info(H5FD_t *file, void** mpi_info)
+{
+ const H5FD_class_mpi_t *cls;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+ cls = (const H5FD_class_mpi_t *)(file->cls);
+ HDassert(cls);
+ HDassert(cls->get_mpi_info); /* All MPI drivers must implement this */
+
+ /* Dispatch to driver */
+ if ((ret_value=(cls->get_mpi_info)(file, mpi_info)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, MPI_COMM_NULL, \
+ "driver get_mpi_info request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_get_mpi_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_MPIOff_to_haddr
+ *
+ * Purpose: Convert an MPI_Offset value to haddr_t.
+ *
+ * Return: Success: The haddr_t equivalent of the MPI_OFF
+ * argument.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Unknown
+ * January 30, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-04-23
+ * An error is reported for address overflows. The ADDR output
+ * argument is optional.
+ *
+ * Robb Matzke, 1999-08-06
+ * Modified to work with the virtual file layer.
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_mpi_MPIOff_to_haddr(MPI_Offset mpi_off)
+{
+ haddr_t ret_value=HADDR_UNDEF;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (mpi_off != (MPI_Offset)(haddr_t)mpi_off)
+ ret_value=HADDR_UNDEF;
+ else
+ ret_value=(haddr_t)mpi_off;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_haddr_to_MPIOff
+ *
+ * Purpose: Convert an haddr_t value to MPI_Offset.
+ *
+ * Return: Success: Non-negative, the MPI_OFF argument contains
+ * the converted value.
+ *
+ * Failure: Negative, MPI_OFF is undefined.
+ *
+ * Programmer: Unknown
+ * January 30, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-04-23
+ * An error is reported for address overflows. The ADDR output
+ * argument is optional.
+ *
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *
+ * Robb Matzke, 1999-08-06
+ * Modified to work with the virtual file layer.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpi_haddr_to_MPIOff(haddr_t addr, MPI_Offset *mpi_off/*out*/)
+{
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mpi_off);
+
+ /* Convert the HDF5 address into an MPI offset */
+ *mpi_off = (MPI_Offset)addr;
+
+ if (addr != (haddr_t)((MPI_Offset)addr))
+ ret_value=FAIL;
+ else
+ ret_value=SUCCEED;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_comm_info_dup
+ *
+ * Purpose: Make duplicates of communicator and Info object.
+ * If the Info object is in fact MPI_INFO_NULL, no duplicate
+ * is made but the same value assigned to the new Info object
+ * handle.
+ *
+ * Return: Success: Non-negative. The new communicator and Info
+ * object handles are returned via comm_new and
+ * info_new pointers.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Albert Cheng
+ * Jan 8, 2003
+ *
+ * Modifications:
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpi_comm_info_dup(MPI_Comm comm, MPI_Info info, MPI_Comm *comm_new, MPI_Info *info_new)
+{
+ herr_t ret_value=SUCCEED;
+ MPI_Comm comm_dup=MPI_COMM_NULL;
+ MPI_Info info_dup=MPI_INFO_NULL;
+ int mpi_code;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if (MPI_COMM_NULL == comm)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "not a valid argument")
+ if (!comm_new || !info_new)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "bad pointers")
+
+ /* Dup them. Using temporary variables for error recovery cleanup. */
+ if (MPI_SUCCESS != (mpi_code=MPI_Comm_dup(comm, &comm_dup)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Comm_dup failed", mpi_code)
+ if (MPI_INFO_NULL != info){
+ if (MPI_SUCCESS != (mpi_code=MPI_Info_dup(info, &info_dup)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Info_dup failed", mpi_code)
+ }else{
+ /* No dup, just copy it. */
+ info_dup = info;
+ }
+
+ /* copy them to the return arguments */
+ *comm_new = comm_dup;
+ *info_new = info_dup;
+
+done:
+ if (FAIL == ret_value){
+ /* need to free anything created here */
+ if (MPI_COMM_NULL != comm_dup)
+ MPI_Comm_free(&comm_dup);
+ if (MPI_INFO_NULL != info_dup)
+ MPI_Info_free(&info_dup);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_comm_info_free
+ *
+ * Purpose: Free the communicator and Info object.
+ * If comm or info is in fact MPI_COMM_NULL or MPI_INFO_NULL
+ * respectively, no action occurs to it.
+ *
+ * Return: Success: Non-negative. The values the pointers refer
+ * to will be set to the corresponding NULL
+ * handles.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Albert Cheng
+ * Jan 8, 2003
+ *
+ * Modifications:
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpi_comm_info_free(MPI_Comm *comm, MPI_Info *info)
+{
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if (!comm || !info)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "not a valid argument")
+
+ if (MPI_COMM_NULL != *comm)
+ MPI_Comm_free(comm);
+ if (MPI_INFO_NULL != *info)
+ MPI_Info_free(info);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+#ifdef NOT_YET
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_wait_for_left_neighbor
+ *
+ * Purpose: Blocks until (empty) msg is received from immediately
+ * lower-rank neighbor. In conjunction with
+ * H5FD_mpio_signal_right_neighbor, useful for enforcing
+ * 1-process-at-at-time access to critical regions to avoid race
+ * conditions (though it is overkill to require that the
+ * processes be allowed to proceed strictly in order of their
+ * rank).
+ *
+ * Note: This routine doesn't read or write any file, just performs
+ * interprocess coordination. It really should reside in a
+ * separate package of such routines.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: rky
+ * 19981207
+ *
+ * Modifications:
+ * Robb Matzke, 1999-08-09
+ * Modified to work with the virtual file layer.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpio_wait_for_left_neighbor(H5FD_t *_file)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ char msgbuf[1];
+ MPI_Status rcvstat;
+ int mpi_code; /* mpi return code */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ /* Portably initialize MPI status variable */
+ HDmemset(&rcvstat,0,sizeof(MPI_Status));
+
+ /* p0 has no left neighbor; all other procs wait for msg */
+ if (file->mpi_rank != 0) {
+ if (MPI_SUCCESS != (mpi_code=MPI_Recv( &msgbuf, 1, MPI_CHAR,
+ file->mpi_rank-1, MPI_ANY_TAG, file->comm, &rcvstat )))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mpi_code)
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_signal_right_neighbor
+ *
+ * Purpose: Blocks until (empty) msg is received from immediately
+ * lower-rank neighbor. In conjunction with
+ * H5FD_mpio_wait_for_left_neighbor, useful for enforcing
+ * 1-process-at-at-time access to critical regions to avoid race
+ * conditions (though it is overkill to require that the
+ * processes be allowed to proceed strictly in order of their
+ * rank).
+ *
+ * Note: This routine doesn't read or write any file, just performs
+ * interprocess coordination. It really should reside in a
+ * separate package of such routines.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: rky
+ * 19981207
+ *
+ * Modifications:
+ * Robb Matzke, 1999-08-09
+ * Modified to work with the virtual file layer.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpio_signal_right_neighbor(H5FD_t *_file)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ char msgbuf[1];
+ int mpi_code; /* mpi return code */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ if(file->mpi_rank != (file->mpi_size - 1))
+ if(MPI_SUCCESS != (mpi_code=MPI_Send(&msgbuf, 0/*empty msg*/, MPI_CHAR, file->mpi_rank + 1, 0, file->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mpi_code)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+#endif /* NOT_YET */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpi_setup_collective
+ *
+ * Purpose: Set the buffer type BTYPE, file type FTYPE for a data
+ * transfer. Also request a MPI type transfer.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 9, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_mpi_setup_collective(hid_t dxpl_id, MPI_Datatype *btype, MPI_Datatype *ftype)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dataset transfer list")
+
+ /* Set buffer MPI type */
+ if(H5P_set(plist, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, btype) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O property")
+
+ /* Set File MPI type */
+ if(H5P_set(plist, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, ftype) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O property")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpi_setup_collective() */
+
+#endif /* H5_HAVE_PARALLEL */
diff --git a/src/H5FDmpi.h b/src/H5FDmpi.h
new file mode 100644
index 0000000..2d62c79
--- /dev/null
+++ b/src/H5FDmpi.h
@@ -0,0 +1,60 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Friday, January 30, 2004
+ *
+ * Purpose: The public header file for common items for all MPI VFL drivers
+ */
+#ifndef H5FDmpi_H
+#define H5FDmpi_H
+
+/***** Macros for One linked collective IO case. *****/
+/* The default value to do one linked collective IO for all chunks.
+ If the average number of chunks per process is greater than this value,
+ the library will create an MPI derived datatype to link all chunks to do collective IO.
+ The user can set this value through an API. */
+
+#define H5D_ONE_LINK_CHUNK_IO_THRESHOLD 0
+/***** Macros for multi-chunk collective IO case. *****/
+/* The default value of the threshold to do collective IO for this chunk.
+ If the average percentage of processes per chunk is greater than the default value,
+ collective IO is done for this chunk.
+*/
+
+#define H5D_MULTI_CHUNK_IO_COL_THRESHOLD 60
+/* Type of I/O for data transfer properties */
+typedef enum H5FD_mpio_xfer_t {
+ H5FD_MPIO_INDEPENDENT = 0, /*zero is the default*/
+ H5FD_MPIO_COLLECTIVE
+} H5FD_mpio_xfer_t;
+
+/* Type of chunked dataset I/O */
+typedef enum H5FD_mpio_chunk_opt_t {
+ H5FD_MPIO_CHUNK_DEFAULT = 0,
+ H5FD_MPIO_CHUNK_ONE_IO, /*zero is the default*/
+ H5FD_MPIO_CHUNK_MULTI_IO
+} H5FD_mpio_chunk_opt_t;
+
+/* Type of collective I/O */
+typedef enum H5FD_mpio_collective_opt_t {
+ H5FD_MPIO_COLLECTIVE_IO = 0,
+ H5FD_MPIO_INDIVIDUAL_IO /*zero is the default*/
+} H5FD_mpio_collective_opt_t;
+
+/* Include all the MPI VFL headers */
+#include "H5FDmpio.h" /* MPI I/O file driver */
+
+#endif /* H5FDmpi_H */
+
diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c
new file mode 100644
index 0000000..ace91f8
--- /dev/null
+++ b/src/H5FDmpio.c
@@ -0,0 +1,2087 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, July 29, 1999
+ *
+ * Purpose: This is the MPI-2 I/O driver.
+ *
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDmpi.h" /* MPI-based file drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*
+ * The driver identification number, initialized at runtime if H5_HAVE_PARALLEL
+ * is defined. This allows applications to still have the H5FD_MPIO
+ * "constants" in their source code.
+ */
+static hid_t H5FD_MPIO_g = 0;
+
+/* Whether to allow collective I/O operations */
+/* (Value can be set from environment variable also) */
+hbool_t H5FD_mpi_opt_types_g = TRUE;
+
+/*
+ * The view is set to this value
+ */
+static char H5FD_mpi_native_g[] = "native";
+
+/*
+ * The description of a file belonging to this driver.
+ * The EOF value is only used just after the file is opened in order for the
+ * library to determine whether the file is empty, truncated, or okay. The MPIO
+ * driver doesn't bother to keep it updated since it's an expensive operation.
+ */
+typedef struct H5FD_mpio_t {
+ H5FD_t pub; /*public stuff, must be first */
+ MPI_File f; /*MPIO file handle */
+ MPI_Comm comm; /*communicator */
+ MPI_Info info; /*file information */
+ int mpi_rank; /* This process's rank */
+ int mpi_size; /* Total number of processes */
+ haddr_t eof; /*end-of-file marker */
+ haddr_t eoa; /*end-of-address marker */
+ haddr_t last_eoa; /* Last known end-of-address marker */
+ haddr_t local_eof; /* Local end-of-file address for each process */
+} H5FD_mpio_t;
+
+/* Private Prototypes */
+
+/* Callbacks */
+static herr_t H5FD_mpio_term(void);
+static void *H5FD_mpio_fapl_get(H5FD_t *_file);
+static void *H5FD_mpio_fapl_copy(const void *_old_fa);
+static herr_t H5FD_mpio_fapl_free(void *_fa);
+static H5FD_t *H5FD_mpio_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+static herr_t H5FD_mpio_close(H5FD_t *_file);
+static herr_t H5FD_mpio_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_mpio_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_mpio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_mpio_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_mpio_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD_mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD_mpio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_mpio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static int H5FD_mpio_mpi_rank(const H5FD_t *_file);
+static int H5FD_mpio_mpi_size(const H5FD_t *_file);
+static MPI_Comm H5FD_mpio_communicator(const H5FD_t *_file);
+static herr_t H5FD_mpio_get_info(H5FD_t *_file, void** mpi_info);
+
+/* The MPIO file driver information */
+static const H5FD_class_mpi_t H5FD_mpio_g = {
+ { /* Start of superclass information */
+ "mpio", /*name */
+ HADDR_MAX, /*maxaddr */
+ H5F_CLOSE_SEMI, /* fc_degree */
+ H5FD_mpio_term, /*terminate */
+ NULL, /*sb_size */
+ NULL, /*sb_encode */
+ NULL, /*sb_decode */
+ sizeof(H5FD_mpio_fapl_t), /*fapl_size */
+ H5FD_mpio_fapl_get, /*fapl_get */
+ H5FD_mpio_fapl_copy, /*fapl_copy */
+ H5FD_mpio_fapl_free, /*fapl_free */
+ 0, /*dxpl_size */
+ NULL, /*dxpl_copy */
+ NULL, /*dxpl_free */
+ H5FD_mpio_open, /*open */
+ H5FD_mpio_close, /*close */
+ NULL, /*cmp */
+ H5FD_mpio_query, /*query */
+ NULL, /*get_type_map */
+ NULL, /*alloc */
+ NULL, /*free */
+ H5FD_mpio_get_eoa, /*get_eoa */
+ H5FD_mpio_set_eoa, /*set_eoa */
+ H5FD_mpio_get_eof, /*get_eof */
+ H5FD_mpio_get_handle, /*get_handle */
+ H5FD_mpio_read, /*read */
+ H5FD_mpio_write, /*write */
+ H5FD_mpio_flush, /*flush */
+ H5FD_mpio_truncate, /*truncate */
+ NULL, /*lock */
+ NULL, /*unlock */
+ H5FD_FLMAP_DICHOTOMY /*fl_map */
+ }, /* End of superclass information */
+ H5FD_mpio_mpi_rank, /*get_rank */
+ H5FD_mpio_mpi_size, /*get_size */
+ H5FD_mpio_communicator, /*get_comm */
+ H5FD_mpio_get_info /*get_info */
+};
+
+#ifdef H5FDmpio_DEBUG
+/* Flags to control debug actions in H5Fmpio.
+ * Meant to be indexed by characters.
+ *
+ * 'c' show result of MPI_Get_count after read
+ * 'r' show read offset and size
+ * 't' trace function entry and exit
+ * 'w' show write offset and size
+ */
+static int H5FD_mpio_Debug[256] =
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+#endif
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5FD__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5FD__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines. (Just calls
+ H5FD_mpio_init currently).
+
+--------------------------------------------------------------------------*/
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_mpio_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize mpio VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the mpio driver.
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 5, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_mpio_init(void)
+{
+#ifdef H5FDmpio_DEBUG
+ static int H5FD_mpio_Debug_inited = 0;
+#endif /* H5FDmpio_DEBUG */
+ const char *s; /* String for environment variables */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Register the MPI-IO VFD, if it isn't already */
+ if(H5I_VFL != H5I_get_type(H5FD_MPIO_g))
+ H5FD_MPIO_g = H5FD_register((const H5FD_class_t *)&H5FD_mpio_g, sizeof(H5FD_class_mpi_t), FALSE);
+
+ /* Allow MPI buf-and-file-type optimizations? */
+ s = HDgetenv("HDF5_MPI_OPT_TYPES");
+ if(s && HDisdigit(*s))
+ H5FD_mpi_opt_types_g = (hbool_t)HDstrtol(s, NULL, 0);
+
+#ifdef H5FDmpio_DEBUG
+ if(!H5FD_mpio_Debug_inited) {
+ /* Retrieve MPI-IO debugging environment variable */
+ s = HDgetenv("H5FD_mpio_Debug");
+ if(s) {
+ /* Set debug mask */
+ while(*s) {
+ H5FD_mpio_Debug[(int)*s]++;
+ s++;
+ } /* end while */
+ } /* end if */
+ H5FD_mpio_Debug_inited++;
+ } /* end if */
+#endif /* H5FDmpio_DEBUG */
+
+ /* Set return value */
+ ret_value = H5FD_MPIO_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_mpio_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: Non-negative on success or negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_MPIO_g=0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_mpio_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_mpio
+ *
+ * Purpose: Store the user supplied MPIO communicator comm and info in
+ * the file access property list FAPL_ID which can then be used
+ * to create and/or open the file. This function is available
+ * only in the parallel HDF5 library and is not collective.
+ *
+ * comm is the MPI communicator to be used for file open as
+ * defined in MPI_FILE_OPEN of MPI-2. This function makes a
+ * duplicate of comm. Any modification to comm after this function
+ * call returns has no effect on the access property list.
+ *
+ * info is the MPI Info object to be used for file open as
+ * defined in MPI_FILE_OPEN of MPI-2. This function makes a
+ * duplicate of info. Any modification to info after this
+ * function call returns has no effect on the access property
+ * list.
+ *
+ * If fapl_id has previously set comm and info values, they
+ * will be replaced and the old communicator and Info object
+ * are freed.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Albert Cheng
+ * Feb 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_mpio(hid_t fapl_id, MPI_Comm comm, MPI_Info info)
+{
+ H5FD_mpio_fapl_t fa;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iMcMi", fapl_id, comm, info);
+
+ if(fapl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a file access list")
+ if(MPI_COMM_NULL == comm)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a valid communicator")
+
+ /* Initialize driver specific properties */
+ fa.comm = comm;
+ fa.info = info;
+
+ /* duplication is done during driver setting. */
+ ret_value = H5P_set_driver(plist, H5FD_MPIO, &fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_fapl_mpio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_mpio
+ *
+ * Purpose: If the file access property list is set to the H5FD_MPIO
+ * driver then this function returns duplicates of the MPI
+ * communicator and Info object stored through the comm and
+ * info pointers. It is the responsibility of the application
+ * to free the returned communicator and Info object.
+ *
+ * Return: Success: Non-negative with the communicator and
+ * Info object returned through the comm and
+ * info arguments if non-null. Since they are
+ * duplicates of the stored objects, future
+ * modifications to the access property list do
+ * not affect them and it is the responsibility
+ * of the application to free them.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 26, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_mpio(hid_t fapl_id, MPI_Comm *comm/*out*/, MPI_Info *info/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5FD_mpio_fapl_t *fa; /* MPIO fapl info */
+ MPI_Comm comm_tmp = MPI_COMM_NULL;
+ hbool_t comm_copied = FALSE; /* MPI Comm has been duplicated */
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", fapl_id, comm, info);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a file access list")
+ if(H5FD_MPIO != H5P_peek_driver(plist))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ if(NULL == (fa = (const H5FD_mpio_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+
+ /* Store the duplicated communicator in a temporary variable for error */
+ /* recovery in case the INFO duplication fails. */
+ if(comm) {
+ if(MPI_SUCCESS != (mpi_code = MPI_Comm_dup(fa->comm, &comm_tmp)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Comm_dup failed", mpi_code)
+ comm_copied = TRUE;
+ } /* end if */
+
+ if(info) {
+ if(MPI_INFO_NULL != fa->info) {
+ if(MPI_SUCCESS != (mpi_code = MPI_Info_dup(fa->info, info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Info_dup failed", mpi_code)
+ } /* end if */
+ else
+ /* do not dup it */
+ *info = MPI_INFO_NULL;
+ } /* end if */
+
+ /* Store the copied communicator, now that the Info object has been
+ * successfully copied.
+ */
+ if(comm)
+ *comm = comm_tmp;
+
+done:
+ if(ret_value < 0)
+ /* need to free anything created here */
+ if(comm_copied)
+ MPI_Comm_free(&comm_tmp);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fapl_mpio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_mpio
+ *
+ * Purpose: Set the data transfer property list DXPL_ID to use transfer
+ * mode XFER_MODE. The property list can then be used to control
+ * the I/O transfer mode during data I/O operations. The valid
+ * transfer modes are:
+ *
+ * H5FD_MPIO_INDEPENDENT:
+ * Use independent I/O access (the default).
+ *
+ * H5FD_MPIO_COLLECTIVE:
+ * Use collective I/O access.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Albert Cheng
+ * April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t xfer_mode)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDt", dxpl_id, xfer_mode);
+
+ if(dxpl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+ if(H5FD_MPIO_INDEPENDENT != xfer_mode && H5FD_MPIO_COLLECTIVE != xfer_mode)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "incorrect xfer_mode")
+
+ /* Set the transfer mode */
+ if(H5P_set(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_dxpl_mpio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_dxpl_mpio
+ *
+ * Purpose: Queries the transfer mode current set in the data transfer
+ * property list DXPL_ID. This is not collective.
+ *
+ * Return: Success: Non-negative, with the transfer mode returned
+ * through the XFER_MODE argument if it is
+ * non-null.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Albert Cheng
+ * April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t *xfer_mode/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", dxpl_id, xfer_mode);
+
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+
+ /* Get the transfer mode */
+ if(xfer_mode)
+ if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, xfer_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_dxpl_mpio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_mpio_collective_opt
+ *
+ * Purpose: To set a flag to choose linked chunk I/O or multi-chunk I/O
+ * without involving decision-making inside HDF5
+ *
+ * Note: The library will do linked chunk I/O or multi-chunk I/O without
+ * involving communications for decision-making process.
+ * The library won't behave as it asks for only when we find
+ * that the low-level MPI-IO package doesn't support this.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Kent Yang
+ * ? ?, ?
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_mpio_collective_opt(hid_t dxpl_id, H5FD_mpio_collective_opt_t opt_mode)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDc", dxpl_id, opt_mode);
+
+ if(dxpl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+
+ /* Set the transfer mode */
+ if(H5P_set(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_dxpl_mpio_collective_opt() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_mpio_chunk_opt
+ *
+ * Purpose: To set a flag to choose linked chunk I/O or multi-chunk I/O
+ * without involving decision-making inside HDF5
+ *
+ * Note: The library will do linked chunk I/O or multi-chunk I/O without
+ * involving communications for decision-making process.
+ * The library won't behave as it asks for only when we find
+ * that the low-level MPI-IO package doesn't support this.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Kent Yang
+ * ? ?, ?
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_mpio_chunk_opt(hid_t dxpl_id, H5FD_mpio_chunk_opt_t opt_mode)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDh", dxpl_id, opt_mode);
+
+ if(dxpl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+
+ /* Set the transfer mode */
+ if(H5P_set(plist, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME, &opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_dxpl_mpio_chunk_opt() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_mpio_chunk_opt_num
+ *
+ * Purpose: To set a threshold for doing linked chunk IO
+ *
+ * Note: If the number is greater than the threshold set by the user,
+ * the library will do linked chunk I/O; otherwise, I/O will be
+ * done for every chunk.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Kent Yang
+ * ? ?, ?
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_mpio_chunk_opt_num(hid_t dxpl_id, unsigned num_chunk_per_proc)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", dxpl_id, num_chunk_per_proc);
+
+ if(dxpl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+
+ /* Set the transfer mode */
+ if(H5P_set(plist, H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME, &num_chunk_per_proc) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_dxpl_mpio_chunk_opt_num() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_mpio_chunk_opt_ratio
+ *
+ * Purpose: To set a threshold for doing collective I/O for each chunk
+ *
+ * Note: The library will calculate the percentage of the number of
+ * process holding selections at each chunk. If that percentage
+ * of number of process in the individual chunk is greater than
+ * the threshold set by the user, the library will do collective
+ * chunk I/O for this chunk; otherwise, independent I/O will be
+ * done for this chunk.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Kent Yang
+ * ? ?, ?
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_mpio_chunk_opt_ratio(hid_t dxpl_id, unsigned percent_num_proc_per_chunk)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", dxpl_id, percent_num_proc_per_chunk);
+
+ if(dxpl_id == H5P_DEFAULT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't set values in default property list")
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl")
+
+ /* Set the transfer mode */
+ if(H5P_set(plist, H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME, &percent_num_proc_per_chunk) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_dxpl_mpio_chunk_opt_ratio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_fapl_get
+ *
+ * Purpose: Returns a file access property list which could be used to
+ * create another file the same as this one.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * fields copied from the file pointer.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_mpio_fapl_get(H5FD_t *_file)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ H5FD_mpio_fapl_t *fa = NULL;
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+ HDassert(H5FD_MPIO == file->pub.driver_id);
+
+ if(NULL == (fa = (H5FD_mpio_fapl_t *)H5MM_calloc(sizeof(H5FD_mpio_fapl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Duplicate communicator and Info object. */
+ if(FAIL == H5FD_mpi_comm_info_dup(file->comm, file->info, &fa->comm, &fa->info))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "Communicator/Info duplicate failed")
+
+ /* Set return value */
+ ret_value = fa;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_fapl_copy
+ *
+ * Purpose: Copies the mpio-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Albert Cheng
+ * Jan 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_mpio_fapl_copy(const void *_old_fa)
+{
+ void *ret_value = NULL;
+ const H5FD_mpio_fapl_t *old_fa = (const H5FD_mpio_fapl_t*)_old_fa;
+ H5FD_mpio_fapl_t *new_fa = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef H5FDmpio_DEBUG
+if (H5FD_mpio_Debug[(int)'t'])
+fprintf(stderr, "enter H5FD_mpio_fapl_copy\n");
+#endif
+
+ if(NULL == (new_fa = (H5FD_mpio_fapl_t *)H5MM_malloc(sizeof(H5FD_mpio_fapl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the general information */
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_mpio_fapl_t));
+
+ /* Duplicate communicator and Info object. */
+ if(FAIL == H5FD_mpi_comm_info_dup(old_fa->comm, old_fa->info, &new_fa->comm, &new_fa->info))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "Communicator/Info duplicate failed")
+ ret_value = new_fa;
+
+done:
+ if (NULL == ret_value){
+ /* cleanup */
+ if (new_fa)
+ H5MM_xfree(new_fa);
+ }
+
+#ifdef H5FDmpio_DEBUG
+if (H5FD_mpio_Debug[(int)'t'])
+fprintf(stderr, "leaving H5FD_mpio_fapl_copy\n");
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_fapl_free
+ *
+ * Purpose: Frees the mpio-specific file access properties.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Albert Cheng
+ * Jan 8, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_fapl_free(void *_fa)
+{
+ herr_t ret_value = SUCCEED;
+ H5FD_mpio_fapl_t *fa = (H5FD_mpio_fapl_t*)_fa;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+#ifdef H5FDmpio_DEBUG
+if (H5FD_mpio_Debug[(int)'t'])
+fprintf(stderr, "in H5FD_mpio_fapl_free\n");
+#endif
+ HDassert(fa);
+
+ /* Free the internal communicator and INFO object */
+ HDassert(MPI_COMM_NULL!=fa->comm);
+ H5FD_mpi_comm_info_free(&fa->comm, &fa->info);
+ H5MM_xfree(fa);
+
+#ifdef H5FDmpio_DEBUG
+if (H5FD_mpio_Debug[(int)'t'])
+fprintf(stderr, "leaving H5FD_mpio_fapl_free\n");
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_fapl_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_set_mpio_atomicity
+ *
+ * Purpose: Sets the atomicity mode
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Feb 14, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_set_mpio_atomicity(H5FD_t *_file, hbool_t flag)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ int mpi_code; /* MPI return code */
+ int temp_flag;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Entering H5FD_set_mpio_atomicity\n");
+#endif
+
+ if (FALSE == flag)
+ temp_flag = 0;
+ else
+ temp_flag = 1;
+
+ /* set atomicity value */
+ if (MPI_SUCCESS != (mpi_code=MPI_File_set_atomicity(file->f, temp_flag)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_atomicity", mpi_code)
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Leaving H5FD_set_mpio_atomicity\n");
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_get_mpio_atomicity
+ *
+ * Purpose: Returns the atomicity mode
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Feb 14, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_get_mpio_atomicity(H5FD_t *_file, hbool_t *flag)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ int mpi_code; /* MPI return code */
+ int temp_flag;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Entering H5FD_get_mpio_atomicity\n");
+#endif
+
+ /* get atomicity value */
+ if (MPI_SUCCESS != (mpi_code=MPI_File_get_atomicity(file->f, &temp_flag)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_get_atomicity", mpi_code)
+
+ if (0 != temp_flag)
+ *flag = TRUE;
+ else
+ *flag = FALSE;
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Leaving H5FD_get_mpio_atomicity\n");
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_open
+ *
+ * Purpose: Opens a file with name NAME. The FLAGS are a bit field with
+ * purpose similar to the second argument of open(2) and which
+ * are defined in H5Fpublic.h. The file access property list
+ * FAPL_ID contains the properties driver properties and MAXADDR
+ * is the largest address which this file will be expected to
+ * access. This is collective.
+ *
+ * Return: Success: A new file pointer.
+ *
+ * Failure: NULL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_mpio_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t H5_ATTR_UNUSED maxaddr)
+{
+ H5FD_mpio_t *file=NULL;
+ MPI_File fh;
+ unsigned file_opened=0; /* Flag to indicate that the file was successfully opened */
+ int mpi_amode;
+ int mpi_rank; /* MPI rank of this process */
+ int mpi_size; /* Total number of MPI processes */
+ int mpi_code; /* mpi return code */
+ MPI_Offset size;
+ const H5FD_mpio_fapl_t *fa = NULL;
+ H5FD_mpio_fapl_t _fa;
+ H5P_genplist_t *plist; /* Property list pointer */
+ MPI_Comm comm_dup = MPI_COMM_NULL;
+ MPI_Info info_dup = MPI_INFO_NULL;
+ H5FD_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t']) {
+ fprintf(stdout, "Entering H5FD_mpio_open(name=\"%s\", flags=0x%x, "
+ "fapl_id=%d, maxaddr=%lu)\n", name, flags, (int)fapl_id, (unsigned long)maxaddr);
+ }
+#endif
+
+ /* Obtain a pointer to mpio-specific file access properties */
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ if(H5P_FILE_ACCESS_DEFAULT == fapl_id || H5FD_MPIO != H5P_peek_driver(plist)) {
+ _fa.comm = MPI_COMM_SELF; /*default*/
+ _fa.info = MPI_INFO_NULL; /*default*/
+ fa = &_fa;
+ } /* end if */
+ else {
+ if(NULL == (fa = (const H5FD_mpio_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
+ } /* end else */
+
+ /* Duplicate communicator and Info object for use by this file. */
+ if(FAIL == H5FD_mpi_comm_info_dup(fa->comm, fa->info, &comm_dup, &info_dup))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "Communicator/Info duplicate failed")
+
+ /* convert HDF5 flags to MPI-IO flags */
+ /* some combinations are illegal; let MPI-IO figure it out */
+ mpi_amode = (flags & H5F_ACC_RDWR) ? MPI_MODE_RDWR : MPI_MODE_RDONLY;
+ if(flags & H5F_ACC_CREAT)
+ mpi_amode |= MPI_MODE_CREATE;
+ if(flags & H5F_ACC_EXCL)
+ mpi_amode |= MPI_MODE_EXCL;
+
+#ifdef H5FDmpio_DEBUG
+ /* Check for debug commands in the info parameter */
+ {
+ if(MPI_INFO_NULL != info_dup) {
+ char debug_str[128];
+ int flag;
+
+ MPI_Info_get(fa->info, H5F_MPIO_DEBUG_KEY, sizeof(debug_str) - 1, debug_str, &flag);
+ if(flag) {
+ int i;
+
+ fprintf(stdout, "H5FD_mpio debug flags = '%s'\n", debug_str);
+ for(i = 0; debug_str[i]/*end of string*/ && i < 128/*just in case*/; ++i)
+ H5FD_mpio_Debug[(int)debug_str[i]] = 1;
+ }
+ }
+ }
+#endif
+
+ if(MPI_SUCCESS != (mpi_code = MPI_File_open(comm_dup, name, mpi_amode, info_dup, &fh)))
+ HMPI_GOTO_ERROR(NULL, "MPI_File_open failed", mpi_code)
+ file_opened=1;
+
+ /* Get the MPI rank of this process and the total number of processes */
+ if (MPI_SUCCESS != (mpi_code=MPI_Comm_rank (comm_dup, &mpi_rank)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Comm_rank failed", mpi_code)
+ if (MPI_SUCCESS != (mpi_code=MPI_Comm_size (comm_dup, &mpi_size)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Comm_size failed", mpi_code)
+
+ /* Build the return value and initialize it */
+ if(NULL == (file = (H5FD_mpio_t *)H5MM_calloc(sizeof(H5FD_mpio_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ file->f = fh;
+ file->comm = comm_dup;
+ file->info = info_dup;
+ file->mpi_rank = mpi_rank;
+ file->mpi_size = mpi_size;
+
+ /* Only processor p0 will get the filesize and broadcast it. */
+ if (mpi_rank == 0) {
+ if (MPI_SUCCESS != (mpi_code=MPI_File_get_size(fh, &size)))
+ HMPI_GOTO_ERROR(NULL, "MPI_File_get_size failed", mpi_code)
+ } /* end if */
+
+ /* Broadcast file size */
+ if(MPI_SUCCESS != (mpi_code = MPI_Bcast(&size, (int)sizeof(MPI_Offset), MPI_BYTE, 0, comm_dup)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code)
+
+ /* Determine if the file should be truncated */
+ if(size && (flags & H5F_ACC_TRUNC)) {
+ if (MPI_SUCCESS != (mpi_code=MPI_File_set_size(fh, (MPI_Offset)0)))
+ HMPI_GOTO_ERROR(NULL, "MPI_File_set_size failed", mpi_code)
+
+ /* Don't let any proc return until all have truncated the file. */
+ if (MPI_SUCCESS!= (mpi_code=MPI_Barrier(comm_dup)))
+ HMPI_GOTO_ERROR(NULL, "MPI_Barrier failed", mpi_code)
+
+ /* File is zero size now */
+ size = 0;
+ } /* end if */
+
+ /* Set the size of the file (from library's perspective) */
+ file->eof = H5FD_mpi_MPIOff_to_haddr(size);
+ file->local_eof = file->eof;
+
+ /* Set return value */
+ ret_value=(H5FD_t*)file;
+
+done:
+ if(ret_value==NULL) {
+ if(file_opened)
+ MPI_File_close(&fh);
+ if (MPI_COMM_NULL != comm_dup)
+ MPI_Comm_free(&comm_dup);
+ if (MPI_INFO_NULL != info_dup)
+ MPI_Info_free(&info_dup);
+ if (file)
+ H5MM_xfree(file);
+ } /* end if */
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Leaving H5FD_mpio_open\n" );
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_close
+ *
+ * Purpose: Closes a file. This is collective.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Unknown
+ * January 30, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1998-02-18
+ * Added the ACCESS_PARMS argument.
+ *
+ * Robb Matzke, 1999-08-06
+ * Modified to work with the virtual file layer.
+ *
+ * Albert Cheng, 2003-04-17
+ * Free the communicator stored.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_close(H5FD_t *_file)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ int mpi_code; /* MPI return code */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Entering H5FD_mpio_close\n");
+#endif
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ /* MPI_File_close sets argument to MPI_FILE_NULL */
+ if (MPI_SUCCESS != (mpi_code=MPI_File_close(&(file->f)/*in,out*/)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_close failed", mpi_code)
+
+ /* Clean up other stuff */
+ H5FD_mpi_comm_info_free(&file->comm, &file->info);
+ H5MM_xfree(file);
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Leaving H5FD_mpio_close\n");
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ * Modifications:
+ *
+ * John Mainzer -- 9/21/05
+ * Modified code to turn off the
+ * H5FD_FEAT_ACCUMULATE_METADATA_WRITE flag.
+ * With the movement of
+ * all cache writes to process 0, this flag has become
+ * problematic in PHDF5.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_query(const H5FD_t H5_ATTR_UNUSED *_file, unsigned long *flags /* out */)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags=0;
+ *flags|=H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags|=H5FD_FEAT_HAS_MPI; /* This driver uses MPI */
+ *flags|=H5FD_FEAT_ALLOCATE_EARLY; /* Allocate space early instead of late */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: Success: The end-of-address marker.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 6, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_mpio_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_mpio_t *file = (const H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 6, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ file->eoa = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_get_eof
+ *
+ * Purpose: Gets the end-of-file marker for the file. The EOF marker
+ * is the real size of the file.
+ *
+ * The MPIO driver doesn't bother keeping this field updated
+ * since that's a relatively expensive operation. Fortunately
+ * the library only needs the EOF just after the file is opened
+ * in order to determine whether the file is empty, truncated,
+ * or okay. Therefore, any MPIO I/O function will set its value
+ * to HADDR_UNDEF which is the error return value of this
+ * function.
+ *
+ * Keeping the EOF updated (during write calls) is expensive
+ * because any process may extend the physical end of the
+ * file. -QAK
+ *
+ * Return: Success: The end-of-address marker.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 6, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_mpio_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_mpio_t *file = (const H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ FUNC_LEAVE_NOAPI(file->eof)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_get_handle
+ *
+ * Purpose: Returns the file handle of MPIO file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+*/
+static herr_t
+H5FD_mpio_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void** file_handle)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+
+ *file_handle = &(file->f);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_get_info
+ *
+ * Purpose: Returns the file info of MPIO file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: John Mainzer
+ * April 4, 2017
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+*/
+static herr_t
+H5FD_mpio_get_info(H5FD_t *_file, void** mpi_info)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!mpi_info)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mpi info not valid")
+
+ *mpi_info = &(file->info);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5FD_mpio_get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID using potentially complex file and buffer types to
+ * effect the transfer.
+ *
+ * Reading past the end of the MPI file returns zeros instead of
+ * failing. MPI is able to coalesce requests from different
+ * processes (collective or independent).
+ *
+ * Return: Success: Zero. Result is stored in caller-supplied
+ * buffer BUF.
+ *
+ * Failure: -1, Contents of buffer BUF are undefined.
+ *
+ * Programmer: rky, 1998-01-30
+ *
+ * Modifications:
+ * Robb Matzke, 1998-02-18
+ * Added the ACCESS_PARMS argument.
+ *
+ * rky, 1998-04-10
+ * Call independent or collective MPI read, based on
+ * ACCESS_PARMS.
+ *
+ * Albert Cheng, 1998-06-01
+ * Added XFER_MODE to control independent or collective MPI
+ * read.
+ *
+ * rky, 1998-08-16
+ * Use BTYPE, FTYPE, and DISP from access parms. The guts of
+ * H5FD_mpio_read and H5FD_mpio_write should be replaced by a
+ * single dual-purpose routine.
+ *
+ * Robb Matzke, 1999-04-21
+ * Changed XFER_MODE to XFER_PARMS for all H5F_*_read()
+ * callbacks.
+ *
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *
+ * Robb Matzke, 1999-08-06
+ * Modified to work with the virtual file layer.
+ *
+ * Quincey Koziol, 2002-05-14
+ * Only call MPI_Get_count if we can use MPI_BYTE for the MPI type
+ * for the I/O transfer. Someday we might include code to decode
+ * the MPI type used for more complicated transfers and call
+ * MPI_Get_count all the time.
+ *
+ * Quincey Koziol - 2002/06/17
+ * Removed 'disp' parameter from H5FD_mpio_setup routine and use
+ * the address of the dataset in MPI_File_set_view() calls, as
+ * necessary.
+ *
+ * Quincey Koziol - 2002/06/24
+ * Removed "lazy" MPI_File_set_view() calls, since they would fail
+ * if the first I/O was a collective I/O using MPI derived types
+ * and the next I/O was an independent I/O.
+ *
+ * Quincey Koziol - 2003/10/22-31
+ * Restructured code massively, straightening out logic and finally
+ * getting the bytes_read stuff working.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t dxpl_id, haddr_t addr, size_t size,
+ void *buf/*out*/)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ MPI_Offset mpi_off;
+ MPI_Status mpi_stat; /* Status from I/O operation */
+ int mpi_code; /* mpi return code */
+ MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */
+ int size_i; /* Integer copy of 'size' to read */
+#if MPI_VERSION >= 3
+ MPI_Count bytes_read; /* Number of bytes read in */
+ MPI_Count type_size; /* MPI datatype used for I/O's size */
+ MPI_Count io_size; /* Actual number of bytes requested */
+ MPI_Count n;
+#else
+ int bytes_read; /* Number of bytes read in */
+ int type_size; /* MPI datatype used for I/O's size */
+ int io_size; /* Actual number of bytes requested */
+ int n;
+#endif
+ H5P_genplist_t *plist = NULL; /* Property list pointer */
+ hbool_t use_view_this_time = FALSE;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Entering H5FD_mpio_read\n" );
+#endif
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+ /* Make certain we have the correct type of property list */
+ HDassert(H5I_GENPROP_LST==H5I_get_type(dxpl_id));
+ HDassert(TRUE==H5P_isa_class(dxpl_id,H5P_DATASET_XFER));
+ HDassert(buf);
+
+ /* Portably initialize MPI status variable */
+ HDmemset(&mpi_stat,0,sizeof(MPI_Status));
+
+ /* some numeric conversions */
+ if (H5FD_mpi_haddr_to_MPIOff(addr, &mpi_off/*out*/)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off")
+ size_i = (int)size;
+ if ((hsize_t)size_i != size)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from size to size_i")
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'r'])
+ fprintf(stdout, "in H5FD_mpio_read mpi_off=%ld size_i=%d\n",
+ (long)mpi_off, size_i );
+#endif
+
+ /* Only look for MPI views for raw data transfers */
+ if(type == H5FD_MEM_DRAW) {
+ H5FD_mpio_xfer_t xfer_mode; /* I/O tranfer mode */
+
+ /* Obtain the data transfer properties */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* get the transfer mode from the dxpl */
+ if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+
+ /*
+ * Set up for a fancy xfer using complex types, or single byte block. We
+ * wouldn't need to rely on the use_view field if MPI semantics allowed
+ * us to test that btype=ftype=MPI_BYTE (or even MPI_TYPE_NULL, which
+ * could mean "use MPI_BYTE" by convention).
+ */
+ if(xfer_mode==H5FD_MPIO_COLLECTIVE) {
+ MPI_Datatype file_type;
+
+ /* Remember that views are used */
+ use_view_this_time = TRUE;
+
+ /* prepare for a full-blown xfer using btype, ftype, and disp */
+ if(H5P_get(plist, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, &buf_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property")
+ if(H5P_get(plist, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, &file_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property")
+
+ /*
+ * Set the file view when we are using MPI derived types
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type, H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* When using types, use the address as the displacement for
+ * MPI_File_set_view and reset the address for the read to zero
+ */
+ mpi_off = 0;
+ } /* end if */
+ } /* end if */
+
+ /* Read the data. */
+ if(use_view_this_time) {
+ H5FD_mpio_collective_opt_t coll_opt_mode;
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n");
+#endif
+ /* Get the collective_opt property to check whether the application wants to do IO individually. */
+ HDassert(plist);
+
+ /* get the transfer mode from the dxpl */
+ if(H5P_get(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &coll_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_op property")
+
+ if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) {
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n");
+#endif
+ if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code)
+ } /* end if */
+ else {
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_read: doing MPI independent IO\n");
+#endif
+
+ if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code)
+ } /* end else */
+
+ /*
+ * Reset the file view when we used MPI derived types
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, (MPI_Offset)0, MPI_BYTE, MPI_BYTE, H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+ } else {
+ if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code)
+ }
+
+ /* How many bytes were actually read? */
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read)))
+#else
+ if (MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code)
+
+ /* Get the type's size */
+#if MPI_VERSION >= 3
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size)))
+#else
+ if (MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code)
+
+ /* Compute the actual number of bytes requested */
+ io_size=type_size*size_i;
+
+ /* Check for read failure */
+ if (bytes_read<0 || bytes_read>io_size)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
+
+ /*
+ * This gives us zeroes beyond end of physical MPI file.
+ */
+ if ((n=(io_size-bytes_read)) > 0)
+ HDmemset((char*)buf+bytes_read, 0, (size_t)n);
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Leaving H5FD_mpio_read\n" );
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID using potentially complex file and buffer types to
+ * effect the transfer.
+ *
+ * MPI is able to coalesce requests from different processes
+ * (collective and independent).
+ *
+ * Return: Success: Zero. USE_TYPES and OLD_USE_TYPES in the
+ * access params are altered.
+ *
+ * Failure: -1, USE_TYPES and OLD_USE_TYPES in the
+ * access params may be altered.
+ *
+ * Programmer: Unknown
+ * January 30, 1998
+ *
+ * Modifications:
+ * rky, 1998-08-28
+ * If the file->allsame flag is set, we assume that all the
+ * procs in the relevant MPI communicator will write identical
+ * data at identical offsets in the file, so only proc 0 will
+ * write, and all other procs will wait for p0 to finish. This
+ * is useful for writing metadata, for example. Note that we
+ * don't _check_ that the data is identical. Also, the mechanism
+ * we use to eliminate the redundant writes is by requiring a
+ * call to H5FD_mpio_tas_allsame before the write, which is
+ * rather klugey. Would it be better to pass a parameter to
+ * low-level writes like H5F_block_write and H5F_low_write,
+ * instead? Or...??? Also, when I created this mechanism I
+ * wanted to minimize the difference in behavior between the old
+ * way of doing things (i.e., all procs write) and the new way,
+ * so the writes are eliminated at the very lowest level, here
+ * in H5FD_mpio_write. It may be better to rethink that, and
+ * short-circuit the writes at a higher level (e.g., at the
+ * points in the code where H5FD_mpio_tas_allsame is called).
+ *
+ *
+ * Robb Matzke, 1998-02-18
+ * Added the ACCESS_PARMS argument.
+ *
+ * rky, 1998-04-10
+ * Call independent or collective MPI write, based on
+ * ACCESS_PARMS.
+ *
+ * rky, 1998-04-24
+ * Removed redundant write from H5FD_mpio_write.
+ *
+ * Albert Cheng, 1998-06-01
+ * Added XFER_MODE to control independent or collective MPI
+ * write.
+ *
+ * rky, 1998-08-16
+ * Use BTYPE, FTYPE, and DISP from access parms. The guts of
+ * H5FD_mpio_read and H5FD_mpio_write should be replaced by a
+ * single dual-purpose routine.
+ *
+ * rky, 1998-08-28
+ * Added ALLSAME parameter to make all but proc 0 skip the
+ * actual write.
+ *
+ * Robb Matzke, 1999-04-21
+ * Changed XFER_MODE to XFER_PARMS for all H5FD_*_write()
+ * callbacks.
+ *
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *
+ * Robb Matzke, 1999-08-06
+ * Modified to work with the virtual file layer.
+ *
+ * Albert Cheng, 1999-12-19
+ * When only-p0-write-allsame-data, p0 Bcasts the
+ * ret_value to other processes. This prevents
+ * a racing condition (that other processes try to
+ * read the file before p0 finishes writing) and also
+ * allows all processes to report the same ret_value.
+ *
+ * Kim Yates, Pat Weidhaas, 2000-09-26
+ * Move block of coding where only p0 writes after the
+ * MPI_File_set_view call.
+ *
+ * Quincey Koziol, 2002-05-10
+ * Instead of always writing metadata from process 0, spread the
+ * burden among all the processes by using a round-robin rotation
+ * scheme.
+ *
+ * Quincey Koziol, 2002-05-10
+ * Removed allsame code, keying off the type parameter instead.
+ *
+ * Quincey Koziol, 2002-05-14
+ * Only call MPI_Get_count if we can use MPI_BYTE for the MPI type
+ * for the I/O transfer. Someday we might include code to decode
+ * the MPI type used for more complicated transfers and call
+ * MPI_Get_count all the time.
+ *
+ * Quincey Koziol - 2002/06/17
+ * Removed 'disp' parameter from H5FD_mpio_setup routine and use
+ * the address of the dataset in MPI_File_set_view() calls, as
+ * necessary.
+ *
+ * Quincey Koziol - 2002/06/24
+ * Removed "lazy" MPI_File_set_view() calls, since they would fail
+ * if the first I/O was a collective I/O using MPI derived types
+ * and the next I/O was an independent I/O.
+ *
+ * Quincey Koziol - 2002/07/18
+ * Added "block_before_meta_write" dataset transfer flag, which
+ * is set during writes from a metadata cache flush and indicates
+ * that all the processes must sync up before (one of them)
+ * writing metadata.
+ *
+ * Quincey Koziol - 2003/10/22-31
+ * Restructured code massively, straightening out logic and finally
+ * getting the bytes_written stuff working.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ MPI_Offset mpi_off;
+ MPI_Status mpi_stat; /* Status from I/O operation */
+ MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */
+ int mpi_code; /* MPI return code */
+#if MPI_VERSION >= 3
+ MPI_Count bytes_written;
+ MPI_Count type_size; /* MPI datatype used for I/O's size */
+ MPI_Count io_size; /* Actual number of bytes requested */
+#else
+ int bytes_written;
+ int type_size; /* MPI datatype used for I/O's size */
+ int io_size; /* Actual number of bytes requested */
+#endif
+ int size_i;
+ hbool_t use_view_this_time = FALSE;
+ H5P_genplist_t *plist = NULL; /* Property list pointer */
+ H5FD_mpio_xfer_t xfer_mode; /* I/O tranfer mode */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if (H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "Entering H5FD_mpio_write\n" );
+#endif
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+ /* Make certain we have the correct type of property list */
+ HDassert(H5I_GENPROP_LST==H5I_get_type(dxpl_id));
+ HDassert(TRUE==H5P_isa_class(dxpl_id,H5P_DATASET_XFER));
+ HDassert(buf);
+
+ /* Portably initialize MPI status variable */
+ HDmemset(&mpi_stat, 0, sizeof(MPI_Status));
+
+ /* some numeric conversions */
+ if(H5FD_mpi_haddr_to_MPIOff(addr, &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off")
+ size_i = (int)size;
+ if((hsize_t)size_i != size)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from size to size_i")
+
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'w'])
+ fprintf(stdout, "in H5FD_mpio_write mpi_off=%ld size_i=%d\n", (long)mpi_off, size_i);
+#endif
+
+ /* Obtain the data transfer properties */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ /* get the transfer mode from the dxpl */
+ if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")
+
+ /*
+ * Set up for a fancy xfer using complex types, or single byte block. We
+ * wouldn't need to rely on the use_view field if MPI semantics allowed
+ * us to test that btype=ftype=MPI_BYTE (or even MPI_TYPE_NULL, which
+ * could mean "use MPI_BYTE" by convention).
+ */
+ if(xfer_mode == H5FD_MPIO_COLLECTIVE) {
+ MPI_Datatype file_type;
+
+ /* Remember that views are used */
+ use_view_this_time = TRUE;
+
+ /* prepare for a full-blown xfer using btype, ftype, and disp */
+ if(H5P_get(plist, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, &buf_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property")
+ if(H5P_get(plist, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, &file_type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O type property")
+
+ /*
+ * Set the file view when we are using MPI derived types
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, mpi_off, MPI_BYTE, file_type, H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+
+ /* When using types, use the address as the displacement for
+ * MPI_File_set_view and reset the address for the read to zero
+ */
+ mpi_off = 0;
+ } /* end if */
+
+ /* Write the data. */
+ if(use_view_this_time) {
+ H5FD_mpio_collective_opt_t coll_opt_mode;
+
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_write: using MPIO collective mode\n");
+#endif
+
+ /* Get the collective_opt property to check whether the application wants to do IO individually. */
+ HDassert(plist);
+ /* get the transfer mode from the dxpl */
+ if(H5P_get(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, &coll_opt_mode)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get MPI-I/O collective_op property")
+
+ if(coll_opt_mode == H5FD_MPIO_COLLECTIVE_IO) {
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_write: doing MPI collective IO\n");
+#endif
+ if(MPI_SUCCESS != (mpi_code = MPI_File_write_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code)
+ } /* end if */
+ else {
+ if(type != H5FD_MEM_DRAW)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "Metadata Coll opt property should be collective at this point")
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "H5FD_mpio_write: doing MPI independent IO\n");
+#endif
+ if(MPI_SUCCESS != (mpi_code = MPI_File_write_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code)
+ } /* end else */
+
+ /* Reset the file view when we used MPI derived types */
+ if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(file->f, (MPI_Offset)0, MPI_BYTE, MPI_BYTE, H5FD_mpi_native_g, file->info)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code)
+ } else {
+ if(MPI_SUCCESS != (mpi_code = MPI_File_write_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at failed", mpi_code)
+ }
+
+ /* How many bytes were actually written? */
+#if MPI_VERSION >= 3
+ if(MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_written)))
+#else
+ if(MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_written)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code)
+
+ /* Get the type's size */
+#if MPI_VERSION >= 3
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size)))
+#else
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size)))
+#endif
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code)
+
+ /* Compute the actual number of bytes requested */
+ io_size = type_size * size_i;
+
+ /* Check for write failure */
+ if(bytes_written != io_size)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Each process will keep track of its perceived EOF value locally, and
+ * ultimately we will reduce this value to the maximum amongst all
+ * processes, but until then keep the actual eof at HADDR_UNDEF just in
+ * case something bad happens before that point. (rather have a value
+ * we know is wrong sitting around rather than one that could only
+ * potentially be wrong.) */
+ file->eof = HADDR_UNDEF;
+
+ if(bytes_written && ((bytes_written + addr) > file->local_eof))
+ file->local_eof = addr + bytes_written;
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ fprintf(stdout, "proc %d: Leaving H5FD_mpio_write with ret_value=%d\n",
+ file->mpi_rank, ret_value );
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_flush
+ *
+ * Purpose: Makes sure that all data is on disk. This is collective.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * January 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t closing)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ int mpi_code; /* mpi return code */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ HDfprintf(stdout, "Entering %s\n", FUNC);
+#endif
+ HDassert(file);
+ HDassert(H5FD_MPIO == file->pub.driver_id);
+
+ /* Only sync the file if we are not going to immediately close it */
+ if(!closing) {
+ if(MPI_SUCCESS != (mpi_code = MPI_File_sync(file->f)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_sync failed", mpi_code)
+ } /* end if */
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ HDfprintf(stdout, "Leaving %s\n", FUNC);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_truncate
+ *
+ * Purpose: Make certain the file's size matches it's allocated size
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * January 31, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mpio_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_mpio_t *file = (H5FD_mpio_t*)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ HDfprintf(stdout, "Entering %s\n", FUNC);
+#endif
+ HDassert(file);
+ HDassert(H5FD_MPIO == file->pub.driver_id);
+
+ /* Extend the file to make sure it's large enough, then sync.
+ * Unfortunately, keeping track of EOF is an expensive operation, so
+ * we can't just check whether EOF<EOA like with other drivers.
+ * Therefore we'll just read the byte at EOA-1 and then write it back. */
+ if(file->eoa > file->last_eoa) {
+ int mpi_code; /* mpi return code */
+ MPI_Offset mpi_off;
+
+ if(H5FD_mpi_haddr_to_MPIOff(file->eoa, &mpi_off) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "cannot convert from haddr_t to MPI_Offset")
+
+ /* Extend the file's size */
+ if(MPI_SUCCESS != (mpi_code = MPI_File_set_size(file->f, mpi_off)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_File_set_size failed", mpi_code)
+
+ /* Don't let any proc return until all have extended the file.
+ * (Prevents race condition where some processes go ahead and write
+ * more data to the file before all the processes have finished making
+ * it the shorter length, potentially truncating the file and dropping
+ * the new data written)
+ */
+ if(MPI_SUCCESS != (mpi_code = MPI_Barrier(file->comm)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
+
+ /* Update the 'last' eoa value */
+ file->last_eoa = file->eoa;
+ } /* end if */
+
+done:
+#ifdef H5FDmpio_DEBUG
+ if(H5FD_mpio_Debug[(int)'t'])
+ HDfprintf(stdout, "Leaving %s\n", FUNC);
+#endif
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mpio_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_mpi_rank
+ *
+ * Purpose: Returns the MPI rank for a process
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 16, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_mpio_mpi_rank(const H5FD_t *_file)
+{
+ const H5FD_mpio_t *file = (const H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ FUNC_LEAVE_NOAPI(file->mpi_rank)
+} /* end H5FD_mpio_mpi_rank() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_mpi_size
+ *
+ * Purpose: Returns the number of MPI processes
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 16, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_mpio_mpi_size(const H5FD_t *_file)
+{
+ const H5FD_mpio_t *file = (const H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ FUNC_LEAVE_NOAPI(file->mpi_size)
+} /* end H5FD_mpio_mpi_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mpio_communicator
+ *
+ * Purpose: Returns the MPI communicator for the file.
+ *
+ * Return: Success: The communicator
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 9, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static MPI_Comm
+H5FD_mpio_communicator(const H5FD_t *_file)
+{
+ const H5FD_mpio_t *file = (const H5FD_mpio_t*)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+ HDassert(H5FD_MPIO==file->pub.driver_id);
+
+ FUNC_LEAVE_NOAPI(file->comm)
+} /* end H5FD_mpio_communicator() */
+
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5FDmpio.h b/src/H5FDmpio.h
new file mode 100644
index 0000000..6ee0a1a
--- /dev/null
+++ b/src/H5FDmpio.h
@@ -0,0 +1,64 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the mpio driver.
+ */
+#ifndef H5FDmpio_H
+#define H5FDmpio_H
+
+/* Macros */
+
+#ifdef H5_HAVE_PARALLEL
+# define H5FD_MPIO (H5FD_mpio_init())
+#else
+# define H5FD_MPIO (-1)
+#endif /* H5_HAVE_PARALLEL */
+
+#ifdef H5_HAVE_PARALLEL
+/*Turn on H5FDmpio_debug if H5F_DEBUG is on */
+#ifdef H5F_DEBUG
+#ifndef H5FDmpio_DEBUG
+#define H5FDmpio_DEBUG
+#endif
+#endif
+
+/* Global var whose value comes from environment variable */
+/* (Defined in H5FDmpio.c) */
+H5_DLLVAR hbool_t H5FD_mpi_opt_types_g;
+
+/* Function prototypes */
+#ifdef __cplusplus
+extern "C" {
+#endif
+H5_DLL hid_t H5FD_mpio_init(void);
+H5_DLL herr_t H5Pset_fapl_mpio(hid_t fapl_id, MPI_Comm comm, MPI_Info info);
+H5_DLL herr_t H5Pget_fapl_mpio(hid_t fapl_id, MPI_Comm *comm/*out*/,
+ MPI_Info *info/*out*/);
+H5_DLL herr_t H5Pset_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t xfer_mode);
+H5_DLL herr_t H5Pget_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t *xfer_mode/*out*/);
+H5_DLL herr_t H5Pset_dxpl_mpio_collective_opt(hid_t dxpl_id, H5FD_mpio_collective_opt_t opt_mode);
+H5_DLL herr_t H5Pset_dxpl_mpio_chunk_opt(hid_t dxpl_id, H5FD_mpio_chunk_opt_t opt_mode);
+H5_DLL herr_t H5Pset_dxpl_mpio_chunk_opt_num(hid_t dxpl_id, unsigned num_chunk_per_proc);
+H5_DLL herr_t H5Pset_dxpl_mpio_chunk_opt_ratio(hid_t dxpl_id, unsigned percent_num_proc_per_chunk);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H5_HAVE_PARALLEL */
+
+#endif
+
diff --git a/src/H5FDmulti.c b/src/H5FDmulti.c
new file mode 100644
index 0000000..8ae23d2
--- /dev/null
+++ b/src/H5FDmulti.c
@@ -0,0 +1,2004 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, November 10, 1997
+ *
+ * Purpose: Implements a file driver which dispatches I/O requests to
+ * other file drivers depending on the purpose of the address
+ * region being accessed. For instance, all meta-data could be
+ * place in one file while all raw data goes to some other file.
+ * This also serves as an example of coding a complex file driver,
+ * therefore, it should not use any non-public definitions.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Disable certain warnings in PC-Lint: */
+/*lint --emacro( {534, 830}, H5P_DEFAULT, H5P_FILE_ACCESS, H5P_DATASET_XFER) */
+/*lint --emacro( {534, 830}, H5FD_MULTI) */
+/*lint -esym( 534, H5Eclear2, H5Epush2) */
+
+#include "hdf5.h"
+
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* Loop through all mapped files */
+#define UNIQUE_MEMBERS_CORE(MAP, ITER, SEEN, LOOPVAR) { \
+ H5FD_mem_t ITER, LOOPVAR; \
+ unsigned SEEN[H5FD_MEM_NTYPES]; \
+ \
+ memset(SEEN, 0, sizeof SEEN); \
+ for (ITER=H5FD_MEM_SUPER; ITER<H5FD_MEM_NTYPES; ITER=(H5FD_mem_t)(ITER+1)) { \
+ LOOPVAR = MAP[ITER]; \
+ if (H5FD_MEM_DEFAULT==LOOPVAR) LOOPVAR=ITER; \
+ assert(LOOPVAR>0 && LOOPVAR<H5FD_MEM_NTYPES); \
+ if (SEEN[LOOPVAR]++) continue; \
+
+/* Need two front-ends, since they are nested sometimes */
+#define UNIQUE_MEMBERS(MAP, LOOPVAR) \
+ UNIQUE_MEMBERS_CORE(MAP, _unmapped, _seen, LOOPVAR)
+#define UNIQUE_MEMBERS2(MAP, LOOPVAR) \
+ UNIQUE_MEMBERS_CORE(MAP, _unmapped2, _seen2, LOOPVAR)
+
+#define ALL_MEMBERS(LOOPVAR) { \
+ H5FD_mem_t LOOPVAR; \
+ for (LOOPVAR=H5FD_MEM_DEFAULT; LOOPVAR<H5FD_MEM_NTYPES; LOOPVAR=(H5FD_mem_t)(LOOPVAR+1)) {
+
+
+#define END_MEMBERS }}
+
+#define H5FD_MULT_MAX_FILE_NAME_LEN 1024
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_MULTI_g = 0;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_multi_fapl_t {
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; /*memory usage map */
+ hid_t memb_fapl[H5FD_MEM_NTYPES]; /*member access properties */
+ char *memb_name[H5FD_MEM_NTYPES]; /*name generators */
+ haddr_t memb_addr[H5FD_MEM_NTYPES]; /*starting addr per member */
+ hbool_t relax; /*less stringent error checking */
+} H5FD_multi_fapl_t;
+
+/*
+ * The description of a file belonging to this driver. The file access
+ * properties and member names do not have to be copied into this struct
+ * since they will be held open by the file access property list which is
+ * copied into the parent file struct in H5F_open().
+ */
+typedef struct H5FD_multi_t {
+ H5FD_t pub; /*public stuff, must be first */
+ H5FD_multi_fapl_t fa; /*driver-specific file access properties */
+ haddr_t memb_next[H5FD_MEM_NTYPES]; /*addr of next member */
+ H5FD_t *memb[H5FD_MEM_NTYPES]; /*member pointers */
+ haddr_t memb_eoa[H5FD_MEM_NTYPES]; /*EOA for individual files,
+ *end of allocated addresses. v1.6 library
+ *have the EOA for the entire file. But it's
+ *meaningless for MULTI file. We replaced it
+ *with the EOAs for individual files */
+ unsigned flags; /*file open flags saved for debugging */
+ char *name; /*name passed to H5Fopen or H5Fcreate */
+} H5FD_multi_t;
+
+/* Driver specific data transfer properties */
+typedef struct H5FD_multi_dxpl_t {
+ hid_t memb_dxpl[H5FD_MEM_NTYPES];/*member data xfer properties*/
+} H5FD_multi_dxpl_t;
+
+/* Private functions */
+static char *my_strdup(const char *s);
+static int compute_next(H5FD_multi_t *file);
+static int open_members(H5FD_multi_t *file);
+
+/* Callback prototypes */
+static herr_t H5FD_multi_term(void);
+static hsize_t H5FD_multi_sb_size(H5FD_t *file);
+static herr_t H5FD_multi_sb_encode(H5FD_t *file, char *name/*out*/,
+ unsigned char *buf/*out*/);
+static herr_t H5FD_multi_sb_decode(H5FD_t *file, const char *name,
+ const unsigned char *buf);
+static void *H5FD_multi_fapl_get(H5FD_t *file);
+static void *H5FD_multi_fapl_copy(const void *_old_fa);
+static herr_t H5FD_multi_fapl_free(void *_fa);
+static H5FD_t *H5FD_multi_open(const char *name, unsigned flags,
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_multi_close(H5FD_t *_file);
+static int H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_multi_query(const H5FD_t *_f1, unsigned long *flags);
+static herr_t H5FD_multi_get_type_map(const H5FD_t *file, H5FD_mem_t *type_map);
+static haddr_t H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa);
+static haddr_t H5FD_multi_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static haddr_t H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+static herr_t H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ hsize_t size);
+static herr_t H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, void *_buf/*out*/);
+static herr_t H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, const void *_buf);
+static herr_t H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_multi_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_multi_unlock(H5FD_t *_file);
+
+/* The class struct */
+static const H5FD_class_t H5FD_multi_g = {
+ "multi", /*name */
+ HADDR_MAX, /*maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_multi_term, /*terminate */
+ H5FD_multi_sb_size, /*sb_size */
+ H5FD_multi_sb_encode, /*sb_encode */
+ H5FD_multi_sb_decode, /*sb_decode */
+ sizeof(H5FD_multi_fapl_t), /*fapl_size */
+ H5FD_multi_fapl_get, /*fapl_get */
+ H5FD_multi_fapl_copy, /*fapl_copy */
+ H5FD_multi_fapl_free, /*fapl_free */
+ 0, /*dxpl_size */
+ NULL, /*dxpl_copy */
+ NULL, /*dxpl_free */
+ H5FD_multi_open, /*open */
+ H5FD_multi_close, /*close */
+ H5FD_multi_cmp, /*cmp */
+ H5FD_multi_query, /*query */
+ H5FD_multi_get_type_map, /*get_type_map */
+ H5FD_multi_alloc, /*alloc */
+ H5FD_multi_free, /*free */
+ H5FD_multi_get_eoa, /*get_eoa */
+ H5FD_multi_set_eoa, /*set_eoa */
+ H5FD_multi_get_eof, /*get_eof */
+ H5FD_multi_get_handle, /*get_handle */
+ H5FD_multi_read, /*read */
+ H5FD_multi_write, /*write */
+ H5FD_multi_flush, /*flush */
+ H5FD_multi_truncate, /*truncate */
+ H5FD_multi_lock, /*lock */
+ H5FD_multi_unlock, /*unlock */
+ H5FD_FLMAP_DEFAULT /*fl_map */
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: my_strdup
+ *
+ * Purpose: Private version of strdup()
+ *
+ * Return: Success: Ptr to new copy of string
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static char *
+my_strdup(const char *s)
+{
+ char *x;
+ size_t str_len;
+
+ if(!s)
+ return NULL;
+ str_len = strlen(s) + 1;
+ if(NULL == (x = (char *)malloc(str_len)))
+ return NULL;
+ memcpy(x, s, str_len);
+
+ return x;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the multi driver.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_multi_init(void)
+{
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if(H5I_VFL!=H5Iget_type(H5FD_MULTI_g))
+ H5FD_MULTI_g = H5FDregister(&H5FD_multi_g);
+
+ return H5FD_MULTI_g;
+}
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_multi_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: Non-negative on success or negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_term(void)
+{
+ /* Reset VFL ID */
+ H5FD_MULTI_g=0;
+
+ return 0;
+} /* end H5FD_multi_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_split
+ *
+ * Purpose: Compatability function. Makes the multi driver act like the
+ * old split driver which stored meta data in one file and raw
+ * data in another file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 11, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_split(hid_t fapl, const char *meta_ext, hid_t meta_plist_id,
+ const char *raw_ext, hid_t raw_plist_id)
+{
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES];
+ hid_t memb_fapl[H5FD_MEM_NTYPES];
+ const char *memb_name[H5FD_MEM_NTYPES];
+ char meta_name[H5FD_MULT_MAX_FILE_NAME_LEN];
+ char raw_name[H5FD_MULT_MAX_FILE_NAME_LEN];
+ haddr_t memb_addr[H5FD_MEM_NTYPES];
+
+ /*NO TRACE*/
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Initialize */
+ ALL_MEMBERS(mt) {
+ /* Treat global heap as raw data, not metadata */
+ memb_map[mt] = ((mt == H5FD_MEM_DRAW || mt == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : H5FD_MEM_SUPER);
+ memb_fapl[mt] = -1;
+ memb_name[mt] = NULL;
+ memb_addr[mt] = HADDR_UNDEF;
+ } END_MEMBERS;
+
+ /* The file access properties */
+ memb_fapl[H5FD_MEM_SUPER] = meta_plist_id;
+ memb_fapl[H5FD_MEM_DRAW] = raw_plist_id;
+
+ /* The names */
+ /* process meta filename */
+ if(meta_ext) {
+ if(strstr(meta_ext, "%s")) {
+ /* Note: this doesn't accommodate for when the '%s' in the user's
+ * string is at a position >sizeof(meta_name) - QK & JK - 2013/01/17
+ */
+ strncpy(meta_name, meta_ext, sizeof(meta_name));
+ meta_name[sizeof(meta_name) - 1] = '\0';
+ }
+ else
+ sprintf(meta_name, "%%s%s", meta_ext);
+ }
+ else {
+ strncpy(meta_name, "%s.meta", sizeof(meta_name));
+ meta_name[sizeof(meta_name) - 1] = '\0';
+ }
+ memb_name[H5FD_MEM_SUPER] = meta_name;
+
+ /* process raw filename */
+ if(raw_ext) {
+ if(strstr(raw_ext, "%s")) {
+ /* Note: this doesn't accommodate for when the '%s' in the user's
+ * string is at a position >sizeof(raw_name) - QK & JK - 2013/01/17
+ */
+ strncpy(raw_name, raw_ext, sizeof(raw_name));
+ raw_name[sizeof(raw_name) - 1] = '\0';
+ }
+ else
+ sprintf(raw_name, "%%s%s", raw_ext);
+ }
+ else {
+ strncpy(raw_name, "%s.raw", sizeof(raw_name));
+ raw_name[sizeof(raw_name) - 1] = '\0';
+ }
+ memb_name[H5FD_MEM_DRAW] = raw_name;
+
+ /* The sizes */
+ memb_addr[H5FD_MEM_SUPER] = 0;
+ memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
+
+ return H5Pset_fapl_multi(fapl, memb_map, memb_fapl, memb_name, memb_addr, TRUE);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_multi
+ *
+ * Purpose: Sets the file access property list FAPL_ID to use the multi
+ * driver. The MEMB_MAP array maps memory usage types to other
+ * memory usage types and is the mechanism which allows the
+ * caller to specify how many files are created. The array
+ * contains H5FD_MEM_NTYPES entries which are either the value
+ * H5FD_MEM_DEFAULT or a memory usage type and the number of
+ * unique values determines the number of files which are
+ * opened. For each memory usage type which will be associated
+ * with a file the MEMB_FAPL array should have a property list
+ * and the MEMB_NAME array should be a name generator (a
+ * printf-style format with a %s which will be replaced with the
+ * name passed to H5FDopen(), usually from H5Fcreate() or
+ * H5Fopen()).
+ *
+ * If RELAX is set then opening an existing file for read-only
+ * access will not fail if some file members are missing. This
+ * allows a file to be accessed in a limited sense if just the
+ * meta data is available.
+ *
+ * Defaults: Default values for each of the optional arguments are:
+ *
+ * memb_map: The default member map has the value
+ * H5FD_MEM_DEFAULT for each element.
+ *
+ * memb_fapl: The value H5P_DEFAULT for each element.
+ *
+ * memb_name: The string `%s-X.h5' where `X' is one of the
+ * letters `s' (H5FD_MEM_SUPER),
+ * `b' (H5FD_MEM_BTREE), `r' (H5FD_MEM_DRAW),
+ * `g' (H5FD_MEM_GHEAP), 'l' (H5FD_MEM_LHEAP),
+ * `o' (H5FD_MEM_OHDR).
+ *
+ * memb_addr: The value HADDR_UNDEF for each element.
+ *
+ *
+ * Example: To set up a multi file access property list which partitions
+ * data into meta and raw files each being 1/2 of the address
+ * space one would say:
+ *
+ * H5FD_mem_t mt, memb_map[H5FD_MEM_NTYPES];
+ * hid_t memb_fapl[H5FD_MEM_NTYPES];
+ * const char *memb[H5FD_MEM_NTYPES];
+ * haddr_t memb_addr[H5FD_MEM_NTYPES];
+ *
+ * // The mapping...
+ * for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ * memb_map[mt] = H5FD_MEM_SUPER;
+ * }
+ * memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW;
+ *
+ * // Member information
+ * memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT;
+ * memb_name[H5FD_MEM_SUPER] = "%s.meta";
+ * memb_addr[H5FD_MEM_SUPER] = 0;
+ *
+ * memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT;
+ * memb_name[H5FD_MEM_DRAW] = "%s.raw";
+ * memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
+ *
+ * hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
+ * H5Pset_fapl_multi(fapl, memb_map, memb_fapl,
+ * memb_name, memb_addr, TRUE);
+ *
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_multi(hid_t fapl_id, const H5FD_mem_t *memb_map,
+ const hid_t *memb_fapl, const char * const *memb_name,
+ const haddr_t *memb_addr, hbool_t relax)
+{
+ H5FD_multi_fapl_t fa;
+ H5FD_mem_t mt, mmt;
+ H5FD_mem_t _memb_map[H5FD_MEM_NTYPES];
+ hid_t _memb_fapl[H5FD_MEM_NTYPES];
+ char _memb_name[H5FD_MEM_NTYPES][16];
+ const char *_memb_name_ptrs[H5FD_MEM_NTYPES];
+ haddr_t _memb_addr[H5FD_MEM_NTYPES];
+ static const char *letters = "Xsbrglo";
+ static const char *func="H5FDset_fapl_multi"; /* Function Name for error reporting */
+
+ /*NO TRACE*/
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check arguments and supply default values */
+ if(H5I_GENPROP_LST != H5Iget_type(fapl_id) ||
+ TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "not an access list", -1)
+ if (!memb_map) {
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
+ _memb_map[mt] = H5FD_MEM_DEFAULT;
+ memb_map = _memb_map;
+ }
+ if (!memb_fapl) {
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
+ _memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
+ memb_fapl = _memb_fapl;
+ }
+ if (!memb_name) {
+ assert(strlen(letters)==H5FD_MEM_NTYPES);
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
+ sprintf(_memb_name[mt], "%%s-%c.h5", letters[mt]);
+ _memb_name_ptrs[mt] = _memb_name[mt];
+ }
+ memb_name = _memb_name_ptrs;
+ }
+ if (!memb_addr) {
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
+ _memb_addr[mt] = (hsize_t)(mt ? (mt - 1) : 0) * (HADDR_MAX / (H5FD_MEM_NTYPES-1));
+ memb_addr = _memb_addr;
+ }
+
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
+ /* Map usage type */
+ mmt = memb_map[mt];
+ if (mmt<0 || mmt>=H5FD_MEM_NTYPES)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADRANGE, "file resource type out of range", -1)
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+
+ /*
+ * All members of MEMB_FAPL must be either defaults or actual file
+ * access property lists.
+ */
+ if (H5P_DEFAULT!=memb_fapl[mmt] && TRUE!=H5Pisa_class(memb_fapl[mmt], H5P_FILE_ACCESS))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type incorrect", -1)
+
+ /* All names must be defined */
+ if (!memb_name[mmt] || !memb_name[mmt][0])
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type not set", -1)
+ }
+
+ /*
+ * Initialize driver specific information. No need to copy it into the FA
+ * struct since all members will be copied by H5Pset_driver().
+ */
+ memcpy(fa.memb_map, memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
+ memcpy(fa.memb_fapl, memb_fapl, H5FD_MEM_NTYPES*sizeof(hid_t));
+ memcpy(fa.memb_name, memb_name, H5FD_MEM_NTYPES*sizeof(char*));
+ memcpy(fa.memb_addr, memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
+ fa.relax = relax;
+
+ /* Patch up H5P_DEFAULT property lists for members */
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
+ if(fa.memb_fapl[mt]==H5P_DEFAULT)
+ fa.memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
+ }
+ return H5Pset_driver(fapl_id, H5FD_MULTI, &fa);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_multi
+ *
+ * Purpose: Returns information about the multi file access property
+ * list though the function arguments which are the same as for
+ * H5Pset_fapl_multi() above.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_multi(hid_t fapl_id, H5FD_mem_t *memb_map/*out*/,
+ hid_t *memb_fapl/*out*/, char **memb_name/*out*/,
+ haddr_t *memb_addr/*out*/, hbool_t *relax)
+{
+ const H5FD_multi_fapl_t *fa;
+ H5FD_mem_t mt;
+ static const char *func="H5FDget_fapl_multi"; /* Function Name for error reporting */
+
+ /*NO TRACE*/
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if(H5I_GENPROP_LST != H5Iget_type(fapl_id) ||
+ TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not an access list", -1)
+ if(H5FD_MULTI != H5Pget_driver(fapl_id))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "incorrect VFL driver", -1)
+ if(NULL == (fa= (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id)))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "bad VFL driver info", -1)
+
+ if (memb_map)
+ memcpy(memb_map, fa->memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
+ if (memb_fapl) {
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
+ if (fa->memb_fapl[mt]>=0)
+ memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
+ else
+ memb_fapl[mt] = fa->memb_fapl[mt]; /*default or bad ID*/
+ }
+ }
+ if(memb_name) {
+ for(mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
+ if(fa->memb_name[mt])
+ memb_name[mt] = my_strdup(fa->memb_name[mt]);
+ else
+ memb_name[mt] = NULL;
+ }
+ }
+ if (memb_addr)
+ memcpy(memb_addr, fa->memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
+ if (relax)
+ *relax = fa->relax;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_size
+ *
+ * Purpose: Returns the size of the private information to be stored in
+ * the superblock.
+ *
+ * Return: Success: The super block driver data size.
+ *
+ * Failure: never fails
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5FD_multi_sb_size(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ unsigned nseen = 0;
+ hsize_t nbytes = 8; /*size of header*/
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* How many unique files? */
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ nseen++;
+ } END_MEMBERS;
+
+ /* Addresses and EOA markers */
+ nbytes += nseen * 2 * 8;
+
+ /* Name templates */
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ size_t n = strlen(file->fa.memb_name[mt])+1;
+ nbytes += (n+7) & ~((size_t)0x0007);
+ } END_MEMBERS;
+
+ return nbytes;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_encode
+ *
+ * Purpose: Encode driver information for the superblock. The NAME
+ * argument is a nine-byte buffer which will be initialized with
+ * an eight-character name/version number and null termination.
+ *
+ * The encoding is a six-byte member mapping followed two bytes
+ * which are unused. For each unique file in usage-type order
+ * encode all the starting addresses as unsigned 64-bit integers,
+ * then all the EOA values as unsigned 64-bit integers, then all
+ * the template names as null terminated strings which are
+ * multiples of 8 characters.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_sb_encode(H5FD_t *_file, char *name/*out*/,
+ unsigned char *buf/*out*/)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ haddr_t memb_eoa;
+ unsigned char *p;
+ size_t nseen;
+ size_t i;
+ H5FD_mem_t m;
+ static const char *func="H5FD_multi_sb_encode"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Name and version number */
+ strncpy(name, "NCSAmulti", (size_t)8);
+ name[8] = '\0';
+
+ assert(7==H5FD_MEM_NTYPES);
+
+ for (m=H5FD_MEM_SUPER; m<H5FD_MEM_NTYPES; m=(H5FD_mem_t)(m+1)) {
+ buf[m-1] = (unsigned char)file->fa.memb_map[m];
+ }
+ buf[6] = 0;
+ buf[7] = 0;
+
+ /*
+ * Copy the starting addresses and EOA values into the buffer in order of
+ * usage type but only for types which map to something unique.
+ */
+
+ /* Encode all starting addresses and EOA values */
+ nseen = 0;
+ p = buf+8;
+ assert(sizeof(haddr_t)<=8);
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ memcpy(p, &(file->fa.memb_addr[mt]), sizeof(haddr_t));
+ p += sizeof(haddr_t);
+ memb_eoa = H5FDget_eoa(file->memb[mt], mt);
+ memcpy(p, &memb_eoa, sizeof(haddr_t));
+ p += sizeof(haddr_t);
+ nseen++;
+ } END_MEMBERS;
+ if (H5Tconvert(H5T_NATIVE_HADDR, H5T_STD_U64LE, nseen*2, buf+8, NULL, H5P_DEFAULT)<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info", -1)
+
+ /* Encode all name templates */
+ p = buf + 8 + nseen*2*8;
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ size_t n = strlen(file->fa.memb_name[mt]) + 1;
+ strncpy((char *)p, file->fa.memb_name[mt], n);
+ p += n;
+ for (i=n; i%8; i++)
+ *p++ = '\0';
+ } END_MEMBERS;
+
+ return 0;
+} /* end H5FD_multi_sb_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_decode
+ *
+ * Purpose: Decodes the superblock information for this driver. The NAME
+ * argument is the eight-character (plus null termination) name
+ * stored in the file.
+ *
+ * The FILE argument is updated according to the information in
+ * the superblock. This may mean that some member files are
+ * closed and others are opened.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ char x[2*H5FD_MEM_NTYPES*8];
+ H5FD_mem_t map[H5FD_MEM_NTYPES];
+ int i;
+ size_t nseen=0;
+ hbool_t map_changed=FALSE;
+ hbool_t in_use[H5FD_MEM_NTYPES];
+ const char *memb_name[H5FD_MEM_NTYPES];
+ haddr_t memb_addr[H5FD_MEM_NTYPES];
+ haddr_t memb_eoa[H5FD_MEM_NTYPES];
+ haddr_t *ap;
+ static const char *func="H5FD_multi_sb_decode"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Make sure the name/version number is correct */
+ if (strcmp(name, "NCSAmult"))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "invalid multi superblock", -1)
+
+ /* Set default values */
+ ALL_MEMBERS(mt) {
+ memb_addr[mt] = HADDR_UNDEF;
+ memb_eoa[mt] = HADDR_UNDEF;
+ memb_name[mt] = NULL;
+ } END_MEMBERS;
+
+ /*
+ * Read the map and count the unique members.
+ */
+ memset(map, 0, sizeof map);
+
+ for (i=0; i<6; i++) {
+ map[i+1] = (H5FD_mem_t)buf[i];
+ if (file->fa.memb_map[i+1]!=map[i+1])
+ map_changed=TRUE;
+ }
+
+ UNIQUE_MEMBERS(map, mt) {
+ nseen++;
+ } END_MEMBERS;
+ buf += 8;
+
+ /* Decode Address and EOA values */
+ assert(sizeof(haddr_t)<=8);
+ memcpy(x, buf, (nseen*2*8));
+ buf += nseen*2*8;
+ if (H5Tconvert(H5T_STD_U64LE, H5T_NATIVE_HADDR, nseen*2, x, NULL, H5P_DEFAULT)<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info", -1)
+ ap = (haddr_t*)x;
+ UNIQUE_MEMBERS(map, mt) {
+ memb_addr[_unmapped] = *ap++;
+ memb_eoa[_unmapped] = *ap++;
+ } END_MEMBERS;
+
+ /* Decode name templates */
+ UNIQUE_MEMBERS(map, mt) {
+ size_t n = strlen((const char *)buf)+1;
+ memb_name[_unmapped] = (const char *)buf;
+ buf += (n+7) & ~((unsigned)0x0007);
+ } END_MEMBERS;
+
+ /*
+ * Use the mapping saved in the superblock in preference to the one
+ * already set for the file. Since we may have opened files which are no
+ * longer needed we should close all those files. We'll open the new
+ * files at the end.
+ */
+ if (map_changed) {
+ /* Commit map */
+ ALL_MEMBERS(mt) {
+ file->fa.memb_map[mt] = map[mt];
+ } END_MEMBERS;
+
+ /* Close files which are unused now */
+ memset(in_use, 0, sizeof in_use);
+ UNIQUE_MEMBERS(map, mt) {
+ in_use[mt] = TRUE;
+ } END_MEMBERS;
+ ALL_MEMBERS(mt) {
+ if (!in_use[mt] && file->memb[mt]) {
+ (void)H5FDclose(file->memb[mt]);
+ file->memb[mt] = NULL;
+ }
+ file->fa.memb_map[mt] = map[mt];
+ } END_MEMBERS;
+ }
+
+ /* Commit member starting addresses and name templates */
+ ALL_MEMBERS(mt) {
+ file->fa.memb_addr[mt] = memb_addr[mt];
+ if (memb_name[mt]) {
+ if (file->fa.memb_name[mt])
+ free(file->fa.memb_name[mt]);
+ file->fa.memb_name[mt] = my_strdup(memb_name[mt]);
+ }
+ } END_MEMBERS;
+ if (compute_next(file)<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", -1)
+
+ /* Open all necessary files */
+ if (open_members(file)<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", -1)
+
+ /* Set the EOA marker for all open files */
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ if (file->memb[mt])
+ if(H5FDset_eoa(file->memb[mt], mt, memb_eoa[mt])<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET, "set_eoa() failed", -1)
+
+ /* Save the individual EOAs in one place for later comparison (in H5FD_multi_set_eoa) */
+ file->memb_eoa[mt] = memb_eoa[mt];
+ } END_MEMBERS;
+
+ return 0;
+} /* end H5FD_multi_sb_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_get
+ *
+ * Purpose: Returns a file access property list which indicates how the
+ * specified file is being accessed. The return list could be
+ * used to access another file the same way.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * members copied from the file struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_multi_fapl_get(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ return H5FD_multi_fapl_copy(&(file->fa));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_copy
+ *
+ * Purpose: Copies the multi-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_multi_fapl_copy(const void *_old_fa)
+{
+ const H5FD_multi_fapl_t *old_fa = (const H5FD_multi_fapl_t*)_old_fa;
+ H5FD_multi_fapl_t *new_fa = (H5FD_multi_fapl_t *)malloc(sizeof(H5FD_multi_fapl_t));
+ int nerrors = 0;
+ static const char *func="H5FD_multi_fapl_copy"; /* Function Name for error reporting */
+
+ assert(new_fa);
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ memcpy(new_fa, old_fa, sizeof(H5FD_multi_fapl_t));
+ ALL_MEMBERS(mt) {
+ if (old_fa->memb_fapl[mt]>=0) {
+ if (H5Iinc_ref(old_fa->memb_fapl[mt]) < 0) {
+ nerrors++;
+ break;
+ }
+ new_fa->memb_fapl[mt] = old_fa->memb_fapl[mt];
+ }
+ if (old_fa->memb_name[mt]) {
+ new_fa->memb_name[mt] = my_strdup(old_fa->memb_name[mt]);
+ if (NULL == new_fa->memb_name[mt]) {
+ nerrors++;
+ break;
+ }
+ }
+ } END_MEMBERS;
+
+ if (nerrors) {
+ ALL_MEMBERS(mt) {
+ if (new_fa->memb_fapl[mt]>=0)
+ (void)H5Idec_ref(new_fa->memb_fapl[mt]);
+ if (new_fa->memb_name[mt])
+ free(new_fa->memb_name[mt]);
+ } END_MEMBERS;
+ free(new_fa);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "can't release object on error", NULL)
+ }
+ return new_fa;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_free
+ *
+ * Purpose: Frees the multi-specific file access properties.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_fapl_free(void *_fa)
+{
+ H5FD_multi_fapl_t *fa = (H5FD_multi_fapl_t*)_fa;
+ static const char *func="H5FD_multi_fapl_free"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ ALL_MEMBERS(mt) {
+ if (fa->memb_fapl[mt]>=0)
+ if(H5Idec_ref(fa->memb_fapl[mt])<0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list", -1)
+ if (fa->memb_name[mt])
+ free(fa->memb_name[mt]);
+ } END_MEMBERS;
+ free(fa);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_open
+ *
+ * Purpose: Creates and/or opens a multi HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_multi_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr)
+{
+ H5FD_multi_t *file=NULL;
+ hid_t close_fapl=-1;
+ const H5FD_multi_fapl_t *fa;
+ H5FD_mem_t m;
+ static const char *func="H5FD_multi_open"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check arguments */
+ if (!name || !*name)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL)
+ if (0==maxaddr || HADDR_UNDEF==maxaddr)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL)
+
+ /*
+ * Initialize the file from the file access properties, using default
+ * values if necessary. Make sure to use CALLOC here because the code
+ * in H5FD_multi_set_eoa depends on the proper initialization of memb_eoa
+ * in H5FD_multi_t.
+ */
+ if(NULL == (file = (H5FD_multi_t *)calloc((size_t)1, sizeof(H5FD_multi_t))))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL)
+ if(H5P_FILE_ACCESS_DEFAULT==fapl_id || H5FD_MULTI!=H5Pget_driver(fapl_id)) {
+ close_fapl = fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if(H5Pset_fapl_multi(fapl_id, NULL, NULL, NULL, NULL, TRUE)<0)
+ H5Epush_goto(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTSET, "can't set property value", error)
+ }
+ fa = (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
+ assert(fa);
+ ALL_MEMBERS(mt) {
+ file->fa.memb_map[mt] = fa->memb_map[mt];
+ file->fa.memb_addr[mt] = fa->memb_addr[mt];
+ if (fa->memb_fapl[mt]>=0)
+ H5Iinc_ref(fa->memb_fapl[mt]);
+ file->fa.memb_fapl[mt] = fa->memb_fapl[mt];
+ if (fa->memb_name[mt])
+ file->fa.memb_name[mt] = my_strdup(fa->memb_name[mt]);
+ else
+ file->fa.memb_name[mt] = NULL;
+ } END_MEMBERS;
+ file->fa.relax = fa->relax;
+ file->flags = flags;
+ file->name = my_strdup(name);
+ if (close_fapl>=0)
+ if(H5Pclose(close_fapl)<0)
+ H5Epush_goto(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list", error)
+
+ /* Compute derived properties and open member files */
+ if (compute_next(file)<0)
+ H5Epush_goto(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", error);
+ if (open_members(file)<0)
+ H5Epush_goto(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", error);
+
+ /* We must have opened at least the superblock file */
+ if (H5FD_MEM_DEFAULT==(m=file->fa.memb_map[H5FD_MEM_SUPER]))
+ m = H5FD_MEM_SUPER;
+ if (NULL==file->memb[m])
+ goto error;
+
+ return (H5FD_t*)file;
+
+error:
+ /* Cleanup and fail */
+ if (file) {
+ ALL_MEMBERS(mt) {
+ if (file->memb[mt]) (void)H5FDclose(file->memb[mt]);
+ if (file->fa.memb_fapl[mt]>=0) (void)H5Idec_ref(file->fa.memb_fapl[mt]);
+ if (file->fa.memb_name[mt]) free(file->fa.memb_name[mt]);
+ } END_MEMBERS;
+ if (file->name) free(file->name);
+ free(file);
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_close
+ *
+ * Purpose: Closes a multi file.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative with as many members closed as
+ * possible. The only subsequent operation
+ * permitted on the file is a close operation.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_close(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ int nerrors=0;
+ static const char *func="H5FD_multi_close"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Close as many members as possible */
+ ALL_MEMBERS(mt) {
+ if (file->memb[mt]) {
+ if (H5FDclose(file->memb[mt])<0) {
+ nerrors++;
+ } else {
+ file->memb[mt] = NULL;
+ }
+ }
+ } END_MEMBERS;
+ if (nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error closing member files", -1)
+
+ /* Clean up other stuff */
+ ALL_MEMBERS(mt) {
+ if (file->fa.memb_fapl[mt]>=0) (void)H5Idec_ref(file->fa.memb_fapl[mt]);
+ if (file->fa.memb_name[mt]) free(file->fa.memb_name[mt]);
+ } END_MEMBERS;
+
+ free(file->name);
+ free(file);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_cmp
+ *
+ * Purpose: Compares two file families to see if they are the same. It
+ * does this by comparing the first common member of the two
+ * families. If the families have no members in common then the
+ * file with the earliest member is smaller than the other file.
+ * We abort if neither file has any members.
+ *
+ * Return: Success: like strcmp()
+ *
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_multi_t *f1 = (const H5FD_multi_t*)_f1;
+ const H5FD_multi_t *f2 = (const H5FD_multi_t*)_f2;
+ H5FD_mem_t out_mt = H5FD_MEM_DEFAULT;
+ int cmp=0;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ ALL_MEMBERS(mt) {
+ out_mt = mt;
+ if(f1->memb[mt] && f2->memb[mt])
+ break;
+ if(!cmp) {
+ if(f1->memb[mt])
+ cmp = -1;
+ else if(f2->memb[mt])
+ cmp = 1;
+ }
+ } END_MEMBERS;
+ assert(cmp || out_mt<H5FD_MEM_NTYPES);
+ if(out_mt>=H5FD_MEM_NTYPES)
+ return cmp;
+
+ return H5FDcmp(f1->memb[out_mt], f2->memb[out_mt]);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 26, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_query(const H5FD_t *_f, unsigned long *flags /* out */)
+{
+ /* Shut compiler up */
+ _f=_f;
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_USE_ALLOC_SIZE; /* OK just pass the allocation size to the alloc callback */
+ *flags |= H5FD_FEAT_PAGED_AGGR; /* OK special file space mapping for paged aggregation */
+ } /* end if */
+
+ return(0);
+} /* end H5FD_multi_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_type_map
+ *
+ * Purpose: Retrieve the memory type mapping for this file
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 9, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map)
+{
+ const H5FD_multi_t *file = (const H5FD_multi_t*)_file;
+
+ /* Copy file's free space type mapping */
+ memcpy(type_map, file->fa.memb_map, sizeof(file->fa.memb_map));
+
+ return(0);
+} /* end H5FD_multi_get_type_map() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_eoa
+ *
+ * Purpose: Returns the end-of-address marker for the file. The EOA
+ * marker is the first address past the last byte allocated in
+ * the format address space.
+ *
+ * Return: Success: The end-of-address-marker
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 21 Dec. 2006
+ * Added the parameter TYPE. It's only used for MULTI driver.
+ * If the TYPE is H5FD_MEM_DEFAULT, simply find the biggest
+ * EOA of individual file because the EOA for the whole file
+ * is meaningless.
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type)
+{
+ const H5FD_multi_t *file = (const H5FD_multi_t*)_file;
+ haddr_t eoa = 0;
+ static const char *func="H5FD_multi_get_eoa"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* The library used to have EOA for the whole file. But it's
+ * taken out because it makes little sense for MULTI files.
+ * However, the library sometimes queries it through H5F_get_eoa.
+ * Here the code finds the biggest EOA for individual file if
+ * the query is for TYPE == H5FD_MEM_DEFAULT.
+ */
+ if(H5FD_MEM_DEFAULT == type) {
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ haddr_t memb_eoa;
+
+ if (file->memb[mt]) {
+ /* Retrieve EOA */
+ H5E_BEGIN_TRY {
+ memb_eoa = H5FDget_eoa(file->memb[mt], mt);
+ } H5E_END_TRY;
+
+ if(HADDR_UNDEF == memb_eoa)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa", HADDR_UNDEF)
+ if(memb_eoa>0)
+ memb_eoa += file->fa.memb_addr[mt];
+ } else if(file->fa.relax) {
+ /*
+ * The member is not open yet (maybe it doesn't exist). Make the
+ * best guess about the end-of-file.
+ */
+ memb_eoa = file->memb_next[mt];
+ assert(HADDR_UNDEF != memb_eoa);
+ } else {
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF)
+ }
+
+ if(memb_eoa > eoa)
+ eoa = memb_eoa;
+ } END_MEMBERS;
+ } else {
+ H5FD_mem_t mmt = file->fa.memb_map[type];
+
+ if(H5FD_MEM_DEFAULT == mmt)
+ mmt = type;
+
+ if(file->memb[mmt]) {
+ H5E_BEGIN_TRY {
+ eoa = H5FDget_eoa(file->memb[mmt], mmt);
+ } H5E_END_TRY;
+
+ if(HADDR_UNDEF == eoa)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa", HADDR_UNDEF)
+ if(eoa > 0)
+ eoa += file->fa.memb_addr[mmt];
+ } else if(file->fa.relax) {
+ /*
+ * The member is not open yet (maybe it doesn't exist). Make the
+ * best guess about the end-of-file.
+ */
+ eoa = file->memb_next[mmt];
+ assert(HADDR_UNDEF != eoa);
+ } else {
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF)
+ }
+ }
+
+ return eoa;
+} /* end H5FD_multi_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file by savig the new
+ * EOA value in the file struct. Also set the EOA marker for the
+ * subfile in which the new EOA value falls. We don't set the
+ * EOA values of any other subfiles.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * 10 January 2007
+ * EOA for the whole file is discarded because it's meaningless
+ * for MULTI file. This function only sets eoa for individual
+ * file.
+ *
+ * Raymond Lu
+ * 21 June 2011
+ * Backward compatibility of EOA. Please the comment in the
+ * code.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mmt;
+ herr_t status;
+ static const char *func="H5FD_multi_set_eoa"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ mmt = file->fa.memb_map[type];
+ if(H5FD_MEM_DEFAULT == mmt) {
+ if(H5FD_MEM_DEFAULT == type)
+ mmt = H5FD_MEM_SUPER;
+ else
+ mmt = type;
+ } /* end if */
+
+ /* Handle backward compatibility in a quick and simple way. v1.6 library
+ * had EOA for the entire virtual file. But it wasn't meaningful. So v1.8
+ * library doesn't have it anymore. It saves the EOA for the metadata file,
+ * instead. Here we try to figure out whether the EOA is from a v1.6 file
+ * by comparing its value. If it is a big value, we assume it's from v1.6
+ * and simply discard it. This is the normal case when the metadata file
+ * has the smallest starting address. If the metadata file has the biggest
+ * address, the EOAs of v1.6 and v1.8 files are the same. It won't cause
+ * any trouble. (Please see Issue 2598 in Jira) SLU - 2011/6/21
+ */
+ if(H5FD_MEM_SUPER == mmt && file->memb_eoa[H5FD_MEM_SUPER] > 0 && eoa > (file->memb_next[H5FD_MEM_SUPER] / 2))
+ return 0;
+
+ assert(eoa >= file->fa.memb_addr[mmt]);
+ assert(eoa < file->memb_next[mmt]);
+
+ H5E_BEGIN_TRY {
+ status = H5FDset_eoa(file->memb[mmt], mmt, (eoa - file->fa.memb_addr[mmt]));
+ } H5E_END_TRY;
+ if(status < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "member H5FDset_eoa failed", -1)
+
+ return 0;
+} /* end H5FD_multi_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the total multi size or the current EOA marker.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the multi of files or the current
+ * EOA, whichever is larger.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_get_eof(const H5FD_t *_file, H5FD_mem_t type)
+{
+ const H5FD_multi_t *file = (const H5FD_multi_t*)_file;
+ haddr_t eof = 0;
+ static const char *func="H5FD_multi_get_eof"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if(H5FD_MEM_DEFAULT == type) {
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ haddr_t tmp_eof;
+
+ if(file->memb[mt]) {
+ /* Retrieve EOF */
+ H5E_BEGIN_TRY {
+ tmp_eof = H5FDget_eof(file->memb[mt], type);
+ } H5E_END_TRY;
+
+ if(HADDR_UNDEF == tmp_eof)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eof", HADDR_UNDEF)
+ if(tmp_eof > 0)
+ tmp_eof += file->fa.memb_addr[mt];
+ } else if(file->fa.relax) {
+ /*
+ * The member is not open yet (maybe it doesn't exist). Make the
+ * best guess about the end-of-file.
+ */
+ tmp_eof = file->memb_next[mt];
+ assert(HADDR_UNDEF != tmp_eof);
+ } else {
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eof", HADDR_UNDEF)
+ }
+ if(tmp_eof > eof)
+ eof = tmp_eof;
+ } END_MEMBERS;
+ } else {
+ H5FD_mem_t mmt = file->fa.memb_map[type];
+
+ if(H5FD_MEM_DEFAULT == mmt)
+ mmt = type;
+
+ if(file->memb[mmt]) {
+ /* Retrieve EOF */
+ H5E_BEGIN_TRY {
+ eof = H5FDget_eof(file->memb[mmt], mmt);
+ } H5E_END_TRY;
+
+ if(HADDR_UNDEF == eof)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eof", HADDR_UNDEF)
+ if(eof > 0)
+ eof += file->fa.memb_addr[mmt];
+ } else if(file->fa.relax) {
+ /*
+ * The member is not open yet (maybe it doesn't exist). Make the
+ * best guess about the end-of-file.
+ */
+ eof = file->memb_next[mmt];
+ assert(HADDR_UNDEF != eof);
+ } else {
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eof", HADDR_UNDEF)
+ }
+ }
+ return eof;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_handle
+ *
+ * Purpose: Returns the file handle of MULTI file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle)
+{
+ H5FD_multi_t *file = (H5FD_multi_t *)_file;
+ H5FD_mem_t type, mmt;
+ static const char *func="H5FD_multi_get_handle"; /* Function Name for error reporting */
+
+ /* Get data type for multi driver */
+ if(H5Pget_multi_type(fapl, &type) < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "can't get data type for multi driver", -1)
+ if(type<H5FD_MEM_DEFAULT || type>=H5FD_MEM_NTYPES)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "data type is out of range", -1)
+ mmt = file->fa.memb_map[type];
+ if(H5FD_MEM_DEFAULT==mmt) mmt = type;
+
+ return (H5FDget_vfd_handle(file->memb[mmt], fapl, file_handle));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_alloc
+ *
+ * Purpose: Allocate file memory.
+ *
+ * Return: Success: Address of new memory
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 12, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mmt;
+ haddr_t addr;
+ static const char *func="H5FD_multi_alloc"; /* Function Name for error reporting */
+
+ mmt = file->fa.memb_map[type];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = type;
+
+ /* XXX: NEED to work on this again */
+ if(file->pub.paged_aggr) {
+ ALL_MEMBERS(mt) {
+ if(file->memb[mt])
+ file->memb[mt]->paged_aggr = file->pub.paged_aggr;
+ } END_MEMBERS;
+ }
+
+ if (HADDR_UNDEF==(addr=H5FDalloc(file->memb[mmt], mmt, dxpl_id, size)))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file can't alloc", HADDR_UNDEF)
+ addr += file->fa.memb_addr[mmt];
+
+/*#ifdef TMP
+ if ( addr + size > file->eoa ) {
+
+ if ( H5FD_multi_set_eoa(_file, addr + size) < 0 ) {
+
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, \
+ "can't set eoa", HADDR_UNDEF)
+ }
+ }
+#else
+ if ( addr + size > file->eoa )
+ file->eoa = addr + size;
+#endif */
+
+ return addr;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_free
+ *
+ * Purpose: Frees memory
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 12, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mmt;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ mmt = file->fa.memb_map[type];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = type;
+
+ assert(addr>=file->fa.memb_addr[mmt]);
+ assert(addr+size<=file->memb_next[mmt]);
+ return H5FDfree(file->memb[mmt], mmt, dxpl_id, addr-file->fa.memb_addr[mmt], size);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero. Result is stored in caller-supplied
+ * buffer BUF.
+ *
+ * Failure: -1, contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, void *_buf/*out*/)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt, mmt, hi = H5FD_MEM_DEFAULT;
+ haddr_t start_addr = 0;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Find the file to which this address belongs */
+ for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
+ mmt = file->fa.memb_map[mt];
+ if(H5FD_MEM_DEFAULT == mmt)
+ mmt = mt;
+ assert(mmt > 0 && mmt < H5FD_MEM_NTYPES);
+
+ if(file->fa.memb_addr[mmt] > addr)
+ continue;
+ if(file->fa.memb_addr[mmt] >= start_addr) {
+ start_addr = file->fa.memb_addr[mmt];
+ hi = mmt;
+ } /* end if */
+ } /* end for */
+ assert(hi > 0);
+
+ /* Read from that member */
+ return H5FDread(file->memb[hi], type, dxpl_id, addr - start_addr, size, _buf);
+} /* end H5FD_multi_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: Zero
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ size_t size, const void *_buf)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt, mmt, hi = H5FD_MEM_DEFAULT;
+ haddr_t start_addr = 0;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Find the file to which this address belongs */
+ for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
+ mmt = file->fa.memb_map[mt];
+ if(H5FD_MEM_DEFAULT == mmt)
+ mmt = mt;
+ assert(mmt > 0 && mmt<H5FD_MEM_NTYPES);
+
+ if(file->fa.memb_addr[mmt] > addr)
+ continue;
+ if(file->fa.memb_addr[mmt] >= start_addr) {
+ start_addr = file->fa.memb_addr[mmt];
+ hi = mmt;
+ } /* end if */
+ } /* end for */
+ assert(hi > 0);
+
+ /* Write to that member */
+ return H5FDwrite(file->memb[hi], type, dxpl_id, addr - start_addr, size, _buf);
+} /* end H5FD_multi_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_flush
+ *
+ * Purpose: Flushes all multi members.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1, as many files flushed as possible.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt;
+ int nerrors=0;
+ static const char *func="H5FD_multi_flush"; /* Function Name for error reporting */
+
+#if 0
+ H5FD_mem_t mmt;
+
+ /* Debugging stuff... */
+ fprintf(stderr, "multifile access information:\n");
+
+ /* print the map */
+ fprintf(stderr, " map=");
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ fprintf(stderr, "%s%d", 1==mt?"":",", (int)mmt);
+ }
+ fprintf(stderr, "\n");
+
+ /* print info about each file */
+ fprintf(stderr, " File Starting Allocated Next Member\n");
+ fprintf(stderr, " Number Address Size Address Name\n");
+ fprintf(stderr, " ------ -------------------- -------------------- -------------------- ------------------------------\n");
+
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ if (HADDR_UNDEF!=file->memb_addr[mt]) {
+ haddr_t eoa = H5FDget_eoa(file->memb[mt], mt);
+ fprintf(stderr, " %6d %20llu %20llu %20llu %s\n",
+ (int)mt, (unsigned long long)(file->memb_addr[mt]),
+ (unsigned long long)eoa,
+ (unsigned long long)(file->memb_next[mt]),
+ file->memb_name[mt]);
+ }
+ }
+#endif
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Flush each file */
+ for (mt=H5FD_MEM_SUPER; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
+ if (file->memb[mt]) {
+ H5E_BEGIN_TRY {
+ if (H5FDflush(file->memb[mt],dxpl_id,closing)<0) nerrors++;
+ } H5E_END_TRY;
+ }
+ }
+ if (nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error flushing member files", -1)
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_truncate
+ *
+ * Purpose: Truncates all multi members.
+ *
+ * Return: Success: 0
+ * Failure: -1, as many files truncated as possible.
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 31, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt;
+ int nerrors=0;
+ static const char *func="H5FD_multi_truncate"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Truncate each file */
+ for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
+ if(file->memb[mt]) {
+ H5E_BEGIN_TRY {
+ if(H5FDtruncate(file->memb[mt], dxpl_id, closing) < 0)
+ nerrors++;
+ } H5E_END_TRY;
+ }
+ }
+ if(nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error truncating member files", -1)
+
+ return 0;
+} /* end H5FD_multi_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_lock
+ *
+ * Purpose: Place a lock on all multi members.
+ * When there is error in locking a member file, it will not
+ * proceed further and will try to remove the locks of those
+ * member files that are locked before error is encountered.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ int nerrors = 0;
+ H5FD_mem_t out_mt;
+ static const char *func="H5FD_multi_unlock"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Lock all member files */
+ ALL_MEMBERS(mt) {
+ out_mt = mt;
+ if(file->memb[mt]) {
+ H5E_BEGIN_TRY {
+ if(H5FDlock(file->memb[mt], rw) < 0) {
+ nerrors++;
+ break;
+ } /* end if */
+ } H5E_END_TRY;
+ } /* end if */
+ } END_MEMBERS;
+
+ /* Try to unlock the member files that are locked before error is encountered */
+ if(nerrors) {
+ H5FD_mem_t k;
+
+ for(k = H5FD_MEM_DEFAULT; k < out_mt; k = (H5FD_mem_t)(k + 1)) {
+ H5E_BEGIN_TRY {
+ if(H5FDunlock(file->memb[k]) < 0)
+ nerrors++;
+ } H5E_END_TRY;
+ } /* end for */
+ } /* end if */
+
+ if(nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error locking member files", -1)
+ return 0;
+
+} /* H5FD_multi_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_unlock
+ *
+ * Purpose: Remove the lock on all multi members.
+ * It will try to unlock all member files but will record error
+ * encountered.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_unlock(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ int nerrors=0;
+ static const char *func="H5FD_multi_unlock"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ ALL_MEMBERS(mt) {
+ if(file->memb[mt])
+ if(H5FDunlock(file->memb[mt]) < 0)
+ nerrors++;
+ } END_MEMBERS;
+
+ if(nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error unlocking member files", -1)
+
+ return 0;
+} /* H5FD_multi_unlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: compute_next
+ *
+ * Purpose: Compute the memb_next[] values of the file based on the
+ * file's member map and the member starting addresses.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 23, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+compute_next(H5FD_multi_t *file)
+{
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ ALL_MEMBERS(mt) {
+ file->memb_next[mt] = HADDR_UNDEF;
+ } END_MEMBERS;
+
+ UNIQUE_MEMBERS(file->fa.memb_map, mt1) {
+ UNIQUE_MEMBERS2(file->fa.memb_map, mt2) {
+ if (file->fa.memb_addr[mt1]<file->fa.memb_addr[mt2] &&
+ (HADDR_UNDEF==file->memb_next[mt1] ||
+ file->memb_next[mt1]>file->fa.memb_addr[mt2])) {
+ file->memb_next[mt1] = file->fa.memb_addr[mt2];
+ }
+ } END_MEMBERS;
+ if (HADDR_UNDEF==file->memb_next[mt1]) {
+ file->memb_next[mt1] = HADDR_MAX; /*last member*/
+ }
+ } END_MEMBERS;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: open_members
+ *
+ * Purpose: Opens all members which are not opened yet.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 23, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+open_members(H5FD_multi_t *file)
+{
+ char tmp[H5FD_MULT_MAX_FILE_NAME_LEN];
+ int nerrors=0;
+ static const char *func="(H5FD_multi)open_members"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ UNIQUE_MEMBERS(file->fa.memb_map, mt) {
+ if(file->memb[mt])
+ continue; /*already open*/
+ assert(file->fa.memb_name[mt]);
+ /* Note: This truncates the user's filename down to only sizeof(tmp)
+ * characters. -QK & JK, 2013/01/17
+ */
+ sprintf(tmp, file->fa.memb_name[mt], file->name);
+
+ H5E_BEGIN_TRY {
+ file->memb[mt] = H5FDopen(tmp, file->flags, file->fa.memb_fapl[mt], HADDR_UNDEF);
+ } H5E_END_TRY;
+ if(!file->memb[mt]) {
+ if(!file->fa.relax || (file->flags & H5F_ACC_RDWR))
+ nerrors++;
+ }
+ } END_MEMBERS;
+ if (nerrors)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error opening member files", -1)
+
+ return 0;
+}
+
+
+#ifdef _H5private_H
+/*
+ * This is not related to the functionality of the driver code.
+ * It is added here to trigger warning if HDF5 private definitions are included
+ * by mistake. The code should use only HDF5 public API and definitions.
+ */
+#error "Do not use HDF5 private definitions"
+#endif
diff --git a/src/H5FDmulti.h b/src/H5FDmulti.h
new file mode 100644
index 0000000..0bd5718
--- /dev/null
+++ b/src/H5FDmulti.h
@@ -0,0 +1,43 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the "multi" driver.
+ */
+#ifndef H5FDmulti_H
+#define H5FDmulti_H
+
+#define H5FD_MULTI (H5FD_multi_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+H5_DLL hid_t H5FD_multi_init(void);
+H5_DLL herr_t H5Pset_fapl_multi(hid_t fapl_id, const H5FD_mem_t *memb_map,
+ const hid_t *memb_fapl, const char * const *memb_name,
+ const haddr_t *memb_addr, hbool_t relax);
+H5_DLL herr_t H5Pget_fapl_multi(hid_t fapl_id, H5FD_mem_t *memb_map/*out*/,
+ hid_t *memb_fapl/*out*/, char **memb_name/*out*/,
+ haddr_t *memb_addr/*out*/, hbool_t *relax/*out*/);
+H5_DLL herr_t H5Pset_fapl_split(hid_t fapl, const char *meta_ext,
+ hid_t meta_plist_id, const char *raw_ext,
+ hid_t raw_plist_id);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5FDpkg.h b/src/H5FDpkg.h
new file mode 100644
index 0000000..31dcf8d
--- /dev/null
+++ b/src/H5FDpkg.h
@@ -0,0 +1,64 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, January 3, 2008
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5FD package. Source files outside the H5FD package should
+ * include H5FDprivate.h instead.
+ */
+#if !(defined H5FD_FRIEND || defined H5FD_MODULE)
+#error "Do not include this file outside the H5FD package!"
+#endif
+
+#ifndef _H5FDpkg_H
+#define _H5FDpkg_H
+
+/* Get package's private header */
+#include "H5FDprivate.h" /* File drivers */
+
+/* Other private headers needed by this file */
+#include "H5FLprivate.h" /* Free lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+H5_DLL haddr_t H5FD_alloc_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type,
+ hsize_t size, haddr_t *align_addr, hsize_t *align_size);
+H5_DLL herr_t H5FD_free_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type,
+ haddr_t addr, hsize_t size);
+
+/* Testing functions */
+#ifdef H5FD_TESTING
+H5_DLL hbool_t H5FD_supports_swmr_test(const char *vfd_name);
+#endif /* H5FD_TESTING */
+
+#endif /* _H5FDpkg_H */
+
diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h
new file mode 100644
index 0000000..0fc2135
--- /dev/null
+++ b/src/H5FDprivate.h
@@ -0,0 +1,208 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, July 26, 1999
+ */
+#ifndef _H5FDprivate_H
+#define _H5FDprivate_H
+
+/* Include package's public header */
+#include "H5FDpublic.h"
+
+/* Private headers needed by this file */
+#include "H5Pprivate.h" /* Property lists */
+
+/*
+ * The MPI drivers are needed because there are
+ * places where we check for things that aren't handled by these drivers.
+ */
+#include "H5FDmpi.h" /* MPI-based file drivers */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Length of filename buffer */
+#define H5FD_MAX_FILENAME_LEN 1024
+
+#ifdef H5_HAVE_PARALLEL
+/* ======== Temporary data transfer properties ======== */
+/* Definitions for memory MPI type property */
+#define H5FD_MPI_XFER_MEM_MPI_TYPE_NAME "H5FD_mpi_mem_mpi_type"
+/* Definitions for file MPI type property */
+#define H5FD_MPI_XFER_FILE_MPI_TYPE_NAME "H5FD_mpi_file_mpi_type"
+
+/* Sub-class the H5FD_class_t to add more specific functions for MPI-based VFDs */
+typedef struct H5FD_class_mpi_t {
+ H5FD_class_t super; /* Superclass information & methods */
+ int (*get_rank)(const H5FD_t *file); /* Get the MPI rank of a process */
+ int (*get_size)(const H5FD_t *file); /* Get the MPI size of a communicator */
+ MPI_Comm (*get_comm)(const H5FD_t *file); /* Get the communicator for a file */
+ herr_t (*get_mpi_info)(H5FD_t *file, void** mpi_info); /* get MPI_Info for a file */
+} H5FD_class_mpi_t;
+#endif
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* File operations */
+typedef enum {
+ OP_UNKNOWN = 0, /* Unknown last file operation */
+ OP_READ = 1, /* Last file I/O operation was a read */
+ OP_WRITE = 2 /* Last file I/O operation was a write */
+} H5FD_file_op_t;
+
+
+/* Define structure to hold initial file image and other relevant information */
+typedef struct {
+ void *buffer;
+ size_t size;
+ H5FD_file_image_callbacks_t callbacks;
+} H5FD_file_image_info_t;
+
+/* Define default file image info */
+#define H5FD_DEFAULT_FILE_IMAGE_INFO { \
+ /* file image buffer */ NULL, \
+ /* buffer size */ 0, \
+ { /* Callbacks */ \
+ /* image_malloc */ NULL, \
+ /* image_memcpy */ NULL, \
+ /* image_realloc */ NULL, \
+ /* image_free */ NULL, \
+ /* udata_copy */ NULL, \
+ /* udata_free */ NULL, \
+ /* udata */ NULL, \
+ } \
+}
+
+/* Define structure to hold driver ID & info for FAPLs */
+typedef struct {
+ hid_t driver_id; /* Driver's ID */
+ const void *driver_info; /* Driver info, for open callbacks */
+} H5FD_driver_prop_t;
+
+#ifdef H5_HAVE_PARALLEL
+/* MPIO-specific file access properties */
+typedef struct H5FD_mpio_fapl_t {
+ MPI_Comm comm; /*communicator */
+ MPI_Info info; /*file information */
+} H5FD_mpio_fapl_t;
+#endif /* H5_HAVE_PARALLEL */
+
+#ifdef H5_DEBUG_BUILD
+/* Definitions for the internal DXPL types created in H5AC__init_package() */
+typedef enum {
+ H5FD_METADATA_DXPL = 0,
+ H5FD_NOIO_DXPL,
+ H5FD_RAWDATA_DXPL
+} H5FD_dxpl_type_t;
+
+#define H5FD_DXPL_TYPE_NAME "H5P_dxpl_type"
+#endif /* H5_DEBUG_BUILD */
+
+/* I/O Info for an operation */
+typedef struct H5FD_io_info_t {
+ H5FD_t *file; /* File driver object */
+#ifndef H5_DEBUG_BUILD
+ const
+#endif /* H5_DEBUG_BUILD */
+ H5P_genplist_t *meta_dxpl; /* Metadata DXPL object */
+#ifndef H5_DEBUG_BUILD
+ const
+#endif /* H5_DEBUG_BUILD */
+ H5P_genplist_t *raw_dxpl; /* Raw data DXPL object */
+} H5FD_io_info_t;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Library Private Prototypes */
+/******************************/
+
+/* Forward declarations for prototype arguments */
+struct H5F_t;
+
+H5_DLL int H5FD_term_interface(void);
+H5_DLL herr_t H5FD_locate_signature(H5FD_io_info_t *fdio_info, haddr_t *sig_addr);
+H5_DLL H5FD_class_t *H5FD_get_class(hid_t id);
+H5_DLL hsize_t H5FD_sb_size(H5FD_t *file);
+H5_DLL herr_t H5FD_sb_encode(H5FD_t *file, char *name/*out*/, uint8_t *buf);
+H5_DLL herr_t H5FD_sb_load(H5FD_t *file, const char *name, const uint8_t *buf);
+H5_DLL void *H5FD_fapl_get(H5FD_t *file);
+H5_DLL herr_t H5FD_fapl_close(hid_t driver_id, const void *fapl);
+H5_DLL hid_t H5FD_register(const void *cls, size_t size, hbool_t app_ref);
+H5_DLL H5FD_t *H5FD_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+H5_DLL herr_t H5FD_close(H5FD_t *file);
+H5_DLL int H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2);
+H5_DLL haddr_t H5FD_alloc(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type,
+ struct H5F_t *f, hsize_t size, haddr_t *frag_addr, hsize_t *frag_size);
+H5_DLL herr_t H5FD_free(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, struct H5F_t *f,
+ haddr_t addr, hsize_t size);
+H5_DLL htri_t H5FD_try_extend(H5FD_t *file, H5FD_mem_t type, struct H5F_t *f,
+ hid_t dxpl_id, haddr_t blk_end, hsize_t extra_requested);
+H5_DLL haddr_t H5FD_get_eoa(const H5FD_t *file, H5FD_mem_t type);
+H5_DLL herr_t H5FD_set_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr);
+H5_DLL haddr_t H5FD_get_eof(const H5FD_t *file, H5FD_mem_t type);
+H5_DLL haddr_t H5FD_get_maxaddr(const H5FD_t *file);
+H5_DLL herr_t H5FD_get_feature_flags(const H5FD_t *file, unsigned long *feature_flags);
+H5_DLL herr_t H5FD_set_feature_flags(H5FD_t *file, unsigned long feature_flags);
+H5_DLL herr_t H5FD_get_fs_type_map(const H5FD_t *file, H5FD_mem_t *type_map);
+H5_DLL herr_t H5FD_read(H5FD_io_info_t *fdio_info, H5FD_mem_t type,
+ haddr_t addr, size_t size, void *buf/*out*/);
+H5_DLL herr_t H5FD_write(const H5FD_io_info_t *fdio_info, H5FD_mem_t type,
+ haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5FD_flush(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+H5_DLL herr_t H5FD_truncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+H5_DLL herr_t H5FD_lock(H5FD_t *file, hbool_t rw);
+H5_DLL herr_t H5FD_unlock(H5FD_t *file);
+H5_DLL herr_t H5FD_get_fileno(const H5FD_t *file, unsigned long *filenum);
+H5_DLL herr_t H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl, void** file_handle);
+H5_DLL herr_t H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr);
+H5_DLL haddr_t H5FD_get_base_addr(const H5FD_t *file);
+H5_DLL herr_t H5FD_set_paged_aggr(H5FD_t *file, hbool_t paged);
+
+/* Function prototypes for MPI based VFDs*/
+#ifdef H5_HAVE_PARALLEL
+/* General routines */
+H5_DLL haddr_t H5FD_mpi_MPIOff_to_haddr(MPI_Offset mpi_off);
+H5_DLL herr_t H5FD_mpi_haddr_to_MPIOff(haddr_t addr, MPI_Offset *mpi_off/*out*/);
+H5_DLL herr_t H5FD_mpi_comm_info_dup(MPI_Comm comm, MPI_Info info,
+ MPI_Comm *comm_new, MPI_Info *info_new);
+H5_DLL herr_t H5FD_mpi_comm_info_free(MPI_Comm *comm, MPI_Info *info);
+#ifdef NOT_YET
+H5_DLL herr_t H5FD_mpio_wait_for_left_neighbor(H5FD_t *file);
+H5_DLL herr_t H5FD_mpio_signal_right_neighbor(H5FD_t *file);
+#endif /* NOT_YET */
+H5_DLL herr_t H5FD_mpi_setup_collective(hid_t dxpl_id, MPI_Datatype *btype,
+ MPI_Datatype *ftype);
+H5_DLL herr_t H5FD_set_mpio_atomicity(H5FD_t *file, hbool_t flag);
+H5_DLL herr_t H5FD_get_mpio_atomicity(H5FD_t *file, hbool_t *flag);
+
+/* Driver specific methods */
+H5_DLL int H5FD_mpi_get_rank(const H5FD_t *file);
+H5_DLL int H5FD_mpi_get_size(const H5FD_t *file);
+H5_DLL MPI_Comm H5FD_mpi_get_comm(const H5FD_t *_file);
+H5_DLL herr_t H5FD_get_mpi_info(H5FD_t *file, void** file_info);
+#endif /* H5_HAVE_PARALLEL */
+
+#endif /* !_H5FDprivate_H */
+
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
new file mode 100644
index 0000000..3032e8a
--- /dev/null
+++ b/src/H5FDpublic.h
@@ -0,0 +1,383 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, July 26, 1999
+ */
+#ifndef _H5FDpublic_H
+#define _H5FDpublic_H
+
+#include "H5public.h"
+#include "H5Fpublic.h" /*for H5F_close_degree_t */
+
+#define H5_HAVE_VFL 1 /*define a convenient app feature test*/
+#define H5FD_VFD_DEFAULT 0 /* Default VFL driver value */
+
+/* Types of allocation requests: see H5Fpublic.h */
+typedef enum H5F_mem_t H5FD_mem_t;
+
+/* Map "fractal heap" header blocks to 'ohdr' type file memory, since its
+ * a fair amount of work to add a new kind of file memory and they are similar
+ * enough to object headers and probably too minor to deserve their own type.
+ *
+ * Map "fractal heap" indirect blocks to 'ohdr' type file memory, since they
+ * are similar to fractal heap header blocks.
+ *
+ * Map "fractal heap" direct blocks to 'lheap' type file memory, since they
+ * will be replacing local heaps.
+ *
+ * Map "fractal heap" 'huge' objects to 'draw' type file memory, since they
+ * represent large objects that are directly stored in the file.
+ *
+ * -QAK
+ */
+#define H5FD_MEM_FHEAP_HDR H5FD_MEM_OHDR
+#define H5FD_MEM_FHEAP_IBLOCK H5FD_MEM_OHDR
+#define H5FD_MEM_FHEAP_DBLOCK H5FD_MEM_LHEAP
+#define H5FD_MEM_FHEAP_HUGE_OBJ H5FD_MEM_DRAW
+
+/* Map "free space" header blocks to 'ohdr' type file memory, since its
+ * a fair amount of work to add a new kind of file memory and they are similar
+ * enough to object headers and probably too minor to deserve their own type.
+ *
+ * Map "free space" serialized sections to 'lheap' type file memory, since they
+ * are similar enough to local heap info.
+ *
+ * -QAK
+ */
+#define H5FD_MEM_FSPACE_HDR H5FD_MEM_OHDR
+#define H5FD_MEM_FSPACE_SINFO H5FD_MEM_LHEAP
+
+/* Map "shared object header message" master table to 'ohdr' type file memory,
+ * since its a fair amount of work to add a new kind of file memory and they are
+ * similar enough to object headers and probably too minor to deserve their own
+ * type.
+ *
+ * Map "shared object header message" indices to 'btree' type file memory,
+ * since they are similar enough to B-tree nodes.
+ *
+ * -QAK
+ */
+#define H5FD_MEM_SOHM_TABLE H5FD_MEM_OHDR
+#define H5FD_MEM_SOHM_INDEX H5FD_MEM_BTREE
+
+/* Map "extensible array" header blocks to 'ohdr' type file memory, since its
+ * a fair amount of work to add a new kind of file memory and they are similar
+ * enough to object headers and probably too minor to deserve their own type.
+ *
+ * Map "extensible array" index blocks to 'ohdr' type file memory, since they
+ * are similar to extensible array header blocks.
+ *
+ * Map "extensible array" super blocks to 'btree' type file memory, since they
+ * are similar enough to B-tree nodes.
+ *
+ * Map "extensible array" data blocks & pages to 'lheap' type file memory, since
+ * they are similar enough to local heap info.
+ *
+ * -QAK
+ */
+#define H5FD_MEM_EARRAY_HDR H5FD_MEM_OHDR
+#define H5FD_MEM_EARRAY_IBLOCK H5FD_MEM_OHDR
+#define H5FD_MEM_EARRAY_SBLOCK H5FD_MEM_BTREE
+#define H5FD_MEM_EARRAY_DBLOCK H5FD_MEM_LHEAP
+#define H5FD_MEM_EARRAY_DBLK_PAGE H5FD_MEM_LHEAP
+
+/* Map "fixed array" header blocks to 'ohdr' type file memory, since its
+ * a fair amount of work to add a new kind of file memory and they are similar
+ * enough to object headers and probably too minor to deserve their own type.
+ *
+ * Map "fixed array" data blocks & pages to 'lheap' type file memory, since
+ * they are similar enough to local heap info.
+ *
+ */
+#define H5FD_MEM_FARRAY_HDR H5FD_MEM_OHDR
+#define H5FD_MEM_FARRAY_DBLOCK H5FD_MEM_LHEAP
+#define H5FD_MEM_FARRAY_DBLK_PAGE H5FD_MEM_LHEAP
+
+/*
+ * A free-list map which maps all types of allocation requests to a single
+ * free list. This is useful for drivers that don't really care about
+ * keeping different requests segregated in the underlying file and which
+ * want to make most efficient reuse of freed memory. The use of the
+ * H5FD_MEM_SUPER free list is arbitrary.
+ */
+#define H5FD_FLMAP_SINGLE { \
+ H5FD_MEM_SUPER, /*default*/ \
+ H5FD_MEM_SUPER, /*super*/ \
+ H5FD_MEM_SUPER, /*btree*/ \
+ H5FD_MEM_SUPER, /*draw*/ \
+ H5FD_MEM_SUPER, /*gheap*/ \
+ H5FD_MEM_SUPER, /*lheap*/ \
+ H5FD_MEM_SUPER /*ohdr*/ \
+}
+
+/*
+ * A free-list map which segregates requests into `raw' or `meta' data
+ * pools.
+ */
+#define H5FD_FLMAP_DICHOTOMY { \
+ H5FD_MEM_SUPER, /*default*/ \
+ H5FD_MEM_SUPER, /*super*/ \
+ H5FD_MEM_SUPER, /*btree*/ \
+ H5FD_MEM_DRAW, /*draw*/ \
+ H5FD_MEM_DRAW, /*gheap*/ \
+ H5FD_MEM_SUPER, /*lheap*/ \
+ H5FD_MEM_SUPER /*ohdr*/ \
+}
+
+/*
+ * The default free list map which causes each request type to use it's own
+ * free-list.
+ */
+#define H5FD_FLMAP_DEFAULT { \
+ H5FD_MEM_DEFAULT, /*default*/ \
+ H5FD_MEM_DEFAULT, /*super*/ \
+ H5FD_MEM_DEFAULT, /*btree*/ \
+ H5FD_MEM_DEFAULT, /*draw*/ \
+ H5FD_MEM_DEFAULT, /*gheap*/ \
+ H5FD_MEM_DEFAULT, /*lheap*/ \
+ H5FD_MEM_DEFAULT /*ohdr*/ \
+}
+
+
+/* Define VFL driver features that can be enabled on a per-driver basis */
+/* These are returned with the 'query' function pointer in H5FD_class_t */
+ /*
+ * Defining H5FD_FEAT_AGGREGATE_METADATA for a VFL driver means that
+ * the library will attempt to allocate a larger block for metadata and
+ * then sub-allocate each metadata request from that larger block.
+ */
+#define H5FD_FEAT_AGGREGATE_METADATA 0x00000001
+ /*
+ * Defining H5FD_FEAT_ACCUMULATE_METADATA for a VFL driver means that
+ * the library will attempt to cache metadata as it is written to the file
+ * and build up a larger block of metadata to eventually pass to the VFL
+ * 'write' routine.
+ *
+ * Distinguish between updating the metadata accumulator on writes and
+ * reads. This is particularly (perhaps only, even) important for MPI-I/O
+ * where we guarantee that writes are collective, but reads may not be.
+ * If we were to allow the metadata accumulator to be written during a
+ * read operation, the application would hang.
+ */
+#define H5FD_FEAT_ACCUMULATE_METADATA_WRITE 0x00000002
+#define H5FD_FEAT_ACCUMULATE_METADATA_READ 0x00000004
+#define H5FD_FEAT_ACCUMULATE_METADATA (H5FD_FEAT_ACCUMULATE_METADATA_WRITE|H5FD_FEAT_ACCUMULATE_METADATA_READ)
+ /*
+ * Defining H5FD_FEAT_DATA_SIEVE for a VFL driver means that
+ * the library will attempt to cache raw data as it is read from/written to
+ * a file in a "data seive" buffer. See Rajeev Thakur's papers:
+ * http://www.mcs.anl.gov/~thakur/papers/romio-coll.ps.gz
+ * http://www.mcs.anl.gov/~thakur/papers/mpio-high-perf.ps.gz
+ */
+#define H5FD_FEAT_DATA_SIEVE 0x00000008
+ /*
+ * Defining H5FD_FEAT_AGGREGATE_SMALLDATA for a VFL driver means that
+ * the library will attempt to allocate a larger block for "small" raw data
+ * and then sub-allocate "small" raw data requests from that larger block.
+ */
+#define H5FD_FEAT_AGGREGATE_SMALLDATA 0x00000010
+ /*
+ * Defining H5FD_FEAT_IGNORE_DRVRINFO for a VFL driver means that
+ * the library will ignore the driver info that is encoded in the file
+ * for the VFL driver. (This will cause the driver info to be eliminated
+ * from the file when it is flushed/closed, if the file is opened R/W).
+ */
+#define H5FD_FEAT_IGNORE_DRVRINFO 0x00000020
+ /*
+ * Defining the H5FD_FEAT_DIRTY_DRVRINFO_LOAD for a VFL driver means that
+ * the library will mark the driver info dirty when the file is opened
+ * R/W. This will cause the driver info to be re-encoded when the file
+ * is flushed/closed.
+ */
+#define H5FD_FEAT_DIRTY_DRVRINFO_LOAD 0x00000040
+ /*
+ * Defining H5FD_FEAT_POSIX_COMPAT_HANDLE for a VFL driver means that
+ * the handle for the VFD (returned with the 'get_handle' callback) is
+ * of type 'int' and is compatible with POSIX I/O calls.
+ */
+#define H5FD_FEAT_POSIX_COMPAT_HANDLE 0x00000080
+ /*
+ * Defining H5FD_FEAT_HAS_MPI for a VFL driver means that
+ * the driver makes use of MPI communication and code may retrieve
+ * communicator/rank information from it
+ */
+#define H5FD_FEAT_HAS_MPI 0x00000100
+ /*
+ * Defining the H5FD_FEAT_ALLOCATE_EARLY for a VFL driver will force
+ * the library to use the H5D_ALLOC_TIME_EARLY on dataset create
+ * instead of the default H5D_ALLOC_TIME_LATE
+ */
+#define H5FD_FEAT_ALLOCATE_EARLY 0x00000200
+ /*
+ * Defining H5FD_FEAT_ALLOW_FILE_IMAGE for a VFL driver means that
+ * the driver is able to use a file image in the fapl as the initial
+ * contents of a file.
+ */
+#define H5FD_FEAT_ALLOW_FILE_IMAGE 0x00000400
+ /*
+ * Defining H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS for a VFL driver
+ * means that the driver is able to use callbacks to make a copy of the
+ * image to store in memory.
+ */
+#define H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS 0x00000800
+ /*
+ * Defining H5FD_FEAT_SUPPORTS_SWMR_IO for a VFL driver means that the
+ * driver supports the single-writer/multiple-readers I/O pattern.
+ */
+#define H5FD_FEAT_SUPPORTS_SWMR_IO 0x00001000
+ /*
+ * Defining H5FD_FEAT_USE_ALLOC_SIZE for a VFL driver
+ * means that the library will just pass the allocation size to the
+ * the driver's allocation callback which will eventually handle alignment.
+ * This is specifically used for the multi/split driver.
+ */
+#define H5FD_FEAT_USE_ALLOC_SIZE 0x00002000
+ /*
+ * Defining H5FD_FEAT_PAGED_AGGR for a VFL driver
+ * means that the driver needs special file space mapping for paged aggregation.
+ * This is specifically used for the multi/split driver.
+ */
+#define H5FD_FEAT_PAGED_AGGR 0x00004000
+
+/* Forward declaration */
+typedef struct H5FD_t H5FD_t;
+
+/* Class information for each file driver */
+typedef struct H5FD_class_t {
+ const char *name;
+ haddr_t maxaddr;
+ H5F_close_degree_t fc_degree;
+ herr_t (*terminate)(void);
+ hsize_t (*sb_size)(H5FD_t *file);
+ herr_t (*sb_encode)(H5FD_t *file, char *name/*out*/,
+ unsigned char *p/*out*/);
+ herr_t (*sb_decode)(H5FD_t *f, const char *name, const unsigned char *p);
+ size_t fapl_size;
+ void * (*fapl_get)(H5FD_t *file);
+ void * (*fapl_copy)(const void *fapl);
+ herr_t (*fapl_free)(void *fapl);
+ size_t dxpl_size;
+ void * (*dxpl_copy)(const void *dxpl);
+ herr_t (*dxpl_free)(void *dxpl);
+ H5FD_t *(*open)(const char *name, unsigned flags, hid_t fapl,
+ haddr_t maxaddr);
+ herr_t (*close)(H5FD_t *file);
+ int (*cmp)(const H5FD_t *f1, const H5FD_t *f2);
+ herr_t (*query)(const H5FD_t *f1, unsigned long *flags);
+ herr_t (*get_type_map)(const H5FD_t *file, H5FD_mem_t *type_map);
+ haddr_t (*alloc)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+ herr_t (*free)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id,
+ haddr_t addr, hsize_t size);
+ haddr_t (*get_eoa)(const H5FD_t *file, H5FD_mem_t type);
+ herr_t (*set_eoa)(H5FD_t *file, H5FD_mem_t type, haddr_t addr);
+ haddr_t (*get_eof)(const H5FD_t *file, H5FD_mem_t type);
+ herr_t (*get_handle)(H5FD_t *file, hid_t fapl, void**file_handle);
+ herr_t (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl,
+ haddr_t addr, size_t size, void *buffer);
+ herr_t (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl,
+ haddr_t addr, size_t size, const void *buffer);
+ herr_t (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+ herr_t (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+ herr_t (*lock)(H5FD_t *file, hbool_t rw);
+ herr_t (*unlock)(H5FD_t *file);
+ H5FD_mem_t fl_map[H5FD_MEM_NTYPES];
+} H5FD_class_t;
+
+/* A free list is a singly-linked list of address/size pairs. */
+typedef struct H5FD_free_t {
+ haddr_t addr;
+ hsize_t size;
+ struct H5FD_free_t *next;
+} H5FD_free_t;
+
+/*
+ * The main datatype for each driver. Public fields common to all drivers
+ * are declared here and the driver appends private fields in memory.
+ */
+struct H5FD_t {
+ hid_t driver_id; /*driver ID for this file */
+ const H5FD_class_t *cls; /*constant class info */
+ unsigned long fileno; /* File 'serial' number */
+ unsigned access_flags; /* File access flags (from create or open) */
+ unsigned long feature_flags; /* VFL Driver feature Flags */
+ haddr_t maxaddr; /* For this file, overrides class */
+ haddr_t base_addr; /* Base address for HDF5 data w/in file */
+
+ /* Space allocation management fields */
+ hsize_t threshold; /* Threshold for alignment */
+ hsize_t alignment; /* Allocation alignment */
+ hbool_t paged_aggr; /* Paged aggregation for file space is enabled or not */
+};
+
+/* Define enum for the source of file image callbacks */
+typedef enum {
+ H5FD_FILE_IMAGE_OP_NO_OP,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE,
+ H5FD_FILE_IMAGE_OP_FILE_OPEN,
+ H5FD_FILE_IMAGE_OP_FILE_RESIZE,
+ H5FD_FILE_IMAGE_OP_FILE_CLOSE
+} H5FD_file_image_op_t;
+
+/* Define structure to hold file image callbacks */
+typedef struct {
+ void *(*image_malloc)(size_t size, H5FD_file_image_op_t file_image_op,
+ void *udata);
+ void *(*image_memcpy)(void *dest, const void *src, size_t size,
+ H5FD_file_image_op_t file_image_op, void *udata);
+ void *(*image_realloc)(void *ptr, size_t size,
+ H5FD_file_image_op_t file_image_op, void *udata);
+ herr_t (*image_free)(void *ptr, H5FD_file_image_op_t file_image_op,
+ void *udata);
+ void *(*udata_copy)(void *udata);
+ herr_t (*udata_free)(void *udata);
+ void *udata;
+} H5FD_file_image_callbacks_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+H5_DLL hid_t H5FDregister(const H5FD_class_t *cls);
+H5_DLL herr_t H5FDunregister(hid_t driver_id);
+H5_DLL H5FD_t *H5FDopen(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+H5_DLL herr_t H5FDclose(H5FD_t *file);
+H5_DLL int H5FDcmp(const H5FD_t *f1, const H5FD_t *f2);
+H5_DLL int H5FDquery(const H5FD_t *f, unsigned long *flags);
+H5_DLL haddr_t H5FDalloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+H5_DLL herr_t H5FDfree(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id,
+ haddr_t addr, hsize_t size);
+H5_DLL haddr_t H5FDget_eoa(H5FD_t *file, H5FD_mem_t type);
+H5_DLL herr_t H5FDset_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t eoa);
+H5_DLL haddr_t H5FDget_eof(H5FD_t *file, H5FD_mem_t type);
+H5_DLL herr_t H5FDget_vfd_handle(H5FD_t *file, hid_t fapl, void**file_handle);
+H5_DLL herr_t H5FDread(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id,
+ haddr_t addr, size_t size, void *buf/*out*/);
+H5_DLL herr_t H5FDwrite(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id,
+ haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+H5_DLL herr_t H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+H5_DLL herr_t H5FDlock(H5FD_t *file, hbool_t rw);
+H5_DLL herr_t H5FDunlock(H5FD_t *file);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
new file mode 100644
index 0000000..26913e2
--- /dev/null
+++ b/src/H5FDsec2.c
@@ -0,0 +1,979 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, July 29, 1999
+ *
+ * Purpose: The POSIX unbuffered file driver using only the HDF5 public
+ * API and with a few optimizations: the lseek() call is made
+ * only when the current file position is unknown or needs to be
+ * changed based on previous I/O through this driver (don't mix
+ * I/O from this driver with I/O from other parts of the
+ * application to the same file).
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDsec2.h" /* Sec2 file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_SEC2_g = 0;
+
+/* The description of a file belonging to this driver. The 'eoa' and 'eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying filesystem file). The
+ * 'pos' value is used to eliminate file position updates when they would be a
+ * no-op. Unfortunately we've found systems that use separate file position
+ * indicators for reading and writing so the lseek can only be eliminated if
+ * the current operation is the same as the previous operation. When opening
+ * a file the 'eof' will be set to the current file size, `eoa' will be set
+ * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
+ * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
+ */
+typedef struct H5FD_sec2_t {
+ H5FD_t pub; /* public stuff, must be first */
+ int fd; /* the filesystem file descriptor */
+ haddr_t eoa; /* end of allocated region */
+ haddr_t eof; /* end of file; current file size */
+ haddr_t pos; /* current file I/O position */
+ H5FD_file_op_t op; /* last operation */
+ char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
+#ifndef H5_HAVE_WIN32_API
+ /* On most systems the combination of device and i-node number uniquely
+ * identify a file. Note that Cygwin, MinGW and other Windows POSIX
+ * environments have the stat function (which fakes inodes)
+ * and will use the 'device + inodes' scheme as opposed to the
+ * Windows code further below.
+ */
+ dev_t device; /* file device number */
+ ino_t inode; /* file i-node number */
+#else
+ /* Files in windows are uniquely identified by the volume serial
+ * number and the file index (both low and high parts).
+ *
+ * There are caveats where these numbers can change, especially
+ * on FAT file systems. On NTFS, however, a file should keep
+ * those numbers the same until renamed or deleted (though you
+ * can use ReplaceFile() on NTFS to keep the numbers the same
+ * while renaming).
+ *
+ * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
+ * more information.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
+ */
+ DWORD nFileIndexLow;
+ DWORD nFileIndexHigh;
+ DWORD dwVolumeSerialNumber;
+
+ HANDLE hFile; /* Native windows file handle */
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Information from properties set by 'h5repart' tool
+ *
+ * Whether to eliminate the family driver info and convert this file to
+ * a single file.
+ */
+ hbool_t fam_to_sec2;
+
+} H5FD_sec2_t;
+
+/*
+ * These macros check for overflow of various quantities. These macros
+ * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely by the second
+ * argument of the file seek function.
+ */
+#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
+#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || \
+ (HDoff_t)((A)+(Z))<(HDoff_t)(A))
+
+/* Prototypes */
+static herr_t H5FD_sec2_term(void);
+static H5FD_t *H5FD_sec2_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr);
+static herr_t H5FD_sec2_close(H5FD_t *_file);
+static int H5FD_sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_sec2_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_sec2_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_sec2_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_sec2_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD_sec2_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_sec2_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_sec2_unlock(H5FD_t *_file);
+
+static const H5FD_class_t H5FD_sec2_g = {
+ "sec2", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_sec2_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ 0, /* fapl_size */
+ NULL, /* fapl_get */
+ NULL, /* fapl_copy */
+ NULL, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_sec2_open, /* open */
+ H5FD_sec2_close, /* close */
+ H5FD_sec2_cmp, /* cmp */
+ H5FD_sec2_query, /* query */
+ NULL, /* get_type_map */
+ NULL, /* alloc */
+ NULL, /* free */
+ H5FD_sec2_get_eoa, /* get_eoa */
+ H5FD_sec2_set_eoa, /* set_eoa */
+ H5FD_sec2_get_eof, /* get_eof */
+ H5FD_sec2_get_handle, /* get_handle */
+ H5FD_sec2_read, /* read */
+ H5FD_sec2_write, /* write */
+ NULL, /* flush */
+ H5FD_sec2_truncate, /* truncate */
+ H5FD_sec2_lock, /* lock */
+ H5FD_sec2_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+/* Declare a free list to manage the H5FD_sec2_t struct */
+H5FL_DEFINE_STATIC(H5FD_sec2_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initializes any interface-specific data or routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_sec2_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize sec2 VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the sec2 driver.
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_sec2_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5I_VFL != H5I_get_type(H5FD_SEC2_g))
+ H5FD_SEC2_g = H5FD_register(&H5FD_sec2_g, sizeof(H5FD_class_t), FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_SEC2_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_sec2_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_SEC2_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_sec2_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_sec2
+ *
+ * Purpose: Modify the file access property list to use the H5FD_SEC2
+ * driver defined in this source file. There are no driver
+ * specific properties.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_sec2(hid_t fapl_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", fapl_id);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ ret_value = H5P_set_driver(plist, H5FD_SEC2, NULL);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_sec2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_open
+ *
+ * Purpose: Create and/or opens a file as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_sec2_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
+{
+ H5FD_sec2_t *file = NULL; /* sec2 VFD info */
+ int fd = -1; /* File descriptor */
+ int o_flags; /* Flags for open() call */
+#ifdef H5_HAVE_WIN32_API
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#endif
+ h5_stat_t sb;
+ H5FD_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check on file offsets */
+ HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t));
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+ if(ADDR_OVERFLOW(maxaddr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
+
+ /* Build the open flags */
+ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
+ if(H5F_ACC_TRUNC & flags)
+ o_flags |= O_TRUNC;
+ if(H5F_ACC_CREAT & flags)
+ o_flags |= O_CREAT;
+ if(H5F_ACC_EXCL & flags)
+ o_flags |= O_EXCL;
+
+ /* Open the file */
+ if((fd = HDopen(name, o_flags, 0666)) < 0) {
+ int myerrno = errno;
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
+ } /* end if */
+
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+
+ /* Create the new file struct */
+ if(NULL == (file = H5FL_CALLOC(H5FD_sec2_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+
+ file->fd = fd;
+ H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t);
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+#ifdef H5_HAVE_WIN32_API
+ file->hFile = (HANDLE)_get_osfhandle(fd);
+ if(INVALID_HANDLE_VALUE == file->hFile)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
+
+ if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
+
+ file->nFileIndexHigh = fileinfo.nFileIndexHigh;
+ file->nFileIndexLow = fileinfo.nFileIndexLow;
+ file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
+#else /* H5_HAVE_WIN32_API */
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Retain a copy of the name used to open the file, for possible error reporting */
+ HDstrncpy(file->filename, name, sizeof(file->filename));
+ file->filename[sizeof(file->filename) - 1] = '\0';
+
+ /* Check for non-default FAPL */
+ if(H5P_FILE_ACCESS_DEFAULT != fapl_id) {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the FAPL */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, NULL, "not a file access property list")
+
+ /* This step is for h5repart tool only. If user wants to change file driver from
+ * family to sec2 while using h5repart, this private property should be set so that
+ * in the later step, the library can ignore the family driver information saved
+ * in the superblock.
+ */
+ if(H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SEC2_NAME) > 0)
+ if(H5P_get(plist, H5F_ACS_FAMILY_TO_SEC2_NAME, &file->fam_to_sec2) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to sec2")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (H5FD_t*)file;
+
+done:
+ if(NULL == ret_value) {
+ if(fd >= 0)
+ HDclose(fd);
+ if(file)
+ file = H5FL_FREE(H5FD_sec2_t, file);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_close
+ *
+ * Purpose: Closes an HDF5 file.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file not closed.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_close(H5FD_t *_file)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(file);
+
+ /* Close the underlying file */
+ if(HDclose(file->fd) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+ /* Release the file info */
+ file = H5FL_FREE(H5FD_sec2_t, file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_cmp
+ *
+ * Purpose: Compares two files belonging to this driver using an
+ * arbitrary (but consistent) ordering.
+ *
+ * Return: Success: A value like strcmp()
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_sec2_t *f1 = (const H5FD_sec2_t *)_f1;
+ const H5FD_sec2_t *f2 = (const H5FD_sec2_t *)_f2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_WIN32_API
+ if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1)
+ if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1)
+
+ if(f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1)
+ if(f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1)
+
+ if(f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1)
+ if(f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1)
+#else /* H5_HAVE_WIN32_API */
+#ifdef H5_DEV_T_IS_SCALAR
+ if(f1->device < f2->device) HGOTO_DONE(-1)
+ if(f1->device > f2->device) HGOTO_DONE(1)
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) HGOTO_DONE(-1)
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) HGOTO_DONE(1)
+#endif /* H5_DEV_T_IS_SCALAR */
+ if(f1->inode < f2->inode) HGOTO_DONE(-1)
+ if(f1->inode > f2->inode) HGOTO_DONE(1)
+#endif /* H5_HAVE_WIN32_API */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
+{
+ const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file; /* sec2 VFD info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
+ *flags |= H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */
+
+ /* Check for flags that are set by h5repart */
+ if(file && file->fam_to_sec2)
+ *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_sec2_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: The end-of-address marker.
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+} /* end H5FD_sec2_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ file->eoa = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_sec2_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the filesystem end-of-file or the HDF5 end-of-address
+ * markers.
+ *
+ * Return: End of file address, the first address past the end of the
+ * "file", either the filesystem file or the HDF5 file.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_sec2_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eof)
+} /* end H5FD_sec2_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_get_handle
+ *
+ * Purpose: Returns the file handle of sec2 file driver.
+ *
+ * Returns: SUCCEED/FAIL
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void **file_handle)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+
+ *file_handle = &(file->fd);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_get_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: SUCCEED. Result is stored in caller-supplied
+ * buffer BUF.
+ * Failure: FAIL, Contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id,
+ haddr_t addr, size_t size, void *buf /*out*/)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
+
+ /* Seek to the correct location */
+ if(addr != file->pos || OP_READ != file->op) {
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ } /* end if */
+
+ /* Read data, being careful of interrupted system calls, partial results,
+ * and the end of the file.
+ */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to read */
+ h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
+
+ /* Trying to read more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_read = HDread(file->fd, buf, bytes_in);
+ } while(-1 == bytes_read && EINTR == errno);
+
+ if(-1 == bytes_read) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)myoffset);
+ } /* end if */
+
+ if(0 == bytes_read) {
+ /* end of file but not end of format address space */
+ HDmemset(buf, 0, size);
+ break;
+ } /* end if */
+
+ HDassert(bytes_read >= 0);
+ HDassert((size_t)bytes_read <= size);
+
+ size -= (size_t)bytes_read;
+ addr += (haddr_t)bytes_read;
+ buf = (char *)buf + bytes_read;
+ } /* end while */
+
+ /* Update current position */
+ file->pos = addr;
+ file->op = OP_READ;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id,
+ haddr_t addr, size_t size, const void *buf)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu", (unsigned long long)addr, (unsigned long long)size)
+
+ /* Seek to the correct location */
+ if(addr != file->pos || OP_WRITE != file->op) {
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ } /* end if */
+
+ /* Write the data, being careful of interrupted system calls and partial
+ * results
+ */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to write */
+ h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
+
+ /* Trying to write more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+ bytes_wrote = HDwrite(file->fd, buf, bytes_in);
+ } while(-1 == bytes_wrote && EINTR == errno);
+
+ if(-1 == bytes_wrote) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = %llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)myoffset);
+ } /* end if */
+
+ HDassert(bytes_wrote > 0);
+ HDassert((size_t)bytes_wrote <= size);
+
+ size -= (size_t)bytes_wrote;
+ addr += (haddr_t)bytes_wrote;
+ buf = (const char *)buf + bytes_wrote;
+ } /* end while */
+
+ /* Update current position and eof */
+ file->pos = addr;
+ file->op = OP_WRITE;
+ if(file->pos > file->eof)
+ file->eof = file->pos;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Extend the file to make sure it's large enough */
+ if(!H5F_addr_eq(file->eoa, file->eof)) {
+#ifdef H5_HAVE_WIN32_API
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#else /* H5_HAVE_WIN32_API */
+ if(-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Update the eof value */
+ file->eof = file->eoa;
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
+ int lock_flags; /* file locking flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Set exclusive or shared lock based on rw status */
+ lock_flags = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place a non-blocking lock on the file */
+ if(HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_unlock(H5FD_t *_file)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_unlock() */
+
diff --git a/src/H5FDsec2.h b/src/H5FDsec2.h
new file mode 100644
index 0000000..a4ade0b
--- /dev/null
+++ b/src/H5FDsec2.h
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the sec2 driver.
+ */
+#ifndef H5FDsec2_H
+#define H5FDsec2_H
+
+#define H5FD_SEC2 (H5FD_sec2_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5_DLL hid_t H5FD_sec2_init(void);
+H5_DLL herr_t H5Pset_fapl_sec2(hid_t fapl_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5FDspace.c b/src/H5FDspace.c
new file mode 100644
index 0000000..e451d6b
--- /dev/null
+++ b/src/H5FDspace.c
@@ -0,0 +1,458 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FDspace.c
+ * Jan 3 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Space allocation routines for the file driver code.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDpkg.h" /* File Drivers */
+#include "H5FDmulti.h" /* Usage-partitioned file family */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Define this to display information about file allocations */
+/* #define H5FD_ALLOC_DEBUG */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5FD_free_t struct */
+H5FL_DEFINE(H5FD_free_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_extend
+ *
+ * Purpose: Extend the EOA space of a file.
+ *
+ * NOTE: Returns absolute file offset
+ *
+ * Return: Success: The address of the previous EOA.
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Bill Wendling
+ * Wednesday, 04. December, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_extend(H5FD_t *file, H5FD_mem_t type, hsize_t size)
+{
+ hsize_t orig_size = size; /* Original allocation size */
+ haddr_t eoa; /* Address of end-of-allocated space */
+ hsize_t extra; /* Extra space to allocate, to align request */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Get current end-of-allocated space address */
+ eoa = file->cls->get_eoa(file, type);
+
+ /* Check for overflow when extending */
+ if(H5F_addr_overflow(eoa, size) || (eoa + size) > file->maxaddr)
+ HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed")
+
+ /* Set the [NOT aligned] address to return */
+ ret_value = eoa;
+
+ /* Extend the end-of-allocated space address */
+ eoa += size;
+ if(file->cls->set_eoa(file, type, eoa) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_extend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_alloc_real
+ *
+ * Purpose: Allocate space in the file with the VFD
+ * Note: the handling of alignment is moved up from each driver to
+ * this routine.
+ *
+ * Return: Success: The format address of the new file memory.
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_alloc_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, hsize_t size,
+ haddr_t *frag_addr, hsize_t *frag_size)
+{
+ hsize_t orig_size = size; /* Original allocation size */
+ haddr_t eoa; /* Address of end-of-allocated space */
+ hsize_t extra; /* Extra space to allocate, to align request */
+ unsigned long flags = 0; /* Driver feature flags */
+ hbool_t use_alloc_size; /* Just pass alloc size to the driver */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size);
+#endif /* H5FD_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Check for query driver and call it */
+ if(file->cls->query)
+ (file->cls->query)(file, &flags);
+
+ /* Check for the driver feature flag */
+ use_alloc_size = flags & H5FD_FEAT_USE_ALLOC_SIZE;
+
+ /* Get current end-of-allocated space address */
+ eoa = file->cls->get_eoa(file, type);
+
+ /* Compute extra space to allocate, if this should be aligned */
+ extra = 0;
+ if(!file->paged_aggr && file->alignment > 1 && orig_size >= file->threshold) {
+ hsize_t mis_align; /* Amount EOA is misaligned */
+
+ /* Check for EOA already aligned */
+ if((mis_align = (eoa % file->alignment)) > 0) {
+ extra = file->alignment - mis_align;
+ if(frag_addr)
+ *frag_addr = eoa - file->base_addr; /* adjust for file's base address */
+ if(frag_size)
+ *frag_size = extra;
+ } /* end if */
+ } /* end if */
+
+ /* Dispatch to driver `alloc' callback or extend the end-of-address marker */
+ /* For the multi/split driver: the size passed down to the alloc callback is the original size from H5FD_alloc() */
+ /* For all other drivers: the size passed down to the alloc callback is the size + [possibly] alignment size */
+ if(file->cls->alloc) {
+ ret_value = (file->cls->alloc)(file, type, dxpl_id, use_alloc_size ? size : size + extra);
+ if(!H5F_addr_defined(ret_value))
+ HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver allocation request failed")
+ } /* end if */
+ else {
+ ret_value = H5FD_extend(file, type, size + extra);
+ if(!H5F_addr_defined(ret_value))
+ HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver eoa update request failed")
+ } /* end else */
+
+ /* Set the [possibly aligned] address to return */
+ if(!use_alloc_size)
+ ret_value += extra;
+
+ /* Post-condition sanity check */
+ if(!file->paged_aggr && file->alignment > 1 && orig_size >= file->threshold)
+ HDassert(!(ret_value % file->alignment));
+
+ /* Convert absolute file offset to relative address */
+ ret_value -= file->base_addr;
+
+done:
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value);
+#endif /* H5FD_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_alloc_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_alloc
+ *
+ * Purpose: Wrapper for H5FD_alloc, to make certain EOA changes are
+ * reflected in superblock.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: The format address of the new file memory.
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 14, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5FD_alloc(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, H5F_t *f, hsize_t size,
+ haddr_t *frag_addr, hsize_t *frag_size)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ /* check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Call the real 'alloc' routine */
+ ret_value = H5FD_alloc_real(file, dxpl_id, type, size, frag_addr, frag_size);
+ if(!H5F_addr_defined(ret_value))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "real 'alloc' request failed")
+
+ /* Mark EOA info dirty in cache, so change will get encoded */
+ if(H5F_eoa_dirty(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, HADDR_UNDEF, "unable to mark EOA info as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_free_real
+ *
+ * Purpose: Release space back to the VFD
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_free_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, hsize_t size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size);
+#endif /* H5FD_ALLOC_DEBUG */
+
+ /* Sanity checking */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid file offset")
+
+ /* Convert address to absolute file offset */
+ addr += file->base_addr;
+
+ /* More sanity checking */
+ if(addr > file->maxaddr || H5F_addr_overflow(addr, size) || (addr + size) > file->maxaddr)
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid file free space region to free")
+
+ /* Check for file driver 'free' callback and call it if available */
+ if(file->cls->free) {
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Letting VFD free space\n", FUNC);
+#endif /* H5FD_ALLOC_DEBUG */
+ if((file->cls->free)(file, type, dxpl_id, addr, size) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "driver free request failed")
+ } /* end if */
+ /* Check if this free block is at the end of file allocated space.
+ * Truncate it if this is true.
+ */
+ else if(file->cls->get_eoa) {
+ haddr_t eoa;
+
+ eoa = file->cls->get_eoa(file, type);
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: eoa = %a\n", FUNC, eoa);
+#endif /* H5FD_ALLOC_DEBUG */
+ if(eoa == (addr + size)) {
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Reducing file size to = %a\n", FUNC, addr);
+#endif /* H5FD_ALLOC_DEBUG */
+ if(file->cls->set_eoa(file, type, addr) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "set end of space allocation request failed")
+ } /* end if */
+ } /* end else-if */
+ else {
+ /* leak memory */
+#ifdef H5FD_ALLOC_DEBUG
+HDfprintf(stderr, "%s: LEAKED MEMORY!!! type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size);
+#endif /* H5FD_ALLOC_DEBUG */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_free_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_free
+ *
+ * Purpose: Wrapper for H5FD_free_real, to make certain EOA changes are
+ * reflected in superblock.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 14, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_free(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, H5F_t *f,
+ haddr_t addr, hsize_t size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Call the real 'free' routine */
+ if(H5FD_free_real(file, dxpl_id, type, addr, size) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "real 'free' request failed")
+
+ /* Mark EOA info dirty in cache, so change will get encoded */
+ if(H5F_eoa_dirty(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, FAIL, "unable to mark EOA info as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_try_extend
+ *
+ * Purpose: Extend a block at the end of the file, if possible.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: TRUE(1) - Block was extended
+ * FALSE(0) - Block could not be extended
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, 17. January, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FD_try_extend(H5FD_t *file, H5FD_mem_t type, H5F_t *f, hid_t dxpl_id,
+ haddr_t blk_end, hsize_t extra_requested)
+{
+ haddr_t eoa; /* End of allocated space in file */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(file);
+ HDassert(file->cls);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(extra_requested > 0);
+ HDassert(f);
+
+ /* Retrieve the end of the address space */
+ if(HADDR_UNDEF == (eoa = file->cls->get_eoa(file, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* Adjust block end by base address of the file, to create absolute address */
+ blk_end += file->base_addr;
+
+ /* Check if the block is exactly at the end of the file */
+ if(H5F_addr_eq(blk_end, eoa)) {
+ /* Extend the object by extending the underlying file */
+ if(HADDR_UNDEF == H5FD_extend(file, type, extra_requested))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTEXTEND, FAIL, "driver extend request failed")
+
+ /* Mark EOA info dirty in cache, so change will get encoded */
+ if(H5F_eoa_dirty(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, FAIL, "unable to mark EOA info as dirty")
+
+ /* Indicate success */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_try_extend() */
+
diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c
new file mode 100644
index 0000000..5023af3
--- /dev/null
+++ b/src/H5FDstdio.c
@@ -0,0 +1,1174 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, October 22, 1997
+ *
+ * Purpose: The C STDIO virtual file driver which only uses calls from stdio.h.
+ * This also serves as an example of coding a simple file driver,
+ * therefore, it should not use any non-public definitions.
+ *
+ * NOTE: This driver is not as well tested as the standard SEC2 driver
+ * and is not intended for production use!
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "hdf5.h"
+
+#ifdef H5_HAVE_FLOCK
+/* Needed for lock type definitions (e.g., LOCK_EX) */
+#include <sys/file.h>
+#endif /* H5_HAVE_FLOCK */
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef H5_HAVE_WIN32_API
+/* The following two defines must be before any windows headers are included */
+#define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
+#define NOGDI /* Exclude Graphic Display Interface macros */
+
+#include <windows.h>
+#include <io.h>
+
+#endif /* H5_HAVE_WIN32_API */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_STDIO_g = 0;
+
+/* The maximum number of bytes which can be written in a single I/O operation */
+static size_t H5_STDIO_MAX_IO_BYTES_g = (size_t)-1;
+
+/* File operations */
+typedef enum {
+ H5FD_STDIO_OP_UNKNOWN=0,
+ H5FD_STDIO_OP_READ=1,
+ H5FD_STDIO_OP_WRITE=2,
+ H5FD_STDIO_OP_SEEK=3
+} H5FD_stdio_file_op;
+
+/* The description of a file belonging to this driver. The 'eoa' and 'eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying Unix file). The 'pos'
+ * value is used to eliminate file position updates when they would be a
+ * no-op. Unfortunately we've found systems that use separate file position
+ * indicators for reading and writing so the lseek can only be eliminated if
+ * the current operation is the same as the previous operation. When opening
+ * a file the 'eof' will be set to the current file size, 'eoa' will be set
+ * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
+ * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
+ */
+typedef struct H5FD_stdio_t {
+ H5FD_t pub; /* public stuff, must be first */
+ FILE *fp; /* the file handle */
+ int fd; /* file descriptor (for truncate) */
+ haddr_t eoa; /* end of allocated region */
+ haddr_t eof; /* end of file; current file size */
+ haddr_t pos; /* current file I/O position */
+ unsigned write_access; /* Flag to indicate the file was opened with write access */
+ H5FD_stdio_file_op op; /* last operation */
+#ifndef H5_HAVE_WIN32_API
+ /* On most systems the combination of device and i-node number uniquely
+ * identify a file. Note that Cygwin, MinGW and other Windows POSIX
+ * environments have the stat function (which fakes inodes)
+ * and will use the 'device + inodes' scheme as opposed to the
+ * Windows code further below.
+ */
+ dev_t device; /* file device number */
+ ino_t inode; /* file i-node number */
+#else
+ /* Files in windows are uniquely identified by the volume serial
+ * number and the file index (both low and high parts).
+ *
+ * There are caveats where these numbers can change, especially
+ * on FAT file systems. On NTFS, however, a file should keep
+ * those numbers the same until renamed or deleted (though you
+ * can use ReplaceFile() on NTFS to keep the numbers the same
+ * while renaming).
+ *
+ * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
+ * more information.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
+ */
+ DWORD nFileIndexLow;
+ DWORD nFileIndexHigh;
+ DWORD dwVolumeSerialNumber;
+
+ HANDLE hFile; /* Native windows file handle */
+#endif /* H5_HAVE_WIN32_API */
+} H5FD_stdio_t;
+
+/* Use similar structure as in H5private.h by defining Windows stuff first. */
+#ifdef H5_HAVE_WIN32_API
+#ifndef H5_HAVE_MINGW
+ #define file_fseek _fseeki64
+ #define file_offset_t __int64
+ #define file_ftruncate _chsize_s /* Supported in VS 2005 or newer */
+ #define file_ftell _ftelli64
+#endif /* H5_HAVE_MINGW */
+#endif /* H5_HAVE_WIN32_API */
+
+/* If these functions weren't re-defined for Windows, give them
+ * more platform-independent names.
+ */
+#ifndef file_fseek
+ #define file_fseek fseeko
+ #define file_offset_t off_t
+ #define file_ftruncate ftruncate
+ #define file_ftell ftello
+#endif /* file_fseek */
+
+/* These macros check for overflow of various quantities. These macros
+ * assume that file_offset_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely by the second
+ * argument of the file seek function.
+ */
+/* adding for windows NT filesystem support. */
+#define MAXADDR (((haddr_t)1<<(8*sizeof(file_offset_t)-1))-1)
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
+#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || (file_offset_t)((A)+(Z))<(file_offset_t)(A))
+
+/* Prototypes */
+static herr_t H5FD_stdio_term(void);
+static H5FD_t *H5FD_stdio_open(const char *name, unsigned flags,
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_stdio_close(H5FD_t *lf);
+static int H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_stdio_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+static haddr_t H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_stdio_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_stdio_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
+static herr_t H5FD_stdio_read(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, void *buf);
+static herr_t H5FD_stdio_write(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
+ size_t size, const void *buf);
+static herr_t H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_stdio_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_stdio_unlock(H5FD_t *_file);
+
+static const H5FD_class_t H5FD_stdio_g = {
+ "stdio", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_stdio_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ 0, /* fapl_size */
+ NULL, /* fapl_get */
+ NULL, /* fapl_copy */
+ NULL, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_stdio_open, /* open */
+ H5FD_stdio_close, /* close */
+ H5FD_stdio_cmp, /* cmp */
+ H5FD_stdio_query, /* query */
+ NULL, /* get_type_map */
+ H5FD_stdio_alloc, /* alloc */
+ NULL, /* free */
+ H5FD_stdio_get_eoa, /* get_eoa */
+ H5FD_stdio_set_eoa, /* set_eoa */
+ H5FD_stdio_get_eof, /* get_eof */
+ H5FD_stdio_get_handle, /* get_handle */
+ H5FD_stdio_read, /* read */
+ H5FD_stdio_write, /* write */
+ H5FD_stdio_flush, /* flush */
+ H5FD_stdio_truncate, /* truncate */
+ H5FD_stdio_lock, /* lock */
+ H5FD_stdio_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the stdio driver.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_stdio_init(void)
+{
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if (H5I_VFL!=H5Iget_type(H5FD_STDIO_g))
+ H5FD_STDIO_g = H5FDregister(&H5FD_stdio_g);
+ return H5FD_STDIO_g;
+} /* end H5FD_stdio_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_stdio_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: Non-negative on success or negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_term(void)
+{
+ /* Reset VFL ID */
+ H5FD_STDIO_g = 0;
+
+ return 0;
+} /* end H5FD_stdio_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_stdio
+ *
+ * Purpose: Modify the file access property list to use the H5FD_STDIO
+ * driver defined in this source file. There are no driver
+ * specific properties.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_stdio(hid_t fapl_id)
+{
+ static const char *func = "H5FDset_fapl_stdio"; /*for error reporting*/
+
+ /*NO TRACE*/
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if(0 == H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not a file access property list", -1)
+
+ return H5Pset_driver(fapl_id, H5FD_STDIO, NULL);
+} /* end H5Pset_fapl_stdio() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_open
+ *
+ * Purpose: Create and/or opens a Standard C file as an HDF5 file.
+ *
+ * Errors:
+ * IO CANTOPENFILE File doesn't exist and CREAT wasn't
+ * specified.
+ * IO CANTOPENFILE fopen() failed.
+ * IO FILEEXISTS File exists but CREAT and EXCL were
+ * specified.
+ *
+ * Return:
+ * Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 22, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_stdio_open( const char *name, unsigned flags, hid_t /*UNUSED*/ fapl_id,
+ haddr_t maxaddr)
+{
+ FILE *f = NULL;
+ unsigned write_access = 0; /* File opened with write access? */
+ H5FD_stdio_t *file = NULL;
+ static const char *func = "H5FD_stdio_open"; /* Function Name for error reporting */
+#ifdef H5_HAVE_WIN32_API
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#else /* H5_HAVE_WIN32_API */
+ struct stat sb;
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Sanity check on file offsets */
+ assert(sizeof(file_offset_t) >= sizeof(size_t));
+
+ /* Quiet compiler */
+ fapl_id = fapl_id;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check arguments */
+ if (!name || !*name)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL)
+ if (0 == maxaddr || HADDR_UNDEF == maxaddr)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL)
+ if (ADDR_OVERFLOW(maxaddr))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_OVERFLOW, "maxaddr too large", NULL)
+
+ /* Tentatively open file in read-only mode, to check for existence */
+ if(flags & H5F_ACC_RDWR)
+ f = fopen(name, "rb+");
+ else
+ f = fopen(name, "rb");
+
+ if(!f) {
+ /* File doesn't exist */
+ if(flags & H5F_ACC_CREAT) {
+ assert(flags & H5F_ACC_RDWR);
+ f = fopen(name, "wb+");
+ write_access = 1; /* Note the write access */
+ }
+ else
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "file doesn't exist and CREAT wasn't specified", NULL)
+ } else if(flags & H5F_ACC_EXCL) {
+ /* File exists, but EXCL is passed. Fail. */
+ assert(flags & H5F_ACC_CREAT);
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FILEEXISTS, "file exists but CREAT and EXCL were specified", NULL)
+ } else if(flags & H5F_ACC_RDWR) {
+ if(flags & H5F_ACC_TRUNC)
+ f = freopen(name, "wb+", f);
+ write_access = 1; /* Note the write access */
+ } /* end if */
+ /* Note there is no need to reopen if neither TRUNC nor EXCL are specified,
+ * as the tentative open will work */
+
+ if(!f)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "fopen failed", NULL)
+
+ /* Build the return value */
+ if(NULL == (file = (H5FD_stdio_t *)calloc((size_t)1, sizeof(H5FD_stdio_t)))) {
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL)
+ } /* end if */
+ file->fp = f;
+ file->op = H5FD_STDIO_OP_SEEK;
+ file->pos = HADDR_UNDEF;
+ file->write_access = write_access; /* Note the write_access for later */
+ if(file_fseek(file->fp, (file_offset_t)0, SEEK_END) < 0) {
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ } else {
+ file_offset_t x = file_ftell(file->fp);
+ assert (x >= 0);
+ file->eof = (haddr_t)x;
+ }
+
+ /* Get the file descriptor (needed for truncate and some Windows information) */
+#ifdef H5_HAVE_WIN32_API
+ file->fd = _fileno(file->fp);
+#else /* H5_HAVE_WIN32_API */
+ file->fd = fileno(file->fp);
+#endif /* H5_HAVE_WIN32_API */
+ if(file->fd < 0) {
+ free(file);
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get file descriptor", NULL);
+ } /* end if */
+
+
+#ifdef H5_HAVE_WIN32_API
+ file->hFile = (HANDLE)_get_osfhandle(file->fd);
+ if(INVALID_HANDLE_VALUE == file->hFile) {
+ free(file);
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file handle", NULL);
+ } /* end if */
+
+ if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo)) {
+ free(file);
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file descriptor information", NULL);
+ } /* end if */
+
+ file->nFileIndexHigh = fileinfo.nFileIndexHigh;
+ file->nFileIndexLow = fileinfo.nFileIndexLow;
+ file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
+#else /* H5_HAVE_WIN32_API */
+ if(fstat(file->fd, &sb) < 0) {
+ free(file);
+ fclose(f);
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADFILE, "unable to fstat file", NULL)
+ } /* end if */
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /* H5_HAVE_WIN32_API */
+
+ return((H5FD_t*)file);
+} /* end H5FD_stdio_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_stdio_close
+ *
+ * Purpose: Closes a file.
+ *
+ * Errors:
+ * IO CLOSEERROR Fclose failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 22, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_close(H5FD_t *_file)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ static const char *func = "H5FD_stdio_close"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ if (fclose(file->fp) < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CLOSEERROR, "fclose failed", -1)
+
+ free(file);
+
+ return 0;
+} /* end H5FD_stdio_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_cmp
+ *
+ * Purpose: Compares two files belonging to this driver using an
+ * arbitrary (but consistent) ordering.
+ *
+ * Return:
+ * Success: A value like strcmp()
+ *
+ * Failure: never fails (arguments were checked by the caller).
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_stdio_t *f1 = (const H5FD_stdio_t*)_f1;
+ const H5FD_stdio_t *f2 = (const H5FD_stdio_t*)_f2;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+#ifdef H5_HAVE_WIN32_API
+ if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) return -1;
+ if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) return 1;
+
+ if(f1->nFileIndexHigh < f2->nFileIndexHigh) return -1;
+ if(f1->nFileIndexHigh > f2->nFileIndexHigh) return 1;
+
+ if(f1->nFileIndexLow < f2->nFileIndexLow) return -1;
+ if(f1->nFileIndexLow > f2->nFileIndexLow) return 1;
+#else /* H5_HAVE_WIN32_API */
+#ifdef H5_DEV_T_IS_SCALAR
+ if(f1->device < f2->device) return -1;
+ if(f1->device > f2->device) return 1;
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) return -1;
+ if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) return 1;
+#endif /* H5_DEV_T_IS_SCALAR */
+ if(f1->inode < f2->inode) return -1;
+ if(f1->inode > f2->inode) return 1;
+#endif /* H5_HAVE_WIN32_API */
+
+ return 0;
+} /* H5FD_stdio_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_query(const H5FD_t *_f, unsigned long /*OUT*/ *flags)
+{
+ /* Quiet the compiler */
+ _f=_f;
+
+ /* Set the VFL feature flags that this driver supports.
+ *
+ * Note that this VFD does not support SWMR due to the unpredictable
+ * nature of the buffering layer.
+ */
+ if(flags) {
+ *flags = 0;
+ *flags|=H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags|=H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags|=H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ }
+
+ return 0;
+} /* end H5FD_stdio_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_alloc
+ *
+ * Purpose: Allocates file memory. If fseeko isn't available, makes
+ * sure the file size isn't bigger than 2GB because the
+ * parameter OFFSET of fseek is of the type LONG INT, limiting
+ * the file size to 2GB.
+ *
+ * Return:
+ * Success: Address of new memory
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Raymond Lu
+ * 30 March 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id, hsize_t size)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ haddr_t addr;
+
+ /* Quiet compiler */
+ type = type;
+ dxpl_id = dxpl_id;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Compute the address for the block to allocate */
+ addr = file->eoa;
+
+ file->eoa = addr + size;
+
+ return addr;
+} /* end H5FD_stdio_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: Success: The end-of-address marker.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
+{
+ const H5FD_stdio_t *file = (const H5FD_stdio_t *)_file;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Quiet compiler */
+ type = type;
+
+ return file->eoa;
+} /* end H5FD_stdio_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: Success: 0
+ *
+ * Failure: Does not fail
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, haddr_t addr)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Quiet the compiler */
+ type = type;
+
+ file->eoa = addr;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the Unix end-of-file or the HDF5 end-of-address
+ * markers.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the "file", either the Unix file
+ * or the HDF5 file.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_stdio_get_eof(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
+{
+ const H5FD_stdio_t *file = (const H5FD_stdio_t *)_file;
+
+ /* Quiet the compiler */
+ type = type;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Quiet the compiler */
+ type = type;
+
+ return(file->eof);
+} /* end H5FD_stdio_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_get_handle
+ *
+ * Purpose: Returns the file handle of stdio file driver.
+ *
+ * Returns: Non-negative if succeed or negative if fails.
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_get_handle(H5FD_t *_file, hid_t /*UNUSED*/ fapl, void **file_handle)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t *)_file;
+ static const char *func = "H5FD_stdio_get_handle"; /* Function Name for error reporting */
+
+ /* Quiet the compiler */
+ fapl = fapl;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ *file_handle = &(file->fp);
+ if(*file_handle == NULL)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "get handle failed", -1)
+
+ return 0;
+} /* end H5FD_stdio_get_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_read
+ *
+ * Purpose: Reads SIZE bytes beginning at address ADDR in file LF and
+ * places them in buffer BUF. Reading past the logical or
+ * physical end of file returns zeros instead of failing.
+ *
+ * Errors:
+ * IO READERROR fread failed.
+ * IO SEEKERROR fseek failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 22, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_read(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
+ haddr_t addr, size_t size, void /*OUT*/ *buf)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ static const char *func = "H5FD_stdio_read"; /* Function Name for error reporting */
+
+ /* Quiet the compiler */
+ type = type;
+ dxpl_id = dxpl_id;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check for overflow */
+ if (HADDR_UNDEF==addr)
+ H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
+ if (REGION_OVERFLOW(addr, size))
+ H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
+
+ /* Check easy cases */
+ if (0 == size)
+ return 0;
+ if ((haddr_t)addr >= file->eof) {
+ memset(buf, 0, size);
+ return 0;
+ }
+
+ /* Seek to the correct file position. */
+ if (!(file->op == H5FD_STDIO_OP_READ || file->op == H5FD_STDIO_OP_SEEK) ||
+ file->pos != addr) {
+ if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) {
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ file->pos = HADDR_UNDEF;
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "fseek failed", -1)
+ }
+ file->pos = addr;
+ }
+
+ /* Read zeros past the logical end of file (physical is handled below) */
+ if (addr + size > file->eof) {
+ size_t nbytes = (size_t) (addr + size - file->eof);
+ memset((unsigned char *)buf + size - nbytes, 0, nbytes);
+ size -= nbytes;
+ }
+
+ /* Read the data. Since we're reading single-byte values, a partial read
+ * will advance the file position by N. If N is zero or an error
+ * occurs then the file position is undefined.
+ */
+ while(size > 0) {
+
+ size_t bytes_in = 0; /* # of bytes to read */
+ size_t bytes_read = 0; /* # of bytes actually read */
+ size_t item_size = 1; /* size of items in bytes */
+
+ if(size > H5_STDIO_MAX_IO_BYTES_g)
+ bytes_in = H5_STDIO_MAX_IO_BYTES_g;
+ else
+ bytes_in = size;
+
+ bytes_read = fread(buf, item_size, bytes_in, file->fp);
+
+ if(0 == bytes_read && ferror(file->fp)) { /* error */
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ file->pos = HADDR_UNDEF;
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "fread failed", -1)
+ } /* end if */
+
+ if(0 == bytes_read && feof(file->fp)) {
+ /* end of file but not end of format address space */
+ memset((unsigned char *)buf, 0, size);
+ break;
+ } /* end if */
+
+ size -= bytes_read;
+ addr += (haddr_t)bytes_read;
+ buf = (char *)buf + bytes_read;
+ } /* end while */
+
+ /* Update the file position data. */
+ file->op = H5FD_STDIO_OP_READ;
+ file->pos = addr;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_write
+ *
+ * Purpose: Writes SIZE bytes from the beginning of BUF into file LF at
+ * file address ADDR.
+ *
+ * Errors:
+ * IO SEEKERROR fseek failed.
+ * IO WRITEERROR fwrite failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 22, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_write(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
+ haddr_t addr, size_t size, const void *buf)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ static const char *func = "H5FD_stdio_write"; /* Function Name for error reporting */
+
+ /* Quiet the compiler */
+ dxpl_id = dxpl_id;
+ type = type;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check for overflow conditions */
+ if (HADDR_UNDEF == addr)
+ H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
+ if (REGION_OVERFLOW(addr, size))
+ H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
+
+ /* Seek to the correct file position. */
+ if ((file->op != H5FD_STDIO_OP_WRITE && file->op != H5FD_STDIO_OP_SEEK) ||
+ file->pos != addr) {
+ if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) {
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ file->pos = HADDR_UNDEF;
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "fseek failed", -1)
+ }
+ file->pos = addr;
+ }
+
+ /* Write the buffer. On successful return, the file position will be
+ * advanced by the number of bytes read. On failure, the file position is
+ * undefined.
+ */
+ while(size > 0) {
+
+ size_t bytes_in = 0; /* # of bytes to write */
+ size_t bytes_wrote = 0; /* # of bytes written */
+ size_t item_size = 1; /* size of items in bytes */
+
+ if(size > H5_STDIO_MAX_IO_BYTES_g)
+ bytes_in = H5_STDIO_MAX_IO_BYTES_g;
+ else
+ bytes_in = size;
+
+ bytes_wrote = fwrite(buf, item_size, bytes_in, file->fp);
+
+ if(bytes_wrote != bytes_in || (0 == bytes_wrote && ferror(file->fp))) { /* error */
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ file->pos = HADDR_UNDEF;
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fwrite failed", -1)
+ } /* end if */
+
+ assert(bytes_wrote > 0);
+ assert((size_t)bytes_wrote <= size);
+
+ size -= bytes_wrote;
+ addr += (haddr_t)bytes_wrote;
+ buf = (const char *)buf + bytes_wrote;
+ }
+
+ /* Update seek optimizing data. */
+ file->op = H5FD_STDIO_OP_WRITE;
+ file->pos = addr;
+
+ /* Update EOF if necessary */
+ if (file->pos > file->eof)
+ file->eof = file->pos;
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_flush
+ *
+ * Purpose: Makes sure that all data is on disk.
+ *
+ * Errors:
+ * IO SEEKERROR fseek failed.
+ * IO WRITEERROR fflush or fwrite failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 22, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_flush(H5FD_t *_file, hid_t /*UNUSED*/ dxpl_id, hbool_t closing)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ static const char *func = "H5FD_stdio_flush"; /* Function Name for error reporting */
+
+ /* Quiet the compiler */
+ dxpl_id = dxpl_id;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Only try to flush the file if we have write access */
+ if(file->write_access) {
+ if(!closing) {
+ if(fflush(file->fp) < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ } /* end if */
+ } /* end if */
+
+ return 0;
+} /* end H5FD_stdio_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Errors:
+ * IO SEEKERROR fseek failed.
+ * IO WRITEERROR fflush or fwrite failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 31, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_truncate(H5FD_t *_file, hid_t /*UNUSED*/ dxpl_id,
+ hbool_t /*UNUSED*/ closing)
+{
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file;
+ static const char *func = "H5FD_stdio_truncate"; /* Function Name for error reporting */
+
+ /* Quiet the compiler */
+ dxpl_id = dxpl_id;
+ closing = closing;
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Only try to flush the file if we have write access */
+ if(file->write_access) {
+ /* Makes sure that the true file size is the same as the end-of-address. */
+ if(file->eoa != file->eof) {
+
+#ifdef H5_HAVE_WIN32_API
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+
+ /* Reset seek offset to beginning of file, so that file isn't re-extended later */
+ rewind(file->fp);
+
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_FILEOPEN, "unable to set file pointer", -1)
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1)
+#else /* H5_HAVE_WIN32_API */
+ /* Reset seek offset to beginning of file, so that file isn't re-extended later */
+ rewind(file->fp);
+
+ /* Truncate file to proper length */
+ if(-1 == file_ftruncate(file->fd, (file_offset_t)file->eoa))
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1)
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Update the eof value */
+ file->eof = file->eoa;
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = H5FD_STDIO_OP_UNKNOWN;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Double-check for problems */
+ if(file->eoa > file->eof)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_TRUNCATED, "eoa > eof!", -1)
+ } /* end else */
+
+ return 0;
+} /* end H5FD_stdio_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_stdio_lock
+ *
+ * Purpose: Lock a file via flock
+ * NOTE: This function is a no-op if flock() is not present.
+ *
+ * Errors:
+ * IO FCNTL flock failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_lock(H5FD_t *_file, hbool_t rw)
+{
+#ifdef H5_HAVE_FLOCK
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file; /* VFD file struct */
+ int lock_flags; /* file locking flags */
+ static const char *func = "H5FD_stdio_lock"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ assert(file);
+
+ /* Set exclusive or shared lock based on rw status */
+ lock_flags = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place a non-blocking lock on the file */
+ if(flock(file->fd, lock_flags | LOCK_NB) < 0) {
+ if(ENOSYS == errno)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)", -1)
+ else
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file lock failed", -1)
+ } /* end if */
+
+ /* Flush the stream */
+ if(fflush(file->fp) < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
+
+#endif /* H5_HAVE_FLOCK */
+
+ return 0;
+} /* end H5FD_stdio_lock() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_stdio_unlock
+ *
+ * Purpose: Unlock a file via flock
+ * NOTE: This function is a no-op if flock() is not present.
+ *
+ * Errors:
+ * IO FCNTL flock failed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; March 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_stdio_unlock(H5FD_t *_file)
+{
+#ifdef H5_HAVE_FLOCK
+ H5FD_stdio_t *file = (H5FD_stdio_t*)_file; /* VFD file struct */
+ static const char *func = "H5FD_stdio_unlock"; /* Function Name for error reporting */
+
+ /* Clear the error stack */
+ H5Eclear2(H5E_DEFAULT);
+
+ assert(file);
+
+ /* Flush the stream */
+ if(fflush(file->fp) < 0)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
+
+ /* Place a non-blocking lock on the file */
+ if(flock(file->fd, LOCK_UN) < 0) {
+ if(ENOSYS == errno)
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)", -1)
+ else
+ H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file unlock failed", -1)
+ } /* end if */
+
+#endif /* H5_HAVE_FLOCK */
+
+ return 0;
+} /* end H5FD_stdio_unlock() */
+
+
+#ifdef _H5private_H
+/*
+ * This is not related to the functionality of the driver code.
+ * It is added here to trigger warning if HDF5 private definitions are included
+ * by mistake. The code should use only HDF5 public API and definitions.
+ */
+#error "Do not use HDF5 private definitions"
+#endif
+
diff --git a/src/H5FDstdio.h b/src/H5FDstdio.h
new file mode 100644
index 0000000..f99aacf
--- /dev/null
+++ b/src/H5FDstdio.h
@@ -0,0 +1,38 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the sec2 driver.
+ */
+#ifndef H5FDstdio_H
+#define H5FDstdio_H
+
+#include "H5Ipublic.h"
+
+#define H5FD_STDIO (H5FD_stdio_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5_DLL hid_t H5FD_stdio_init(void);
+H5_DLL herr_t H5Pset_fapl_stdio(hid_t fapl_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/H5FDtest.c b/src/H5FDtest.c
new file mode 100644
index 0000000..f528dfb
--- /dev/null
+++ b/src/H5FDtest.c
@@ -0,0 +1,116 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FDtest.c
+ * Fall 2014
+ *
+ * Purpose: File driver testing routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
+#define H5FD_TESTING /* Suppress warning about H5FD testing funcs */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5FDpkg.h" /* File Drivers */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_supports_swmr_test()
+ *
+ * Purpose: Determines if a VFD supports SWMR.
+ *
+ * The function determines SWMR support by inspecting the
+ * HDF5_DRIVER environment variable, not by checking the
+ * VFD feature flags (which do not exist until the driver
+ * is instantiated).
+ *
+ * See test/Makefile.am for a list of the VFD strings.
+ *
+ * This function is only intended for use in the test code.
+ *
+ * Return: TRUE (1) if the VFD supports SWMR I/O or vfd_name is
+ * NULL or the empty string (which implies the default VFD).
+ *
+ * FALSE (0) if it does not
+ *
+ * This function cannot fail at this time so there is no
+ * error return value.
+ *
+ * Programmer: Dana Robinson
+ * Fall 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_supports_swmr_test(const char *vfd_name)
+{
+ hbool_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(!vfd_name || !HDstrcmp(vfd_name, ""))
+ ret_value = TRUE;
+ else
+ ret_value = !HDstrcmp(vfd_name, "log")
+ || !HDstrcmp(vfd_name, "sec2");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD_supports_swmr_test() */
+
diff --git a/src/H5FDwindows.c b/src/H5FDwindows.c
new file mode 100644
index 0000000..76c4f18
--- /dev/null
+++ b/src/H5FDwindows.c
@@ -0,0 +1,67 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDwindows.h" /* Windows file driver */
+#include "H5FDsec2.h" /* Windows file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+#ifdef H5_HAVE_WINDOWS
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_windows
+ *
+ * Purpose: Modify the file access property list to use the H5FD_WINDOWS
+ * driver defined in this source file. There are no driver
+ * specific properties.
+ *
+ * NOTE: The Windows VFD was merely a merge of the SEC2 and STDIO drivers
+ * so it has been retired. Selecting the Windows VFD will actually
+ * set the SEC2 VFD (though for backwards compatibility, we'll keep
+ * the H5FD_WINDOWS symbol).
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_windows(hid_t fapl_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", fapl_id);
+
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ ret_value = H5P_set_driver(plist, H5FD_WINDOWS, NULL);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_windows() */
+
+#endif /* H5_HAVE_WINDOWS */
+
diff --git a/src/H5FDwindows.h b/src/H5FDwindows.h
new file mode 100644
index 0000000..5cf68a1
--- /dev/null
+++ b/src/H5FDwindows.h
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Scott Wegner <swegner@hdfgroup.org>
+ * Based on code by Robb Matzke
+ * Thursday, May 24 2007
+ *
+ * Purpose: The public header file for the windows driver.
+ */
+#ifndef H5FDwindows_H
+#define H5FDwindows_H
+
+#define H5FD_WINDOWS (H5FD_sec2_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+H5_DLL herr_t H5Pset_fapl_windows(hid_t fapl_id);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* H5FDwindows_H */
+
diff --git a/src/H5FL.c b/src/H5FL.c
new file mode 100644
index 0000000..0e67414
--- /dev/null
+++ b/src/H5FL.c
@@ -0,0 +1,2533 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, March 23, 2000
+ *
+ * Purpose: Manage priority queues of free-lists (of blocks of bytes).
+ * These are used in various places in the library which allocate and
+ * free differently blocks of bytes repeatedly. Usually the same size
+ * of block is allocated and freed repeatly in a loop, while writing out
+ * chunked data for example, but the blocks may also be of different sizes
+ * from different datasets and an attempt is made to optimize access to
+ * the proper free list of blocks by using these priority queues to
+ * move frequently accessed free lists to the head of the queue.
+ */
+
+#include "H5FLmodule.h" /* This source code file is part of the H5FL module */
+
+
+/* #define H5FL_DEBUG */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MMprivate.h" /* Memory management */
+
+/*
+ * Private type definitions
+ */
+
+/*
+ Default limits on how much memory can accumulate on each free list before
+ it is garbage collected.
+ */
+static size_t H5FL_reg_glb_mem_lim=1*1024*1024; /* Default to 1MB limit on all regular free lists */
+static size_t H5FL_reg_lst_mem_lim=1*65536; /* Default to 64KB limit on each regular free list */
+static size_t H5FL_arr_glb_mem_lim=4*1024*1024; /* Default to 4MB limit on all array free lists */
+static size_t H5FL_arr_lst_mem_lim=4*65536; /* Default to 256KB limit on each array free list */
+static size_t H5FL_blk_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all block free lists */
+static size_t H5FL_blk_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each block free list */
+static size_t H5FL_fac_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all factory free lists */
+static size_t H5FL_fac_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each factory free list */
+
+/* A garbage collection node for regular free lists */
+typedef struct H5FL_reg_gc_node_t {
+ H5FL_reg_head_t *list; /* Pointer to the head of the list to garbage collect */
+ struct H5FL_reg_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_reg_gc_node_t;
+
+/* The garbage collection head for regular free lists */
+typedef struct H5FL_reg_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_reg_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} H5FL_reg_gc_list_t;
+
+/* The head of the list of things to garbage collect */
+static H5FL_reg_gc_list_t H5FL_reg_gc_head={0,NULL};
+
+/* A garbage collection node for array free lists */
+typedef struct H5FL_gc_arr_node_t {
+ H5FL_arr_head_t *list; /* Pointer to the head of the list to garbage collect */
+ struct H5FL_gc_arr_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_gc_arr_node_t;
+
+/* The garbage collection head for array free lists */
+typedef struct H5FL_gc_arr_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_gc_arr_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} H5FL_gc_arr_list_t;
+
+/* The head of the list of array things to garbage collect */
+static H5FL_gc_arr_list_t H5FL_arr_gc_head={0,NULL};
+
+/* A garbage collection node for blocks */
+typedef struct H5FL_blk_gc_node_t {
+ H5FL_blk_head_t *pq; /* Pointer to the head of the PQ to garbage collect */
+ struct H5FL_blk_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_blk_gc_node_t;
+
+/* The garbage collection head for blocks */
+typedef struct H5FL_blk_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_blk_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} H5FL_blk_gc_list_t;
+
+/* The head of the list of PQs to garbage collect */
+static H5FL_blk_gc_list_t H5FL_blk_gc_head={0,NULL};
+
+/* A garbage collection node for factory free lists */
+struct H5FL_fac_gc_node_t {
+ H5FL_fac_head_t *list; /* Pointer to the head of the list to garbage collect */
+ struct H5FL_fac_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+};
+
+/* The garbage collection head for factory free lists */
+typedef struct H5FL_fac_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_fac_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} H5FL_fac_gc_list_t;
+
+/* Data structure to store each block in factory free list */
+struct H5FL_fac_node_t {
+ struct H5FL_fac_node_t *next; /* Pointer to next block in free list */
+};
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* The head of the list of factory things to garbage collect */
+static H5FL_fac_gc_list_t H5FL_fac_gc_head={0,NULL};
+
+#ifdef H5FL_TRACK
+
+/* Extra headers needed */
+#include "H5CSprivate.h" /* Function stack */
+
+/* Head of "outstanding allocations" list */
+static H5FL_track_t *H5FL_out_head_g = NULL;
+#endif /* H5FL_TRACK */
+
+/* Forward declarations of local static functions */
+static herr_t H5FL__reg_gc(void);
+static herr_t H5FL__reg_gc_list(H5FL_reg_head_t *head);
+static int H5FL__reg_term(void);
+static herr_t H5FL__arr_gc(void);
+static herr_t H5FL__arr_gc_list(H5FL_arr_head_t *head);
+static int H5FL__arr_term(void);
+static herr_t H5FL__blk_gc(void);
+static herr_t H5FL__blk_gc_list(H5FL_blk_head_t *head);
+static int H5FL__blk_term(void);
+static herr_t H5FL__fac_gc(void);
+static herr_t H5FL__fac_gc_list(H5FL_fac_head_t *head);
+static int H5FL__fac_term_all(void);
+
+/* Declare a free list to manage the H5FL_blk_node_t struct */
+H5FL_DEFINE(H5FL_blk_node_t);
+
+/* Declare a free list to manage the H5FL_fac_gc_node_t struct */
+H5FL_DEFINE(H5FL_fac_gc_node_t);
+
+/* Declare a free list to manage the H5FL_fac_head_t struct */
+H5FL_DEFINE(H5FL_fac_head_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FL_term_package
+ PURPOSE
+ Terminate various H5FL objects
+ USAGE
+ void H5FL_term_package()
+ RETURNS
+ Success: Positive if any action might have caused a change in some
+ other interface; zero otherwise.
+ Failure: Negative
+ DESCRIPTION
+ Release any resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5FL_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Garbage collect any nodes on the free lists */
+ (void)H5FL_garbage_coll();
+
+ /* Shut down the various kinds of free lists */
+ n += H5FL__reg_term();
+ n += H5FL__fac_term_all();
+ n += H5FL__arr_term();
+ n += H5FL__blk_term();
+
+ /* Mark interface closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+#ifdef H5FL_TRACK
+ /* If we haven't freed all the allocated memory, dump out the list now */
+ if(n > 0 && H5FL_out_head_g) {
+ H5FL_track_t *trk = H5FL_out_head_g;
+
+ /* Dump information about all the outstanding allocations */
+ while(trk != NULL) {
+ /* Print information about the outstanding block */
+ HDfprintf(stderr,"%s: Outstanding allocation:\n", FUNC);
+ HDfprintf(stderr,"\tPtr: %p, File: %s, Function: %s, Line: %d\n", (((unsigned char *)trk) + sizeof(H5FL_track_t)), trk->file, trk->func, trk->line);
+ H5CS_print_stack(trk->stack, stderr);
+
+ /* Advance to next node */
+ trk = trk->next;
+ } /* end while */
+ } /* end if */
+#endif /* H5FL_TRACK */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5FL_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_malloc
+ *
+ * Purpose: Attempt to allocate space using malloc. If malloc fails, garbage
+ * collect and try again. If malloc fails again, then return NULL.
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 1, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FL_malloc(size_t mem_size)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Attempt to allocate the memory requested */
+ if(NULL==(ret_value=H5MM_malloc(mem_size))) {
+ /* If we can't allocate the memory now, try garbage collecting first */
+ if(H5FL_garbage_coll()<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during allocation")
+
+ /* Now try allocating the memory again */
+ if(NULL==(ret_value=H5MM_malloc(mem_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for chunk")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_reg_init
+ *
+ * Purpose: Initialize a free list for a certain type. Right now, this just
+ * adds the free list to the list of things to garbage collect.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_reg_init(H5FL_reg_head_t *head)
+{
+ H5FL_reg_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
+ herr_t ret_value=SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate a new garbage collection node */
+ if(NULL == (new_node = (H5FL_reg_gc_node_t *)H5MM_malloc(sizeof(H5FL_reg_gc_node_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the new garbage collection node */
+ new_node->list = head;
+
+ /* Link in to the garbage collection list */
+ new_node->next=H5FL_reg_gc_head.first;
+ H5FL_reg_gc_head.first=new_node;
+
+ /* Indicate that the free list is initialized */
+ head->init = TRUE;
+
+ /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */
+ if(head->size<sizeof(H5FL_reg_node_t))
+ head->size=sizeof(H5FL_reg_node_t);
+
+ /* Make certain there's room for tracking information, if any */
+#ifdef H5FL_TRACK
+ head->size += sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_reg_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_reg_free
+ *
+ * Purpose: Release an object & put on free list
+ *
+ * Return: Always returns NULL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_reg_free(H5FL_reg_head_t *head, void *obj)
+{
+ void *ret_value=NULL; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_reg_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(obj);
+
+#ifdef H5FL_TRACK
+ {
+ H5FL_track_t *trk = obj = ((unsigned char *)obj) - sizeof(H5FL_track_t);
+
+ /* Free tracking information about the allocation location */
+ H5CS_close_stack(trk->stack);
+ trk->file = H5MM_xfree(trk->file);
+ trk->func = H5MM_xfree(trk->func);
+
+ /* Remove from "outstanding allocations" list */
+ if(trk == H5FL_out_head_g) {
+ H5FL_out_head_g = H5FL_out_head_g->next;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = NULL;
+ } /* end if */
+ else {
+ trk->prev->next = trk->next;
+ if(trk->next)
+ trk->next->prev = trk->prev;
+ } /* end else */
+ }
+#endif /* H5FL_TRACK */
+
+#ifdef H5FL_DEBUG
+ HDmemset(obj,255,head->size);
+#endif /* H5FL_DEBUG */
+
+ /* Make certain that the free list is initialized */
+ HDassert(head->init);
+
+ /* Link into the free list */
+ ((H5FL_reg_node_t *)obj)->next=head->list;
+
+ /* Point free list at the node freed */
+ head->list=(H5FL_reg_node_t *)obj;
+
+ /* Increment the number of blocks on free list */
+ head->onlist++;
+
+ /* Increment the amount of "regular" freed memory globally */
+ H5FL_reg_gc_head.mem_freed+=head->size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->onlist * head->size > H5FL_reg_lst_mem_lim)
+ if(H5FL__reg_gc_list(head) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+ /* Then check the global amount memory on regular free lists */
+ if(H5FL_reg_gc_head.mem_freed>H5FL_reg_glb_mem_lim)
+ if(H5FL__reg_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_reg_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_reg_malloc
+ *
+ * Purpose: Allocate a block on a free list
+ *
+ * Return: Success: Pointer to a valid object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to object to return */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+
+ /* Make certain the list is initialized first */
+ if(!head->init)
+ if(H5FL_reg_init(head)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'regular' blocks")
+
+ /* Check for nodes available on the free list first */
+ if(head->list!=NULL) {
+ /* Get a pointer to the block on the free list */
+ ret_value=(void *)(head->list);
+
+ /* Remove node from free list */
+ head->list=head->list->next;
+
+ /* Decrement the number of blocks & memory on free list */
+ head->onlist--;
+
+ /* Decrement the amount of global "regular" free list memory in use */
+ H5FL_reg_gc_head.mem_freed-=(head->size);
+ } /* end if */
+ /* Otherwise allocate a node */
+ else {
+ if (NULL==(ret_value = H5FL_malloc(head->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment the number of blocks allocated in list */
+ head->allocated++;
+ } /* end else */
+
+#ifdef H5FL_TRACK
+ /* Copy allocation location information */
+ ((H5FL_track_t *)ret_value)->stack = H5CS_copy_stack();
+ HDassert(((H5FL_track_t *)ret_value)->stack);
+ ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file);
+ ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func);
+ ((H5FL_track_t *)ret_value)->line = call_line;
+
+ /* Add to "outstanding allocations" list */
+ ((H5FL_track_t *)ret_value)->prev = NULL;
+ ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = (H5FL_track_t *)ret_value;
+ H5FL_out_head_g = (H5FL_track_t *)ret_value;
+
+ /* Adjust for allocation tracking information */
+ ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_reg_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_reg_calloc
+ *
+ * Purpose: Allocate a block on a free list and clear it to zeros
+ *
+ * Return: Success: Pointer to a valid object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to object to return */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+
+ /* Allocate the block */
+ if (NULL==(ret_value = H5FL_reg_malloc(head H5FL_TRACK_INFO_INT)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear to zeros */
+ /* (Accomodate tracking information, if present) */
+ HDmemset(ret_value,0,head->size - H5FL_TRACK_SIZE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_reg_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__reg_gc_list
+ *
+ * Purpose: Garbage collect on a particular object free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__reg_gc_list(H5FL_reg_head_t *head)
+{
+ H5FL_reg_node_t *free_list; /* Pointer to nodes in free list being garbage collected */
+ size_t total_mem; /* Total memory used on list */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Calculate the total memory used on this list */
+ total_mem = head->onlist * head->size;
+
+ /* For each free list being garbage collected, walk through the nodes and free them */
+ free_list = head->list;
+ while(free_list != NULL) {
+ void *tmp; /* Temporary node pointer */
+
+ tmp = free_list->next;
+
+ /* Decrement the count of nodes allocated and free the node */
+ head->allocated--;
+
+ H5MM_free(free_list);
+
+ free_list = (H5FL_reg_node_t *)tmp;
+ } /* end while */
+
+ /* Indicate no free nodes on the free list */
+ head->list = NULL;
+ head->onlist = 0;
+
+ /* Decrement global count of free memory on "regular" lists */
+ H5FL_reg_gc_head.mem_freed -= total_mem;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FL__reg_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__reg_gc
+ *
+ * Purpose: Garbage collect on all the object free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ * Broke into two parts, one for looping over all the free lists and
+ * another for freeing each list - QAK 7/25/00
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__reg_gc(void)
+{
+ H5FL_reg_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
+ herr_t ret_value = SUCCEED; /* return value*/
+
+ FUNC_ENTER_STATIC
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_node = H5FL_reg_gc_head.first;
+ while(gc_node != NULL) {
+ /* Release the free nodes on the list */
+ if(H5FL__reg_gc_list(gc_node->list) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed")
+
+ /* Go on to the next free list to garbage collect */
+ gc_node = gc_node->next;
+ } /* end while */
+
+ /* Double check that all the memory on the free lists is recycled */
+ HDassert(H5FL_reg_gc_head.mem_freed == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL__reg_gc() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FL_reg_term
+ PURPOSE
+ Terminate various H5FL object free lists
+ USAGE
+ int H5FL_reg_term()
+ RETURNS
+ Success: Positive if any action might have caused a change in some
+ other interface; zero otherwise.
+ Failure: Negative
+ DESCRIPTION
+ Release any resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+ Robb Matzke, 2000-04-25
+ If a list cannot be freed because something is using it then return
+ zero (failure to free a list doesn't affect any other part of the
+ library). If some other layer frees something during its termination
+ it will return non-zero, which will cause this function to get called
+ again to reclaim this layer's memory.
+--------------------------------------------------------------------------*/
+static int
+H5FL__reg_term(void)
+{
+ H5FL_reg_gc_node_t *left; /* pointer to garbage collection lists with work left */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
+ left = NULL;
+ while(H5FL_reg_gc_head.first != NULL) {
+ H5FL_reg_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+
+ /* Get a copy of the next node */
+ tmp = H5FL_reg_gc_head.first->next;
+
+#ifdef H5FL_DEBUG
+printf("%s: head->name = %s, head->allocated = %d\n", FUNC, H5FL_reg_gc_head.first->list->name, (int)H5FL_reg_gc_head.first->list->allocated);
+#endif /* H5FL_DEBUG */
+ /* Check if the list has allocations outstanding */
+ if(H5FL_reg_gc_head.first->list->allocated > 0) {
+ /* Add free list to the list of nodes with allocations open still */
+ H5FL_reg_gc_head.first->next = left;
+ left = H5FL_reg_gc_head.first;
+ } /* end if */
+ /* No allocations left open for list, get rid of it */
+ else {
+ /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
+ H5FL_reg_gc_head.first->list->init = FALSE;
+
+ /* Free the node from the garbage collection list */
+ H5MM_xfree(H5FL_reg_gc_head.first);
+ } /* end else */
+
+ H5FL_reg_gc_head.first = tmp;
+ } /* end while */
+
+ /* Point to the list of nodes left with allocations open, if any */
+ H5FL_reg_gc_head.first = left;
+
+ FUNC_LEAVE_NOAPI(H5FL_reg_gc_head.first != NULL ? 1 : 0)
+} /* end H5FL__reg_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_find_list
+ *
+ * Purpose: Finds the free list for blocks of a given size. Also moves that
+ * free list node to the head of the priority queue (if it isn't there
+ * already). This routine does not manage the actual free list, it just
+ * works with the priority queue.
+ *
+ * Return: Success: valid pointer to the free list node
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FL_blk_node_t *
+H5FL_blk_find_list(H5FL_blk_node_t **head, size_t size)
+{
+ H5FL_blk_node_t *temp = NULL; /* Temp. pointer to node in the native list */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Find the correct free list */
+ temp=*head;
+
+ /* Check if the node is at the head of the list */
+ if(temp && temp->size!=size) {
+ temp=temp->next;
+
+ while(temp!=NULL) {
+ /* Check if we found the correct node */
+ if(temp->size==size) {
+ /* Take the node found out of it's current position */
+ if(temp->next==NULL) {
+ temp->prev->next=NULL;
+ } /* end if */
+ else {
+ temp->prev->next=temp->next;
+ temp->next->prev=temp->prev;
+ } /* end else */
+
+ /* Move the found node to the head of the list */
+ temp->prev=NULL;
+ temp->next=*head;
+ (*head)->prev=temp;
+ *head=temp;
+
+ /* Get out */
+ break;
+ } /* end if */
+
+ temp=temp->next;
+ } /* end while */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(temp)
+} /* end H5FL_blk_find_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_create_list
+ *
+ * Purpose: Creates a new free list for blocks of the given size at the
+ * head of the priority queue.
+ *
+ * Return: Success: valid pointer to the free list node
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FL_blk_node_t *
+H5FL_blk_create_list(H5FL_blk_node_t **head, size_t size)
+{
+ H5FL_blk_node_t *temp; /* Temp. pointer to node in the list */
+ H5FL_blk_node_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate room for the new free list node */
+ if(NULL==(temp=H5FL_MALLOC(H5FL_blk_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for chunk info")
+
+ /* Set the correct values for the new free list */
+ temp->size=size;
+ temp->list=NULL;
+
+ /* Attach to head of priority queue */
+ if(*head==NULL) {
+ *head=temp;
+ temp->next=temp->prev=NULL;
+ } /* end if */
+ else {
+ temp->next=*head;
+ (*head)->prev=temp;
+ temp->prev=NULL;
+ *head=temp;
+ } /* end else */
+
+ ret_value=temp;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_create_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_init
+ *
+ * Purpose: Initialize a priority queue of a certain type. Right now, this just
+ * adds the PQ to the list of things to garbage collect.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_blk_init(H5FL_blk_head_t *head)
+{
+ H5FL_blk_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
+ herr_t ret_value=SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate a new garbage collection node */
+ if(NULL == (new_node = (H5FL_blk_gc_node_t *)H5MM_malloc(sizeof(H5FL_blk_gc_node_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the new garbage collection node */
+ new_node->pq = head;
+
+ /* Link in to the garbage collection list */
+ new_node->next=H5FL_blk_gc_head.first;
+ H5FL_blk_gc_head.first=new_node;
+
+ /* Indicate that the PQ is initialized */
+ head->init = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_free_block_avail
+ *
+ * Purpose: Checks if a free block of the appropriate size is available
+ * for a given list.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 16, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size)
+{
+ H5FL_blk_node_t *free_list; /* The free list of nodes of correct size */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+
+ /* check if there is a free list for blocks of this size */
+ /* and if there are any blocks available on the list */
+ if((free_list = H5FL_blk_find_list(&(head->head), size)) != NULL && free_list->list != NULL)
+ ret_value = TRUE;
+ else
+ ret_value = FALSE;
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_free_block_avail() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_malloc
+ *
+ * Purpose: Allocates memory for a block. This routine is used
+ * instead of malloc because the block can be kept on a free list so
+ * they don't thrash malloc/free as much.
+ *
+ * Return: Success: valid pointer to the block
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS)
+{
+ H5FL_blk_node_t *free_list; /* The free list of nodes of correct size */
+ H5FL_blk_list_t *temp; /* Temp. ptr to the new native list allocated */
+ void *ret_value = NULL; /* Pointer to the block to return to the user */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(size);
+
+ /* Make certain the list is initialized first */
+ if(!head->init)
+ if(H5FL_blk_init(head)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'block' list")
+
+ /* check if there is a free list for blocks of this size */
+ /* and if there are any blocks available on the list */
+ if((free_list=H5FL_blk_find_list(&(head->head),size))!=NULL && free_list->list!=NULL) {
+ /* Remove the first node from the free list */
+ temp=free_list->list;
+ free_list->list=free_list->list->next;
+
+ /* Decrement the number of blocks & memory used on free list */
+ head->onlist--;
+ head->list_mem-=size;
+
+ /* Decrement the amount of global "block" free list memory in use */
+ H5FL_blk_gc_head.mem_freed-=size;
+
+ } /* end if */
+ /* No free list available, or there are no nodes on the list, allocate a new node to give to the user */
+ else {
+ /* Allocate new node, with room for the page info header and the actual page data */
+ if(NULL == (temp = (H5FL_blk_list_t *)H5FL_malloc(sizeof(H5FL_blk_list_t) + H5FL_TRACK_SIZE + size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for chunk")
+
+ /* Increment the number of blocks allocated */
+ head->allocated++;
+ } /* end else */
+
+ /* Initialize the block allocated */
+ temp->size=size;
+
+ /* Set the return value to the block itself */
+ ret_value=((char *)temp)+sizeof(H5FL_blk_list_t);
+
+#ifdef H5FL_TRACK
+ /* Copy allocation location information */
+ ((H5FL_track_t *)ret_value)->stack = H5CS_copy_stack();
+ HDassert(((H5FL_track_t *)ret_value)->stack);
+ ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file);
+ ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func);
+ ((H5FL_track_t *)ret_value)->line = call_line;
+
+ /* Add to "outstanding allocations" list */
+ ((H5FL_track_t *)ret_value)->prev = NULL;
+ ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = (H5FL_track_t *)ret_value;
+ H5FL_out_head_g = (H5FL_track_t *)ret_value;
+
+ /* Adjust for allocation tracking information */
+ ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_calloc
+ *
+ * Purpose: Allocates memory for a block and clear it to zeros.
+ * This routine is used
+ * instead of malloc because the block can be kept on a free list so
+ * they don't thrash malloc/free as much.
+ *
+ * Return: Success: valid pointer to the block
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return to the user */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(size);
+
+ /* Allocate the block */
+ if (NULL==(ret_value = H5FL_blk_malloc(head,size H5FL_TRACK_INFO_INT)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear the block to zeros */
+ HDmemset(ret_value,0,size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_free
+ *
+ * Purpose: Releases memory for a block. This routine is used
+ * instead of free because the blocks can be kept on a free list so
+ * they don't thrash malloc/free as much.
+ *
+ * Return: Success: NULL
+ *
+ * Failure: never fails
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_blk_free(H5FL_blk_head_t *head, void *block)
+{
+ H5FL_blk_node_t *free_list; /* The free list of nodes of correct size */
+ H5FL_blk_list_t *temp; /* Temp. ptr to the new free list node allocated */
+ size_t free_size; /* Size of the block freed */
+ void *ret_value=NULL; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_blk_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(block);
+
+#ifdef H5FL_TRACK
+ {
+ H5FL_track_t *trk = block = ((unsigned char *)block) - sizeof(H5FL_track_t);
+
+ /* Free tracking information about the allocation location */
+ H5CS_close_stack(trk->stack);
+ trk->file = H5MM_xfree(trk->file);
+ trk->func = H5MM_xfree(trk->func);
+
+ /* Remove from "outstanding allocations" list */
+ if(trk == H5FL_out_head_g) {
+ H5FL_out_head_g = H5FL_out_head_g->next;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = NULL;
+ } /* end if */
+ else {
+ trk->prev->next = trk->next;
+ if(trk->next)
+ trk->next->prev = trk->prev;
+ } /* end else */
+ }
+#endif /* H5FL_TRACK */
+
+ /* Get the pointer to the native block info header in front of the native block to free */
+ temp=(H5FL_blk_list_t *)((unsigned char *)block-sizeof(H5FL_blk_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
+
+ /* Save the block's size for later */
+ free_size=temp->size;
+
+#ifdef H5FL_DEBUG
+ HDmemset(temp,255,free_size + sizeof(H5FL_blk_list_t) + H5FL_TRACK_SIZE);
+#endif /* H5FL_DEBUG */
+
+ /* check if there is a free list for native blocks of this size */
+ if((free_list=H5FL_blk_find_list(&(head->head),free_size))==NULL) {
+ /* No free list available, create a new list node and insert it to the queue */
+ free_list=H5FL_blk_create_list(&(head->head),free_size);
+ HDassert(free_list);
+ } /* end if */
+
+ /* Prepend the free'd native block to the front of the free list */
+ if(free_list!=NULL) {
+ temp->next=free_list->list; /* Overwrites the size field in union */
+ free_list->list=temp;
+ } /* end if */
+
+ /* Increment the number of blocks on free list */
+ head->onlist++;
+ head->list_mem += free_size;
+
+ /* Increment the amount of "block" freed memory globally */
+ H5FL_blk_gc_head.mem_freed += free_size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->list_mem > H5FL_blk_lst_mem_lim)
+ if(H5FL__blk_gc_list(head) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+ /* Then check the global amount memory on block free lists */
+ if(H5FL_blk_gc_head.mem_freed > H5FL_blk_glb_mem_lim)
+ if(H5FL__blk_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_blk_realloc
+ *
+ * Purpose: Resizes a block. This does things the straightforward, simple way,
+ * not actually using realloc.
+ *
+ * Return: Success: NULL
+ *
+ * Failure: never fails
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_PARAMS)
+{
+ void *ret_value=NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(new_size);
+
+ /* Check if we are actually re-allocating a block */
+ if(block!=NULL) {
+ H5FL_blk_list_t *temp; /* Temp. ptr to the new block node allocated */
+
+ /* Get the pointer to the chunk info header in front of the chunk to free */
+ temp=(H5FL_blk_list_t *)((unsigned char *)block - (sizeof(H5FL_blk_list_t) + H5FL_TRACK_SIZE)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
+
+ /* check if we are actually changing the size of the buffer */
+ if(new_size!=temp->size) {
+ size_t blk_size; /* Temporary block size */
+
+ if((ret_value=H5FL_blk_malloc(head,new_size H5FL_TRACK_INFO_INT))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for block")
+ blk_size=MIN(new_size,temp->size);
+ HDmemcpy(ret_value,block,blk_size);
+ H5FL_blk_free(head,block);
+ } /* end if */
+ else {
+#ifdef H5FL_TRACK
+ {
+ H5FL_track_t *trk = (H5FL_track_t *)(((unsigned char *)block) - sizeof(H5FL_track_t));
+
+ /* Release previous tracking information */
+ H5CS_close_stack(trk->stack);
+ trk->file = H5MM_xfree(trk->file);
+ trk->func = H5MM_xfree(trk->func);
+
+ /* Store new tracking information */
+ trk->stack = H5CS_copy_stack();
+ HDassert(trk->stack);
+ trk->file = H5MM_strdup(call_file);
+ trk->func = H5MM_strdup(call_func);
+ trk->line = call_line;
+ }
+#endif /* H5FL_TRACK */
+ ret_value=block;
+ } /* end if */
+ } /* end if */
+ /* Not re-allocating, just allocate a fresh block */
+ else
+ ret_value=H5FL_blk_malloc(head,new_size H5FL_TRACK_INFO_INT);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_blk_realloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__blk_gc_list
+ *
+ * Purpose: Garbage collect a priority queue
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 23, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__blk_gc_list(H5FL_blk_head_t *head)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Loop through all the nodes in the block free list queue */
+ while(head->head != NULL) {
+ H5FL_blk_list_t *list; /* The free list of native nodes of a particular size */
+ void *temp; /* Temp. ptr to the free list page node */
+
+ temp = head->head->next;
+
+ /* Loop through all the blocks in the free list, freeing them */
+ list = head->head->list;
+ while(list != NULL) {
+ void *next; /* Temp. ptr to the free list list node */
+
+ next = list->next;
+
+ /* Decrement the number of blocks & memory allocated from this PQ */
+ head->allocated--;
+ head->list_mem -= head->head->size;
+
+ /* Decrement global count of free memory on "block" lists */
+ H5FL_blk_gc_head.mem_freed -= head->head->size;
+
+ /* Free the block */
+ H5MM_free(list);
+
+ list = (H5FL_blk_list_t *)next;
+ } /* end while */
+
+ /* Free the free list node */
+ head->head = H5FL_FREE(H5FL_blk_node_t, head->head);
+
+ /* Advance to the next free list */
+ head->head = (H5FL_blk_node_t *)temp;
+ } /* end while */
+
+ /* Indicate no free nodes on the free list */
+ head->head = NULL;
+ head->onlist = 0;
+
+ /* Double check that all the memory on this list is recycled */
+ HDassert(0 == head->list_mem);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FL__blk_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__blk_gc
+ *
+ * Purpose: Garbage collect on all the priority queues
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__blk_gc(void)
+{
+ H5FL_blk_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
+ herr_t ret_value = SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_node = H5FL_blk_gc_head.first;
+ while(gc_node != NULL) {
+ /* For each free list being garbage collected, walk through the nodes and free them */
+ if(H5FL__blk_gc_list(gc_node->pq) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed")
+
+ /* Go on to the next free list to garbage collect */
+ gc_node = gc_node->next;
+ } /* end while */
+
+ /* Double check that all the memory on the free lists are recycled */
+ HDassert(H5FL_blk_gc_head.mem_freed == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL__blk_gc() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FL__blk_term
+ PURPOSE
+ Terminate various H5FL_blk objects
+ USAGE
+ void H5FL__blk_term()
+ RETURNS
+ Success: Positive if any action might have caused a change in some
+ other interface; zero otherwise.
+ Failure: Negative
+ DESCRIPTION
+ Release any resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5FL__blk_term(void)
+{
+ H5FL_blk_gc_node_t *left; /* pointer to garbage collection lists with work left */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
+ left = NULL;
+ while(H5FL_blk_gc_head.first != NULL) {
+ H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+
+ tmp = H5FL_blk_gc_head.first->next;
+
+#ifdef H5FL_DEBUG
+printf("%s: head->name = %s, head->allocated = %d\n", FUNC, H5FL_blk_gc_head.first->pq->name, (int)H5FL_blk_gc_head.first->pq->allocated);
+#endif /* H5FL_DEBUG */
+
+ /* Check if the list has allocations outstanding */
+ if(H5FL_blk_gc_head.first->pq->allocated > 0) {
+ /* Add free list to the list of nodes with allocations open still */
+ H5FL_blk_gc_head.first->next = left;
+ left = H5FL_blk_gc_head.first;
+ } /* end if */
+ /* No allocations left open for list, get rid of it */
+ else {
+ /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
+ H5FL_blk_gc_head.first->pq->init = FALSE;
+
+ /* Free the node from the garbage collection list */
+ H5MM_free(H5FL_blk_gc_head.first);
+ } /* end else */
+
+ H5FL_blk_gc_head.first = tmp;
+ } /* end while */
+
+ /* Point to the list of nodes left with allocations open, if any */
+ H5FL_blk_gc_head.first = left;
+
+ FUNC_LEAVE_NOAPI(H5FL_blk_gc_head.first != NULL ? 1 : 0)
+} /* end H5FL__blk_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_init
+ *
+ * Purpose: Initialize a free list for a arrays of certain type. Right now,
+ * this just adds the free list to the list of things to garbage collect.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_arr_init(H5FL_arr_head_t *head)
+{
+ H5FL_gc_arr_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
+ size_t u; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate a new garbage collection node */
+ if(NULL == (new_node = (H5FL_gc_arr_node_t *)H5MM_malloc(sizeof(H5FL_gc_arr_node_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the new garbage collection node */
+ new_node->list = head;
+
+ /* Link in to the garbage collection list */
+ new_node->next=H5FL_arr_gc_head.first;
+ H5FL_arr_gc_head.first=new_node;
+
+ /* Allocate room for the free lists */
+ if(NULL == (head->list_arr = (H5FL_arr_node_t *)H5MM_calloc((size_t)head->maxelem * sizeof(H5FL_arr_node_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the size of each array */
+ for(u = 0; u < (size_t)head->maxelem; u++)
+ head->list_arr[u].size = head->base_size + (head->elem_size * u);
+
+ /* Indicate that the free list is initialized */
+ head->init = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_arr_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_free
+ *
+ * Purpose: Release an array of objects & put on free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_arr_free(H5FL_arr_head_t *head, void *obj)
+{
+ H5FL_arr_list_t *temp; /* Temp. ptr to the new free list node allocated */
+ size_t mem_size; /* Size of memory being freed */
+ size_t free_nelem; /* Number of elements in node being free'd */
+ void *ret_value=NULL; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_arr_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* The H5MM_xfree code allows obj to null */
+ if (!obj)
+ HGOTO_DONE (NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+
+ /* Make certain that the free list is initialized */
+ HDassert(head->init);
+
+ /* Get the pointer to the info header in front of the block to free */
+ temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
+
+ /* Get the number of elements */
+ free_nelem=temp->nelem;
+
+ /* Double-check that there is enough room for arrays of this size */
+ HDassert((int)free_nelem<=head->maxelem);
+
+ /* Link into the free list */
+ temp->next=head->list_arr[free_nelem].list;
+
+ /* Point free list at the node freed */
+ head->list_arr[free_nelem].list=temp;
+
+ /* Get the size of arrays with this many elements */
+ mem_size=head->list_arr[free_nelem].size;
+
+ /* Increment the number of blocks & memory used on free list */
+ head->list_arr[free_nelem].onlist++;
+ head->list_mem+=mem_size;
+
+ /* Increment the amount of "array" freed memory globally */
+ H5FL_arr_gc_head.mem_freed+=mem_size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->list_mem > H5FL_arr_lst_mem_lim)
+ if(H5FL__arr_gc_list(head) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+ /* Then check the global amount memory on array free lists */
+ if(H5FL_arr_gc_head.mem_freed > H5FL_arr_glb_mem_lim)
+ if(H5FL__arr_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_arr_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_malloc
+ *
+ * Purpose: Allocate an array of objects
+ *
+ * Return: Success: Pointer to a valid array object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem)
+{
+ H5FL_arr_list_t *new_obj; /* Pointer to the new free list node allocated */
+ size_t mem_size; /* Size of memory block being recycled */
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(elem);
+
+ /* Make certain the list is initialized first */
+ if(!head->init)
+ if(H5FL_arr_init(head)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'array' blocks")
+
+ /* Sanity check that the number of elements is supported */
+ HDassert(elem<=(unsigned) head->maxelem);
+
+ /* Get the set of the memory block */
+ mem_size=head->list_arr[elem].size;
+
+ /* Check for nodes available on the free list first */
+ if(head->list_arr[elem].list!=NULL) {
+ /* Get a pointer to the block on the free list */
+ new_obj=head->list_arr[elem].list;
+
+ /* Remove node from free list */
+ head->list_arr[elem].list=head->list_arr[elem].list->next;
+
+ /* Decrement the number of blocks & memory used on free list */
+ head->list_arr[elem].onlist--;
+ head->list_mem-=mem_size;
+
+ /* Decrement the amount of global "array" free list memory in use */
+ H5FL_arr_gc_head.mem_freed-=mem_size;
+
+ } /* end if */
+ /* Otherwise allocate a node */
+ else {
+ if(NULL == (new_obj = (H5FL_arr_list_t *)H5FL_malloc(sizeof(H5FL_arr_list_t)+mem_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment the number of blocks allocated in list */
+ head->allocated++;
+ } /* end else */
+
+ /* Initialize the new object */
+ new_obj->nelem=elem;
+
+ /* Get a pointer to the new block */
+ ret_value=((char *)new_obj)+sizeof(H5FL_arr_list_t);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_arr_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_calloc
+ *
+ * Purpose: Allocate an array of objects and clear it to zeros
+ *
+ * Return: Success: Pointer to a valid array object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(elem);
+
+ /* Allocate the array */
+ if(NULL == (ret_value = H5FL_arr_malloc(head, elem)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear to zeros */
+ HDmemset(ret_value, 0, head->list_arr[elem].size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_arr_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_realloc
+ *
+ * Purpose: Reallocate an array of objects
+ *
+ * Return: Success: Pointer to a valid array object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(new_elem);
+
+ /* Check if we are really allocating the object */
+ if(obj == NULL)
+ ret_value = H5FL_arr_malloc(head, new_elem);
+ else {
+ H5FL_arr_list_t *temp; /* Temp. ptr to the new free list node allocated */
+
+ /* Sanity check that the number of elements is supported */
+ HDassert((int)new_elem <= head->maxelem);
+
+ /* Get the pointer to the info header in front of the block to free */
+ temp = (H5FL_arr_list_t *)((unsigned char *)obj - sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
+
+ /* Check if the size is really changing */
+ if(temp->nelem != new_elem) {
+ size_t blk_size; /* Size of block */
+
+ /* Get the new array of objects */
+ ret_value = H5FL_arr_malloc(head, new_elem);
+
+ /* Copy the appropriate amount of elements */
+ blk_size = head->list_arr[MIN(temp->nelem, new_elem)].size;
+ HDmemcpy(ret_value, obj, blk_size);
+
+ /* Free the old block */
+ H5FL_arr_free(head, obj);
+ } /* end if */
+ else
+ ret_value = obj;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_arr_realloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__arr_gc_list
+ *
+ * Purpose: Garbage collect on an array object free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__arr_gc_list(H5FL_arr_head_t *head)
+{
+ unsigned u; /* Counter for array of free lists */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Walk through the array of free lists */
+ for(u = 0; u < (unsigned)head->maxelem; u++) {
+ if(head->list_arr[u].onlist > 0) {
+ H5FL_arr_list_t *arr_free_list; /* Pointer to nodes in free list being garbage collected */
+ size_t total_mem; /* Total memory used on list */
+
+ /* Calculate the total memory used on this list */
+ total_mem = head->list_arr[u].onlist * head->list_arr[u].size;
+
+ /* For each free list being garbage collected, walk through the nodes and free them */
+ arr_free_list = head->list_arr[u].list;
+ while(arr_free_list != NULL) {
+ void *tmp; /* Temporary node pointer */
+
+ tmp = arr_free_list->next;
+
+ /* Decrement the count of nodes allocated and free the node */
+ head->allocated--;
+ H5MM_free(arr_free_list);
+
+ arr_free_list = (H5FL_arr_list_t *)tmp;
+ } /* end while */
+
+ /* Indicate no free nodes on the free list */
+ head->list_arr[u].list = NULL;
+ head->list_arr[u].onlist = 0;
+
+ /* Decrement count of free memory on this "array" list */
+ head->list_mem -= total_mem;
+
+ /* Decrement global count of free memory on "array" lists */
+ H5FL_arr_gc_head.mem_freed -= total_mem;
+ } /* end if */
+ } /* end for */
+
+ /* Double check that all the memory on this list is recycled */
+ HDassert(head->list_mem == 0);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FL__arr_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__arr_gc
+ *
+ * Purpose: Garbage collect on all the array object free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__arr_gc(void)
+{
+ H5FL_gc_arr_node_t *gc_arr_node; /* Pointer into the list of things to garbage collect */
+ herr_t ret_value = SUCCEED; /* return value*/
+
+ FUNC_ENTER_STATIC
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_arr_node = H5FL_arr_gc_head.first;
+ while(gc_arr_node != NULL) {
+ /* Release the free nodes on the list */
+ if(H5FL__arr_gc_list(gc_arr_node->list) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed")
+
+ /* Go on to the next free list to garbage collect */
+ gc_arr_node = gc_arr_node->next;
+ } /* end while */
+
+ /* Double check that all the memory on the free lists are recycled */
+ HDassert(H5FL_arr_gc_head.mem_freed == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL__arr_gc() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FL__arr_term
+ PURPOSE
+ Terminate various H5FL array object free lists
+ USAGE
+ int H5FL__arr_term()
+ RETURNS
+ Success: Positive if any action might have caused a change in some
+ other interface; zero otherwise.
+ Failure: Negative
+ DESCRIPTION
+ Release any resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5FL__arr_term(void)
+{
+ H5FL_gc_arr_node_t *left; /* pointer to garbage collection lists with work left */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
+ left = NULL;
+ while(H5FL_arr_gc_head.first != NULL) {
+ H5FL_gc_arr_node_t *tmp; /* Temporary pointer to a garbage collection node */
+
+ tmp = H5FL_arr_gc_head.first->next;
+
+ /* Check if the list has allocations outstanding */
+#ifdef H5FL_DEBUG
+printf("%s: head->name = %s, head->allocated = %d\n", FUNC, H5FL_arr_gc_head.first->list->name, (int)H5FL_arr_gc_head.first->list->allocated);
+#endif /* H5FL_DEBUG */
+ if(H5FL_arr_gc_head.first->list->allocated > 0) {
+ /* Add free list to the list of nodes with allocations open still */
+ H5FL_arr_gc_head.first->next = left;
+ left = H5FL_arr_gc_head.first;
+ } /* end if */
+ /* No allocations left open for list, get rid of it */
+ else {
+ /* Free the array of free lists */
+ H5MM_xfree(H5FL_arr_gc_head.first->list->list_arr);
+
+ /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
+ H5FL_arr_gc_head.first->list->init = FALSE;
+
+ /* Free the node from the garbage collection list */
+ H5MM_free(H5FL_arr_gc_head.first);
+ } /* end else */
+
+ H5FL_arr_gc_head.first = tmp;
+ } /* end while */
+
+ /* Point to the list of nodes left with allocations open, if any */
+ H5FL_arr_gc_head.first = left;
+
+ FUNC_LEAVE_NOAPI(H5FL_arr_gc_head.first != NULL ? 1 : 0)
+} /* end H5FL__arr_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_seq_free
+ *
+ * Purpose: Release a sequence of objects & put on free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, April 3, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_seq_free(H5FL_seq_head_t *head, void *obj)
+{
+ /* NOINIT OK here because this must be called after H5FL_seq_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(obj);
+
+ /* Make certain that the free list is initialized */
+ HDassert(head->queue.init);
+
+ /* Use block routine */
+ H5FL_blk_free(&(head->queue),obj);
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5FL_seq_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_seq_malloc
+ *
+ * Purpose: Allocate a sequence of objects
+ *
+ * Return: Success: Pointer to a valid sequence object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, April 3, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(elem);
+
+ /* Use block routine */
+ ret_value = H5FL_blk_malloc(&(head->queue), head->size * elem H5FL_TRACK_INFO_INT);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_seq_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_seq_calloc
+ *
+ * Purpose: Allocate a sequence of objects and clear it to zeros
+ *
+ * Return: Success: Pointer to a valid array object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, April 3, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(elem);
+
+ /* Use block routine */
+ ret_value = H5FL_blk_calloc(&(head->queue), head->size * elem H5FL_TRACK_INFO_INT);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_seq_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_seq_realloc
+ *
+ * Purpose: Reallocate a sequence of objects
+ *
+ * Return: Success: Pointer to a valid sequence object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, April 3, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_seq_realloc(H5FL_seq_head_t *head, void * obj, size_t new_elem H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(new_elem);
+
+ /* Use block routine */
+ ret_value = H5FL_blk_realloc(&(head->queue), obj, head->size * new_elem H5FL_TRACK_INFO_INT);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_seq_realloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_init
+ *
+ * Purpose: Initialize a block factory
+ *
+ * Return: Success: Pointer to factory object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 2, 2005
+ *
+ * Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FL_fac_head_t *
+H5FL_fac_init(size_t size)
+{
+ H5FL_fac_gc_node_t *new_node = NULL; /* Pointer to the node for the new list to garbage collect */
+ H5FL_fac_head_t *factory = NULL; /* Pointer to new block factory */
+ H5FL_fac_head_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(size > 0);
+
+ /* Allocate room for the new factory */
+ if(NULL == (factory = (H5FL_fac_head_t *)H5FL_CALLOC(H5FL_fac_head_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for factory object")
+
+ /* Set size of blocks for factory */
+ factory->size = size;
+
+ /* Allocate a new garbage collection node */
+ if(NULL == (new_node = (H5FL_fac_gc_node_t *)H5FL_MALLOC(H5FL_fac_gc_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Initialize the new garbage collection node */
+ new_node->list = factory;
+
+ /* Link in to the garbage collection list */
+ new_node->next = H5FL_fac_gc_head.first;
+ H5FL_fac_gc_head.first = new_node;
+ if(new_node->next)
+ new_node->next->list->prev_gc=new_node;
+ /* The new factory's prev_gc field will be set to NULL */
+
+ /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */
+ if(factory->size < sizeof(H5FL_fac_node_t))
+ factory->size = sizeof(H5FL_fac_node_t);
+
+ /* Make certain there's room for tracking information, if any */
+#ifdef H5FL_TRACK
+ factory->size += sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+ /* Indicate that the free list is initialized */
+ factory->init = TRUE;
+
+ /* Set return value */
+ ret_value = factory;
+
+done:
+ if(!ret_value) {
+ if(factory)
+ factory = H5FL_FREE(H5FL_fac_head_t, factory);
+ if(new_node)
+ new_node = H5FL_FREE(H5FL_fac_gc_node_t, new_node);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_free
+ *
+ * Purpose: Release a block back to a factory & put on free list
+ *
+ * Return: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 2, 2005
+ *
+ * Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_fac_free(H5FL_fac_head_t *head, void *obj)
+{
+ void *ret_value = NULL; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(obj);
+
+#ifdef H5FL_TRACK
+ {
+ H5FL_track_t *trk = obj = ((unsigned char *)obj) - sizeof(H5FL_track_t);
+
+ /* Free tracking information about the allocation location */
+ H5CS_close_stack(trk->stack);
+ trk->file = H5MM_xfree(trk->file);
+ trk->func = H5MM_xfree(trk->func);
+
+ /* Remove from "outstanding allocations" list */
+ if(trk == H5FL_out_head_g) {
+ H5FL_out_head_g = H5FL_out_head_g->next;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = NULL;
+ } /* end if */
+ else {
+ trk->prev->next = trk->next;
+ if(trk->next)
+ trk->next->prev = trk->prev;
+ } /* end else */
+ }
+#endif /* H5FL_TRACK */
+
+#ifdef H5FL_DEBUG
+ HDmemset(obj,255,head->size);
+#endif /* H5FL_DEBUG */
+
+ /* Make certain that the free list is initialized */
+ HDassert(head->init);
+
+ /* Link into the free list */
+ ((H5FL_fac_node_t *)obj)->next = head->list;
+
+ /* Point free list at the node freed */
+ head->list = (H5FL_fac_node_t *)obj;
+
+ /* Increment the number of blocks on free list */
+ head->onlist++;
+
+ /* Increment the amount of "factory" freed memory globally */
+ H5FL_fac_gc_head.mem_freed += head->size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->onlist * head->size > H5FL_fac_lst_mem_lim)
+ if(H5FL__fac_gc_list(head) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+ /* Then check the global amount memory on factory free lists */
+ if(H5FL_fac_gc_head.mem_freed > H5FL_fac_glb_mem_lim)
+ if(H5FL__fac_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_malloc
+ *
+ * Purpose: Allocate a block from a factory
+ *
+ * Return: Success: Pointer to a valid sequence object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 2, 2005
+ *
+ * Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Double check parameters */
+ HDassert(head);
+ HDassert(head->init);
+
+ /* Check for nodes available on the free list first */
+ if(head->list!=NULL) {
+ /* Get a pointer to the block on the free list */
+ ret_value=(void *)(head->list);
+
+ /* Remove node from free list */
+ head->list=head->list->next;
+
+ /* Decrement the number of blocks & memory on free list */
+ head->onlist--;
+
+ /* Decrement the amount of global "factory" free list memory in use */
+ H5FL_fac_gc_head.mem_freed-=(head->size);
+ } /* end if */
+ /* Otherwise allocate a node */
+ else {
+ if (NULL==(ret_value = H5FL_malloc(head->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment the number of blocks allocated in list */
+ head->allocated++;
+ } /* end else */
+
+#ifdef H5FL_TRACK
+ /* Copy allocation location information */
+ ((H5FL_track_t *)ret_value)->stack = H5CS_copy_stack();
+ HDassert(((H5FL_track_t *)ret_value)->stack);
+ ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file);
+ ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func);
+ ((H5FL_track_t *)ret_value)->line = call_line;
+
+ /* Add to "outstanding allocations" list */
+ ((H5FL_track_t *)ret_value)->prev = NULL;
+ ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = (H5FL_track_t *)ret_value;
+ H5FL_out_head_g = (H5FL_track_t *)ret_value;
+
+ /* Adjust for allocation tracking information */
+ ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_calloc
+ *
+ * Purpose: Allocate a block from a factory and clear it to zeros
+ *
+ * Return: Success: Pointer to a valid array object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 2, 2005
+ *
+ * Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS)
+{
+ void *ret_value = NULL; /* Pointer to the block to return */
+
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Double check parameters */
+ HDassert(head);
+
+ /* Allocate the block */
+ if (NULL==(ret_value = H5FL_fac_malloc(head H5FL_TRACK_INFO_INT)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear to zeros */
+ /* (Accomodate tracking information, if present) */
+ HDmemset(ret_value,0,head->size - H5FL_TRACK_SIZE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__fac_gc_list
+ *
+ * Purpose: Garbage collect on a particular factory free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__fac_gc_list(H5FL_fac_head_t *head)
+{
+ H5FL_fac_node_t *free_list; /* Pointer to nodes in free list being garbage collected */
+ size_t total_mem; /* Total memory used on list */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Calculate the total memory used on this list */
+ total_mem = head->onlist * head->size;
+
+ /* For each free list being garbage collected, walk through the nodes and free them */
+ free_list = head->list;
+ while(free_list != NULL) {
+ void *tmp; /* Temporary node pointer */
+
+ tmp = free_list->next;
+
+ /* Decrement the count of nodes allocated and free the node */
+ head->allocated--;
+
+ H5MM_free(free_list);
+
+ free_list = (H5FL_fac_node_t *)tmp;
+ } /* end while */
+
+ /* Indicate no free nodes on the free list */
+ head->list = NULL;
+ head->onlist = 0;
+
+ /* Decrement global count of free memory on "factory" lists */
+ H5FL_fac_gc_head.mem_freed -= total_mem;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FL__fac_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__fac_gc
+ *
+ * Purpose: Garbage collect on all the factory free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL__fac_gc(void)
+{
+ H5FL_fac_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
+ herr_t ret_value = SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_node = H5FL_fac_gc_head.first;
+ while(gc_node != NULL) {
+ /* Release the free nodes on the list */
+ if(H5FL__fac_gc_list(gc_node->list) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed")
+
+ /* Go on to the next free list to garbage collect */
+ gc_node = gc_node->next;
+ } /* end while */
+
+ /* Double check that all the memory on the free lists is recycled */
+ HDassert(H5FL_fac_gc_head.mem_freed == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL__fac_gc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_term
+ *
+ * Purpose: Terminate a block factory
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 2, 2005
+ *
+ * Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FL_fac_term(H5FL_fac_head_t *factory)
+{
+ H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(factory);
+
+ /* Garbage collect all the blocks in the factory's free list */
+ if(H5FL__fac_gc_list(factory) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of factory failed")
+
+ /* Verify that all the blocks have been freed */
+ if(factory->allocated > 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "factory still has objects allocated")
+
+ /* Unlink block free list for factory from global free list */
+ if(factory->prev_gc) {
+ H5FL_fac_gc_node_t *last = factory->prev_gc; /* Garbage collection node before the one being removed */
+
+ HDassert(last->next->list == factory);
+ tmp = last->next->next;
+ last->next = H5FL_FREE(H5FL_fac_gc_node_t, last->next);
+ last->next = tmp;
+ if(tmp)
+ tmp->list->prev_gc = last;
+ } else {
+ HDassert(H5FL_fac_gc_head.first->list == factory);
+ tmp = H5FL_fac_gc_head.first->next;
+ H5FL_fac_gc_head.first = H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first);
+ H5FL_fac_gc_head.first = tmp;
+ if(tmp)
+ tmp->list->prev_gc = NULL;
+ } /* end else */
+
+ /* Free factory info */
+ factory = H5FL_FREE(H5FL_fac_head_t, factory);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL__fac_term_all
+ *
+ * Purpose: Terminate all block factories
+ *
+ * Return: 0. There should never be any outstanding allocations
+ * when this is called.
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FL__fac_term_all(void)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Free the nodes on the garbage collection list */
+ while(H5FL_fac_gc_head.first != NULL) {
+ H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+
+ tmp = H5FL_fac_gc_head.first->next;
+
+#ifdef H5FL_DEBUG
+printf("%s: head->size = %d, head->allocated = %d\n", FUNC, (int)H5FL_fac_gc_head.first->list->size, (int)H5FL_fac_gc_head.first->list->allocated);
+#endif /* H5FL_DEBUG */
+
+ /* The list cannot have any allocations outstanding */
+ HDassert(H5FL_fac_gc_head.first->list->allocated == 0);
+
+ /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
+ H5FL_fac_gc_head.first->list->init = FALSE;
+
+ /* Free the node from the garbage collection list */
+ H5FL_fac_gc_head.first = H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first);
+
+ H5FL_fac_gc_head.first = tmp;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(0)
+} /* end H5FL__fac_term_all() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_garbage_coll
+ *
+ * Purpose: Garbage collect on all the free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FL_garbage_coll(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Garbage collect the free lists for array objects */
+ if(H5FL__arr_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect array objects")
+
+ /* Garbage collect free lists for blocks */
+ if(H5FL__blk_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect block objects")
+
+ /* Garbage collect the free lists for regular objects */
+ if(H5FL__reg_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects")
+
+ /* Garbage collect the free lists for factory objects */
+ if(H5FL__fac_gc() < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect factory objects")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_garbage_coll() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_set_free_list_limits
+ *
+ * Purpose: Sets limits on the different kinds of free lists. Setting a value
+ * of -1 for a limit means no limit of that type. These limits are global
+ * for the entire library. Each "global" limit only applies to free lists
+ * of that type, so if an application sets a limit of 1 MB on each of the
+ * global lists, up to 3 MB of total storage might be allocated (1MB on
+ * each of regular, array and block type lists).
+ *
+ * Parameters:
+ * int reg_global_lim; IN: The limit on all "regular" free list memory used
+ * int reg_list_lim; IN: The limit on memory used in each "regular" free list
+ * int arr_global_lim; IN: The limit on all "array" free list memory used
+ * int arr_list_lim; IN: The limit on memory used in each "array" free list
+ * int blk_global_lim; IN: The limit on all "block" free list memory used
+ * int blk_list_lim; IN: The limit on memory used in each "block" free list
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 2, 2000
+ *
+ * Modifications: Neil Fortner
+ * Wednesday, April 8, 2009
+ * Added support for factory free lists
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim,
+ int arr_list_lim, int blk_global_lim, int blk_list_lim, int fac_global_lim,
+ int fac_list_lim)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Set the limit variables */
+ /* limit on all regular free lists */
+ H5FL_reg_glb_mem_lim = (reg_global_lim == -1 ? UINT_MAX : (size_t)reg_global_lim);
+ /* limit on each regular free list */
+ H5FL_reg_lst_mem_lim = (reg_list_lim == -1 ? UINT_MAX : (size_t)reg_list_lim);
+ /* limit on all array free lists */
+ H5FL_arr_glb_mem_lim = (arr_global_lim == -1 ? UINT_MAX : (size_t)arr_global_lim);
+ /* limit on each array free list */
+ H5FL_arr_lst_mem_lim = (arr_list_lim == -1 ? UINT_MAX : (size_t)arr_list_lim);
+ /* limit on all block free lists */
+ H5FL_blk_glb_mem_lim = (blk_global_lim == -1 ? UINT_MAX : (size_t)blk_global_lim);
+ /* limit on each block free list */
+ H5FL_blk_lst_mem_lim = (blk_list_lim == -1 ? UINT_MAX : (size_t)blk_list_lim);
+ /* limit on all factory free lists */
+ H5FL_fac_glb_mem_lim = (fac_global_lim == -1 ? UINT_MAX : (size_t)fac_global_lim);
+ /* limit on each factory free list */
+ H5FL_fac_lst_mem_lim = (fac_list_lim == -1 ? UINT_MAX : (size_t)fac_list_lim);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_set_free_list_limits() */
+
diff --git a/src/H5FLmodule.h b/src/H5FLmodule.h
new file mode 100644
index 0000000..48b8d2b
--- /dev/null
+++ b/src/H5FLmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5FL package. Including this header means that the source file
+ * is part of the H5FL package.
+ */
+#ifndef _H5FLmodule_H
+#define _H5FLmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5FL_MODULE
+#define H5_MY_PKG H5FL
+#define H5_MY_PKG_ERR H5E_RESOURCE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5FLmodule_H */
+
diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h
new file mode 100644
index 0000000..4aa44f9
--- /dev/null
+++ b/src/H5FLprivate.h
@@ -0,0 +1,428 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FLprivate.h
+ * Mar 23 2000
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Private non-prototype header.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5FLprivate_H
+#define _H5FLprivate_H
+
+/* Public headers needed by this file */
+#ifdef LATER
+#include "H5FLpublic.h" /*API prototypes */
+#endif /* LATER */
+
+/* Private headers needed by this file */
+
+/* Macros for turning off free lists in the library */
+/*#define H5_NO_FREE_LISTS*/
+#if defined H5_NO_FREE_LISTS || defined H5_USING_MEMCHECKER
+#define H5_NO_REG_FREE_LISTS
+#define H5_NO_ARR_FREE_LISTS
+#define H5_NO_SEQ_FREE_LISTS
+#define H5_NO_BLK_FREE_LISTS
+#define H5_NO_FAC_FREE_LISTS
+#endif /* H5_NO_FREE_LISTS */
+
+/* Macro to track location where block was allocated from */
+/* Uncomment next line to turn on tracking, but don't leave it on after
+ * debugging is done because of the extra overhead it imposes.
+ */
+/* NOTE: This hasn't been extended to all the free-list allocation routines
+ * yet. -QAK
+ */
+/* #define H5FL_TRACK */
+#ifdef H5FL_TRACK
+/* Macro for inclusion in the free list allocation calls */
+#define H5FL_TRACK_INFO ,__FILE__, FUNC, __LINE__
+
+/* Macro for inclusion in internal free list allocation calls */
+#define H5FL_TRACK_INFO_INT ,call_file, call_func, call_line
+
+/* Macro for inclusion in the free list allocation parameters */
+#define H5FL_TRACK_PARAMS ,const char *call_file, const char *call_func, int call_line
+
+/* Forward declarations for structure fields */
+struct H5CS_t;
+
+/* Tracking information for each block */
+typedef struct H5FL_track_t {
+ struct H5CS_t *stack; /* Function stack */
+ char *file; /* Name of file containing calling function */
+ char *func; /* Name of calling function */
+ int line; /* Line # within calling function */
+ struct H5FL_track_t *next; /* Pointer to next tracking block */
+ struct H5FL_track_t *prev; /* Pointer to previous tracking block */
+} H5FL_track_t;
+
+/* Macro for size of tracking information */
+#define H5FL_TRACK_SIZE sizeof(H5FL_track_t)
+
+#else /* H5FL_TRACK */
+#define H5FL_TRACK_INFO
+#define H5FL_TRACK_INFO_INT
+#define H5FL_TRACK_PARAMS
+#define H5FL_TRACK_SIZE 0
+#endif /* H5FL_TRACK */
+
+/*
+ * Private datatypes.
+ */
+
+/* Data structure to store each block in free list */
+typedef struct H5FL_reg_node_t {
+ struct H5FL_reg_node_t *next; /* Pointer to next block in free list */
+} H5FL_reg_node_t;
+
+/* Data structure for free list of blocks */
+typedef struct H5FL_reg_head_t {
+ hbool_t init; /* Whether the free list has been initialized */
+ unsigned allocated; /* Number of blocks allocated */
+ unsigned onlist; /* Number of blocks on free list */
+ const char *name; /* Name of the type */
+ size_t size; /* Size of the blocks in the list */
+ H5FL_reg_node_t *list; /* List of free blocks */
+} H5FL_reg_head_t;
+
+/*
+ * Macros for defining & using free lists for a type
+ */
+#define H5FL_REG_NAME(t) H5_##t##_reg_free_list
+#ifndef H5_NO_REG_FREE_LISTS
+/* Common macros for H5FL_DEFINE & H5FL_DEFINE_STATIC */
+#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,#t,sizeof(t),NULL}
+
+/* Declare a free list to manage objects of type 't' */
+#define H5FL_DEFINE(t) H5_DLL H5FL_DEFINE_COMMON(t)
+
+/* Reference a free list for type 't' defined in another file */
+#define H5FL_EXTERN(t) H5_DLLVAR H5FL_reg_head_t H5FL_REG_NAME(t)
+
+/* Declare a static free list to manage objects of type 't' */
+#define H5FL_DEFINE_STATIC(t) static H5FL_DEFINE_COMMON(t)
+
+/* Allocate an object of type 't' */
+#define H5FL_MALLOC(t) (t *)H5FL_reg_malloc(&(H5FL_REG_NAME(t)) H5FL_TRACK_INFO)
+
+/* Allocate an object of type 't' and clear it to all zeros */
+#define H5FL_CALLOC(t) (t *)H5FL_reg_calloc(&(H5FL_REG_NAME(t)) H5FL_TRACK_INFO)
+
+/* Free an object of type 't' */
+#define H5FL_FREE(t,obj) (t *)H5FL_reg_free(&(H5FL_REG_NAME(t)),obj)
+
+/* Re-allocating an object of type 't' is not defined, because these free-lists
+ * only support fixed sized types, like structs, etc..
+ */
+
+#else /* H5_NO_REG_FREE_LISTS */
+#include "H5MMprivate.h"
+/* Common macro for H5FL_DEFINE & H5FL_DEFINE_STATIC */
+#define H5FL_DEFINE_COMMON(t) int H5_ATTR_UNUSED H5FL_REG_NAME(t)
+
+#define H5FL_DEFINE(t) H5_DLL H5FL_DEFINE_COMMON(t)
+#define H5FL_EXTERN(t) H5_DLLVAR H5FL_DEFINE_COMMON(t)
+#define H5FL_DEFINE_STATIC(t) static H5FL_DEFINE_COMMON(t)
+#define H5FL_MALLOC(t) (t *)H5MM_malloc(sizeof(t))
+#define H5FL_CALLOC(t) (t *)H5MM_calloc(sizeof(t))
+#define H5FL_FREE(t,obj) (t *)H5MM_xfree(obj)
+#endif /* H5_NO_REG_FREE_LISTS */
+
+/* Data structure to store information about each block allocated */
+typedef union H5FL_blk_list_t {
+ size_t size; /* Size of the page */
+ union H5FL_blk_list_t *next; /* Pointer to next block in free list */
+ double unused1; /* Unused normally, just here for aligment */
+ haddr_t unused2; /* Unused normally, just here for aligment */
+} H5FL_blk_list_t;
+
+/* Data structure for priority queue node of block free lists */
+typedef struct H5FL_blk_node_t {
+ size_t size; /* Size of the blocks in the list */
+ H5FL_blk_list_t *list; /* List of free blocks */
+ struct H5FL_blk_node_t *next; /* Pointer to next free list in queue */
+ struct H5FL_blk_node_t *prev; /* Pointer to previous free list in queue */
+} H5FL_blk_node_t;
+
+/* Data structure for priority queue of native block free lists */
+typedef struct H5FL_blk_head_t {
+ hbool_t init; /* Whether the free list has been initialized */
+ unsigned allocated; /* Number of blocks allocated */
+ unsigned onlist; /* Number of blocks on free list */
+ size_t list_mem; /* Amount of memory in block on free list */
+ const char *name; /* Name of the type */
+ H5FL_blk_node_t *head; /* Pointer to first free list in queue */
+} H5FL_blk_head_t;
+
+/*
+ * Macros for defining & using priority queues
+ */
+#define H5FL_BLK_NAME(t) H5_##t##_blk_free_list
+#ifndef H5_NO_BLK_FREE_LISTS
+/* Common macro for H5FL_BLK_DEFINE & H5FL_BLK_DEFINE_STATIC */
+#define H5FL_BLK_DEFINE_COMMON(t) H5FL_blk_head_t H5FL_BLK_NAME(t)={0,0,0,0,#t"_blk",NULL}
+
+/* Declare a free list to manage objects of type 't' */
+#define H5FL_BLK_DEFINE(t) H5_DLL H5FL_BLK_DEFINE_COMMON(t)
+
+/* Reference a free list for type 't' defined in another file */
+#define H5FL_BLK_EXTERN(t) H5_DLLVAR H5FL_blk_head_t H5FL_BLK_NAME(t)
+
+/* Declare a static free list to manage objects of type 't' */
+#define H5FL_BLK_DEFINE_STATIC(t) static H5FL_BLK_DEFINE_COMMON(t)
+
+/* Allocate an block of type 't' */
+#define H5FL_BLK_MALLOC(t,size) (uint8_t *)H5FL_blk_malloc(&(H5FL_BLK_NAME(t)),size H5FL_TRACK_INFO)
+
+/* Allocate an block of type 't' and clear it to zeros */
+#define H5FL_BLK_CALLOC(t,size) (uint8_t *)H5FL_blk_calloc(&(H5FL_BLK_NAME(t)),size H5FL_TRACK_INFO)
+
+/* Free a block of type 't' */
+#define H5FL_BLK_FREE(t,blk) (uint8_t *)H5FL_blk_free(&(H5FL_BLK_NAME(t)),blk)
+
+/* Re-allocate a block of type 't' */
+#define H5FL_BLK_REALLOC(t,blk,new_size) (uint8_t *)H5FL_blk_realloc(&(H5FL_BLK_NAME(t)),blk,new_size H5FL_TRACK_INFO)
+
+/* Check if there is a free block available to re-use */
+#define H5FL_BLK_AVAIL(t,size) H5FL_blk_free_block_avail(&(H5FL_BLK_NAME(t)),size)
+
+#else /* H5_NO_BLK_FREE_LISTS */
+/* Common macro for H5FL_BLK_DEFINE & H5FL_BLK_DEFINE_STATIC */
+#define H5FL_BLK_DEFINE_COMMON(t) int H5_ATTR_UNUSED H5FL_BLK_NAME(t)
+
+#define H5FL_BLK_DEFINE(t) H5_DLL H5FL_BLK_DEFINE_COMMON(t)
+#define H5FL_BLK_EXTERN(t) H5_DLLVAR H5FL_BLK_DEFINE_COMMON(t)
+#define H5FL_BLK_DEFINE_STATIC(t) static H5FL_BLK_DEFINE_COMMON(t)
+#define H5FL_BLK_MALLOC(t,size) (uint8_t *)H5MM_malloc(size)
+#define H5FL_BLK_CALLOC(t,size) (uint8_t *)H5MM_calloc(size)
+#define H5FL_BLK_FREE(t,blk) (uint8_t *)H5MM_xfree(blk)
+#define H5FL_BLK_REALLOC(t,blk,new_size) (uint8_t *)H5MM_realloc(blk,new_size)
+#define H5FL_BLK_AVAIL(t,size) (FALSE)
+#endif /* H5_NO_BLK_FREE_LISTS */
+
+/* Data structure to store each array in free list */
+typedef union H5FL_arr_list_t {
+ union H5FL_arr_list_t *next; /* Pointer to next block in free list */
+ size_t nelem; /* Number of elements in this array */
+ double unused1; /* Unused normally, just here for aligment */
+ haddr_t unused2; /* Unused normally, just here for aligment */
+} H5FL_arr_list_t;
+
+/* Data structure for each size of array element */
+typedef struct H5FL_arr_node_t {
+ size_t size; /* Size of the blocks in the list */
+ unsigned onlist; /* Number of blocks on free list */
+ H5FL_arr_list_t *list; /* List of free blocks */
+} H5FL_arr_node_t;
+
+/* Data structure for free list of array blocks */
+typedef struct H5FL_arr_head_t {
+ hbool_t init; /* Whether the free list has been initialized */
+ unsigned allocated; /* Number of blocks allocated */
+ size_t list_mem; /* Amount of memory in block on free list */
+ const char *name; /* Name of the type */
+ int maxelem; /* Maximum number of elements in an array */
+ size_t base_size; /* Size of the "base" object in the list */
+ size_t elem_size; /* Size of the array elements in the list */
+ H5FL_arr_node_t *list_arr; /* Array of lists of free blocks */
+} H5FL_arr_head_t;
+
+/*
+ * Macros for defining & using free lists for an array of a type
+ */
+#define H5FL_ARR_NAME(t) H5_##t##_arr_free_list
+#ifndef H5_NO_ARR_FREE_LISTS
+/* Common macro for H5FL_ARR_DEFINE & H5FL_ARR_DEFINE_STATIC (and H5FL_BARR variants) */
+#define H5FL_ARR_DEFINE_COMMON(b,t,m) H5FL_arr_head_t H5FL_ARR_NAME(t)={0,0,0,#t"_arr",m+1,b,sizeof(t),NULL}
+
+/* Declare a free list to manage arrays of type 't' */
+#define H5FL_ARR_DEFINE(t,m) H5_DLL H5FL_ARR_DEFINE_COMMON(0,t,m)
+
+/* Declare a free list to manage base 'b' + arrays of type 't' */
+#define H5FL_BARR_DEFINE(b,t,m) H5_DLL H5FL_ARR_DEFINE_COMMON(sizeof(b),t,m)
+
+/* Reference a free list for arrays of type 't' defined in another file */
+#define H5FL_ARR_EXTERN(t) H5_DLLVAR H5FL_arr_head_t H5FL_ARR_NAME(t)
+
+/* Declare a static free list to manage arrays of type 't' */
+#define H5FL_ARR_DEFINE_STATIC(t,m) static H5FL_ARR_DEFINE_COMMON(0,t,m)
+
+/* Declare a static free list to manage base 'b' + arrays of type 't' */
+#define H5FL_BARR_DEFINE_STATIC(b,t,m) static H5FL_ARR_DEFINE_COMMON(sizeof(b),t,m)
+
+/* Allocate an array of type 't' */
+#define H5FL_ARR_MALLOC(t,elem) H5FL_arr_malloc(&(H5FL_ARR_NAME(t)),elem)
+
+/* Allocate an array of type 't' and clear it to all zeros */
+#define H5FL_ARR_CALLOC(t,elem) H5FL_arr_calloc(&(H5FL_ARR_NAME(t)),elem)
+
+/* Free an array of type 't' */
+#define H5FL_ARR_FREE(t,obj) (t *)H5FL_arr_free(&(H5FL_ARR_NAME(t)),obj)
+
+/* Re-allocate an array of type 't' */
+#define H5FL_ARR_REALLOC(t,obj,new_elem) H5FL_arr_realloc(&(H5FL_ARR_NAME(t)),obj,new_elem)
+
+#else /* H5_NO_ARR_FREE_LISTS */
+/* Common macro for H5FL_ARR_DEFINE & H5FL_ARR_DEFINE_STATIC (and H5FL_BARR variants) */
+#define H5FL_ARR_DEFINE_COMMON(t,m) size_t H5FL_ARR_NAME(t)
+
+#define H5FL_ARR_DEFINE(t,m) H5_DLL H5FL_ARR_DEFINE_COMMON(t,m) = 0
+#define H5FL_BARR_DEFINE(b,t,m) H5_DLL H5FL_ARR_DEFINE_COMMON(t,m) = sizeof(b)
+#define H5FL_ARR_EXTERN(t) H5_DLLVAR H5FL_ARR_DEFINE_COMMON(t,m)
+#define H5FL_ARR_DEFINE_STATIC(t,m) static H5FL_ARR_DEFINE_COMMON(t,m) = 0
+#define H5FL_BARR_DEFINE_STATIC(b,t,m) static H5FL_ARR_DEFINE_COMMON(t,m) = sizeof(b)
+#define H5FL_ARR_MALLOC(t,elem) H5MM_malloc(H5FL_ARR_NAME(t) + ((elem)*sizeof(t)))
+#define H5FL_ARR_CALLOC(t,elem) H5MM_calloc(H5FL_ARR_NAME(t) + ((elem)*sizeof(t)))
+#define H5FL_ARR_FREE(t,obj) (t *)H5MM_xfree(obj)
+#define H5FL_ARR_REALLOC(t,obj,new_elem) H5MM_realloc(obj,H5FL_ARR_NAME(t) + ((new_elem)*sizeof(t)))
+#endif /* H5_NO_ARR_FREE_LISTS */
+
+/* Data structure for free list of sequence blocks */
+typedef struct H5FL_seq_head_t {
+ H5FL_blk_head_t queue; /* Priority queue of sequence blocks */
+ size_t size; /* Size of the sequence elements in the list */
+} H5FL_seq_head_t;
+
+/*
+ * Macros for defining & using free lists for a sequence of a type
+ *
+ * Sequences are like arrays, except they have no upper limit.
+ *
+ */
+#define H5FL_SEQ_NAME(t) H5_##t##_seq_free_list
+#ifndef H5_NO_SEQ_FREE_LISTS
+/* Common macro for H5FL_SEQ_DEFINE & H5FL_SEQ_DEFINE_STATIC */
+#define H5FL_SEQ_DEFINE_COMMON(t) H5FL_seq_head_t H5FL_SEQ_NAME(t)={{0,0,0,0,#t"_seq",NULL},sizeof(t)}
+
+/* Declare a free list to manage sequences of type 't' */
+#define H5FL_SEQ_DEFINE(t) H5_DLL H5FL_SEQ_DEFINE_COMMON(t)
+
+/* Reference a free list for sequences of type 't' defined in another file */
+#define H5FL_SEQ_EXTERN(t) H5_DLLVAR H5FL_seq_head_t H5FL_SEQ_NAME(t)
+
+/* Declare a static free list to manage sequences of type 't' */
+#define H5FL_SEQ_DEFINE_STATIC(t) static H5FL_SEQ_DEFINE_COMMON(t)
+
+/* Allocate a sequence of type 't' */
+#define H5FL_SEQ_MALLOC(t,elem) (t *)H5FL_seq_malloc(&(H5FL_SEQ_NAME(t)),elem H5FL_TRACK_INFO)
+
+/* Allocate a sequence of type 't' and clear it to all zeros */
+#define H5FL_SEQ_CALLOC(t,elem) (t *)H5FL_seq_calloc(&(H5FL_SEQ_NAME(t)),elem H5FL_TRACK_INFO)
+
+/* Free a sequence of type 't' */
+#define H5FL_SEQ_FREE(t,obj) (t *)H5FL_seq_free(&(H5FL_SEQ_NAME(t)),obj)
+
+/* Re-allocate a sequence of type 't' */
+#define H5FL_SEQ_REALLOC(t,obj,new_elem) (t *)H5FL_seq_realloc(&(H5FL_SEQ_NAME(t)),obj,new_elem H5FL_TRACK_INFO)
+
+#else /* H5_NO_SEQ_FREE_LISTS */
+/* Common macro for H5FL_SEQ_DEFINE & H5FL_SEQ_DEFINE_STATIC */
+#define H5FL_SEQ_DEFINE_COMMON(t) int H5_ATTR_UNUSED H5FL_SEQ_NAME(t)
+
+#define H5FL_SEQ_DEFINE(t) H5_DLL H5FL_SEQ_DEFINE_COMMON(t)
+#define H5FL_SEQ_EXTERN(t) H5_DLLVAR H5FL_SEQ_DEFINE_COMMON(t)
+#define H5FL_SEQ_DEFINE_STATIC(t) static H5FL_SEQ_DEFINE_COMMON(t)
+#define H5FL_SEQ_MALLOC(t,elem) (t *)H5MM_malloc((elem)*sizeof(t))
+#define H5FL_SEQ_CALLOC(t,elem) (t *)H5MM_calloc((elem)*sizeof(t))
+#define H5FL_SEQ_FREE(t,obj) (t *)H5MM_xfree(obj)
+#define H5FL_SEQ_REALLOC(t,obj,new_elem) (t *)H5MM_realloc(obj,(new_elem)*sizeof(t))
+#endif /* H5_NO_SEQ_FREE_LISTS */
+
+/* Forward declarations of the data structures for free list block factory */
+typedef struct H5FL_fac_gc_node_t H5FL_fac_gc_node_t;
+typedef struct H5FL_fac_node_t H5FL_fac_node_t;
+
+/* Data structure for free list block factory */
+typedef struct H5FL_fac_head_t {
+ hbool_t init; /* Whether the free list has been initialized */
+ unsigned allocated; /* Number of blocks allocated */
+ unsigned onlist; /* Number of blocks on free list */
+ size_t size; /* Size of the blocks in the list */
+ H5FL_fac_node_t *list; /* List of free blocks */
+ H5FL_fac_gc_node_t *prev_gc; /* Previous garbage collection node in list */
+} H5FL_fac_head_t;
+
+
+/*
+ * Macros for defining & using free list factories
+ *
+ * Factories are dynamically created free list managers for blocks of
+ * a particular size.
+ *
+ */
+#ifndef H5_NO_FAC_FREE_LISTS
+/* Allocate a block from a factory */
+#define H5FL_FAC_MALLOC(f) H5FL_fac_malloc(f H5FL_TRACK_INFO)
+
+/* Allocate a block from a factory and clear it to all zeros */
+#define H5FL_FAC_CALLOC(f) H5FL_fac_calloc(f H5FL_TRACK_INFO)
+
+/* Return a block to a factory */
+#define H5FL_FAC_FREE(f, obj) H5FL_fac_free(f, obj)
+
+#else /* H5_NO_FAC_FREE_LISTS */
+#define H5FL_FAC_MALLOC(f) H5MM_malloc(f->size)
+#define H5FL_FAC_CALLOC(f) H5MM_calloc(f->size)
+#define H5FL_FAC_FREE(f, obj) H5MM_xfree(obj)
+#endif /* H5_NO_FAC_FREE_LISTS */
+
+/*
+ * Library prototypes.
+ */
+ /* Block free lists */
+H5_DLL void * H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_blk_free(H5FL_blk_head_t *head, void *block);
+H5_DLL void * H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_PARAMS);
+H5_DLL htri_t H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size);
+
+/* Regular free lists */
+H5_DLL void * H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_reg_free(H5FL_reg_head_t *head, void *obj);
+
+/* Array free lists */
+H5_DLL void * H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem);
+H5_DLL void * H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem);
+H5_DLL void * H5FL_arr_free(H5FL_arr_head_t *head, void *obj);
+H5_DLL void * H5FL_arr_realloc(H5FL_arr_head_t *head, void *obj, size_t new_elem);
+
+/* Sequence free lists */
+H5_DLL void * H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj);
+H5_DLL void * H5FL_seq_realloc(H5FL_seq_head_t *head, void *obj, size_t new_elem H5FL_TRACK_PARAMS);
+
+/* Factory free lists */
+H5_DLL H5FL_fac_head_t *H5FL_fac_init(size_t size);
+H5_DLL void * H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS);
+H5_DLL void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj);
+H5_DLL herr_t H5FL_fac_term(H5FL_fac_head_t *head);
+
+/* General free list routines */
+H5_DLL herr_t H5FL_garbage_coll(void);
+H5_DLL herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim,
+ int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim,
+ int fac_global_lim, int fac_list_lim);
+H5_DLL int H5FL_term_interface(void);
+
+#endif
diff --git a/src/H5FO.c b/src/H5FO.c
new file mode 100644
index 0000000..627ee64
--- /dev/null
+++ b/src/H5FO.c
@@ -0,0 +1,602 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Open object info algorithms.
+ *
+ * These are used to track the objects currently open in a file, for various
+ * internal mechanisms which need to be aware of such things.
+ *
+ */
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Oprivate.h" /* Object headers */
+
+/* Private typedefs */
+
+/* Information about open objects in a file */
+typedef struct H5FO_open_obj_t {
+ haddr_t addr; /* Address of object header for object */
+ void *obj; /* Pointer to the object */
+ hbool_t deleted; /* Flag to indicate that the object was deleted from the file */
+} H5FO_open_obj_t;
+
+/* Information about counted objects in a file */
+typedef struct H5FO_obj_count_t {
+ haddr_t addr; /* Address of object header for object */
+ hsize_t count; /* Number of times object is opened */
+} H5FO_obj_count_t;
+
+/* Declare a free list to manage the H5FO_open_obj_t struct */
+H5FL_DEFINE_STATIC(H5FO_open_obj_t);
+
+/* Declare a free list to manage the H5FO_obj_count_t struct */
+H5FL_DEFINE_STATIC(H5FO_obj_count_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_create
+ PURPOSE
+ Create an open object info set
+ USAGE
+ herr_t H5FO_create(f)
+ H5F_t *f; IN/OUT: File to create opened object info set for
+
+ RETURNS
+ Returns non-negative on success, negative on failure
+ DESCRIPTION
+ Create a new open object info set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_create(const H5F_t *f)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Create container used to store open object info */
+ if((f->shared->open_objs = H5SL_create(H5SL_TYPE_HADDR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create open object container")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_opened
+ PURPOSE
+ Checks if an object at an address is already open in the file.
+ USAGE
+ void * H5FO_opened(f,addr)
+ const H5F_t *f; IN: File to check opened object info set
+ haddr_t addr; IN: Address of object to check
+
+ RETURNS
+ Returns a pointer to the object on success, NULL on failure
+ DESCRIPTION
+ Check is an object at an address (the address of the object's object header)
+ is already open in the file and return the ID for that object if it is open.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5FO_opened(const H5F_t *f, haddr_t addr)
+{
+ H5FO_open_obj_t *open_obj; /* Information about open object */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (open_obj = (H5FO_open_obj_t *)H5SL_search(f->shared->open_objs,&addr))) {
+ ret_value = open_obj->obj;
+ HDassert(ret_value != NULL);
+ } /* end if */
+ else
+ ret_value = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_opened() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_insert
+ PURPOSE
+ Insert a newly opened object/pointer pair into the opened object info set
+ USAGE
+ herr_t H5FO_insert(f,addr,obj)
+ H5F_t *f; IN/OUT: File's opened object info set
+ haddr_t addr; IN: Address of object to insert
+ void *obj; IN: Pointer to object to insert
+ hbool_t delete_flag; IN: Whether to 'mark' this object for deletion
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Insert an object/ID pair into the opened object info set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_insert(const H5F_t *f, haddr_t addr, void *obj, hbool_t delete_flag)
+{
+ H5FO_open_obj_t *open_obj; /* Information about open object */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(obj);
+
+ /* Allocate new opened object information structure */
+ if((open_obj=H5FL_MALLOC(H5FO_open_obj_t))==NULL)
+ HGOTO_ERROR(H5E_CACHE,H5E_NOSPACE,FAIL,"memory allocation failed")
+
+ /* Assign information */
+ open_obj->addr=addr;
+ open_obj->obj=obj;
+ open_obj->deleted=delete_flag;
+
+ /* Insert into container */
+ if(H5SL_insert(f->shared->open_objs,&open_obj->addr,open_obj)<0)
+ HGOTO_ERROR(H5E_CACHE,H5E_CANTINSERT,FAIL,"can't insert object into container")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_insert() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_delete
+ PURPOSE
+ Remove an opened object/ID pair from the opened object info set
+ USAGE
+ herr_t H5FO_delete(f,addr)
+ H5F_t *f; IN/OUT: File's opened object info set
+ haddr_t addr; IN: Address of object to remove
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Remove an object/ID pair from the opened object info.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)
+{
+ H5FO_open_obj_t *open_obj; /* Information about open object */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Remove from container */
+ if(NULL == (open_obj = (H5FO_open_obj_t *)H5SL_remove(f->shared->open_objs, &addr)))
+ HGOTO_ERROR(H5E_CACHE,H5E_CANTRELEASE,FAIL,"can't remove object from container")
+
+ /* Check if the object was deleted from the file */
+ if(open_obj->deleted) {
+ if(H5O_delete(f, dxpl_id, addr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file")
+ } /* end if */
+
+ /* Release the object information */
+ open_obj = H5FL_FREE(H5FO_open_obj_t, open_obj);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_delete() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_mark
+ PURPOSE
+ Mark an object to be deleted when it is closed
+ USAGE
+ herr_t H5FO_mark(f,addr)
+ const H5F_t *f; IN: File opened object is in
+ haddr_t addr; IN: Address of object to delete
+
+ RETURNS
+ Returns a non-negative ID for the object on success, negative on failure
+ DESCRIPTION
+ Mark an opened object for deletion from the file when it is closed.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_mark(const H5F_t *f, haddr_t addr, hbool_t deleted)
+{
+ H5FO_open_obj_t *open_obj; /* Information about open object */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (open_obj = (H5FO_open_obj_t *)H5SL_search(f->shared->open_objs, &addr)))
+ open_obj->deleted = deleted;
+ else
+ ret_value = FAIL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_mark() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_marked
+ PURPOSE
+ Check if an object is marked to be deleted when it is closed
+ USAGE
+ hbool_t H5FO_marked(f,addr)
+ const H5F_t *f; IN: File opened object is in
+ haddr_t addr; IN: Address of object to delete
+
+ RETURNS
+ Returns a TRUE/FALSE on success
+ DESCRIPTION
+ Checks if the object is currently in the "opened objects" tree and
+ whether its marks for deletion from the file when it is closed.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hbool_t
+H5FO_marked(const H5F_t *f, haddr_t addr)
+{
+ H5FO_open_obj_t *open_obj; /* Information about open object */
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (open_obj = (H5FO_open_obj_t *)H5SL_search(f->shared->open_objs, &addr)))
+ ret_value = open_obj->deleted;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_marked() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_dest
+ PURPOSE
+ Destroy an open object info set
+ USAGE
+ herr_t H5FO_dest(f)
+ H5F_t *f; IN/OUT: File's opened object info set
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Destroy an existing open object info set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_dest(const H5F_t *f)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->open_objs);
+
+ /* Check if the object info set is empty */
+ if(H5SL_count(f->shared->open_objs)!=0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "objects still in open object info set")
+
+ /* Release the open object info set container */
+ if(H5SL_close(f->shared->open_objs)<0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCLOSEOBJ, FAIL, "can't close open object info set")
+
+ f->shared->open_objs=NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_dest() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_top_create
+ PURPOSE
+ Create the "top" open object count set
+ USAGE
+ herr_t H5FO_create(f)
+ H5F_t *f; IN/OUT: File to create opened object count set for
+
+ RETURNS
+ Returns non-negative on success, negative on failure
+ DESCRIPTION
+ Create a new open object count set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_top_create(H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Create container used to store open object info */
+ if((f->obj_count = H5SL_create(H5SL_TYPE_HADDR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create open object container")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_top_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_top_incr
+ PURPOSE
+ Increment the "top" reference count for an object in a file
+ USAGE
+ herr_t H5FO_top_incr(f, addr)
+ H5F_t *f; IN/OUT: File's opened object info set
+ haddr_t addr; IN: Address of object to increment
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Increment the reference count for an object in the opened object count set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_top_incr(const H5F_t *f, haddr_t addr)
+{
+ H5FO_obj_count_t *obj_count; /* Ref. count for object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->obj_count);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (obj_count = (H5FO_obj_count_t *)H5SL_search(f->obj_count, &addr))) {
+ (obj_count->count)++;
+ } /* end if */
+ else {
+ /* Allocate new opened object information structure */
+ if(NULL == (obj_count = H5FL_MALLOC(H5FO_obj_count_t)))
+ HGOTO_ERROR(H5E_CACHE,H5E_NOSPACE,FAIL,"memory allocation failed")
+
+ /* Assign information */
+ obj_count->addr = addr;
+ obj_count->count = 1;
+
+ /* Insert into container */
+ if(H5SL_insert(f->obj_count, &obj_count->addr, obj_count) < 0)
+ HGOTO_ERROR(H5E_CACHE,H5E_CANTINSERT,FAIL,"can't insert object into container")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_top_incr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_top_decr
+ PURPOSE
+ Decrement the "top" reference count for an object in a file
+ USAGE
+ herr_t H5FO_top_decr(f, addr)
+ H5F_t *f; IN/OUT: File's opened object info set
+ haddr_t addr; IN: Address of object to decrement
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Decrement the reference count for an object in the opened object count set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_top_decr(const H5F_t *f, haddr_t addr)
+{
+ H5FO_obj_count_t *obj_count; /* Ref. count for object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->obj_count);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (obj_count = (H5FO_obj_count_t *)H5SL_search(f->obj_count, &addr))) {
+ /* Decrement the reference count for the object */
+ (obj_count->count)--;
+
+ if(obj_count->count == 0) {
+ /* Remove from container */
+ if(NULL == (obj_count = (H5FO_obj_count_t *)H5SL_remove(f->obj_count, &addr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "can't remove object from container")
+
+ /* Release the object information */
+ obj_count = H5FL_FREE(H5FO_obj_count_t, obj_count);
+ } /* end if */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, "can't decrement ref. count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_top_decr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_top_count
+ PURPOSE
+ Return the "top" reference count for an object in a file
+ USAGE
+ hsize_t H5FO_top_incr(f, addr)
+ H5F_t *f; IN/OUT: File's opened object info set
+ haddr_t addr; IN: Address of object to increment
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the reference count for an object in the opened object count set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hsize_t
+H5FO_top_count(const H5F_t *f, haddr_t addr)
+{
+ H5FO_obj_count_t *obj_count; /* Ref. count for object */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->obj_count);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Get the object node from the container */
+ if(NULL != (obj_count = (H5FO_obj_count_t *)H5SL_search(f->obj_count, &addr)))
+ ret_value = obj_count->count;
+ else
+ ret_value = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_top_count() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5FO_top_dest
+ PURPOSE
+ Destroy an open object info set
+ USAGE
+ herr_t H5FO_top_dest(f)
+ H5F_t *f; IN/OUT: File's opened object info set
+
+ RETURNS
+ Returns a non-negative on success, negative on failure
+ DESCRIPTION
+ Destroy an existing open object info set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5FO_top_dest(H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->obj_count);
+
+ /* Check if the object count set is empty */
+ if(H5SL_count(f->obj_count) != 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "objects still in open object info set")
+
+ /* Release the open object count set container */
+ if(H5SL_close(f->obj_count) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCLOSEOBJ, FAIL, "can't close open object info set")
+
+ f->obj_count = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FO_top_dest() */
+
diff --git a/src/H5FOprivate.h b/src/H5FOprivate.h
new file mode 100644
index 0000000..aa85c29
--- /dev/null
+++ b/src/H5FOprivate.h
@@ -0,0 +1,51 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains library private information about the H5FO module
+ */
+#ifndef _H5FOprivate_H
+#define _H5FOprivate_H
+
+#ifdef LATER
+#include "H5FOpublic.h"
+#endif /* LATER */
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* File access */
+#include "H5SLprivate.h" /* Skip lists */
+
+/* Typedefs */
+
+/* Typedef for open object cache */
+typedef H5SL_t H5FO_t; /* Currently, all open objects are stored in skip list */
+
+/* Macros */
+
+/* Private routines */
+H5_DLL herr_t H5FO_create(const H5F_t *f);
+H5_DLL void *H5FO_opened(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5FO_insert(const H5F_t *f, haddr_t addr, void *obj, hbool_t delete_flag);
+H5_DLL herr_t H5FO_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr);
+H5_DLL herr_t H5FO_mark(const H5F_t *f, haddr_t addr, hbool_t deleted);
+H5_DLL hbool_t H5FO_marked(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5FO_dest(const H5F_t *f);
+H5_DLL herr_t H5FO_top_create(H5F_t *f);
+H5_DLL herr_t H5FO_top_incr(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5FO_top_decr(const H5F_t *f, haddr_t addr);
+H5_DLL hsize_t H5FO_top_count(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5FO_top_dest(H5F_t *f);
+
+#endif /* _H5FOprivate_H */
+
diff --git a/src/H5FS.c b/src/H5FS.c
new file mode 100644
index 0000000..b789dfd
--- /dev/null
+++ b/src/H5FS.c
@@ -0,0 +1,1236 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, May 2, 2006
+ *
+ * Purpose: Free space tracking functions.
+ *
+ * Note: (Used to be in the H5HFflist.c file, prior to the date above)
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FSpkg.h" /* File free space */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Section info routines */
+static herr_t H5FS_sinfo_free_sect_cb(void *item, void *key, void *op_data);
+static herr_t H5FS_sinfo_free_node_cb(void *item, void *key, void *op_data);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the H5FS_section_class_t sequence information */
+H5FL_SEQ_DEFINE(H5FS_section_class_t);
+
+/* Declare a free list to manage the H5FS_t struct */
+H5FL_DEFINE(H5FS_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_create
+ *
+ * Purpose: Allocate & initialize file free space info
+ *
+ * Return: Success: Pointer to free space structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FS_t *
+H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_create,
+ uint16_t nclasses, const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
+{
+ H5FS_t *fspace = NULL; /* New free space structure */
+ H5FS_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Creating free space manager, nclasses = %Zu\n", FUNC, nclasses);
+#endif /* H5FS_DEBUG */
+
+ /* Check arguments. */
+ HDassert(fs_create->shrink_percent);
+ HDassert(fs_create->shrink_percent < fs_create->expand_percent);
+ HDassert(fs_create->max_sect_size);
+ HDassert(nclasses == 0 || classes);
+
+ /*
+ * Allocate free space structure
+ */
+ if(NULL == (fspace = H5FS__new(f, nclasses, classes, cls_init_udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
+
+ /* Initialize creation information for free space manager */
+ fspace->client = fs_create->client;
+ fspace->shrink_percent = fs_create->shrink_percent;
+ fspace->expand_percent = fs_create->expand_percent;
+ fspace->max_sect_addr = fs_create->max_sect_addr;
+ fspace->max_sect_size = fs_create->max_sect_size;
+ fspace->swmr_write = (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) > 0;
+
+ fspace->alignment = alignment;
+ fspace->align_thres = threshold;
+
+ /* Check if the free space tracker is supposed to be persistant */
+ if(fs_addr) {
+ /* Allocate space for the free space header */
+ if(HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, dxpl_id, (hsize_t)fspace->hdr_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "file allocation failed for free space header")
+
+ /* Cache the new free space header (pinned) */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't add free space header to cache")
+
+ /* Return free space header address to caller, if desired */
+ *fs_addr = fspace->addr;
+ } /* end if */
+
+ /* Set the reference count to 1, since we inserted the entry in the cache pinned */
+ fspace->rc = 1;
+
+ /* Set the return value */
+ ret_value = fspace;
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: fspace = %p, fspace->addr = %a\n", FUNC, fspace, fspace->addr);
+#endif /* H5FS_DEBUG */
+
+done:
+ if(!ret_value && fspace)
+ if(H5FS__hdr_dest(fspace) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header")
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* H5FS_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_open
+ *
+ * Purpose: Open an existing file free space info structure on disk
+ *
+ * Return: Success: Pointer to free space structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FS_t *
+H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, uint16_t nclasses,
+ const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
+{
+ H5FS_t *fspace = NULL; /* New free space structure */
+ H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ H5FS_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Opening free space manager, fs_addr = %a, nclasses = %Zu\n", FUNC, fs_addr, nclasses);
+#endif /* H5FS_DEBUG */
+
+ /* Check arguments. */
+ HDassert(H5F_addr_defined(fs_addr));
+ HDassert(nclasses);
+ HDassert(classes);
+
+ /* Initialize user data for protecting the free space manager */
+ cache_udata.f = f;
+ cache_udata.nclasses = nclasses;
+ cache_udata.classes = classes;
+ cache_udata.cls_init_udata = cls_init_udata;
+ cache_udata.addr = fs_addr;
+
+ /* Protect the free space header */
+ if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space header")
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
+HDfprintf(stderr, "%s: fspace->sect_size = %Hu\n", FUNC, fspace->sect_size);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu\n", FUNC, fspace->alloc_sect_size);
+HDfprintf(stderr, "%s: fspace->sinfo = %p\n", FUNC, fspace->sinfo);
+HDfprintf(stderr, "%s: fspace->rc = %u\n", FUNC, fspace->rc);
+#endif /* H5FS_DEBUG */
+
+ /* Increment the reference count on the free space manager header */
+ HDassert(fspace->rc <= 1);
+ if(H5FS_incr(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header")
+
+ fspace->alignment = alignment;
+ fspace->align_thres = threshold;
+
+ /* Unlock free space header */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, NULL, "unable to release free space header")
+
+ /* Set return value */
+ ret_value = fspace;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_delete
+ *
+ * Purpose: Delete a free space manager on disk
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr)
+{
+ H5FS_t *fspace = NULL; /* Free space header loaded from file */
+ H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Deleting free space manager, fs_addr = %a\n", FUNC, fs_addr);
+#endif /* H5FS_DEBUG */
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fs_addr));
+
+ /* Initialize user data for protecting the free space manager */
+ /* (no class information necessary for delete) */
+ cache_udata.f = f;
+ cache_udata.nclasses = 0;
+ cache_udata.classes = NULL;
+ cache_udata.cls_init_udata = NULL;
+ cache_udata.addr = fs_addr;
+
+#ifdef H5FS_DEBUG
+{
+ unsigned fspace_status = 0; /* Free space section info's status in the metadata cache */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(fs_addr));
+
+ /* Check the free space section info's status in the metadata cache */
+ if(H5AC_get_entry_status(f, fs_addr, &fspace_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for free space section info")
+
+ HDfprintf(stderr, "%s: fspace_status = %0x: ", FUNC, fspace_status);
+ if(fspace_status) {
+ hbool_t printed = FALSE;
+
+ if(fspace_status & H5AC_ES__IN_CACHE) {
+ HDfprintf(stderr, "H5AC_ES__IN_CACHE");
+ printed = TRUE;
+ } /* end if */
+ if(fspace_status & H5AC_ES__IS_DIRTY) {
+ HDfprintf(stderr, "%sH5AC_ES__IS_DIRTY", (printed ? " | " : ""));
+ printed = TRUE;
+ } /* end if */
+ if(fspace_status & H5AC_ES__IS_PROTECTED) {
+ HDfprintf(stderr, "%sH5AC_ES__IS_PROTECTED", (printed ? " | " : ""));
+ printed = TRUE;
+ } /* end if */
+ if(fspace_status & H5AC_ES__IS_PINNED) {
+ HDfprintf(stderr, "%sH5AC_ES__IS_PINNED", (printed ? " | " : ""));
+ printed = TRUE;
+ } /* end if */
+ if(fspace_status & H5AC_ES__IS_FLUSH_DEP_PARENT) {
+ HDfprintf(stderr, "%sH5AC_ES__IS_FLUSH_DEP_PARENT", (printed ? " | " : ""));
+ printed = TRUE;
+ } /* end if */
+ if(fspace_status & H5AC_ES__IS_FLUSH_DEP_CHILD) {
+ HDfprintf(stderr, "%sH5AC_ES__IS_FLUSH_DEP_CHILD", (printed ? " | " : ""));
+ printed = TRUE;
+ } /* end if */
+ } /* end if */
+ HDfprintf(stderr, "\n");
+}
+#endif /* H5FS_DEBUG */
+
+ /* Protect the free space header */
+ if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header")
+
+ /* Sanity check */
+ HDassert(fspace->sinfo == NULL);
+
+ /* Delete serialized section storage, if there are any */
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
+#endif /* H5FS_DEBUG */
+ if(fspace->serial_sect_count > 0) {
+ unsigned sinfo_status = 0; /* Free space section info's status in the metadata cache */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(fspace->sect_addr));
+ HDassert(fspace->alloc_sect_size > 0);
+
+ /* Check the free space section info's status in the metadata cache */
+ if(H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for free space section info")
+
+ /* If the free space section info is in the cache, expunge it now */
+ if(sinfo_status & H5AC_ES__IN_CACHE) {
+ /* Sanity checks on direct block */
+ HDassert(!(sinfo_status & H5AC_ES__IS_PINNED));
+ HDassert(!(sinfo_status & H5AC_ES__IS_PROTECTED));
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Expunging free space section info from cache\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Evict the free space section info from the metadata cache */
+ /* (Free file space) */
+ {
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+
+ /* if the indirect block is in real file space, tell
+ * the cache to free its file space.
+ */
+ if (!H5F_IS_TMP_ADDR(f, fspace->sect_addr))
+ cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+ if(H5AC_expunge_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, cache_flags) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove free space section info from cache")
+ } /* end block */
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Done expunging free space section info from cache\n", FUNC);
+#endif /* H5FS_DEBUG */
+ } /* end if */
+ else {
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Deleting free space section info from file\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Release the space in the file */
+ if(!H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
+ if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+done:
+ if(fspace && H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_close
+ *
+ * Purpose: Destroy & deallocate free list structure, serializing sections
+ * in the bins
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Entering, fspace = %p, fspace->addr = %a, fspace->sinfo = %p\n", FUNC, fspace, fspace->addr, fspace->sinfo);
+#endif /* H5FS_DEBUG */
+
+ /* Check if section info is valid */
+ /* (i.e. the header "owns" the section info and it's not in the cache) */
+ if(fspace->sinfo) {
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu, fspace->serial_sect_count = %Hu, fspace->sect_addr = %a, fspace->rc = %u\n", FUNC, fspace->tot_sect_count, fspace->serial_sect_count, fspace->sect_addr, fspace->rc);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
+#endif /* H5FS_DEBUG */
+ /* If there are sections to serialize, update them */
+ /* (if the free space manager is persistant) */
+ if(fspace->serial_sect_count > 0 && H5F_addr_defined(fspace->addr)) {
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Real sections to store in file\n", FUNC);
+#endif /* H5FS_DEBUG */
+ if(fspace->sinfo->dirty) {
+ /* Check if the section info is "floating" */
+ if(!H5F_addr_defined(fspace->sect_addr)) {
+ /* Sanity check */
+ HDassert(fspace->sect_size > 0);
+
+ /* Allocate space for the section info in file */
+ if(H5F_USE_TMP_SPACE(f)) {
+ if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc_tmp(f, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+ } /* end if */
+ else {
+ if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+ } /* end if */
+ fspace->alloc_sect_size = (size_t)fspace->sect_size;
+
+ /* Mark free space header as dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end if */
+ } /* end if */
+ else
+ /* Sanity check that section info has address */
+ HDassert(H5F_addr_defined(fspace->sect_addr));
+
+ /* Cache the free space section info */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache")
+ } /* end if */
+ else {
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: NOT storing section info in file\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Check if space for the section info is allocated */
+ if(H5F_addr_defined(fspace->sect_addr)) {
+ /* Sanity check */
+ /* (section info should only be in the file if the header is */
+ HDassert(H5F_addr_defined(fspace->addr));
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Section info allocated though\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Check if the section info is for the free space in the file */
+ /* (NOTE: This is the "bootstrapping" special case for the
+ * free space manager, to avoid freeing the space for the
+ * section info and re-creating it as a section in the
+ * manager. -QAK)
+ */
+ if(fspace->client == H5FS_CLIENT_FILE_ID) {
+ htri_t status; /* "can absorb" status for section into */
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Section info is for file free space\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Try to shrink the file or absorb the section info into a block aggregator */
+ if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Section info in temp. address space went 'go away'\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Reset section info in header */
+ fspace->sect_addr = HADDR_UNDEF;
+ fspace->alloc_sect_size = 0;
+
+ /* Mark free space header as dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end if */
+ else {
+ if((status = H5MF_try_shrink(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for absorbing section info")
+ else if(status == FALSE) {
+ /* Section info can't "go away", but it's free. Allow
+ * header to record it
+ */
+#ifdef H5FS_DEBUG
+ HDfprintf(stderr, "%s: Section info can't 'go away', header will own it\n", FUNC);
+#endif /* H5FS_DEBUG */
+ } /* end if */
+ else {
+#ifdef H5FS_DEBUG
+ HDfprintf(stderr, "%s: Section info went 'go away'\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Reset section info in header */
+ fspace->sect_addr = HADDR_UNDEF;
+ fspace->alloc_sect_size = 0;
+
+ /* Mark free space header as dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ else {
+ haddr_t old_sect_addr = fspace->sect_addr; /* Previous location of section info in file */
+ hsize_t old_alloc_sect_size = fspace->alloc_sect_size; /* Previous size of section info in file */
+
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Section info is NOT for file free space\n", FUNC);
+#endif /* H5FS_DEBUG */
+ /* Reset section info in header */
+ fspace->sect_addr = HADDR_UNDEF;
+ fspace->alloc_sect_size = 0;
+
+ /* Mark free space header as dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+
+ /* Free previous serialized sections disk space */
+ if(!H5F_IS_TMP_ADDR(f, old_sect_addr)) {
+ if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_sect_addr, old_alloc_sect_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Destroy section info */
+ if(H5FS_sinfo_dest(fspace->sinfo) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space section info")
+ } /* end else */
+
+ /* Reset the header's pointer to the section info */
+ fspace->sinfo = NULL;
+ } /* end if */
+ else {
+ /* Just sanity checks... */
+ if(fspace->serial_sect_count > 0)
+ /* Sanity check that section info has address */
+ HDassert(H5F_addr_defined(fspace->sect_addr));
+ } /* end else */
+
+ /* Decrement the reference count on the free space manager header */
+ if(H5FS_decr(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
+
+done:
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d, fspace->rc = %u\n", FUNC, ret_value, fspace->rc);
+#endif /* H5FS_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__new
+ *
+ * Purpose: Create new free space manager structure
+ *
+ * Return: Success: non-NULL, pointer to new free space manager struct
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 31, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FS_t *
+H5FS__new(const H5F_t *f, uint16_t nclasses, const H5FS_section_class_t *classes[],
+ void *cls_init_udata)
+{
+ H5FS_t *fspace = NULL; /* Free space manager */
+ size_t u; /* Local index variable */
+ H5FS_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(nclasses == 0 || (nclasses > 0 && classes));
+
+ /*
+ * Allocate free space structure
+ */
+ if(NULL == (fspace = H5FL_CALLOC(H5FS_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
+
+ /* Set immutable free list parameters */
+ H5_CHECKED_ASSIGN(fspace->nclasses, uint16_t, nclasses, size_t);
+ if(nclasses > 0) {
+ if(NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section class array")
+
+ /* Initialize the section classes for this free space list */
+ for(u = 0; u < nclasses; u++) {
+ /* Make certain that section class type can be used as an array index into this array */
+ HDassert(u == classes[u]->type);
+
+ /* Copy the class information into the free space manager */
+ HDmemcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t));
+
+ /* Call the class initialization routine, if there is one */
+ if(fspace->sect_cls[u].init_cls)
+ if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class")
+
+ /* Determine maximum class-specific serialization size for each section */
+ if(fspace->sect_cls[u].serial_size > fspace->max_cls_serial_size)
+ fspace->max_cls_serial_size = fspace->sect_cls[u].serial_size;
+ } /* end for */
+ } /* end if */
+
+ /* Initialize non-zero information for new free space manager */
+ fspace->addr = HADDR_UNDEF;
+ fspace->hdr_size = (size_t)H5FS_HEADER_SIZE(f);
+ fspace->sect_addr = HADDR_UNDEF;
+
+ /* Set return value */
+ ret_value = fspace;
+
+done:
+ if(!ret_value)
+ if(fspace) {
+ /* Should probably call the class 'term' callback for all classes
+ * that have had their 'init' callback called... -QAK
+ */
+ if(fspace->sect_cls)
+ fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
+ fspace = H5FL_FREE(H5FS_t, fspace);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS__new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_size
+ *
+ * Purpose: Collect meta storage info used by the free space manager
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Vailin Choi
+ * June 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_size(const H5F_t *f, const H5FS_t *fspace, hsize_t *meta_size)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(meta_size);
+
+ /* Get the free space size info */
+ *meta_size += fspace->hdr_size + (fspace->sinfo ? fspace->sect_size : fspace->alloc_sect_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_incr
+ *
+ * Purpose: Increment reference count on free space header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * February 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_incr(H5FS_t *fspace)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
+#endif /* H5FS_DEBUG */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fspace);
+
+ /* Check if we should pin the header in the cache */
+ if(fspace->rc == 0 && H5F_addr_defined(fspace->addr))
+ if(H5AC_pin_protected_entry(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPIN, FAIL, "unable to pin free space header")
+
+ /* Increment reference count on header */
+ fspace->rc++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_decr
+ *
+ * Purpose: Decrement reference count on free space header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * February 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_decr(H5FS_t *fspace)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+#ifdef H5FS_DEBUG
+HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
+#endif /* H5FS_DEBUG */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fspace);
+
+ /* Decrement reference count on header */
+ fspace->rc--;
+
+ /* Check if we should unpin the header in the cache */
+ if(fspace->rc == 0) {
+ if(H5F_addr_defined(fspace->addr)) {
+ if(H5AC_unpin_entry(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin free space header")
+ } /* end if */
+ else {
+ if(H5FS__hdr_dest(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space header")
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_dirty
+ *
+ * Purpose: Mark free space header as dirty
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Feb 14 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_dirty(H5FS_t *fspace)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef QAK
+HDfprintf(stderr, "%s: Marking free space header as dirty\n", FUNC);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(fspace);
+
+ /* Check if the free space manager is persistant */
+ if(H5F_addr_defined(fspace->addr))
+ /* Mark header as dirty in cache */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_alloc_hdr()
+ *
+ * Purpose: Allocate space for the free-space manager header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_alloc_hdr(H5F_t *f, H5FS_t *fspace, haddr_t *fs_addr, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+
+ if(!H5F_addr_defined(fspace->addr)) {
+ /* Allocate space for the free space header */
+ if(HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, dxpl_id, (hsize_t)H5FS_HEADER_SIZE(f))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for free space header")
+
+ /* Cache the new free space header (pinned) */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space header to cache")
+ } /* end if */
+
+ if(fs_addr)
+ *fs_addr = fspace->addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_alloc_hdr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_alloc_sect()
+ *
+ * Purpose: Allocate space for the free-space manager section info header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_alloc_sect(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+
+ if(!H5F_addr_defined(fspace->sect_addr) && fspace->sinfo && fspace->serial_sect_count > 0) {
+ if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for section info")
+ fspace->alloc_sect_size = fspace->sect_size;
+
+ /* Mark free-space header as dirty */
+ if(H5FS_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+
+ /* Cache the free-space section info */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache")
+
+ /* Since space has been allocated for the section info and the sinfo
+ * has been inserted into the cache, relinquish owership (i.e. float)
+ * the section info.
+ */
+ fspace->sinfo = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_alloc_sect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_free()
+ *
+ * Purpose: Free space for free-space manager header and section info header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_free(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id, hbool_t free_file_space)
+{
+ haddr_t saved_addr; /* Previous address of item */
+ unsigned cache_flags; /* Flags for unprotecting cache entries */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+
+ cache_flags = H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;;
+
+ /* Free space for section info */
+ if(H5F_addr_defined(fspace->sect_addr)) {
+ hsize_t saved_size; /* Size of previous section info */
+ unsigned sinfo_status = 0; /* Section info cache status */
+
+ /* Check whether free-space manager section info is in cache or not */
+ if(H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "unable to check metadata cache status for free-space section info")
+
+ /* Load free-space manager section info */
+ if(sinfo_status & H5AC_ES__IN_CACHE || !fspace->sinfo) {
+ H5FS_sinfo_cache_ud_t cache_udata; /* User-data for cache callback */
+
+ /* Protect the free space sections */
+ cache_udata.f = f;
+ cache_udata.dxpl_id = dxpl_id;
+ cache_udata.fspace = fspace;
+ if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info")
+
+ /* Unload and release ownership of the free-space manager section info */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, cache_flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info")
+ } /* end if */
+
+ saved_addr = fspace->sect_addr;
+ saved_size = fspace->alloc_sect_size;
+
+ fspace->sect_addr = HADDR_UNDEF;
+ fspace->alloc_sect_size = 0;
+
+ /* Free space for the free-space manager section info */
+ if(!H5F_IS_TMP_ADDR(f, saved_addr)) {
+ if(free_file_space &&
+ H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, saved_addr, saved_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections")
+ } /* end if */
+
+ /* Mark free-space manager header as dirty */
+ if(H5FS_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end if */
+
+ /* Free space for header */
+ if(H5F_addr_defined(fspace->addr)) {
+ unsigned hdr_status = 0; /* Header entry status */
+
+ /* Check whether free-space manager header is in cache or not */
+ if(H5AC_get_entry_status(f, fspace->addr, &hdr_status) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "unable to check metadata cache status for free-space section info")
+
+ if(hdr_status & H5AC_ES__IN_CACHE) {
+ H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+
+ /* Protect the free-space manager header */
+ /* (no class information necessary since it's in the cache) */
+ cache_udata.f = f;
+ cache_udata.nclasses = 0;
+ cache_udata.classes = NULL;
+ cache_udata.cls_init_udata = NULL;
+ if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info")
+
+ /* Unpin the free-space manager header */
+ if(H5AC_unpin_entry(fspace) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap header")
+
+ /* Unload and release ownership of the free-space header */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, cache_flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info")
+ } /* end if */
+
+ saved_addr = fspace->addr;
+ fspace->addr = HADDR_UNDEF;
+
+ /* Free space for the free-space manager header */
+ if(free_file_space &&
+ H5MF_xfree(f, H5FD_MEM_FSPACE_HDR, dxpl_id, saved_addr, (hsize_t)H5FS_HEADER_SIZE(f)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space header")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__hdr_dest
+ *
+ * Purpose: Destroys a free space header in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * May 2 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS__hdr_dest(H5FS_t *fspace)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fspace);
+
+ /* Terminate the section classes for this free space list */
+ for(u = 0; u < fspace->nclasses ; u++) {
+ /* Call the class termination routine, if there is one */
+ if(fspace->sect_cls[u].term_cls)
+ if((fspace->sect_cls[u].term_cls)(&fspace->sect_cls[u]) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "unable to finalize section class")
+ } /* end for */
+
+ /* Release the memory for the free space section classes */
+ if(fspace->sect_cls)
+ fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
+
+ /* Free free space info */
+ fspace = H5FL_FREE(H5FS_t, fspace);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__hdr_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_free_sect_cb
+ *
+ * Purpose: Free a size-tracking node for a bin
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sinfo_free_sect_cb(void *_sect, void H5_ATTR_UNUSED *key, void *op_data)
+{
+ H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect; /* Section to free */
+ const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)op_data; /* Free space manager for section */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(sect);
+ HDassert(sinfo);
+
+ /* Call the section's class 'free' method on the section */
+ (*sinfo->fspace->sect_cls[sect->type].free)(sect);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_sinfo_free_sect_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_free_node_cb
+ *
+ * Purpose: Free a size-tracking node for a bin
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sinfo_free_node_cb(void *item, void H5_ATTR_UNUSED *key, void *op_data)
+{
+ H5FS_node_t *fspace_node = (H5FS_node_t *)item; /* Temporary pointer to free space list node */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(fspace_node);
+ HDassert(op_data);
+
+ /* Release the skip list for sections of this size */
+ H5SL_destroy(fspace_node->sect_list, H5FS_sinfo_free_sect_cb, op_data);
+
+ /* Release free space list node */
+ fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_sinfo_free_node_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_dest
+ *
+ * Purpose: Destroys a free space section info in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * July 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sinfo_dest(H5FS_sinfo_t *sinfo)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sinfo);
+ HDassert(sinfo->fspace);
+ HDassert(sinfo->bins);
+
+ /* Clear out lists of nodes */
+ for(u = 0; u < sinfo->nbins; u++)
+ if(sinfo->bins[u].bin_list) {
+ H5SL_destroy(sinfo->bins[u].bin_list, H5FS_sinfo_free_node_cb, sinfo);
+ sinfo->bins[u].bin_list = NULL;
+ } /* end if */
+
+ /* Release bins for skip lists */
+ sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
+
+ /* Release skip list for merging sections */
+ if(sinfo->merge_list)
+ if(H5SL_close(sinfo->merge_list) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy section merging skip list")
+
+ /* Decrement the reference count on free space header */
+ /* (make certain this is last action with section info, to allow for header
+ * disappearing immediately)
+ */
+ sinfo->fspace->sinfo = NULL;
+ if(H5FS_decr(sinfo->fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
+ sinfo->fspace = NULL;
+
+ /* Release free space section info */
+ sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_sinfo_dest() */
+
+herr_t
+H5FS_get_sect_count(const H5FS_t *frsp, hsize_t *tot_sect_count)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(frsp);
+ HDassert(tot_sect_count);
+
+ /* Report statistics for free space */
+ *tot_sect_count = frsp->serial_sect_count;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+#ifdef H5FS_DEBUG_ASSERT
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_assert
+ *
+ * Purpose: Verify that the free space manager is mostly sane
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Jul 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_assert(const H5FS_t *fspace, hid_t dxpl_id)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", "H5FS_assert", fspace->tot_sect_count);
+#endif /* QAK */
+
+ /* Checks for section info, if it's available */
+ if(fspace->sinfo) {
+ /* Sanity check sections */
+ H5FS_sect_assert(fspace, dxpl_id);
+
+ /* General assumptions about the section size counts */
+ HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->serial_size_count);
+ HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->ghost_size_count);
+ } /* end if */
+
+ /* General assumptions about the section counts */
+ HDassert(fspace->tot_sect_count >= fspace->serial_sect_count);
+ HDassert(fspace->tot_sect_count >= fspace->ghost_sect_count);
+ HDassert(fspace->tot_sect_count == (fspace->serial_sect_count + fspace->ghost_sect_count));
+#ifdef QAK
+ HDassert(fspace->serial_sect_count > 0 || fspace->ghost_sect_count == 0);
+#endif /* QAK */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS_assert() */
+#endif /* H5FS_DEBUG_ASSERT */
+
diff --git a/src/H5FScache.c b/src/H5FScache.c
new file mode 100644
index 0000000..628fba0
--- /dev/null
+++ b/src/H5FScache.c
@@ -0,0 +1,1518 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FScache.c
+ * May 2 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement file free space metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File */
+#include "H5FSpkg.h" /* File free space */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* File free space format version #'s */
+#define H5FS_HDR_VERSION 0 /* Header */
+#define H5FS_SINFO_VERSION 0 /* Serialized sections */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for skip list iterator callback for iterating over section size nodes when syncing */
+typedef struct {
+ H5FS_sinfo_t *sinfo; /* Free space section info */
+ uint8_t **image; /* Pointer to address of buffer pointer to serialize with */
+ unsigned sect_cnt_size; /* # of bytes to encode section size counts in */
+} H5FS_iter_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Section info routines */
+static herr_t H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata);
+static herr_t H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata);
+
+/* Metadata cache callbacks */
+static herr_t H5FS__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5FS__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5FS__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5FS__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5FS__cache_hdr_pre_serialize(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags);
+static herr_t H5FS__cache_hdr_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5FS__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5FS__cache_hdr_free_icr(void *thing);
+
+static herr_t H5FS__cache_sinfo_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5FS__cache_sinfo_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5FS__cache_sinfo_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5FS__cache_sinfo_image_len(const void *thing, size_t *image_len);
+static herr_t H5FS__cache_sinfo_pre_serialize(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags);
+static herr_t H5FS__cache_sinfo_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5FS__cache_sinfo_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5FS header inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FSPACE_HDR[1] = {{
+ H5AC_FSPACE_HDR_ID, /* Metadata client ID */
+ "Free Space Header", /* Metadata client name (for debugging) */
+ H5FD_MEM_FSPACE_HDR, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5FS__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5FS__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5FS__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5FS__cache_hdr_image_len, /* 'image_len' callback */
+ H5FS__cache_hdr_pre_serialize, /* 'pre_serialize' callback */
+ H5FS__cache_hdr_serialize, /* 'serialize' callback */
+ H5FS__cache_hdr_notify, /* 'notify' callback */
+ H5FS__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5FS section info inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{
+ H5AC_FSPACE_SINFO_ID, /* Metadata client ID */
+ "Free Space Section Info", /* Metadata client name (for debugging) */
+ H5FD_MEM_FSPACE_SINFO, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5FS__cache_sinfo_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5FS__cache_sinfo_verify_chksum, /* 'verify_chksum' callback */
+ H5FS__cache_sinfo_deserialize, /* 'deserialize' callback */
+ H5FS__cache_sinfo_image_len, /* 'image_len' callback */
+ H5FS__cache_sinfo_pre_serialize, /* 'pre_serialize' callback */
+ H5FS__cache_sinfo_serialize, /* 'serialize' callback */
+ H5FS__cache_sinfo_notify, /* 'notify' callback */
+ H5FS__cache_sinfo_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User-data for metadata cache callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5FS_HEADER_SIZE(udata->f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of the free space
+ * manager section info, allocate an instance of H5FS_t, load
+ * it with the data contained in the image, and return a pointer
+ * to the new instance.
+ *
+ * Return: Success: Pointer to new object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 18 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FS__cache_hdr_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5FS_t *fspace = NULL; /* Free space header info */
+ H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User data for callback */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned nclasses; /* Number of section classes */
+ H5FS_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Allocate a new free space manager */
+ if(NULL == (fspace = H5FS__new(udata->f, udata->nclasses, udata->classes, udata->cls_init_udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set free space manager's internal information */
+ fspace->addr = udata->addr;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5FS_HDR_VERSION)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header version")
+
+ /* Client ID */
+ fspace->client = (H5FS_client_t)*image++;
+ if(fspace->client >= H5FS_NUM_CLIENT_ID)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "unknown client ID in free space header")
+
+ /* Total space tracked */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->tot_space);
+
+ /* Total # of free space sections tracked */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->tot_sect_count);
+
+ /* # of serializable free space sections tracked */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->serial_sect_count);
+
+ /* # of ghost free space sections tracked */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->ghost_sect_count);
+
+ /* # of section classes */
+ /* (only check if we actually have some classes) */
+ UINT16DECODE(image, nclasses);
+ if(fspace->nclasses > 0 && nclasses > fspace->nclasses)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "section class count mismatch")
+
+ /* Shrink percent */
+ UINT16DECODE(image, fspace->shrink_percent);
+
+ /* Expand percent */
+ UINT16DECODE(image, fspace->expand_percent);
+
+ /* Size of address space free space sections are within
+ * (log2 of actual value)
+ */
+ UINT16DECODE(image, fspace->max_sect_addr);
+
+ /* Max. size of section to track */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->max_sect_size);
+
+ /* Address of serialized free space sections */
+ H5F_addr_decode(udata->f, &image, &fspace->sect_addr);
+
+ /* Size of serialized free space sections */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->sect_size);
+
+ /* Allocated size of serialized free space sections */
+ H5F_DECODE_LENGTH(udata->f, image, fspace->alloc_sect_size);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = fspace;
+
+done:
+ /* Release resources */
+ if(!ret_value && fspace)
+ if(H5FS__hdr_dest(fspace) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk and return
+ * it in *image_len.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_hdr_image_len(const void *_thing, size_t *image_len)
+{
+ const H5FS_t *fspace = (const H5FS_t *)_thing; /* Pointer to the object */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(fspace);
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = fspace->hdr_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_pre_serialize
+ *
+ * Purpose: The free space manager header contains the address, size, and
+ * allocation size of the free space manager section info. However,
+ * since it is possible for the section info to either not be allocated
+ * at all, or be allocated in temporary (AKA imaginary) files space,
+ * it is possible for the above mentioned fields to contain giberish
+ * when the free space manager header is serialized.
+ *
+ * This function exists to prevent this problem. It does so by
+ * forcing allocation of real file space for the section information.
+ *
+ * Note that in the Version 2 cache, this problem was dealt with by
+ * simply flushing the section info before flushing the header. This
+ * was possible, since the clients handled file I/O directly. As
+ * this responsibility has moved to the cache in Version 3, this
+ * solution is no longer directly applicable.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_hdr_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
+ haddr_t addr, size_t H5_ATTR_UNUSED len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags)
+{
+ H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(new_addr);
+ HDassert(new_len);
+ HDassert(flags);
+
+ if(fspace->sinfo) {
+ H5AC_ring_t ring;
+
+ /* Retrieve the ring type for the header */
+ if(H5AC_get_entry_ring(f, addr, &ring) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "unable to get property value");
+
+ /* Set the ring type for the section info in the DXPL */
+ if(H5AC_set_ring(dxpl_id, ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* This implies that the header "owns" the section info.
+ *
+ * Unfortunately, the comments in the code are not clear as to
+ * what this means, but from reviewing the code (most particularly
+ * H5FS_close(), H5FS_sinfo_lock, and H5FS_sinfo_unlock()), I
+ * gather that it means that the header is maintaining a pointer to
+ * an instance of H5FS_sinfo_t in which free space data is
+ * maintained, and either:
+ *
+ * 1) The instance of H5FS_sinfo_t is not in the metadata cache.
+ *
+ * This will be TRUE iff H5F_addr_defined(fspace->sect_addr)
+ * is FALSE, and fspace->sinfo is not NULL. This is sometimes
+ * referred to as "floating" section info in the comments.
+ *
+ * If the section info structure contains free space data
+ * that must be placed on disk eventually, then
+ *
+ * fspace->serial_sect_count > 0
+ *
+ * and
+ *
+ * H5F_addr_defined(fspace->addr)
+ *
+ * will both be TRUE. If this contition does not hold, then
+ * either the free space info is not persistant
+ * (!H5F_addr_defined(fspace->addr)???) or the section info
+ * contains no free space data that must be written to file
+ * ( fspace->serial_sect_count == 0 ).
+ *
+ * 2) The instance of H5FS_sinfo_t is in the metadata cache with
+ * address in temporary file space (AKA imaginary file space).
+ * The entry may or may not be protected, and if protected, it
+ * may be protected either RW or RO (as indicated by
+ * fspace->sinfo_protected and fspace->sinfo_accmod).
+ *
+ * 3) The instance of H5FS_sinfo_t is in the metadata cache with
+ * address in real file space. As in case 2) above, the entry
+ * may or may not be protected, and if protected, it
+ * may be protected either RW or RO (as indicated by
+ * fspace->sinfo_protected and fspace->sinfo_accmod).
+ *
+ * Observe that fspace->serial_sect_count > 0 must be TRUE in
+ * cases 2) and 3), as the section info should not be stored on
+ * disk if it doesn't exist. Similarly, since the section info
+ * will not be stored to disk unless the header is,
+ * H5F_addr_defined(fspace->addr) must hold as well.
+ *
+ * As the objective is to touch up the free space manager header
+ * so that it contains sensical data on the size and location of
+ * the section information, we have to handle each of the above
+ * cases differently.
+ *
+ * Case 1) If either fspace->serial_sect_count == 0 or
+ * ! H5F_addr_defined(fspace->addr) do nothing as either
+ * the free space manager data is not persistant, or the
+ * section info is empty.
+ *
+ * Otherwise, allocate space for the section info in real
+ * file space, insert the section info at this location, and
+ * set fspace->sect_addr, fspace->sect_size, and
+ * fspace->alloc_sect_size to reflect the new location
+ * of the section info. Note that it is not necessary to
+ * force a write of the section info.
+ *
+ * Case 2) Allocate space for the section info in real file space,
+ * and tell the metadata cache to relocate the entry.
+ * Update fspace->sect_addr, fspace->sect_size, and
+ * fspace->alloc_sect_size to reflect the new location.
+ *
+ * Case 3) Nothing to be done in this case, although it is useful
+ * to perform sanity checks.
+ *
+ * Note that while we may alter the contents of the free space
+ * header in cases 1) and 2), there is no need to mark the header
+ * as dirty, as the metadata cache would not be attempting to
+ * serialize the header if it thought it was clean.
+ */
+ if(fspace->serial_sect_count > 0 && H5F_addr_defined(fspace->addr)) {
+ /* Sanity check */
+ HDassert(fspace->sect_size > 0);
+
+ if(!H5F_addr_defined(fspace->sect_addr)) { /* case 1 */
+ haddr_t tag = HADDR_UNDEF;
+
+ /* allocate file space for the section info, and insert it
+ * into the metadata cache.
+ */
+ if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+
+ fspace->alloc_sect_size = (size_t)fspace->sect_size;
+
+ /* Get the tag for this free space manager and use it to insert the entry */
+ if(H5AC_get_tag((const void *)fspace, &tag) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTTAG, FAIL, "can't get tag for metadata cache object")
+ H5_BEGIN_TAG(dxpl_id, tag, FAIL)
+ if(H5AC_insert_entry((H5F_t *)f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR_TAG(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache")
+ H5_END_TAG(FAIL)
+
+ HDassert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size);
+
+ /* the metadata cache is now managing the section info,
+ * so set fspace->sinfo to NULL.
+ */
+ fspace->sinfo = NULL;
+ } /* end if */
+ else if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) { /* case 2 */
+ haddr_t new_sect_addr;
+
+ /* move the section info from temporary (AKA imaginary) file
+ * space to real file space.
+ */
+
+ /* if my reading of the code is correct, this should always
+ * be the case. If not, we will have to add code to resize
+ * file space allocation for section info as well as moving it.
+ */
+ HDassert(fspace->sect_size > 0);
+ HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
+
+ /* Allocate space for the section info in file */
+ if(HADDR_UNDEF == (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+
+ fspace->alloc_sect_size = (size_t)fspace->sect_size;
+ HDassert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size);
+
+ /* Let the metadata cache know the section info moved */
+ if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move section info")
+
+ fspace->sect_addr = new_sect_addr;
+ } /* end else-if */
+ else { /* case 3 -- nothing to do but sanity checking */
+ /* if my reading of the code is correct, this should always
+ * be the case. If not, we will have to add code to resize
+ * file space allocation for section info.
+ */
+ HDassert(fspace->sect_size > 0);
+ HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
+ } /* end else */
+ } /* end else */
+ else {
+ /* for one reason or another (see comment above) there should
+ * not be any file space allocated for the section info.
+ */
+ HDassert(!H5F_addr_defined(fspace->sect_addr));
+ } /* end else */
+ } /* end if */
+ else if(H5F_addr_defined(fspace->sect_addr)) {
+ /* Here the metadata cache is managing the section info.
+ *
+ * Do some sanity checks, and then test to see if the section
+ * info is in real file space. If it isn't relocate it into
+ * real file space lest the header be written to file with
+ * a nonsense section info address.
+ */
+ if(!H5F_POINT_OF_NO_RETURN(f)) {
+ HDassert(fspace->serial_sect_count > 0);
+ HDassert(fspace->sect_size > 0);
+ HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
+ } /* end if */
+
+ if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
+ unsigned sect_status = 0;
+ haddr_t new_sect_addr;
+
+ /* we have work to do -- must relocate section info into
+ * real file space.
+ *
+ * Since the section info address is in temporary space (AKA
+ * imaginary space), it follows that the entry must be in
+ * cache. Further, since fspace->sinfo is NULL, it must be
+ * unprotected and un-pinned. Start by verifying this.
+ */
+ if(H5AC_get_entry_status(f, fspace->sect_addr, &sect_status) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info status")
+
+ HDassert(sect_status & H5AC_ES__IN_CACHE);
+ HDassert((sect_status & H5AC_ES__IS_PROTECTED) == 0);
+ HDassert((sect_status & H5AC_ES__IS_PINNED) == 0);
+
+ /* Allocate space for the section info in file */
+ if(HADDR_UNDEF == (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+
+ fspace->alloc_sect_size = (size_t)fspace->sect_size;
+
+ /* Sanity check */
+ HDassert(!H5F_addr_eq(fspace->sect_addr, new_sect_addr));
+
+ /* Let the metadata cache know the section info moved */
+ if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info")
+
+ /* Update the internal address for the section info */
+ fspace->sect_addr = new_sect_addr;
+
+ /* No need to mark the header dirty, as we are about to
+ * serialize it.
+ */
+ } /* end if */
+ } /* end else-if */
+ else { /* there is no section info at present */
+ /* do some sanity checks */
+ HDassert(fspace->serial_sect_count == 0);
+ HDassert(fspace->tot_sect_count == fspace->ghost_sect_count);
+ } /* end else */
+
+ /* what ever happened above, set *flags to 0 */
+ *flags = 0;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_hdr_pre_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_serialize
+ *
+ * Purpose: Given an instance of H5FS_t and a suitably sized buffer,
+ * serialize the contents of the instance of H5FS_t and write
+ * its contents to the buffer. This buffer will be used to
+ * write the image of the instance to file.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(fspace);
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(fspace->hdr_size == len);
+
+ /* The section information does not always exits, and if it does,
+ * it is not always in the cache. To make matters more interesting,
+ * even if it is in the cache, it may not be in real file space.
+ *
+ * The pre-serialize function should have moved the section info
+ * into real file space if necessary before this function was called.
+ * The following asserts are a cursory check on this.
+ */
+ HDassert((! H5F_addr_defined(fspace->sect_addr)) || (! H5F_IS_TMP_ADDR(f, fspace->sect_addr)));
+
+ if(!H5F_POINT_OF_NO_RETURN(f))
+ HDassert((! H5F_addr_defined(fspace->sect_addr)) ||
+ ((fspace->serial_sect_count > 0) &&
+ (fspace->sect_size > 0) &&
+ (fspace->alloc_sect_size == (size_t)fspace->sect_size)));
+
+ /* Magic number */
+ HDmemcpy(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5FS_HDR_VERSION;
+
+ /* Client ID */
+ *image++ = fspace->client;
+
+ /* Total space tracked */
+ H5F_ENCODE_LENGTH(f, image, fspace->tot_space);
+
+ /* Total # of free space sections tracked */
+ H5F_ENCODE_LENGTH(f, image, fspace->tot_sect_count);
+
+ /* # of serializable free space sections tracked */
+ H5F_ENCODE_LENGTH(f, image, fspace->serial_sect_count);
+
+ /* # of ghost free space sections tracked */
+ H5F_ENCODE_LENGTH(f, image, fspace->ghost_sect_count);
+
+ /* # of section classes */
+ UINT16ENCODE(image, fspace->nclasses);
+
+ /* Shrink percent */
+ UINT16ENCODE(image, fspace->shrink_percent);
+
+ /* Expand percent */
+ UINT16ENCODE(image, fspace->expand_percent);
+
+ /* Size of address space free space sections are within (log2 of
+ * actual value)
+ */
+ UINT16ENCODE(image, fspace->max_sect_addr);
+
+ /* Max. size of section to track */
+ H5F_ENCODE_LENGTH(f, image, fspace->max_sect_size);
+
+ /* Address of serialized free space sections */
+ H5F_addr_encode(f, &image, fspace->sect_addr);
+
+ /* Size of serialized free space sections */
+ H5F_ENCODE_LENGTH(f, image, fspace->sect_size);
+
+ /* Allocated size of serialized free space sections */
+ H5F_ENCODE_LENGTH(f, image, fspace->alloc_sect_size);
+
+ /* Compute checksum */
+ metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* sanity checks */
+ HDassert((size_t)(image - (uint8_t *)_image) == fspace->hdr_size);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * January 3, 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS__cache_hdr_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(fspace);
+
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ if(H5AC_unsettle_entry_ring(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to mark FSM ring as unsettled")
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* do nothing */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_hdr_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_hdr_free_icr
+ *
+ * Purpose: Destroys a free space header in memory.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_hdr_free_icr(void *_thing)
+{
+ H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(fspace);
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+
+ /* We should not still be holding on to the free space section info */
+ HDassert(!fspace->sinfo);
+
+ /* Destroy free space header */
+ if(H5FS__hdr_dest(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_get_initial_load_size()
+ *
+ * Purpose: Compute the size of the on disk image of the free space
+ * manager section info, and place this value in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/7/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_sinfo_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ const H5FS_t *fspace; /* free space manager */
+ H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(udata);
+ fspace = udata->fspace;
+ HDassert(fspace);
+ HDassert(fspace->sect_size > 0);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)(fspace->sect_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS__cache_sinfo_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS__cache_sinfo_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of the free space
+ * manager section info, allocate an instance of H5FS_sinfo_t, load
+ * it with the data contained in the image, and return a pointer to
+ * the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/7/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FS__cache_sinfo_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t *dirty)
+{
+ H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */
+ H5FS_t *fspace; /* free space manager */
+ H5FS_sinfo_t *sinfo = NULL; /* Free space section info */
+ haddr_t fs_addr; /* Free space header address */
+ size_t old_sect_size; /* Old section size */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ fspace = udata->fspace;
+ HDassert(fspace);
+ HDassert(fspace->sect_size == len);
+ HDassert(dirty);
+
+ /* Allocate a new free space section info */
+ if(NULL == (sinfo = H5FS_sinfo_new(udata->f, fspace)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* initialize old_sect_size */
+ H5_CHECKED_ASSIGN(old_sect_size, size_t, udata->fspace->sect_size, hsize_t);
+
+ /* Magic number */
+ if(HDmemcmp(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5FS_SINFO_VERSION)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections version")
+
+ /* Address of free space header for these sections */
+ H5F_addr_decode(udata->f, &image, &fs_addr);
+ if(H5F_addr_ne(fs_addr, udata->fspace->addr))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "incorrect header address for free space sections")
+
+ /* Check for any serialized sections */
+ if(fspace->serial_sect_count > 0) {
+ hsize_t old_tot_sect_count; /* Total section count from header */
+ hsize_t old_serial_sect_count; /* Total serializable section count from header */
+ hsize_t old_ghost_sect_count; /* Total ghost section count from header */
+ hsize_t old_tot_space; /* Total space managed from header */
+ unsigned sect_cnt_size; /* The size of the section size counts */
+
+ /* Compute the size of the section counts */
+ sect_cnt_size = H5VM_limit_enc_size((uint64_t)udata->fspace->serial_sect_count);
+
+ /* Reset the section count, the "add" routine will update it */
+ old_tot_sect_count = fspace->tot_sect_count;
+ old_serial_sect_count = fspace->serial_sect_count;
+ old_ghost_sect_count = fspace->ghost_sect_count;
+ old_tot_space = fspace->tot_space;
+ fspace->tot_sect_count = 0;
+ fspace->serial_sect_count = 0;
+ fspace->ghost_sect_count = 0;
+ fspace->tot_space = 0;
+
+ /* Walk through the image, deserializing sections */
+ do {
+ hsize_t sect_size; /* Current section size */
+ size_t node_count; /* # of sections of this size */
+ size_t u; /* Local index variable */
+
+ /* The number of sections of this node's size */
+ UINT64DECODE_VAR(image, node_count, sect_cnt_size);
+ HDassert(node_count);
+
+ /* The size of the sections for this node */
+ UINT64DECODE_VAR(image, sect_size, sinfo->sect_len_size);
+ HDassert(sect_size);
+
+ /* Loop over nodes of this size */
+ for(u = 0; u < node_count; u++) {
+ H5FS_section_info_t *new_sect; /* Section that was deserialized */
+ haddr_t sect_addr; /* Address of free space section in the address space */
+ unsigned sect_type; /* Type of free space section */
+ unsigned des_flags; /* Flags from deserialize callback */
+
+ /* The address of the section */
+ UINT64DECODE_VAR(image, sect_addr, sinfo->sect_off_size);
+
+ /* The type of this section */
+ sect_type = *image++;
+
+ /* Call 'deserialize' callback for this section */
+ des_flags = 0;
+ HDassert(udata->fspace->sect_cls[sect_type].deserialize);
+ if(NULL == (new_sect = (*fspace->sect_cls[sect_type].deserialize) (&fspace->sect_cls[sect_type], udata->dxpl_id, image, sect_addr, sect_size, &des_flags)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, NULL, "can't deserialize section")
+
+ /* Update offset in serialization image */
+ image += udata->fspace->sect_cls[sect_type].serial_size;
+
+ /* Insert section in free space manager, unless requested not to */
+ if(!(des_flags & H5FS_DESERIALIZE_NO_ADD))
+ if(H5FS_sect_add(udata->f, udata->dxpl_id, udata->fspace, new_sect, H5FS_ADD_DESERIALIZING, udata) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, NULL, "can't add section to free space manager")
+ } /* end for */
+ } while(image < (((const uint8_t *)_image + old_sect_size) - H5FS_SIZEOF_CHKSUM));
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (old_sect_size - H5FS_SIZEOF_CHKSUM));
+ HDassert(old_sect_size == fspace->sect_size);
+ HDassert(old_tot_sect_count == fspace->tot_sect_count);
+ HDassert(old_serial_sect_count == fspace->serial_sect_count);
+ HDassert(old_ghost_sect_count == fspace->ghost_sect_count);
+ HDassert(old_tot_space == fspace->tot_space);
+ } /* end if */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == old_sect_size);
+
+ /* Set return value */
+ ret_value = sinfo;
+
+done:
+ if(!ret_value && sinfo)
+ if(H5FS_sinfo_dest(sinfo) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk and return
+ * it in *image_len.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_sinfo_image_len(const void *_thing, size_t *image_len)
+{
+ const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)_thing; /* Pointer to the object */
+ const H5FS_t *fspace; /* Free space header */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(sinfo);
+ HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
+ fspace = sinfo->fspace;
+ HDassert(fspace);
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ H5_CHECKED_ASSIGN(*image_len, size_t, sinfo->fspace->alloc_sect_size, hsize_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS__cache_sinfo_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_pre_serialize
+ *
+ * Purpose: The objective of this function is to test to see if file space
+ * for the section info is located in temporary (AKA imaginary) file
+ * space. If it is, relocate file space for the section info to
+ * regular file space.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/7/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_sinfo_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
+ haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len, unsigned *flags)
+{
+ H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
+ H5FS_t *fspace; /* Free space header */
+ haddr_t sinfo_addr; /* Address for section info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(sinfo);
+ HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
+ fspace = sinfo->fspace;
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(fspace->cache_info.is_pinned);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(H5F_addr_eq(fspace->sect_addr, addr));
+ HDassert(fspace->sect_size == len);
+ HDassert(new_addr);
+ HDassert(new_len);
+ HDassert(flags);
+
+ /* we shouldn't be called if the section info is empty, unless we hit the point of no return. */
+ if(!H5F_POINT_OF_NO_RETURN(f))
+ HDassert(fspace->serial_sect_count > 0);
+
+ sinfo_addr = addr; /* this will change if we relocate the section data */
+
+ /* Check for section info at temporary address */
+ if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
+ /* Sanity check */
+ HDassert(fspace->sect_size > 0);
+ HDassert(H5F_addr_eq(fspace->sect_addr, addr));
+
+ /* Allocate space for the section info in file */
+ if(HADDR_UNDEF == (sinfo_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
+
+ fspace->alloc_sect_size = (size_t)fspace->sect_size;
+
+ /* Sanity check */
+ HDassert(!H5F_addr_eq(sinfo->fspace->sect_addr, sinfo_addr));
+
+ /* Let the metadata cache know the section info moved */
+ if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, sinfo->fspace->sect_addr, sinfo_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info")
+
+ /* Update the internal address for the section info */
+ sinfo->fspace->sect_addr = sinfo_addr;
+
+ /* Mark free space header as dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end if */
+
+ if(!H5F_addr_eq(addr, sinfo_addr)) {
+ *new_addr = sinfo_addr;
+ *flags = H5C__SERIALIZE_MOVED_FLAG;
+ } /* end if */
+ else
+ *flags = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_pre_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_serialize
+ *
+ * Purpose: Given an instance of H5FS_sinfo_t and a suitably sized buffer,
+ * serialize the contents of the instance of H5FS_sinfo_t and write
+ * its contents to the buffer. This buffer will be used to write
+ * the image of the instance to file.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_sinfo_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
+ H5FS_t *fspace; /* Free space header */
+ H5FS_iter_ud_t udata; /* User data for callbacks */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ unsigned bin; /* Current bin we are on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image);
+ HDassert(sinfo);
+ HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
+ fspace = sinfo->fspace;
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(fspace->cache_info.is_pinned);
+ HDassert(fspace->sect_size == len);
+ HDassert(fspace->sect_cls);
+
+ /* Magic number */
+ HDmemcpy(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5FS_SINFO_VERSION;
+
+ /* Address of free space header for these sections */
+ H5F_addr_encode(f, &image, sinfo->fspace->addr);
+
+ /* Set up user data for iterator */
+ udata.sinfo = sinfo;
+ udata.image = &image;
+ udata.sect_cnt_size = H5VM_limit_enc_size((uint64_t)sinfo->fspace->serial_sect_count);
+
+ /* Iterate over all the bins */
+ for(bin = 0; bin < sinfo->nbins; bin++)
+ /* Check if there are any sections in this bin */
+ if(sinfo->bins[bin].bin_list)
+ /* Iterate over list of section size nodes for bin */
+ if(H5SL_iterate(sinfo->bins[bin].bin_list, H5FS__sinfo_serialize_node_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes")
+
+
+ /* Compute checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == sinfo->fspace->sect_size);
+ HDassert(sinfo->fspace->sect_size <= sinfo->fspace->alloc_sect_size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(sinfo);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(sinfo->fspace->swmr_write) {
+ /* Determine which action to take */
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5FS__create_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency between data block and header, address = %llu", (unsigned long long)sinfo->fspace->sect_addr)
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5FS__destroy_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__cache_sinfo_free_icr
+ *
+ * Purpose: Free the memory used for the in core representation of the
+ * free space manager section info.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__cache_sinfo_free_icr(void *_thing)
+{
+ H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
+ H5FS_t *fspace; /* Free space header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(sinfo);
+ HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
+ fspace = sinfo->fspace;
+ HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR);
+ HDassert(fspace->cache_info.is_pinned);
+
+ /* Destroy free space info */
+ if(H5FS_sinfo_dest(sinfo) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__cache_sinfo_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__sinfo_serialize_sect_cb
+ *
+ * Purpose: Skip list iterator callback to serialize free space sections
+ * of a particular size
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5FS_section_class_t *sect_cls; /* Class of section */
+ H5FS_section_info_t *sect= (H5FS_section_info_t *)_item; /* Free space section to work on */
+ H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(udata->sinfo);
+ HDassert(udata->image);
+
+ /* Get section's class */
+ sect_cls = &udata->sinfo->fspace->sect_cls[sect->type];
+
+ /* Check if this section should be serialized (i.e. is not a ghost section) */
+ if(!(sect_cls->flags & H5FS_CLS_GHOST_OBJ)) {
+ /* The address of the section */
+ UINT64ENCODE_VAR(*udata->image, sect->addr, udata->sinfo->sect_off_size);
+
+ /* The type of this section */
+ *(*udata->image)++ = (uint8_t)sect->type;
+
+ /* Call 'serialize' callback for this section */
+ if(sect_cls->serialize) {
+ if((*sect_cls->serialize)(sect_cls, sect, *udata->image) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't syncronize section")
+
+ /* Update offset in serialization buffer */
+ (*udata->image) += sect_cls->serial_size;
+ } /* end if */
+ else
+ HDassert(sect_cls->serial_size == 0);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS__sinfo_serialize_sect_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__sinfo_serialize_node_cb
+ *
+ * Purpose: Skip list iterator callback to serialize free space sections
+ * in a bin
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5FS_node_t *fspace_node = (H5FS_node_t *)_item; /* Free space size node to work on */
+ H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments. */
+ HDassert(fspace_node);
+ HDassert(udata->sinfo);
+ HDassert(udata->image);
+
+ /* Check if this node has any serializable sections */
+ if(fspace_node->serial_count > 0) {
+ /* The number of serializable sections of this node's size */
+ UINT64ENCODE_VAR(*udata->image, fspace_node->serial_count, udata->sect_cnt_size);
+
+ /* The size of the sections for this node */
+ UINT64ENCODE_VAR(*udata->image, fspace_node->sect_size, udata->sinfo->sect_len_size);
+
+ /* Iterate through all the sections of this size */
+ HDassert(fspace_node->sect_list);
+ if(H5SL_iterate(fspace_node->sect_list, H5FS__sinfo_serialize_sect_cb, udata) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS__sinfo_serialize_node_cb() */
diff --git a/src/H5FSdbg.c b/src/H5FSdbg.c
new file mode 100644
index 0000000..450216b
--- /dev/null
+++ b/src/H5FSdbg.c
@@ -0,0 +1,302 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FSdbg.c
+ * May 9 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Dump debugging information about a free space manager
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+#define H5HF_DEBUGGING /* Need access to fractal heap debugging routines */
+#define H5MF_DEBUGGING /* Need access to file space debugging routines */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FSpkg.h" /* File free space */
+#include "H5HFprivate.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_debug
+ *
+ * Purpose: Prints debugging info about a free space manager.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * May 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth)
+{
+ H5FS_t *fspace = NULL; /* Free space header info */
+ H5FS_hdr_cache_ud_t cache_udata; /* User-data for cache callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Initialize user data for protecting the free space manager */
+ cache_udata.f = f;
+ cache_udata.nclasses = 0;
+ cache_udata.classes = NULL;
+ cache_udata.cls_init_udata = NULL;
+ cache_udata.addr = addr;
+
+ /*
+ * Load the free space header.
+ */
+ if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, FAIL, "unable to load free space header")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFree Space Header...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Free space client:",
+ (fspace->client == H5FS_CLIENT_FHEAP_ID ? "Fractal heap" :
+ (fspace->client == H5FS_CLIENT_FILE_ID ? "File" : "Unknown")));
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Total free space tracked:",
+ fspace->tot_space);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Total number of free space sections tracked:",
+ fspace->tot_sect_count);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of serializable free space sections tracked:",
+ fspace->serial_sect_count);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of ghost free space sections tracked:",
+ fspace->ghost_sect_count);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of free space section classes:",
+ (unsigned)fspace->nclasses);
+ HDfprintf(stream, "%*s%-*s %u%%\n", indent, "", fwidth,
+ "Shrink percent:",
+ fspace->shrink_percent);
+ HDfprintf(stream, "%*s%-*s %u%%\n", indent, "", fwidth,
+ "Expand percent:",
+ fspace->expand_percent);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "# of bits for section address space:",
+ fspace->max_sect_addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Maximum section size:",
+ fspace->max_sect_size);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Serialized sections address:",
+ fspace->sect_addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Serialized sections size used:",
+ fspace->sect_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Serialized sections size allocated:",
+ fspace->alloc_sect_size);
+
+done:
+ if(fspace && H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, addr, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_PROTECT, FAIL, "unable to release free space header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_debug
+ *
+ * Purpose: Prints debugging info about a free space section.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * May 30 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_debug(const H5FS_t *fspace, const H5FS_section_info_t *sect, FILE *stream, int indent, int fwidth)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fspace);
+ HDassert(sect);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Call the section's debugging routine */
+ if(fspace->sect_cls[sect->type].debug)
+ if((fspace->sect_cls[sect->type].debug)(sect, stream, indent, fwidth) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't dump section's debugging info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_sect_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sects_debug
+ *
+ * Purpose: Prints debugging info about the free space sections.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * May 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, FILE *stream, int indent, int fwidth,
+ haddr_t fs_addr, haddr_t client_addr)
+{
+ H5FS_t *fspace = NULL; /* Free space header info */
+ H5FS_client_t client; /* The client of the free space */
+ H5FS_hdr_cache_ud_t cache_udata; /* User-data for cache callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(H5F_addr_defined(fs_addr));
+ HDassert(H5F_addr_defined(client_addr));
+
+ /* Initialize user data for protecting the free space manager */
+ cache_udata.f = f;
+ cache_udata.nclasses = 0;
+ cache_udata.classes = NULL;
+ cache_udata.cls_init_udata = NULL;
+ cache_udata.addr = fs_addr;
+
+ /*
+ * Load the free space header.
+ */
+ if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, FAIL, "unable to load free space header")
+
+ /* Retrieve the client id */
+ client = fspace->client;
+
+ /* Release the free space header */
+ /* (set the "deleted" flag for the unprotect, so the cache entry is removed
+ * and reloaded later, with the correct client information -QAK)
+ */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__DELETED_FLAG) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_PROTECT, FAIL, "unable to release free space header")
+ fspace = NULL;
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFree Space Sections...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ switch(client) {
+ case H5FS_CLIENT_FHEAP_ID:
+ if(H5HF_sects_debug(f, dxpl_id, client_addr, stream, indent + 3, MAX(0, fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_SYSTEM, FAIL, "unable to dump fractal heap free space sections")
+ break;
+
+ case H5FS_CLIENT_FILE_ID:
+ if(H5MF_sects_debug(f, dxpl_id, fs_addr, stream, indent + 3, MAX(0, fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_SYSTEM, FAIL, "unable to dump file free space sections")
+ break;
+
+ case H5FS_NUM_CLIENT_ID:
+ default:
+ HDfprintf(stream, "Unknown client!\n");
+ break;
+ } /* end switch */
+
+done:
+ if(fspace && H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_PROTECT, FAIL, "unable to release free space header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS_sects_debug() */
+
diff --git a/src/H5FSint.c b/src/H5FSint.c
new file mode 100644
index 0000000..1a41172
--- /dev/null
+++ b/src/H5FSint.c
@@ -0,0 +1,143 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FSint.c
+ * Fall 2012
+ * Dana Robinson <derobins@hdfgroup.org>
+ *
+ * Purpose: Internal routines for free space managers.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**********************/
+/* Module Declaration */
+/**********************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+
+
+/***********************/
+/* Other Packages Used */
+/***********************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error Handling */
+#include "H5FSpkg.h" /* Free Space Managers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__create_flush_depend
+ *
+ * Purpose: Create a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS__create_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Create a flush dependency between parent and child entry */
+ if(H5AC_create_flush_dependency(parent_entry, child_entry) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__create_flush_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS__destroy_flush_depend
+ *
+ * Purpose: Destroy a flush dependency between two data structure components
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS__destroy_flush_depend(H5AC_info_t *parent_entry, H5AC_info_t *child_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(parent_entry);
+ HDassert(child_entry);
+
+ /* Destroy a flush dependency between parent and child entry */
+ if(H5AC_destroy_flush_dependency(parent_entry, child_entry) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FS__destroy_flush_depend() */
+
diff --git a/src/H5FSmodule.h b/src/H5FSmodule.h
new file mode 100644
index 0000000..b2869dd
--- /dev/null
+++ b/src/H5FSmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5FS package. Including this header means that the source file
+ * is part of the H5FS package.
+ */
+#ifndef _H5FSmodule_H
+#define _H5FSmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5FS_MODULE
+#define H5_MY_PKG H5FS
+#define H5_MY_PKG_ERR H5E_FSPACE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5FSmodule_H */
+
diff --git a/src/H5FSpkg.h b/src/H5FSpkg.h
new file mode 100644
index 0000000..df1d92f
--- /dev/null
+++ b/src/H5FSpkg.h
@@ -0,0 +1,251 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, May 2, 2006
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5FS package. Source files outside the H5FS package should
+ * include H5FSprivate.h instead.
+ */
+#if !(defined H5FS_FRIEND || defined H5FS_MODULE)
+#error "Do not include this file outside the H5FS package!"
+#endif
+
+#ifndef _H5FSpkg_H
+#define _H5FSpkg_H
+
+/* Uncomment this macro to enable debugging output for free space manager */
+/* #define H5FS_DEBUG */
+
+/* Uncomment this macro to enable debugging output for free space sections */
+/* #define H5FS_SINFO_DEBUG */
+
+/* Uncomment this macro to enable extra sanity checking */
+/* #define H5FS_DEBUG_ASSERT */
+
+/* Get package's private header */
+#include "H5FSprivate.h" /* File free space */
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5SLprivate.h" /* Skip lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Size of checksum information (on disk) */
+#define H5FS_SIZEOF_CHKSUM 4
+
+/* "Standard" size of prefix information for free space metadata */
+#define H5FS_METADATA_PREFIX_SIZE ( \
+ H5_SIZEOF_MAGIC /* Signature */ \
+ + 1 /* Version */ \
+ + H5FS_SIZEOF_CHKSUM /* Metadata checksum */ \
+ )
+
+/* Size of the fractal heap header on disk */
+#define H5FS_HEADER_SIZE(f) ( \
+ /* General metadata fields */ \
+ H5FS_METADATA_PREFIX_SIZE \
+ \
+ /* Free space header specific fields */ \
+ + 1 /* Client ID */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* Total free space tracked */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* Total # of sections tracked */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* # of serializable sections tracked */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* # of ghost sections tracked */ \
+ + 2 /* Number of section classes */ \
+ + 2 /* Shrink percent */ \
+ + 2 /* Expand percent */ \
+ + 2 /* Size of address space for sections (log2 of value) */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* Max. size of section to track */ \
+ + (unsigned)H5F_SIZEOF_ADDR(f) /* Address of serialized free space sections */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* Size of serialized free space sections used */ \
+ + (unsigned)H5F_SIZEOF_SIZE(f) /* Allocated size of serialized free space sections */ \
+ )
+
+/* Size of the free space serialized sections on disk */
+#define H5FS_SINFO_PREFIX_SIZE(f) ( \
+ /* General metadata fields */ \
+ H5FS_METADATA_PREFIX_SIZE \
+ \
+ /* Free space serialized sections specific fields */ \
+ + (unsigned)H5F_SIZEOF_ADDR(f) /* Address of free space header for these sections */ \
+ )
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Callback info for loading a free space header into the cache */
+typedef struct H5FS_hdr_cache_ud_t {
+ H5F_t *f; /* File that free space header is within */
+ uint16_t nclasses; /* Number of section classes */
+ const H5FS_section_class_t **classes; /* Array of section class info */
+ void *cls_init_udata; /* Pointer to class init user data */
+ haddr_t addr; /* Address of header */
+} H5FS_hdr_cache_ud_t;
+
+/* Callback info for loading free space section info into the cache */
+typedef struct H5FS_sinfo_cache_ud_t {
+ H5F_t *f; /* File that free space section info is within */
+ H5FS_t *fspace; /* free space manager */
+ hid_t dxpl_id;
+} H5FS_sinfo_cache_ud_t;
+
+/* Free space section bin info */
+typedef struct H5FS_bin_t {
+ size_t tot_sect_count; /* Total # of sections in this bin */
+ size_t serial_sect_count; /* # of serializable sections in this bin */
+ size_t ghost_sect_count; /* # of un-serializable sections in this bin */
+ H5SL_t *bin_list; /* Skip list of differently sized sections */
+} H5FS_bin_t;
+
+/* Free space node for free space sections of the same size */
+typedef struct H5FS_node_t {
+ hsize_t sect_size; /* Size of all sections on list */
+ size_t serial_count; /* # of serializable sections on list */
+ size_t ghost_count; /* # of un-serializable sections on list */
+ H5SL_t *sect_list; /* Skip list to hold pointers to actual free list section node */
+} H5FS_node_t;
+
+/* Free space section info */
+typedef struct H5FS_sinfo_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+/* Stored information */
+ H5FS_bin_t *bins; /* Array of lists of lists of free sections */
+
+/* Computed/cached values */
+ hbool_t dirty; /* Whether this info in memory is out of sync w/info in file */
+ unsigned nbins; /* Number of bins */
+ size_t serial_size; /* Total size of all serializable sections */
+ size_t tot_size_count; /* Total number of differently sized sections */
+ size_t serial_size_count; /* Total number of differently sized serializable sections */
+ size_t ghost_size_count; /* Total number of differently sized un-serializable sections */
+ unsigned sect_prefix_size; /* Size of the section serialization prefix (in bytes) */
+ unsigned sect_off_size; /* Size of a section offset (in bytes) */
+ unsigned sect_len_size; /* Size of a section length (in bytes) */
+ H5FS_t *fspace; /* Pointer to free space manager that owns sections */
+
+/* Memory data structures (not stored directly) */
+ H5SL_t *merge_list; /* Skip list to hold sections for detecting merges */
+} H5FS_sinfo_t;
+
+/* Free space header info */
+struct H5FS_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+/* Stored information */
+ /* Statistics about sections managed */
+ hsize_t tot_space; /* Total amount of space tracked */
+ hsize_t tot_sect_count; /* Total # of sections tracked */
+ hsize_t serial_sect_count; /* # of serializable sections tracked */
+ hsize_t ghost_sect_count; /* # of un-serializable sections tracked */
+
+ /* Creation parameters */
+ H5FS_client_t client; /* Type of user of this free space manager */
+ uint16_t nclasses; /* Number of section classes handled */
+ unsigned shrink_percent; /* Percent of "normal" serialized size to shrink serialized space at */
+ unsigned expand_percent; /* Percent of "normal" serialized size to expand serialized space at */
+ unsigned max_sect_addr; /* Size of address space free sections are within (log2 of actual value) */
+ hsize_t max_sect_size; /* Maximum size of section to track */
+
+ /* Serialized section information */
+ haddr_t sect_addr; /* Address of the section info in the file */
+ hsize_t sect_size; /* Size of the section info in the file */
+ hsize_t alloc_sect_size; /* Allocated size of the section info in the file */
+
+/* Computed/cached values */
+ unsigned rc; /* Count of outstanding references to struct */
+ haddr_t addr; /* Address of free space header on disk */
+ size_t hdr_size; /* Size of free space header on disk */
+ H5FS_sinfo_t *sinfo; /* Section information */
+ hbool_t swmr_write; /* Flag indicating the file is opened with SWMR-write access */
+ unsigned sinfo_lock_count; /* # of times the section info has been locked */
+ hbool_t sinfo_protected; /* Whether the section info was protected when locked */
+ hbool_t sinfo_modified; /* Whether the section info has been modified while locked */
+ unsigned sinfo_accmode; /* Access mode for protecting the section info */
+ /* must be either H5C__NO_FLAGS_SET (i.e r/w) */
+ /* or H5AC__READ_ONLY_FLAG (i.e. r/o). */
+ size_t max_cls_serial_size; /* Max. additional size of serialized form of section */
+ hsize_t alignment; /* Alignment */
+ hsize_t align_thres; /* Threshold for alignment */
+
+
+/* Memory data structures (not stored directly) */
+ H5FS_section_class_t *sect_cls; /* Array of section classes for this free list */
+};
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare a free list to manage the H5FS_node_t struct */
+H5FL_EXTERN(H5FS_node_t);
+
+/* Declare a free list to manage the H5FS_bin_t sequence information */
+H5FL_SEQ_EXTERN(H5FS_bin_t);
+
+/* Declare a free list to manage the H5FS_sinfo_t struct */
+H5FL_EXTERN(H5FS_sinfo_t);
+
+/* Declare a free list to manage the H5FS_t struct */
+H5FL_EXTERN(H5FS_t);
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Generic routines */
+H5_DLL herr_t H5FS__create_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+H5_DLL herr_t H5FS__destroy_flush_depend(H5AC_info_t *parent_entry,
+ H5AC_info_t *child_entry);
+
+/* Free space manager header routines */
+H5_DLL H5FS_t *H5FS__new(const H5F_t *f, uint16_t nclasses,
+ const H5FS_section_class_t *classes[], void *cls_init_udata);
+H5_DLL herr_t H5FS_incr(H5FS_t *fspace);
+H5_DLL herr_t H5FS_decr(H5FS_t *fspace);
+H5_DLL herr_t H5FS_dirty(H5FS_t *fspace);
+
+/* Free space section routines */
+H5_DLL H5FS_sinfo_t *H5FS_sinfo_new(H5F_t *f, H5FS_t *fspace);
+
+/* Routines for destroying structures */
+H5_DLL herr_t H5FS__hdr_dest(H5FS_t *hdr);
+H5_DLL herr_t H5FS_sinfo_dest(H5FS_sinfo_t *sinfo);
+
+/* Sanity check routines */
+#ifdef H5FS_DEBUG
+H5_DLL herr_t H5FS_assert(const H5FS_t *fspace, hid_t dxpl_id);
+H5_DLL herr_t H5FS_sect_assert(const H5FS_t *fspace, hid_t dxpl_id);
+#endif /* H5FS_DEBUG */
+
+/* Testing routines */
+#ifdef H5FS_TESTING
+H5_DLL herr_t H5FS_get_cparam_test(const H5FS_t *fh, H5FS_create_t *cparam);
+H5_DLL int H5FS_cmp_cparam_test(const H5FS_create_t *cparam1, const H5FS_create_t *cparam2);
+#endif /* H5FS_TESTING */
+
+#endif /* _H5FSpkg_H */
+
diff --git a/src/H5FSprivate.h b/src/H5FSprivate.h
new file mode 100644
index 0000000..c0467a6
--- /dev/null
+++ b/src/H5FSprivate.h
@@ -0,0 +1,230 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FSprivate.h
+ * May 2 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Private header for library accessible file free space routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5FSprivate_H
+#define _H5FSprivate_H
+
+/* Include package's public header */
+#include "H5FSpublic.h"
+
+/* Private headers needed by this file */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Flags for H5FS_section_class_t 'flags' field */
+#define H5FS_CLS_GHOST_OBJ 0x01 /* Objects in this class shouldn't be
+ * serialized to the file.
+ */
+#define H5FS_CLS_SEPAR_OBJ 0x02 /* Objects in this class shouldn't
+ * participate in merge operations.
+ */
+#define H5FS_CLS_MERGE_SYM 0x04 /* Objects in this class only merge
+ * with other objects in this class.
+ */
+#define H5FS_CLS_ADJUST_OK 0x08 /* Objects in this class can be merged
+ * without requiring a can_adjust/adjust
+ * callback pair.
+ */
+
+/* Flags for H5FS_add() */
+#define H5FS_ADD_DESERIALIZING 0x01 /* Free space is being deserialized
+ */
+#define H5FS_ADD_RETURNED_SPACE 0x02 /* Section was previously allocated
+ * and is being returned to the
+ * free space manager (usually
+ * as a result of freeing an
+ * object)
+ */
+#define H5FS_ADD_SKIP_VALID 0x04 /* Don't check validity after adding
+ * this section. (state of the
+ * managed sections is in flux)
+ */
+
+#define H5FS_PAGE_END_NO_ADD 0x08 /* For "small" page fs:
+ * Don't add section to free space:
+ * when the section is at page end and
+ * when the section size is <= "small"
+ */
+
+/* Flags for deserialize callback */
+#define H5FS_DESERIALIZE_NO_ADD 0x01 /* Don't add section to free space
+ * manager after it's deserialized
+ * (its only here for it's side-
+ * effects).
+ */
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Free space info (forward decl - defined in H5FSpkg.h) */
+typedef struct H5FS_t H5FS_t;
+
+/* Forward declaration free space section info */
+typedef struct H5FS_section_info_t H5FS_section_info_t;
+
+/* Free space section class info */
+typedef struct H5FS_section_class_t {
+ /* Class variables */
+ const unsigned type; /* Type of free space section */
+ size_t serial_size; /* Size of serialized form of section */
+ unsigned flags; /* Class flags */
+ void *cls_private; /* Class private information */
+
+ /* Class methods */
+ herr_t (*init_cls)(struct H5FS_section_class_t *, void *); /* Routine to initialize class-specific settings */
+ herr_t (*term_cls)(struct H5FS_section_class_t *); /* Routine to terminate class-specific settings */
+
+ /* Object methods */
+ herr_t (*add)(H5FS_section_info_t **, unsigned *, void *); /* Routine called when section is about to be added to manager */
+ herr_t (*serialize)(const struct H5FS_section_class_t *, const H5FS_section_info_t *, uint8_t *); /* Routine to serialize a "live" section into a buffer */
+ H5FS_section_info_t *(*deserialize)(const struct H5FS_section_class_t *, hid_t dxpl_id, const uint8_t *, haddr_t, hsize_t, unsigned *); /* Routine to deserialize a buffer into a "live" section */
+ htri_t (*can_merge)(const H5FS_section_info_t *, const H5FS_section_info_t *, void *); /* Routine to determine if two nodes are mergable */
+ herr_t (*merge)(H5FS_section_info_t **, H5FS_section_info_t *, void *); /* Routine to merge two nodes */
+ htri_t (*can_shrink)(const H5FS_section_info_t *, void *); /* Routine to determine if node can shrink container */
+ herr_t (*shrink)(H5FS_section_info_t **, void *); /* Routine to shrink container */
+ herr_t (*free)(H5FS_section_info_t *); /* Routine to free node */
+ herr_t (*valid)(const struct H5FS_section_class_t *, const H5FS_section_info_t *, hid_t dxpl_id); /* Routine to check if a section is valid */
+ H5FS_section_info_t *(*split)(H5FS_section_info_t *, hsize_t); /* Routine to create the split section */
+ herr_t (*debug)(const H5FS_section_info_t *, FILE *, int , int ); /* Routine to dump debugging information about a section */
+} H5FS_section_class_t;
+
+/* State of section ("live" or "serialized") */
+typedef enum H5FS_section_state_t {
+ H5FS_SECT_LIVE, /* Section has "live" memory references */
+ H5FS_SECT_SERIALIZED /* Section is in "serialized" form */
+} H5FS_section_state_t;
+
+/* Free space section info */
+struct H5FS_section_info_t {
+ haddr_t addr; /* Offset of free space section in the address space */
+ hsize_t size; /* Size of free space section */
+ unsigned type; /* Type of free space section (i.e. class) */
+ H5FS_section_state_t state; /* Whether the section is in "serialized" or "live" form */
+};
+
+/* Free space client IDs for identifying user of free space */
+typedef enum H5FS_client_t {
+ H5FS_CLIENT_FHEAP_ID = 0, /* Free space is used by fractal heap */
+ H5FS_CLIENT_FILE_ID, /* Free space is used by file */
+ H5FS_NUM_CLIENT_ID /* Number of free space client IDs (must be last) */
+} H5FS_client_t;
+
+/* Free space creation parameters */
+typedef struct H5FS_create_t {
+ H5FS_client_t client; /* Client's ID */
+ unsigned shrink_percent; /* Percent of "normal" serialized size to shrink serialized space at */
+ unsigned expand_percent; /* Percent of "normal" serialized size to expand serialized space at */
+ unsigned max_sect_addr; /* Size of address space free sections are within (log2 of actual value) */
+ hsize_t max_sect_size; /* Maximum size of section to track */
+} H5FS_create_t;
+
+/* Free space statistics info */
+typedef struct H5FS_stat_t {
+ hsize_t tot_space; /* Total amount of space tracked */
+ hsize_t tot_sect_count; /* Total # of sections tracked */
+ hsize_t serial_sect_count; /* # of serializable sections tracked */
+ hsize_t ghost_sect_count; /* # of un-serializable sections tracked */
+ haddr_t addr; /* Address of free space header on disk */
+ hsize_t hdr_size; /* Size of the free-space header on disk */
+ haddr_t sect_addr; /* Address of the section info in the file */
+ hsize_t alloc_sect_size; /* Allocated size of the section info in the file */
+ hsize_t sect_size; /* Size of the section info in the file */
+} H5FS_stat_t;
+
+/* Typedef for iteration operations */
+typedef herr_t (*H5FS_operator_t)(H5FS_section_info_t *sect,
+ void *operator_data/*in,out*/);
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+/* Declare a free list to manage the H5FS_section_class_t sequence information */
+H5FL_SEQ_EXTERN(H5FS_section_class_t);
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* Free space manager routines */
+H5_DLL H5FS_t *H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr,
+ const H5FS_create_t *fs_create, uint16_t nclasses,
+ const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold);
+H5_DLL H5FS_t *H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr,
+ uint16_t nclasses, const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold);
+H5_DLL herr_t H5FS_size(const H5F_t *f, const H5FS_t *fspace, hsize_t *meta_size);
+H5_DLL herr_t H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr);
+H5_DLL herr_t H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace);
+H5_DLL herr_t H5FS_alloc_hdr(H5F_t *f, H5FS_t *fspace, haddr_t *fs_addr, hid_t dxpl_id);
+H5_DLL herr_t H5FS_alloc_sect(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id);
+H5_DLL herr_t H5FS_free(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id,
+ hbool_t free_file_space);
+
+/* Free space section routines */
+H5_DLL herr_t H5FS_sect_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *node, unsigned flags, void *op_data);
+H5_DLL htri_t H5FS_sect_try_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *sect, unsigned flags, void *op_data);
+H5_DLL htri_t H5FS_sect_try_extend(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ haddr_t addr, hsize_t size, hsize_t extra_requested, unsigned flags, void *op_data);
+H5_DLL herr_t H5FS_sect_remove(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *node);
+H5_DLL htri_t H5FS_sect_find(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ hsize_t request, H5FS_section_info_t **node);
+H5_DLL herr_t H5FS_sect_iterate(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_operator_t op, void *op_data);
+H5_DLL herr_t H5FS_sect_stats(const H5FS_t *fspace, hsize_t *tot_space,
+ hsize_t *nsects);
+H5_DLL herr_t H5FS_sect_change_class(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *sect, uint16_t new_class);
+H5_DLL htri_t H5FS_sect_try_shrink_eoa(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ void *op_data);
+
+/* Statistics routine */
+H5_DLL herr_t H5FS_stat_info(const H5F_t *f, const H5FS_t *frsp, H5FS_stat_t *stats);
+H5_DLL herr_t H5FS_get_sect_count(const H5FS_t *frsp, hsize_t *tot_sect_count);
+
+/* free space manager settling routines */
+H5_DLL herr_t H5FS_vfd_alloc_hdr_and_section_info_if_needed(H5F_t *f,
+ hid_t dxpl_id,
+ H5FS_t *fspace,
+ haddr_t *fs_addr_ptr);
+
+/* Debugging routines for dumping file structures */
+H5_DLL herr_t H5FS_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth);
+H5_DLL herr_t H5FS_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, haddr_t fs_addr, haddr_t client_addr);
+H5_DLL herr_t H5FS_sect_debug(const H5FS_t *fspace, const H5FS_section_info_t *sect,
+ FILE *stream, int indent, int fwidth);
+
+#endif /* _H5FSprivate_H */
+
diff --git a/src/H5FSpublic.h b/src/H5FSpublic.h
new file mode 100644
index 0000000..3090d0d
--- /dev/null
+++ b/src/H5FSpublic.h
@@ -0,0 +1,52 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5FSpublic.h
+ * May 2 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Public declarations for the file free space package.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5FSpublic_H
+#define _H5FSpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/**********************************/
+/* Public API Function Prototypes */
+/**********************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5FSpublic_H */
+
diff --git a/src/H5FSsection.c b/src/H5FSsection.c
new file mode 100644
index 0000000..8f911a4
--- /dev/null
+++ b/src/H5FSsection.c
@@ -0,0 +1,2682 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Monday, July 31, 2006
+ *
+ * Purpose: Free space tracking functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FSpkg.h" /* File free space */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for skip list iterator callback for iterating over section size nodes */
+typedef struct {
+ H5FS_t *fspace; /* Free space manager info */
+ H5FS_operator_t op; /* Operator for the iteration */
+ void *op_data; /* Information to pass to the operator */
+} H5FS_iter_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5FS_sect_increase(H5FS_t *fspace, const H5FS_section_class_t *cls,
+ unsigned flags);
+static herr_t H5FS_sect_decrease(H5FS_t *fspace, const H5FS_section_class_t *cls);
+static herr_t H5FS_size_node_decr(H5FS_sinfo_t *sinfo, unsigned bin, H5FS_node_t *fspace_node,
+ const H5FS_section_class_t *cls);
+static herr_t H5FS_sect_unlink_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect);
+static herr_t H5FS_sect_unlink_rest(H5FS_t *fspace,
+ const H5FS_section_class_t *cls, H5FS_section_info_t *sect);
+static herr_t H5FS_sect_remove_real(H5FS_t *fspace, H5FS_section_info_t *sect);
+static herr_t H5FS_sect_link_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect);
+static herr_t H5FS_sect_link_rest(H5FS_t *fspace, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect, unsigned flags);
+static herr_t H5FS_sect_link(H5FS_t *fspace, H5FS_section_info_t *sect,
+ unsigned flags);
+static herr_t H5FS_sect_merge(H5FS_t *fspace, H5FS_section_info_t **sect,
+ void *op_data);
+static htri_t H5FS_sect_find_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node);
+static herr_t H5FS_sect_serialize_size(H5FS_t *fspace);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5FS_node_t struct */
+H5FL_DEFINE(H5FS_node_t);
+
+/* Declare a free list to manage the H5FS_bin_t sequence information */
+H5FL_SEQ_DEFINE(H5FS_bin_t);
+
+/* Declare a free list to manage the H5FS_sinfo_t struct */
+H5FL_DEFINE(H5FS_sinfo_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_new
+ *
+ * Purpose: Create new section info structure
+ *
+ * Return: Success: non-NULL, pointer to new section info struct
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 31, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5FS_sinfo_t *
+H5FS_sinfo_new(H5F_t *f, H5FS_t *fspace)
+{
+ H5FS_sinfo_t *sinfo = NULL; /* Section information struct created */
+ H5FS_sinfo_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: fspace->addr = %a\n", FUNC, fspace->addr);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Allocate the free space header */
+ if(NULL == (sinfo = H5FL_CALLOC(H5FS_sinfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set non-zero values */
+ sinfo->nbins = H5VM_log2_gen(fspace->max_sect_size);
+ sinfo->sect_prefix_size = H5FS_SINFO_PREFIX_SIZE(f);
+ sinfo->sect_off_size = (fspace->max_sect_addr + 7) / 8;
+ sinfo->sect_len_size = H5VM_limit_enc_size((uint64_t)fspace->max_sect_size);
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: fspace->max_sect_size = %Hu\n", FUNC, fspace->max_sect_size);
+HDfprintf(stderr, "%s: fspace->max_sect_addr = %u\n", FUNC, fspace->max_sect_addr);
+HDfprintf(stderr, "%s: sinfo->nbins = %u\n", FUNC, sinfo->nbins);
+HDfprintf(stderr, "%s: sinfo->sect_off_size = %u, sinfo->sect_len_size = %u\n", FUNC, sinfo->sect_off_size, sinfo->sect_len_size);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Allocate space for the section size bins */
+ if(NULL == (sinfo->bins = H5FL_SEQ_CALLOC(H5FS_bin_t, (size_t)sinfo->nbins)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section bin array")
+
+ /* Increment the reference count on the free space manager header */
+ if(H5FS_incr(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header")
+ sinfo->fspace = fspace;
+
+ /* Link free space manager to section info */
+ /* (for deserializing sections) */
+ HDassert(fspace->sinfo == NULL);
+ fspace->sinfo = sinfo;
+
+ /* Set return value */
+ ret_value = sinfo;
+
+done:
+ if(ret_value == NULL && sinfo) {
+ /* Release bins for skip lists */
+ if(sinfo->bins)
+ sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
+
+ /* Release free space section info */
+ sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sinfo_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_lock
+ *
+ * Purpose: Make certain the section info for the free space manager is
+ * in memory.
+ *
+ * Either uses existing section info owned by the free space
+ * header, loads section info from disk, or creates new section
+ * info
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sinfo_lock(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, unsigned accmode)
+{
+ H5FS_sinfo_cache_ud_t cache_udata; /* User-data for cache callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Called, fspace->addr = %a, fspace->sinfo = %p, fspace->sect_addr = %a\n", FUNC, fspace->addr, fspace->sinfo, fspace->sect_addr);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+
+ /* only H5AC__READ_ONLY_FLAG may appear in accmode */
+ HDassert((accmode & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* If the free space header doesn't already "own" the section info, load
+ * section info or create it
+ */
+ if(fspace->sinfo) {
+ /* Check if the section info was protected & we want a different access mode */
+
+ /* only H5AC__READ_ONLY_FLAG may appear in fspace->sinfo_accmode */
+ HDassert(((fspace->sinfo_accmode) & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ if(fspace->sinfo_protected && accmode != fspace->sinfo_accmode) {
+ /* Check if we need to switch from read-only access to read-write */
+ if(0 == (accmode & (unsigned)(~H5AC__READ_ONLY_FLAG))) {
+ /* Unprotect the read-only section info */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info")
+
+ /* Re-protect the section info with read-write access */
+ cache_udata.f = f;
+ cache_udata.dxpl_id = dxpl_id;
+ cache_udata.fspace = fspace;
+ if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to load free space sections")
+
+ /* Switch the access mode we have */
+ fspace->sinfo_accmode = H5AC__NO_FLAGS_SET;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ else {
+ /* If the section address is defined, load it from the file */
+ if(H5F_addr_defined(fspace->sect_addr)) {
+ /* Sanity check */
+ HDassert(fspace->sinfo_protected == FALSE);
+ HDassert(H5F_addr_defined(fspace->addr));
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Reading in existing sections, fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Protect the free space sections */
+ cache_udata.f = f;
+ cache_udata.dxpl_id = dxpl_id;
+ cache_udata.fspace = fspace;
+ if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, accmode)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to load free space sections")
+
+ /* Remember that we protected the section info & the access mode */
+ fspace->sinfo_protected = TRUE;
+ fspace->sinfo_accmode = accmode;
+ } /* end if */
+ else {
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Creating new section info\n", FUNC);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Sanity check */
+ HDassert(fspace->tot_sect_count == 0);
+ HDassert(fspace->serial_sect_count == 0);
+ HDassert(fspace->ghost_sect_count == 0);
+
+ /* Allocate and initialize free space section info */
+ if(NULL == (fspace->sinfo = H5FS_sinfo_new(f, fspace)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create section info")
+
+ /* Set initial size of section info to 0 */
+ fspace->sect_size = fspace->alloc_sect_size = 0;
+ } /* end if */
+ } /* end if */
+ HDassert(fspace->rc == 2);
+
+ /* Increment the section info lock count */
+ fspace->sinfo_lock_count++;
+
+done:
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Leaving, fspace->addr = %a, fspace->sinfo = %p, fspace->sect_addr = %a\n", FUNC, fspace->addr, fspace->sinfo, fspace->sect_addr);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
+#endif /* H5FS_SINFO_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sinfo_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sinfo_unlock
+ *
+ * Purpose: Release the section info, either giving ownership back to
+ * the cache or letting the free space header keep it.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, February 7, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sinfo_unlock(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, hbool_t modified)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Called, modified = %t, fspace->addr = %a, fspace->sect_addr = %a\n", FUNC, modified, fspace->addr, fspace->sect_addr);
+HDfprintf(stderr, "%s: fspace->sinfo_lock_count = %u, fspace->sinfo_modified = %t, fspace->sinfo_protected = %t\n", FUNC, fspace->sinfo_lock_count, fspace->sinfo_modified, fspace->sinfo_protected);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(fspace->rc == 2);
+ HDassert(fspace->sinfo);
+
+ /* Check if we modified any section */
+ if(modified) {
+ /* Check if the section info was protected with a different access mode */
+ if(fspace->sinfo_protected && (0 != ((fspace->sinfo_accmode) & H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTDIRTY, FAIL, "attempt to modify read-only section info")
+
+ /* If we modified the section info, mark it dirty */
+ fspace->sinfo->dirty = TRUE;
+
+ /* Remember that the section info was modified while locked */
+ fspace->sinfo_modified = TRUE;
+
+ /* Assume that the modification will affect the statistics in the header
+ * and mark that dirty also
+ */
+ if(H5FS_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+ } /* end if */
+
+ /* Decrement the lock count on the section info */
+ fspace->sinfo_lock_count--;
+
+ /* Check if section info lock count dropped to zero */
+ if(fspace->sinfo_lock_count == 0) {
+ hbool_t release_sinfo_space = FALSE; /* Flag to indicate section info space in file should be released */
+
+ /* Check if we actually protected the section info */
+ if(fspace->sinfo_protected) {
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(fspace->addr));
+
+ /* Check if we've made new changes to the section info while locked */
+ if(fspace->sinfo_modified) {
+ /* Note that we've modified the section info */
+ cache_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Check if the section info size in the file has changed */
+ if(fspace->sect_size != fspace->alloc_sect_size)
+ cache_flags |= H5AC__DELETED_FLAG | H5AC__TAKE_OWNERSHIP_FLAG;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(fspace->sect_addr));
+
+ /* Unprotect section info in cache */
+ /* (Possibly dirty) */
+ /* (Possibly taking ownership from the cache) */
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Unprotecting section info, cache_flags = %u\n", FUNC, cache_flags);
+#endif /* H5FS_SINFO_DEBUG */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, cache_flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info")
+
+ /* Reset the protected flag on the section info */
+ fspace->sinfo_protected = FALSE;
+
+ /* Check if header is taking ownership of section info */
+ if((cache_flags & H5AC__TAKE_OWNERSHIP_FLAG)) {
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Taking ownership of section info\n", FUNC);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Set flag to release section info space in file */
+ release_sinfo_space = TRUE;
+ } /* end if */
+ else {
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Relinquishing section info ownership\n", FUNC);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Free space header relinquished ownership of section info */
+ fspace->sinfo = NULL;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check if the section info was modified */
+ if(fspace->sinfo_modified) {
+ /* Check if we need to release section info in the file */
+ if(H5F_addr_defined(fspace->sect_addr))
+ /* Set flag to release section info space in file */
+ release_sinfo_space = TRUE;
+ else
+ HDassert(fspace->alloc_sect_size == 0);
+ } /* end if */
+ else {
+ /* Sanity checks... */
+ if(H5F_addr_defined(fspace->sect_addr))
+ HDassert(fspace->alloc_sect_size == fspace->sect_size);
+ else
+ HDassert(fspace->alloc_sect_size == 0);
+ } /* end else */
+ } /* end else */
+
+ /* Reset the "section info modified" flag */
+ fspace->sinfo_modified = FALSE;
+
+ /* Check if header needs to release section info in the file */
+ if(release_sinfo_space) {
+ haddr_t old_sect_addr = fspace->sect_addr; /* Previous location of section info in file */
+ hsize_t old_alloc_sect_size = fspace->alloc_sect_size; /* Previous size of section info in file */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(fspace->addr));
+
+ /* Reset section info in header */
+ fspace->sect_addr = HADDR_UNDEF;
+ fspace->alloc_sect_size = 0;
+
+ /* If we haven't already marked the header dirty, do so now */
+ if(!modified)
+ if(H5FS_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Freeing section info on disk, old_sect_addr = %a, old_alloc_sect_size = %Hu\n", FUNC, old_sect_addr, old_alloc_sect_size);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Release space for section info in file */
+ if(!H5F_IS_TMP_ADDR(f, old_sect_addr)) {
+ if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_sect_addr, old_alloc_sect_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* H5FS_SINFO_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sinfo_unlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_serialize_size
+ *
+ * Purpose: Determine serialized size of all sections in free space manager
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_serialize_size(H5FS_t *fspace)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fspace);
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 1.0 - fspace->sect_size = %Hu\n", "H5FS_sect_serialize_size", fspace->sect_size);
+HDfprintf(stderr, "%s: fspace->serial_sect_count = %Zu\n", "H5FS_sect_serialize_size", fspace->serial_sect_count);
+HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu\n", "H5FS_sect_serialize_size", fspace->alloc_sect_size);
+HDfprintf(stderr, "%s: fspace->sinfo->serial_size_count = %Zu\n", "H5FS_sect_serialize_size", fspace->sinfo->serial_size_count);
+#endif /* QAK */
+
+ /* Compute the size of the buffer required to serialize all the sections */
+ if(fspace->serial_sect_count > 0) {
+ size_t sect_buf_size; /* Section buffer size */
+
+ /* Serialized sections prefix */
+ sect_buf_size = fspace->sinfo->sect_prefix_size;
+
+ /* Count for each differently sized serializable section */
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->sinfo->serial_size_count = %Zu\n", "H5FS_sect_serialize_size", fspace->sinfo->serial_size_count);
+HDfprintf(stderr, "%s: fspace->serial_sect_count = %Hu\n", "H5FS_sect_serialize_size", fspace->serial_sect_count);
+#endif /* QAK */
+ sect_buf_size += fspace->sinfo->serial_size_count * H5VM_limit_enc_size((uint64_t)fspace->serial_sect_count);
+
+ /* Size for each differently sized serializable section */
+ sect_buf_size += fspace->sinfo->serial_size_count * fspace->sinfo->sect_len_size;
+
+ /* Offsets of each section in address space */
+ sect_buf_size += fspace->serial_sect_count * fspace->sinfo->sect_off_size;
+
+ /* Class of each section */
+ sect_buf_size += fspace->serial_sect_count * 1 /* byte */;
+
+ /* Extra space required to serialize each section */
+ sect_buf_size += fspace->sinfo->serial_size;
+
+ /* Update section size in header */
+ fspace->sect_size = sect_buf_size;
+ } /* end if */
+ else
+ /* Reset section size in header */
+ fspace->sect_size = fspace->sinfo->sect_prefix_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_sect_serialize_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_increase
+ *
+ * Purpose: Increase the size of the serialized free space section info
+ * on disk
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_increase(H5FS_t *fspace, const H5FS_section_class_t *cls,
+ unsigned flags)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(cls);
+
+ /* Increment total # of sections on free space list */
+ fspace->tot_sect_count++;
+
+ /* Check for serializable or 'ghost' section */
+ if(cls->flags & H5FS_CLS_GHOST_OBJ) {
+ /* Sanity check */
+ HDassert(cls->serial_size == 0);
+
+ /* Increment # of ghost sections */
+ fspace->ghost_sect_count++;
+ } /* end if */
+ else {
+ /* Increment # of serializable sections */
+ fspace->serial_sect_count++;
+
+ /* Increment amount of space required to serialize all sections */
+#ifdef QAK
+HDfprintf(stderr, "%s: sinfo->serial_size = %Zu\n", FUNC, fspace->sinfo->serial_size);
+HDfprintf(stderr, "%s: cls->serial_size = %Zu\n", FUNC, cls->serial_size);
+#endif /* QAK */
+ fspace->sinfo->serial_size += cls->serial_size;
+
+ /* Update the free space sections' serialized size */
+ /* (if we're not deserializing the sections from disk) */
+ if(!(flags & H5FS_ADD_DESERIALIZING)) {
+ if(H5FS_sect_serialize_size(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_increase() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_decrease
+ *
+ * Purpose: Decrease the size of the serialized free space section info
+ * on disk
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_decrease(H5FS_t *fspace, const H5FS_section_class_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(cls);
+
+ /* Decrement total # of sections in free space manager */
+ fspace->tot_sect_count--;
+
+ /* Check for serializable or 'ghost' section */
+ if(cls->flags & H5FS_CLS_GHOST_OBJ) {
+ /* Sanity check */
+ HDassert(cls->serial_size == 0);
+
+ /* Decrement # of ghost sections */
+ fspace->ghost_sect_count--;
+ } /* end if */
+ else {
+ /* Decrement # of serializable sections */
+ fspace->serial_sect_count--;
+
+ /* Decrement amount of space required to serialize all sections */
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->sinfo->serial_size);
+HDfprintf(stderr, "%s: cls->serial_size = %Zu\n", FUNC, cls->serial_size);
+#endif /* QAK */
+ fspace->sinfo->serial_size -= cls->serial_size;
+
+ /* Update the free space sections' serialized size */
+ if(H5FS_sect_serialize_size(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_decrease() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_size_node_decr
+ *
+ * Purpose: Decrement the number of sections of a particular size
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_size_node_decr(H5FS_sinfo_t *sinfo, unsigned bin, H5FS_node_t *fspace_node,
+ const H5FS_section_class_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sinfo);
+ HDassert(fspace_node);
+ HDassert(cls);
+
+ /* Decrement the # of sections in this bin */
+ /* (Different from the # of items in the bin's skiplist, since each node on
+ * the bin's skiplist is also a skiplist...)
+ */
+ sinfo->bins[bin].tot_sect_count--;
+#ifdef QAK
+HDfprintf(stderr, "%s: sinfo->bins[%u].sect_count = %Zu\n", FUNC, bin, sinfo->bins[bin].sect_count);
+#endif /* QAK */
+
+ /* Check for 'ghost' or 'serializable' section */
+ if(cls->flags & H5FS_CLS_GHOST_OBJ) {
+ /* Decrement node's ghost section count */
+ fspace_node->ghost_count--;
+
+ /* Decrement bin's ghost section count */
+ sinfo->bins[bin].ghost_sect_count--;
+
+ /* If the node has no more ghost sections, decrement number of ghost section sizes managed */
+ if(fspace_node->ghost_count == 0)
+ sinfo->ghost_size_count--;
+ } /* end if */
+ else {
+ /* Decrement node's serializable section count */
+ fspace_node->serial_count--;
+
+ /* Decrement bin's serializable section count */
+ sinfo->bins[bin].serial_sect_count--;
+
+ /* If the node has no more serializable sections, decrement number of serializable section sizes managed */
+ if(fspace_node->serial_count == 0)
+ sinfo->serial_size_count--;
+ } /* end else */
+
+ /* Check for no more nodes on list of that size */
+ if(H5SL_count(fspace_node->sect_list) == 0) {
+ H5FS_node_t *tmp_fspace_node; /* Free space list size node */
+
+ /* Sanity checks */
+ HDassert(fspace_node->ghost_count == 0);
+ HDassert(fspace_node->serial_count == 0);
+
+ /* Remove size tracking list from bin */
+ tmp_fspace_node = (H5FS_node_t *)H5SL_remove(sinfo->bins[bin].bin_list, &fspace_node->sect_size);
+ if(tmp_fspace_node == NULL || tmp_fspace_node != fspace_node)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list")
+
+ /* Destroy skip list for size tracking node */
+ if(H5SL_close(fspace_node->sect_list) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size tracking node's skip list")
+
+ /* Release free space list node */
+ fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
+
+ /* Decrement total number of section sizes managed */
+ sinfo->tot_size_count--;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_size_node_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_unlink_size
+ *
+ * Purpose: Remove a section node from size tracking data structures for
+ * a free space manager
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_unlink_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect)
+{
+ H5FS_node_t *fspace_node; /* Free list size node */
+ H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
+ unsigned bin; /* Bin to put the free space section in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sinfo);
+ HDassert(sinfo->bins);
+ HDassert(sect);
+ HDassert(cls);
+
+ /* Determine correct bin which holds items of at least the section's size */
+ bin = H5VM_log2_gen(sect->size);
+ HDassert(bin < sinfo->nbins);
+ if(sinfo->bins[bin].bin_list == NULL)
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "node's bin is empty?")
+
+ /* Find space node for section's size */
+ if((fspace_node = (H5FS_node_t *)H5SL_search(sinfo->bins[bin].bin_list, &sect->size)) == NULL)
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section size node")
+
+ /* Remove the section's node from the list */
+ tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace_node->sect_list, &sect->addr);
+ if(tmp_sect_node == NULL || tmp_sect_node != sect)
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list")
+
+ /* Decrement # of sections in section size node */
+ if(H5FS_size_node_decr(sinfo, bin, fspace_node, cls) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_unlink_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_unlink_rest
+ *
+ * Purpose: Finish unlinking a section from the rest of the free space
+ * manager's data structures, after the section has been removed
+ * from the size tracking data structures
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_unlink_rest(H5FS_t *fspace, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(cls);
+ HDassert(sect);
+
+ /* Remove node from merge list, if it was entered there */
+ if(!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
+ H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: removing object from merge list, sect->type = %u\n", FUNC, (unsigned)sect->type);
+#endif /* QAK */
+ tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
+ if(tmp_sect_node == NULL || tmp_sect_node != sect)
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list")
+ } /* end if */
+
+ /* Update section info & check if we need less room for the serialized free space sections */
+ if(H5FS_sect_decrease(fspace, cls) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk")
+
+ /* Decrement amount of free space managed */
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->tot_space = %Hu\n", FUNC, fspace->tot_space);
+#endif /* QAK */
+ fspace->tot_space -= sect->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_unlink_rest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_remove_real
+ *
+ * Purpose: Remove a section from the free space manager
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_remove_real(H5FS_t *fspace, H5FS_section_info_t *sect)
+{
+ const H5FS_section_class_t *cls; /* Class of section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(sect);
+
+ /* Get section's class */
+ cls = &fspace->sect_cls[sect->type];
+
+ /* Remove node from size tracked data structures */
+ if(H5FS_sect_unlink_size(fspace->sinfo, cls, sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from size tracking data structures")
+
+ /* Update rest of free space manager data structures for node removal */
+ if(H5FS_sect_unlink_rest(fspace, cls, sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_remove_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_remove
+ *
+ * Purpose: Remove a section from the free space manager
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_remove(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *sect)
+{
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(sect);
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ /* Perform actual section removal */
+ if(H5FS_sect_remove_real(fspace, sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove section")
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, TRUE) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_link_size
+ *
+ * Purpose: Add a section of free space to the free list bins
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, March 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_link_size(H5FS_sinfo_t *sinfo, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect)
+{
+ H5FS_node_t *fspace_node = NULL; /* Pointer to free space node of the correct size */
+ hbool_t fspace_node_alloc = FALSE; /* Whether the free space node was allocated */
+ unsigned bin; /* Bin to put the free space section in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef QAK
+HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a\n", FUNC, sect->size, sect->addr);
+#endif /* QAK */
+
+ /* Check arguments. */
+ HDassert(sinfo);
+ HDassert(sect);
+ HDassert(H5F_addr_defined(sect->addr));
+ HDassert(sect->size);
+
+ /* Determine correct bin which holds items of the section's size */
+ bin = H5VM_log2_gen(sect->size);
+ HDassert(bin < sinfo->nbins);
+ if(sinfo->bins[bin].bin_list == NULL) {
+ if(NULL == (sinfo->bins[bin].bin_list = H5SL_create(H5SL_TYPE_HSIZE, NULL)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes")
+ } /* end if */
+ else {
+ /* Check for node list of the correct size already */
+ fspace_node = (H5FS_node_t *)H5SL_search(sinfo->bins[bin].bin_list, &sect->size);
+ } /* end else */
+
+ /* Check if we need to create a new skip list for nodes of this size */
+ if(fspace_node == NULL) {
+ /* Allocate new free list size node */
+ if(NULL == (fspace_node = H5FL_MALLOC(H5FS_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for free space node")
+ fspace_node_alloc = TRUE;
+
+ /* Initialize the free list size node */
+ fspace_node->sect_size = sect->size;
+ fspace_node->serial_count = fspace_node->ghost_count = 0;
+ if(NULL == (fspace_node->sect_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes")
+
+ /* Insert new free space size node into bin's list */
+ if(H5SL_insert(sinfo->bins[bin].bin_list, fspace_node, &fspace_node->sect_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list")
+ fspace_node_alloc = FALSE; /* (owned by the bin skip list now, don't need to free on error) */
+
+ /* Increment number of section sizes */
+ sinfo->tot_size_count++;
+ } /* end if */
+
+ /* Increment # of section in bin */
+ /* (Different from the # of items in the bin's skiplist, since each node on
+ * the bin's skiplist is also a skiplist...)
+ */
+#ifdef QAK
+HDfprintf(stderr, "%s: sinfo->bins[%u].sect_count = %Zu\n", FUNC, bin, sinfo->bins[bin].sect_count);
+#endif /* QAK */
+ sinfo->bins[bin].tot_sect_count++;
+ if(cls->flags & H5FS_CLS_GHOST_OBJ) {
+ sinfo->bins[bin].ghost_sect_count++;
+ fspace_node->ghost_count++;
+
+ /* Check for first ghost section in node */
+ if(fspace_node->ghost_count == 1)
+ sinfo->ghost_size_count++;
+ } /* end if */
+ else {
+ sinfo->bins[bin].serial_sect_count++;
+ fspace_node->serial_count++;
+
+ /* Check for first serializable section in node */
+ if(fspace_node->serial_count == 1)
+ sinfo->serial_size_count++;
+ } /* end else */
+
+ /* Insert free space node into correct skip list */
+ if(H5SL_insert(fspace_node->sect_list, sect, &sect->addr) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list")
+
+done:
+ if(ret_value < 0)
+ if(fspace_node && fspace_node_alloc) {
+ if(fspace_node->sect_list && H5SL_close(fspace_node->sect_list) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size free space node's skip list")
+ fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_link_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_link_rest
+ *
+ * Purpose: Link a section into the rest of the non-size tracking
+ * free space manager data structures
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_link_rest(H5FS_t *fspace, const H5FS_section_class_t *cls,
+ H5FS_section_info_t *sect, unsigned flags)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(sect);
+
+ /* Add section to the address-ordered list of sections, if allowed */
+ if(!(cls->flags & H5FS_CLS_SEPAR_OBJ)) {
+#ifdef QAK
+HDfprintf(stderr, "%s: inserting object into merge list, sect->type = %u\n", FUNC, (unsigned)sect->type);
+#endif /* QAK */
+ if(fspace->sinfo->merge_list == NULL)
+ if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for merging free space sections")
+ if(H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into merging skip list")
+ } /* end if */
+
+ /* Update section info & check if we need more room for the serialized free space sections */
+ if(H5FS_sect_increase(fspace, cls, flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk")
+
+ /* Increment amount of free space managed */
+ fspace->tot_space += sect->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_link_rest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_link
+ *
+ * Purpose: Link a section into the internal data structures
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_link(H5FS_t *fspace, H5FS_section_info_t *sect, unsigned flags)
+{
+ const H5FS_section_class_t *cls; /* Class of section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(sect);
+
+ /* Get section's class */
+ cls = &fspace->sect_cls[sect->type];
+
+ /* Add section to size tracked data structures */
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 1.0 - fspace->tot_space = %Hu\n", FUNC, fspace->tot_space);
+#endif /* QAK */
+ if(H5FS_sect_link_size(fspace->sinfo, cls, sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to size tracking data structures")
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 2.0 - fspace->tot_space = %Hu\n", FUNC, fspace->tot_space);
+#endif /* QAK */
+ /* Update rest of free space manager data structures for section addition */
+ if(H5FS_sect_link_rest(fspace, cls, sect, flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to non-size tracking data structures")
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 3.0 - fspace->tot_space = %Hu\n", FUNC, fspace->tot_space);
+#endif /* QAK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_merge
+ *
+ * Purpose: Attempt to merge a returned free space section with existing
+ * free space.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_sect_merge(H5FS_t *fspace, H5FS_section_info_t **sect, void *op_data)
+{
+ H5FS_section_class_t *sect_cls; /* Section's class */
+ hbool_t modified; /* Flag to indicate merge or shrink occurred */
+ hbool_t remove_sect = FALSE; /* Whether a section should be removed before shrinking */
+ htri_t status; /* Status value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(*sect);
+ HDassert(H5F_addr_defined((*sect)->addr));
+ HDassert((*sect)->size);
+
+ /* Loop until no more merging */
+ if(fspace->sinfo->merge_list) {
+ do {
+ H5SL_node_t *less_sect_node; /* Skip list node for section less than new section */
+ H5SL_node_t *greater_sect_node; /* Skip list node for section greater than new section */
+ H5FS_section_info_t *tmp_sect; /* Temporary free space section */
+ H5FS_section_class_t *tmp_sect_cls; /* Temporary section's class */
+ hbool_t greater_sect_node_valid = FALSE; /* Indicate if 'greater than' section node is valid */
+
+ /* Reset 'modification occurred' flag */
+ modified = FALSE;
+
+ /* Look for neighboring section before new section */
+ less_sect_node = H5SL_below(fspace->sinfo->merge_list, &(*sect)->addr);
+
+ /* Check for node before new node able to merge with new node */
+ if(less_sect_node) {
+ /* Check for node greater than section */
+ greater_sect_node = H5SL_next(less_sect_node);
+ greater_sect_node_valid = TRUE;
+
+ /* Get section for 'less than' skip list node */
+ tmp_sect = (H5FS_section_info_t *)H5SL_item(less_sect_node);
+
+ /* Get classes for right & left sections */
+ tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
+ sect_cls = &fspace->sect_cls[(*sect)->type];
+
+ /* Check if sections of the left most class can merge with sections
+ * of another class & whether the sections are the same type,
+ * then check for 'can merge' callback
+ */
+ if((!(tmp_sect_cls->flags & H5FS_CLS_MERGE_SYM) || (tmp_sect->type == (*sect)->type))
+ && tmp_sect_cls->can_merge) {
+ /* Determine if the sections can merge */
+ if((status = (*tmp_sect_cls->can_merge)(tmp_sect, *sect, op_data)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections")
+ if(status > 0) {
+ /* Sanity check */
+ HDassert(tmp_sect_cls->merge);
+
+ /* Remove 'less than' node from data structures */
+ if(H5FS_sect_remove_real(fspace, tmp_sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")
+
+ /* Merge the two sections together */
+ if((*tmp_sect_cls->merge)(&tmp_sect, *sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections")
+
+ /* Retarget section pointer to 'less than' node that was merged into */
+ *sect = tmp_sect;
+ if(*sect == NULL)
+ HGOTO_DONE(ret_value);
+
+ /* Indicate successful merge occurred */
+ modified = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Look for section after new (or merged) section, if not already determined */
+ if(!greater_sect_node_valid)
+ greater_sect_node = H5SL_above(fspace->sinfo->merge_list, &(*sect)->addr);
+
+ /* Check for node after new node able to merge with new node */
+ if(greater_sect_node) {
+ /* Get section for 'greater than' skip list node */
+ tmp_sect = (H5FS_section_info_t *)H5SL_item(greater_sect_node);
+
+ /* Get classes for right & left sections */
+ sect_cls = &fspace->sect_cls[(*sect)->type];
+ tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
+
+ /* Check if sections of the left most class can merge with sections
+ * of another class & whether the sections are the same type,
+ * then check for 'can merge' callback
+ */
+ if((!(sect_cls->flags & H5FS_CLS_MERGE_SYM) || ((*sect)->type == tmp_sect->type))
+ && sect_cls->can_merge) {
+
+ /* Determine if the sections can merge */
+ if((status = (*sect_cls->can_merge)(*sect, tmp_sect, op_data)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections")
+ if(status > 0) {
+ /* Sanity check */
+ HDassert(sect_cls->merge);
+
+ /* Remove 'greater than' node from data structures */
+ if(H5FS_sect_remove_real(fspace, tmp_sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")
+
+ /* Merge the two sections together */
+ if((*sect_cls->merge)(sect, tmp_sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections")
+
+ /* It's possible that the merge caused the section to be deleted (particularly in the paged allocation case) */
+ if(*sect == NULL)
+ HGOTO_DONE(ret_value);
+
+ /* Indicate successful merge occurred */
+ modified = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } while(modified);
+ } /* end if */
+ HDassert(*sect);
+#ifdef QAK
+HDfprintf(stderr, "%s: Done merging, (*sect) = {%a, %Hu, %u, %s}\n", FUNC, (*sect)->addr, (*sect)->size, (*sect)->type, ((*sect)->state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED"));
+#endif /* QAK */
+
+ /* Loop until no more shrinking */
+ do {
+ /* Reset 'modification occurred' flag */
+ modified = FALSE;
+
+ /* Check for (possibly merged) section able to shrink the size of the container */
+ sect_cls = &fspace->sect_cls[(*sect)->type];
+ if(sect_cls->can_shrink) {
+ if((status = (*sect_cls->can_shrink)(*sect, op_data)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container")
+ if(status > 0) {
+#ifdef QAK
+HDfprintf(stderr, "%s: Can shrink!\n", FUNC);
+#endif /* QAK */
+
+ /* Remove SECT from free-space manager */
+ /* (only possible to happen on second+ pass through loop) */
+ if(remove_sect) {
+ if(H5FS_sect_remove_real(fspace, *sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")
+ remove_sect = FALSE;
+ } /* end if */
+
+ /* Shrink the container */
+ /* (callback can indicate that it has discarded the section by setting *sect to NULL) */
+ HDassert(sect_cls->shrink);
+ if((*sect_cls->shrink)(sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container")
+
+ /* If this section was shrunk away, we may need to shrink another section */
+ if(*sect == NULL) {
+ /* Check for sections on merge list */
+ if(fspace->sinfo->merge_list) {
+ H5SL_node_t *last_node; /* Last node in merge list */
+
+ /* Check for last node in the merge list */
+ if(NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
+ /* Get the pointer to the last section, from the last node */
+ *sect = (H5FS_section_info_t *)H5SL_item(last_node);
+ HDassert(*sect);
+
+ /* Indicate that this section needs to be removed if it causes a shrink */
+ remove_sect = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /* Indicate successful merge occurred */
+ modified = TRUE;
+ } /* end if */
+ } /* end if */
+ } while(modified && *sect);
+
+ /* Check for section that was shrunk away and next section not shrinking */
+ if(remove_sect && (*sect != NULL))
+ *sect = NULL;
+
+#ifdef QAK
+HDfprintf(stderr, "%s: Done shrinking\n", FUNC);
+if(*sect)
+ HDfprintf(stderr, "%s: (*sect) = {%a, %Hu, %u, %s}\n", FUNC, (*sect)->addr, (*sect)->size, (*sect)->type, ((*sect)->state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED"));
+else
+ HDfprintf(stderr, "%s: *sect = %p\n", FUNC, *sect);
+#endif /* QAK */
+
+done:
+#ifdef QAK
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* QAK */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_add
+ *
+ * Purpose: Add a section of free space to the free list
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect,
+ unsigned flags, void *op_data)
+{
+ H5FS_section_class_t *cls; /* Section's class */
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ hbool_t sinfo_modified = FALSE; /* Whether the section info was modified */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: *sect = {%a, %Hu, %u, %s}\n", FUNC, sect->addr, sect->size, sect->type, (sect->state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED"));
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(sect);
+ HDassert(H5F_addr_defined(sect->addr));
+ HDassert(sect->size);
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ /* Call "add" section class callback, if there is one */
+ cls = &fspace->sect_cls[sect->type];
+ if(cls->add) {
+ if((*cls->add)(&sect, &flags, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "'add' section class callback failed")
+ } /* end if */
+
+ /* Check for merging returned space with existing section node */
+ if(flags & H5FS_ADD_RETURNED_SPACE) {
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Returning space\n", FUNC);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Attempt to merge returned section with existing sections */
+ if(H5FS_sect_merge(fspace, &sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections")
+ } /* end if */
+
+ /* Add new (possibly merged) node to free sections data structures */
+ /* (If section has been completely merged or shrunk away, 'sect' will
+ * be NULL at this point - QAK)
+ */
+ if(sect)
+ if(H5FS_sect_link(fspace, sect, flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list")
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: fspace->tot_space = %Hu\n", FUNC, fspace->tot_space);
+#endif /* H5FS_SINFO_DEBUG */
+ /* Mark free space sections as changed */
+ /* (if adding sections while deserializing sections, don't set the flag) */
+ if(!(flags & (H5FS_ADD_DESERIALIZING | H5FS_PAGE_END_NO_ADD)))
+ sinfo_modified = TRUE;
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, sinfo_modified) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+#ifdef H5FS_DEBUG_ASSERT
+if(!(flags & (H5FS_ADD_DESERIALIZING | H5FS_ADD_SKIP_VALID)))
+ H5FS_assert(fspace, dxpl_id);
+#endif /* H5FS_DEBUG_ASSERT */
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* H5FS_SINFO_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_try_extend
+ *
+ * Purpose: Try to extend a block using space from a section on the free list
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS_sect_try_extend(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, haddr_t addr,
+ hsize_t size, hsize_t extra_requested, unsigned flags, void *op_data)
+{
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ hbool_t sinfo_modified = FALSE; /* Whether the section info was modified */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: addr = %a, size = %Hu, extra_requested = %hu\n", FUNC, addr, size, extra_requested);
+#endif /* H5FS_SINFO_DEBUG */
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(size > 0);
+ HDassert(extra_requested > 0);
+
+ /* Check for any sections on free space list */
+#ifdef H5FS_SINFO_DEBUG
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", FUNC, fspace->tot_sect_count);
+HDfprintf(stderr, "%s: fspace->serial_sect_count = %Hu\n", FUNC, fspace->serial_sect_count);
+HDfprintf(stderr, "%s: fspace->ghost_sect_count = %Hu\n", FUNC, fspace->ghost_sect_count);
+#endif /* H5FS_SINFO_DEBUG */
+ if(fspace->tot_sect_count > 0) {
+ H5FS_section_info_t *sect; /* Temporary free space section */
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+
+/*
+
+Pseudo-code for algorithm:
+
+_section_ = <Get pointer to section with address > _region.addr_>
+if(_section_)
+ if(_section_ adjoins _region_ && _section.size_ >= _extra_requested_)
+ <remove section from data structures>
+ if(_section.size_ > _extra_requested_)
+ if(<can adjust _section_>)
+ <adjust _section_ by _extra_requested_>
+ <add adjusted section back to data structures>
+ else
+ <re-add UNadjusted section back to data structures>
+ <error>
+ <mark free space sections as changed in metadata cache>
+
+*/
+ /* Look for a section after block to extend */
+ if((sect = (H5FS_section_info_t *)H5SL_greater(fspace->sinfo->merge_list, &addr))) {
+ /* Check if this section adjoins the block and is large enough to
+ * fulfill extension request.
+ *
+ * (Note: we assume that the section is fully merged with any
+ * possible neighboring nodes and is not at the end of the file
+ * (or it would have been eliminated), etc)
+ */
+ if(sect->size >= extra_requested && (addr + size) == sect->addr) {
+ H5FS_section_class_t *cls; /* Section's class */
+
+ /* Remove section from data structures */
+ if(H5FS_sect_remove_real(fspace, sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")
+
+ /* Get class for section */
+ cls = &fspace->sect_cls[sect->type];
+
+ /* Check for the section needing to be adjusted and re-added */
+ /* (Note: we should probably add a can_adjust/adjust callback
+ * to the section class structure, but we don't need it
+ * for the current usage, so I've deferred messing with
+ * it. - QAK - 2008/01/08)
+ */
+ if(sect->size > extra_requested) {
+ /* Sanity check (for now) */
+ HDassert(cls->flags & H5FS_CLS_ADJUST_OK);
+
+ /* Adjust section by amount requested */
+ sect->addr += extra_requested;
+ sect->size -= extra_requested;
+ if(cls->add)
+ if((*cls->add)(&sect, &flags, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "'add' section class callback failed")
+
+ /* Re-adding the section could cause it to disappear (particularly when paging) */
+ if(sect) {
+ /* Re-add adjusted section to free sections data structures */
+ if(H5FS_sect_link(fspace, sect, 0) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list")
+ } /* end if */
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(sect->size == extra_requested);
+
+ /* Exact match, so just free section */
+ if((*cls->free)(sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't free section")
+ } /* end else */
+
+ /* Note that we modified the section info */
+ sinfo_modified = TRUE;
+
+ /* Indicate success */
+ HGOTO_DONE(TRUE);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, sinfo_modified) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_try_extend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_try_merge
+ *
+ * Purpose: Try to merge/shrink a block
+ *
+ * Return: TRUE: merged/shrunk
+ * FALSE: not merged/not shrunk
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * June 10, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS_sect_try_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect,
+ unsigned flags, void *op_data)
+{
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ hbool_t sinfo_modified = FALSE; /* Whether the section info was modified */
+ hsize_t saved_fs_size; /* Copy of the free-space section size */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(sect);
+ HDassert(H5F_addr_defined(sect->addr));
+ HDassert(sect->size);
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+ saved_fs_size = sect->size;
+
+ /* Attempt to merge/shrink section with existing sections */
+ if(H5FS_sect_merge(fspace, &sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections")
+
+ /* Check if section is shrunk and/or merged away completely */
+ if(!sect) {
+ sinfo_modified = TRUE;
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ else {
+ /* Check if section is merged */
+ if(sect->size > saved_fs_size) {
+ if(H5FS_sect_link(fspace, sect, flags) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list")
+ sinfo_modified = TRUE;
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end else */
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, sinfo_modified) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_try_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_find_node
+ *
+ * Purpose: Locate a section of free space (in existing free space list
+ * bins) that is large enough to fulfill request.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, March 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5FS_sect_find_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node)
+{
+ H5FS_node_t *fspace_node; /* Free list size node */
+ unsigned bin; /* Bin to put the free space section in */
+ htri_t ret_value = FALSE; /* Return value */
+
+ H5SL_node_t *curr_size_node=NULL;
+ const H5FS_section_class_t *cls; /* Class of section */
+ hsize_t alignment;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->sinfo);
+ HDassert(fspace->sinfo->bins);
+ HDassert(request > 0);
+ HDassert(node);
+
+ /* Determine correct bin which holds items of at least the section's size */
+ bin = H5VM_log2_gen(request);
+ HDassert(bin < fspace->sinfo->nbins);
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->sinfo->nbins = %u\n", FUNC, fspace->sinfo->nbins);
+HDfprintf(stderr, "%s: bin = %u\n", FUNC, bin);
+#endif /* QAK */
+ alignment = fspace->alignment;
+ if(!((alignment > 1) && (request >= fspace->align_thres)))
+ alignment = 0; /* no alignment */
+
+ do {
+ /* Check if there's any sections in this bin */
+ if(fspace->sinfo->bins[bin].bin_list) {
+
+ if (!alignment) { /* no alignment */
+ /* Find the first free space section that is large enough to fulfill request */
+ /* (Since the bins use skip lists to track the sizes of the address-ordered
+ * lists, this is actually a "best fit" algorithm)
+ */
+ /* Look for large enough free space section in this bin */
+ if((fspace_node = (H5FS_node_t *)H5SL_greater(fspace->sinfo->bins[bin].bin_list, &request))) {
+ /* Take first node off of the list (ie. node w/lowest address) */
+ if(NULL == (*node = (H5FS_section_info_t *)H5SL_remove_first(fspace_node->sect_list)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list")
+
+ /* Get section's class */
+ cls = &fspace->sect_cls[(*node)->type];
+ /* Decrement # of sections in section size node */
+ if(H5FS_size_node_decr(fspace->sinfo, bin, fspace_node, cls) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list")
+ if(H5FS_sect_unlink_rest(fspace, cls, *node) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures")
+ /* Indicate that we found a node for the request */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+ else { /* alignment is set */
+ /* get the first node of a certain size in this bin */
+ curr_size_node = H5SL_first(fspace->sinfo->bins[bin].bin_list);
+ while (curr_size_node != NULL) {
+ H5FS_node_t *curr_fspace_node=NULL;
+ H5SL_node_t *curr_sect_node=NULL;
+
+ /* Get the free space node for free space sections of the same size */
+ curr_fspace_node = (H5FS_node_t *)H5SL_item(curr_size_node);
+
+ /* Get the Skip list which holds pointers to actual free list sections */
+ curr_sect_node = (H5SL_node_t *)H5SL_first(curr_fspace_node->sect_list);
+
+ while(curr_sect_node != NULL) {
+ H5FS_section_info_t *curr_sect=NULL;
+ hsize_t mis_align=0, frag_size=0;
+ H5FS_section_info_t *split_sect=NULL;
+
+ /* Get section node */
+ curr_sect = (H5FS_section_info_t *)H5SL_item(curr_sect_node);
+
+ HDassert(H5F_addr_defined(curr_sect->addr));
+ HDassert(curr_fspace_node->sect_size == curr_sect->size);
+
+ cls = &fspace->sect_cls[curr_sect->type];
+
+ HDassert(alignment);
+ HDassert(cls);
+
+ if((mis_align = curr_sect->addr % alignment))
+ frag_size = alignment - mis_align;
+
+ if((curr_sect->size >= (request + frag_size)) && (cls->split)) {
+ /* remove the section with aligned address */
+ if(NULL == (*node = (H5FS_section_info_t *)H5SL_remove(curr_fspace_node->sect_list, &curr_sect->addr)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list")
+ /* Decrement # of sections in section size node */
+ if(H5FS_size_node_decr(fspace->sinfo, bin, curr_fspace_node, cls) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list")
+
+ if(H5FS_sect_unlink_rest(fspace, cls, *node) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures")
+
+ /*
+ * The split() callback splits NODE into 2 sections:
+ * split_sect is the unused fragment for aligning NODE
+ * NODE's addr & size are updated to point to the remaining aligned section
+ * split_sect is re-added to free-space
+ */
+ if(mis_align) {
+ split_sect = cls->split(*node, frag_size);
+ if((H5FS_sect_link(fspace, split_sect, 0) < 0))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list")
+ /* sanity check */
+ HDassert(split_sect->addr < (*node)->addr);
+ HDassert(request <= (*node)->size);
+ } /* end if */
+ /* Indicate that we found a node for the request */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+
+ /* Get the next section node in the list */
+ curr_sect_node = H5SL_next(curr_sect_node);
+ } /* end while of curr_sect_node */
+
+ /* Get the next size node in the bin */
+ curr_size_node = H5SL_next(curr_size_node);
+ } /* end while of curr_size_node */
+ } /* else of alignment */
+ } /* if bin_list */
+ /* Advance to next larger bin */
+ bin++;
+ } while(bin < fspace->sinfo->nbins);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_find_node() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_find
+ *
+ * Purpose: Locate a section of free space (in existing free space list) that
+ * is large enough to fulfill request.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS_sect_find(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, hsize_t request,
+ H5FS_section_info_t **node)
+{
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ hbool_t sinfo_modified = FALSE; /* Whether the section info was modified */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+#ifdef QAK
+HDfprintf(stderr, "%s: request = %Hu\n", FUNC, request);
+#endif /* QAK */
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(fspace->nclasses);
+ HDassert(request);
+ HDassert(node);
+
+ /* Check for any sections on free space list */
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", FUNC, fspace->tot_sect_count);
+HDfprintf(stderr, "%s: fspace->serial_sect_count = %Hu\n", FUNC, fspace->serial_sect_count);
+HDfprintf(stderr, "%s: fspace->ghost_sect_count = %Hu\n", FUNC, fspace->ghost_sect_count);
+#endif /* QAK */
+ if(fspace->tot_sect_count > 0) {
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ /* Look for node in bins */
+ if((ret_value = H5FS_sect_find_node(fspace, request, node)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from bins")
+
+ /* Decrement # of sections on free list, if we found an object */
+ if(ret_value > 0) {
+ /* Note that we've modified the section info */
+ sinfo_modified = TRUE;
+#ifdef QAK
+HDfprintf(stderr, "%s: (*node)->size = %Hu, (*node)->addr = %a, (*node)->type = %u\n", FUNC, (*node)->size, (*node)->addr, (*node)->type);
+#endif /* QAK */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, sinfo_modified) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+#ifdef H5FS_DEBUG_ASSERT
+ H5FS_assert(fspace, dxpl_id);
+#endif /* H5FS_DEBUG_ASSERT */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_iterate_sect_cb
+ *
+ * Purpose: Skip list iterator callback to iterate over free space sections
+ * of a particular size
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_iterate_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5FS_section_info_t *sect_info = (H5FS_section_info_t *)_item; /* Free space section to work on */
+ H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect_info);
+ HDassert(udata->fspace);
+ HDassert(udata->op);
+
+ /* Make callback for this section */
+ if((*udata->op)(sect_info, udata->op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "iteration callback failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_iterate_sect_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_iterate_node_cb
+ *
+ * Purpose: Skip list iterator callback to iterate over free space sections
+ * in a bin
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FS_iterate_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5FS_node_t *fspace_node = (H5FS_node_t *)_item; /* Free space size node to work on */
+ H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace_node);
+ HDassert(udata->fspace);
+ HDassert(udata->op);
+
+ /* Iterate through all the sections of this size */
+ HDassert(fspace_node->sect_list);
+ if(H5SL_iterate(fspace_node->sect_list, H5FS_iterate_sect_cb, udata) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_iterate_node_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_iterate
+ *
+ * Purpose: Iterate over all the sections managed
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_iterate(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_operator_t op, void *op_data)
+{
+ H5FS_iter_ud_t udata; /* User data for callbacks */
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(op);
+
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", FUNC, fspace->tot_sect_count);
+#endif /* QAK */
+
+ /* Set up user data for iterator */
+ udata.fspace = fspace;
+ udata.op = op;
+ udata.op_data = op_data;
+
+ /* Iterate over sections, if there are any */
+ if(fspace->tot_sect_count) {
+ unsigned bin; /* Current bin we are on */
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__READ_ONLY_FLAG) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ /* Iterate over all the bins */
+#ifdef QAK
+HDfprintf(stderr, "%s: Iterate over section bins\n", FUNC);
+#endif /* QAK */
+ for(bin = 0; bin < fspace->sinfo->nbins; bin++) {
+ /* Check if there are any sections in this bin */
+ if(fspace->sinfo->bins[bin].bin_list) {
+ /* Iterate over list of section size nodes for bin */
+ if(H5SL_iterate(fspace->sinfo->bins[bin].bin_list, H5FS_iterate_node_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes")
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, FALSE) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_stats
+ *
+ * Purpose: Retrieve info about the sections managed
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_stats(const H5FS_t *fspace, hsize_t *tot_space, hsize_t *nsects)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fspace);
+
+ /* Get the stats desired */
+ if(tot_space)
+ *tot_space = fspace->tot_space;
+ if(nsects)
+ *nsects = fspace->tot_sect_count;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_sect_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_change_class
+ *
+ * Purpose: Make appropriate adjustments to internal data structures when
+ * a section changes class
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_change_class(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
+ H5FS_section_info_t *sect, uint16_t new_class)
+{
+ const H5FS_section_class_t *old_cls; /* Old class of section */
+ const H5FS_section_class_t *new_cls; /* New class of section */
+ unsigned old_class; /* Old class ID of section */
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(fspace);
+ HDassert(sect);
+ HDassert(sect->type < fspace->nclasses);
+ HDassert(new_class < fspace->nclasses);
+
+ /* Get a pointer to the section info */
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ /* Get class info */
+ old_class = sect->type;
+ old_cls = &fspace->sect_cls[sect->type];
+ new_cls = &fspace->sect_cls[new_class];
+#ifdef QAK
+HDfprintf(stderr, "%s: old_cls->flags = %x\n", FUNC, old_cls->flags);
+HDfprintf(stderr, "%s: new_cls->flags = %x\n", FUNC, new_cls->flags);
+#endif /* QAK */
+
+ /* Check if the section's class change will affect the # of serializable or ghost sections */
+ if((old_cls->flags & H5FS_CLS_GHOST_OBJ) != (new_cls->flags & H5FS_CLS_GHOST_OBJ)) {
+ H5FS_node_t *fspace_node; /* Free list size node */
+ unsigned bin; /* Bin to put the free space section in */
+ hbool_t to_ghost; /* Flag if the section is changing to a ghost section */
+
+ /* Determine if this section is becoming a ghost or is becoming serializable */
+ if(old_cls->flags & H5FS_CLS_GHOST_OBJ)
+ to_ghost = FALSE;
+ else
+ to_ghost = TRUE;
+#ifdef QAK
+HDfprintf(stderr, "%s: to_ghost = %u\n", FUNC, to_ghost);
+#endif /* QAK */
+
+ /* Sanity check */
+ HDassert(fspace->sinfo->bins);
+
+ /* Determine correct bin which holds items of at least the section's size */
+ bin = H5VM_log2_gen(sect->size);
+ HDassert(bin < fspace->sinfo->nbins);
+ HDassert(fspace->sinfo->bins[bin].bin_list);
+
+ /* Get space node for section's size */
+ fspace_node = (H5FS_node_t *)H5SL_search(fspace->sinfo->bins[bin].bin_list, &sect->size);
+ HDassert(fspace_node);
+
+ /* Adjust serializable/ghost counts */
+ if(to_ghost) {
+ /* Adjust global section count totals */
+ fspace->serial_sect_count--;
+ fspace->ghost_sect_count++;
+
+ /* Adjust bin's section count totals */
+ fspace->sinfo->bins[bin].serial_sect_count--;
+ fspace->sinfo->bins[bin].ghost_sect_count++;
+
+ /* Adjust section size node's section count totals */
+ fspace_node->serial_count--;
+ fspace_node->ghost_count++;
+
+ /* Check if we switched a section size node's status */
+ if(fspace_node->serial_count == 0)
+ fspace->sinfo->serial_size_count--;
+ if(fspace_node->ghost_count == 1)
+ fspace->sinfo->ghost_size_count++;
+ } /* end if */
+ else {
+ /* Adjust global section count totals */
+ fspace->serial_sect_count++;
+ fspace->ghost_sect_count--;
+
+ /* Adjust bin's section count totals */
+ fspace->sinfo->bins[bin].serial_sect_count++;
+ fspace->sinfo->bins[bin].ghost_sect_count--;
+
+ /* Adjust section size node's section count totals */
+ fspace_node->serial_count++;
+ fspace_node->ghost_count--;
+
+ /* Check if we switched a section size node's status */
+ if(fspace_node->serial_count == 1)
+ fspace->sinfo->serial_size_count++;
+ if(fspace_node->ghost_count == 0)
+ fspace->sinfo->ghost_size_count--;
+ } /* end else */
+ } /* end if */
+
+ /* Check if the section's class change will affect the mergable list */
+ if((old_cls->flags & H5FS_CLS_SEPAR_OBJ) != (new_cls->flags & H5FS_CLS_SEPAR_OBJ)) {
+ hbool_t to_mergable; /* Flag if the section is changing to a mergable section */
+
+ /* Determine if this section is becoming mergable or is becoming separate */
+ if(old_cls->flags & H5FS_CLS_SEPAR_OBJ)
+ to_mergable = TRUE;
+ else
+ to_mergable = FALSE;
+#ifdef QAK
+HDfprintf(stderr, "%s: to_mergable = %u\n", FUNC, to_mergable);
+#endif /* QAK */
+
+ /* Add or remove section from merge list, as appropriate */
+ if(to_mergable) {
+#ifdef QAK
+HDfprintf(stderr, "%s: inserting object into merge list, sect->type = %u\n", FUNC, (unsigned)sect->type);
+#endif /* QAK */
+ if(fspace->sinfo->merge_list == NULL)
+ if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for merging free space sections")
+ if(H5SL_insert(fspace->sinfo->merge_list, sect, &sect->addr) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into merging skip list")
+ } /* end if */
+ else {
+ H5FS_section_info_t *tmp_sect_node; /* Temporary section node */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: removing object from merge list, sect->type = %u\n", FUNC, (unsigned)sect->type);
+#endif /* QAK */
+ tmp_sect_node = (H5FS_section_info_t *)H5SL_remove(fspace->sinfo->merge_list, &sect->addr);
+ if(tmp_sect_node == NULL || tmp_sect_node != sect)
+ HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list")
+ } /* end else */
+ } /* end if */
+
+ /* Change the section's class */
+ sect->type = new_class;
+
+ /* Change the serialized size of sections */
+ fspace->sinfo->serial_size -= fspace->sect_cls[old_class].serial_size;
+ fspace->sinfo->serial_size += fspace->sect_cls[new_class].serial_size;
+
+ /* Update current space used for free space sections */
+ if(H5FS_sect_serialize_size(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, TRUE) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_change_class() */
+
+#ifdef H5FS_DEBUG_ASSERT
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_assert
+ *
+ * Purpose: Verify that the sections managed are mostly sane
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Jul 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_sect_assert(const H5FS_t *fspace, hid_t dxpl_id)
+{
+ hsize_t separate_obj; /* The number of separate objects managed */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+#ifdef QAK
+HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", "H5FS_sect_assert", fspace->tot_sect_count);
+#endif /* QAK */
+
+ /* Initialize state */
+ separate_obj = 0;
+
+ /* Check for bins to work on */
+ if(fspace->sinfo->bins) {
+ hsize_t acc_tot_sect_count; /* Accumulated total section count from bins */
+ hsize_t acc_serial_sect_count; /* Accumulated serializable section count from bins */
+ hsize_t acc_ghost_sect_count; /* Accumulated ghost section count from bins */
+ size_t acc_tot_size_count; /* Accumulated total section size count from bins */
+ size_t acc_serial_size_count; /* Accumulated serializable section size count from bins */
+ size_t acc_ghost_size_count; /* Accumulated ghost section size count from bins */
+ unsigned u; /* Local index variable */
+
+ /* Walk through all sections in bins */
+ acc_tot_sect_count = 0;
+ acc_serial_sect_count = 0;
+ acc_ghost_sect_count = 0;
+ acc_tot_size_count = 0;
+ acc_serial_size_count = 0;
+ acc_ghost_size_count = 0;
+ for(u = 0; u < fspace->sinfo->nbins; u++) {
+ acc_tot_sect_count += fspace->sinfo->bins[u].tot_sect_count;
+ acc_serial_sect_count += fspace->sinfo->bins[u].serial_sect_count;
+ acc_ghost_sect_count += fspace->sinfo->bins[u].ghost_sect_count;
+ if(fspace->sinfo->bins[u].bin_list) {
+ H5SL_node_t *curr_size_node; /* Current section size node in skip list */
+ size_t bin_serial_count; /* # of serializable sections in this bin */
+ size_t bin_ghost_count; /* # of ghost sections in this bin */
+
+ acc_tot_size_count += H5SL_count(fspace->sinfo->bins[u].bin_list);
+
+ /* Walk through the sections in this bin */
+ curr_size_node = H5SL_first(fspace->sinfo->bins[u].bin_list);
+ bin_serial_count = 0;
+ bin_ghost_count = 0;
+ while(curr_size_node != NULL) {
+ H5FS_node_t *fspace_node; /* Section size node */
+ H5SL_node_t *curr_sect_node; /* Current section node in skip list */
+ size_t size_serial_count; /* # of serializable sections of this size */
+ size_t size_ghost_count; /* # of ghost sections of this size */
+
+ /* Get section size node */
+ fspace_node = H5SL_item(curr_size_node);
+
+ /* Check sections on list */
+ curr_sect_node = H5SL_first(fspace_node->sect_list);
+ size_serial_count = 0;
+ size_ghost_count = 0;
+ while(curr_sect_node != NULL) {
+ H5FS_section_class_t *cls; /* Class of section */
+ H5FS_section_info_t *sect; /* Section */
+
+ /* Get section node & it's class */
+ sect = H5SL_item(curr_sect_node);
+ cls = &fspace->sect_cls[sect->type];
+#ifdef QAK
+HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a, sect->type = %u\n", "H5FS_assert", sect->size, sect->addr, sect->type);
+#endif /* QAK */
+
+ /* Sanity check section */
+ HDassert(H5F_addr_defined(sect->addr));
+ HDassert(fspace_node->sect_size == sect->size);
+ if(cls->valid)
+ (*cls->valid)(cls, sect, dxpl_id);
+
+ /* Add to correct count */
+ if(cls->flags & H5FS_CLS_GHOST_OBJ)
+ size_ghost_count++;
+ else
+ size_serial_count++;
+
+ /* Count node, if separate */
+ if(cls->flags & H5FS_CLS_SEPAR_OBJ)
+ separate_obj++;
+
+ /* Get the next section node in the list */
+ curr_sect_node = H5SL_next(curr_sect_node);
+ } /* end while */
+
+ /* Check the number of serializable & ghost sections of this size */
+ HDassert(fspace_node->serial_count == size_serial_count);
+ HDassert(fspace_node->ghost_count == size_ghost_count);
+
+ /* Add to global count of serializable & ghost section sizes */
+ if(fspace_node->serial_count > 0)
+ acc_serial_size_count++;
+ if(fspace_node->ghost_count > 0)
+ acc_ghost_size_count++;
+
+ /* Add to bin's serializable & ghost counts */
+ bin_serial_count += size_serial_count;
+ bin_ghost_count += size_ghost_count;
+
+ /* Get the next section size node in the list */
+ curr_size_node = H5SL_next(curr_size_node);
+ } /* end while */
+
+ /* Check the number of serializable & ghost sections in this bin */
+ HDassert(fspace->sinfo->bins[u].tot_sect_count == (bin_serial_count + bin_ghost_count));
+ HDassert(fspace->sinfo->bins[u].serial_sect_count == bin_serial_count);
+ HDassert(fspace->sinfo->bins[u].ghost_sect_count == bin_ghost_count);
+ } /* end if */
+ } /* end for */
+
+ /* Check counts from bins vs. global counts */
+ HDassert(fspace->sinfo->tot_size_count == acc_tot_size_count);
+ HDassert(fspace->sinfo->serial_size_count == acc_serial_size_count);
+ HDassert(fspace->sinfo->ghost_size_count == acc_ghost_size_count);
+ HDassert(fspace->tot_sect_count == acc_tot_sect_count);
+ HDassert(fspace->serial_sect_count == acc_serial_sect_count);
+ HDassert(fspace->ghost_sect_count == acc_ghost_sect_count);
+ } /* end if */
+ else {
+ /* Check counts are zero */
+ HDassert(fspace->tot_sect_count == 0);
+ HDassert(fspace->serial_sect_count == 0);
+ HDassert(fspace->ghost_sect_count == 0);
+ } /* end else */
+
+ /* Make certain that the number of sections on the address list is correct */
+ if(fspace->sinfo->merge_list)
+ HDassert(fspace->tot_sect_count == (separate_obj + H5SL_count(fspace->sinfo->merge_list)));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FS_sect_assert() */
+#endif /* H5FS_DEBUG_ASSERT */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_sect_try_shrink_eoa
+ *
+ * Purpose: To shrink the last section on the merge list if the section
+ * is at EOF.
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5FS_sect_try_shrink_eoa(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, void *op_data)
+{
+ hbool_t sinfo_valid = FALSE; /* Whether the section info is valid */
+ hbool_t section_removed = FALSE; /* Whether a section was removed */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ HDassert(fspace);
+
+ if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info")
+ sinfo_valid = TRUE;
+
+ if(fspace->sinfo && fspace->sinfo->merge_list) {
+ H5SL_node_t *last_node; /* Last node in merge list */
+
+ /* Check for last node in the merge list */
+ if(NULL != (last_node = H5SL_last(fspace->sinfo->merge_list))) {
+ H5FS_section_info_t *tmp_sect; /* Temporary free space section */
+ H5FS_section_class_t *tmp_sect_cls; /* Temporary section's class */
+
+ /* Get the pointer to the last section, from the last node */
+ tmp_sect = (H5FS_section_info_t *)H5SL_item(last_node);
+ HDassert(tmp_sect);
+ tmp_sect_cls = &fspace->sect_cls[tmp_sect->type];
+ if(tmp_sect_cls->can_shrink) {
+ /* Check if the section can be shrunk away */
+ if((ret_value = (*tmp_sect_cls->can_shrink)(tmp_sect, op_data)) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container")
+ if(ret_value > 0) {
+ HDassert(tmp_sect_cls->shrink);
+
+ /* Remove section from free space manager */
+ if(H5FS_sect_remove_real(fspace, tmp_sect) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")
+ section_removed = TRUE;
+
+ /* Shrink away section */
+ if((*tmp_sect_cls->shrink)(&tmp_sect, op_data) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the section info */
+ if(sinfo_valid && H5FS_sinfo_unlock(f, dxpl_id, fspace, section_removed) < 0)
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't release section info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_sect_try_shrink_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_vfd_alloc_hdr_and_section_info_if_needed
+ *
+ * Purpose: This function is part of a hack to patch over a design
+ * flaw in the free space managers for file space allocation.
+ * Specifically, if a free space manager allocates space for
+ * its own section info, it is possible for it to
+ * go into an infinite loop as it:
+ *
+ * 1) computes the size of the section info
+ *
+ * 2) allocates file space for the section info
+ *
+ * 3) notices that the size of the section info
+ * has changed
+ *
+ * 4) deallocates the section info file space and
+ * returns to 1) above.
+ *
+ * Similarly, if it allocates space for its own header, it
+ * can go into an infinte loop as it:
+ *
+ * 1) allocates space for the header
+ *
+ * 2) notices that the free space manager is empty
+ * and thus should not have file space allocated
+ * to its header
+ *
+ * 3) frees the space allocated to the header
+ *
+ * 4) notices that the free space manager is not
+ * empty and thus must have file space allocated
+ * to it, and thus returns to 1) above.
+ *
+ * In a nutshell, the solution applied in this hack is to
+ * deallocate file space for the free space manager(s) that
+ * handle FSM header and/or section info file space allocations,
+ * wait until all other allocation/deallocation requests have
+ * been handled, and then test to see if the free space manager(s)
+ * in question are empty. If they are, do nothing. If they
+ * are not, allocate space for them at end of file bypassing the
+ * usual file space allocation calls, and thus avoiding the
+ * potential infinite loops.
+ *
+ * The purpose of this function is to allocate file space for
+ * the header and section info of the target free space manager
+ * directly from the VFD if needed. In this case the function
+ * also re-inserts the header and section info in the metadata
+ * cache with this allocation.
+ *
+ * When paged allocation is not enabled, allocation of space
+ * for the free space manager header and section info is
+ * straight forward -- we simply allocate the space directly
+ * from file driver.
+ *
+ * Note that if f->shared->alignment > 1, and EOA is not a
+ * multiple of the alignment, it is possible that performing
+ * these allocations may generate a fragment of file space in
+ * addition to the space allocated for the section info. This
+ * excess space is dropped on the floor. As shall be seen,
+ * it will usually be reclaimed later.
+ *
+ * When page allocation is enabled, things are more difficult,
+ * as there is the possibility that page buffering will be
+ * enabled when the free space managers are read. To allow
+ * for this, we must ensure that space allocated for the
+ * free space manager header and section info is either larger
+ * than a page, or resides completely withing a page.
+ *
+ * Do this by allocating space for the free space header and
+ * section info starting at page boundaries, and extending
+ * allocation to the next page boundary. This of course wastes
+ * space, but see below.
+ *
+ * On the first free space allocation / deallocation after the
+ * next file open, we will read the self referential free space
+ * managers, float them and reduce the EOA to its value prior
+ * to allocation of file space for the self referential free
+ * space managers on the preceeding file close. This EOA value
+ * is stored in the free space manager superblock extension
+ * message.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: John Mainzer
+ * 6/6/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_vfd_alloc_hdr_and_section_info_if_needed(H5F_t *f, hid_t dxpl_id,
+ H5FS_t *fspace, haddr_t *fs_addr_ptr)
+{
+ hsize_t hdr_alloc_size;
+ hsize_t sinfo_alloc_size;
+ haddr_t sect_addr = HADDR_UNDEF; /* address of sinfo */
+ haddr_t eoa_frag_addr = HADDR_UNDEF; /* Address of fragment at EOA */
+ hsize_t eoa_frag_size = 0; /* Size of fragment at EOA */
+ haddr_t eoa = HADDR_UNDEF; /* Initial EOA for the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(fspace);
+ HDassert(fs_addr_ptr);
+
+ /* the section info should be unlocked */
+ HDassert(fspace->sinfo_lock_count == 0);
+
+ /* no space should be allocated */
+ HDassert(*fs_addr_ptr == HADDR_UNDEF);
+ HDassert(fspace->addr == HADDR_UNDEF);
+ HDassert(fspace->sect_addr == HADDR_UNDEF);
+ HDassert(fspace->alloc_sect_size == 0);
+
+ /* persistant free space managers must be enabled */
+ HDassert(f->shared->fs_persist);
+
+ /* At present, all free space strategies enable the free space managers.
+ * This will probably change -- at which point this assertion should
+ * be revisited.
+ */
+ /* Updated: Only the following two strategies enable the free-space managers */
+ HDassert((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) ||
+ (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE));
+
+ if(fspace->serial_sect_count > 0) {
+ /* the section info is floating, so space->sinfo should be defined */
+ HDassert(fspace->sinfo);
+
+ /* start by allocating file space for the header */
+
+ /* Get the EOA for the file -- need for sanity check below */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_HDR)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa")
+
+ /* check for overlap into temporary allocation space */
+ if(H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "hdr file space alloc will overlap into 'temporary' file space")
+
+ hdr_alloc_size = H5FS_HEADER_SIZE(f);
+
+ /* if page allocation is enabled, extend the hdr_alloc_size to the
+ * next page boundary.
+ */
+ if(H5F_PAGED_AGGR(f)) {
+ HDassert(0 == (eoa % f->shared->fs_page_size));
+
+ hdr_alloc_size = ((hdr_alloc_size / f->shared->fs_page_size) + 1) * f->shared->fs_page_size;
+
+ HDassert(hdr_alloc_size >= H5FS_HEADER_SIZE(f));
+ HDassert((hdr_alloc_size % f->shared->fs_page_size) == 0);
+ } /* end if */
+
+ /* allocate space for the hdr */
+ if(HADDR_UNDEF == (fspace->addr = H5FD_alloc(f->shared->lf, dxpl_id,
+ H5FD_MEM_FSPACE_HDR, f,
+ hdr_alloc_size,
+ &eoa_frag_addr,
+ &eoa_frag_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTALLOC, FAIL, "can't allocate file space for hdr")
+
+ /* if the file alignement is 1, there should be no
+ * eoa fragment. Otherwise, drop any fragment on the floor.
+ */
+ HDassert((eoa_frag_size == 0) || (f->shared->alignment != 1));
+
+ /* Cache the new free space header (pinned) */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space header to cache")
+
+ *fs_addr_ptr = fspace->addr;
+
+ /* now allocate file space for the section info */
+
+ /* Get the EOA for the file -- need for sanity check below */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_FSPACE_SINFO)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "Unable to get eoa")
+
+ /* check for overlap into temporary allocation space */
+ if(H5F_IS_TMP_ADDR(f, (eoa + fspace->sect_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADRANGE, FAIL, "sinfo file space alloc will overlap into 'temporary' file space")
+
+ sinfo_alloc_size = fspace->sect_size;
+
+ /* if paged allocation is enabled, extend the sinfo_alloc_size to the
+ * next page boundary.
+ */
+ if(H5F_PAGED_AGGR(f)) {
+ HDassert(0 == (eoa % f->shared->fs_page_size));
+
+ sinfo_alloc_size = ((sinfo_alloc_size / f->shared->fs_page_size) + 1) * f->shared->fs_page_size;
+
+ HDassert(sinfo_alloc_size >= fspace->sect_size);
+ HDassert((sinfo_alloc_size % f->shared->fs_page_size) == 0);
+ } /* end if */
+
+ /* allocate space for the section info */
+ if(HADDR_UNDEF == (sect_addr = H5FD_alloc(f->shared->lf, dxpl_id,
+ H5FD_MEM_FSPACE_SINFO, f,
+ sinfo_alloc_size,
+ &eoa_frag_addr,
+ &eoa_frag_size)))
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTALLOC, FAIL, "can't allocate file space")
+
+ /* if the file alignement is 1, there should be no
+ * eoa fragment. Otherwise, drop the fragment on the floor.
+ */
+ HDassert((eoa_frag_size == 0) || (f->shared->alignment != 1));
+
+ /* update fspace->alloc_sect_size and fspace->sect_addr to reflect
+ * the allocation
+ */
+ fspace->alloc_sect_size = fspace->sect_size;
+ fspace->sect_addr = sect_addr;
+
+ /* insert the new section info into the metadata cache. */
+
+ /* Question: Do we need to worry about this insertion causing an
+ * eviction from the metadata cache? Think on this. If so, add a
+ * flag to H5AC_insert() to force it to skip the call to make space in
+ * cache.
+ *
+ * On reflection, no.
+ *
+ * On a regular file close, any eviction will not change the
+ * the contents of the free space manger(s), as all entries
+ * should have correct file space allocated by the time this
+ * function is called.
+ *
+ * In the cache image case, the selection of entries for inclusion
+ * in the cache image will not take place until after this call.
+ * (Recall that this call is made during the metadata fsm settle
+ * routine, which is called during the serialization routine in
+ * the cache image case. Entries are not selected for inclusion
+ * in the image until after the cache is serialized.)
+ *
+ * JRM -- 11/4/16
+ */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_SINFO, sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sinfo to cache")
+
+ /* We have changed the sinfo address -- Mark free space header dirty */
+ if(H5AC_mark_entry_dirty(fspace) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
+
+ /* since space has been allocated for the section info and the sinfo
+ * has been inserted into the cache, relinquish owership (i.e. float)
+ * the section info.
+ */
+ fspace->sinfo = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_vfd_alloc_hdr_and_section_info_if_needed() */
+
diff --git a/src/H5FSstat.c b/src/H5FSstat.c
new file mode 100644
index 0000000..e2ad5bb
--- /dev/null
+++ b/src/H5FSstat.c
@@ -0,0 +1,104 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Free-space metadata statistics functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FSpkg.h" /* Free-space manager */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_stat_info
+ *
+ * Purpose: Retrieve metadata statistics for the free-space manager
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Vailin Choi
+ * August 25th, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_stat_info(const H5F_t *f, const H5FS_t *frsp, H5FS_stat_t *stats)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(frsp);
+ HDassert(stats);
+
+ /* Report statistics for free space */
+ stats->tot_space = frsp->tot_space;
+ stats->tot_sect_count = frsp->tot_sect_count;
+ stats->serial_sect_count = frsp->serial_sect_count;
+ stats->ghost_sect_count = frsp->ghost_sect_count;
+ stats->addr = frsp->addr;
+ stats->hdr_size = (hsize_t)H5FS_HEADER_SIZE(f);
+ stats->sect_addr = frsp->sect_addr;
+ stats->alloc_sect_size = frsp->alloc_sect_size;
+ stats->sect_size = frsp->sect_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_stat_info() */
+
diff --git a/src/H5FStest.c b/src/H5FStest.c
new file mode 100644
index 0000000..5ab0219
--- /dev/null
+++ b/src/H5FStest.c
@@ -0,0 +1,155 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Free-space manager testing functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
+#define H5FS_TESTING /* Suppress warning about H5FS testing funcs */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FSpkg.h" /* Free-space manager */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_get_cparam_test
+ *
+ * Purpose: Retrieve the parameters used to create the free-space manager
+ * similar to H5HF_get_cparam_test()
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * August 25th, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FS_get_cparam_test(const H5FS_t *frsp, H5FS_create_t *cparam)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(frsp);
+ HDassert(cparam);
+
+ cparam->client = frsp->client;
+ cparam->shrink_percent = frsp->shrink_percent;
+ cparam->expand_percent = frsp->expand_percent;
+ cparam->max_sect_addr = frsp->max_sect_addr;
+ cparam->max_sect_size = frsp->max_sect_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5FS_get_cparam_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FS_cmp_cparam_test
+ *
+ * Purpose: Compare the parameters used to create the free space manager
+ * similar to H5HF_cmp_cparam_test()
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * August 25th, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5FS_cmp_cparam_test(const H5FS_create_t *cparam1, const H5FS_create_t *cparam2)
+{
+ int ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(cparam1);
+ HDassert(cparam2);
+
+ if(cparam1->client < cparam2->client)
+ HGOTO_DONE(-1)
+ else if(cparam1->client > cparam2->client)
+ HGOTO_DONE(1)
+
+ if(cparam1->shrink_percent < cparam2->shrink_percent)
+ HGOTO_DONE(-1)
+ else if(cparam1->shrink_percent > cparam2->shrink_percent)
+ HGOTO_DONE(1)
+
+ if(cparam1->expand_percent < cparam2->expand_percent)
+ HGOTO_DONE(-1)
+ else if(cparam1->expand_percent > cparam2->expand_percent)
+ HGOTO_DONE(1)
+
+ if(cparam1->max_sect_size < cparam2->max_sect_size)
+ HGOTO_DONE(-1)
+ else if(cparam1->max_sect_size > cparam2->max_sect_size)
+ HGOTO_DONE(1)
+
+ if(cparam1->max_sect_addr < cparam2->max_sect_addr)
+ HGOTO_DONE(-1)
+ else if(cparam1->max_sect_addr > cparam2->max_sect_addr)
+ HGOTO_DONE(1)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FS_cmp_cparam_test */
+
diff --git a/src/H5Faccum.c b/src/H5Faccum.c
new file mode 100644
index 0000000..e84cfda
--- /dev/null
+++ b/src/H5Faccum.c
@@ -0,0 +1,1108 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Faccum.c
+ * Jan 10 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File metadata "accumulator" routines. (Used to
+ * cache small metadata I/Os and group them into a
+ * single larger I/O)
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Metadata accumulator controls */
+#define H5F_ACCUM_THROTTLE 8
+#define H5F_ACCUM_THRESHOLD 2048
+#define H5F_ACCUM_MAX_SIZE (1024 *1024) /* Max. accum. buf size (max. I/Os will be 1/2 this size) */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Enumerated type to indicate how data will be added to accumulator */
+typedef enum {
+ H5F_ACCUM_PREPEND, /* Data will be prepended to accumulator */
+ H5F_ACCUM_APPEND /* Data will be appended to accumulator */
+} H5F_accum_adjust_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a PQ free list to manage the metadata accumulator buffer */
+H5FL_BLK_DEFINE_STATIC(meta_accum);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_read
+ *
+ * Purpose: Attempts to read some data from the metadata accumulator for
+ * a file into a buffer.
+ *
+ * Note: We can't change (or add to) the metadata accumulator, because
+ * this might be a speculative read and could possibly read raw
+ * data into the metadata accumulator.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 10 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__accum_read(const H5F_io_info2_t *fio_info, H5FD_mem_t map_type, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(fio_info->meta_dxpl);
+ HDassert(fio_info->raw_dxpl);
+ HDassert(buf);
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Check if this information is in the metadata accumulator */
+ if((fio_info->f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && map_type != H5FD_MEM_DRAW) {
+ H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */
+
+ /* Set up alias for file's metadata accumulator info */
+ accum = &fio_info->f->shared->accum;
+
+ if(size < H5F_ACCUM_MAX_SIZE) {
+ /* Sanity check */
+ HDassert(!accum->buf || (accum->alloc_size >= accum->size));
+
+ /* Current read adjoins or overlaps with metadata accumulator */
+ if(H5F_addr_overlap(addr, size, accum->loc, accum->size)
+ || ((addr + size) == accum->loc)
+ || (accum->loc + accum->size) == addr) {
+ size_t amount_before; /* Amount to read before current accumulator */
+ haddr_t new_addr; /* New address of the accumulator buffer */
+ size_t new_size; /* New size of the accumulator buffer */
+
+ /* Compute new values for accumulator */
+ new_addr = MIN(addr, accum->loc);
+ new_size = (size_t)(MAX((addr + size), (accum->loc + accum->size)) - new_addr);
+
+ /* Check if we need more buffer space */
+ if(new_size > accum->alloc_size) {
+ size_t new_alloc_size; /* New size of accumulator */
+
+ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */
+ new_alloc_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(new_size - 1)));
+
+ /* Reallocate the metadata accumulator buffer */
+ if(NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_alloc_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Note the new buffer size */
+ accum->alloc_size = new_alloc_size;
+
+ /* Clear the memory */
+ HDmemset(accum->buf + accum->size, 0, (accum->alloc_size - accum->size));
+ } /* end if */
+
+ /* Read the part before the metadata accumulator */
+ if(addr < accum->loc) {
+ /* Set the amount to read */
+ H5_CHECKED_ASSIGN(amount_before, size_t, (accum->loc - addr), hsize_t);
+
+ /* Make room for the metadata to read in */
+ HDmemmove(accum->buf + amount_before, accum->buf, accum->size);
+
+ /* Adjust dirty region tracking info, if present */
+ if(accum->dirty)
+ accum->dirty_off += amount_before;
+
+ /* Dispatch to driver */
+ if(H5FD_read(&fdio_info, map_type, addr, amount_before, accum->buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed")
+ } /* end if */
+ else
+ amount_before = 0;
+
+ /* Read the part after the metadata accumulator */
+ if((addr + size) > (accum->loc + accum->size)) {
+ size_t amount_after; /* Amount to read at a time */
+
+ /* Set the amount to read */
+ H5_CHECKED_ASSIGN(amount_after, size_t, ((addr + size) - (accum->loc + accum->size)), hsize_t);
+
+ /* Dispatch to driver */
+ if(H5FD_read(&fdio_info, map_type, (accum->loc + accum->size), amount_after, (accum->buf + accum->size + amount_before)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed")
+ } /* end if */
+
+ /* Copy the data out of the buffer */
+ HDmemcpy(buf, accum->buf + (addr - new_addr), size);
+
+ /* Adjust the accumulator address & size */
+ accum->loc = new_addr;
+ accum->size = new_size;
+ } /* end if */
+ /* Current read doesn't overlap with metadata accumulator, read it from file */
+ else {
+ /* Dispatch to driver */
+ if(H5FD_read(&fdio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Read the data */
+ if(H5FD_read(&fdio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed")
+
+ /* Check for overlap w/dirty accumulator */
+ /* (Note that this could be improved by updating the non-dirty
+ * information in the accumulator with [some of] the information
+ * just read in. -QAK)
+ */
+ if(accum->dirty &&
+ H5F_addr_overlap(addr, size, accum->loc + accum->dirty_off, accum->dirty_len)) {
+ haddr_t dirty_loc = accum->loc + accum->dirty_off; /* File offset of dirty information */
+ size_t buf_off; /* Offset of dirty region in buffer */
+ size_t dirty_off; /* Offset within dirty region */
+ size_t overlap_size; /* Size of overlap with dirty region */
+
+ /* Check for read starting before beginning dirty region */
+ if(H5F_addr_le(addr, dirty_loc)) {
+ /* Compute offset of dirty region within buffer */
+ buf_off = (size_t)(dirty_loc - addr);
+
+ /* Compute offset within dirty region */
+ dirty_off = 0;
+
+ /* Check for read ending within dirty region */
+ if(H5F_addr_lt(addr + size, dirty_loc + accum->dirty_len))
+ overlap_size = (size_t)((addr + size) - buf_off);
+ else /* Access covers whole dirty region */
+ overlap_size = accum->dirty_len;
+ } /* end if */
+ else { /* Read starts after beginning of dirty region */
+ /* Compute dirty offset within buffer and overlap size */
+ buf_off = 0;
+ dirty_off = (size_t)(addr - dirty_loc);
+ overlap_size = (size_t)((dirty_loc + accum->dirty_len) - addr);
+ } /* end else */
+
+ /* Copy the dirty region to buffer */
+ HDmemcpy((unsigned char *)buf + buf_off, (unsigned char *)accum->buf + accum->dirty_off + dirty_off, overlap_size);
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Read the data */
+ if(H5FD_read(&fdio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_adjust
+ *
+ * Purpose: Adjust accumulator size, if necessary
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 11 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__accum_adjust(H5F_meta_accum_t *accum, const H5FD_io_info_t *fdio_info,
+ H5F_accum_adjust_t adjust, size_t size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(accum);
+ HDassert(fdio_info);
+ HDassert(H5F_ACCUM_APPEND == adjust || H5F_ACCUM_PREPEND == adjust);
+ HDassert(size > 0);
+ HDassert(size <= H5F_ACCUM_MAX_SIZE);
+
+ /* Check if we need more buffer space */
+ if((size + accum->size) > accum->alloc_size) {
+ size_t new_size; /* New size of accumulator */
+
+ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */
+ new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)((size + accum->size) - 1)));
+
+ /* Check for accumulator getting too big */
+ if(new_size > H5F_ACCUM_MAX_SIZE) {
+ size_t shrink_size; /* Amount to shrink accumulator by */
+ size_t remnant_size; /* Amount left in accumulator */
+
+ /* Cap the accumulator's growth, leaving some room */
+
+ /* Determine the amounts to work with */
+ if(size > (H5F_ACCUM_MAX_SIZE / 2)) {
+ new_size = H5F_ACCUM_MAX_SIZE;
+ shrink_size = accum->size;
+ remnant_size = 0;
+ } /* end if */
+ else {
+ if(H5F_ACCUM_PREPEND == adjust) {
+ new_size = (H5F_ACCUM_MAX_SIZE / 2);
+ shrink_size = (H5F_ACCUM_MAX_SIZE / 2);
+ remnant_size = accum->size - shrink_size;
+ } /* end if */
+ else {
+ size_t adjust_size = size + accum->dirty_len;
+
+ /* Check if we can slide the dirty region down, to accommodate the request */
+ if(accum->dirty && (adjust_size <= H5F_ACCUM_MAX_SIZE)) {
+ if((ssize_t)(H5F_ACCUM_MAX_SIZE - (accum->dirty_off + adjust_size)) >= (ssize_t)(2 * size))
+ shrink_size = accum->dirty_off / 2;
+ else
+ shrink_size = accum->dirty_off;
+ remnant_size = accum->size - shrink_size;
+ new_size = remnant_size + size;
+ } /* end if */
+ else {
+ new_size = (H5F_ACCUM_MAX_SIZE / 2);
+ shrink_size = (H5F_ACCUM_MAX_SIZE / 2);
+ remnant_size = accum->size - shrink_size;
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+ /* Check if we need to flush accumulator data to file */
+ if(accum->dirty) {
+ /* Check whether to accumulator will be prepended or appended */
+ if(H5F_ACCUM_PREPEND == adjust) {
+ /* Check if the dirty region overlaps the region to eliminate from the accumulator */
+ if((accum->size - shrink_size) < (accum->dirty_off + accum->dirty_len)) {
+ /* Write out the dirty region from the metadata accumulator, with dispatch to driver */
+ if(H5FD_write(fdio_info, H5FD_MEM_DEFAULT, (accum->loc + accum->dirty_off), accum->dirty_len, (accum->buf + accum->dirty_off)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Reset accumulator dirty flag */
+ accum->dirty = FALSE;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Check if the dirty region overlaps the region to eliminate from the accumulator */
+ if(shrink_size > accum->dirty_off) {
+ /* Write out the dirty region from the metadata accumulator, with dispatch to driver */
+ if(H5FD_write(fdio_info, H5FD_MEM_DEFAULT, (accum->loc + accum->dirty_off), accum->dirty_len, (accum->buf + accum->dirty_off)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Reset accumulator dirty flag */
+ accum->dirty = FALSE;
+ } /* end if */
+
+ /* Adjust dirty region tracking info */
+ accum->dirty_off -= shrink_size;
+ } /* end else */
+ } /* end if */
+
+ /* Trim the accumulator's use of its buffer */
+ accum->size = remnant_size;
+
+ /* When appending, need to adjust location of accumulator */
+ if(H5F_ACCUM_APPEND == adjust) {
+ /* Move remnant of accumulator down */
+ HDmemmove(accum->buf, (accum->buf + shrink_size), remnant_size);
+
+ /* Adjust accumulator's location */
+ accum->loc += shrink_size;
+ } /* end if */
+ } /* end if */
+
+ /* Check for accumulator needing to be reallocated */
+ if(new_size > accum->alloc_size) {
+ unsigned char *new_buf; /* New buffer to hold the accumulated metadata */
+
+ /* Reallocate the metadata accumulator buffer */
+ if(NULL == (new_buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Update accumulator info */
+ accum->buf = new_buf;
+ accum->alloc_size = new_size;
+
+ /* Clear the memory */
+ HDmemset(accum->buf + accum->size, 0, (accum->alloc_size - (accum->size + size)));
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_adjust() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_write
+ *
+ * Purpose: Attempts to write some data to the metadata accumulator for
+ * a file from a buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 10 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__accum_write(const H5F_io_info2_t *fio_info, H5FD_mem_t map_type, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(H5F_INTENT(fio_info->f) & H5F_ACC_RDWR);
+ HDassert(fio_info->meta_dxpl);
+ HDassert(fio_info->raw_dxpl);
+ HDassert(buf);
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Check for accumulating metadata */
+ if((fio_info->f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && map_type != H5FD_MEM_DRAW) {
+ H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */
+
+ /* Set up alias for file's metadata accumulator info */
+ accum = &fio_info->f->shared->accum;
+
+ if(size < H5F_ACCUM_MAX_SIZE) {
+ /* Sanity check */
+ HDassert(!accum->buf || (accum->alloc_size >= accum->size));
+
+ /* Check if there is already metadata in the accumulator */
+ if(accum->size > 0) {
+ /* Check if the new metadata adjoins the beginning of the current accumulator */
+ if((addr + size) == accum->loc) {
+ /* Check if we need to adjust accumulator size */
+ if(H5F__accum_adjust(accum, &fdio_info, H5F_ACCUM_PREPEND, size) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator")
+
+ /* Move the existing metadata to the proper location */
+ HDmemmove(accum->buf + size, accum->buf, accum->size);
+
+ /* Copy the new metadata at the front */
+ HDmemcpy(accum->buf, buf, size);
+
+ /* Set the new size & location of the metadata accumulator */
+ accum->loc = addr;
+ accum->size += size;
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ if(accum->dirty)
+ accum->dirty_len = size + accum->dirty_off + accum->dirty_len;
+ else {
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ accum->dirty_off = 0;
+ } /* end if */
+ /* Check if the new metadata adjoins the end of the current accumulator */
+ else if(addr == (accum->loc + accum->size)) {
+ /* Check if we need to adjust accumulator size */
+ if(H5F__accum_adjust(accum, &fdio_info, H5F_ACCUM_APPEND, size) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator")
+
+ /* Copy the new metadata to the end */
+ HDmemcpy(accum->buf + accum->size, buf, size);
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ if(accum->dirty)
+ accum->dirty_len = size + (accum->size - accum->dirty_off);
+ else {
+ accum->dirty_off = accum->size;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+
+ /* Set the new size of the metadata accumulator */
+ accum->size += size;
+ } /* end if */
+ /* Check if the piece of metadata being written overlaps the metadata accumulator */
+ else if(H5F_addr_overlap(addr, size, accum->loc, accum->size)) {
+ size_t add_size; /* New size of the accumulator buffer */
+
+ /* Check if the new metadata is entirely within the current accumulator */
+ if(addr >= accum->loc && (addr + size) <= (accum->loc + accum->size)) {
+ size_t dirty_off = (size_t)(addr - accum->loc);
+
+ /* Copy the new metadata to the proper location within the accumulator */
+ HDmemcpy(accum->buf + dirty_off, buf, size);
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ if(accum->dirty) {
+ /* Check for new metadata starting before current dirty region */
+ if(dirty_off <= accum->dirty_off) {
+ if((dirty_off + size) <= (accum->dirty_off + accum->dirty_len))
+ accum->dirty_len = (accum->dirty_off + accum->dirty_len) - dirty_off;
+ else
+ accum->dirty_len = size;
+ accum->dirty_off = dirty_off;
+ } /* end if */
+ else {
+ if((dirty_off + size) <= (accum->dirty_off + accum->dirty_len))
+ ; /* accum->dirty_len doesn't change */
+ else
+ accum->dirty_len = (dirty_off + size) - accum->dirty_off;
+ } /* end else */
+ } /* end if */
+ else {
+ accum->dirty_off = dirty_off;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ /* Check if the new metadata overlaps the beginning of the current accumulator */
+ else if(addr < accum->loc && (addr + size) <= (accum->loc + accum->size)) {
+ size_t old_offset; /* Offset of old data within the accumulator buffer */
+
+ /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */
+ H5_CHECKED_ASSIGN(add_size, size_t, (accum->loc - addr), hsize_t);
+
+ /* Check if we need to adjust accumulator size */
+ if(H5F__accum_adjust(accum, &fdio_info, H5F_ACCUM_PREPEND, add_size) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator")
+
+ /* Calculate the proper offset of the existing metadata */
+ H5_CHECKED_ASSIGN(old_offset, size_t, (addr + size) - accum->loc, hsize_t);
+
+ /* Move the existing metadata to the proper location */
+ HDmemmove(accum->buf + size, accum->buf + old_offset, (accum->size - old_offset));
+
+ /* Copy the new metadata at the front */
+ HDmemcpy(accum->buf, buf, size);
+
+ /* Set the new size & location of the metadata accumulator */
+ accum->loc = addr;
+ accum->size += add_size;
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ if(accum->dirty) {
+ size_t curr_dirty_end = add_size + accum->dirty_off + accum->dirty_len;
+
+ accum->dirty_off = 0;
+ if(size <= curr_dirty_end)
+ accum->dirty_len = curr_dirty_end;
+ else
+ accum->dirty_len = size;
+ } /* end if */
+ else {
+ accum->dirty_off = 0;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ /* Check if the new metadata overlaps the end of the current accumulator */
+ else if(addr >= accum->loc && (addr + size) > (accum->loc + accum->size)) {
+ size_t dirty_off; /* Offset of dirty region */
+
+ /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */
+ H5_CHECKED_ASSIGN(add_size, size_t, (addr + size) - (accum->loc + accum->size), hsize_t);
+
+ /* Check if we need to adjust accumulator size */
+ if(H5F__accum_adjust(accum, &fdio_info, H5F_ACCUM_APPEND, add_size) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator")
+
+ /* Compute offset of dirty region (after adjusting accumulator) */
+ dirty_off = (size_t)(addr - accum->loc);
+
+ /* Copy the new metadata to the end */
+ HDmemcpy(accum->buf + dirty_off, buf, size);
+
+ /* Set the new size of the metadata accumulator */
+ accum->size += add_size;
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ if(accum->dirty) {
+ /* Check for new metadata starting before current dirty region */
+ if(dirty_off <= accum->dirty_off) {
+ accum->dirty_off = dirty_off;
+ accum->dirty_len = size;
+ } /* end if */
+ else {
+ accum->dirty_len = (dirty_off + size) - accum->dirty_off;
+ } /* end else */
+ } /* end if */
+ else {
+ accum->dirty_off = dirty_off;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ /* New metadata overlaps both ends of the current accumulator */
+ else {
+ /* Check if we need more buffer space */
+ if(size > accum->alloc_size) {
+ size_t new_alloc_size; /* New size of accumulator */
+
+ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */
+ new_alloc_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1)));
+
+ /* Reallocate the metadata accumulator buffer */
+ if(NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_alloc_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Note the new buffer size */
+ accum->alloc_size = new_alloc_size;
+
+ /* Clear the memory */
+ HDmemset(accum->buf + size, 0, (accum->alloc_size - size));
+ } /* end if */
+
+ /* Copy the new metadata to the buffer */
+ HDmemcpy(accum->buf, buf, size);
+
+ /* Set the new size & location of the metadata accumulator */
+ accum->loc = addr;
+ accum->size = size;
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ accum->dirty_off = 0;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ /* New piece of metadata doesn't adjoin or overlap the existing accumulator */
+ else {
+ /* Write out the existing metadata accumulator, with dispatch to driver */
+ if(accum->dirty) {
+ if(H5FD_write(&fdio_info, H5FD_MEM_DEFAULT, accum->loc + accum->dirty_off, accum->dirty_len, accum->buf + accum->dirty_off) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Reset accumulator dirty flag */
+ accum->dirty = FALSE;
+ } /* end if */
+
+ /* Cache the new piece of metadata */
+ /* Check if we need to resize the buffer */
+ if(size > accum->alloc_size) {
+ size_t new_size; /* New size of accumulator */
+ size_t clear_size; /* Size of memory that needs clearing */
+
+ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */
+ new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1)));
+
+ /* Grow the metadata accumulator buffer */
+ if(NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Note the new buffer size */
+ accum->alloc_size = new_size;
+
+ /* Clear the memory */
+ clear_size = MAX(accum->size, size);
+ HDmemset(accum->buf + clear_size, 0, (accum->alloc_size - clear_size));
+ } /* end if */
+ else {
+ /* Check if we should shrink the accumulator buffer */
+ if(size < (accum->alloc_size / H5F_ACCUM_THROTTLE) &&
+ accum->alloc_size > H5F_ACCUM_THRESHOLD) {
+ size_t tmp_size = (accum->alloc_size / H5F_ACCUM_THROTTLE); /* New size of accumulator buffer */
+
+ /* Shrink the accumulator buffer */
+ if(NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, tmp_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Note the new buffer size */
+ accum->alloc_size = tmp_size;
+ } /* end if */
+ } /* end else */
+
+ /* Update the metadata accumulator information */
+ accum->loc = addr;
+ accum->size = size;
+
+ /* Store the piece of metadata in the accumulator */
+ HDmemcpy(accum->buf, buf, size);
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ accum->dirty_off = 0;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ /* No metadata in the accumulator, grab this piece and keep it */
+ else {
+ /* Check if we need to reallocate the buffer */
+ if(size > accum->alloc_size) {
+ size_t new_size; /* New size of accumulator */
+
+ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */
+ new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1)));
+
+ /* Reallocate the metadata accumulator buffer */
+ if(NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer")
+
+ /* Note the new buffer size */
+ accum->alloc_size = new_size;
+
+ /* Clear the memory */
+ HDmemset(accum->buf + size, 0, (accum->alloc_size - size));
+ } /* end if */
+
+ /* Update the metadata accumulator information */
+ accum->loc = addr;
+ accum->size = size;
+
+ /* Store the piece of metadata in the accumulator */
+ HDmemcpy(accum->buf, buf, size);
+
+ /* Adjust the dirty region and mark accumulator dirty */
+ accum->dirty_off = 0;
+ accum->dirty_len = size;
+ accum->dirty = TRUE;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Make certain that data in accumulator is visible before new write */
+ if((H5F_INTENT(fio_info->f) & H5F_ACC_SWMR_WRITE) > 0)
+ /* Flush if dirty and reset accumulator */
+ if(H5F__accum_reset(fio_info, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+
+ /* Write the data */
+ if(H5FD_write(&fdio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Check for overlap w/accumulator */
+ /* (Note that this could be improved by updating the accumulator
+ * with [some of] the information just read in. -QAK)
+ */
+ if(H5F_addr_overlap(addr, size, accum->loc, accum->size)) {
+ /* Check for write starting before beginning of accumulator */
+ if(H5F_addr_le(addr, accum->loc)) {
+ /* Check for write ending within accumulator */
+ if(H5F_addr_le(addr + size, accum->loc + accum->size)) {
+ size_t overlap_size; /* Size of overlapping region */
+
+ /* Compute overlap size */
+ overlap_size = (size_t)((addr + size) - accum->loc);
+
+ /* Check for dirty region */
+ if(accum->dirty) {
+ haddr_t dirty_start = accum->loc + accum->dirty_off; /* File address of start of dirty region */
+ haddr_t dirty_end = dirty_start + accum->dirty_len; /* File address of end of dirty region */
+
+ /* Check if entire dirty region is overwritten */
+ if(H5F_addr_le(dirty_end, addr + size)) {
+ accum->dirty = FALSE;
+ accum->dirty_len = 0;
+ } /* end if */
+ else {
+ /* Check for dirty region falling after write */
+ if(H5F_addr_le(addr + size, dirty_start))
+ accum->dirty_off = overlap_size;
+ else { /* Dirty region overlaps w/written region */
+ accum->dirty_off = 0;
+ accum->dirty_len -= (size_t)((addr + size) - dirty_start);
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ /* Trim bottom of accumulator off */
+ accum->loc += overlap_size;
+ accum->size -= overlap_size;
+ HDmemmove(accum->buf, accum->buf + overlap_size, accum->size);
+ } /* end if */
+ else { /* Access covers whole accumulator */
+ /* Reset accumulator, but don't flush */
+ if(H5F__accum_reset(fio_info, FALSE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+ } /* end else */
+ } /* end if */
+ else { /* Write starts after beginning of accumulator */
+ size_t overlap_size; /* Size of overlapping region */
+
+ /* Sanity check */
+ HDassert(H5F_addr_gt(addr + size, accum->loc + accum->size));
+
+ /* Compute overlap size */
+ overlap_size = (size_t)((accum->loc + accum->size) - addr);
+
+ /* Check for dirty region */
+ if(accum->dirty) {
+ haddr_t dirty_start = accum->loc + accum->dirty_off; /* File address of start of dirty region */
+ haddr_t dirty_end = dirty_start + accum->dirty_len; /* File address of end of dirty region */
+
+ /* Check if entire dirty region is overwritten */
+ if(H5F_addr_ge(dirty_start, addr)) {
+ accum->dirty = FALSE;
+ accum->dirty_len = 0;
+ } /* end if */
+ else {
+ /* Check for dirty region falling before write */
+ if(H5F_addr_le(dirty_end, addr))
+ ; /* noop */
+ else /* Dirty region overlaps w/written region */
+ accum->dirty_len = (size_t)(addr - dirty_start);
+ } /* end if */
+ } /* end if */
+
+ /* Trim top of accumulator off */
+ accum->size -= overlap_size;
+ } /* end else */
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Write the data */
+ if(H5FD_write(&fdio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_free
+ *
+ * Purpose: Check for free space invalidating [part of] a metadata
+ * accumulator.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 10 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__accum_free(const H5F_io_info2_t *fio_info, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr,
+ hsize_t size)
+{
+ H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(fio_info->meta_dxpl);
+ HDassert(fio_info->raw_dxpl);
+
+ /* Set up alias for file's metadata accumulator info */
+ accum = &fio_info->f->shared->accum;
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Adjust the metadata accumulator to remove the freed block, if it overlaps */
+ if((fio_info->f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA)
+ && H5F_addr_overlap(addr, size, accum->loc, accum->size)) {
+ size_t overlap_size; /* Size of overlap with accumulator */
+
+ /* Sanity check */
+ /* (The metadata accumulator should not intersect w/raw data */
+ HDassert(H5FD_MEM_DRAW != type);
+ HDassert(H5FD_MEM_GHEAP != type); /* (global heap data is being treated as raw data currently) */
+
+ /* Check for overlapping the beginning of the accumulator */
+ if(H5F_addr_le(addr, accum->loc)) {
+ /* Check for completely overlapping the accumulator */
+ if(H5F_addr_ge(addr + size, accum->loc + accum->size)) {
+ /* Reset the accumulator, but don't free buffer */
+ accum->loc = HADDR_UNDEF;
+ accum->size = 0;
+ accum->dirty = FALSE;
+ } /* end if */
+ /* Block to free must end within the accumulator */
+ else {
+ size_t new_accum_size; /* Size of new accumulator buffer */
+
+ /* Calculate the size of the overlap with the accumulator, etc. */
+ H5_CHECKED_ASSIGN(overlap_size, size_t, (addr + size) - accum->loc, haddr_t);
+ new_accum_size = accum->size - overlap_size;
+
+ /* Move the accumulator buffer information to eliminate the freed block */
+ HDmemmove(accum->buf, accum->buf + overlap_size, new_accum_size);
+
+ /* Adjust the accumulator information */
+ accum->loc += overlap_size;
+ accum->size = new_accum_size;
+
+ /* Adjust the dirty region and possibly mark accumulator clean */
+ if(accum->dirty) {
+ /* Check if block freed is entirely before dirty region */
+ if(overlap_size < accum->dirty_off)
+ accum->dirty_off -= overlap_size;
+ else {
+ /* Check if block freed ends within dirty region */
+ if(overlap_size < (accum->dirty_off + accum->dirty_len)) {
+ accum->dirty_len = (accum->dirty_off + accum->dirty_len) - overlap_size;
+ accum->dirty_off = 0;
+ } /* end if */
+ /* Block freed encompasses dirty region */
+ else
+ accum->dirty = FALSE;
+ } /* end else */
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ /* Block to free must start within the accumulator */
+ else {
+ haddr_t dirty_end = accum->loc + accum->dirty_off + accum->dirty_len;
+ haddr_t dirty_start = accum->loc + accum->dirty_off;
+
+ /* Calculate the size of the overlap with the accumulator */
+ H5_CHECKED_ASSIGN(overlap_size, size_t, (accum->loc + accum->size) - addr, haddr_t);
+
+ /* Check if block to free begins before end of dirty region */
+ if(accum->dirty && H5F_addr_lt(addr, dirty_end)) {
+ haddr_t tail_addr;
+
+ /* Calculate the address of the tail to write */
+ tail_addr = addr + size;
+
+ /* Check if the block to free begins before dirty region */
+ if(H5F_addr_lt(addr, dirty_start)) {
+ /* Check if block to free is entirely before dirty region */
+ if(H5F_addr_le(tail_addr, dirty_start)) {
+ /* Write out the entire dirty region of the accumulator */
+ if(H5FD_write(&fdio_info, H5FD_MEM_DEFAULT, dirty_start, accum->dirty_len, accum->buf + accum->dirty_off) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+ } /* end if */
+ /* Block to free overlaps with some/all of dirty region */
+ /* Check for unfreed dirty region to write */
+ else if(H5F_addr_lt(tail_addr, dirty_end)) {
+ size_t write_size;
+ size_t dirty_delta;
+
+ write_size = (size_t)(dirty_end - tail_addr);
+ dirty_delta = accum->dirty_len - write_size;
+
+ HDassert(write_size > 0);
+
+ /* Write out the unfreed dirty region of the accumulator */
+ if(H5FD_write(&fdio_info, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, accum->buf + accum->dirty_off + dirty_delta) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+ } /* end if */
+
+ /* Reset dirty flag */
+ accum->dirty = FALSE;
+ } /* end if */
+ /* Block to free begins at beginning of or in middle of dirty region */
+ else {
+ /* Check if block to free ends before end of dirty region */
+ if(H5F_addr_lt(tail_addr, dirty_end)) {
+ size_t write_size;
+ size_t dirty_delta;
+
+ write_size = (size_t)(dirty_end - tail_addr);
+ dirty_delta = accum->dirty_len - write_size;
+
+ HDassert(write_size > 0);
+
+ /* Write out the unfreed end of the dirty region of the accumulator */
+ if(H5FD_write(&fdio_info, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, accum->buf + accum->dirty_off + dirty_delta) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+ } /* end if */
+
+ /* Check for block to free beginning at same location as dirty region */
+ if(H5F_addr_eq(addr, dirty_start)) {
+ /* Reset dirty flag */
+ accum->dirty = FALSE;
+ } /* end if */
+ /* Block to free eliminates end of dirty region */
+ else {
+ accum->dirty_len = (size_t)(addr - dirty_start);
+ } /* end else */
+ } /* end else */
+
+ } /* end if */
+
+ /* Adjust the accumulator information */
+ accum->size = accum->size - overlap_size;
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_flush
+ *
+ * Purpose: Flush the metadata accumulator to the file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 10 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__accum_flush(const H5F_io_info2_t *fio_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(fio_info->meta_dxpl);
+ HDassert(fio_info->raw_dxpl);
+
+ /* Check if we need to flush out the metadata accumulator */
+ if((fio_info->f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && fio_info->f->shared->accum.dirty) {
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Flush the metadata contents */
+ if(H5FD_write(&fdio_info, H5FD_MEM_DEFAULT, fio_info->f->shared->accum.loc + fio_info->f->shared->accum.dirty_off, fio_info->f->shared->accum.dirty_len, fio_info->f->shared->accum.buf + fio_info->f->shared->accum.dirty_off) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Reset the dirty flag */
+ fio_info->f->shared->accum.dirty = FALSE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__accum_reset
+ *
+ * Purpose: Reset the metadata accumulator for the file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 10 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__accum_reset(const H5F_io_info2_t *fio_info, hbool_t flush)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+
+ /* Flush any dirty data in accumulator, if requested */
+ if(flush)
+ if(H5F__accum_flush(fio_info) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "can't flush metadata accumulator")
+
+ /* Check if we need to reset the metadata accumulator information */
+ if(fio_info->f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) {
+ /* Sanity check */
+ HDassert(!fio_info->f->closing || FALSE == fio_info->f->shared->accum.dirty);
+
+ /* Free the buffer */
+ if(fio_info->f->shared->accum.buf)
+ fio_info->f->shared->accum.buf = H5FL_BLK_FREE(meta_accum, fio_info->f->shared->accum.buf);
+
+ /* Reset the buffer sizes & location */
+ fio_info->f->shared->accum.alloc_size = fio_info->f->shared->accum.size = 0;
+ fio_info->f->shared->accum.loc = HADDR_UNDEF;
+ fio_info->f->shared->accum.dirty = FALSE;
+ fio_info->f->shared->accum.dirty_len = 0;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__accum_reset() */
+
diff --git a/src/H5Fcwfs.c b/src/H5Fcwfs.c
new file mode 100644
index 0000000..04b86d2
--- /dev/null
+++ b/src/H5Fcwfs.c
@@ -0,0 +1,325 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, July 19, 2011
+ *
+ * Purpose: Each file has a small cache of global heap collections called
+ * the CWFS list and recently accessed collections with free
+ * space appear on this list. As collections are accessed the
+ * collection is moved toward the front of the list. New
+ * collections are added to the front of the list while old
+ * collections are added to the end of the list.
+ *
+ * The collection model reduces the overhead which would be
+ * incurred if the global heap were a single object, and the
+ * CWFS list allows the library to cheaply choose a collection
+ * for a new object based on object size, amount of free space
+ * in the collection, and temporal locality.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5HGprivate.h" /* Global heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/*
+ * Maximum length of the CWFS list, the list of remembered collections that
+ * have free space.
+ */
+#define H5F_NCWFS 16
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_cwfs_add
+ *
+ * Purpose: Add a global heap collection to the CWFS for a file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 19, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_cwfs_add(H5F_t *f, H5HG_heap_t *heap)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(heap);
+
+ /*
+ * Add the new heap to the CWFS list, removing some other entry if
+ * necessary to make room. We remove the right-most entry that has less
+ * free space than this heap.
+ */
+ if(NULL == f->shared->cwfs) {
+ if(NULL == (f->shared->cwfs = (H5HG_heap_t **)H5MM_malloc(H5F_NCWFS * sizeof(H5HG_heap_t *))))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate CWFS for file")
+ f->shared->cwfs[0] = heap;
+ f->shared->ncwfs = 1;
+ } else if(H5F_NCWFS == f->shared->ncwfs) {
+ int i; /* Local index variable */
+
+ for(i = H5F_NCWFS - 1; i >= 0; --i)
+ if(H5HG_FREE_SIZE(f->shared->cwfs[i]) < H5HG_FREE_SIZE(heap)) {
+ HDmemmove(f->shared->cwfs + 1, f->shared->cwfs, (size_t)i * sizeof(H5HG_heap_t *));
+ f->shared->cwfs[0] = heap;
+ break;
+ } /* end if */
+ } else {
+ HDmemmove(f->shared->cwfs + 1, f->shared->cwfs, f->shared->ncwfs * sizeof(H5HG_heap_t *));
+ f->shared->cwfs[0] = heap;
+ f->shared->ncwfs += 1;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_cwfs_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_cwfs_find_free_heap
+ *
+ * Purpose: Find a global heap collection with free space for storing
+ * a new object.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_cwfs_find_free_heap(H5F_t *f, hid_t dxpl_id, size_t need, haddr_t *addr)
+{
+ unsigned cwfsno; /* Local index for iterating over collections */
+ hbool_t found = FALSE; /* Flag to indicate a heap with enough space was found */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(addr);
+
+ /* Note that we don't have metadata cache locks on the entries in
+ * f->shared->cwfs.
+ *
+ * In the current situation, this doesn't matter, as we are single
+ * threaded, and as best I can tell, entries are added to and deleted
+ * from f->shared->cwfs as they are added to and deleted from the
+ * metadata cache.
+ *
+ * To be proper, we should either lock each entry in f->shared->cwfs
+ * as we examine it, or lock the whole array. However, at present
+ * I don't see the point as there will be significant overhead,
+ * and protecting and unprotecting all the collections in the global
+ * heap on a regular basis will skew the replacement policy.
+ *
+ * JRM - 5/24/04
+ */
+ for(cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++)
+ if(H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]) >= need) {
+ *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]);
+ found = TRUE;
+ break;
+ } /* end if */
+
+ /*
+ * If we didn't find any collection with enough free space the check if
+ * we can extend any of the collections to make enough room.
+ */
+ if(!found) {
+ size_t new_need;
+
+ for(cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++) {
+ new_need = need;
+ new_need -= H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]);
+ new_need = MAX(H5HG_SIZE(f->shared->cwfs[cwfsno]), new_need);
+
+ if((H5HG_SIZE(f->shared->cwfs[cwfsno]) + new_need) <= H5HG_MAXSIZE) {
+ htri_t was_extended; /* Whether the heap was extended */
+
+ was_extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_GHEAP, H5HG_ADDR(f->shared->cwfs[cwfsno]), (hsize_t)H5HG_SIZE(f->shared->cwfs[cwfsno]), (hsize_t)new_need);
+ if(was_extended < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "error trying to extend heap")
+ else if(was_extended == TRUE) {
+ if(H5HG_extend(f, dxpl_id, H5HG_ADDR(f->shared->cwfs[cwfsno]), new_need) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to extend global heap collection")
+ *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]);
+ found = TRUE;
+ break;
+ } /* end if */
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ if(found) {
+ /* Move the collection forward in the CWFS list, if it's not
+ * already at the front
+ */
+ if(cwfsno > 0) {
+ H5HG_heap_t *tmp = f->shared->cwfs[cwfsno];
+
+ f->shared->cwfs[cwfsno] = f->shared->cwfs[cwfsno - 1];
+ f->shared->cwfs[cwfsno - 1] = tmp;
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_cwfs_find_free_heap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_cwfs_advance_heap
+ *
+ * Purpose: Advance a heap in the CWFS
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_cwfs_advance_heap(H5F_t *f, H5HG_heap_t *heap, hbool_t add_heap)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(heap);
+
+ for(u = 0; u < f->shared->ncwfs; u++)
+ if(f->shared->cwfs[u] == heap) {
+ if(u) {
+ f->shared->cwfs[u] = f->shared->cwfs[u - 1];
+ f->shared->cwfs[u - 1] = heap;
+ } /* end if */
+ break;
+ } /* end if */
+ if(add_heap && u >= f->shared->ncwfs) {
+ f->shared->ncwfs = MIN(f->shared->ncwfs + 1, H5F_NCWFS);
+ f->shared->cwfs[f->shared->ncwfs - 1] = heap;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_cwfs_advance_heap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_cwfs_remove_heap
+ *
+ * Purpose: Remove a heap from the CWFS
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_cwfs_remove_heap(H5F_file_t *shared, H5HG_heap_t *heap)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(shared);
+ HDassert(heap);
+
+ /* Remove the heap from the CWFS list */
+ for(u = 0; u < shared->ncwfs; u++) {
+ if(shared->cwfs[u] == heap) {
+ shared->ncwfs -= 1;
+ HDmemmove(shared->cwfs + u, shared->cwfs + u + 1, (shared->ncwfs - u) * sizeof(H5HG_heap_t *));
+ break;
+ } /* end if */
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_cwfs_remove_heap() */
+
diff --git a/src/H5Fdbg.c b/src/H5Fdbg.c
new file mode 100644
index 0000000..535b43d
--- /dev/null
+++ b/src/H5Fdbg.c
@@ -0,0 +1,148 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Wednesday, July 9, 2003
+ *
+ * Purpose: File object debugging functions.
+ */
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* ID Functions */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_debug
+ *
+ * Purpose: Prints a file header to the specified stream. Each line
+ * is indented and the field name occupies the specified width
+ * number of characters.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 1 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_debug(H5F_t *f, FILE *stream, int indent, int fwidth)
+{
+ H5P_genplist_t *plist; /* File creation property list */
+ hsize_t userblock_size; /* Userblock size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Get property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Retrieve file creation properties */
+ if(H5P_get(plist, H5F_CRT_USER_BLOCK_NAME, &userblock_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get userblock size")
+
+ /* debug */
+ HDfprintf(stream, "%*sFile Super Block...\n", indent, "");
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "File name (as opened):", H5F_OPEN_NAME(f));
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "File name (after resolving symlinks):", H5F_ACTUAL_NAME(f));
+ HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth,
+ "File access flags", f->shared->flags);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "File open reference count:", f->shared->nrefs);
+ HDfprintf(stream, "%*s%-*s %a (abs)\n", indent, "", fwidth,
+ "Address of super block:", f->shared->sblock->base_addr);
+ HDfprintf(stream, "%*s%-*s %Hu bytes\n", indent, "", fwidth,
+ "Size of userblock:", userblock_size);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Superblock version number:", f->shared->sblock->super_vers);
+
+ /* Hard-wired versions */
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Free list version number:", (unsigned)HDF5_FREESPACE_VERSION);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Root group symbol table entry version number:", (unsigned)HDF5_OBJECTDIR_VERSION);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Shared header version number:", (unsigned)HDF5_SHAREDHEADER_VERSION);
+
+ HDfprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth,
+ "Size of file offsets (haddr_t type):", (unsigned) f->shared->sizeof_addr);
+ HDfprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth,
+ "Size of file lengths (hsize_t type):", (unsigned) f->shared->sizeof_size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Symbol table leaf node 1/2 rank:", f->shared->sblock->sym_leaf_k);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Symbol table internal node 1/2 rank:", f->shared->sblock->btree_k[H5B_SNODE_ID]);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Indexed storage internal node 1/2 rank:", f->shared->sblock->btree_k[H5B_CHUNK_ID]);
+ HDfprintf(stream, "%*s%-*s 0x%02x\n", indent, "", fwidth,
+ "File status flags:", (unsigned)(f->shared->sblock->status_flags));
+ HDfprintf(stream, "%*s%-*s %a (rel)\n", indent, "", fwidth,
+ "Superblock extension address:", f->shared->sblock->ext_addr);
+ HDfprintf(stream, "%*s%-*s %a (rel)\n", indent, "", fwidth,
+ "Shared object header message table address:", f->shared->sohm_addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Shared object header message version number:", (unsigned) f->shared->sohm_vers);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of shared object header message indexes:", (unsigned) f->shared->sohm_nindexes);
+
+ HDfprintf(stream, "%*s%-*s %a (rel)\n", indent, "", fwidth,
+ "Address of driver information block:", f->shared->sblock->driver_addr);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Root group symbol table entry:",
+ f->shared->root_grp ? "" : "(none)");
+ if(f->shared->root_grp) {
+ if(f->shared->sblock->root_ent) /* Use real root group symbol table entry */
+ H5G__ent_debug(f->shared->sblock->root_ent, stream, indent + 3, MAX(0, fwidth - 3), NULL);
+ else {
+ H5O_loc_t *root_oloc; /* Root object location */
+ H5G_entry_t root_ent; /* Constructed root symbol table entry */
+
+ /* Reset the root group entry */
+ H5G__ent_reset(&root_ent);
+
+ /* Build up a simulated root group symbol table entry */
+ root_oloc = H5G_oloc(f->shared->root_grp);
+ HDassert(root_oloc);
+ root_ent.type = H5G_NOTHING_CACHED;
+ root_ent.header = root_oloc->addr;
+
+ /* Display root group symbol table entry info */
+ H5G__ent_debug(&root_ent, stream, indent + 3, MAX(0, fwidth - 3), NULL);
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_debug() */
+
diff --git a/src/H5Fdeprec.c b/src/H5Fdeprec.c
new file mode 100644
index 0000000..03f5df8
--- /dev/null
+++ b/src/H5Fdeprec.c
@@ -0,0 +1,147 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fdeprec.c
+ * October 1 2009
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5F interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Iprivate.h" /* IDs */
+#include "H5SMprivate.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_info1
+ *
+ * Purpose: Gets general information about the file, including:
+ * 1. Get storage size for superblock extension if there is one.
+ * 2. Get the amount of btree and heap storage for entries
+ * in the SOHM table if there is one.
+ * 3. The amount of free space tracked in the file.
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * July 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_info1(hid_t obj_id, H5F_info1_t *finfo)
+{
+ H5F_t *f; /* Top file in mount hierarchy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", obj_id, finfo);
+
+ /* Check args */
+ if(!finfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* For file IDs, get the file object directly */
+ /* (This prevents the H5G_loc() call from returning the file pointer for
+ * the top file in a mount hierarchy)
+ */
+ if(H5I_get_type(obj_id) == H5I_FILE ) {
+ if(NULL == (f = (H5F_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ } /* end if */
+ else {
+ H5G_loc_t loc; /* Object location */
+
+ /* Get symbol table entry */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID")
+ f = loc.oloc->file;
+ } /* end else */
+ HDassert(f->shared);
+
+ /* Reset file info struct */
+ HDmemset(finfo, 0, sizeof(*finfo));
+
+ /* Get the size of the superblock extension */
+ if(H5F__super_size(f, H5AC_ind_read_dxpl_id, NULL, &finfo->super_ext_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "Unable to retrieve superblock extension size")
+
+ /* Check for SOHM info */
+ if(H5F_addr_defined(f->shared->sohm_addr))
+ if(H5SM_ih_size(f, H5AC_ind_read_dxpl_id, &finfo->sohm.hdr_size, &finfo->sohm.msgs_info) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "Unable to retrieve SOHM index & heap storage info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fget_info1() */
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Fefc.c b/src/H5Fefc.c
new file mode 100644
index 0000000..5652d15
--- /dev/null
+++ b/src/H5Fefc.c
@@ -0,0 +1,945 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Defc.c
+ * December 13, 2010
+ * Neil Fortner <nfortne2@hdfgroup.org>
+ *
+ * Purpose: External file caching routines - implements a
+ * cache of external files to minimize the number of
+ * file opens and closes.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/* Special values for the "tag" field below */
+#define H5F_EFC_TAG_DEFAULT -1
+#define H5F_EFC_TAG_LOCK -2
+#define H5F_EFC_TAG_CLOSE -3
+#define H5F_EFC_TAG_DONTCLOSE -4
+
+/* Structure for each entry in a file's external file cache */
+typedef struct H5F_efc_ent_t {
+ char *name; /* Name of the file */
+ H5F_t *file; /* File object */
+ struct H5F_efc_ent_t *LRU_next; /* Next item in LRU list */
+ struct H5F_efc_ent_t *LRU_prev; /* Previous item in LRU list */
+ unsigned nopen; /* Number of times this file is currently opened by an EFC client */
+} H5F_efc_ent_t;
+
+/* Structure for a shared file struct's external file cache */
+struct H5F_efc_t {
+ H5SL_t *slist; /* Skip list of cached external files */
+ H5F_efc_ent_t *LRU_head; /* Head of LRU list. This is the least recently used file */
+ H5F_efc_ent_t *LRU_tail; /* Tail of LRU list. This is the most recently used file */
+ unsigned nfiles; /* Size of the external file cache */
+ unsigned max_nfiles; /* Maximum size of the external file cache */
+ unsigned nrefs; /* Number of times this file appears in another file's EFC */
+ int tag; /* Temporary variable used by H5F_efc_try_close() */
+ H5F_file_t *tmp_next; /* Next file in temporary list used by H5F_efc_try_close() */
+};
+
+/* Private prototypes */
+static herr_t H5F_efc_remove_ent(H5F_efc_t *efc, H5F_efc_ent_t *ent);
+static void H5F_efc_try_close_tag1(H5F_file_t *sf, H5F_file_t **tail);
+static void H5F_efc_try_close_tag2(H5F_file_t *sf, H5F_file_t **tail);
+
+/* Free lists */
+H5FL_DEFINE_STATIC(H5F_efc_ent_t);
+H5FL_DEFINE_STATIC(H5F_efc_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_create
+ *
+ * Purpose: Allocate and initialize a new external file cache object,
+ * which can the be used to cache open external files.
+ * the object must be freed with H5F_efc_destroy.
+ *
+ * Return: Pointer to new external file cache object on success
+ * NULL on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 14, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_efc_t *
+H5F_efc_create(unsigned max_nfiles)
+{
+ H5F_efc_t *efc = NULL; /* EFC object */
+ H5F_efc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity checks */
+ HDassert(max_nfiles > 0);
+
+ /* Allocate EFC struct */
+ if(NULL == (efc = H5FL_CALLOC(H5F_efc_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Initialize maximum number of files */
+ efc->max_nfiles = max_nfiles;
+
+ /* Initialize temporary ref count */
+ efc->tag = H5F_EFC_TAG_DEFAULT;
+
+ /* Set the return value */
+ ret_value = efc;
+
+done:
+ if(ret_value == NULL && efc)
+ efc = H5FL_FREE(H5F_efc_t, efc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_efc_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_open
+ *
+ * Purpose: Opens a file using the external file cache. The target
+ * file is added to the external file cache of the parent
+ * if it is not already present. If the target file is in
+ * the parent's EFC, simply returns the target file. When
+ * the file object is no longer in use, it should be closed
+ * with H5F_efc_close (will not actually close the file
+ * until it is evicted from the EFC).
+ *
+ * Return: Pointer to open file on success
+ * NULL on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 14, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5F_efc_open(H5F_t *parent, const char *name, unsigned flags, hid_t fcpl_id,
+ hid_t fapl_id, hid_t dxpl_id)
+{
+ H5F_efc_t *efc = NULL; /* External file cache for parent file */
+ H5F_efc_ent_t *ent = NULL; /* Entry for target file in efc */
+ hbool_t open_file = FALSE; /* Whether ent->file needs to be closed in case of error */
+ H5F_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(parent);
+ HDassert(parent->shared);
+ HDassert(name);
+
+ /* Get external file cache */
+ efc = parent->shared->efc;
+
+ /* Check if the EFC exists. If it does not, just call H5F_open(). We
+ * support this so clients do not have to make 2 different calls depending
+ * on the state of the efc. */
+ if(!efc) {
+ if(NULL == (ret_value = H5F_open(name, flags, fcpl_id, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "can't open file")
+
+ /* Increment the number of open objects to prevent the file from being
+ * closed out from under us - "simulate" having an open file id. Note
+ * that this behaviour replaces the calls to H5F_incr_nopen_objs() and
+ * H5F_decr_nopen_objs() in H5L_extern_traverse(). */
+ ret_value->nopen_objs++;
+
+ HGOTO_DONE(ret_value)
+ } /* end if */
+
+ /* Search the skip list for name if the skip list exists, create the skip
+ * list otherwise */
+ if(efc->slist) {
+ if(efc->nfiles > 0)
+ ent = (H5F_efc_ent_t *)H5SL_search(efc->slist, name);
+ } /* end if */
+ else {
+ HDassert(efc->nfiles == 0);
+ if(NULL == (efc->slist = H5SL_create(H5SL_TYPE_STR, NULL)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, NULL, "can't create skip list")
+ } /* end else */
+
+ /* If we found the file update the LRU list and return the cached file,
+ * otherwise open the file and cache it */
+ if(ent) {
+ HDassert(efc->LRU_head);
+ HDassert(efc->LRU_tail);
+
+ /* Move ent to the head of the LRU list, if it is not already there */
+ if(ent->LRU_prev) {
+ HDassert(efc->LRU_head != ent);
+
+ /* Remove from current position. Note that once we touch the LRU
+ * list we cannot revert to the previous state. Make sure there can
+ * be no errors between when we first touch the LRU list and when
+ * the cache is in a consistent state! */
+ if(ent->LRU_next)
+ ent->LRU_next->LRU_prev = ent->LRU_prev;
+ else {
+ HDassert(efc->LRU_tail == ent);
+ efc->LRU_tail = ent->LRU_prev;
+ } /* end else */
+ ent->LRU_prev->LRU_next = ent->LRU_next;
+
+ /* Add to head of LRU list */
+ ent->LRU_next = efc->LRU_head;
+ ent->LRU_next->LRU_prev = ent;
+ ent->LRU_prev = NULL;
+ efc->LRU_head = ent;
+ } /* end if */
+
+ /* Mark the file as open */
+ ent->nopen++;
+ } /* end if */
+ else {
+ /* Check if we need to evict something */
+ if(efc->nfiles == efc->max_nfiles) {
+ /* Search for an unopened file from the tail */
+ for(ent = efc->LRU_tail; ent && ent->nopen; ent = ent->LRU_prev);
+
+ /* Evict the file if found, otherwise just open the target file and
+ * do not add it to cache */
+ if(ent) {
+ if(H5F_efc_remove_ent(efc, ent) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTREMOVE, NULL, "can't remove entry from external file cache")
+
+ /* Do not free ent, we will recycle it below */
+ } /* end if */
+ else {
+ /* Cannot cache file, just open file and return */
+ if(NULL == (ret_value = H5F_open(name, flags, fcpl_id, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "can't open file")
+
+ /* Increment the number of open objects to prevent the file from
+ * being closed out from under us - "simulate" having an open
+ * file id */
+ ret_value->nopen_objs++;
+
+ HGOTO_DONE(ret_value)
+ } /* end else */
+ } /* end if */
+ else
+ /* Allocate new entry */
+ if(NULL == (ent = H5FL_MALLOC(H5F_efc_ent_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Build new entry */
+ if(NULL == (ent->name = H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Open the file */
+ if(NULL == (ent->file = H5F_open(name, flags, fcpl_id, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "can't open file")
+ open_file = TRUE;
+
+ /* Increment the number of open objects to prevent the file from being
+ * closed out from under us - "simulate" having an open file id */
+ ent->file->nopen_objs++;
+
+ /* Add the file to the cache */
+ /* Skip list */
+ if(H5SL_insert(efc->slist, ent, ent->name) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINSERT, NULL, "can't insert entry into skip list")
+
+ /* Add to head of LRU list and update tail if necessary */
+ ent->LRU_next = efc->LRU_head;
+ if(ent->LRU_next)
+ ent->LRU_next->LRU_prev = ent;
+ ent->LRU_prev = NULL;
+ efc->LRU_head = ent;
+ if(!efc->LRU_tail) {
+ HDassert(!ent->LRU_next);
+ efc->LRU_tail = ent;
+ } /* end if */
+
+ /* Mark the file as open */
+ ent->nopen = 1;
+
+ /* Update nfiles and nrefs */
+ efc->nfiles++;
+ if(ent->file->shared->efc)
+ ent->file->shared->efc->nrefs++;
+ } /* end else */
+
+ HDassert(ent);
+ HDassert(ent->file);
+ HDassert(ent->name);
+ HDassert(ent->nopen);
+
+ /* Set the return value */
+ ret_value = ent->file;
+
+done:
+ if(!ret_value)
+ if(ent) {
+ if(open_file) {
+ ent->file->nopen_objs--;
+ if(H5F_try_close(ent->file, NULL) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "can't close external file")
+ } /* end if */
+ ent->name = (char *)H5MM_xfree(ent->name);
+ ent = H5FL_FREE(H5F_efc_ent_t, ent);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_efc_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_close
+ *
+ * Purpose: Closes (unlocks) a file opened using the external file
+ * cache. The target file is not immediately closed unless
+ * there is no external file cache for the parent file.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, December 15, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_efc_close(H5F_t *parent, H5F_t *file)
+{
+ H5F_efc_t *efc = NULL; /* External file cache for parent file */
+ H5F_efc_ent_t *ent = NULL; /* Entry for target file in efc */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(parent);
+ HDassert(parent->shared);
+ HDassert(file);
+ HDassert(file->shared);
+
+ /* Get external file cache */
+ efc = parent->shared->efc;
+
+ /* Check if the EFC exists. If it does not, just call H5F_try_close(). We
+ * support this so clients do not have to make 2 different calls depending
+ * on the state of the efc. */
+ if(!efc) {
+ file->nopen_objs--;
+ if(H5F_try_close(file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close external file")
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Scan the parent's LRU list from the head to file file. We do this
+ * instead of a skip list lookup because the file will almost always be at
+ * the head. In the unlikely case that the file is not found, just call
+ * H5F_try_close(). This could happen if the EFC was full of open files
+ * when the file was opened. */
+ for(ent = efc->LRU_head; ent && ent->file != file; ent = ent->LRU_next);
+ if(!ent) {
+ file->nopen_objs--;
+ if(H5F_try_close(file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close external file")
+ } /* end if */
+ else
+ /* Reduce the open count on this entry */
+ ent->nopen--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_efc_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_max_nfiles
+ *
+ * Purpose: Returns the maximum number of files in the provided
+ * external file cache.
+ *
+ * Return: Maximum number of files (never fails)
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, December 15, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_efc_max_nfiles(H5F_efc_t *efc)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(efc);
+ HDassert(efc->max_nfiles > 0);
+
+ FUNC_LEAVE_NOAPI(efc->max_nfiles)
+} /* end H5F_efc_max_nfiles */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_release
+ *
+ * Purpose: Releases the external file cache, potentially closing any
+ * cached files unless they are held open from somewhere
+ * else (or are currently opened by a client).
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, December 15, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_efc_release(H5F_efc_t *efc)
+{
+ H5F_efc_ent_t *ent = NULL; /* EFC entry */
+ H5F_efc_ent_t *prev_ent = NULL; /* Previous EFC entry */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(efc);
+
+ /* Lock the EFC to prevent manipulation of the EFC wile we are releasing it.
+ * The EFC should never be locked when we enter this function because that
+ * would require a cycle, a cycle would necessarily invoke
+ * H5F_efc_try_close(), and that function checks the status of the lock
+ * before calling this one. */
+ HDassert((efc->tag == H5F_EFC_TAG_DEFAULT)
+ || (efc->tag == H5F_EFC_TAG_CLOSE));
+ efc->tag = H5F_EFC_TAG_LOCK;
+
+ /* Walk down the LRU list, releasing any files that are not opened by an EFC
+ * client */
+ ent = efc->LRU_head;
+ while(ent)
+ if(!ent->nopen) {
+ if(H5F_efc_remove_ent(efc, ent) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTREMOVE, FAIL, "can't remove entry from external file cache")
+
+ /* Free the entry and move to next entry in LRU list */
+ prev_ent = ent;
+ ent = ent->LRU_next;
+ prev_ent = H5FL_FREE(H5F_efc_ent_t, prev_ent);
+ } /* end if */
+ else
+ /* Can't release file because it's open; just advance the pointer */
+ ent = ent->LRU_next;
+
+ /* Reset tag. No need to reset to CLOSE if that was the original tag, as in
+ * that case the file must be getting closed anyways. */
+ efc->tag = H5F_EFC_TAG_DEFAULT;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_efc_release() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_destroy
+ *
+ * Purpose: Frees an external file cache object, releasing it first
+ * if necessary. If it cannot be fully released, for example
+ * if there are open files, returns an error.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, December 15, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_efc_destroy(H5F_efc_t *efc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(efc);
+
+ if(efc->nfiles > 0) {
+ /* Release (clear) the efc */
+ if(H5F_efc_release(efc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release external file cache")
+
+ /* If there are still cached files, return an error */
+ if(efc->nfiles > 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't destroy EFC after incomplete release")
+ } /* end if */
+
+ HDassert(efc->nfiles == 0);
+ HDassert(efc->LRU_head == NULL);
+ HDassert(efc->LRU_tail == NULL);
+
+ /* Close skip list */
+ if(efc->slist)
+ if(H5SL_close(efc->slist) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close skip list")
+
+ /* Free EFC object */
+ (void)H5FL_FREE(H5F_efc_t, efc);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_efc_destroy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_remove_ent
+ *
+ * Purpose: Removes the specified entry from the specified EFC,
+ * closing the file if requested. Does not free the entry.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, December 15, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_efc_remove_ent(H5F_efc_t *efc, H5F_efc_ent_t *ent)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(efc);
+ HDassert(efc->slist);
+ HDassert(ent);
+
+ /* Remove from skip list */
+ if(ent != H5SL_remove(efc->slist, ent->name))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDELETE, FAIL, "can't delete entry from skip list")
+
+ /* Remove from LRU list */
+ if(ent->LRU_next)
+ ent->LRU_next->LRU_prev = ent->LRU_prev;
+ else {
+ HDassert(efc->LRU_tail == ent);
+ efc->LRU_tail = ent->LRU_prev;
+ } /* end else */
+ if(ent->LRU_prev)
+ ent->LRU_prev->LRU_next = ent->LRU_next;
+ else {
+ HDassert(efc->LRU_head == ent);
+ efc->LRU_head = ent->LRU_next;
+ } /* end else */
+
+ /* Update nfiles and nrefs */
+ efc->nfiles--;
+ if(ent->file->shared->efc)
+ ent->file->shared->efc->nrefs--;
+
+ /* Free the name */
+ ent->name = (char *)H5MM_xfree(ent->name);
+
+ /* Close the file. Note that since H5F_t structs returned from H5F_open()
+ * are *always* unique, there is no need to reference count this struct.
+ * However we must still manipulate the nopen_objs field to prevent the file
+ * from being closed out from under us. */
+ ent->file->nopen_objs--;
+ if(H5F_try_close(ent->file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close external file")
+ ent->file = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_efc_remove_ent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_try_close_tag1
+ *
+ * Purpose: Recursively traverse the EFC tree, keeping a temporary
+ * reference count on each file that assumes all reachable
+ * files will eventually be closed.
+ *
+ * Return: void (never fails)
+ *
+ * Programmer: Neil Fortner
+ * Monday, January 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5F_efc_try_close_tag1(H5F_file_t *sf, H5F_file_t **tail)
+{
+ H5F_efc_ent_t *ent = NULL; /* EFC entry */
+ H5F_file_t *esf; /* Convenience pointer to ent->file->shared */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(sf);
+ HDassert(sf->efc);
+ HDassert((sf->efc->tag > 0) || (sf->nrefs == sf->efc->nrefs));
+ HDassert(sf->efc->tag != H5F_EFC_TAG_LOCK);
+ HDassert(tail);
+ HDassert(*tail);
+
+ /* Recurse into this file's cached files */
+ for(ent = sf->efc->LRU_head; ent; ent = ent->LRU_next) {
+ esf = ent->file->shared;
+
+ if(esf->efc) {
+ /* If tag were 0, that would mean there are more actual references
+ * than are counted by nrefs */
+ HDassert(esf->efc->tag != 0);
+
+ /* If tag has been set, we have already visited this file so just
+ * decrement tag and continue */
+ if(esf->efc->tag > 0)
+ esf->efc->tag--;
+ /* If there are references that are not from an EFC, it will never
+ * be possible to close the file. Just continue. Also continue if
+ * the EFC is locked or the file is open (through the EFC). Note
+ * that the reference counts will never match for the root file, but
+ * that's ok because the root file will always have a tag and enter
+ * the branch above. */
+ else if((esf->nrefs == esf->efc->nrefs)
+ && (esf->efc->tag != H5F_EFC_TAG_LOCK) && !(ent->nopen)) {
+ /* If we get here, this file's "tmp_next" pointer must be NULL
+ */
+ HDassert(esf->efc->tmp_next == NULL);
+
+ /* If nrefs > 1, Add this file to the list of files with nrefs >
+ * 1 and initialize tag to the number of references (except this
+ * one) */
+ if(esf->nrefs > 1) {
+ (*tail)->efc->tmp_next = esf;
+ *tail = esf;
+ esf->efc->tag = (int)esf->nrefs - 1;
+ } /* end if */
+
+ /* Recurse into the entry */
+ H5F_efc_try_close_tag1(ent->file->shared, tail);
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_efc_try_close_tag1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_try_close_tag2
+ *
+ * Purpose: Recuresively mark all files reachable through this one as
+ * uncloseable, and add newly uncloseable files to the tail
+ * of the provided linked list.
+ *
+ * Return: void (never fails)
+ *
+ * Programmer: Neil Fortner
+ * Monday, January 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5F_efc_try_close_tag2(H5F_file_t *sf, H5F_file_t **tail)
+{
+ H5F_efc_ent_t *ent = NULL; /* EFC entry */
+ H5F_file_t *esf; /* Convenience pointer to ent->file->shared */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(sf);
+ HDassert(sf->efc);
+
+ /* Recurse into this file's cached files */
+ for(ent = sf->efc->LRU_head; ent; ent = ent->LRU_next) {
+ esf = ent->file->shared;
+
+ /* Only recurse if the file is tagged CLOSE or DEFAULT. If it is tagged
+ * DONTCLOSE, we have already visited this file *or* it will be the
+ * start point of another iteration. No files should be tagged with a
+ * nonegative value at this point. If it is tagged as DEFAULT, we must
+ * apply the same conditions as in cb1 above for recursion in order to
+ * make sure we do not go off into somewhere cb1 didn't touch. The
+ * root file should never be tagged DEFAULT here, so the reference check
+ * is still appropriate. */
+ if((esf->efc) && ((esf->efc->tag == H5F_EFC_TAG_CLOSE)
+ || ((esf->efc->tag == H5F_EFC_TAG_DEFAULT)
+ && (esf->nrefs == esf->efc->nrefs) && !(ent->nopen)))) {
+ /* tag should always be CLOSE is nrefs > 1 or DEFAULT if nrefs == 1
+ * here */
+ HDassert(((esf->nrefs > 1)
+ && ((esf->efc->tag == H5F_EFC_TAG_CLOSE)))
+ || ((esf->nrefs == 1)
+ && (esf->efc->tag == H5F_EFC_TAG_DEFAULT)));
+
+ /* If tag is set to DONTCLOSE, we have already visited this file
+ * *or* it will be the start point of another iteration so just
+ * continue */
+ if(esf->efc->tag != H5F_EFC_TAG_DONTCLOSE) {
+ /* If tag is CLOSE, set to DONTCLOSE and add to the list of
+ * uncloseable files. */
+ if(esf->efc->tag == H5F_EFC_TAG_CLOSE) {
+ esf->efc->tag = H5F_EFC_TAG_DONTCLOSE;
+ esf->efc->tmp_next = NULL;
+ (*tail)->efc->tmp_next = esf;
+ *tail = esf;
+ } /* end if */
+
+ /* Recurse into the entry */
+ H5F_efc_try_close_tag2(esf, tail);
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_efc_try_close_tag2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_efc_try_close
+ *
+ * Purpose: Attempts to close the provided (shared) file by checking
+ * to see if the releasing the EFC would cause its reference
+ * count to drop to 0. Necessary to handle the case where
+ * chained EFCs form a cycle. Note that this function does
+ * not actually close the file (though it closes all children
+ * as appropriate), as that is left up to the calling
+ * function H5F_try_close().
+ *
+ * Because H5F_try_close() has no way of telling if it is
+ * called recursively from within this function, this
+ * function serves as both the root of iteration and the
+ * "callback" for the final pass (the one where the files are
+ * actually closed). The code for the callback case is at
+ * the top of this function; luckily it only consists of a
+ * (possible) call to H5F_efc_release().
+ *
+ * The algorithm basically consists of 3 passes over the EFC
+ * tree. The first pass assumes that every reachable file is
+ * closed, and keeps track of what the final reference count
+ * would be for every reachable file. The files are then
+ * tagged as either closeable or uncloseable based on whether
+ * this reference count drops to 0.
+ *
+ * The second pass initiates a traversal from each file
+ * marked as uncloseable in the first pass, and marks every
+ * file reachable from the initial uncloseable file as
+ * uncloseable. This eliminates files that were marked as
+ * closeable only because the first pass assumed that an
+ * uncloseable file would be closed.
+ *
+ * The final pass exploits the H5F_efc_release()->
+ * H5F_efc_remove_ent()->H5F_try_close()->H5F_efc_try_close()
+ * calling chain to recursively close the tree, but only the
+ * files that are still marked as closeable. All files
+ * marked as closeable have their EFCs released, and will
+ * eventually be closed when their last parent EFC is
+ * released (the last part is guaranteed to be true by the
+ * first 2 passes).
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Thursday, January 6, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_efc_try_close(H5F_t *f)
+{
+ H5F_file_t *tail; /* Tail of linked list of found files. Head will be f->shared. */
+ H5F_file_t *uncloseable_head = NULL; /* Head of linked list of files found to be uncloseable by the first pass */
+ H5F_file_t *uncloseable_tail = NULL; /* Tail of linked list of files found to be uncloseable by the first pass */
+ H5F_file_t *sf; /* Temporary file pointer */
+ H5F_file_t *next; /* Temporary file pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->efc);
+ HDassert(f->shared->nrefs > f->shared->efc->nrefs);
+ HDassert(f->shared->nrefs > 1);
+ HDassert(f->shared->efc->tag < 0);
+
+ if(f->shared->efc->tag == H5F_EFC_TAG_CLOSE) {
+ /* We must have reentered this function, and we should close this file.
+ * In actuality, we just release the EFC, the recursion should
+ * eventually reduce this file's reference count to 1 (though possibly
+ * not from this call to H5F_efc_release()). */
+ if(H5F_efc_release(f->shared->efc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release external file cache")
+
+ /* If we marked the file as closeable, there must be no open files in
+ * its EFC. This is because, in order to close an open child file, the
+ * client must keep a copy of the parent file open. The algorithm
+ * detect that the parent file is open (directly or through an EFC) and
+ * refuse to close it. Verify that all files were released from this
+ * EFC (i.e. none were open). */
+ HDassert(f->shared->efc->nfiles == 0);
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Conditions where we should not do anything and just return immediately */
+ /* If there are references that are not from an EFC or f, it will never
+ * be possible to close the file. Just return. Note that this holds true
+ * for the case that this file is being closed through H5F_efc_release()
+ * because that function (through H5F_efc_remove_ent()) decrements the EFC
+ * reference count before it calls H5F_try_close(). This may occur if this
+ * function is reentered. */
+ /* If the tag is H5F_EFC_TAG_DONTCLOSE, then we have definitely reentered
+ * this function, and this file has been marked as uncloseable, so we should
+ * not close/release it */
+ /* If nfiles is 0, then there is nothing to do. Just return. This may also
+ * occur on reentry (for example if this file was previously released). */
+ if((f->shared->nrefs != f->shared->efc->nrefs + 1)
+ || (f->shared->efc->tag == H5F_EFC_TAG_DONTCLOSE)
+ || (f->shared->efc->nfiles == 0))
+ /* We must have reentered this function, and we should not close this
+ * file. Just return. */
+ HGOTO_DONE(SUCCEED)
+
+ /* If the file EFC were locked, that should always mean that there exists
+ * a reference to this file that is not in an EFC (it may have just been
+ * removed from an EFC), and should have been caught by the above check */
+ /* If we get here then we must be beginning a new run. Make sure that the
+ * temporary variables in f->shared->efc are at the default value */
+ HDassert(f->shared->efc->tag == H5F_EFC_TAG_DEFAULT);
+ HDassert(f->shared->efc->tmp_next == NULL);
+
+ /* Set up linked list for traversal into EFC tree. f->shared is guaranteed
+ * to always be at the head. */
+ tail = f->shared;
+
+ /* Set up temporary reference count on root file */
+ f->shared->efc->tag = (int)f->shared->efc->nrefs;
+
+ /* First Pass: simulate closing all files reachable from this one, use "tag"
+ * field to keep track of final reference count for each file (including
+ * this one). Keep list of files with starting reference count > 1 (head is
+ * f->shared). */
+ H5F_efc_try_close_tag1(f->shared, &tail);
+
+ /* Check if f->shared->efc->tag dropped to 0. If it did not,
+ * we cannot close anything. Just reset temporary values and return. */
+ if(f->shared->efc->tag > 0) {
+ sf = f->shared;
+ while(sf) {
+ next = sf->efc->tmp_next;
+ sf->efc->tag = H5F_EFC_TAG_DEFAULT;
+ sf->efc->tmp_next = NULL;
+ sf = next;
+ } /* end while */
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Run through the linked list , separating into two lists, one with tag ==
+ * 0 and one with tag > 0. Mark them as either H5F_EFC_TAG_CLOSE or
+ * H5F_EFC_TAG_DONTCLOSE as appropriate. */
+ sf = f->shared;
+ tail = NULL;
+ while(sf) {
+ HDassert(sf->efc->tag >= 0);
+ next = sf->efc->tmp_next;
+ if(sf->efc->tag > 0) {
+ /* Remove from main list */
+ HDassert(tail);
+ tail->efc->tmp_next = sf->efc->tmp_next;
+ sf->efc->tmp_next = NULL;
+
+ /* Add to uncloseable list */
+ if(!uncloseable_head)
+ uncloseable_head = sf;
+ else
+ uncloseable_tail->efc->tmp_next = sf;
+ uncloseable_tail = sf;
+
+ /* Mark as uncloseable */
+ sf->efc->tag = H5F_EFC_TAG_DONTCLOSE;
+ } /* end if */
+ else {
+ sf->efc->tag = H5F_EFC_TAG_CLOSE;
+ tail = sf;
+ } /* end else */
+ sf = next;
+ } /* end while */
+
+ /* Second pass: Determine which of the reachable files found in pass 1
+ * cannot be closed by releasing the root file's EFC. Run through the
+ * uncloseable list, for each item traverse the files reachable through the
+ * EFC, mark the file as uncloseable, and add it to the list of uncloseable
+ * files (for cleanup). Use "tail" to store the original uncloseable tail
+ * so we know when to stop. We do not need to keep track of the closeable
+ * list any more. */
+ sf = uncloseable_head;
+ if(sf) {
+ tail = uncloseable_tail;
+ HDassert(tail);
+ while(sf != tail->efc->tmp_next) {
+ H5F_efc_try_close_tag2(sf, &uncloseable_tail);
+ sf = sf->efc->tmp_next;
+ } /* end while */
+ } /* end if */
+
+ /* If the root file's tag is still H5F_EFC_TAG_CLOSE, release its EFC. This
+ * should start the recursive release that should close all closeable files.
+ * Also, see the top of this function. */
+ if(f->shared->efc->tag == H5F_EFC_TAG_CLOSE) {
+ if(H5F_efc_release(f->shared->efc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release external file cache")
+
+ /* Make sure the file's reference count is now 1 and will be closed by
+ * H5F_dest(). */
+ HDassert(f->shared->nrefs == 1);
+ } /* end if */
+
+ /* Clean up uncloseable files (reset tag and tmp_next). All closeable files
+ * should have been closed, and therefore do not need to be cleaned up. */
+ if(uncloseable_head) {
+ sf = uncloseable_head;
+ while(sf) {
+ next = sf->efc->tmp_next;
+ HDassert(sf->efc->tag == H5F_EFC_TAG_DONTCLOSE);
+ sf->efc->tag = H5F_EFC_TAG_DEFAULT;
+ sf->efc->tmp_next = NULL;
+ sf = next;
+ } /* end while */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_efc_try_close() */
+
diff --git a/src/H5Ffake.c b/src/H5Ffake.c
new file mode 100644
index 0000000..6072f2e
--- /dev/null
+++ b/src/H5Ffake.c
@@ -0,0 +1,102 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+
+/* PRIVATE PROTOTYPES */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_fake_alloc
+ *
+ * Purpose: Allocate a "fake" file structure, for various routines to
+ * use for encoding/decoding data structures using internal API
+ * routines that need a file structure, but don't ultimately
+ * depend on having a "real" file.
+ *
+ * Return: Success: Pointer to 'faked up' file structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5F_fake_alloc(uint8_t sizeof_size)
+{
+ H5F_t *f = NULL; /* Pointer to fake file struct */
+ H5F_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate faked file struct */
+ if(NULL == (f = H5FL_CALLOC(H5F_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate top file structure")
+ if(NULL == (f->shared = H5FL_CALLOC(H5F_file_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate shared file structure")
+
+ /* Only set fields necessary for clients */
+ if(sizeof_size == 0)
+ f->shared->sizeof_size = H5F_OBJ_SIZE_SIZE;
+ else
+ f->shared->sizeof_size = sizeof_size;
+
+ /* Set return value */
+ ret_value = f;
+
+done:
+ if(!ret_value)
+ H5F_fake_free(f);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_fake_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_fake_free
+ *
+ * Purpose: Free a "fake" file structure.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_fake_free(H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Free faked file struct */
+ if(f) {
+ /* Destroy shared file struct */
+ if(f->shared)
+ f->shared = H5FL_FREE(H5F_file_t, f->shared);
+ f = H5FL_FREE(H5F_t, f);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F_fake_free() */
+
diff --git a/src/H5Fint.c b/src/H5Fint.c
new file mode 100644
index 0000000..fe532b2
--- /dev/null
+++ b/src/H5Fint.c
@@ -0,0 +1,2820 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Aprivate.h" /* Attributes */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+#include "H5Tprivate.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Struct only used by functions H5F_get_objects and H5F_get_objects_cb */
+typedef struct H5F_olist_t {
+ H5I_type_t obj_type; /* Type of object to look for */
+ hid_t *obj_id_list; /* Pointer to the list of open IDs to return */
+ size_t *obj_id_count; /* Number of open IDs */
+ struct {
+ hbool_t local; /* Set flag for "local" file searches */
+ union {
+ H5F_file_t *shared; /* Pointer to shared file to look inside */
+ const H5F_t *file; /* Pointer to file to look inside */
+ } ptr;
+ } file_info;
+ size_t list_index; /* Current index in open ID array */
+ size_t max_nobjs; /* Maximum # of IDs to put into array */
+} H5F_olist_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key);
+static herr_t H5F_build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl,
+ const char *name, char ** /*out*/ actual_name);/* Declare a free list to manage the H5F_t struct */
+static herr_t H5F__flush_phase1(H5F_t *f, hid_t meta_dxpl_id);
+static herr_t H5F__flush_phase2(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t closing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5F_t struct */
+H5FL_DEFINE(H5F_t);
+
+/* Declare a free list to manage the H5F_file_t struct */
+H5FL_DEFINE(H5F_file_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_access_plist
+ *
+ * Purpose: Returns a copy of the file access property list of the
+ * specified file.
+ *
+ * NOTE: Make sure that, if you are going to overwrite
+ * information in the copied property list that was
+ * previously opened and assigned to the property list, then
+ * you must close it before overwriting the values.
+ *
+ * Return: Success: Object ID for a copy of the file access
+ * property list.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 25, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5F_get_access_plist(H5F_t *f, hbool_t app_ref)
+{
+ H5P_genplist_t *new_plist; /* New property list */
+ H5P_genplist_t *old_plist; /* Old property list */
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+ hbool_t driver_prop_copied = FALSE; /* Whether the driver property has been set up */
+ unsigned efc_size = 0;
+ hbool_t latest_format = FALSE; /* Always use the latest format? */
+ hid_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+
+ /* Make a copy of the default file access property list */
+ if(NULL == (old_plist = (H5P_genplist_t *)H5I_object(H5P_LST_FILE_ACCESS_ID_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if((ret_value = H5P_copy_plist(old_plist, app_ref)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, "can't copy file access property list")
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(ret_value)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Copy properties of the file access property list */
+ if(H5P_set(new_plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, &(f->shared->mdc_initCacheCfg)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set initial metadata cache resize config.")
+ if(H5P_set(new_plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(f->shared->rdcc_nslots)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache number of slots")
+ if(H5P_set(new_plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(f->shared->rdcc_nbytes)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache byte size")
+ if(H5P_set(new_plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, &(f->shared->rdcc_w0)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set preempt read chunks")
+ if(H5P_set(new_plist, H5F_ACS_ALIGN_THRHD_NAME, &(f->shared->threshold)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set alignment threshold")
+ if(H5P_set(new_plist, H5F_ACS_ALIGN_NAME, &(f->shared->alignment)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set alignment")
+ if(H5P_set(new_plist, H5F_ACS_GARBG_COLCT_REF_NAME, &(f->shared->gc_ref)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set garbage collect reference")
+ if(H5P_set(new_plist, H5F_ACS_META_BLOCK_SIZE_NAME, &(f->shared->meta_aggr.alloc_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set metadata cache size")
+ if(H5P_set(new_plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, &(f->shared->sieve_buf_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't sieve buffer size")
+ if(H5P_set(new_plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, &(f->shared->sdata_aggr.alloc_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'small data' cache size")
+ if(f->shared->latest_flags > 0)
+ latest_format = TRUE;
+ if(H5P_set(new_plist, H5F_ACS_LATEST_FORMAT_NAME, &latest_format) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'latest format' flag")
+ if(H5P_set(new_plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &(f->shared->read_attempts)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'read attempts ' flag")
+ if(H5P_set(new_plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &(f->shared->object_flush)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object flush callback")
+
+ if(f->shared->efc)
+ efc_size = H5F_efc_max_nfiles(f->shared->efc);
+ if(H5P_set(new_plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set elink file cache size")
+ if(f->shared->page_buf != NULL) {
+ if(H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, &(f->shared->page_buf->max_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set page buffer size")
+ if(H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, &(f->shared->page_buf->min_meta_perc)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set minimum metadata fraction of page buffer")
+ if(H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &(f->shared->page_buf->min_raw_perc)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set minimum raw data fraction of page buffer")
+ } /* end if */
+#ifdef H5_HAVE_PARALLEL
+ if(H5P_set(new_plist, H5_COLL_MD_READ_FLAG_NAME, &(f->coll_md_read)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set collective metadata read flag")
+ if(H5P_set(new_plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, &(f->coll_md_write)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set collective metadata read flag")
+#endif /* H5_HAVE_PARALLEL */
+ if(H5P_set(new_plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, &(f->shared->mdc_initCacheImageCfg)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set initial metadata cache resize config.")
+
+ /* Prepare the driver property */
+ driver_prop.driver_id = f->shared->lf->driver_id;
+ driver_prop.driver_info = H5FD_fapl_get(f->shared->lf);
+ driver_prop_copied = TRUE;
+
+ /* Set the driver property */
+ if(H5P_set(new_plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file driver ID & info")
+
+ /* Set the file close degree appropriately */
+ if(f->shared->fc_degree == H5F_CLOSE_DEFAULT && H5P_set(new_plist, H5F_ACS_CLOSE_DEGREE_NAME, &(f->shared->lf->cls->fc_degree)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree")
+ else if(f->shared->fc_degree != H5F_CLOSE_DEFAULT && H5P_set(new_plist, H5F_ACS_CLOSE_DEGREE_NAME, &(f->shared->fc_degree)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree")
+
+done:
+ /* Release the copy of the driver info, if it was set up */
+ if(driver_prop_copied && H5FD_fapl_close(driver_prop.driver_id, driver_prop.driver_info) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close copy of driver info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_access_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_obj_count
+ *
+ * Purpose: Private function return the number of opened object IDs
+ * (files, datasets, groups, datatypes) in the same file.
+ *
+ * Return: SUCCEED on success, FAIL on failure.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
+
+ /* Perform the query */
+ if((ret_value = H5F_get_objects(f, types, 0, NULL, app_ref, obj_id_count_ptr)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_obj_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_obj_ids
+ *
+ * Purpose: Private function to return a list of opened object IDs.
+ *
+ * Return: Non-negative on success; can't fail.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
+
+ /* Perform the query */
+ if((ret_value = H5F_get_objects(f, types, max_objs, oid_list, app_ref, obj_id_count_ptr)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_obj_ids() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5F_get_objects
+ *
+ * Purpose: This function is called by H5F_get_obj_count or
+ * H5F_get_obj_ids to get number of object IDs and/or a
+ * list of opened object IDs (in return value).
+ * Return: Non-negative on success; Can't fail.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ *---------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_objects(const H5F_t *f, unsigned types, size_t max_nobjs, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr)
+{
+ size_t obj_id_count=0; /* Number of open IDs */
+ H5F_olist_t olist; /* Structure to hold search results */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
+
+ /* Set up search information */
+ olist.obj_id_list = (max_nobjs==0 ? NULL : obj_id_list);
+ olist.obj_id_count = &obj_id_count;
+ olist.list_index = 0;
+ olist.max_nobjs = max_nobjs;
+
+ /* Determine if we are searching for local or global objects */
+ if(types & H5F_OBJ_LOCAL) {
+ olist.file_info.local = TRUE;
+ olist.file_info.ptr.file = f;
+ } /* end if */
+ else {
+ olist.file_info.local = FALSE;
+ olist.file_info.ptr.shared = f ? f->shared : NULL;
+ } /* end else */
+
+ /* Iterate through file IDs to count the number, and put their
+ * IDs on the object list. */
+ if(types & H5F_OBJ_FILE) {
+ olist.obj_type = H5I_FILE;
+ if(H5I_iterate(H5I_FILE, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(1)")
+ } /* end if */
+
+ /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero),
+ * or the caller wants to get the list of IDs and the list isn't full,
+ * search through dataset IDs to count number of datasets, and put their
+ * IDs on the object list */
+ if(!olist.max_nobjs || (olist.max_nobjs && olist.list_index<olist.max_nobjs)) {
+ if (types & H5F_OBJ_DATASET) {
+ olist.obj_type = H5I_DATASET;
+ if(H5I_iterate(H5I_DATASET, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(2)")
+ } /* end if */
+ }
+
+ /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero),
+ * or the caller wants to get the list of IDs and the list isn't full,
+ * search through group IDs to count number of groups, and put their
+ * IDs on the object list */
+ if(!olist.max_nobjs || (olist.max_nobjs && olist.list_index<olist.max_nobjs)) {
+ if(types & H5F_OBJ_GROUP) {
+ olist.obj_type = H5I_GROUP;
+ if(H5I_iterate(H5I_GROUP, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(3)")
+ } /* end if */
+ }
+
+ /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero),
+ * or the caller wants to get the list of IDs and the list isn't full,
+ * search through datatype IDs to count number of named datatypes, and put their
+ * IDs on the object list */
+ if(!olist.max_nobjs || (olist.max_nobjs && olist.list_index<olist.max_nobjs)) {
+ if(types & H5F_OBJ_DATATYPE) {
+ olist.obj_type = H5I_DATATYPE;
+ if(H5I_iterate(H5I_DATATYPE, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(4)")
+ } /* end if */
+ }
+
+ /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero),
+ * or the caller wants to get the list of IDs and the list isn't full,
+ * search through attribute IDs to count number of attributes, and put their
+ * IDs on the object list */
+ if(!olist.max_nobjs || (olist.max_nobjs && olist.list_index<olist.max_nobjs)) {
+ if(types & H5F_OBJ_ATTR) {
+ olist.obj_type = H5I_ATTR;
+ if(H5I_iterate(H5I_ATTR, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(5)")
+ } /* end if */
+ }
+
+ /* Set the number of objects currently open */
+ *obj_id_count_ptr = obj_id_count;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_objects() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_objects_cb
+ *
+ * Purpose: H5F_get_objects' callback function. It verifies if an
+ * object is in the file, and either count it or put its ID
+ * on the list.
+ *
+ * Return: H5_ITER_STOP if the array of object IDs is filled up.
+ * H5_ITER_CONT otherwise.
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Dec 5, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key)
+{
+ H5F_olist_t *olist = (H5F_olist_t *)key; /* Alias for search info */
+ hbool_t add_obj = FALSE;
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(obj_ptr);
+ HDassert(olist);
+
+ /* Count file IDs */
+ if(olist->obj_type == H5I_FILE) {
+ if((olist->file_info.local &&
+ (!olist->file_info.ptr.file || (olist->file_info.ptr.file && (H5F_t*)obj_ptr == olist->file_info.ptr.file) ))
+ || (!olist->file_info.local &&
+ ( !olist->file_info.ptr.shared || (olist->file_info.ptr.shared && ((H5F_t*)obj_ptr)->shared == olist->file_info.ptr.shared) ))) {
+ add_obj = TRUE;
+ } /* end if */
+ } /* end if */
+ else { /* either count opened object IDs or put the IDs on the list */
+ H5O_loc_t *oloc; /* Group entry info for object */
+
+ switch(olist->obj_type) {
+ case H5I_ATTR:
+ oloc = H5A_oloc((H5A_t *)obj_ptr);
+ break;
+
+ case H5I_GROUP:
+ oloc = H5G_oloc((H5G_t *)obj_ptr);
+ break;
+
+ case H5I_DATASET:
+ oloc = H5D_oloc((H5D_t *)obj_ptr);
+ break;
+
+ case H5I_DATATYPE:
+ if(H5T_is_named((H5T_t*)obj_ptr)==TRUE)
+ oloc = H5T_oloc((H5T_t*)obj_ptr);
+ else
+ oloc = NULL;
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "unknown data object")
+ } /* end switch */
+
+ if((olist->file_info.local &&
+ ( (!olist->file_info.ptr.file && olist->obj_type == H5I_DATATYPE && H5T_is_immutable((H5T_t *)obj_ptr) == FALSE)
+ || (!olist->file_info.ptr.file && olist->obj_type != H5I_DATATYPE)
+ || (oloc && oloc->file == olist->file_info.ptr.file)))
+ || (!olist->file_info.local &&
+ ((!olist->file_info.ptr.shared && olist->obj_type == H5I_DATATYPE && H5T_is_immutable((H5T_t *)obj_ptr) == FALSE)
+ || (!olist->file_info.ptr.shared && olist->obj_type != H5I_DATATYPE)
+ || (oloc && oloc->file && oloc->file->shared == olist->file_info.ptr.shared)))) {
+ add_obj = TRUE;
+ } /* end if */
+ } /* end else */
+
+ if(add_obj) {
+ /* Add the object's ID to the ID list, if appropriate */
+ if(olist->obj_id_list) {
+ olist->obj_id_list[olist->list_index] = obj_id;
+ olist->list_index++;
+ } /* end if */
+
+ /* Increment the number of open objects */
+ if(olist->obj_id_count)
+ (*olist->obj_id_count)++;
+
+ /* Check if we've filled up the array. Return H5_ITER_STOP only if
+ * we have filled up the array. Otherwise return H5_ITER_CONT(RET_VALUE is
+ * preset to H5_ITER_CONT) because H5I_iterate needs the return value of
+ * H5_ITER_CONT to continue the iteration. */
+ if(olist->max_nobjs > 0 && olist->list_index >= olist->max_nobjs)
+ HGOTO_DONE(H5_ITER_STOP) /* Indicate that the iterator should stop */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_objects_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__is_hdf5
+ *
+ * Purpose: Check the file signature to detect an HDF5 file.
+ *
+ * Bugs: This function is not robust: it only uses the default file
+ * driver when attempting to open the file when in fact it
+ * should use all known file drivers.
+ *
+ * Return: Success: TRUE/FALSE
+ *
+ * Failure: Negative
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5F__is_hdf5(const char *name, hid_t meta_dxpl_id, hid_t raw_dxpl_id)
+{
+ H5FD_t *file = NULL; /* Low-level file struct */
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ haddr_t sig_addr; /* Addess of hdf5 file signature */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Open the file at the virtual file layer */
+ if(NULL == (file = H5FD_open(name, H5F_ACC_RDONLY, H5P_FILE_ACCESS_DEFAULT, HADDR_UNDEF)))
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to open file")
+
+ /* Set up the file driver info */
+ fdio_info.file = file;
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(meta_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(raw_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
+
+ /* The file is an hdf5 file if the hdf5 file signature can be found */
+ if(H5FD_locate_signature(&fdio_info, &sig_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_NOTHDF5, FAIL, "unable to locate file signature")
+ ret_value = (HADDR_UNDEF != sig_addr);
+
+done:
+ /* Close the file */
+ if(file)
+ if(H5FD_close(file) < 0 && ret_value >= 0)
+ HDONE_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__is_hdf5() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_new
+ *
+ * Purpose: Creates a new file object and initializes it. The
+ * H5Fopen and H5Fcreate functions then fill in various
+ * fields. If SHARED is a non-null pointer then the shared info
+ * to which it points has the reference count incremented.
+ * Otherwise a new, empty shared info struct is created and
+ * initialized with the specified file access property list.
+ *
+ * Errors:
+ *
+ * Return: Success: Ptr to a new file struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5F_new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf)
+{
+ H5F_t *f = NULL, *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(NULL == (f = H5FL_CALLOC(H5F_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate top file structure")
+ f->file_id = -1;
+
+ if(shared) {
+ HDassert(lf == NULL);
+ f->shared = shared;
+ } /* end if */
+ else {
+ H5P_genplist_t *plist; /* Property list */
+ unsigned efc_size; /* External file cache size */
+ hbool_t latest_format; /* Always use the latest format? */
+ size_t u; /* Local index variable */
+
+ HDassert(lf != NULL);
+ if(NULL == (f->shared = H5FL_CALLOC(H5F_file_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate shared file structure")
+
+ f->shared->flags = flags;
+ f->shared->sohm_addr = HADDR_UNDEF;
+ f->shared->sohm_vers = HDF5_SHAREDHEADER_VERSION;
+ f->shared->accum.loc = HADDR_UNDEF;
+ f->shared->lf = lf;
+
+ /* Initialization for handling file space */
+ for(u = 0; u < NELMTS(f->shared->fs_addr); u++) {
+ f->shared->fs_state[u] = H5F_FS_STATE_CLOSED;
+ f->shared->fs_addr[u] = HADDR_UNDEF;
+ f->shared->fs_man[u] = NULL;
+ } /* end for */
+ f->shared->first_alloc_dealloc = FALSE;
+ f->shared->eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+ f->shared->eoa_post_fsm_fsalloc = HADDR_UNDEF;
+ f->shared->eoa_post_mdci_fsalloc = HADDR_UNDEF;
+
+ /* Initialization for handling file space (for paged aggregation) */
+ f->shared->pgend_meta_thres = H5F_FILE_SPACE_PGEND_META_THRES;
+
+ /* intialize point of no return */
+ f->shared->point_of_no_return = FALSE;
+
+ /*
+ * Copy the file creation and file access property lists into the
+ * new file handle. We do this early because some values might need
+ * to change as the file is being opened.
+ */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not property list")
+ f->shared->fcpl_id = H5P_copy_plist(plist, FALSE);
+
+ /* Get the FCPL values to cache */
+ if(H5P_get(plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &f->shared->sizeof_addr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get byte number for address")
+ if(H5P_get(plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &f->shared->sizeof_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get byte number for object size")
+ if(H5P_get(plist, H5F_CRT_SHMSG_NINDEXES_NAME, &f->shared->sohm_nindexes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get number of SOHM indexes")
+ HDassert(f->shared->sohm_nindexes < 255);
+ if(H5P_get(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &f->shared->fs_strategy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space strategy")
+ if(H5P_get(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &f->shared->fs_persist) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space persisting status")
+ if(H5P_get(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &f->shared->fs_threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get free-space section threshold")
+ if(H5P_get(plist, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, &f->shared->fs_page_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space page size")
+ HDassert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN);
+
+ /* Temporary for multi/split drivers: fail file creation
+ when persisting free-space or using paged aggregation strategy */
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_PAGED_AGGR))
+ if(f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE || f->shared->fs_persist)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't open with this strategy or persistent fs")
+
+ /* Get the FAPL values to cache */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not file access property list")
+ if(H5P_get(plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, &(f->shared->mdc_initCacheCfg)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial metadata cache resize config")
+ if(H5P_get(plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(f->shared->rdcc_nslots)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get data cache number of slots")
+ if(H5P_get(plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(f->shared->rdcc_nbytes)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get data cache byte size")
+ if(H5P_get(plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, &(f->shared->rdcc_w0)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get preempt read chunk")
+ if(H5P_get(plist, H5F_ACS_ALIGN_THRHD_NAME, &(f->shared->threshold)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment threshold")
+ if(H5P_get(plist, H5F_ACS_ALIGN_NAME, &(f->shared->alignment)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment")
+ if(H5P_get(plist, H5F_ACS_GARBG_COLCT_REF_NAME,&(f->shared->gc_ref)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get garbage collect reference")
+ if(H5P_get(plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, &(f->shared->sieve_buf_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get sieve buffer size")
+ if(H5P_get(plist, H5F_ACS_LATEST_FORMAT_NAME, &latest_format) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'latest format' flag")
+ /* For latest format or SWMR_WRITE, activate all latest version support */
+ if(latest_format || (H5F_INTENT(f) & H5F_ACC_SWMR_WRITE))
+ f->shared->latest_flags |= H5F_LATEST_ALL_FLAGS;
+ if(H5P_get(plist, H5F_ACS_USE_MDC_LOGGING_NAME, &(f->shared->use_mdc_logging)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'use mdc logging' flag")
+ if(H5P_get(plist, H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME, &(f->shared->start_mdc_log_on_access)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'start mdc log on access' flag")
+ if(H5P_get(plist, H5F_ACS_META_BLOCK_SIZE_NAME, &(f->shared->meta_aggr.alloc_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get metadata cache size")
+ f->shared->meta_aggr.feature_flag = H5FD_FEAT_AGGREGATE_METADATA;
+ if(H5P_get(plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, &(f->shared->sdata_aggr.alloc_size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'small data' cache size")
+ f->shared->sdata_aggr.feature_flag = H5FD_FEAT_AGGREGATE_SMALLDATA;
+ if(H5P_get(plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get elink file cache size")
+ if(efc_size > 0)
+ if(NULL == (f->shared->efc = H5F_efc_create(efc_size)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't create external file cache")
+#ifdef H5_HAVE_PARALLEL
+ if(H5P_get(plist, H5_COLL_MD_READ_FLAG_NAME, &(f->coll_md_read)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get collective metadata read flag")
+ if(H5P_get(plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, &(f->coll_md_write)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get collective metadata write flag")
+#endif /* H5_HAVE_PARALLEL */
+ if(H5P_get(plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, &(f->shared->mdc_initCacheImageCfg)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial metadata cache resize config")
+
+ /* Get the VFD values to cache */
+ f->shared->maxaddr = H5FD_get_maxaddr(lf);
+ if(!H5F_addr_defined(f->shared->maxaddr))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad maximum address from VFD")
+ if(H5FD_get_feature_flags(lf, &f->shared->feature_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get feature flags from VFD")
+
+ /* Require the SWMR feature flag if SWMR I/O is desired */
+ if(!H5F_HAS_FEATURE(f, H5FD_FEAT_SUPPORTS_SWMR_IO) && (H5F_INTENT(f) & (H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ)))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "must use a SWMR-compatible VFD when SWMR is specified")
+
+ /* Require a POSIX compatible VFD to use SWMR feature */
+ /* (It's reasonable to try to expand this to other VFDs eventually -QAK) */
+ if(!H5F_HAS_FEATURE(f, H5FD_FEAT_POSIX_COMPAT_HANDLE) && (H5F_INTENT(f) & (H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ)))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "must use POSIX compatible VFD with SWMR write access")
+ if(H5FD_get_fs_type_map(lf, f->shared->fs_type_map) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get free space type mapping from VFD")
+ if(H5MF_init_merge_flags(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "problem initializing free space merge flags")
+ f->shared->tmp_addr = f->shared->maxaddr;
+ /* Disable temp. space allocation for parallel I/O (for now) */
+ /* (When we've arranged to have the relocated metadata addresses (and
+ * sizes) broadcast during the "end of epoch" metadata operations,
+ * this can be enabled - QAK)
+ */
+ /* (This should be disabled when the metadata journaling branch is
+ * merged into the trunk and journaling is enabled, at least until
+ * we make it work. - QAK)
+ */
+ f->shared->use_tmp_space = !H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI);
+
+ /* Retrieve the # of read attempts here so that sohm in superblock will get the correct # of attempts */
+ if(H5P_get(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &f->shared->read_attempts) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get the # of read attempts")
+
+ /* When opening file with SWMR access, the # of read attempts is H5F_SWMR_METADATA_READ_ATTEMPTS if not set */
+ /* When opening file without SWMR access, the # of read attempts is always H5F_METADATA_READ_ATTEMPTS (set or not set) */
+ if(H5F_INTENT(f) & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)) {
+ /* If no value for read attempts has been set, use the default */
+ if(!f->shared->read_attempts)
+ f->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS;
+
+ /* Turn off accumulator with SWMR */
+ f->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(f->shared->lf, f->shared->feature_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't set feature_flags in VFD")
+ } /* end if */
+ else {
+ /* If no value for read attempts has been set, use the default */
+ if(!f->shared->read_attempts)
+ f->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS;
+ } /* end else */
+
+ /* Determine the # of bins for metdata read retries */
+ if(H5F_set_retries(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't set retries and retries_nbins")
+
+ /* Get the metadata cache log location (if we're logging) */
+ {
+ char *mdc_log_location = NULL; /* location of metadata cache log location */
+
+ if(H5P_get(plist, H5F_ACS_MDC_LOG_LOCATION_NAME, &mdc_log_location) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get mdc log location")
+ if(mdc_log_location != NULL) {
+ size_t len = HDstrlen(mdc_log_location);
+ if(NULL == (f->shared->mdc_log_location = (char *)H5MM_calloc((len + 1) * sizeof(char))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate memory for mdc log file name")
+ HDstrncpy(f->shared->mdc_log_location, mdc_log_location, len);
+ }
+ else
+ f->shared->mdc_log_location = NULL;
+ } /* end block */
+
+ /* Get object flush callback information */
+ if(H5P_get(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &(f->shared->object_flush)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get object flush cb info")
+
+ /*
+ * Create a metadata cache with the specified number of elements.
+ * The cache might be created with a different number of elements and
+ * the access property list should be updated to reflect that.
+ */
+ if(H5AC_create(f, &(f->shared->mdc_initCacheCfg), &(f->shared->mdc_initCacheImageCfg)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create metadata cache")
+
+ /* Create the file's "open object" information */
+ if(H5FO_create(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure")
+
+ /* Add new "shared" struct to list of open files */
+ if(H5F_sfile_add(f->shared) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to append to list of open files")
+ } /* end else */
+
+ f->shared->nrefs++;
+
+ /* Create the file's "top open object" information */
+ if(H5FO_top_create(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure")
+
+ /* Set return value */
+ ret_value = f;
+
+done:
+ if(!ret_value && f) {
+ if(!shared) {
+ /* Attempt to clean up some of the shared file structures */
+ if(f->shared->efc)
+ if(H5F_efc_destroy(f->shared->efc) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, NULL, "can't destroy external file cache")
+ if(f->shared->fcpl_id > 0)
+ if(H5I_dec_ref(f->shared->fcpl_id) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTDEC, NULL, "can't close property list")
+
+ f->shared = H5FL_FREE(H5F_file_t, f->shared);
+ } /* end if */
+ f = H5FL_FREE(H5F_t, f);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__dest
+ *
+ * Purpose: Destroys a file structure. This function flushes the cache
+ * but doesn't do any other cleanup other than freeing memory
+ * for the file struct. The shared info for the file is freed
+ * only when its reference count reaches zero.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__dest(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t flush)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ if(1 == f->shared->nrefs) {
+ int actype; /* metadata cache type (enum value) */
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+
+ /* Flush at this point since the file will be closed (phase 1).
+ * Only try to flush the file if it was opened with write access, and if
+ * the caller requested a flush.
+ */
+ if((H5F_ACC_RDWR & H5F_INTENT(f)) && flush)
+ if(H5F__flush_phase1(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush cached data (phase 1)")
+
+ /* Notify the metadata cache that the file is about to be closed.
+ * This allows the cache to set up for creating a metadata cache
+ * image if this has been requested.
+ */
+ if(H5AC_prep_for_file_close(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going */
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "metadata cache prep for close failed")
+
+ /* Flush at this point since the file will be closed (phase 2).
+ * Only try to flush the file if it was opened with write access, and if
+ * the caller requested a flush.
+ */
+ if((H5F_ACC_RDWR & H5F_INTENT(f)) && flush)
+ if(H5F__flush_phase2(f, meta_dxpl_id, raw_dxpl_id, TRUE) < 0)
+ /* Push error, but keep going */
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush cached data (phase 2)")
+
+ /* With the shutdown modifications, the contents of the metadata cache
+ * should be clean at this point, with the possible exception of the
+ * the superblock and superblock extension.
+ *
+ * Verify this.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* Release the external file cache */
+ if(f->shared->efc) {
+ if(H5F_efc_destroy(f->shared->efc) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't destroy external file cache")
+ f->shared->efc = NULL;
+ } /* end if */
+
+ /* With the shutdown modifications, the contents of the metadata cache
+ * should be clean at this point, with the possible exception of the
+ * the superblock and superblock extension.
+ *
+ * Verify this.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* Release objects that depend on the superblock being initialized */
+ if(f->shared->sblock) {
+ /* Shutdown file free space manager(s) */
+ /* (We should release the free space information now (before
+ * truncating the file and before the metadata cache is shut
+ * down) since the free space manager is holding some data
+ * structures in memory and also because releasing free space
+ * can shrink the file's 'eoa' value)
+ *
+ * Update 11/1/16:
+ *
+ * With recent library shutdown modifications, the free space
+ * managers should be settled and written to file at this point
+ * (assuming they are persistent). In this case, closing the
+ * free space managers should have no effect on EOA.
+ *
+ * -- JRM
+ */
+ if(H5F_ACC_RDWR & H5F_INTENT(f)) {
+ if(H5MF_close(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file free space info")
+
+ /* at this point, only the superblock and superblock
+ * extension should be dirty.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* Flush the file again (if requested), as shutting down the
+ * free space manager may dirty some data structures again.
+ */
+ if(flush) {
+ /* Clear status_flags */
+ f->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_WRITE_ACCESS);
+ f->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_SWMR_WRITE_ACCESS);
+
+ /* Mark EOA info dirty in cache, so change will get encoded */
+ if(H5F_eoa_dirty(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Release any space allocated to space aggregators,
+ * so that the eoa value corresponds to the end of the
+ * space written to in the file.
+ *
+ * At most, this should change the superblock or the
+ * superblock extension messages.
+ */
+ if(H5MF_free_aggrs(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file space")
+
+ /* Truncate the file to the current allocated size */
+ if(H5FD_truncate(f->shared->lf, meta_dxpl_id, TRUE) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "low level truncate failed")
+
+ /* at this point, only the superblock and superblock
+ * extension should be dirty.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+ } /* end if */
+ } /* end if */
+
+ /* if it exists, unpin the driver information block cache entry,
+ * since we're about to destroy the cache
+ */
+ if(f->shared->drvinfo)
+ if(H5AC_unpin_entry(f->shared->drvinfo) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin drvinfo")
+
+ /* Unpin the superblock, since we're about to destroy the cache */
+ if(H5AC_unpin_entry(f->shared->sblock) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock")
+ f->shared->sblock = NULL;
+ } /* end if */
+
+ /* with the possible exception of the superblock and superblock
+ * extension, the metadata cache should be clean at this point.
+ *
+ * Verify this.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* Remove shared file struct from list of open files */
+ if(H5F_sfile_remove(f->shared) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+
+ /* Shutdown the metadata cache */
+ if(H5AC_dest(f, meta_dxpl_id))
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+
+ /* Set up I/O info for operation */
+ fio_info.f = f;
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(meta_dxpl_id)))
+ HDONE_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HDONE_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Shutdown the page buffer cache */
+ if(H5PB_dest(&fio_info) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing page buffer cache")
+
+ /* Clean up the metadata cache log location string */
+ if(f->shared->mdc_log_location)
+ f->shared->mdc_log_location = (char *)H5MM_xfree(f->shared->mdc_log_location);
+
+ /*
+ * Do not close the root group since we didn't count it, but free
+ * the memory associated with it.
+ */
+ if(f->shared->root_grp) {
+ /* Free the root group */
+ if(H5G_root_free(f->shared->root_grp) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+ f->shared->root_grp = NULL;
+ } /* end if */
+
+ /* Destroy other components of the file */
+ if(H5F__accum_reset(&fio_info, TRUE) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+ if(H5FO_dest(f) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+ f->shared->cwfs = (struct H5HG_heap_t **)H5MM_xfree(f->shared->cwfs);
+ if(H5G_node_close(f) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file")
+
+ /* Destroy file creation properties */
+ if(H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id))
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "not a property list")
+ if(H5I_dec_ref(f->shared->fcpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close property list")
+
+ /* Close the file */
+ if(H5FD_close(f->shared->lf) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+ /* Free mount table */
+ f->shared->mtab.child = (H5F_mount_t *)H5MM_xfree(f->shared->mtab.child);
+ f->shared->mtab.nalloc = 0;
+
+ /* Clean up the metadata retries array */
+ for(actype = 0; actype < (int)H5AC_NTYPES; actype++)
+ if(f->shared->retries[actype])
+ f->shared->retries[actype] = (uint32_t *)H5MM_xfree(f->shared->retries[actype]);
+
+ /* Destroy shared file struct */
+ f->shared = (H5F_file_t *)H5FL_FREE(H5F_file_t, f->shared);
+
+ } else if(f->shared->nrefs > 0) {
+ /*
+ * There are other references to the shared part of the file.
+ * Only decrement the reference count.
+ */
+ --f->shared->nrefs;
+ }
+
+ /* Free the non-shared part of the file */
+ f->open_name = (char *)H5MM_xfree(f->open_name);
+ f->actual_name = (char *)H5MM_xfree(f->actual_name);
+ f->extpath = (char *)H5MM_xfree(f->extpath);
+ if(H5FO_top_dest(f) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file")
+ f->shared = NULL;
+ f = H5FL_FREE(H5F_t, f);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_open
+ *
+ * Purpose: Opens (or creates) a file. This function understands the
+ * following flags which are similar in nature to the Posix
+ * open(2) flags.
+ *
+ * H5F_ACC_RDWR: Open with read/write access. If the file is
+ * currently open for read-only access then it
+ * will be reopened. Absence of this flag
+ * implies read-only access.
+ *
+ * H5F_ACC_CREAT: Create a new file if it doesn't exist yet.
+ * The permissions are 0666 bit-wise AND with
+ * the current umask. H5F_ACC_WRITE must also
+ * be specified.
+ *
+ * H5F_ACC_EXCL: This flag causes H5F_open() to fail if the
+ * file already exists.
+ *
+ * H5F_ACC_TRUNC: The file is truncated and a new HDF5 superblock
+ * is written. This operation will fail if the
+ * file is already open.
+ *
+ * Unlinking the file name from the group directed graph while
+ * the file is opened causes the file to continue to exist but
+ * one will not be able to upgrade the file from read-only
+ * access to read-write access by reopening it. Disk resources
+ * for the file are released when all handles to the file are
+ * closed. NOTE: This paragraph probably only applies to Unix;
+ * deleting the file name in other OS's has undefined results.
+ *
+ * The CREATE_PARMS argument is optional. A null pointer will
+ * cause the default file creation parameters to be used.
+ *
+ * The ACCESS_PARMS argument is optional. A null pointer will
+ * cause the default file access parameters to be used.
+ *
+ * The following two tables show results of file opens for single and concurrent access:
+ *
+ * SINGLE PROCESS ACCESS CONCURRENT ACCESS
+ *
+ * #1st open# #1st open#
+ * -- SR SR -- -- SR SR -- -- SR SR -- -- SR SR --
+ * -- -- SW SW SW SW -- -- -- -- SW SW SW SW -- --
+ * W W W W R R R R W W W W R R R R
+ * #2nd open# #2nd open#
+ * -------------------------- --------------------------
+ * -- -- W | s x x s x x f f | -- -- W | f x x f x x f f |
+ * SR -- W | x x x x x x x x | SR -- W | x x x x x x x x |
+ * SR SW W | x x x x x x x x | SR SW W | x x x x x x x x |
+ * -- SW W | f x x s x x f f | -- SW W | f x x f x x f f |
+ * -- SW R | x x x x x x x x | -- SW R | x x x x x x x x |
+ * SR SW R | x x x x x x x x | SR SW R | x x x x x x x x |
+ * SR -- R | s x x s x x s f | SR -- R | f x x s x x s s |
+ * -- -- R | s x x s x x s s | -- -- R | f x x f x x s s |
+ * -------------------------- --------------------------
+ *
+ * Notations:
+ * W: H5F_ACC_RDWR
+ * R: H5F_ACC_RDONLY
+ * SW: H5F_ACC_SWMR_WRITE
+ * SR: H5F_ACC_SWMR_READ
+ *
+ * x: the first open or second open itself fails due to invalid flags combination
+ * f: the open fails with flags combination from both the first and second opens
+ * s: the open succeeds with flags combination from both the first and second opens
+ *
+ *
+ * Return: Success: A new file pointer.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, September 23, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
+ hid_t meta_dxpl_id)
+{
+ H5F_t *file = NULL; /*the success return value */
+ H5F_file_t *shared = NULL; /*shared part of `file' */
+ H5FD_t *lf = NULL; /*file driver part of `shared' */
+ unsigned tent_flags; /*tentative flags */
+ H5FD_class_t *drvr; /*file driver class info */
+ H5P_genplist_t *a_plist; /*file access property list */
+ H5F_close_degree_t fc_degree; /*file close degree */
+ hid_t raw_dxpl_id = H5AC_rawdata_dxpl_id; /* Raw data dxpl used by library */
+ size_t page_buf_size;
+ unsigned page_buf_min_meta_perc;
+ unsigned page_buf_min_raw_perc;
+ hbool_t set_flag = FALSE; /*set the status_flags in the superblock */
+ hbool_t clear = FALSE; /*clear the status_flags */
+ hbool_t evict_on_close; /* evict on close value from plist */
+ H5F_t *ret_value = NULL; /*actual return value */
+ char *lock_env_var = NULL;/*env var pointer */
+ hbool_t use_file_locking; /*read from env var */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * If the driver has a `cmp' method then the driver is capable of
+ * determining when two file handles refer to the same file and the
+ * library can insure that when the application opens a file twice
+ * that the two handles coordinate their operations appropriately.
+ * Otherwise it is the application's responsibility to never open the
+ * same file more than once at a time.
+ */
+ if(NULL == (drvr = H5FD_get_class(fapl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to retrieve VFL class")
+
+ /* Check the environment variable that determines if we care
+ * about file locking. File locking should be used unless explicitly
+ * disabled.
+ */
+ lock_env_var = HDgetenv("HDF5_USE_FILE_LOCKING");
+ if(lock_env_var && !HDstrcmp(lock_env_var, "FALSE"))
+ use_file_locking = FALSE;
+ else
+ use_file_locking = TRUE;
+
+ /*
+ * Opening a file is a two step process. First we try to open the
+ * file in a way which doesn't affect its state (like not truncating
+ * or creating it) so we can compare it with files that are already
+ * open. If that fails then we try again with the full set of flags
+ * (only if they're different than the original failed attempt).
+ * However, if the file driver can't distinquish between files then
+ * there's no reason to open the file tentatively because it's the
+ * application's responsibility to prevent this situation (there's no
+ * way for us to detect it here anyway).
+ */
+ if(drvr->cmp)
+ tent_flags = flags & ~(H5F_ACC_CREAT|H5F_ACC_TRUNC|H5F_ACC_EXCL);
+ else
+ tent_flags = flags;
+
+ if(NULL == (lf = H5FD_open(name, tent_flags, fapl_id, HADDR_UNDEF))) {
+ if(tent_flags == flags) {
+#ifndef H5_USING_MEMCHECKER
+ time_t mytime = HDtime(NULL);
+
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: time = %s, name = '%s', tent_flags = %x", HDctime(&mytime), name, tent_flags)
+#else /* H5_USING_MEMCHECKER */
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', tent_flags = %x", name, tent_flags)
+#endif /* H5_USING_MEMCHECKER */
+ } /* end if */
+ H5E_clear_stack(NULL);
+ tent_flags = flags;
+ if(NULL == (lf = H5FD_open(name, tent_flags, fapl_id, HADDR_UNDEF))) {
+#ifndef H5_USING_MEMCHECKER
+ time_t mytime = HDtime(NULL);
+
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: time = %s, name = '%s', tent_flags = %x", HDctime(&mytime), name, tent_flags)
+#else /* H5_USING_MEMCHECKER */
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', tent_flags = %x", name, tent_flags)
+#endif /* H5_USING_MEMCHECKER */
+ } /* end if */
+ } /* end if */
+
+ /* Is the file already open? */
+ if((shared = H5F_sfile_search(lf)) != NULL) {
+ /*
+ * The file is already open, so use that one instead of the one we
+ * just opened. We only one one H5FD_t* per file so one doesn't
+ * confuse the other. But fail if this request was to truncate the
+ * file (since we can't do that while the file is open), or if the
+ * request was to create a non-existent file (since the file already
+ * exists), or if the new request adds write access (since the
+ * readers don't expect the file to change under them), or if the
+ * SWMR write/read access flags don't agree.
+ */
+ if(H5FD_close(lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
+ if(flags & H5F_ACC_TRUNC)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to truncate a file which is already open")
+ if(flags & H5F_ACC_EXCL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file exists")
+ if((flags & H5F_ACC_RDWR) && 0 == (shared->flags & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for read-only")
+
+ if((flags & H5F_ACC_SWMR_WRITE) && 0 == (shared->flags & H5F_ACC_SWMR_WRITE))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "SWMR write access flag not the same for file that is already open")
+ if((flags & H5F_ACC_SWMR_READ) && !((shared->flags & H5F_ACC_SWMR_WRITE) || (shared->flags & H5F_ACC_SWMR_READ) || (shared->flags & H5F_ACC_RDWR)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "SWMR read access flag not the same for file that is already open")
+
+ /* Allocate new "high-level" file struct */
+ if((file = H5F_new(shared, flags, fcpl_id, fapl_id, NULL)) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create new file object")
+ } /* end if */
+ else {
+ /* Check if tentative open was good enough */
+ if(flags != tent_flags) {
+ /*
+ * This file is not yet open by the library and the flags we used to
+ * open it are different than the desired flags. Close the tentative
+ * file and open it for real.
+ */
+ if(H5FD_close(lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
+
+ if(NULL == (lf = H5FD_open(name, flags, fapl_id, HADDR_UNDEF)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
+ } /* end if */
+
+ /* Place an advisory lock on the file */
+ if(use_file_locking)
+ if(H5FD_lock(lf, (hbool_t)((flags & H5F_ACC_RDWR) ? TRUE : FALSE)) < 0) {
+ /* Locking failed - Closing will remove the lock */
+ if(H5FD_close(lf) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to lock the file")
+ } /* end if */
+
+ /* Create the 'top' file structure */
+ if(NULL == (file = H5F_new(NULL, flags, fcpl_id, fapl_id, lf))) {
+ /* If this is the only time the file has been opened and the struct
+ * returned is NULL, H5FD_close() will never be called via H5F_dest()
+ * so we have to close lf here before heading to the error handling.
+ */
+ if(H5FD_close(lf) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to initialize file structure")
+ } /* end if */
+
+ /* Need to set status_flags in the superblock if the driver has a 'lock' method */
+ if(drvr->lock)
+ set_flag = TRUE;
+ } /* end else */
+
+ /* Retain the name the file was opened with */
+ file->open_name = H5MM_xstrdup(name);
+
+ /* Short cuts */
+ shared = file->shared;
+ lf = shared->lf;
+
+ /* Get the file access property list, for future queries */
+ if(NULL == (a_plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not file access property list")
+
+ /* Check if page buffering is enabled */
+ if(H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, &page_buf_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get page buffer size")
+ if(page_buf_size) {
+#ifdef H5_HAVE_PARALLEL
+ /* Collective metadata writes are not supported with page buffering */
+ if(file->coll_md_write)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "collective metadata writes are not supported with page buffering")
+
+ /* Temporary: fail file create when page buffering feature is enabled for parallel */
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "page buffering is disabled for parallel")
+#endif /* H5_HAVE_PARALLEL */
+ /* Query for other page buffer cache properties */
+ if(H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, &page_buf_min_meta_perc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get minimum metadata fraction of page buffer")
+ if(H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &page_buf_min_raw_perc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get minimum raw data fraction of page buffer")
+ } /* end if */
+
+ /*
+ * Read or write the file superblock, depending on whether the file is
+ * empty or not.
+ */
+ if(0 == (MAX(H5FD_get_eof(lf, H5FD_MEM_SUPER), H5FD_get_eoa(lf, H5FD_MEM_SUPER))) && (flags & H5F_ACC_RDWR)) {
+ /*
+ * We've just opened a fresh new file (or truncated one). We need
+ * to create & write the superblock.
+ */
+
+ /* Create the page buffer before initializing the superblock */
+ if(page_buf_size)
+ if(H5PB_create(file, page_buf_size, page_buf_min_meta_perc, page_buf_min_raw_perc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create page buffer")
+
+ /* Initialize information about the superblock and allocate space for it */
+ /* (Writes superblock extension messages, if there are any) */
+ if(H5F__super_init(file, meta_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to allocate file superblock")
+
+ /* Create and open the root group */
+ /* (This must be after the space for the superblock is allocated in
+ * the file, since the superblock must be at offset 0)
+ */
+ if(H5G_mkroot(file, meta_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create/open root group")
+ } /* end if */
+ else if (1 == shared->nrefs) {
+ /* Read the superblock if it hasn't been read before. */
+ if(H5F__super_read(file, meta_dxpl_id, raw_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "unable to read superblock")
+
+ /* Create the page buffer before initializing the superblock */
+ if(page_buf_size)
+ if(H5PB_create(file, page_buf_size, page_buf_min_meta_perc, page_buf_min_raw_perc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create page buffer")
+
+ /* Open the root group */
+ if(H5G_mkroot(file, meta_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read root group")
+ } /* end if */
+
+ /*
+ * Decide the file close degree. If it's the first time to open the
+ * file, set the degree to access property list value; if it's the
+ * second time or later, verify the access property list value matches
+ * the degree in shared file structure.
+ */
+ if(H5P_get(a_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file close degree")
+
+ /* This is a private property to clear the status_flags in the super block */
+ /* Use by h5clear and a routine in test/flush2.c to clear the test file's status_flags */
+ if(H5P_exist_plist(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME) > 0) {
+ if(H5P_get(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME, &clear) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get clearance for status_flags")
+ else if(clear)
+ file->shared->sblock->status_flags = 0;
+ } /* end if */
+
+ if(shared->nrefs == 1) {
+ if(fc_degree == H5F_CLOSE_DEFAULT)
+ shared->fc_degree = lf->cls->fc_degree;
+ else
+ shared->fc_degree = fc_degree;
+ } /* end if */
+ else if(shared->nrefs > 1) {
+ if(fc_degree == H5F_CLOSE_DEFAULT && shared->fc_degree != lf->cls->fc_degree)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "file close degree doesn't match")
+ if(fc_degree != H5F_CLOSE_DEFAULT && fc_degree != shared->fc_degree)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "file close degree doesn't match")
+ } /* end if */
+
+ /* Record the evict-on-close MDC behavior. If it's the first time opening
+ * the file, set it to access property list value; if it's the second time
+ * or later, verify that the access property list value matches the value
+ * in shared file structure.
+ */
+ if(H5P_get(a_plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, &evict_on_close) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get evict on close value")
+ if(shared->nrefs == 1)
+ shared->evict_on_close = evict_on_close;
+ else if(shared->nrefs > 1) {
+ if(shared->evict_on_close != evict_on_close)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "file evict-on-close value doesn't match")
+ } /* end if */
+
+ /* Formulate the absolute path for later search of target file for external links */
+ if(H5_build_extpath(name, &file->extpath) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build extpath")
+
+ /* Formulate the actual file name, after following symlinks, etc. */
+ if(H5F_build_actual_name(file, a_plist, name, &file->actual_name) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build actual name")
+
+ if(set_flag) {
+ if(H5F_INTENT(file) & H5F_ACC_RDWR) { /* Set and check consistency of status_flags */
+ /* Skip check of status_flags for file with < superblock version 3 */
+ if(file->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3) {
+
+ if(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS ||
+ file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for write/SWMR write (may use <h5clear file> to clear file consistency flags)")
+ } /* version 3 superblock */
+
+ file->shared->sblock->status_flags |= H5F_SUPER_WRITE_ACCESS;
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_WRITE)
+ file->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS;
+
+ /* Flush the superblock */
+ if(H5F_super_dirty(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, NULL, "unable to mark superblock as dirty")
+ if(H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG, meta_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, NULL, "unable to flush superblock")
+
+ /* Remove the file lock for SWMR_WRITE */
+ if(use_file_locking && (H5F_INTENT(file) & H5F_ACC_SWMR_WRITE)) {
+ if(H5FD_unlock(file->shared->lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to unlock the file")
+ } /* end if */
+ } /* end if */
+ else { /* H5F_ACC_RDONLY: check consistency of status_flags */
+ /* Skip check of status_flags for file with < superblock version 3 */
+ if(file->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3) {
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_READ) {
+ if((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS &&
+ !(file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ ||
+ (!(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) &&
+ file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is not already open for SWMR writing")
+ } /* end if */
+ else if((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) ||
+ (file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for write (may use <h5clear file> to clear file consistency flags)")
+ } /* version 3 superblock */
+ } /* end else */
+ } /* end if set_flag */
+
+ /* Success */
+ ret_value = file;
+
+done:
+ if((NULL == ret_value) && file)
+ if(H5F__dest(file, meta_dxpl_id, raw_dxpl_id, FALSE) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "problems closing file")
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_flush_phase1
+ *
+ * Purpose: First phase of flushing cached data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Jan 1 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__flush_phase1(H5F_t *f, hid_t meta_dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check arguments */
+ HDassert(f);
+
+ /* Flush any cached dataset storage raw data */
+ if(H5D_flush(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush dataset cache")
+
+ /* Release any space allocated to space aggregators, so that the eoa value
+ * corresponds to the end of the space written to in the file.
+ */
+ /* (needs to happen before cache flush, with superblock write, since the
+ * 'eoa' value is written in superblock -QAK)
+ */
+ if(H5MF_free_aggrs(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file space")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__flush_phase1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__flush_phase2
+ *
+ * Purpose: Second phase of flushing cached data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Jan 1 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__flush_phase2(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t closing)
+{
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check arguments */
+ HDassert(f);
+
+ /* Flush the entire metadata cache */
+ if(H5AC_flush(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush metadata cache")
+
+ /* Truncate the file to the current allocated size */
+ if(H5FD_truncate(f->shared->lf, meta_dxpl_id, closing) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "low level truncate failed")
+
+ /* Flush the entire metadata cache again since the EOA could have changed in the truncate call. */
+ if(H5AC_flush(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush metadata cache")
+
+ /* Set up I/O info for operation */
+ fio_info.f = f;
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(meta_dxpl_id)))
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(raw_dxpl_id)))
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Flush out the metadata accumulator */
+ if(H5F__accum_flush(&fio_info) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush metadata accumulator")
+
+ /* Flush the page buffer */
+ if(H5PB_flush(&fio_info) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "page buffer flush failed")
+
+ /* Flush file buffers to disk. */
+ if(H5FD_flush(f->shared->lf, meta_dxpl_id, closing) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "low level flush failed")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__flush_phase2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__flush
+ *
+ * Purpose: Flushes cached data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 29 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__flush(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t closing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check arguments */
+ HDassert(f);
+
+ /* First phase of flushing data */
+ if(H5F__flush_phase1(f, meta_dxpl_id) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush file data")
+
+ /* Second phase of flushing data */
+ if(H5F__flush_phase2(f, meta_dxpl_id, raw_dxpl_id, closing) < 0)
+ /* Push error, but keep going*/
+ HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush file data")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_close
+ *
+ * Purpose: Closes a file or causes the close operation to be pended.
+ * This function is called two ways: from the API it gets called
+ * by H5Fclose->H5I_dec_ref->H5F_close when H5I_dec_ref()
+ * decrements the file ID reference count to zero. The file ID
+ * is removed from the H5I_FILE group by H5I_dec_ref() just
+ * before H5F_close() is called. If there are open object
+ * headers then the close is pended by moving the file to the
+ * H5I_FILE_CLOSING ID group (the f->closing contains the ID
+ * assigned to file).
+ *
+ * This function is also called directly from H5O_close() when
+ * the last object header is closed for the file and the file
+ * has a pending close.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, September 23, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_close(H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->file_id > 0); /* This routine should only be called when a file ID's ref count drops to zero */
+
+ /* Perform checks for "semi" file close degree here, since closing the
+ * file is not allowed if there are objects still open */
+ if(f->shared->fc_degree == H5F_CLOSE_SEMI) {
+ unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */
+ unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */
+
+ /* Get the number of open objects and open files on this file/mount hierarchy */
+ if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy")
+
+ /* If there are no other file IDs open on this file/mount hier., but
+ * there are still open objects, issue an error and bail out now,
+ * without decrementing the file ID's reference count and triggering
+ * a "real" attempt at closing the file */
+ if(nopen_files == 1 && nopen_objs > 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open")
+ } /* end if */
+
+ /* Reset the file ID for this file */
+ f->file_id = -1;
+
+ /* Attempt to close the file/mount hierarchy */
+ if(H5F_try_close(f, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_try_close
+ *
+ * Purpose: Attempts to close a file due to one of several actions:
+ * - The reference count on the file ID dropped to zero
+ * - The last open object was closed in the file
+ * - The file was unmounted
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_try_close(H5F_t *f, hbool_t *was_closed /*out*/)
+{
+ unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */
+ unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Set the was_closed flag to the default value.
+ * This flag lets downstream code know if the file struct is
+ * still accessible and/or likely to contain useful data.
+ * It's needed by the evict-on-close code. Clients can ignore
+ * this value by passing in NULL.
+ */
+ if(was_closed)
+ *was_closed = FALSE;
+
+ /* Check if this file is already in the process of closing */
+ if(f->closing) {
+ if(was_closed)
+ *was_closed = TRUE;
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Get the number of open objects and open files on this file/mount hierarchy */
+ if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy")
+
+ /*
+ * Close file according to close degree:
+ *
+ * H5F_CLOSE_WEAK: if there are still objects open, wait until
+ * they are all closed.
+ * H5F_CLOSE_SEMI: if there are still objects open, return fail;
+ * otherwise, close file.
+ * H5F_CLOSE_STRONG: if there are still objects open, close them
+ * first, then close file.
+ */
+ switch(f->shared->fc_degree) {
+ case H5F_CLOSE_WEAK:
+ /*
+ * If file or object IDS are still open then delay deletion of
+ * resources until they have all been closed. Flush all
+ * caches and update the object header anyway so that failing to
+ * close all objects isn't a major problem.
+ */
+ if((nopen_files + nopen_objs) > 0)
+ HGOTO_DONE(SUCCEED)
+ break;
+
+ case H5F_CLOSE_SEMI:
+ /* Can leave safely if file IDs are still open on this file */
+ if(nopen_files > 0)
+ HGOTO_DONE(SUCCEED)
+
+ /* Sanity check: If close degree if "semi" and we have gotten this
+ * far and there are objects left open, bail out now */
+ HDassert(nopen_files == 0 && nopen_objs == 0);
+
+ /* If we've gotten this far (ie. there are no open objects in the file), fall through to flush & close */
+ break;
+
+ case H5F_CLOSE_STRONG:
+ /* If there are other open files in the hierarchy, we can leave now */
+ if(nopen_files > 0)
+ HGOTO_DONE(SUCCEED)
+
+ /* If we've gotten this far (ie. there are no open file IDs in the file/mount hierarchy), fall through to flush & close */
+ break;
+
+ case H5F_CLOSE_DEFAULT:
+ default:
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, unknown file close degree")
+ } /* end switch */
+
+ /* Mark this file as closing (prevents re-entering file shutdown code below) */
+ f->closing = TRUE;
+
+ /* If the file close degree is "strong", close all the open objects in this file */
+ if(f->shared->fc_degree == H5F_CLOSE_STRONG) {
+ HDassert(nopen_files == 0);
+
+ /* Forced close of all opened objects in this file */
+ if(f->nopen_objs > 0) {
+ size_t obj_count; /* # of open objects */
+ hid_t objs[128]; /* Array of objects to close */
+ herr_t result; /* Local result from obj ID query */
+ size_t u; /* Local index variable */
+
+ /* Get the list of IDs of open dataset, group, & attribute objects */
+ while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_ATTR, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0
+ && obj_count != 0 ) {
+
+ /* Try to close all the open objects in this file */
+ for(u = 0; u < obj_count; u++)
+ if(H5I_dec_ref(objs[u]) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object")
+ } /* end while */
+ if(result < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(1)")
+
+ /* Get the list of IDs of open named datatype objects */
+ /* (Do this separately from the dataset & attribute IDs, because
+ * they could be using one of the named datatypes and then the
+ * open named datatype ID will get closed twice)
+ */
+ while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATATYPE, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0
+ && obj_count != 0) {
+
+ /* Try to close all the open objects in this file */
+ for(u = 0; u < obj_count; u++)
+ if(H5I_dec_ref(objs[u]) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object")
+ } /* end while */
+ if(result < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(2)")
+ } /* end if */
+ } /* end if */
+
+ /* Check if this is a child file in a mounting hierarchy & proceed up the
+ * hierarchy if so.
+ */
+ if(f->parent)
+ if(H5F_try_close(f->parent, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close parent file")
+
+ /* Unmount and close each child before closing the current file. */
+ if(H5F_close_mounts(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child files")
+
+ /* If there is more than one reference to the shared file struct and the
+ * file has an external file cache, we should see if it can be closed. This
+ * can happen if a cycle is formed with external file caches */
+ if(f->shared->efc && (f->shared->nrefs > 1))
+ if(H5F_efc_try_close(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't attempt to close EFC")
+
+ /* Delay flush until the shared file struct is closed, in H5F__dest. If the
+ * application called H5Fclose, it would have been flushed in that function
+ * (unless it will have been flushed in H5F_dest anyways). */
+
+ /*
+ * Destroy the H5F_t struct and decrement the reference count for the
+ * shared H5F_file_t struct. If the reference count for the H5F_file_t
+ * struct reaches zero then destroy it also.
+ */
+ if(H5F__dest(f, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file")
+
+ /* Since we closed the file, this should be set to TRUE */
+ if(was_closed)
+ *was_closed = TRUE;
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_try_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_id
+ *
+ * Purpose: Get the file ID, incrementing it, or "resurrecting" it as
+ * appropriate.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Oct 29, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5F_get_id(H5F_t *file, hbool_t app_ref)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(file->file_id == -1) {
+ /* Get an atom for the file */
+ if((file->file_id = H5I_register(H5I_FILE, file, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file")
+ } else {
+ /* Increment reference count on atom. */
+ if(H5I_inc_ref(file->file_id, app_ref) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTSET, FAIL, "incrementing file ID failed")
+ } /* end else */
+
+ ret_value = file->file_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_incr_nopen_objs
+ *
+ * Purpose: Increment the number of open objects for a file.
+ *
+ * Return: Success: The number of open objects, after the increment
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_incr_nopen_objs(H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(++f->nopen_objs)
+} /* end H5F_incr_nopen_objs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_decr_nopen_objs
+ *
+ * Purpose: Decrement the number of open objects for a file.
+ *
+ * Return: Success: The number of open objects, after the decrement
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_decr_nopen_objs(H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(--f->nopen_objs)
+} /* end H5F_decr_nopen_objs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_build_actual_name
+ *
+ * Purpose: Retrieve the name of a file, after following symlinks, etc.
+ *
+ * Note: Currently only working for "POSIX I/O compatible" VFDs
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * November 25, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl, const char *name,
+ char **actual_name/*out*/)
+{
+ hid_t new_fapl_id = -1; /* ID for duplicated FAPL */
+#ifdef H5_HAVE_SYMLINK
+ /* This has to be declared here to avoid unfreed resources on errors */
+ char *realname = NULL; /* Fully resolved path name of file */
+#endif /* H5_HAVE_SYMLINK */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(fapl);
+ HDassert(name);
+ HDassert(actual_name);
+
+ /* Clear actual name pointer to begin with */
+ *actual_name = NULL;
+
+/* Assume that if the OS can't create symlinks, that we don't need to worry
+ * about resolving them either. -QAK
+ */
+#ifdef H5_HAVE_SYMLINK
+ /* Check for POSIX I/O compatible file handle */
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_POSIX_COMPAT_HANDLE)) {
+ h5_stat_t lst; /* Stat info from lstat() call */
+
+ /* Call lstat() on the file's name */
+ if(HDlstat(name, &lst) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve stat info for file")
+
+ /* Check for symbolic link */
+ if(S_IFLNK == (lst.st_mode & S_IFMT)) {
+ H5P_genplist_t *new_fapl; /* Duplicated FAPL */
+ int *fd; /* POSIX I/O file descriptor */
+ h5_stat_t st; /* Stat info from stat() call */
+ h5_stat_t fst; /* Stat info from fstat() call */
+ hbool_t want_posix_fd; /* Flag for retrieving file descriptor from VFD */
+
+ /* Allocate realname buffer */
+ if(NULL == (realname = (char *)H5MM_calloc((size_t)PATH_MAX * sizeof(char))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Perform a sanity check that the file or link wasn't switched
+ * between when we opened it and when we called lstat(). This is
+ * according to the security best practices for lstat() documented
+ * here: https://www.securecoding.cert.org/confluence/display/seccode/POS35-C.+Avoid+race+conditions+while+checking+for+the+existence+of+a+symbolic+link
+ */
+
+ /* Copy the FAPL object to modify */
+ if((new_fapl_id = H5P_copy_plist(fapl, FALSE)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy file access property list")
+ if(NULL == (new_fapl = (H5P_genplist_t *)H5I_object(new_fapl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "can't get property list")
+
+ /* Set the character encoding on the new property list */
+ want_posix_fd = TRUE;
+ if(H5P_set(new_fapl, H5F_ACS_WANT_POSIX_FD_NAME, &want_posix_fd) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set character encoding")
+
+ /* Retrieve the file handle */
+ if(H5F_get_vfd_handle(f, new_fapl_id, (void **)&fd) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve POSIX file descriptor")
+
+ /* Stat the filename we're resolving */
+ if(HDstat(name, &st) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to stat file")
+
+ /* Stat the file we opened */
+ if(HDfstat(*fd, &fst) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to fstat file")
+
+ /* Verify that the files are really the same */
+ if(st.st_mode != fst.st_mode || st.st_ino != fst.st_ino || st.st_dev != fst.st_dev)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "files' st_ino or st_dev fields changed!")
+
+ /* Get the resolved path for the file name */
+ if(NULL == HDrealpath(name, realname))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve real path for file")
+
+ /* Duplicate the resolved path for the file name */
+ if(NULL == (*actual_name = (char *)H5MM_strdup(realname)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate real path")
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_SYMLINK */
+
+ /* Check if we've resolved the file's name */
+ if(NULL == *actual_name) {
+ /* Just duplicate the name used to open the file */
+ if(NULL == (*actual_name = (char *)H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate open name")
+ } /* end else */
+
+done:
+ /* Close the property list */
+ if(new_fapl_id > 0)
+ if(H5I_dec_app_ref(new_fapl_id) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close duplicated FAPL")
+#ifdef H5_HAVE_SYMLINK
+ if(realname)
+ realname = (char *)H5MM_xfree(realname);
+#endif /* H5_HAVE_SYMLINK */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_build_actual_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_addr_encode_len
+ *
+ * Purpose: Encodes an address into the buffer pointed to by *PP and
+ * then increments the pointer to the first byte after the
+ * address. An undefined value is stored as all 1's.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 7, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_addr_encode_len(size_t addr_len, uint8_t **pp/*in,out*/, haddr_t addr)
+{
+ unsigned u; /* Local index variable */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(addr_len);
+ HDassert(pp && *pp);
+
+ if(H5F_addr_defined(addr)) {
+ for(u = 0; u < addr_len; u++) {
+ *(*pp)++ = (uint8_t)(addr & 0xff);
+ addr >>= 8;
+ } /* end for */
+ HDassert("overflow" && 0 == addr);
+ } /* end if */
+ else {
+ for(u = 0; u < addr_len; u++)
+ *(*pp)++ = 0xff;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_addr_encode_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_addr_encode
+ *
+ * Purpose: Encodes an address into the buffer pointed to by *PP and
+ * then increments the pointer to the first byte after the
+ * address. An undefined value is stored as all 1's.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 7, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_addr_encode(const H5F_t *f, uint8_t **pp/*in,out*/, haddr_t addr)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ H5F_addr_encode_len(H5F_SIZEOF_ADDR(f), pp, addr);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_addr_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_addr_decode_len
+ *
+ * Purpose: Decodes an address from the buffer pointed to by *PP and
+ * updates the pointer to point to the next byte after the
+ * address.
+ *
+ * If the value read is all 1's then the address is returned
+ * with an undefined value.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 7, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_addr_decode_len(size_t addr_len, const uint8_t **pp/*in,out*/, haddr_t *addr_p/*out*/)
+{
+ hbool_t all_zero = TRUE; /* True if address was all zeroes */
+ unsigned u; /* Local index variable */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(addr_len);
+ HDassert(pp && *pp);
+ HDassert(addr_p);
+
+ /* Reset value in destination */
+ *addr_p = 0;
+
+ /* Decode bytes from address */
+ for(u = 0; u < addr_len; u++) {
+ uint8_t c; /* Local decoded byte */
+
+ /* Get decoded byte (and advance pointer) */
+ c = *(*pp)++;
+
+ /* Check for non-undefined address byte value */
+ if(c != 0xff)
+ all_zero = FALSE;
+
+ if(u < sizeof(*addr_p)) {
+ haddr_t tmp = c; /* Local copy of address, for casting */
+
+ /* Shift decoded byte to correct position */
+ tmp <<= (u * 8); /*use tmp to get casting right */
+
+ /* Merge into already decoded bytes */
+ *addr_p |= tmp;
+ } /* end if */
+ else
+ if(!all_zero)
+ HDassert(0 == **pp); /*overflow */
+ } /* end for */
+
+ /* If 'all_zero' is still TRUE, the address was entirely composed of '0xff'
+ * bytes, which is the encoded form of 'HADDR_UNDEF', so set the destination
+ * to that value */
+ if(all_zero)
+ *addr_p = HADDR_UNDEF;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_addr_decode_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_addr_decode
+ *
+ * Purpose: Decodes an address from the buffer pointed to by *PP and
+ * updates the pointer to point to the next byte after the
+ * address.
+ *
+ * If the value read is all 1's then the address is returned
+ * with an undefined value.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 7, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_addr_decode(const H5F_t *f, const uint8_t **pp/*in,out*/, haddr_t *addr_p/*out*/)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ H5F_addr_decode_len(H5F_SIZEOF_ADDR(f), pp, addr_p);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_addr_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_grp_btree_shared
+ *
+ * Purpose: Set the grp_btree_shared field with a valid ref-count pointer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 7/19/11
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_grp_btree_shared(H5F_t *f, H5UC_t *rc)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(rc);
+
+ f->shared->grp_btree_shared = rc;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_grp_btree_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_sohm_addr
+ *
+ * Purpose: Set the sohm_addr field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 7/20/11
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_sohm_addr(H5F_t *f, haddr_t addr)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ f->shared->sohm_addr = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_sohm_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_sohm_vers
+ *
+ * Purpose: Set the sohm_vers field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 7/20/11
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_sohm_vers(H5F_t *f, unsigned vers)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ f->shared->sohm_vers = vers;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_sohm_vers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_sohm_nindexes
+ *
+ * Purpose: Set the sohm_nindexes field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 7/20/11
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_sohm_nindexes(H5F_t *f, unsigned nindexes)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ f->shared->sohm_nindexes = nindexes;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_sohm_nindexes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_store_msg_crt_idx
+ *
+ * Purpose: Set the store_msg_crt_idx field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 7/20/11
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_store_msg_crt_idx(H5F_t *f, hbool_t flag)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ f->shared->store_msg_crt_idx = flag;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_store_msg_crt_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_file_image
+ *
+ * Purpose: Private version of H5Fget_file_image
+ *
+ * Return: Success: Bytes copied / number of bytes needed.
+ * Failure: negative value
+ *
+ * Programmer: John Mainzer
+ * 11/15/11
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5F_get_file_image(H5F_t *file, void *buf_ptr, size_t buf_len, hid_t meta_dxpl_id,
+ hid_t raw_dxpl_id)
+{
+ H5FD_t *fd_ptr; /* file driver */
+ haddr_t eoa; /* End of file address */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ if(!file || !file->shared || !file->shared->lf)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file_id yields invalid file pointer")
+ fd_ptr = file->shared->lf;
+ if(!fd_ptr->cls)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "fd_ptr yields invalid class pointer")
+
+ /* the address space used by the split and multi file drivers is not
+ * a good fit for this call. Since the plan is to depreciate these
+ * drivers anyway, don't bother to do a "force fit".
+ *
+ * The following clause tests for the multi file driver, and fails
+ * if the supplied file has the multi file driver as its top level
+ * file driver. However, this test will not work if there is some
+ * other file driver sitting on top of the multi file driver.
+ *
+ * I'm not sure if this is possible at present, but in all likelyhood,
+ * it will become possible in the future. On the other hand, we may
+ * remove the split/multi file drivers before then.
+ *
+ * I am leaving this solution in for now, but we should review it,
+ * and improve the solution if necessary.
+ *
+ * JRM -- 11/11/22
+ */
+ if(HDstrcmp(fd_ptr->cls->name, "multi") == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not supported for multi file driver.")
+
+ /* While the family file driver is conceptually fully compatible
+ * with the get file image operation, it sets a file driver message
+ * in the super block that prevents the image being opened with any
+ * driver other than the family file driver. Needless to say, this
+ * rather defeats the purpose of the get file image operation.
+ *
+ * While this problem is quire solvable, the required time and
+ * resources are lacking at present. Hence, for now, we don't
+ * allow the get file image operation to be perfomed on files
+ * opened with the family file driver.
+ *
+ * Observe that the following test only looks at the top level
+ * driver, and fails if there is some other driver sitting on to
+ * of the family file driver.
+ *
+ * I don't think this can happen at present, but that may change
+ * in the future.
+ * JRM -- 12/21/11
+ */
+ if(HDstrcmp(fd_ptr->cls->name, "family") == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "Not supported for family file driver.")
+
+ /* Go get the actual file size */
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(file->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* set ret_value = to eoa -- will overwrite this if appropriate */
+ ret_value = (ssize_t)eoa;
+
+ /* test to see if a buffer was provided -- if not, we are done */
+ if(buf_ptr != NULL) {
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ size_t space_needed; /* size of file image */
+ hsize_t tmp;
+ size_t tmp_size;
+
+ /* Check for buffer too small */
+ if((haddr_t)buf_len < eoa)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "supplied buffer too small")
+
+ space_needed = (size_t)eoa;
+
+ /* Set up file driver I/O info object */
+ fdio_info.file = fd_ptr;
+ if(NULL == (fdio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(meta_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get property list object")
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(raw_dxpl_id)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get property list object")
+
+ /* read in the file image */
+ /* (Note compensation for base address addition in internal routine) */
+ if(H5FD_read(&fdio_info, H5FD_MEM_DEFAULT, 0, space_needed, buf_ptr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "file image read request failed")
+
+ /* Offset to "status_flags" in the superblock */
+ tmp = H5F_SUPER_STATUS_FLAGS_OFF(file->shared->sblock->super_vers);
+ /* Size of "status_flags" depends on the superblock version */
+ tmp_size = H5F_SUPER_STATUS_FLAGS_SIZE(file->shared->sblock->super_vers);
+
+ /* Clear "status_flags" */
+ HDmemset((uint8_t *)(buf_ptr) + tmp, 0, tmp_size);
+
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_get_file_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_track_metadata_read_retries
+ *
+ * Purpose: To track the # of a "retries" (log10) for a metadata item.
+ * This routine should be used only when:
+ * "retries" > 0
+ * f->shared->read_attempts > 1 (does not have retry when 1)
+ * f->shared->retries_nbins > 0 (calculated based on f->shared->read_attempts)
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; October 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries)
+{
+ unsigned log_ind; /* Index to the array of retries based on log10 of retries */
+ double tmp; /* Temporary value, to keep compiler quiet */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared->read_attempts > 1);
+ HDassert(f->shared->retries_nbins > 0);
+ HDassert(retries > 0);
+ HDassert(retries < f->shared->read_attempts);
+ HDassert(actype < H5AC_NTYPES);
+
+ /* Allocate memory for retries */
+ if(NULL == f->shared->retries[actype])
+ if(NULL == (f->shared->retries[actype] = (uint32_t *)H5MM_calloc((size_t)f->shared->retries_nbins * sizeof(uint32_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Index to retries based on log10 */
+ tmp = HDlog10((double)retries);
+ log_ind = (unsigned)tmp;
+ HDassert(log_ind < f->shared->retries_nbins);
+
+ /* Increment the # of the "retries" */
+ f->shared->retries[actype][log_ind]++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_track_metadata_read_retries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_retries
+ *
+ * Purpose: To initialize data structures for read retries:
+ * --zero out "retries"
+ * --set up "retries_nbins" based on read_attempts
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; November 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_retries(H5F_t *f)
+{
+ double tmp; /* Temporary variable */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Initialize the tracking for metadata read retries */
+ HDmemset(f->shared->retries, 0, sizeof(f->shared->retries));
+
+ /* Initialize the # of bins for retries */
+ f->shared->retries_nbins = 0;
+ if(f->shared->read_attempts > 1) {
+ tmp = HDlog10((double)(f->shared->read_attempts - 1));
+ f->shared->retries_nbins = (unsigned)tmp + 1;
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_retries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_object_flush_cb
+ *
+ * Purpose: To invoke the callback function for object flush that is set
+ * in the file's access property list.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; October 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_object_flush_cb(H5F_t *f, hid_t obj_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Invoke object flush callback if there is one */
+ if(f->shared->object_flush.func && f->shared->object_flush.func(obj_id, f->shared->object_flush.udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "object flush callback returns error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_object_flush_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__set_base_addr
+ *
+ * Purpose: Quick and dirty routine to set the file's 'base_addr' value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * July 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__set_base_addr(const H5F_t *f, haddr_t addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Dispatch to driver */
+ if(H5FD_set_base_addr(f->shared->lf, addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set_base_addr request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__set_base_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__set_eoa
+ *
+ * Purpose: Quick and dirty routine to set the file's 'eoa' value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * July 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__set_eoa(const H5F_t *f, H5F_mem_t type, haddr_t addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Dispatch to driver */
+ if(H5FD_set_eoa(f->shared->lf, type, addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set_eoa request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__set_paged_aggr
+ *
+ * Purpose: Quick and dirty routine to set the file's paged_aggr mode
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * June 19, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__set_paged_aggr(const H5F_t *f, hbool_t paged)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Dispatch to driver */
+ if(H5FD_set_paged_aggr(f->shared->lf, paged) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set paged aggr mode failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__set_paged_aggr() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_coll_md_read
+ *
+ * Purpose: Set the coll_md_read field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 2/10/16
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_set_coll_md_read(H5F_t *f, H5P_coll_md_read_flag_t cmr)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+
+ f->coll_md_read = cmr;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5F_set_coll_md_read() */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_latest_flags
+ *
+ * Purpose: Set the latest_flags field with a new value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * 4/26/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_set_latest_flags(H5F_t *f, unsigned flags)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(0 == ((~flags) & H5F_LATEST_ALL_FLAGS));
+
+ f->shared->latest_flags = flags;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_latest_flags() */
+
diff --git a/src/H5Fio.c b/src/H5Fio.c
new file mode 100644
index 0000000..81fa514
--- /dev/null
+++ b/src/H5Fio.c
@@ -0,0 +1,370 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fio.c
+ * Jan 10 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File I/O routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5PBprivate.h" /* Page Buffer */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_block_read
+ *
+ * Purpose: Reads some data from a file/server/etc into a buffer.
+ * The data is contiguous. The address is relative to the base
+ * address for the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 10 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size,
+ hid_t dxpl_id, void *buf/*out*/)
+{
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ H5FD_mem_t map_type; /* Mapped memory type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(buf);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Check for attempting I/O on 'temporary' file address */
+ if(H5F_addr_le(f->shared->tmp_addr, (addr + size)))
+ HGOTO_ERROR(H5E_IO, H5E_BADRANGE, FAIL, "attempting I/O in temporary file space")
+
+ /* Treat global heap as raw data */
+ map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type;
+
+ /* Set up the I/O info object */
+ fio_info.f = f;
+ if(H5FD_MEM_DRAW == type) {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end if */
+ else {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end else */
+
+ /* Pass through page buffer layer */
+ if(H5PB_read(&fio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read through page buffer failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_block_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_block_write
+ *
+ * Purpose: Writes some data from memory to a file/server/etc. The
+ * data is contiguous. The address is relative to the base
+ * address.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 10 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size,
+ hid_t dxpl_id, const void *buf)
+{
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ H5FD_mem_t map_type; /* Mapped memory type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
+ HDassert(buf);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Check for attempting I/O on 'temporary' file address */
+ if(H5F_addr_le(f->shared->tmp_addr, (addr + size)))
+ HGOTO_ERROR(H5E_IO, H5E_BADRANGE, FAIL, "attempting I/O in temporary file space")
+
+ /* Treat global heap as raw data */
+ map_type = (type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type;
+
+ /* Set up the I/O info object */
+ fio_info.f = f;
+ if(H5FD_MEM_DRAW == type) {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end if */
+ else {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end else */
+
+ /* Pass through page buffer layer */
+ if(H5PB_write(&fio_info, map_type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write through page buffer failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_block_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_flush_tagged_metadata
+ *
+ * Purpose: Flushes metadata with specified tag in the metadata cache
+ * to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * September 9, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id)
+{
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Use tag to search for and flush associated metadata */
+ if(H5AC_flush_tagged_metadata(f, tag, dxpl_id)<0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
+
+ /* Set up I/O info for operation */
+ fio_info.f = f;
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Flush and reset the accumulator */
+ if(H5F__accum_reset(&fio_info, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+
+ /* Flush file buffers to disk. */
+ if(H5FD_flush(f->shared->lf, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "low level flush failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_flush_tagged_metadata */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_evict_tagged_metadata
+ *
+ * Purpose: Evicts metadata from the cache with specified tag.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * September 9, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Evict the object's metadata */
+ if(H5AC_evict_tagged_metadata(f, tag, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "unable to evict tagged metadata")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_evict_tagged_metadata */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__evict_cache_entries
+ *
+ * Purpose: To evict all cache entries except the pinned superblock entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__evict_cache_entries(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Evict all except pinned entries in the cache */
+ if(H5AC_evict(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "unable to evict all except pinned entries")
+
+#ifndef NDEBUG
+{
+ unsigned status = 0;
+ uint32_t cur_num_entries;
+
+ /* Retrieve status of the superblock */
+ if(H5AC_get_entry_status(f, (haddr_t)0, &status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to get entry status")
+
+ /* Verify status of the superblock entry in the cache */
+ if(!(status & H5AC_ES__IN_CACHE) || !(status & H5AC_ES__IS_PINNED))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to get entry status")
+
+ /* Get the number of cache entries */
+ if(H5AC_get_cache_size(f->shared->cache, NULL, NULL, NULL, &cur_num_entries) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_get_cache_size() failed.")
+
+ /* Should be the only one left in the cache (the superblock) */
+ if(cur_num_entries != 1)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "number of cache entries is not correct")
+}
+#endif /* NDEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F__evict_cache_entries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_checksums
+ *
+ * Purpose: Decode checksum stored in the buffer
+ * Calculate checksum for the data in the buffer
+ *
+ * Note: Assumes that the checksum is the last data in the buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Sept 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_checksums(const uint8_t *buf, size_t buf_size, uint32_t *s_chksum/*out*/, uint32_t *c_chksum/*out*/)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(buf);
+ HDassert(buf_size);
+
+ /* Return the stored checksum */
+ if(s_chksum) {
+ const uint8_t *chk_p; /* Pointer into raw data buffer */
+
+ /* Offset to the checksum in the buffer */
+ chk_p = buf + buf_size - H5_SIZEOF_CHKSUM;
+
+ /* Decode the checksum stored in the buffer */
+ UINT32DECODE(chk_p, *s_chksum);
+ } /* end if */
+
+ /* Return the computed checksum for the buffer */
+ if(c_chksum)
+ *c_chksum = H5_checksum_metadata(buf, buf_size - H5_SIZEOF_CHKSUM, 0);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F_get_chksums() */
+
diff --git a/src/H5Fmodule.h b/src/H5Fmodule.h
new file mode 100644
index 0000000..0481512
--- /dev/null
+++ b/src/H5Fmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5F package. Including this header means that the source file
+ * is part of the H5F package.
+ */
+#ifndef _H5Fmodule_H
+#define _H5Fmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5F_MODULE
+#define H5_MY_PKG H5F
+#define H5_MY_PKG_ERR H5E_FILE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Fmodule_H */
+
diff --git a/src/H5Fmount.c b/src/H5Fmount.c
new file mode 100644
index 0000000..3cd5c21
--- /dev/null
+++ b/src/H5Fmount.c
@@ -0,0 +1,757 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5MMprivate.h" /* Memory management */
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5F_mount(H5G_loc_t *loc, const char *name, H5F_t *child,
+ hid_t plist_id, hid_t dxpl_id);
+static herr_t H5F_unmount(H5G_loc_t *loc, const char *name, hid_t dxpl_id);
+static void H5F_mount_count_ids_recurse(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_close_mounts
+ *
+ * Purpose: Close all mounts for a given file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 2, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_close_mounts(H5F_t *f)
+{
+ unsigned u; /* Local index */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+
+ /* Unmount all child files. Loop backwards to avoid having to adjust u when
+ * a file is unmounted. Note that we rely on unsigned u "wrapping around"
+ * to terminate the loop. */
+ for (u = f->shared->mtab.nmounts - 1; u < f->shared->mtab.nmounts; u--) {
+ /* Only unmount children mounted to this top level file structure */
+ if(f->shared->mtab.child[u].file->parent == f) {
+ /* Detach the child file from the parent file */
+ f->shared->mtab.child[u].file->parent = NULL;
+
+ /* Close the internal group maintaining the mount point */
+ if(H5G_close(f->shared->mtab.child[u].group) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close child group")
+
+ /* Close the child file */
+ if(H5F_try_close(f->shared->mtab.child[u].file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close child file")
+
+ /* Eliminate the mount point from the table */
+ HDmemmove(f->shared->mtab.child + u, f->shared->mtab.child + u + 1,
+ (f->shared->mtab.nmounts - u - 1) * sizeof(f->shared->mtab.child[0]));
+ f->shared->mtab.nmounts--;
+ f->nmounts--;
+ }
+ } /* end if */
+
+ HDassert(f->nmounts == 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_close_mounts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mount
+ *
+ * Purpose: Mount file CHILD onto the group specified by LOC and NAME,
+ * using mount properties in PLIST. CHILD must not already be
+ * mouted and must not be a mount ancestor of the mount-point.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mount(H5G_loc_t *loc, const char *name, H5F_t *child,
+ hid_t H5_ATTR_UNUSED plist_id, hid_t dxpl_id)
+{
+ H5G_t *mount_point = NULL; /*mount point group */
+ H5F_t *ancestor = NULL; /*ancestor files */
+ H5F_t *parent = NULL; /*file containing mount point */
+ unsigned lt, rt, md; /*binary search indices */
+ int cmp; /*binary search comparison value*/
+ H5G_loc_t mp_loc; /* entry of moint point to be opened */
+ H5G_name_t mp_path; /* Mount point group hier. path */
+ H5O_loc_t mp_oloc; /* Mount point object location */
+ H5G_loc_t root_loc; /* Group location of root of file to mount */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(child);
+ HDassert(TRUE == H5P_isa_class(plist_id, H5P_FILE_MOUNT));
+
+ /* Set up group location to fill in */
+ mp_loc.oloc = &mp_oloc;
+ mp_loc.path = &mp_path;
+ H5G_loc_reset(&mp_loc);
+
+ /*
+ * Check that the child isn't mounted, that the mount point exists, that
+ * the mount point wasn't reached via external link, that
+ * the parent & child files have the same file close degree, and
+ * that the mount wouldn't introduce a cycle in the mount tree.
+ */
+ if(child->parent)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "file is already mounted")
+ if(H5G_loc_find(loc, name, &mp_loc/*out*/, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ /* If the mount location is holding its file open, that file will close
+ * and remove the mount as soon as we exit this function. Prevent the
+ * user from doing this.
+ */
+ if(mp_loc.oloc->holding_file != FALSE)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount path cannot contain links to external files")
+
+ /* Open the mount point group */
+ if(NULL == (mount_point = H5G_open(&mp_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found")
+
+ /* Check if the proposed mount point group is already a mount point */
+ if(H5G_MOUNTED(mount_point))
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point is already in use")
+
+ /* Retrieve information from the mount point group */
+ /* (Some of which we had before but was reset in mp_loc when the group
+ * "took over" the group location - QAK)
+ */
+ parent = H5G_fileof(mount_point);
+ HDassert(parent);
+ mp_loc.oloc = H5G_oloc(mount_point);
+ HDassert(mp_loc.oloc);
+ mp_loc.path = H5G_nameof(mount_point);
+ HDassert(mp_loc.path);
+ for(ancestor = parent; ancestor; ancestor = ancestor->parent) {
+ if(ancestor->shared == child->shared)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount would introduce a cycle")
+ } /* end for */
+
+ /* Make certain that the parent & child files have the same "file close degree" */
+ if(parent->shared->fc_degree != child->shared->fc_degree)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mounted file has different file close degree than parent")
+
+ /*
+ * Use a binary search to locate the position that the child should be
+ * inserted into the parent mount table. At the end of this paragraph
+ * `md' will be the index where the child should be inserted.
+ */
+ lt = md = 0;
+ rt = parent->shared->mtab.nmounts;
+ cmp = -1;
+ while(lt < rt && cmp) {
+ H5O_loc_t *oloc; /*temporary symbol table entry */
+
+ md = (lt + rt) / 2;
+ oloc = H5G_oloc(parent->shared->mtab.child[md].group);
+ cmp = H5F_addr_cmp(mp_loc.oloc->addr, oloc->addr);
+ if(cmp < 0)
+ rt = md;
+ else if(cmp > 0)
+ lt = md + 1;
+ } /* end while */
+ if(cmp > 0)
+ md++;
+ if(!cmp)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point is already in use")
+
+ /* Make room in the table */
+ if(parent->shared->mtab.nmounts >= parent->shared->mtab.nalloc) {
+ unsigned n = MAX(16, 2 * parent->shared->mtab.nalloc);
+ H5F_mount_t *x = (H5F_mount_t *)H5MM_realloc(parent->shared->mtab.child, n * sizeof(parent->shared->mtab.child[0]));
+
+ if(!x)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for mount table")
+ parent->shared->mtab.child = x;
+ parent->shared->mtab.nalloc = n;
+ } /* end if */
+
+ /* Insert into table */
+ HDmemmove(parent->shared->mtab.child + md + 1, parent->shared->mtab.child + md,
+ (parent->shared->mtab.nmounts-md) * sizeof(parent->shared->mtab.child[0]));
+ parent->shared->mtab.nmounts++;
+ parent->nmounts++;
+ parent->shared->mtab.child[md].group = mount_point;
+ parent->shared->mtab.child[md].file = child;
+ child->parent = parent;
+
+ /* Set the group's mountpoint flag */
+ if(H5G_mount(parent->shared->mtab.child[md].group) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to set group mounted flag")
+
+ /* Get the group location for the root group in the file to unmount */
+ if(NULL == (root_loc.oloc = H5G_oloc(child->shared->root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (root_loc.path = H5G_nameof(child->shared->root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Search the open IDs and replace names for mount operation */
+ /* We pass H5G_UNKNOWN as object type; search all IDs */
+ if(H5G_name_replace(NULL, H5G_NAME_MOUNT, mp_loc.oloc->file,
+ mp_loc.path->full_path_r, root_loc.oloc->file, root_loc.path->full_path_r,
+ dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to replace name")
+
+done:
+ if(ret_value < 0) {
+ if(mount_point) {
+ if(H5G_close(mount_point) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close mounted group")
+ } /* end if */
+ else {
+ if(H5G_loc_free(&mp_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to free mount location")
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_mount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_unmount
+ *
+ * Purpose: Unmount the child which is mounted at the group specified by
+ * LOC and NAME or fail if nothing is mounted there. Neither
+ * file is closed.
+ *
+ * Because the mount point is specified by name and opened as a
+ * group, the H5G_namei() will resolve it to the root of the
+ * mounted file, not the group where the file is mounted.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_unmount(H5G_loc_t *loc, const char *name, hid_t dxpl_id)
+{
+ H5G_t *child_group = NULL; /* Child's group in parent mtab */
+ H5F_t *child = NULL; /*mounted file */
+ H5F_t *parent = NULL; /*file where mounted */
+ H5O_loc_t *mnt_oloc; /* symbol table entry for root of mounted file */
+ H5G_name_t mp_path; /* Mount point group hier. path */
+ H5O_loc_t mp_oloc; /* Mount point object location */
+ H5G_loc_t mp_loc; /* entry used to open mount point*/
+ hbool_t mp_loc_setup = FALSE; /* Whether mount point location is set up */
+ H5G_loc_t root_loc; /* Group location of root of file to unmount */
+ int child_idx; /* Index of child in parent's mtab */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up mount point location to fill in */
+ mp_loc.oloc = &mp_oloc;
+ mp_loc.path = &mp_path;
+ H5G_loc_reset(&mp_loc);
+
+ /*
+ * Get the mount point, or more precisely the root of the mounted file.
+ * If we get the root group and the file has a parent in the mount tree,
+ * then we must have found the mount point.
+ */
+ if(H5G_loc_find(loc, name, &mp_loc/*out*/, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ mp_loc_setup = TRUE;
+ child = mp_loc.oloc->file;
+ mnt_oloc = H5G_oloc(child->shared->root_grp);
+ child_idx = -1;
+
+ if(child->parent && H5F_addr_eq(mp_oloc.addr, mnt_oloc->addr)) {
+ unsigned u; /*counters */
+
+ /*
+ * We've been given the root group of the child. We do a reverse
+ * lookup in the parent's mount table to find the correct entry.
+ */
+ parent = child->parent;
+ for(u = 0; u < parent->shared->mtab.nmounts; u++) {
+ if(parent->shared->mtab.child[u].file->shared == child->shared) {
+ /* Found the correct index */
+ child_idx = (int)u;
+ break;
+ } /* end if */
+ } /* end for */
+ } else {
+ unsigned lt, rt, md = 0; /*binary search indices */
+ int cmp; /*binary search comparison value*/
+
+ /*
+ * We've been given the mount point in the parent. We use a binary
+ * search in the parent to locate the mounted file, if any.
+ */
+ parent = child; /*we guessed wrong*/
+ lt = 0;
+ rt = parent->shared->mtab.nmounts;
+ cmp = -1;
+ while(lt < rt && cmp) {
+ md = (lt + rt) / 2;
+ mnt_oloc = H5G_oloc(parent->shared->mtab.child[md].group);
+ cmp = H5F_addr_cmp(mp_oloc.addr, mnt_oloc->addr);
+ if (cmp<0)
+ rt = md;
+ else
+ lt = md + 1;
+ } /* end while */
+ if(cmp)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "not a mount point")
+
+ /* Found the correct index, set the info about the child */
+ child_idx = (int)md;
+ H5G_loc_free(&mp_loc);
+ mp_loc_setup = FALSE;
+ mp_loc.oloc = mnt_oloc;
+ mp_loc.path = H5G_nameof(parent->shared->mtab.child[md].group);
+ child = parent->shared->mtab.child[child_idx].file;
+
+ /* Set the parent to be the actual parent of the discovered child.
+ * Could be different due to the shared mount table. */
+ parent = child->parent;
+ } /* end else */
+ HDassert(child_idx >= 0);
+
+ /* Save the information about the child from the mount table */
+ child_group = parent->shared->mtab.child[child_idx].group;
+
+ /* Get the group location for the root group in the file to unmount */
+ if(NULL == (root_loc.oloc = H5G_oloc(child->shared->root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (root_loc.path = H5G_nameof(child->shared->root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Search the open IDs replace names to reflect unmount operation */
+ if(H5G_name_replace(NULL, H5G_NAME_UNMOUNT, mp_loc.oloc->file,
+ mp_loc.path->full_path_r, root_loc.oloc->file, root_loc.path->full_path_r,
+ dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to replace name")
+
+ /* Eliminate the mount point from the table */
+ HDmemmove(parent->shared->mtab.child + (unsigned)child_idx, (parent->shared->mtab.child + (unsigned)child_idx) + 1,
+ ((parent->shared->mtab.nmounts - (unsigned)child_idx) - 1) * sizeof(parent->shared->mtab.child[0]));
+ parent->shared->mtab.nmounts -= 1;
+ parent->nmounts -= 1;
+
+ /* Unmount the child file from the parent file */
+ if(H5G_unmount(child_group) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to reset group mounted flag")
+ if(H5G_close(child_group) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group")
+
+ /* Detach child file from parent & see if it should close */
+ child->parent = NULL;
+ if(H5F_try_close(child, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file")
+
+done:
+ /* Free the mount point location's information, if it's been set up */
+ if(mp_loc_setup)
+ H5G_loc_free(&mp_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_unmount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_is_mount
+ *
+ * Purpose: Check if a file is mounted within another file.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 2, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_is_mount(const H5F_t *file)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(file);
+
+ if(file->parent != NULL)
+ ret_value = TRUE;
+ else
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_is_mount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fmount
+ *
+ * Purpose: Mount file CHILD_ID onto the group specified by LOC_ID and
+ * NAME using mount properties PLIST_ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id)
+{
+ H5G_loc_t loc;
+ H5F_t *child = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*sii", loc_id, name, child_id, plist_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(NULL == (child = (H5F_t *)H5I_object_verify(child_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+ if(H5P_DEFAULT == plist_id)
+ plist_id = H5P_FILE_MOUNT_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(plist_id, H5P_FILE_MOUNT))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property list")
+
+ /* Do the mount */
+ if(H5F_mount(&loc, name, child, plist_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to mount file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fmount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Funmount
+ *
+ * Purpose: Given a mount point, dissassociate the mount point's file
+ * from the file mounted there. Do not close either file.
+ *
+ * The mount point can either be the group in the parent or the
+ * root group of the mounted file (both groups have the same
+ * name). If the mount point was opened before the mount then
+ * it's the group in the parent, but if it was opened after the
+ * mount then it's the root group of the child.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Funmount(hid_t loc_id, const char *name)
+{
+ H5G_loc_t loc;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", loc_id, name);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Unmount */
+ if (H5F_unmount(&loc, name, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to unmount file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Funmount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mount_count_ids_recurse
+ *
+ * Purpose: Helper routine for counting number of open IDs in mount
+ * hierarchy.
+ *
+ * Return: <none>
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5F_mount_count_ids_recurse(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs)
+{
+ unsigned u; /* Local index value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(nopen_files);
+ HDassert(nopen_objs);
+
+ /* If this file is still open, increment number of file IDs open */
+ if(f->file_id > 0)
+ *nopen_files += 1;
+
+ /* Increment number of open objects in file
+ * (Reduced by number of mounted files, we'll add back in the mount point's
+ * groups later, if they are open)
+ */
+ *nopen_objs += (f->nopen_objs - f->nmounts);
+
+ /* Iterate over files mounted in this file and add in their open ID counts also */
+ for(u = 0; u < f->shared->mtab.nmounts; u++) {
+ /* Only recurse on children mounted to this top level file structure */
+ if(f->shared->mtab.child[u].file->parent == f) {
+ /* Increment the open object count if the mount point group has an open ID */
+ if(H5G_get_shared_count(f->shared->mtab.child[u].group) > 1)
+ *nopen_objs += 1;
+
+ H5F_mount_count_ids_recurse(f->shared->mtab.child[u].file, nopen_files, nopen_objs);
+ }
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5F_mount_count_ids_recurse() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mount_count_ids
+ *
+ * Purpose: Count the number of open file & object IDs in a mount hierarchy
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tues, July 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(nopen_files);
+ HDassert(nopen_objs);
+
+ /* Find the top file in the mounting hierarchy */
+ while(f->parent)
+ f = f->parent;
+
+ /* Count open IDs in the hierarchy */
+ H5F_mount_count_ids_recurse(f, nopen_files, nopen_objs);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F_mount_count_ids() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_flush_mounts_recurse
+ *
+ * Purpose: Flush a mount hierarchy, recursively
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Fri, August 21, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_flush_mounts_recurse(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id)
+{
+ unsigned nerrors = 0; /* Errors from recursive flushes */
+ unsigned u; /* Index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Flush all child files, not stopping for errors */
+ for(u = 0; u < f->shared->mtab.nmounts; u++)
+ if(H5F_flush_mounts_recurse(f->shared->mtab.child[u].file, meta_dxpl_id, raw_dxpl_id) < 0)
+ nerrors++;
+
+ /* Call the "real" flush routine, for this file */
+ if(H5F__flush(f, meta_dxpl_id, raw_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+
+ /* Check flush errors for children - errors are already on the stack */
+ if(nerrors)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's child mounts")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_flush_mounts_recurse() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_flush_mounts
+ *
+ * Purpose: Flush a mount hierarchy
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Fri, August 21, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_flush_mounts(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Find the top file in the mount hierarchy */
+ while(f->parent)
+ f = f->parent;
+
+ /* Flush the mounted file hierarchy */
+ if(H5F_flush_mounts_recurse(f, meta_dxpl_id, raw_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush mounted file hierarchy")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_flush_mounts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_traverse_mount
+ *
+ * Purpose: If LNK is a mount point then copy the entry for the root
+ * group of the mounted file into LNK.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_traverse_mount(H5O_loc_t *oloc/*in,out*/)
+{
+ H5F_t *parent = oloc->file, /* File of object */
+ *child = NULL; /* Child file */
+ unsigned lt, rt, md = 0; /* Binary search indices */
+ int cmp;
+ H5O_loc_t *mnt_oloc = NULL; /* Object location for mount points */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /*
+ * The loop is necessary because we might have file1 mounted at the root
+ * of file2, which is mounted somewhere in file3.
+ */
+ do {
+ /*
+ * Use a binary search to find the potential mount point in the mount
+ * table for the parent
+ */
+ lt = 0;
+ rt = parent->shared->mtab.nmounts;
+ cmp = -1;
+ while(lt < rt && cmp) {
+ md = (lt + rt) / 2;
+ mnt_oloc = H5G_oloc(parent->shared->mtab.child[md].group);
+ cmp = H5F_addr_cmp(oloc->addr, mnt_oloc->addr);
+ if(cmp < 0)
+ rt = md;
+ else
+ lt = md + 1;
+ } /* end while */
+
+ /* Copy root info over to ENT */
+ if(0 == cmp) {
+ /* Get the child file */
+ child = parent->shared->mtab.child[md].file;
+
+ /* Get the location for the root group in the child's file */
+ mnt_oloc = H5G_oloc(child->shared->root_grp);
+
+ /* Release the mount point */
+ if(H5O_loc_free(oloc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "unable to free object location")
+
+ /* Copy the entry for the root group */
+ if(H5O_loc_copy(oloc, mnt_oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ /* In case the shared root group info points to a different file handle
+ * than the child, modify oloc */
+ oloc->file = child;
+
+ /* Switch to child's file */
+ parent = child;
+ } /* end if */
+ } while(!cmp);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_traverse_mount() */
+
diff --git a/src/H5Fmpi.c b/src/H5Fmpi.c
new file mode 100644
index 0000000..2ce454a
--- /dev/null
+++ b/src/H5Fmpi.c
@@ -0,0 +1,384 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fmpi.c
+ * Jan 10 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: MPI-related routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_mpi_handle
+ *
+ * Purpose: Retrieves MPI File handle.
+ *
+ * Return: Success: The size (positive)
+ * Failure: Negative
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_mpi_handle(const H5F_t *f, MPI_File **f_handle)
+{
+ herr_t ret_value = SUCCEED;
+ hid_t fapl = -1;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ assert(f && f->shared);
+
+ /* Dispatch to driver */
+ if ((ret_value = H5FD_get_vfd_handle(f->shared->lf, fapl, (void **)f_handle)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get mpi file handle")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_mpi_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpi_get_rank
+ *
+ * Purpose: Retrieves the rank of an MPI process.
+ *
+ * Return: Success: The rank (non-negative)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5F_mpi_get_rank(const H5F_t *f)
+{
+ int ret_value;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f && f->shared);
+
+ /* Dispatch to driver */
+ if ((ret_value=H5FD_mpi_get_rank(f->shared->lf)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_rank request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_mpi_get_rank() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpi_get_comm
+ *
+ * Purpose: Retrieves the file's communicator
+ *
+ * Return: Success: The communicator (non-negative)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 30, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+MPI_Comm
+H5F_mpi_get_comm(const H5F_t *f)
+{
+ MPI_Comm ret_value;
+
+ FUNC_ENTER_NOAPI(MPI_COMM_NULL)
+
+ HDassert(f && f->shared);
+
+ /* Dispatch to driver */
+ if ((ret_value=H5FD_mpi_get_comm(f->shared->lf))==MPI_COMM_NULL)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, MPI_COMM_NULL, "driver get_comm request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_mpi_get_comm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpi_get_size
+ *
+ * Purpose: Retrieves the size of an MPI process.
+ *
+ * Return: Success: The size (positive)
+ *
+ * Failure: Negative
+ *
+ * Programmer: John Mainzer
+ * Friday, May 6, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5F_mpi_get_size(const H5F_t *f)
+{
+ int ret_value;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f && f->shared);
+
+ /* Dispatch to driver */
+ if ((ret_value=H5FD_mpi_get_size(f->shared->lf)) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_size request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_mpi_get_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fset_mpi_atomicity
+ *
+ * Purpose: Sets the atomicity mode
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Feb 14, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fset_mpi_atomicity(hid_t file_id, hbool_t flag)
+{
+ H5F_t *file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", file_id, flag);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Check VFD */
+ if(!H5F_HAS_FEATURE(file, H5FD_FEAT_HAS_MPI))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "incorrect VFL driver, does not support MPI atomicity mode")
+
+ /* set atomicity value */
+ if (H5FD_set_mpio_atomicity (file->shared->lf, flag) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set atomicity flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fget_mpi_atomicity
+ *
+ * Purpose: Returns the atomicity mode
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Feb 14, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fget_mpi_atomicity(hid_t file_id, hbool_t *flag)
+{
+ H5F_t *file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", file_id, flag);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+
+ /* Check VFD */
+ if(!H5F_HAS_FEATURE(file, H5FD_FEAT_HAS_MPI))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "incorrect VFL driver, does not support MPI atomicity mode")
+
+ /* get atomicity value */
+ if (H5FD_get_mpio_atomicity (file->shared->lf, flag) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get atomicity flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpi_retrieve_comm
+ *
+ * Purpose: Retrieves an MPI communicator from the file the location ID
+ * is in. If the loc_id is invalid, the fapl_id is used to
+ * retrieve the communicator.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Feb 14, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_mpi_retrieve_comm(hid_t loc_id, hid_t acspl_id, MPI_Comm *mpi_comm)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(mpi_comm);
+ *mpi_comm = MPI_COMM_NULL;
+
+ /* if the loc_id is valid, then get the comm from the file
+ attached to the loc_id */
+ if(H5I_INVALID_HID != loc_id) {
+ H5G_loc_t loc;
+ H5F_t *f = NULL;
+
+ /* retrieve the file structure */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ f = loc.oloc->file;
+ HDassert(f);
+
+ /* check if MPIO driver is used */
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
+ /* retrieve the file communicator */
+ if(MPI_COMM_NULL == (*mpi_comm = H5F_mpi_get_comm(f)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI communicator")
+ }
+ }
+ /* otherwise, this if from H5Fopen or H5Fcreate and has to be collective */
+ else {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ HDassert(H5P_isa_class(acspl_id, H5P_FILE_ACCESS));
+
+ if(NULL == (plist = H5P_object_verify(acspl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a file access list")
+
+ if(H5FD_MPIO == H5P_peek_driver(plist)) {
+ const H5FD_mpio_fapl_t *fa; /* MPIO fapl info */
+
+ if(NULL == (fa = (const H5FD_mpio_fapl_t *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+
+ *mpi_comm = fa->comm;
+ }
+ }
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_mpi_retrieve_comm */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_mpi_info
+ *
+ * Purpose: Retrieves MPI File info.
+ *
+ * Return: Success: The size (positive)
+ * Failure: Negative
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_mpi_info(const H5F_t *f, MPI_Info **f_info)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f && f->shared);
+
+ /* Dispatch to driver */
+ if ((ret_value = H5FD_get_mpi_info(f->shared->lf, (void **)f_info)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get mpi file info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_mpi_info() */
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h
new file mode 100644
index 0000000..7a5c126
--- /dev/null
+++ b/src/H5Fpkg.h
@@ -0,0 +1,472 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, September 28, 2000
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5F package. Source files outside the H5F package should
+ * include H5Fprivate.h instead.
+ */
+#if !(defined H5F_FRIEND || defined H5F_MODULE)
+#error "Do not include this file outside the H5F package!"
+#endif
+
+#ifndef _H5Fpkg_H
+#define _H5Fpkg_H
+
+/* Get package's private header */
+#include "H5Fprivate.h"
+
+/* Other public headers needed by this file */
+#include "H5Bpublic.h" /* B-tree header, for H5B_NUM_BTREE_ID */
+
+/* Other private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5FOprivate.h" /* File objects */
+#include "H5FSprivate.h" /* File free space */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Oprivate.h" /* Object header messages */
+#include "H5PBprivate.h" /* Page buffer */
+#include "H5UCprivate.h" /* Reference counted object functions */
+
+
+/*
+ * Feature: Define this constant on the compiler command-line if you want to
+ * see some debugging messages on the debug stream.
+ */
+#ifdef NDEBUG
+# undef H5F_DEBUG
+#endif
+
+/* Superblock status flags */
+#define H5F_SUPER_WRITE_ACCESS 0x01
+#define H5F_SUPER_FILE_OK 0x02
+#define H5F_SUPER_SWMR_WRITE_ACCESS 0x04
+#define H5F_SUPER_ALL_FLAGS (H5F_SUPER_WRITE_ACCESS | H5F_SUPER_FILE_OK | H5F_SUPER_SWMR_WRITE_ACCESS)
+
+/* Mask for removing private file access flags */
+#define H5F_ACC_PUBLIC_FLAGS 0x007fu
+
+/* Free space section+aggregator merge flags */
+#define H5F_FS_MERGE_METADATA 0x01 /* Section can merge with metadata aggregator */
+#define H5F_FS_MERGE_RAWDATA 0x02 /* Section can merge with small 'raw' data aggregator */
+
+/* Macro to abstract checking whether file is using a free space manager */
+#define H5F_HAVE_FREE_SPACE_MANAGER(F) \
+ ((F)->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || \
+ (F)->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE)
+
+/* Macros for encoding/decoding superblock */
+#define H5F_MAX_DRVINFOBLOCK_SIZE 1024 /* Maximum size of superblock driver info buffer */
+#define H5F_DRVINFOBLOCK_HDR_SIZE 16 /* Size of superblock driver info header */
+
+/* Superblock sizes for various versions */
+#define H5F_SIZEOF_CHKSUM 4 /* Checksum size in the file */
+
+/* Fixed-size portion at the beginning of all superblocks */
+#define H5F_SUPERBLOCK_FIXED_SIZE ( H5F_SIGNATURE_LEN \
+ + 1) /* superblock version */
+
+/* The H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE is the minimal amount of super block
+ * variable length data guarnateed to load the sizeof offsets and the sizeof
+ * lengths fields in all versions of the superblock.
+ *
+ * This is necessary in the V3 cache, as on the initial load, we need to
+ * get enough of the superblock to determine its version and size so that
+ * the metadata cache can load the correct amount of data from file to
+ * allow the second deserialization attempt to succeed.
+ *
+ * The value selected will have to be revisited for each new version
+ * of the super block. Note that the current value is one byte larger
+ * than it needs to be.
+ */
+#define H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE 7
+
+/* Macros for computing variable-size superblock size */
+#define H5F_SUPERBLOCK_VARLEN_SIZE_COMMON \
+ (2 /* freespace, and root group versions */ \
+ + 1 /* reserved */ \
+ + 3 /* shared header vers, size of address, size of lengths */ \
+ + 1 /* reserved */ \
+ + 4 /* group leaf k, group internal k */ \
+ + 4) /* consistency flags */
+#define H5F_SUPERBLOCK_VARLEN_SIZE_V0(sizeof_addr, sizeof_size) \
+ ( H5F_SUPERBLOCK_VARLEN_SIZE_COMMON /* Common variable-length info */ \
+ + (sizeof_addr) /* base address */ \
+ + (sizeof_addr) /* <unused> */ \
+ + (sizeof_addr) /* EOF address */ \
+ + (sizeof_addr) /* driver block address */ \
+ + H5G_SIZEOF_ENTRY(sizeof_addr, sizeof_size)) /* root group ptr */
+#define H5F_SUPERBLOCK_VARLEN_SIZE_V1(sizeof_addr, sizeof_size) \
+ ( H5F_SUPERBLOCK_VARLEN_SIZE_COMMON /* Common variable-length info */ \
+ + 2 /* indexed B-tree internal k */ \
+ + 2 /* reserved */ \
+ + (sizeof_addr) /* base address */ \
+ + (sizeof_addr) /* <unused> */ \
+ + (sizeof_addr) /* EOF address */ \
+ + (sizeof_addr) /* driver block address */ \
+ + H5G_SIZEOF_ENTRY(sizeof_addr, sizeof_size)) /* root group ptr */
+#define H5F_SUPERBLOCK_VARLEN_SIZE_V2(sizeof_addr) \
+ ( 2 /* size of address, size of lengths */ \
+ + 1 /* consistency flags */ \
+ + (sizeof_addr) /* base address */ \
+ + (sizeof_addr) /* superblock extension address */ \
+ + (sizeof_addr) /* EOF address */ \
+ + (sizeof_addr) /* root group object header address */ \
+ + H5F_SIZEOF_CHKSUM) /* superblock checksum (keep this last) */
+#define H5F_SUPERBLOCK_VARLEN_SIZE(v, sizeof_addr, sizeof_size) ( \
+ (v == 0 ? H5F_SUPERBLOCK_VARLEN_SIZE_V0(sizeof_addr, sizeof_size) : 0) \
+ + (v == 1 ? H5F_SUPERBLOCK_VARLEN_SIZE_V1(sizeof_addr, sizeof_size) : 0) \
+ + (v >= 2 ? H5F_SUPERBLOCK_VARLEN_SIZE_V2(sizeof_addr) : 0))
+
+/* Total size of superblock, depends on superblock version */
+#define H5F_SUPERBLOCK_SIZE(s) ( H5F_SUPERBLOCK_FIXED_SIZE \
+ + H5F_SUPERBLOCK_VARLEN_SIZE((s)->super_vers, (s)->sizeof_addr, (s)->sizeof_size))
+
+/* For superblock version 0 & 1:
+ Offset to the file consistency flags (status_flags) in the superblock (excluding H5F_SUPERBLOCK_FIXED_SIZE) */
+#define H5F_SUPER_STATUS_OFF_V01 \
+ (2 /* freespace, and root group versions */ \
+ + 1 /* reserved */ \
+ + 3 /* shared header vers, size of address, size of lengths */ \
+ + 1 /* reserved */ \
+ + 4) /* group leaf k, group internal k */
+
+#define H5F_SUPER_STATUS_OFF(v) (v >= 2 ? 2 : H5F_SUPER_STATUS_OFF_V01)
+
+/* Offset to the file consistency flags (status_flags) in the superblock */
+#define H5F_SUPER_STATUS_FLAGS_OFF(v) (H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPER_STATUS_OFF(v))
+
+/* Size of file consistency flags (status_flags) in the superblock */
+#define H5F_SUPER_STATUS_FLAGS_SIZE(v) (v >= 2 ? 1 : 4)
+
+/* Forward declaration external file cache struct used below (defined in
+ * H5Fefc.c) */
+typedef struct H5F_efc_t H5F_efc_t;
+
+/* Structure for passing 'user data' to superblock cache callbacks */
+typedef struct H5F_superblock_cache_ud_t {
+/* IN: */
+ H5F_t *f; /* Pointer to file */
+ hbool_t ignore_drvrinfo; /* Indicate if the driver info should be ignored */
+/* OUT: */
+ unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */
+ unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree key values for each type */
+ haddr_t stored_eof; /* End-of-file in file */
+ hbool_t drvrinfo_removed; /* Indicate if the driver info was removed */
+ unsigned super_vers; /* Superblock version obtained in get_load_size callback.
+ * It will be used later in verify_chksum callback
+ */
+} H5F_superblock_cache_ud_t;
+
+/* Structure for passing 'user data' to driver info block cache callbacks */
+typedef struct H5F_drvrinfo_cache_ud_t {
+ H5F_t *f; /* Pointer to file */
+ haddr_t driver_addr; /* address of driver info block */
+} H5F_drvrinfo_cache_ud_t;
+
+/* Structure for metadata & "small [raw] data" block aggregation fields */
+struct H5F_blk_aggr_t {
+ unsigned long feature_flag; /* Feature flag type */
+ hsize_t alloc_size; /* Size for allocating new blocks */
+ hsize_t tot_size; /* Total amount of bytes aggregated into block */
+ hsize_t size; /* Current size of block left */
+ haddr_t addr; /* Location of block left */
+};
+
+/* Structure for metadata accumulator fields */
+typedef struct H5F_meta_accum_t {
+ unsigned char *buf; /* Buffer to hold the accumulated metadata */
+ haddr_t loc; /* File location (offset) of the accumulated metadata */
+ size_t size; /* Size of the accumulated metadata buffer used (in bytes) */
+ size_t alloc_size; /* Size of the accumulated metadata buffer allocated (in bytes) */
+ size_t dirty_off; /* Offset of the dirty region in the accumulator buffer */
+ size_t dirty_len; /* Length of the dirty region in the accumulator buffer */
+ hbool_t dirty; /* Flag to indicate that the accumulated metadata is dirty */
+} H5F_meta_accum_t;
+
+/* A record of the mount table */
+typedef struct H5F_mount_t {
+ struct H5G_t *group; /* Mount point group held open */
+ struct H5F_t *file; /* File mounted at that point */
+} H5F_mount_t;
+
+/*
+ * The mount table describes what files are attached to (mounted on) the file
+ * to which this table belongs.
+ */
+typedef struct H5F_mtab_t {
+ unsigned nmounts;/* Number of children which are mounted */
+ unsigned nalloc; /* Number of mount slots allocated */
+ H5F_mount_t *child; /* An array of mount records */
+} H5F_mtab_t;
+
+/* Structure specifically to store superblock. This was originally
+ * maintained entirely within H5F_file_t, but is now extracted
+ * here because the superblock is now handled by the cache */
+typedef struct H5F_super_t {
+ H5AC_info_t cache_info; /* Cache entry information structure */
+ unsigned super_vers; /* Superblock version */
+ uint8_t sizeof_addr; /* Size of addresses in file */
+ uint8_t sizeof_size; /* Size of offsets in file */
+ uint8_t status_flags; /* File status flags */
+ unsigned sym_leaf_k; /* Size of leaves in symbol tables */
+ unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree key values for each type */
+ haddr_t base_addr; /* Absolute base address for rel.addrs. */
+ /* (superblock for file is at this offset) */
+ haddr_t ext_addr; /* Relative address of superblock extension */
+ haddr_t driver_addr; /* File driver information block address */
+ haddr_t root_addr; /* Root group address */
+ H5G_entry_t *root_ent; /* Root group symbol table entry */
+} H5F_super_t;
+
+/*
+ * Define the structure to store the file information for HDF5 files. One of
+ * these structures is allocated per file, not per H5Fopen(). That is, set of
+ * H5F_t structs can all point to the same H5F_file_t struct. The `nrefs'
+ * count in this struct indicates the number of H5F_t structs which are
+ * pointing to this struct.
+ */
+struct H5F_file_t {
+ H5FD_t *lf; /* Lower level file handle for I/O */
+ H5F_super_t *sblock; /* Pointer to (pinned) superblock for file */
+ H5O_drvinfo_t *drvinfo; /* Pointer to the (pinned) driver info
+ * cache entry. This field is only defined
+ * for older versions of the super block,
+ * and then only when a driver information
+ * block is present. At all other times
+ * it should be NULL.
+ */
+ hbool_t drvinfo_sb_msg_exists; /* Convenience field used to track
+ * whether the driver info superblock
+ * extension message has been created
+ * yet. This field should be TRUE iff the
+ * superblock extension exists and contains
+ * a driver info message. Under all other
+ * circumstances, it must be set to FALSE.
+ */
+ unsigned nrefs; /* Ref count for times file is opened */
+ unsigned flags; /* Access Permissions for file */
+ H5F_mtab_t mtab; /* File mount table */
+ H5F_efc_t *efc; /* External file cache */
+
+ /* Cached values from FCPL/superblock */
+ uint8_t sizeof_addr; /* Size of addresses in file */
+ uint8_t sizeof_size; /* Size of offsets in file */
+ haddr_t sohm_addr; /* Relative address of shared object header message table */
+ unsigned sohm_vers; /* Version of shared message table on disk */
+ unsigned sohm_nindexes; /* Number of shared messages indexes in the table */
+ unsigned long feature_flags; /* VFL Driver feature Flags */
+ haddr_t maxaddr; /* Maximum address for file */
+
+ H5PB_t *page_buf; /* The page buffer cache */
+ H5AC_t *cache; /* The object cache */
+ H5AC_cache_config_t
+ mdc_initCacheCfg; /* initial configuration for the */
+ /* metadata cache. This structure is */
+ /* fixed at creation time and should */
+ /* not change thereafter. */
+ H5AC_cache_image_config_t
+ mdc_initCacheImageCfg; /* initial configuration for the */
+ /* generate metadata cache image on */
+ /* close option. This structure is */
+ /* fixed at creation time and should */
+ /* not change thereafter. */
+ hbool_t use_mdc_logging; /* Set when metadata logging is desired */
+ hbool_t start_mdc_log_on_access; /* set when mdc logging should */
+ /* begin on file access/create */
+ char *mdc_log_location; /* location of mdc log */
+ hid_t fcpl_id; /* File creation property list ID */
+ H5F_close_degree_t fc_degree; /* File close behavior degree */
+ hbool_t evict_on_close; /* If the file's objects should be evicted from the metadata cache on close */
+ size_t rdcc_nslots; /* Size of raw data chunk cache (slots) */
+ size_t rdcc_nbytes; /* Size of raw data chunk cache (bytes) */
+ double rdcc_w0; /* Preempt read chunks first? [0.0..1.0]*/
+ size_t sieve_buf_size; /* Size of the data sieve buffer allocated (in bytes) */
+ hsize_t threshold; /* Threshold for alignment */
+ hsize_t alignment; /* Alignment */
+ unsigned gc_ref; /* Garbage-collect references? */
+ unsigned latest_flags; /* The latest version support */
+ hbool_t store_msg_crt_idx; /* Store creation index for object header messages? */
+ unsigned ncwfs; /* Num entries on cwfs list */
+ struct H5HG_heap_t **cwfs; /* Global heap cache */
+ struct H5G_t *root_grp; /* Open root group */
+ H5FO_t *open_objs; /* Open objects in file */
+ H5UC_t *grp_btree_shared; /* Ref-counted group B-tree node info */
+
+ /* File space allocation information */
+ H5F_fspace_strategy_t fs_strategy; /* File space handling strategy */
+ hsize_t fs_threshold; /* Free space section threshold */
+ hbool_t fs_persist; /* Free-space persist or not */
+ hbool_t use_tmp_space; /* Whether temp. file space allocation is allowed */
+ haddr_t tmp_addr; /* Next address to use for temp. space in the file */
+ hbool_t point_of_no_return; /* flag to indicate that we can't go back and delete a freespace header when it's used up */
+
+ H5F_fs_state_t fs_state[H5F_MEM_PAGE_NTYPES]; /* State of free space manager for each type */
+ haddr_t fs_addr[H5F_MEM_PAGE_NTYPES]; /* Address of free space manager info for each type */
+ H5FS_t *fs_man[H5F_MEM_PAGE_NTYPES]; /* Free space manager for each file space type */
+ hbool_t first_alloc_dealloc; /* TRUE iff free space managers */
+ /* are persistant and have not */
+ /* been used accessed for either */
+ /* allocation or deallocation */
+ /* since file open. */
+ haddr_t eoa_pre_fsm_fsalloc; /* eoa pre file space allocation */
+ /* for self referential FSMs */
+ haddr_t eoa_post_fsm_fsalloc; /* eoa post file space allocation */
+ /* for self referential FSMs */
+ haddr_t eoa_post_mdci_fsalloc; /* eoa past file space allocation */
+ /* for metadata cache image, or */
+ /* HADDR_UNDEF if no cache image. */
+
+ /* Free-space aggregation info */
+ unsigned fs_aggr_merge[H5FD_MEM_NTYPES]; /* Flags for whether free space can merge with aggregator(s) */
+ H5FD_mem_t fs_type_map[H5FD_MEM_NTYPES]; /* Mapping of "real" file space type into tracked type */
+ H5F_blk_aggr_t meta_aggr; /* Metadata aggregation info (if aggregating metadata allocations) */
+ H5F_blk_aggr_t sdata_aggr; /* "Small data" aggregation info (if aggregating "small data" allocations) */
+
+ /* Paged aggregation info */
+ hsize_t fs_page_size; /* File space page size */
+ size_t pgend_meta_thres; /* Do not track page end meta section <= this threshold */
+
+ /* Metadata accumulator information */
+ H5F_meta_accum_t accum; /* Metadata accumulator info */
+
+ /* Metadata retry info */
+ unsigned read_attempts; /* The # of reads to try when reading metadata with checksum */
+ unsigned retries_nbins; /* # of bins for each retries[] */
+ uint32_t *retries[H5AC_NTYPES]; /* Track # of read retries for metdata items with checksum */
+
+ /* Object flush info */
+ H5F_object_flush_t object_flush; /* Information for object flush callback */
+};
+
+/*
+ * This is the top-level file descriptor. One of these structures is
+ * allocated every time H5Fopen() is called although they may contain pointers
+ * to shared H5F_file_t structs.
+ */
+struct H5F_t {
+ char *open_name; /* Name used to open file */
+ char *actual_name; /* Actual name of the file, after resolving symlinks, etc. */
+ char *extpath; /* Path for searching target external link file */
+ H5F_file_t *shared; /* The shared file info */
+ unsigned nopen_objs; /* Number of open object headers*/
+ H5FO_t *obj_count; /* # of time each object is opened through top file structure */
+ hid_t file_id; /* ID of this file */
+ hbool_t closing; /* File is in the process of being closed */
+ struct H5F_t *parent; /* Parent file that this file is mounted to */
+ unsigned nmounts; /* Number of children mounted to this file */
+#ifdef H5_HAVE_PARALLEL
+ H5P_coll_md_read_flag_t coll_md_read; /* Do all metadata reads collectively */
+ hbool_t coll_md_write; /* Do all metadata writes collectively */
+#endif /* H5_HAVE_PARALLEL */
+};
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare a free list to manage the H5F_t struct */
+H5FL_EXTERN(H5F_t);
+
+/* Declare a free list to manage the H5F_file_t struct */
+H5FL_EXTERN(H5F_file_t);
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* General routines */
+H5F_t *H5F_new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id,
+ hid_t fapl_id, H5FD_t *lf);
+H5_DLL herr_t H5F__dest(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t flush);
+H5_DLL herr_t H5F__flush(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t closing);
+H5_DLL htri_t H5F__is_hdf5(const char *name, hid_t meta_dxpl_id, hid_t raw_dxpl_id);
+H5_DLL herr_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr);
+H5_DLL ssize_t H5F_get_file_image(H5F_t *f, void *buf_ptr, size_t buf_len,
+ hid_t meta_dxpl_id, hid_t raw_dxpl_id);
+H5_DLL herr_t H5F_close(H5F_t *f);
+
+/* File mount related routines */
+H5_DLL herr_t H5F_close_mounts(H5F_t *f);
+H5_DLL int H5F_term_unmount_cb(void *obj_ptr, hid_t obj_id, void *key);
+H5_DLL herr_t H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs);
+
+/* Superblock related routines */
+H5_DLL herr_t H5F__super_init(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5F__super_read(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id,
+ hbool_t initial_read);
+H5_DLL herr_t H5F__super_size(H5F_t *f, hid_t dxpl_id, hsize_t *super_size, hsize_t *super_ext_size);
+H5_DLL herr_t H5F__super_free(H5F_super_t *sblock);
+
+/* Superblock extension related routines */
+H5_DLL herr_t H5F_super_ext_open(H5F_t *f, haddr_t ext_addr, H5O_loc_t *ext_ptr);
+H5_DLL herr_t H5F_super_ext_write_msg(H5F_t *f, hid_t dxpl_id, unsigned id,
+ void *mesg, hbool_t may_create, unsigned mesg_flags);
+H5_DLL herr_t H5F_super_ext_remove_msg(H5F_t *f, hid_t dxpl_id, unsigned id);
+H5_DLL herr_t H5F_super_ext_close(H5F_t *f, H5O_loc_t *ext_ptr, hid_t dxpl_id,
+ hbool_t was_created);
+
+/* Metadata accumulator routines */
+H5_DLL herr_t H5F__accum_read(const H5F_io_info2_t *fio_info, H5FD_mem_t type,
+ haddr_t addr, size_t size, void *buf);
+H5_DLL herr_t H5F__accum_write(const H5F_io_info2_t *fio_info, H5FD_mem_t type,
+ haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5F__accum_free(const H5F_io_info2_t *fio_info, H5FD_mem_t type,
+ haddr_t addr, hsize_t size);
+H5_DLL herr_t H5F__accum_flush(const H5F_io_info2_t *fio_info);
+H5_DLL herr_t H5F__accum_reset(const H5F_io_info2_t *fio_info, hbool_t flush);
+
+/* Shared file list related routines */
+H5_DLL herr_t H5F_sfile_add(H5F_file_t *shared);
+H5_DLL H5F_file_t * H5F_sfile_search(H5FD_t *lf);
+H5_DLL herr_t H5F_sfile_remove(H5F_file_t *shared);
+
+/* External file cache routines */
+H5_DLL H5F_efc_t *H5F_efc_create(unsigned max_nfiles);
+H5_DLL unsigned H5F_efc_max_nfiles(H5F_efc_t *efc);
+H5_DLL herr_t H5F_efc_release(H5F_efc_t *efc);
+H5_DLL herr_t H5F_efc_destroy(H5F_efc_t *efc);
+H5_DLL herr_t H5F_efc_try_close(H5F_t *f);
+
+/* Space allocation routines */
+H5_DLL haddr_t H5F_alloc(H5F_t *f, hid_t dxpl_id, H5F_mem_t type, hsize_t size, haddr_t *frag_addr, hsize_t *frag_size);
+H5_DLL herr_t H5F_free(H5F_t *f, hid_t dxpl_id, H5F_mem_t type, haddr_t addr, hsize_t size);
+H5_DLL htri_t H5F_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type,
+ haddr_t blk_end, hsize_t extra_requested);
+
+/* Functions that get/retrieve values from VFD layer */
+H5_DLL herr_t H5F__set_eoa(const H5F_t *f, H5F_mem_t type, haddr_t addr);
+H5_DLL herr_t H5F__set_base_addr(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5F__set_paged_aggr(const H5F_t *f, hbool_t paged);
+
+/* Functions that flush or evict */
+H5_DLL herr_t H5F__evict_cache_entries(H5F_t *f, hid_t dxpl_id);
+
+/* Testing functions */
+#ifdef H5F_TESTING
+H5_DLL herr_t H5F_get_sohm_mesg_count_test(hid_t fid, unsigned type_id,
+ size_t *mesg_count);
+H5_DLL herr_t H5F_check_cached_stab_test(hid_t file_id);
+H5_DLL herr_t H5F_get_maxaddr_test(hid_t file_id, haddr_t *maxaddr);
+H5_DLL herr_t H5F_get_sbe_addr_test(hid_t file_id, haddr_t *sbe_addr);
+#endif /* H5F_TESTING */
+
+#endif /* _H5Fpkg_H */
+
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
new file mode 100644
index 0000000..6f68a62
--- /dev/null
+++ b/src/H5Fprivate.h
@@ -0,0 +1,872 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains macros & information for file access
+ */
+
+#ifndef _H5Fprivate_H
+#define _H5Fprivate_H
+
+/* Include package's public header */
+#include "H5Fpublic.h"
+
+/* Public headers needed by this file */
+#include "H5FDpublic.h" /* File drivers */
+
+/* Private headers needed by this file */
+#ifdef H5_HAVE_PARALLEL
+#include "H5Pprivate.h" /* Property lists */
+#endif /* H5_HAVE_PARALLEL */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/*
+ * Encode and decode macros for file meta-data.
+ * Currently, all file meta-data is little-endian.
+ */
+
+# define INT16ENCODE(p, i) { \
+ *(p) = (uint8_t)( (unsigned)(i) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((unsigned)(i) >> 8) & 0xff); (p)++; \
+}
+
+# define UINT16ENCODE(p, i) { \
+ *(p) = (uint8_t)( (unsigned)(i) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((unsigned)(i) >> 8) & 0xff); (p)++; \
+}
+
+# define INT32ENCODE(p, i) { \
+ *(p) = (uint8_t)( (uint32_t)(i) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((uint32_t)(i) >> 8) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((uint32_t)(i) >> 16) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((uint32_t)(i) >> 24) & 0xff); (p)++; \
+}
+
+# define UINT32ENCODE(p, i) { \
+ *(p) = (uint8_t)( (i) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((i) >> 8) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((i) >> 16) & 0xff); (p)++; \
+ *(p) = (uint8_t)(((i) >> 24) & 0xff); (p)++; \
+}
+
+/* Encode an unsigned integer into a variable-sized buffer */
+/* (Assumes that the high bits of the integer are zero) */
+# define ENCODE_VAR(p, typ, n, l) { \
+ typ _n = (n); \
+ size_t _i; \
+ uint8_t *_p = (uint8_t*)(p); \
+ \
+ for(_i = 0; _i < l; _i++, _n >>= 8) \
+ *_p++ = (uint8_t)(_n & 0xff); \
+ (p) = (uint8_t*)(p) + l; \
+}
+
+/* Encode a 32-bit unsigned integer into a variable-sized buffer */
+/* (Assumes that the high bits of the integer are zero) */
+# define UINT32ENCODE_VAR(p, n, l) ENCODE_VAR(p, uint32_t, n, l)
+
+# define INT64ENCODE(p, n) { \
+ int64_t _n = (n); \
+ size_t _i; \
+ uint8_t *_p = (uint8_t*)(p); \
+ \
+ for (_i = 0; _i < sizeof(int64_t); _i++, _n >>= 8) \
+ *_p++ = (uint8_t)(_n & 0xff); \
+ for (/*void*/; _i < 8; _i++) \
+ *_p++ = (n) < 0 ? 0xff : 0; \
+ (p) = (uint8_t*)(p)+8; \
+}
+
+# define UINT64ENCODE(p, n) { \
+ uint64_t _n = (n); \
+ size_t _i; \
+ uint8_t *_p = (uint8_t*)(p); \
+ \
+ for (_i = 0; _i < sizeof(uint64_t); _i++, _n >>= 8) \
+ *_p++ = (uint8_t)(_n & 0xff); \
+ for (/*void*/; _i < 8; _i++) \
+ *_p++ = 0; \
+ (p) = (uint8_t*)(p) + 8; \
+}
+
+/* Encode a 64-bit unsigned integer into a variable-sized buffer */
+/* (Assumes that the high bits of the integer are zero) */
+# define UINT64ENCODE_VAR(p, n, l) ENCODE_VAR(p, uint64_t, n, l)
+
+/* Encode a 64-bit unsigned integer and its length into a variable-sized buffer */
+/* (Assumes that the high bits of the integer are zero) */
+# define UINT64ENCODE_VARLEN(p, n) { \
+ uint64_t __n = (uint64_t)(n); \
+ unsigned _s = H5VM_limit_enc_size(__n); \
+ \
+ *(p)++ = (uint8_t)_s; \
+ UINT64ENCODE_VAR(p, __n, _s); \
+}
+
+# define H5_ENCODE_UNSIGNED(p, n) { \
+ HDcompile_assert(sizeof(unsigned) == sizeof(uint32_t)); \
+ UINT32ENCODE(p, n) \
+}
+
+/* Assumes the endianness of uint64_t is the same as double */
+# define H5_ENCODE_DOUBLE(p, n) { \
+ uint64_t _n; \
+ size_t _u; \
+ uint8_t *_p = (uint8_t*)(p); \
+ \
+ HDcompile_assert(sizeof(double) == 8); \
+ HDcompile_assert(sizeof(double) == sizeof(uint64_t)); \
+ HDmemcpy(&_n, &n, sizeof(double)); \
+ for(_u = 0; _u < sizeof(uint64_t); _u++, _n >>= 8) \
+ *_p++ = (uint8_t)(_n & 0xff); \
+ (p) = (uint8_t *)(p) + 8; \
+}
+
+/* DECODE converts little endian bytes pointed by p to integer values and store
+ * it in i. For signed values, need to do sign-extension when converting
+ * the last byte which carries the sign bit.
+ * The macros does not require i be of a certain byte sizes. It just requires
+ * i be big enough to hold the intended value range. E.g. INT16DECODE works
+ * correctly even if i is actually a 64bit int like in a Cray.
+ */
+
+# define INT16DECODE(p, i) { \
+ (i) = (int16_t)((*(p) & 0xff)); (p)++; \
+ (i) |= (int16_t)(((*(p) & 0xff) << 8) | \
+ ((*(p) & 0x80) ? ~0xffff : 0x0)); (p)++; \
+}
+
+# define UINT16DECODE(p, i) { \
+ (i) = (uint16_t) (*(p) & 0xff); (p)++; \
+ (i) |= (uint16_t)((*(p) & 0xff) << 8); (p)++; \
+}
+
+# define INT32DECODE(p, i) { \
+ (i) = ((int32_t)(*(p) & (unsigned)0xff)); (p)++; \
+ (i) |= ((int32_t)(*(p) & (unsigned)0xff) << 8); (p)++; \
+ (i) |= ((int32_t)(*(p) & (unsigned)0xff) << 16); (p)++; \
+ (i) |= ((int32_t)(((*(p) & (unsigned)0xff) << 24) | \
+ ((*(p) & (unsigned)0x80) ? (unsigned)(~0xffffffff) : (unsigned)0x0))); (p)++; \
+}
+
+# define UINT32DECODE(p, i) { \
+ (i) = (uint32_t)(*(p) & 0xff); (p)++; \
+ (i) |= ((uint32_t)(*(p) & 0xff) << 8); (p)++; \
+ (i) |= ((uint32_t)(*(p) & 0xff) << 16); (p)++; \
+ (i) |= ((uint32_t)(*(p) & 0xff) << 24); (p)++; \
+}
+
+/* Decode a variable-sized buffer */
+/* (Assumes that the high bits of the integer will be zero) */
+# define DECODE_VAR(p, n, l) { \
+ size_t _i; \
+ \
+ n = 0; \
+ (p) += l; \
+ for (_i = 0; _i < l; _i++) \
+ n = (n << 8) | *(--p); \
+ (p) += l; \
+}
+
+/* Decode a variable-sized buffer into a 32-bit unsigned integer */
+/* (Assumes that the high bits of the integer will be zero) */
+# define UINT32DECODE_VAR(p, n, l) DECODE_VAR(p, n, l)
+
+# define INT64DECODE(p, n) { \
+ /* WE DON'T CHECK FOR OVERFLOW! */ \
+ size_t _i; \
+ \
+ n = 0; \
+ (p) += 8; \
+ for (_i = 0; _i < sizeof(int64_t); _i++) \
+ n = (n << 8) | *(--p); \
+ (p) += 8; \
+}
+
+# define UINT64DECODE(p, n) { \
+ /* WE DON'T CHECK FOR OVERFLOW! */ \
+ size_t _i; \
+ \
+ n = 0; \
+ (p) += 8; \
+ for (_i = 0; _i < sizeof(uint64_t); _i++) \
+ n = (n << 8) | *(--p); \
+ (p) += 8; \
+}
+
+/* Decode a variable-sized buffer into a 64-bit unsigned integer */
+/* (Assumes that the high bits of the integer will be zero) */
+# define UINT64DECODE_VAR(p, n, l) DECODE_VAR(p, n, l)
+
+/* Decode a 64-bit unsigned integer and its length from a variable-sized buffer */
+/* (Assumes that the high bits of the integer will be zero) */
+# define UINT64DECODE_VARLEN(p, n) { \
+ unsigned _s = *(p)++; \
+ \
+ UINT64DECODE_VAR(p, n, _s); \
+}
+
+# define H5_DECODE_UNSIGNED(p, n) { \
+ HDcompile_assert(sizeof(unsigned) == sizeof(uint32_t)); \
+ UINT32DECODE(p, n) \
+}
+
+/* Assumes the endianness of uint64_t is the same as double */
+# define H5_DECODE_DOUBLE(p, n) { \
+ uint64_t _n; \
+ size_t _u; \
+ \
+ HDcompile_assert(sizeof(double) == 8); \
+ HDcompile_assert(sizeof(double) == sizeof(uint64_t)); \
+ _n = 0; \
+ (p) += 8; \
+ for(_u = 0; _u < sizeof(uint64_t); _u++) \
+ _n = (_n << 8) | *(--p); \
+ HDmemcpy(&(n), &_n, sizeof(double)); \
+ (p) += 8; \
+}
+
+/* Address-related macros */
+#define H5F_addr_overflow(X,Z) (HADDR_UNDEF==(X) || \
+ HADDR_UNDEF==(X)+(haddr_t)(Z) || \
+ (X)+(haddr_t)(Z)<(X))
+#define H5F_addr_defined(X) ((X)!=HADDR_UNDEF)
+/* The H5F_addr_eq() macro guarantees that Y is not HADDR_UNDEF by making
+ * certain that X is not HADDR_UNDEF and then checking that X equals Y
+ */
+#define H5F_addr_eq(X,Y) ((X)!=HADDR_UNDEF && \
+ (X)==(Y))
+#define H5F_addr_ne(X,Y) (!H5F_addr_eq((X),(Y)))
+#define H5F_addr_lt(X,Y) ((X)!=HADDR_UNDEF && \
+ (Y)!=HADDR_UNDEF && \
+ (X)<(Y))
+#define H5F_addr_le(X,Y) ((X)!=HADDR_UNDEF && \
+ (Y)!=HADDR_UNDEF && \
+ (X)<=(Y))
+#define H5F_addr_gt(X,Y) ((X)!=HADDR_UNDEF && \
+ (Y)!=HADDR_UNDEF && \
+ (X)>(Y))
+#define H5F_addr_ge(X,Y) ((X)!=HADDR_UNDEF && \
+ (Y)!=HADDR_UNDEF && \
+ (X)>=(Y))
+#define H5F_addr_cmp(X,Y) (H5F_addr_eq((X), (Y)) ? 0 : \
+ (H5F_addr_lt((X), (Y)) ? -1 : 1))
+#define H5F_addr_pow2(N) ((haddr_t)1<<(N))
+#define H5F_addr_overlap(O1,L1,O2,L2) (((O1) < (O2) && ((O1) + (L1)) > (O2)) || \
+ ((O1) >= (O2) && (O1) < ((O2) + (L2))))
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5F_MODULE
+#define H5F_INTENT(F) ((F)->shared->flags)
+#define H5F_OPEN_NAME(F) ((F)->open_name)
+#define H5F_ACTUAL_NAME(F) ((F)->actual_name)
+#define H5F_EXTPATH(F) ((F)->extpath)
+#define H5F_SHARED(F) ((F)->shared)
+#define H5F_SAME_SHARED(F1, F2) ((F1)->shared == (F2)->shared)
+#define H5F_NOPEN_OBJS(F) ((F)->nopen_objs)
+#define H5F_INCR_NOPEN_OBJS(F) ((F)->nopen_objs++)
+#define H5F_DECR_NOPEN_OBJS(F) ((F)->nopen_objs--)
+#define H5F_FILE_ID(F) ((F)->file_id)
+#define H5F_PARENT(F) ((F)->parent)
+#define H5F_NMOUNTS(F) ((F)->nmounts)
+#define H5F_GET_READ_ATTEMPTS(F) ((F)->shared->read_attempts)
+#define H5F_DRIVER_ID(F) ((F)->shared->lf->driver_id)
+#define H5F_GET_FILENO(F,FILENUM) ((FILENUM) = (F)->shared->lf->fileno)
+#define H5F_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags & (FL))
+#define H5F_BASE_ADDR(F) ((F)->shared->sblock->base_addr)
+#define H5F_SYM_LEAF_K(F) ((F)->shared->sblock->sym_leaf_k)
+#define H5F_KVALUE(F,T) ((F)->shared->sblock->btree_k[(T)->id])
+#define H5F_NREFS(F) ((F)->shared->nrefs)
+#define H5F_SIZEOF_ADDR(F) ((F)->shared->sizeof_addr)
+#define H5F_SIZEOF_SIZE(F) ((F)->shared->sizeof_size)
+#define H5F_SOHM_ADDR(F) ((F)->shared->sohm_addr)
+#define H5F_SET_SOHM_ADDR(F, A) ((F)->shared->sohm_addr = (A))
+#define H5F_SOHM_VERS(F) ((F)->shared->sohm_vers)
+#define H5F_SET_SOHM_VERS(F, V) ((F)->shared->sohm_vers = (V))
+#define H5F_SOHM_NINDEXES(F) ((F)->shared->sohm_nindexes)
+#define H5F_SET_SOHM_NINDEXES(F, N) ((F)->shared->sohm_nindexes = (N))
+#define H5F_FCPL(F) ((F)->shared->fcpl_id)
+#define H5F_GET_FC_DEGREE(F) ((F)->shared->fc_degree)
+#define H5F_EVICT_ON_CLOSE(F) ((F)->shared->evict_on_close)
+#define H5F_RDCC_NSLOTS(F) ((F)->shared->rdcc_nslots)
+#define H5F_RDCC_NBYTES(F) ((F)->shared->rdcc_nbytes)
+#define H5F_RDCC_W0(F) ((F)->shared->rdcc_w0)
+#define H5F_SIEVE_BUF_SIZE(F) ((F)->shared->sieve_buf_size)
+#define H5F_GC_REF(F) ((F)->shared->gc_ref)
+#define H5F_USE_LATEST_FLAGS(F,FL) ((F)->shared->latest_flags & (FL))
+#define H5F_STORE_MSG_CRT_IDX(F) ((F)->shared->store_msg_crt_idx)
+#define H5F_SET_STORE_MSG_CRT_IDX(F, FL) ((F)->shared->store_msg_crt_idx = (FL))
+#define H5F_GRP_BTREE_SHARED(F) ((F)->shared->grp_btree_shared)
+#define H5F_SET_GRP_BTREE_SHARED(F, RC) (((F)->shared->grp_btree_shared = (RC)) ? SUCCEED : FAIL)
+#define H5F_USE_TMP_SPACE(F) ((F)->shared->fs.use_tmp_space)
+#define H5F_IS_TMP_ADDR(F, ADDR) (H5F_addr_le((F)->shared->fs.tmp_addr, (ADDR)))
+#define H5F_SET_LATEST_FLAGS(F, FL) ((F)->shared->latest_flags = (FL))
+#ifdef H5_HAVE_PARALLEL
+#define H5F_COLL_MD_READ(F) ((F)->coll_md_read)
+#endif /* H5_HAVE_PARALLEL */
+#define H5F_USE_MDC_LOGGING(F) ((F)->shared->use_mdc_logging)
+#define H5F_START_MDC_LOG_ON_ACCESS(F) ((F)->shared->start_mdc_log_on_access)
+#define H5F_MDC_LOG_LOCATION(F) ((F)->shared->mdc_log_location)
+#define H5F_ALIGNMENT(F) ((F)->shared->alignment)
+#define H5F_THRESHOLD(F) ((F)->shared->threshold)
+#define H5F_PGEND_META_THRES(F) ((F)->shared->fs.pgend_meta_thres)
+#define H5F_POINT_OF_NO_RETURN(F) ((F)->shared->fs.point_of_no_return)
+#define H5F_FIRST_ALLOC_DEALLOC(F) ((F)->shared->first_alloc_dealloc)
+#define H5F_EOA_PRE_FSM_FSALLOC(F) ((F)->shared->eoa_pre_fsm_fsalloc)
+#else /* H5F_MODULE */
+#define H5F_INTENT(F) (H5F_get_intent(F))
+#define H5F_OPEN_NAME(F) (H5F_get_open_name(F))
+#define H5F_ACTUAL_NAME(F) (H5F_get_actual_name(F))
+#define H5F_EXTPATH(F) (H5F_get_extpath(F))
+#define H5F_SHARED(F) (H5F_get_shared(F))
+#define H5F_SAME_SHARED(F1, F2) (H5F_same_shared((F1), (F2)))
+#define H5F_NOPEN_OBJS(F) (H5F_get_nopen_objs(F))
+#define H5F_INCR_NOPEN_OBJS(F) (H5F_incr_nopen_objs(F))
+#define H5F_DECR_NOPEN_OBJS(F) (H5F_decr_nopen_objs(F))
+#define H5F_FILE_ID(F) (H5F_get_file_id(F))
+#define H5F_PARENT(F) (H5F_get_parent(F))
+#define H5F_NMOUNTS(F) (H5F_get_nmounts(F))
+#define H5F_GET_READ_ATTEMPTS(F) (H5F_get_read_attempts(F))
+#define H5F_DRIVER_ID(F) (H5F_get_driver_id(F))
+#define H5F_GET_FILENO(F,FILENUM) (H5F_get_fileno((F), &(FILENUM)))
+#define H5F_HAS_FEATURE(F,FL) (H5F_has_feature(F,FL))
+#define H5F_BASE_ADDR(F) (H5F_get_base_addr(F))
+#define H5F_SYM_LEAF_K(F) (H5F_sym_leaf_k(F))
+#define H5F_KVALUE(F,T) (H5F_Kvalue(F,T))
+#define H5F_NREFS(F) (H5F_get_nrefs(F))
+#define H5F_SIZEOF_ADDR(F) (H5F_sizeof_addr(F))
+#define H5F_SIZEOF_SIZE(F) (H5F_sizeof_size(F))
+#define H5F_SOHM_ADDR(F) (H5F_get_sohm_addr(F))
+#define H5F_SET_SOHM_ADDR(F, A) (H5F_set_sohm_addr((F), (A)))
+#define H5F_SOHM_VERS(F) (H5F_get_sohm_vers(F))
+#define H5F_SET_SOHM_VERS(F, V) (H5F_set_sohm_vers((F), (V)))
+#define H5F_SOHM_NINDEXES(F) (H5F_get_sohm_nindexes(F))
+#define H5F_SET_SOHM_NINDEXES(F, N) (H5F_set_sohm_nindexes((F), (N)))
+#define H5F_FCPL(F) (H5F_get_fcpl(F))
+#define H5F_GET_FC_DEGREE(F) (H5F_get_fc_degree(F))
+#define H5F_EVICT_ON_CLOSE(F) (H5F_get_evict_on_close(F))
+#define H5F_RDCC_NSLOTS(F) (H5F_rdcc_nslots(F))
+#define H5F_RDCC_NBYTES(F) (H5F_rdcc_nbytes(F))
+#define H5F_RDCC_W0(F) (H5F_rdcc_w0(F))
+#define H5F_SIEVE_BUF_SIZE(F) (H5F_sieve_buf_size(F))
+#define H5F_GC_REF(F) (H5F_gc_ref(F))
+#define H5F_USE_LATEST_FLAGS(F,FL) (H5F_use_latest_flags(F,FL))
+#define H5F_STORE_MSG_CRT_IDX(F) (H5F_store_msg_crt_idx(F))
+#define H5F_SET_STORE_MSG_CRT_IDX(F, FL) (H5F_set_store_msg_crt_idx((F), (FL)))
+#define H5F_GRP_BTREE_SHARED(F) (H5F_grp_btree_shared(F))
+#define H5F_SET_GRP_BTREE_SHARED(F, RC) (H5F_set_grp_btree_shared((F), (RC)))
+#define H5F_USE_TMP_SPACE(F) (H5F_use_tmp_space(F))
+#define H5F_IS_TMP_ADDR(F, ADDR) (H5F_is_tmp_addr((F), (ADDR)))
+#define H5F_SET_LATEST_FLAGS(F, FL) (H5F_set_latest_flags((F), (FL)))
+#ifdef H5_HAVE_PARALLEL
+#define H5F_COLL_MD_READ(F) (H5F_coll_md_read(F))
+#endif /* H5_HAVE_PARALLEL */
+#define H5F_USE_MDC_LOGGING(F) (H5F_use_mdc_logging(F))
+#define H5F_START_MDC_LOG_ON_ACCESS(F) (H5F_start_mdc_log_on_access(F))
+#define H5F_MDC_LOG_LOCATION(F) (H5F_mdc_log_location(F))
+#define H5F_ALIGNMENT(F) (H5F_get_alignment(F))
+#define H5F_THRESHOLD(F) (H5F_get_threshold(F))
+#define H5F_PGEND_META_THRES(F) (H5F_get_pgend_meta_thres(F))
+#define H5F_POINT_OF_NO_RETURN(F) (H5F_get_point_of_no_return(F))
+#define H5F_FIRST_ALLOC_DEALLOC(F) (H5F_get_first_alloc_dealloc(F))
+#define H5F_EOA_PRE_FSM_FSALLOC(F) (H5F_get_eoa_pre_fsm_fsalloc(F))
+#endif /* H5F_MODULE */
+
+
+/* Macros to encode/decode offset/length's for storing in the file */
+#define H5F_ENCODE_OFFSET(f,p,o) switch(H5F_SIZEOF_ADDR(f)) { \
+ case 4: UINT32ENCODE(p,o); break; \
+ case 8: UINT64ENCODE(p,o); break; \
+ case 2: UINT16ENCODE(p,o); break; \
+}
+
+#define H5F_DECODE_OFFSET(f,p,o) switch (H5F_SIZEOF_ADDR (f)) { \
+ case 4: UINT32DECODE(p, o); break; \
+ case 8: UINT64DECODE(p, o); break; \
+ case 2: UINT16DECODE(p, o); break; \
+}
+
+#define H5F_ENCODE_LENGTH_LEN(p,l,s) switch(s) { \
+ case 4: UINT32ENCODE(p,l); break; \
+ case 8: UINT64ENCODE(p,l); break; \
+ case 2: UINT16ENCODE(p,l); break; \
+ default: HDassert("bad sizeof size" && 0); \
+}
+
+#define H5F_ENCODE_LENGTH(f,p,l) H5F_ENCODE_LENGTH_LEN(p,l,H5F_SIZEOF_SIZE(f))
+
+#define H5F_DECODE_LENGTH_LEN(p,l,s) switch(s) { \
+ case 4: UINT32DECODE(p,l); break; \
+ case 8: UINT64DECODE(p,l); break; \
+ case 2: UINT16DECODE(p,l); break; \
+ default: HDassert("bad sizeof size" && 0); \
+}
+
+#define H5F_DECODE_LENGTH(f,p,l) H5F_DECODE_LENGTH_LEN(p,l,H5F_SIZEOF_SIZE(f))
+
+/*
+ * Macros that check for overflows. These are somewhat dangerous to fiddle
+ * with.
+ */
+#if (H5_SIZEOF_SIZE_T >= H5_SIZEOF_OFF_T)
+# define H5F_OVERFLOW_SIZET2OFFT(X) \
+ ((size_t)(X)>=(size_t)((size_t)1<<(8*sizeof(HDoff_t)-1)))
+#else
+# define H5F_OVERFLOW_SIZET2OFFT(X) 0
+#endif
+#if (H5_SIZEOF_HSIZE_T >= H5_SIZEOF_OFF_T)
+# define H5F_OVERFLOW_HSIZET2OFFT(X) \
+ ((hsize_t)(X) >= (hsize_t)((hsize_t)1 << (8 * sizeof(HDoff_t) - 1)))
+#else
+# define H5F_OVERFLOW_HSIZET2OFFT(X) 0
+#endif
+
+/* Sizes of object addresses & sizes in the file (in bytes) */
+#define H5F_OBJ_ADDR_SIZE sizeof(haddr_t)
+#define H5F_OBJ_SIZE_SIZE sizeof(hsize_t)
+
+/* File-wide default character encoding can not yet be set via the file
+ * creation property list and is always ASCII. */
+#define H5F_DEFAULT_CSET H5T_CSET_ASCII
+
+/* ========= File Creation properties ============ */
+#define H5F_CRT_USER_BLOCK_NAME "block_size" /* Size of the file user block in bytes */
+#define H5F_CRT_SYM_LEAF_NAME "symbol_leaf" /* 1/2 rank for symbol table leaf nodes */
+#define H5F_CRT_SYM_LEAF_DEF 4
+#define H5F_CRT_BTREE_RANK_NAME "btree_rank" /* 1/2 rank for btree internal nodes */
+#define H5F_CRT_ADDR_BYTE_NUM_NAME "addr_byte_num" /* Byte number in an address */
+#define H5F_CRT_OBJ_BYTE_NUM_NAME "obj_byte_num" /* Byte number for object size */
+#define H5F_CRT_SUPER_VERS_NAME "super_version" /* Version number of the superblock */
+#define H5F_CRT_SHMSG_NINDEXES_NAME "num_shmsg_indexes" /* Number of shared object header message indexes */
+#define H5F_CRT_SHMSG_INDEX_TYPES_NAME "shmsg_message_types" /* Types of message in each index */
+#define H5F_CRT_SHMSG_INDEX_MINSIZE_NAME "shmsg_message_minsize" /* Minimum size of messages in each index */
+#define H5F_CRT_SHMSG_LIST_MAX_NAME "shmsg_list_max" /* Shared message list maximum size */
+#define H5F_CRT_SHMSG_BTREE_MIN_NAME "shmsg_btree_min" /* Shared message B-tree minimum size */
+#define H5F_CRT_FILE_SPACE_STRATEGY_NAME "file_space_strategy" /* File space handling strategy */
+#define H5F_CRT_FREE_SPACE_PERSIST_NAME "free_space_persist" /* Free-space persisting status */
+#define H5F_CRT_FREE_SPACE_THRESHOLD_NAME "free_space_threshold" /* Free space section threshold */
+#define H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME "file_space_page_size" /* File space page size */
+
+
+
+/* ========= File Access properties ============ */
+#define H5F_ACS_META_CACHE_INIT_CONFIG_NAME "mdc_initCacheCfg" /* Initial metadata cache resize configuration */
+#define H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME "rdcc_nslots" /* Size of raw data chunk cache(slots) */
+#define H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME "rdcc_nbytes" /* Size of raw data chunk cache(bytes) */
+#define H5F_ACS_PREEMPT_READ_CHUNKS_NAME "rdcc_w0" /* Preemption read chunks first */
+#define H5F_ACS_ALIGN_THRHD_NAME "threshold" /* Threshold for alignment */
+#define H5F_ACS_ALIGN_NAME "align" /* Alignment */
+#define H5F_ACS_META_BLOCK_SIZE_NAME "meta_block_size" /* Minimum metadata allocation block size (when aggregating metadata allocations) */
+#define H5F_ACS_SIEVE_BUF_SIZE_NAME "sieve_buf_size" /* Maximum sieve buffer size (when data sieving is allowed by file driver) */
+#define H5F_ACS_SDATA_BLOCK_SIZE_NAME "sdata_block_size" /* Minimum "small data" allocation block size (when aggregating "small" raw data allocations) */
+#define H5F_ACS_GARBG_COLCT_REF_NAME "gc_ref" /* Garbage-collect references */
+#define H5F_ACS_FILE_DRV_NAME "driver-id/info" /* File driver ID & info */
+#define H5F_ACS_CLOSE_DEGREE_NAME "close_degree" /* File close degree */
+#define H5F_ACS_FAMILY_OFFSET_NAME "family_offset" /* Offset position in file for family file driver */
+#define H5F_ACS_FAMILY_NEWSIZE_NAME "family_newsize" /* New member size of family driver. (private property only used by h5repart) */
+#define H5F_ACS_FAMILY_TO_SEC2_NAME "family_to_sec2" /* Whether to convert family to sec2 driver. (private property only used by h5repart) */
+#define H5F_ACS_MULTI_TYPE_NAME "multi_type" /* Data type in multi file driver */
+#define H5F_ACS_LATEST_FORMAT_NAME "latest_format" /* 'Use latest format version' flag */
+#define H5F_ACS_WANT_POSIX_FD_NAME "want_posix_fd" /* Internal: query the file descriptor from the core VFD, instead of the memory address */
+#define H5F_ACS_METADATA_READ_ATTEMPTS_NAME "metadata_read_attempts" /* # of metadata read attempts */
+#define H5F_ACS_OBJECT_FLUSH_CB_NAME "object_flush_cb" /* Object flush callback */
+#define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */
+#define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */
+#define H5F_ACS_CLEAR_STATUS_FLAGS_NAME "clear_status_flags" /* Whether to clear superblock status_flags (private property only used by h5clear) */
+#define H5F_ACS_USE_MDC_LOGGING_NAME "use_mdc_logging" /* Whether to use metadata cache logging */
+#define H5F_ACS_MDC_LOG_LOCATION_NAME "mdc_log_location" /* Name of metadata cache log location */
+#define H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME "start_mdc_log_on_access" /* Whether logging starts on file create/open */
+#define H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME "core_write_tracking_flag" /* Whether or not core VFD backing store write tracking is enabled */
+#define H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME "evict_on_close_flag" /* Whether or not the metadata cache will evict objects on close */
+#define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME "core_write_tracking_page_size" /* The page size in kiB when core VFD write tracking is enabled */
+#define H5F_ACS_COLL_MD_WRITE_FLAG_NAME "collective_metadata_write" /* property indicating whether metadata writes are done collectively or not */
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME "mdc_initCacheImageCfg" /* Initial metadata cache image creation configuration */
+#define H5F_ACS_PAGE_BUFFER_SIZE_NAME "page_buffer_size" /* the maximum size for the page buffer cache */
+#define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME "page_buffer_min_meta_perc" /* the min metadata percentage for the page buffer cache */
+#define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME "page_buffer_min_raw_perc" /* the min raw data percentage for the page buffer cache */
+
+/* ======================== File Mount properties ====================*/
+#define H5F_MNT_SYM_LOCAL_NAME "local" /* Whether absolute symlinks local to file. */
+
+
+#ifdef H5_HAVE_PARALLEL
+/* Which process writes metadata */
+#define H5_PAR_META_WRITE 0
+#endif /* H5_HAVE_PARALLEL */
+
+/* Define the HDF5 file signature */
+#define H5F_SIGNATURE "\211HDF\r\n\032\n"
+#define H5F_SIGNATURE_LEN 8
+
+/* Version #'s of the major components of the file format */
+#define HDF5_SUPERBLOCK_VERSION_DEF 0 /* The default super block format */
+#define HDF5_SUPERBLOCK_VERSION_1 1 /* Version with non-default B-tree 'K' value */
+#define HDF5_SUPERBLOCK_VERSION_2 2 /* Revised version with superblock extension and checksum */
+#define HDF5_SUPERBLOCK_VERSION_3 3 /* With file locking and consistency flags (at least this version for SWMR support) */
+#define HDF5_SUPERBLOCK_VERSION_LATEST HDF5_SUPERBLOCK_VERSION_3 /* The maximum super block format */
+#define HDF5_SUPERBLOCK_VERSION_V18_LATEST HDF5_SUPERBLOCK_VERSION_2 /* The latest superblock version for v18 */
+#define HDF5_FREESPACE_VERSION 0 /* of the Free-Space Info */
+#define HDF5_OBJECTDIR_VERSION 0 /* of the Object Directory format */
+#define HDF5_SHAREDHEADER_VERSION 0 /* of the Shared-Header Info */
+#define HDF5_DRIVERINFO_VERSION_0 0 /* of the Driver Information Block*/
+
+/* B-tree internal 'K' values */
+#define HDF5_BTREE_SNODE_IK_DEF 16
+#define HDF5_BTREE_CHUNK_IK_DEF 32 /* Note! this value is assumed
+ to be 32 for version 0
+ of the superblock and
+ if it is changed, the code
+ must compensate. -QAK
+ */
+#define HDF5_BTREE_IK_MAX_ENTRIES 65536 /* 2^16 - 2 bytes for storing entries (children) */
+ /* See format specification on version 1 B-trees */
+
+/* Default file space handling strategy */
+#define H5F_FILE_SPACE_STRATEGY_DEF H5F_FSPACE_STRATEGY_FSM_AGGR
+
+/* Default free space section threshold used by free-space managers */
+#define H5F_FREE_SPACE_PERSIST_DEF FALSE
+
+/* Default free space section threshold used by free-space managers */
+#define H5F_FREE_SPACE_THRESHOLD_DEF 1
+
+/* For paged aggregation: default file space page size when not set */
+#define H5F_FILE_SPACE_PAGE_SIZE_DEF 4096
+/* For paged aggregation: minimum value for file space page size */
+#define H5F_FILE_SPACE_PAGE_SIZE_MIN 512
+
+/* For paged aggregation: drop free-space with size <= this threshold for small meta section */
+#define H5F_FILE_SPACE_PGEND_META_THRES 10
+
+/* Default for threshold for alignment (can be set via H5Pset_alignment()) */
+#define H5F_ALIGN_DEF 1
+/* Default for alignment (can be set via H5Pset_alignment()) */
+#define H5F_ALIGN_THRHD_DEF 1
+/* Default size for meta data aggregation block (can be set via H5Pset_meta_block_size()) */
+#define H5F_META_BLOCK_SIZE_DEF 2048
+/* Default size for small data aggregation block (can be set via H5Pset_small_data_block_size()) */
+#define H5F_SDATA_BLOCK_SIZE_DEF 2048
+
+/* Check for file using paged aggregation */
+#define H5F_PAGED_AGGR(F) (F->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE && F->shared->fs_page_size)
+
+/* Metadata read attempt values */
+#define H5F_METADATA_READ_ATTEMPTS 1 /* Default # of read attempts for non-SWMR access */
+#define H5F_SWMR_METADATA_READ_ATTEMPTS 100 /* Default # of read attempts for SWMR access */
+
+
+/* Macros to define signatures of all objects in the file */
+
+/* Size of signature information (on disk) */
+/* (all on-disk signatures should be this length) */
+#define H5_SIZEOF_MAGIC 4
+
+/* Size of checksum information (on disk) */
+/* (all on-disk checksums should be this length) */
+#define H5_SIZEOF_CHKSUM 4
+
+/* v1 B-tree node signature */
+#define H5B_MAGIC "TREE"
+
+/* v2 B-tree signatures */
+#define H5B2_HDR_MAGIC "BTHD" /* Header */
+#define H5B2_INT_MAGIC "BTIN" /* Internal node */
+#define H5B2_LEAF_MAGIC "BTLF" /* Leaf node */
+
+/* Extensible array signatures */
+#define H5EA_HDR_MAGIC "EAHD" /* Header */
+#define H5EA_IBLOCK_MAGIC "EAIB" /* Index block */
+#define H5EA_SBLOCK_MAGIC "EASB" /* Super block */
+#define H5EA_DBLOCK_MAGIC "EADB" /* Data block */
+
+/* Fixed array signatures */
+#define H5FA_HDR_MAGIC "FAHD" /* Header */
+#define H5FA_DBLOCK_MAGIC "FADB" /* Data block */
+
+/* Free space signatures */
+#define H5FS_HDR_MAGIC "FSHD" /* Header */
+#define H5FS_SINFO_MAGIC "FSSE" /* Serialized sections */
+
+/* Symbol table node signature */
+#define H5G_NODE_MAGIC "SNOD"
+
+/* Fractal heap signatures */
+#define H5HF_HDR_MAGIC "FRHP" /* Header */
+#define H5HF_IBLOCK_MAGIC "FHIB" /* Indirect block */
+#define H5HF_DBLOCK_MAGIC "FHDB" /* Direct block */
+
+/* Global heap signature */
+#define H5HG_MAGIC "GCOL"
+
+/* Local heap signature */
+#define H5HL_MAGIC "HEAP"
+
+/* Object header signatures */
+#define H5O_HDR_MAGIC "OHDR" /* Header */
+#define H5O_CHK_MAGIC "OCHK" /* Continuation chunk */
+
+/* Shared Message signatures */
+#define H5SM_TABLE_MAGIC "SMTB" /* Shared Message Table */
+#define H5SM_LIST_MAGIC "SMLI" /* Shared Message List */
+
+
+/* Latest format will activate the following latest version support */
+/* "latest_flags" in H5F_file_t */
+#define H5F_LATEST_DATATYPE 0x0001
+#define H5F_LATEST_DATASPACE 0x0002
+#define H5F_LATEST_ATTRIBUTE 0x0004
+#define H5F_LATEST_FILL_MSG 0x0008
+#define H5F_LATEST_PLINE_MSG 0x0010
+#define H5F_LATEST_LAYOUT_MSG 0x0020
+#define H5F_LATEST_NO_MOD_TIME_MSG 0x0040
+#define H5F_LATEST_STYLE_GROUP 0x0080
+#define H5F_LATEST_OBJ_HEADER 0x0100
+#define H5F_LATEST_SUPERBLOCK 0x0200
+#define H5F_LATEST_ALL_FLAGS (H5F_LATEST_DATATYPE | H5F_LATEST_DATASPACE | H5F_LATEST_ATTRIBUTE | H5F_LATEST_FILL_MSG | H5F_LATEST_PLINE_MSG | H5F_LATEST_LAYOUT_MSG | H5F_LATEST_NO_MOD_TIME_MSG | H5F_LATEST_STYLE_GROUP | H5F_LATEST_OBJ_HEADER | H5F_LATEST_SUPERBLOCK)
+
+#define H5F_LATEST_DSET_MSG_FLAGS (H5F_LATEST_FILL_MSG | H5F_LATEST_PLINE_MSG | H5F_LATEST_LAYOUT_MSG)
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Forward declarations (for prototypes & type definitions) */
+struct H5B_class_t;
+struct H5UC_t;
+struct H5O_loc_t;
+struct H5HG_heap_t;
+struct H5P_genplist_t;
+
+/* Forward declarations for anonymous H5F objects */
+
+/* Main file structures */
+typedef struct H5F_t H5F_t;
+typedef struct H5F_file_t H5F_file_t;
+
+/* Block aggregation structure */
+typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
+
+/* Structure for object flush callback property (H5Pset_object_flush_cb)*/
+typedef struct H5F_object_flush_t {
+ H5F_flush_cb_t func; /* The callback function */
+ void *udata; /* User data */
+} H5F_object_flush_t;
+
+/* I/O Info for an operation (old) */
+typedef struct H5F_io_info_t {
+ const H5F_t *f; /* File object */
+ const struct H5P_genplist_t *dxpl; /* DXPL object */
+} H5F_io_info_t;
+
+/* I/O Info for an operation */
+/* (Migrate toward this one, so that both raw data & metadata DXPLs are available) */
+typedef struct H5F_io_info2_t {
+ const H5F_t *f; /* File object */
+ const struct H5P_genplist_t *meta_dxpl; /* Metadata DXPL object */
+ const struct H5P_genplist_t *raw_dxpl; /* Raw data DXPL object */
+} H5F_io_info2_t;
+
+/* Concise info about a block of bytes in a file */
+typedef struct H5F_block_t {
+ haddr_t offset; /* Offset of the block in the file */
+ hsize_t length; /* Length of the block in the file */
+} H5F_block_t;
+
+/* Enum for free space manager state */
+typedef enum H5F_fs_state_t {
+ H5F_FS_STATE_CLOSED = 0, /* Free space manager is closed */
+ H5F_FS_STATE_OPEN = 1, /* Free space manager has been opened */
+ H5F_FS_STATE_DELETING = 2 /* Free space manager is being deleted */
+} H5F_fs_state_t;
+
+/* For paged aggregation */
+/* The values 0 to 6 is the same as H5F_mem_t */
+typedef enum H5F_mem_page_t {
+ H5F_MEM_PAGE_DEFAULT = 0, /* Not used */
+ H5F_MEM_PAGE_SUPER = 1,
+ H5F_MEM_PAGE_BTREE = 2,
+ H5F_MEM_PAGE_DRAW = 3,
+ H5F_MEM_PAGE_GHEAP = 4,
+ H5F_MEM_PAGE_LHEAP = 5,
+ H5F_MEM_PAGE_OHDR = 6,
+ H5F_MEM_PAGE_LARGE_SUPER = 7,
+ H5F_MEM_PAGE_LARGE_BTREE = 8,
+ H5F_MEM_PAGE_LARGE_DRAW = 9,
+ H5F_MEM_PAGE_LARGE_GHEAP = 10,
+ H5F_MEM_PAGE_LARGE_LHEAP = 11,
+ H5F_MEM_PAGE_LARGE_OHDR = 12,
+ H5F_MEM_PAGE_NTYPES = 13 /* Sentinel value - must be last */
+} H5F_mem_page_t;
+
+#define H5F_MEM_PAGE_META H5F_MEM_PAGE_SUPER /* Small-sized meta data */
+#define H5F_MEM_PAGE_GENERIC H5F_MEM_PAGE_LARGE_SUPER /* Large-sized generic: meta and raw */
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+
+/* Private functions */
+H5_DLL H5F_t *H5F_open(const char *name, unsigned flags, hid_t fcpl_id,
+ hid_t fapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5F_try_close(H5F_t *f, hbool_t *was_closed/*out*/);
+
+/* Functions than retrieve values from the file struct */
+H5_DLL unsigned H5F_get_intent(const H5F_t *f);
+H5_DLL char *H5F_get_open_name(const H5F_t *f);
+H5_DLL char *H5F_get_actual_name(const H5F_t *f);
+H5_DLL char *H5F_get_extpath(const H5F_t *f);
+H5_DLL H5F_file_t *H5F_get_shared(const H5F_t *f);
+H5_DLL hbool_t H5F_same_shared(const H5F_t *f1, const H5F_t *f2);
+H5_DLL unsigned H5F_get_nopen_objs(const H5F_t *f);
+H5_DLL unsigned H5F_incr_nopen_objs(H5F_t *f);
+H5_DLL unsigned H5F_decr_nopen_objs(H5F_t *f);
+H5_DLL hid_t H5F_get_file_id(const H5F_t *f);
+H5_DLL H5F_t *H5F_get_parent(const H5F_t *f);
+H5_DLL unsigned H5F_get_nmounts(const H5F_t *f);
+H5_DLL unsigned H5F_get_read_attempts(const H5F_t *f);
+H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref);
+H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref);
+H5_DLL herr_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr);
+H5_DLL herr_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr);
+H5_DLL hsize_t H5F_get_pgend_meta_thres(const H5F_t *f);
+H5_DLL hbool_t H5F_get_point_of_no_return(const H5F_t *f);
+H5_DLL hbool_t H5F_get_first_alloc_dealloc(const H5F_t *f);
+H5_DLL hbool_t H5F_get_eoa_pre_fsm_fsalloc(const H5F_t *f);
+
+/* Functions than retrieve values set/cached from the superblock/FCPL */
+H5_DLL haddr_t H5F_get_base_addr(const H5F_t *f);
+H5_DLL unsigned H5F_sym_leaf_k(const H5F_t *f);
+H5_DLL unsigned H5F_Kvalue(const H5F_t *f, const struct H5B_class_t *type);
+H5_DLL unsigned H5F_get_nrefs(const H5F_t *f);
+H5_DLL uint8_t H5F_sizeof_addr(const H5F_t *f);
+H5_DLL uint8_t H5F_sizeof_size(const H5F_t *f);
+H5_DLL haddr_t H5F_get_sohm_addr(const H5F_t *f);
+H5_DLL herr_t H5F_set_sohm_addr(H5F_t *f, haddr_t addr);
+H5_DLL unsigned H5F_get_sohm_vers(const H5F_t *f);
+H5_DLL herr_t H5F_set_sohm_vers(H5F_t *f, unsigned vers);
+H5_DLL unsigned H5F_get_sohm_nindexes(const H5F_t *f);
+H5_DLL herr_t H5F_set_sohm_nindexes(H5F_t *f, unsigned nindexes);
+H5_DLL hid_t H5F_get_fcpl(const H5F_t *f);
+H5_DLL H5F_close_degree_t H5F_get_fc_degree(const H5F_t *f);
+H5_DLL hbool_t H5F_get_evict_on_close(const H5F_t *f);
+H5_DLL size_t H5F_rdcc_nbytes(const H5F_t *f);
+H5_DLL size_t H5F_rdcc_nslots(const H5F_t *f);
+H5_DLL double H5F_rdcc_w0(const H5F_t *f);
+H5_DLL size_t H5F_sieve_buf_size(const H5F_t *f);
+H5_DLL unsigned H5F_gc_ref(const H5F_t *f);
+H5_DLL unsigned H5F_use_latest_flags(const H5F_t *f, unsigned fl);
+H5_DLL hbool_t H5F_store_msg_crt_idx(const H5F_t *f);
+H5_DLL herr_t H5F_set_store_msg_crt_idx(H5F_t *f, hbool_t flag);
+H5_DLL struct H5UC_t *H5F_grp_btree_shared(const H5F_t *f);
+H5_DLL herr_t H5F_set_grp_btree_shared(H5F_t *f, struct H5UC_t *rc);
+H5_DLL hbool_t H5F_use_tmp_space(const H5F_t *f);
+H5_DLL hbool_t H5F_is_tmp_addr(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5F_set_latest_flags(H5F_t *f, unsigned flags);
+H5_DLL hsize_t H5F_get_alignment(const H5F_t *f);
+H5_DLL hsize_t H5F_get_threshold(const H5F_t *f);
+#ifdef H5_HAVE_PARALLEL
+H5_DLL H5P_coll_md_read_flag_t H5F_coll_md_read(const H5F_t *f);
+H5_DLL void H5F_set_coll_md_read(H5F_t *f, H5P_coll_md_read_flag_t flag);
+#endif /* H5_HAVE_PARALLEL */
+H5_DLL hbool_t H5F_use_mdc_logging(const H5F_t *f);
+H5_DLL hbool_t H5F_start_mdc_log_on_access(const H5F_t *f);
+H5_DLL char *H5F_mdc_log_location(const H5F_t *f);
+
+/* Functions that retrieve values from VFD layer */
+H5_DLL hid_t H5F_get_driver_id(const H5F_t *f);
+H5_DLL herr_t H5F_get_fileno(const H5F_t *f, unsigned long *filenum);
+H5_DLL hbool_t H5F_has_feature(const H5F_t *f, unsigned feature);
+H5_DLL haddr_t H5F_get_eoa(const H5F_t *f, H5FD_mem_t type);
+H5_DLL herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void **file_handle);
+
+/* Functions that check file mounting information */
+H5_DLL hbool_t H5F_is_mount(const H5F_t *file);
+H5_DLL hbool_t H5F_has_mount(const H5F_t *file);
+H5_DLL herr_t H5F_traverse_mount(struct H5O_loc_t *oloc/*in,out*/);
+H5_DLL herr_t H5F_flush_mounts(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id);
+
+/* Functions that operate on blocks of bytes wrt super block */
+H5_DLL herr_t H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr,
+ size_t size, hid_t dxpl_id, void *buf/*out*/);
+H5_DLL herr_t H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr,
+ size_t size, hid_t dxpl_id, const void *buf);
+
+/* Functions that flush or evict */
+H5_DLL herr_t H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id);
+H5_DLL herr_t H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id);
+
+/* Functions that verify a piece of metadata with checksum */
+H5_DLL herr_t H5F_get_checksums(const uint8_t *buf, size_t chk_size, uint32_t *s_chksum, uint32_t *c_chksum);
+
+/* Routine to track the # of retries */
+H5_DLL herr_t H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries);
+H5_DLL herr_t H5F_set_retries(H5F_t *f);
+
+/* Routine to invoke callback function upon object flush */
+H5_DLL herr_t H5F_object_flush_cb(H5F_t *f, hid_t obj_id);
+
+/* Address-related functions */
+H5_DLL void H5F_addr_encode(const H5F_t *f, uint8_t **pp, haddr_t addr);
+H5_DLL void H5F_addr_encode_len(size_t addr_len, uint8_t **pp, haddr_t addr);
+H5_DLL void H5F_addr_decode(const H5F_t *f, const uint8_t **pp, haddr_t *addr_p);
+H5_DLL void H5F_addr_decode_len(size_t addr_len, const uint8_t **pp, haddr_t *addr_p);
+
+/* Shared file list related routines */
+H5_DLL void H5F_sfile_assert_num(unsigned n);
+
+/* Routines for creating & destroying "fake" file structures */
+H5_DLL H5F_t *H5F_fake_alloc(uint8_t sizeof_size);
+H5_DLL herr_t H5F_fake_free(H5F_t *f);
+
+/* Superblock related routines */
+H5_DLL herr_t H5F_super_dirty(H5F_t *f);
+H5_DLL herr_t H5F_eoa_dirty(H5F_t *f, hid_t dxpl_id);
+
+/* Parallel I/O (i.e. MPI) related routines */
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5F_get_mpi_handle(const H5F_t *f, MPI_File **f_handle);
+H5_DLL int H5F_mpi_get_rank(const H5F_t *f);
+H5_DLL MPI_Comm H5F_mpi_get_comm(const H5F_t *f);
+H5_DLL int H5F_mpi_get_size(const H5F_t *f);
+H5_DLL herr_t H5F_mpi_retrieve_comm(hid_t loc_id, hid_t acspl_id, MPI_Comm *mpi_comm);
+H5_DLL herr_t H5F_get_mpi_info(const H5F_t *f, MPI_Info **f_info);
+#endif /* H5_HAVE_PARALLEL */
+
+/* External file cache routines */
+H5_DLL H5F_t *H5F_efc_open(H5F_t *parent, const char *name, unsigned flags,
+ hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5F_efc_close(H5F_t *parent, H5F_t *file);
+
+/* Global heap CWFS routines */
+H5_DLL herr_t H5F_cwfs_add(H5F_t *f, struct H5HG_heap_t *heap);
+H5_DLL herr_t H5F_cwfs_find_free_heap(H5F_t *f, hid_t dxpl_id, size_t need, haddr_t *addr);
+H5_DLL herr_t H5F_cwfs_advance_heap(H5F_t *f, struct H5HG_heap_t *heap,
+ hbool_t add_heap);
+H5_DLL herr_t H5F_cwfs_remove_heap(H5F_file_t *shared, struct H5HG_heap_t *heap);
+
+/* Debugging functions */
+H5_DLL herr_t H5F_debug(H5F_t *f, FILE * stream, int indent, int fwidth);
+
+#endif /* _H5Fprivate_H */
+
diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h
new file mode 100644
index 0000000..1594cb2
--- /dev/null
+++ b/src/H5Fpublic.h
@@ -0,0 +1,305 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5F module.
+ */
+#ifndef _H5Fpublic_H
+#define _H5Fpublic_H
+
+/* Public header files needed by this file */
+#include "H5public.h"
+#include "H5ACpublic.h"
+#include "H5Ipublic.h"
+
+/* When this header is included from a private header, don't make calls to H5check() */
+#undef H5CHECK
+#ifndef _H5private_H
+#define H5CHECK H5check(),
+#else /* _H5private_H */
+#define H5CHECK
+#endif /* _H5private_H */
+
+/* When this header is included from a private HDF5 header, don't make calls to H5open() */
+#undef H5OPEN
+#ifndef _H5private_H
+#define H5OPEN H5open(),
+#else /* _H5private_H */
+#define H5OPEN
+#endif /* _H5private_H */
+
+/*
+ * These are the bits that can be passed to the `flags' argument of
+ * H5Fcreate() and H5Fopen(). Use the bit-wise OR operator (|) to combine
+ * them as needed. As a side effect, they call H5check_version() to make sure
+ * that the application is compiled with a version of the hdf5 header files
+ * which are compatible with the library to which the application is linked.
+ * We're assuming that these constants are used rather early in the hdf5
+ * session.
+ */
+#define H5F_ACC_RDONLY (H5CHECK H5OPEN 0x0000u) /*absence of rdwr => rd-only */
+#define H5F_ACC_RDWR (H5CHECK H5OPEN 0x0001u) /*open for read and write */
+#define H5F_ACC_TRUNC (H5CHECK H5OPEN 0x0002u) /*overwrite existing files */
+#define H5F_ACC_EXCL (H5CHECK H5OPEN 0x0004u) /*fail if file already exists*/
+/* NOTE: 0x0008u was H5F_ACC_DEBUG, now deprecated */
+#define H5F_ACC_CREAT (H5CHECK H5OPEN 0x0010u) /*create non-existing files */
+#define H5F_ACC_SWMR_WRITE (H5CHECK 0x0020u) /*indicate that this file is
+ * open for writing in a
+ * single-writer/multi-reader (SWMR)
+ * scenario. Note that the
+ * process(es) opening the file
+ * for reading must open the file
+ * with RDONLY access, and use
+ * the special "SWMR_READ" access
+ * flag. */
+#define H5F_ACC_SWMR_READ (H5CHECK 0x0040u) /*indicate that this file is
+ * open for reading in a
+ * single-writer/multi-reader (SWMR)
+ * scenario. Note that the
+ * process(es) opening the file
+ * for SWMR reading must also
+ * open the file with the RDONLY
+ * flag. */
+
+/* Value passed to H5Pset_elink_acc_flags to cause flags to be taken from the
+ * parent file. */
+#define H5F_ACC_DEFAULT (H5CHECK H5OPEN 0xffffu) /*ignore setting on lapl */
+
+/* Flags for H5Fget_obj_count() & H5Fget_obj_ids() calls */
+#define H5F_OBJ_FILE (0x0001u) /* File objects */
+#define H5F_OBJ_DATASET (0x0002u) /* Dataset objects */
+#define H5F_OBJ_GROUP (0x0004u) /* Group objects */
+#define H5F_OBJ_DATATYPE (0x0008u) /* Named datatype objects */
+#define H5F_OBJ_ATTR (0x0010u) /* Attribute objects */
+#define H5F_OBJ_ALL (H5F_OBJ_FILE|H5F_OBJ_DATASET|H5F_OBJ_GROUP|H5F_OBJ_DATATYPE|H5F_OBJ_ATTR)
+#define H5F_OBJ_LOCAL (0x0020u) /* Restrict search to objects opened through current file ID */
+ /* (as opposed to objects opened through any file ID accessing this file) */
+
+#define H5F_FAMILY_DEFAULT (hsize_t)0
+
+#ifdef H5_HAVE_PARALLEL
+/*
+ * Use this constant string as the MPI_Info key to set H5Fmpio debug flags.
+ * To turn on H5Fmpio debug flags, set the MPI_Info value with this key to
+ * have the value of a string consisting of the characters that turn on the
+ * desired flags.
+ */
+#define H5F_MPIO_DEBUG_KEY "H5F_mpio_debug_key"
+#endif /* H5_HAVE_PARALLEL */
+
+/* The difference between a single file and a set of mounted files */
+typedef enum H5F_scope_t {
+ H5F_SCOPE_LOCAL = 0, /*specified file handle only */
+ H5F_SCOPE_GLOBAL = 1 /*entire virtual file */
+} H5F_scope_t;
+
+/* Unlimited file size for H5Pset_external() */
+#define H5F_UNLIMITED ((hsize_t)(-1L))
+
+/* How does file close behave?
+ * H5F_CLOSE_DEFAULT - Use the degree pre-defined by underlining VFL
+ * H5F_CLOSE_WEAK - file closes only after all opened objects are closed
+ * H5F_CLOSE_SEMI - if no opened objects, file is close; otherwise, file
+ close fails
+ * H5F_CLOSE_STRONG - if there are opened objects, close them first, then
+ close file
+ */
+typedef enum H5F_close_degree_t {
+ H5F_CLOSE_DEFAULT = 0,
+ H5F_CLOSE_WEAK = 1,
+ H5F_CLOSE_SEMI = 2,
+ H5F_CLOSE_STRONG = 3
+} H5F_close_degree_t;
+
+/* Current "global" information about file */
+typedef struct H5F_info2_t {
+ struct {
+ unsigned version; /* Superblock version # */
+ hsize_t super_size; /* Superblock size */
+ hsize_t super_ext_size; /* Superblock extension size */
+ } super;
+ struct {
+ unsigned version; /* Version # of file free space management */
+ hsize_t meta_size; /* Free space manager metadata size */
+ hsize_t tot_space; /* Amount of free space in the file */
+ } free;
+ struct {
+ unsigned version; /* Version # of shared object header info */
+ hsize_t hdr_size; /* Shared object header message header size */
+ H5_ih_info_t msgs_info; /* Shared object header message index & heap size */
+ } sohm;
+} H5F_info2_t;
+
+/*
+ * Types of allocation requests. The values larger than H5FD_MEM_DEFAULT
+ * should not change other than adding new types to the end. These numbers
+ * might appear in files.
+ *
+ * Note: please change the log VFD flavors array if you change this
+ * enumeration.
+ */
+typedef enum H5F_mem_t {
+ H5FD_MEM_NOLIST = -1, /* Data should not appear in the free list.
+ * Must be negative.
+ */
+ H5FD_MEM_DEFAULT = 0, /* Value not yet set. Can also be the
+ * datatype set in a larger allocation
+ * that will be suballocated by the library.
+ * Must be zero.
+ */
+ H5FD_MEM_SUPER = 1, /* Superblock data */
+ H5FD_MEM_BTREE = 2, /* B-tree data */
+ H5FD_MEM_DRAW = 3, /* Raw data (content of datasets, etc.) */
+ H5FD_MEM_GHEAP = 4, /* Global heap data */
+ H5FD_MEM_LHEAP = 5, /* Local heap data */
+ H5FD_MEM_OHDR = 6, /* Object header data */
+
+ H5FD_MEM_NTYPES /* Sentinel value - must be last */
+} H5F_mem_t;
+
+/* Free space section information */
+typedef struct H5F_sect_info_t {
+ haddr_t addr; /* Address of free space section */
+ hsize_t size; /* Size of free space section */
+} H5F_sect_info_t;
+
+/* Library's file format versions */
+typedef enum H5F_libver_t {
+ H5F_LIBVER_EARLIEST, /* Use the earliest possible format for storing objects */
+ H5F_LIBVER_LATEST /* Use the latest possible format available for storing objects*/
+} H5F_libver_t;
+
+/* File space handling strategy */
+typedef enum H5F_fspace_strategy_t {
+ H5F_FSPACE_STRATEGY_FSM_AGGR = 0, /* Mechanisms: free-space managers, aggregators, and virtual file drivers */
+ /* This is the library default when not set */
+ H5F_FSPACE_STRATEGY_PAGE = 1, /* Mechanisms: free-space managers with embedded paged aggregation and virtual file drivers */
+ H5F_FSPACE_STRATEGY_AGGR = 2, /* Mechanisms: aggregators and virtual file drivers */
+ H5F_FSPACE_STRATEGY_NONE = 3, /* Mechanisms: virtual file drivers */
+ H5F_FSPACE_STRATEGY_NTYPES /* must be last */
+} H5F_fspace_strategy_t;
+
+/* Deprecated: File space handling strategy for release 1.10.0 */
+/* They are mapped to H5F_fspace_strategy_t as defined above from release 1.10.1 onwards */
+typedef enum H5F_file_space_type_t {
+ H5F_FILE_SPACE_DEFAULT = 0, /* Default (or current) free space strategy setting */
+ H5F_FILE_SPACE_ALL_PERSIST = 1, /* Persistent free space managers, aggregators, virtual file driver */
+ H5F_FILE_SPACE_ALL = 2, /* Non-persistent free space managers, aggregators, virtual file driver */
+ /* This is the library default */
+ H5F_FILE_SPACE_AGGR_VFD = 3, /* Aggregators, Virtual file driver */
+ H5F_FILE_SPACE_VFD = 4, /* Virtual file driver */
+ H5F_FILE_SPACE_NTYPES /* must be last */
+} H5F_file_space_type_t;
+
+/* Data structure to report the collection of read retries for metadata items with checksum */
+/* Used by public routine H5Fget_metadata_read_retry_info() */
+#define H5F_NUM_METADATA_READ_RETRY_TYPES 21
+typedef struct H5F_retry_info_t {
+ unsigned nbins;
+ uint32_t *retries[H5F_NUM_METADATA_READ_RETRY_TYPES];
+} H5F_retry_info_t;
+
+/* Callback for H5Pset_object_flush_cb() in a file access property list */
+typedef herr_t (*H5F_flush_cb_t)(hid_t object_id, void *udata);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions in H5F.c */
+H5_DLL htri_t H5Fis_hdf5(const char *filename);
+H5_DLL hid_t H5Fcreate(const char *filename, unsigned flags,
+ hid_t create_plist, hid_t access_plist);
+H5_DLL hid_t H5Fopen(const char *filename, unsigned flags,
+ hid_t access_plist);
+H5_DLL hid_t H5Freopen(hid_t file_id);
+H5_DLL herr_t H5Fflush(hid_t object_id, H5F_scope_t scope);
+H5_DLL herr_t H5Fclose(hid_t file_id);
+H5_DLL hid_t H5Fget_create_plist(hid_t file_id);
+H5_DLL hid_t H5Fget_access_plist(hid_t file_id);
+H5_DLL herr_t H5Fget_intent(hid_t file_id, unsigned * intent);
+H5_DLL ssize_t H5Fget_obj_count(hid_t file_id, unsigned types);
+H5_DLL ssize_t H5Fget_obj_ids(hid_t file_id, unsigned types, size_t max_objs, hid_t *obj_id_list);
+H5_DLL herr_t H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle);
+H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist);
+H5_DLL herr_t H5Funmount(hid_t loc, const char *name);
+H5_DLL hssize_t H5Fget_freespace(hid_t file_id);
+H5_DLL herr_t H5Fget_filesize(hid_t file_id, hsize_t *size);
+H5_DLL ssize_t H5Fget_file_image(hid_t file_id, void * buf_ptr, size_t buf_len);
+H5_DLL herr_t H5Fget_mdc_config(hid_t file_id,
+ H5AC_cache_config_t * config_ptr);
+H5_DLL herr_t H5Fset_mdc_config(hid_t file_id,
+ H5AC_cache_config_t * config_ptr);
+H5_DLL herr_t H5Fget_mdc_hit_rate(hid_t file_id, double * hit_rate_ptr);
+H5_DLL herr_t H5Fget_mdc_size(hid_t file_id,
+ size_t * max_size_ptr,
+ size_t * min_clean_size_ptr,
+ size_t * cur_size_ptr,
+ int * cur_num_entries_ptr);
+H5_DLL herr_t H5Freset_mdc_hit_rate_stats(hid_t file_id);
+H5_DLL ssize_t H5Fget_name(hid_t obj_id, char *name, size_t size);
+H5_DLL herr_t H5Fget_info2(hid_t obj_id, H5F_info2_t *finfo);
+H5_DLL herr_t H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info);
+H5_DLL herr_t H5Fstart_swmr_write(hid_t file_id);
+H5_DLL ssize_t H5Fget_free_sections(hid_t file_id, H5F_mem_t type,
+ size_t nsects, H5F_sect_info_t *sect_info/*out*/);
+H5_DLL herr_t H5Fclear_elink_file_cache(hid_t file_id);
+H5_DLL herr_t H5Fset_latest_format(hid_t file_id, hbool_t latest_format);
+H5_DLL herr_t H5Fstart_mdc_logging(hid_t file_id);
+H5_DLL herr_t H5Fstop_mdc_logging(hid_t file_id);
+H5_DLL herr_t H5Fget_mdc_logging_status(hid_t file_id,
+ /*OUT*/ hbool_t *is_enabled,
+ /*OUT*/ hbool_t *is_currently_logging);
+H5_DLL herr_t H5Fformat_convert(hid_t fid);
+H5_DLL herr_t H5Freset_page_buffering_stats(hid_t file_id);
+H5_DLL herr_t H5Fget_page_buffering_stats(hid_t file_id, unsigned accesses[2],
+ unsigned hits[2], unsigned misses[2], unsigned evictions[2], unsigned bypasses[2]);
+H5_DLL herr_t H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_size);
+
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5Fset_mpi_atomicity(hid_t file_id, hbool_t flag);
+H5_DLL herr_t H5Fget_mpi_atomicity(hid_t file_id, hbool_t *flag);
+#endif /* H5_HAVE_PARALLEL */
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+#define H5F_ACC_DEBUG (H5CHECK H5OPEN 0x0000u) /*print debug info (deprecated)*/
+
+/* Typedefs */
+
+/* Current "global" information about file */
+typedef struct H5F_info1_t {
+ hsize_t super_ext_size; /* Superblock extension size */
+ struct {
+ hsize_t hdr_size; /* Shared object header message header size */
+ H5_ih_info_t msgs_info; /* Shared object header message index & heap size */
+ } sohm;
+} H5F_info1_t;
+
+
+/* Function prototypes */
+H5_DLL herr_t H5Fget_info1(hid_t obj_id, H5F_info1_t *finfo);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Fpublic_H */
+
diff --git a/src/H5Fquery.c b/src/H5Fquery.c
new file mode 100644
index 0000000..41cf4d2
--- /dev/null
+++ b/src/H5Fquery.c
@@ -0,0 +1,1382 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fquery.c
+ * Jan 10 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File structure query routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_intent
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'intent' flags
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: 'intent' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * September 29, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_intent(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->shared->flags)
+} /* end H5F_get_intent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_open_name
+ *
+ * Purpose: Retrieve the name used to open a file.
+ *
+ * Return: Success: The name of the file.
+ * Failure: ? (should not happen)
+ *
+ * Programmer: Neil Fortner
+ * December 15 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_get_open_name(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->open_name);
+
+ FUNC_LEAVE_NOAPI(f->open_name)
+} /* end H5F_get_open_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_actual_name
+ *
+ * Purpose: Retrieve the actual name of a file, after resolving symlinks, etc.
+ *
+ * Return: Success: The name of the file.
+ * Failure: ? (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * November 25 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_get_actual_name(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->actual_name);
+
+ FUNC_LEAVE_NOAPI(f->actual_name)
+} /* end H5F_get_actual_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_extpath
+ *
+ * Purpose: Retrieve the file's 'extpath' flags
+ * This is used by H5L_extern_traverse() and H5D_build_extfile_prefix() to retrieve the main file's location
+ * when searching the target file.
+ *
+ * Return: 'extpath' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Vailin Choi, April 2, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_get_extpath(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->extpath);
+
+ FUNC_LEAVE_NOAPI(f->extpath)
+} /* end H5F_get_extpath() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_shared
+ *
+ * Purpose: Retrieve the file's 'shared' pointer
+ *
+ * Return: 'shared' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_file_t *
+H5F_get_shared(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->shared)
+} /* end H5F_get_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_same_shared
+ *
+ * Purpose: Determine if two files have the same shared file pointer
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 19, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_same_shared(const H5F_t *f1, const H5F_t *f2)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f1);
+ HDassert(f1->shared);
+ HDassert(f2);
+ HDassert(f2->shared);
+
+ FUNC_LEAVE_NOAPI(f1->shared == f2->shared)
+} /* end H5F_same_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_nopen_objs
+ *
+ * Purpose: Retrieve the file's 'nopen_objs' value
+ *
+ * Return: 'nopen_objs' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_nopen_objs(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->nopen_objs)
+} /* end H5F_get_nopen_objs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_file_id
+ *
+ * Purpose: Retrieve the file's 'file_id' value
+ *
+ * Return: 'file_id' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5F_get_file_id(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->file_id)
+} /* end H5F_get_file_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_parent
+ *
+ * Purpose: Retrieve the file's 'parent' pointer
+ *
+ * Return: 'parent' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 19, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5F_get_parent(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->parent)
+} /* end H5F_get_parent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_nmounts
+ *
+ * Purpose: Retrieve the file's 'nmounts' value
+ *
+ * Return: 'nmounts' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_nmounts(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->nmounts)
+} /* end H5F_get_nmounts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_read_attempts
+ *
+ * Purpose: Retrieve the file's 'read_attempts' value
+ *
+ * Return: '# of read attempts' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Vaili Choi; Sept 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_read_attempts(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->shared->read_attempts)
+} /* end H5F_get_read_attempts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_fcpl
+ *
+ * Purpose: Retrieve the value of a file's FCPL.
+ *
+ * Return: Success: The FCPL for the file.
+ *
+ * Failure: ? (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 25 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5F_get_fcpl(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->fcpl_id)
+} /* end H5F_get_fcpl() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sizeof_addr
+ *
+ * Purpose: Quick and dirty routine to retrieve the size of the file's size_t
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: 'sizeof_addr' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * September 29, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+uint8_t
+H5F_sizeof_addr(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sizeof_addr)
+} /* end H5F_sizeof_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sizeof_size
+ *
+ * Purpose: Quick and dirty routine to retrieve the size of the file's off_t
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: 'sizeof_size' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * September 29, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+uint8_t
+H5F_sizeof_size(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sizeof_size)
+} /* H5F_sizeof_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_sohm_addr
+ *
+ * Purpose: Retrieve the file's 'sohm_addr' value
+ *
+ * Return: 'sohm_addr' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5F_get_sohm_addr(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sohm_addr)
+} /* end H5F_get_sohm_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_sohm_vers
+ *
+ * Purpose: Retrieve the file's 'sohm_vers' value
+ *
+ * Return: 'sohm_vers' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_sohm_vers(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sohm_vers)
+} /* end H5F_get_sohm_vers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_sohm_nindexes
+ *
+ * Purpose: Retrieve the file's 'sohm_nindexes' value
+ *
+ * Return: 'sohm_nindexes' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_sohm_nindexes(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sohm_nindexes)
+} /* end H5F_get_sohm_nindexes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sym_leaf_k
+ *
+ * Purpose: Replaced a macro to retrieve the symbol table leaf size,
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-negative, and the symbol table leaf size is
+ * returned.
+ *
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * Oct 14 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_sym_leaf_k(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ FUNC_LEAVE_NOAPI(f->shared->sblock->sym_leaf_k)
+} /* end H5F_sym_leaf_k() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_Kvalue
+ *
+ * Purpose: Replaced a macro to retrieve a B-tree key value for a certain
+ * type, now that the generic properties are being used to store
+ * the B-tree values.
+ *
+ * Return: Success: Non-negative, and the B-tree key value is
+ * returned.
+ *
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * Oct 14 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_Kvalue(const H5F_t *f, const H5B_class_t *type)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+ HDassert(type);
+
+ FUNC_LEAVE_NOAPI(f->shared->sblock->btree_k[type->id])
+} /* end H5F_Kvalue() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_nrefs
+ *
+ * Purpose: Retrieve the file's 'nrefs' value
+ *
+ * Return: 'nrefs' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_get_nrefs(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->nrefs)
+} /* end H5F_get_nrefs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_rdcc_nslots
+ *
+ * Purpose: Replaced a macro to retrieve the raw data cache number of slots,
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-negative, and the raw data cache number of
+ * of slots is returned.
+ *
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jun 1 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5F_rdcc_nslots(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->rdcc_nslots)
+} /* end H5F_rdcc_nelmts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_rdcc_nbytes
+ *
+ * Purpose: Replaced a macro to retrieve the raw data cache number of bytes,
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-negative, and the raw data cache number of
+ * of bytes is returned.
+ *
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jun 1 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5F_rdcc_nbytes(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->rdcc_nbytes)
+} /* end H5F_rdcc_nbytes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_rdcc_w0
+ *
+ * Purpose: Replaced a macro to retrieve the raw data cache 'w0' value
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-negative, and the raw data cache 'w0' value
+ * is returned.
+ *
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jun 2 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+double
+H5F_rdcc_w0(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->rdcc_w0)
+} /* end H5F_rdcc_w0() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_base_addr
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'base_addr' value
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu <slu@ncsa.uiuc.edu>
+ * December 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5F_get_base_addr(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ FUNC_LEAVE_NOAPI(f->shared->sblock->base_addr)
+} /* end H5F_get_base_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_grp_btree_shared
+ *
+ * Purpose: Replaced a macro to retrieve the shared B-tree node info
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-void, and the shared B-tree node info
+ * is returned.
+ *
+ * Failure: void (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jul 5 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+H5UC_t *
+H5F_grp_btree_shared(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->grp_btree_shared)
+} /* end H5F_grp_btree_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sieve_buf_size
+ *
+ * Purpose: Replaced a macro to retrieve the dataset sieve buffer size
+ * now that the generic properties are being used to store
+ * the values.
+ *
+ * Return: Success: Non-void, and the dataset sieve buffer size
+ * is returned.
+ *
+ * Failure: void (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jul 8 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5F_sieve_buf_size(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->sieve_buf_size)
+} /* end H5F_sieve_buf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_gc_ref
+ *
+ * Purpose: Replaced a macro to retrieve the "garbage collect
+ * references flag" now that the generic properties are being used
+ * to store the values.
+ *
+ * Return: Success: The "garbage collect references flag"
+ * is returned.
+ *
+ * Failure: (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jul 8 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_gc_ref(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->gc_ref)
+} /* end H5F_gc_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_use_latest_flags
+ *
+ * Purpose: Retrieve the 'latest version support' for the file.
+ *
+ * Return: Success: Non-negative, the requested 'version support'
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 5 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5F_use_latest_flags(const H5F_t *f, unsigned fl)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->latest_flags & (fl))
+} /* end H5F_use_latest_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_fc_degree
+ *
+ * Purpose: Retrieve the 'file close degree' for the file.
+ *
+ * Return: Success: Non-negative, the 'file close degree'
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 5 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_close_degree_t
+H5F_get_fc_degree(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->fc_degree)
+} /* end H5F_get_fc_degree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_evict_on_close
+ *
+ * Purpose: Checks if evict-on-close is desired for objects in the
+ * file.
+ *
+ * Return: Success: Flag indicating whether the evict-on-close
+ * property was set for the file.
+ * Failure: (can't happen)
+ *
+ * Programmer: Dana Robinson
+ * Spring 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_get_evict_on_close(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->evict_on_close)
+} /* end H5F_get_evict_on_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_store_msg_crt_idx
+ *
+ * Purpose: Retrieve the 'store message creation index' flag for the file.
+ *
+ * Return: Success: Non-negative, the 'store message creation index' flag
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_store_msg_crt_idx(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->store_msg_crt_idx)
+} /* end H5F_store_msg_crt_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_has_feature
+ *
+ * Purpose: Check if a file has a particular feature enabled
+ *
+ * Return: Success: Non-negative - TRUE or FALSE
+ * Failure: Negative (should not happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_has_feature(const H5F_t *f, unsigned feature)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI((hbool_t)(f->shared->lf->feature_flags&feature))
+} /* end H5F_has_feature() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_driver_id
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'driver_id' value
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: 'driver_id' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * October 10, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5F_get_driver_id(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+
+ FUNC_LEAVE_NOAPI(f->shared->lf->driver_id)
+} /* end H5F_get_driver_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_fileno
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'fileno' value
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * March 27, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_fileno(const H5F_t *f, unsigned long *filenum)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(filenum);
+
+ /* Retrieve the file's serial number */
+ if(H5FD_get_fileno(f->shared->lf, filenum) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, FAIL, "can't retrieve fileno")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_fileno() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_eoa
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'eoa' value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * June 1, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5F_get_eoa(const H5F_t *f, H5FD_mem_t type)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Dispatch to driver */
+ if(HADDR_UNDEF == (ret_value = H5FD_get_eoa(f->shared->lf, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "driver get_eoa request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_vfd_handle
+ *
+ * Purpose: Returns a pointer to the file handle of the low-level file
+ * driver. This is the private function for H5Fget_vfd_handle.
+ *
+ * Return: Success: Non-negative.
+ * Failure: negative.
+ *
+ * Programmer: Raymond Lu
+ * Sep. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void **file_handle)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file_handle);
+
+ /* Get the VFD handle */
+ if(H5FD_get_vfd_handle(file->shared->lf, fapl, file_handle) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_vfd_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_is_tmp_addr
+ *
+ * Purpose: Quick and dirty routine to determine if an address is in
+ * the 'temporary' file space.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * June 11, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_is_tmp_addr(const H5F_t *f, haddr_t addr)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(H5F_addr_le(f->shared->tmp_addr, addr))
+} /* end H5F_is_tmp_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_use_tmp_space
+ *
+ * Purpose: Quick and dirty routine to determine if using temporary
+ * file space is allowed for this file.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * July 1, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_use_tmp_space(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->use_tmp_space)
+} /* end H5F_use_tmp_space() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_coll_md_read
+ *
+ * Purpose: Retrieve the 'collective metadata reads' flag for the file.
+ *
+ * Return: Success: Non-negative, the 'collective metadata reads' flag
+ * Failure: (can't happen)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 10 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+H5P_coll_md_read_flag_t
+H5F_coll_md_read(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->coll_md_read)
+} /* end H5F_coll_md_read() */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_use_mdc_logging
+ *
+ * Purpose: Quick and dirty routine to determine if using MDC logging
+ * is enabled for this file.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * June 5, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_use_mdc_logging(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->use_mdc_logging)
+} /* end H5F_use_mdc_logging() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_start_mdc_log_on_access
+ *
+ * Purpose: Quick and dirty routine to determine if we should start MDC
+ * logging on access for this file.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * June 5, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_start_mdc_log_on_access(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->start_mdc_log_on_access)
+} /* end H5F_start_mdc_log_on_access() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mdc_log_location
+ *
+ * Purpose: Quick and dirty routine to retrieve the MDC log location
+ * for this file.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5F_t data structure)
+ *
+ * Return: TRUE/FALSE on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * June 5, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_mdc_log_location(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->mdc_log_location)
+} /* end H5F_mdc_log_location() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_alignment
+ *
+ * Purpose: Retrieve the 'alignment' for the file.
+ *
+ * Return: Success: Non-negative, the 'alignment'
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5F_get_alignment(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->alignment)
+} /* end H5F_get_alignment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_threshold
+ *
+ * Purpose: Retrieve the 'threshold' for alignment in the file.
+ *
+ * Return: Success: Non-negative, the 'threshold'
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5F_get_threshold(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->threshold)
+} /* end H5F_get_threshold() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_pgend_meta_thres
+ *
+ * Purpose: Retrieve the 'page end meta threshold size' for the file.
+ *
+ * Return: Success: Non-negative, the 'pgend_meta_thres'
+ *
+ * Failure: (can't happen)
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5F_get_pgend_meta_thres(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->pgend_meta_thres)
+} /* end H5F_get_pgend_meta_thres() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_point_of_no_return
+ *
+ * Purpose: Retrieve the 'point of no return' value for the file.
+ *
+ * Return: Success: Non-negative, the 'point_of_no_return'
+ * Failure: (can't happen)
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_get_point_of_no_return(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->point_of_no_return)
+} /* end H5F_get_point_of_no_return() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_first_alloc_dealloc
+ *
+ * Purpose: Retrieve the 'first alloc / dealloc' value for the file.
+ *
+ * Return: Success: Non-negative, the 'first_alloc_dealloc'
+ * Failure: (can't happen)
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_get_first_alloc_dealloc(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->first_alloc_dealloc)
+} /* end H5F_get_first_alloc_dealloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_eoa_pre_fsm_fsalloc
+ *
+ * Purpose: Retrieve the 'EOA pre-FSM fsalloc' value for the file.
+ *
+ * Return: Success: Non-negative, the 'EOA pre-FSM fsalloc'
+ * Failure: (can't happen)
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5F_get_eoa_pre_fsm_fsalloc(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ FUNC_LEAVE_NOAPI(f->shared->eoa_pre_fsm_fsalloc)
+} /* end H5F_get_eoa_pre_fsm_fsalloc() */
+
diff --git a/src/H5Fsfile.c b/src/H5Fsfile.c
new file mode 100644
index 0000000..e0c830b
--- /dev/null
+++ b/src/H5Fsfile.c
@@ -0,0 +1,223 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free lists */
+
+/* PRIVATE TYPEDEFS */
+
+/* Struct for tracking "shared" file structs */
+typedef struct H5F_sfile_node_t {
+ H5F_file_t *shared; /* Pointer to "shared" file struct */
+ struct H5F_sfile_node_t *next; /* Pointer to next node */
+} H5F_sfile_node_t;
+
+/* PRIVATE PROTOTYPES */
+
+/* PRIVATE VARIABLES */
+
+/* Declare a free list to manage the H5F_sfile_node_t struct */
+H5FL_DEFINE_STATIC(H5F_sfile_node_t);
+
+/* Declare a local variable to track the shared file information */
+H5F_sfile_node_t *H5F_sfile_head_g = NULL;
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sfile_assert_num
+ *
+ * Purpose: Sanity checking that shared file list is empty
+ *
+ * Return: none (void)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 25, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5F_sfile_assert_num(unsigned n)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(n == 0) {
+ /* Sanity checking */
+ HDassert(H5F_sfile_head_g == NULL);
+ } /* end if */
+ else {
+ unsigned count; /* Number of open shared files */
+ H5F_sfile_node_t *curr; /* Current shared file node */
+
+ /* Iterate through low-level files for matching low-level file info */
+ curr = H5F_sfile_head_g;
+ count = 0;
+ while(curr) {
+ /* Increment # of open shared file structs */
+ count++;
+
+ /* Advance to next shared file node */
+ curr = curr->next;
+ } /* end while */
+
+ /* Sanity checking */
+ HDassert(count == n);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5F_sfile_assert_num() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sfile_add
+ *
+ * Purpose: Add a "shared" file struct to the list of open files
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 18, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_sfile_add(H5F_file_t *shared)
+{
+ H5F_sfile_node_t *new_shared; /* New shared file node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(shared);
+
+ /* Allocate new shared file node */
+ if (NULL == (new_shared = H5FL_CALLOC(H5F_sfile_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set shared file value */
+ new_shared->shared = shared;
+
+ /* Prepend to list of shared files open */
+ new_shared->next = H5F_sfile_head_g;
+ H5F_sfile_head_g = new_shared;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_sfile_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sfile_search
+ *
+ * Purpose: Search for a "shared" file with low-level file info that
+ * matches
+ *
+ * Return: Non-NULL on success / NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 18, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_file_t *
+H5F_sfile_search(H5FD_t *lf)
+{
+ H5F_sfile_node_t *curr; /* Current shared file node */
+ H5F_file_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(lf);
+
+ /* Iterate through low-level files for matching low-level file info */
+ curr = H5F_sfile_head_g;
+ while(curr) {
+ /* Check for match */
+ if(0==H5FD_cmp(curr->shared->lf, lf))
+ HGOTO_DONE(curr->shared)
+
+ /* Advance to next shared file node */
+ curr = curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_sfile_search() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_sfile_remove
+ *
+ * Purpose: Remove a "shared" file struct from the list of open files
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 18, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_sfile_remove(H5F_file_t *shared)
+{
+ H5F_sfile_node_t *curr; /* Current shared file node */
+ H5F_sfile_node_t *last; /* Last shared file node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(shared);
+
+ /* Locate shared file node with correct shared file */
+ last = NULL;
+ curr = H5F_sfile_head_g;
+ while(curr && curr->shared != shared) {
+ /* Advance to next node */
+ last = curr;
+ curr = curr->next;
+ } /* end while */
+
+ /* Indicate error if the node wasn't found */
+ if(curr == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOTFOUND, FAIL, "can't find shared file info")
+
+ /* Remove node found from list */
+ if(last != NULL)
+ /* Removing middle or tail node in list */
+ last->next = curr->next;
+ else
+ /* Removing head node in list */
+ H5F_sfile_head_g = curr->next;
+
+ /* Release the shared file node struct */
+ /* (the shared file info itself is freed elsewhere) */
+ curr = H5FL_FREE(H5F_sfile_node_t, curr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_sfile_remove() */
+
diff --git a/src/H5Fspace.c b/src/H5Fspace.c
new file mode 100644
index 0000000..0962f69
--- /dev/null
+++ b/src/H5Fspace.c
@@ -0,0 +1,224 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fspace.c
+ * Dec 30 2013
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Space allocation routines for the file.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_alloc
+ *
+ * Purpose: Wrapper for H5FD_alloc, to make certain EOA changes are
+ * reflected in superblock.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: The format address of the new file memory.
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 30, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5F_alloc(H5F_t *f, hid_t dxpl_id, H5F_mem_t type, hsize_t size, haddr_t *frag_addr, hsize_t *frag_size)
+{
+ haddr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Check whether the file can use temporary addresses */
+ if(f->shared->use_tmp_space) {
+ haddr_t eoa; /* Current EOA for the file */
+
+ /* Get the EOA for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa")
+
+ /* Check for overlapping into file's temporary allocation space */
+ if(H5F_addr_gt((eoa + size), f->shared->tmp_addr))
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, HADDR_UNDEF, "'normal' file space allocation request will overlap into 'temporary' file space")
+ } /* end if */
+
+ /* Call the file driver 'alloc' routine */
+ ret_value = H5FD_alloc(f->shared->lf, dxpl_id, type, f, size, frag_addr, frag_size);
+ if(!H5F_addr_defined(ret_value))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, HADDR_UNDEF, "file driver 'alloc' request failed")
+
+ /* Mark EOA dirty */
+ if(H5F_eoa_dirty(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, HADDR_UNDEF, "unable to mark EOA as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_free
+ *
+ * Purpose: Wrapper for H5FD_free, to make certain EOA changes are
+ * reflected in superblock.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 30, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, hsize_t size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Call the file driver 'free' routine */
+ if(H5FD_free(f->shared->lf, dxpl_id, type, f, addr, size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "file driver 'free' request failed")
+
+ /* Mark EOA dirty */
+ if(H5F_eoa_dirty(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark EOA as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_try_extend
+ *
+ * Purpose: Extend a block at the end of the file, if possible.
+ *
+ * Note: When the metadata cache routines are updated to allow
+ * marking an entry dirty without a H5F_t*, this routine should
+ * be changed to take a H5F_super_t* directly.
+ *
+ * Return: Success: TRUE(1) - Block was extended
+ * FALSE(0) - Block could not be extended
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, 30 December, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5F_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t blk_end, hsize_t extra_requested)
+{
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(extra_requested > 0);
+
+ /* Extend the object by extending the underlying file */
+ if((ret_value = H5FD_try_extend(f->shared->lf, type, f, dxpl_id, blk_end, extra_requested)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTEXTEND, FAIL, "driver try extend request failed")
+
+ /* H5FD_try_extend() updates driver message and marks the superblock
+ * dirty, so no need to do it again here.
+ */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_try_extend() */
+
diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c
new file mode 100644
index 0000000..7c70a64
--- /dev/null
+++ b/src/H5Fsuper.c
@@ -0,0 +1,1642 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5F_super_ext_create(H5F_t *f, hid_t dxpl_id, H5O_loc_t *ext_ptr);
+static herr_t H5F__update_super_ext_driver_msg(H5F_t *f, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Declare a free list to manage the H5F_super_t struct */
+H5FL_DEFINE(H5F_super_t);
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_ext_create
+ *
+ * Purpose: Create the superblock extension
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_super_ext_create(H5F_t *f, hid_t dxpl_id, H5O_loc_t *ext_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+ HDassert(!H5F_addr_defined(f->shared->sblock->ext_addr));
+ HDassert(ext_ptr);
+
+ /* Check for older version of superblock format that can't support superblock extensions */
+ if(f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "superblock extension not permitted with version %u of superblock", f->shared->sblock->super_vers)
+ else if(H5F_addr_defined(f->shared->sblock->ext_addr))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "superblock extension already exists?!?!")
+ else {
+ /* The superblock extension isn't actually a group, but the
+ * default group creation list should work fine.
+ * If we don't supply a size for the object header, HDF5 will
+ * allocate H5O_MIN_SIZE by default. This is currently
+ * big enough to hold the biggest possible extension, but should
+ * be tuned if more information is added to the superblock
+ * extension.
+ */
+ H5O_loc_reset(ext_ptr);
+ if(H5O_create(f, dxpl_id, (size_t)0, (size_t)1, H5P_GROUP_CREATE_DEFAULT, ext_ptr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "unable to create superblock extension")
+
+ /* Record the address of the superblock extension */
+ f->shared->sblock->ext_addr = ext_ptr->addr;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_ext_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_ext_open
+ *
+ * Purpose: Open an existing superblock extension
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_super_ext_open(H5F_t *f, haddr_t ext_addr, H5O_loc_t *ext_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(ext_addr));
+ HDassert(ext_ptr);
+
+ /* Set up "fake" object location for superblock extension */
+ H5O_loc_reset(ext_ptr);
+ ext_ptr->file = f;
+ ext_ptr->addr = ext_addr;
+
+ /* Open the superblock extension object header */
+ if(H5O_open(ext_ptr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open superblock extension")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_ext_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_ext_close
+ *
+ * Purpose: Close superblock extension
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_super_ext_close(H5F_t *f, H5O_loc_t *ext_ptr, hid_t dxpl_id,
+ hbool_t was_created)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(ext_ptr);
+
+ /* Check if extension was created */
+ if(was_created) {
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_SBE, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Increment link count on superblock extension's object header */
+ if(H5O_link(ext_ptr, 1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_LINKCOUNT, FAIL, "unable to increment hard link count")
+
+ /* Decrement refcount on superblock extension's object header in memory */
+ if(H5O_dec_rc_by_loc(ext_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to decrement refcount on superblock extension");
+ } /* end if */
+
+ /* Twiddle the number of open objects to avoid closing the file. */
+ f->nopen_objs++;
+ if(H5O_close(ext_ptr, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close superblock extension")
+ f->nopen_objs--;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_ext_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__update_super_ext_driver_msg
+ *
+ * Purpose: Update the superblock extension file driver info message if
+ * we are using a V 2 superblock. Observe that the function
+ * is a NO-OP if the file driver info message does not exist.
+ * This is necessary, as the function is called whenever the
+ * EOA is updated, and were it to create the file driver info
+ * message, it would find itself in an infinite recursion.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 11/10/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__update_super_ext_driver_msg(H5F_t *f, hid_t dxpl_id)
+{
+ H5F_super_t *sblock; /* Pointer to the super block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ sblock = f->shared->sblock;
+ HDassert(sblock);
+ HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK);
+
+ /* Update the driver information message in the superblock extension
+ * if appropriate.
+ */
+ if(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2) {
+ if(H5F_addr_defined(sblock->ext_addr)) {
+ /* Check for ignoring the driver info for this file */
+ if(!H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) {
+ size_t driver_size; /* Size of driver info block (bytes)*/
+
+ /* Check for driver info */
+ H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t);
+
+ /* Nothing to do unless there is both driver info and
+ * the driver info superblock extension message has
+ * already been created.
+ */
+ if(driver_size > 0) {
+ H5O_drvinfo_t drvinfo; /* Driver info */
+ uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */
+
+ /* Sanity check */
+ HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE);
+
+ /* Encode driver-specific data */
+ if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information")
+
+ /* Write the message to the superblock extension.
+ *
+ * Note that the superblock extension and the
+ * file driver info message must already exist.
+ */
+ drvinfo.len = driver_size;
+ drvinfo.buf = dbuf;
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_DRVINFO_ID, &drvinfo, FALSE, H5O_MSG_NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "unable to update driver info header message")
+ } /* end if driver_size > 0 */
+ } /* end if !H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO) */
+ } /* end if superblock extension exists */
+ } /* end if sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__update_super_ext_driver_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__super_read
+ *
+ * Purpose: Reads the superblock from the file or from the BUF. If
+ * ADDR is a valid address, then it reads it from the file.
+ * If not, then BUF must be non-NULL for it to read from the
+ * BUF.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Bill Wendling
+ * wendling@ncsa.uiuc.edu
+ * Sept 12, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__super_read(H5F_t *f, hid_t meta_dxpl_id, hid_t raw_dxpl_id, hbool_t initial_read)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL object */
+ H5AC_ring_t ring, orig_ring = H5AC_RING_INV;
+ H5F_super_t * sblock = NULL; /* Superblock structure */
+ H5F_superblock_cache_ud_t udata; /* User data for cache callbacks */
+ H5P_genplist_t *c_plist; /* File creation property list */
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ unsigned sblock_flags = H5AC__NO_FLAGS_SET; /* flags used in superblock unprotect call */
+ haddr_t super_addr; /* Absolute address of superblock */
+ haddr_t eof; /* End of file address */
+ unsigned rw_flags; /* Read/write permissions for file */
+ hbool_t skip_eof_check = FALSE; /* Whether to skip checking the EOF value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(meta_dxpl_id, H5AC__SUPERBLOCK_TAG, FAIL)
+
+ /* initialize the drvinfo to NULL -- we will overwrite this if there
+ * is a driver information block
+ */
+ f->shared->drvinfo = NULL;
+
+ /* Get the DXPL plist object for DXPL ID */
+ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object(meta_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if((H5P_get(dxpl, H5AC_RING_NAME, &orig_ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get property value");
+
+ /* Set up file driver I/O info */
+ fdio_info.file = f->shared->lf;
+ fdio_info.meta_dxpl = dxpl;
+ if(NULL == (fdio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(raw_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Find the superblock */
+ if(H5FD_locate_signature(&fdio_info, &super_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_NOTHDF5, FAIL, "unable to locate file signature")
+ if(HADDR_UNDEF == super_addr)
+ HGOTO_ERROR(H5E_FILE, H5E_NOTHDF5, FAIL, "file signature not found")
+
+ /* Check for userblock present */
+ if(H5F_addr_gt(super_addr, 0)) {
+ /* Set the base address for the file in the VFD now */
+ if(H5F__set_base_addr(f, super_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "failed to set base address for file driver")
+ } /* end if */
+
+ /* Determine file intent for superblock protect */
+
+ /* Must tell cache at protect time that the super block is to be
+ * flushed last (and collectively in the parallel case).
+ */
+ rw_flags = H5AC__FLUSH_LAST_FLAG;
+#ifdef H5_HAVE_PARALLEL
+ rw_flags |= H5C__FLUSH_COLLECTIVELY_FLAG;
+#endif /* H5_HAVE_PARALLEL */
+ if(!(H5F_INTENT(f) & H5F_ACC_RDWR))
+ rw_flags |= H5AC__READ_ONLY_FLAG;
+
+ /* Get the shared file creation property list */
+ if(NULL == (c_plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Make certain we can read the fixed-size portion of the superblock */
+ if(H5F__set_eoa(f, H5FD_MEM_SUPER,
+ (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "set end of space allocation request failed")
+
+ /* Set up the user data for cache callbacks */
+ udata.f = f;
+ udata.ignore_drvrinfo = H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO);
+ udata.sym_leaf_k = 0;
+ if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, udata.btree_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes")
+ udata.stored_eof = HADDR_UNDEF;
+ udata.drvrinfo_removed = FALSE;
+
+ /* Set the ring type in the DXPL */
+ ring = H5AC_RING_SB;
+ if((H5P_set(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set property value");
+
+ /* Look up the superblock */
+ if(NULL == (sblock = (H5F_super_t *)H5AC_protect(f, meta_dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, &udata, rw_flags)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTPROTECT, FAIL, "unable to load superblock")
+
+ if(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE)
+ if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_3)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTPROTECT, FAIL, "invalid superblock version for SWMR_WRITE")
+
+ /* Enable all latest version support when file has v3 superblock */
+ if(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3)
+ f->shared->latest_flags |= H5F_LATEST_ALL_FLAGS;
+
+ /* Pin the superblock in the cache */
+ if(H5AC_pin_protected_entry(sblock) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTPIN, FAIL, "unable to pin superblock")
+
+ /* Mark the superblock dirty if it was modified during loading */
+ if(((rw_flags & H5AC__READ_ONLY_FLAG) == 0) && udata.ignore_drvrinfo && udata.drvrinfo_removed) {
+ HDassert(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2);
+ sblock_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* The superblock must be flushed last (and collectively in parallel) */
+ sblock_flags |= H5AC__FLUSH_LAST_FLAG;
+#ifdef H5_HAVE_PARALLEL
+ sblock_flags |= H5AC__FLUSH_COLLECTIVELY_FLAG;
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Check if superblock address is different from base address and adjust
+ * base address and "end of address" address if so.
+ */
+ if(!H5F_addr_eq(super_addr, sblock->base_addr)) {
+ /* Check if the superblock moved earlier in the file */
+ if(H5F_addr_lt(super_addr, sblock->base_addr))
+ udata.stored_eof -= (sblock->base_addr - super_addr);
+ else
+ /* The superblock moved later in the file */
+ udata.stored_eof += (super_addr - sblock->base_addr);
+
+ /* Adjust base address for offsets of the HDF5 data in the file */
+ sblock->base_addr = super_addr;
+
+ /* Set the base address for the file in the VFD now */
+ if(H5F__set_base_addr(f, sblock->base_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "failed to set base address for file driver")
+
+ /* Indicate that the superblock should be marked dirty */
+ if((rw_flags & H5AC__READ_ONLY_FLAG) == 0)
+ sblock_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Set information in the file's creation property list */
+ if(H5P_set(c_plist, H5F_CRT_SUPER_VERS_NAME, &sblock->super_vers) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set superblock version")
+ if(H5P_set(c_plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &sblock->sizeof_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set byte number in an address")
+ if(H5P_set(c_plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &sblock->sizeof_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set byte number for object size")
+
+ /* Handle the B-tree 'K' values */
+ if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
+ /* Sanity check */
+ HDassert(udata.sym_leaf_k != 0);
+
+ /* Set the symbol table internal node 'K' value */
+ if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &udata.sym_leaf_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for symbol table leaf nodes")
+ sblock->sym_leaf_k = udata.sym_leaf_k;
+
+ /* Set the B-tree internal node values, etc */
+ if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, udata.btree_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for btree internal nodes")
+ HDmemcpy(sblock->btree_k, udata.btree_k, sizeof(unsigned) * (size_t)H5B_NUM_BTREE_ID);
+ } /* end if */
+ else {
+ /* Get the (default) B-tree internal node values, etc */
+ /* (Note: these may be reset in a superblock extension) */
+ if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, sblock->btree_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes")
+ if(H5P_get(c_plist, H5F_CRT_SYM_LEAF_NAME, &sblock->sym_leaf_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes")
+ } /* end else */
+
+ /*
+ * The user-defined data is the area of the file before the base
+ * address.
+ */
+ if(H5P_set(c_plist, H5F_CRT_USER_BLOCK_NAME, &sblock->base_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set userblock size")
+
+ /*
+ * Make sure that the data is not truncated. One case where this is
+ * possible is if the first file of a family of files was opened
+ * individually.
+ */
+ /* Can skip this test when it is not the initial file open--
+ * H5F__super_read() call from H5F_evict_tagged_metadata() for
+ * refreshing object.
+ * When flushing file buffers and fractal heap is involved,
+ * the library will allocate actual space for tmp addresses
+ * via the file layer. The aggregator allocates a block,
+ * thus the eoa might be greater than eof.
+ * Note: the aggregator is changed again after being reset
+ * earlier before H5AC_flush due to allocation of tmp addresses.
+ */
+ /* The EOF check must be skipped when the file is opened for SWMR read,
+ * as the file can appear truncated if only part of it has been
+ * been flushed to disk by the SWMR writer process.
+ */
+ if(H5F_INTENT(f) & H5F_ACC_SWMR_READ) {
+ /*
+ * When the file is opened for SWMR read access, skip the check if:
+ * --the file is already marked for SWMR writing and
+ * --the file has version 3 superblock for SWMR support
+ */
+ if((sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS) &&
+ (sblock->status_flags & H5F_SUPER_WRITE_ACCESS) &&
+ sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3)
+ skip_eof_check = TRUE;
+ } /* end if */
+ if(!skip_eof_check && initial_read) {
+ if(HADDR_UNDEF == (eof = H5FD_get_eof(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to determine file size")
+
+ /* (Account for the stored EOA being absolute offset -QAK) */
+ if((eof + sblock->base_addr) < udata.stored_eof)
+ HGOTO_ERROR(H5E_FILE, H5E_TRUNCATED, FAIL, "truncated file: eof = %llu, sblock->base_addr = %llu, stored_eof = %llu", (unsigned long long)eof, (unsigned long long)sblock->base_addr, (unsigned long long)udata.stored_eof)
+ } /* end if */
+
+ /*
+ * Tell the file driver how much address space has already been
+ * allocated so that it knows how to allocate additional memory.
+ */
+
+ /* Set the ring type in the DXPL */
+ ring = H5AC_RING_SBE;
+ if((H5P_set(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set property value");
+
+ /* Decode the optional driver information block */
+ if(H5F_addr_defined(sblock->driver_addr)) {
+ H5O_drvinfo_t *drvinfo; /* Driver info */
+ H5F_drvrinfo_cache_ud_t drvrinfo_udata; /* User data for metadata callbacks */
+ unsigned drvinfo_flags = H5AC__NO_FLAGS_SET; /* Flags used in driver info block unprotect call */
+
+ /* Sanity check - driver info block should only be defined for
+ * superblock version < 2.
+ */
+ HDassert(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2);
+
+ /* Set up user data */
+ drvrinfo_udata.f = f;
+ drvrinfo_udata.driver_addr = sblock->driver_addr;
+
+ /* extend EOA so we can read at least the fixed sized
+ * portion of the driver info block
+ */
+ if(H5FD_set_eoa(f->shared->lf, H5FD_MEM_SUPER, sblock->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE) < 0) /* will extend eoa later if required */
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed")
+
+ /* Look up the driver info block */
+ if(NULL == (drvinfo = (H5O_drvinfo_t *)H5AC_protect(f, meta_dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, &drvrinfo_udata, rw_flags)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTPROTECT, FAIL, "unable to load driver info block")
+
+ /* Loading the driver info block is enough to set up the right info */
+
+ /* Check if we need to rewrite the driver info block info */
+ if(((rw_flags & H5AC__READ_ONLY_FLAG) == 0) && H5F_HAS_FEATURE(f, H5FD_FEAT_DIRTY_DRVRINFO_LOAD))
+ drvinfo_flags |= H5AC__DIRTIED_FLAG;
+
+ /* set the pin entry flag so that the driver information block
+ * cache entry will be pinned in the cache.
+ */
+ drvinfo_flags |= H5AC__PIN_ENTRY_FLAG;
+
+ /* Release the driver info block */
+ if(H5AC_unprotect(f, meta_dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, drvinfo, drvinfo_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTUNPROTECT, FAIL, "unable to release driver info block")
+
+ /* save a pointer to the driver information cache entry */
+ f->shared->drvinfo = drvinfo;
+ } /* end if */
+
+ /* (Account for the stored EOA being absolute offset -NAF) */
+ if(H5F__set_eoa(f, H5FD_MEM_DEFAULT, udata.stored_eof - sblock->base_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set end-of-address marker for file")
+
+ /* Decode the optional superblock extension info */
+ if(H5F_addr_defined(sblock->ext_addr)) {
+ H5O_loc_t ext_loc; /* "Object location" for superblock extension */
+ H5O_btreek_t btreek; /* v1 B-tree 'K' value message from superblock extension */
+ H5O_drvinfo_t drvinfo; /* Driver info message from superblock extension */
+ size_t u; /* Local index variable */
+ htri_t status; /* Status for message existing */
+
+ /* Sanity check - superblock extension should only be defined for
+ * superblock version >= 2.
+ */
+ HDassert(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2);
+
+ /* Check for superblock extension being located "outside" the stored
+ * 'eoa' value, which can occur with the split/multi VFD.
+ */
+ if(H5F_addr_gt(sblock->ext_addr, udata.stored_eof)) {
+ /* Set the 'eoa' for the object header memory type large enough
+ * to give some room for a reasonably sized superblock extension.
+ * (This is _rather_ a kludge -QAK)
+ */
+ if(H5F__set_eoa(f, H5FD_MEM_OHDR, (haddr_t)(sblock->ext_addr + 1024)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set end-of-address marker for file")
+ } /* end if */
+
+ /* Open the superblock extension */
+ if(H5F_super_ext_open(f, sblock->ext_addr, &ext_loc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open file's superblock extension")
+
+ /* Check for the extension having a 'driver info' message */
+ if((status = H5O_msg_exists(&ext_loc, H5O_DRVINFO_ID, meta_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header")
+ if(status) {
+ /* Check for ignoring the driver info for this file */
+ if(!udata.ignore_drvrinfo) {
+
+ /* Retrieve the 'driver info' structure */
+ if(NULL == H5O_msg_read(&ext_loc, H5O_DRVINFO_ID, &drvinfo, meta_dxpl_id))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "driver info message not present")
+
+ /* Validate and decode driver information */
+ if(H5FD_sb_load(f->shared->lf, drvinfo.name, drvinfo.buf) < 0) {
+ H5O_msg_reset(H5O_DRVINFO_ID, &drvinfo);
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, FAIL, "unable to decode driver information")
+ } /* end if */
+
+ /* Reset driver info message */
+ H5O_msg_reset(H5O_DRVINFO_ID, &drvinfo);
+
+ HDassert(FALSE == f->shared->drvinfo_sb_msg_exists);
+ f->shared->drvinfo_sb_msg_exists = TRUE;
+ } /* end else */
+ } /* end if */
+
+ /* Read in the shared OH message information if there is any */
+ if(H5SM_get_info(&ext_loc, c_plist, meta_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to read SOHM table information")
+
+ /* Check for the extension having a 'v1 B-tree "K"' message */
+ if((status = H5O_msg_exists(&ext_loc, H5O_BTREEK_ID, meta_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header")
+ if(status) {
+ /* Retrieve the 'v1 B-tree "K"' structure */
+ if(NULL == H5O_msg_read(&ext_loc, H5O_BTREEK_ID, &btreek, meta_dxpl_id))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "v1 B-tree 'K' info message not present")
+
+ /* Set non-default v1 B-tree 'K' value info from file */
+ sblock->btree_k[H5B_CHUNK_ID] = btreek.btree_k[H5B_CHUNK_ID];
+ sblock->btree_k[H5B_SNODE_ID] = btreek.btree_k[H5B_SNODE_ID];
+ sblock->sym_leaf_k = btreek.sym_leaf_k;
+
+ /* Set non-default v1 B-tree 'K' values in the property list */
+ if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, btreek.btree_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for btree internal nodes")
+ if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &btreek.sym_leaf_k) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for symbol table leaf nodes")
+ } /* end if */
+
+ /* Check for the extension having a 'free-space manager info' message */
+ if((status = H5O_msg_exists(&ext_loc, H5O_FSINFO_ID, meta_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header")
+ if(status) {
+ H5O_fsinfo_t fsinfo; /* File space info message from superblock extension */
+ uint8_t flags; /* Message flags */
+
+ /* Get message flags */
+ if(H5O_msg_get_flags(&ext_loc, H5O_FSINFO_ID, meta_dxpl_id, &flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to message flags for free-space manager info message")
+
+ /* If message is NOT marked "unknown"--set up file space info */
+ if(!(flags & H5O_MSG_FLAG_WAS_UNKNOWN)) {
+
+ /* Retrieve the 'file space info' structure */
+ if(NULL == H5O_msg_read(&ext_loc, H5O_FSINFO_ID, &fsinfo, meta_dxpl_id))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get free-space manager info message")
+
+ /* Update changed values */
+ if(f->shared->fs_strategy != fsinfo.strategy) {
+ f->shared->fs_strategy = fsinfo.strategy;
+
+ /* Set non-default strategy in the property list */
+ if(H5P_set(c_plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &fsinfo.strategy) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space strategy")
+ } /* end if */
+ if(f->shared->fs_persist != fsinfo.persist) {
+ f->shared->fs_persist = fsinfo.persist;
+
+ /* Set non-default strategy in the property list */
+ if(H5P_set(c_plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &fsinfo.persist) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space strategy")
+ } /* end if */
+ if(f->shared->fs_threshold != fsinfo.threshold) {
+ f->shared->fs_threshold = fsinfo.threshold;
+
+ /* Set non-default threshold in the property list */
+ if(H5P_set(c_plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &fsinfo.threshold) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space strategy")
+ } /* end if */
+
+ HDassert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN);
+ HDassert(fsinfo.page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN);
+ if(f->shared->fs_page_size != fsinfo.page_size) {
+ f->shared->fs_page_size = fsinfo.page_size;
+
+ /* Set file space page size in the property list */
+ if(H5P_set(c_plist, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, &fsinfo.page_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space page size")
+ } /* end if */
+ if(f->shared->pgend_meta_thres != fsinfo.pgend_meta_thres)
+ /* Initialize page end meta threshold */
+ f->shared->pgend_meta_thres = fsinfo.pgend_meta_thres;
+
+ if(f->shared->eoa_pre_fsm_fsalloc != fsinfo.eoa_pre_fsm_fsalloc)
+ f->shared->eoa_pre_fsm_fsalloc = fsinfo.eoa_pre_fsm_fsalloc;
+
+ /* f->shared->eoa_pre_fsm_fsalloc must always be HADDR_UNDEF
+ * in the absence of persistant free space managers.
+ */
+ HDassert((!f->shared->fs_persist) || (f->shared->eoa_pre_fsm_fsalloc != HADDR_UNDEF));
+ HDassert(!f->shared->first_alloc_dealloc);
+
+ if((f->shared->eoa_pre_fsm_fsalloc != HADDR_UNDEF) &&
+ (H5F_INTENT(f) & H5F_ACC_RDWR))
+ f->shared->first_alloc_dealloc = TRUE;
+
+ f->shared->fs_addr[0] = HADDR_UNDEF;
+ for(u = 1; u < NELMTS(f->shared->fs_addr); u++)
+ f->shared->fs_addr[u] = fsinfo.fs_addr[u - 1];
+
+ if(fsinfo.mapped && (rw_flags & H5AC__READ_ONLY_FLAG) == 0) {
+
+ /* Do the same kluge until we know for sure. VC */
+#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */
+ /* KLUGE ALERT!!
+ *
+ * H5F_super_ext_write_msg() expects f->shared->sblock to
+ * be set -- verify that it is NULL, and then set it.
+ * Set it back to NULL when we are done.
+ */
+ HDassert(f->shared->sblock == NULL);
+ f->shared->sblock = sblock;
+#endif /* JRM */
+
+ if(H5F_super_ext_remove_msg(f, meta_dxpl_id, H5O_FSINFO_ID) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDELETE, FAIL, "error in removing message from superblock extension")
+
+ if(H5F_super_ext_write_msg(f, meta_dxpl_id, H5O_FSINFO_ID, &fsinfo, TRUE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing fsinfo message to superblock extension")
+#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */
+ f->shared->sblock = NULL;
+#endif /* JRM */
+
+ }
+ } /* end if not marked "unknown" */
+ } /* end if */
+
+ /* Check for the extension having a 'metadata cache image' message */
+ if((status = H5O_msg_exists(&ext_loc, H5O_MDCI_MSG_ID, meta_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header")
+ if(status) {
+ hbool_t rw = ((rw_flags & H5AC__READ_ONLY_FLAG) == 0);
+ H5O_mdci_t mdci_msg;
+
+ /* if the metadata cache image superblock extension message exists,
+ * read its contents and pass the data on to the metadata cache.
+ * Given this data, the cache will load and decode the metadata
+ * cache image block, decoded it and load its contents into the
+ * the cache on the test protect call.
+ *
+ * Further, if the file is opened R/W, the metadata cache will
+ * delete the metadata cache image superblock extension and free
+ * the cache image block. Don't do this now as f->shared
+ * is not fully setup, which complicates matters.
+ */
+
+ /* Retrieve the 'metadata cache image message' structure */
+ if(NULL == H5O_msg_read(&ext_loc, H5O_MDCI_MSG_ID, &mdci_msg, meta_dxpl_id))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get metadata cache image message")
+
+ /* Indicate to the cache that there's an image to load on first protect call */
+ if(H5AC_load_cache_image_on_next_protect(f, mdci_msg.addr, mdci_msg.size, rw) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTLOAD, FAIL, "call to H5AC_load_cache_image_on_next_protect failed");
+ } /* end if */
+
+ /* Close superblock extension */
+ if(H5F_super_ext_close(f, &ext_loc, meta_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close file's superblock extension")
+ } /* end if */
+
+ /* Update the driver info if VFD indicated to do so */
+ /* (NOTE: only for later versions of superblock, earlier versions are handled
+ * earlier in this routine.
+ */
+ if(((rw_flags & H5AC__READ_ONLY_FLAG) == 0) &&
+ sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 &&
+ H5F_addr_defined(sblock->ext_addr)) {
+ /* Check for modifying the driver info when opening the file */
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_DIRTY_DRVRINFO_LOAD)) {
+ size_t driver_size; /* Size of driver info block (bytes) */
+
+ /* Check for driver info message */
+ H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t);
+ if(driver_size > 0) {
+ H5O_drvinfo_t drvinfo; /* Driver info */
+ uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */
+
+ /* Sanity check */
+ HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE);
+
+ /* Encode driver-specific data */
+ if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information")
+
+ /* Set the driver info information for the superblock extension */
+ drvinfo.len = driver_size;
+ drvinfo.buf = dbuf;
+
+ /* Write driver info information to the superblock extension */
+
+#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */
+ /* KLUGE ALERT!!
+ *
+ * H5F_super_ext_write_msg() expects f->shared->sblock to
+ * be set -- verify that it is NULL, and then set it.
+ * Set it back to NULL when we are done.
+ */
+ HDassert(f->shared->sblock == NULL);
+ f->shared->sblock = sblock;
+#endif /* JRM */
+ if(H5F_super_ext_write_msg(f, meta_dxpl_id, H5O_DRVINFO_ID, &drvinfo, FALSE, H5O_MSG_NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension")
+
+#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */
+ f->shared->sblock = NULL;
+#endif /* JRM */
+
+ } /* end if */
+ } /* end if */
+ /* Check for eliminating the driver info block */
+ else if(H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) {
+ /* Remove the driver info message from the superblock extension */
+ if(H5F_super_ext_remove_msg(f, meta_dxpl_id, H5O_DRVINFO_ID) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "error in removing message from superblock extension")
+
+ /* Check if the superblock extension was removed */
+ if(!H5F_addr_defined(sblock->ext_addr))
+ sblock_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ } /* end if */
+
+ /* Set the pointer to the pinned superblock */
+ f->shared->sblock = sblock;
+
+ /* Set the page aggregation mode */
+ if(H5F__set_paged_aggr(f, (hbool_t)H5F_PAGED_AGGR(f)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "failed to set paged_aggr status for file driver")
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Release the superblock */
+ if(sblock && H5AC_unprotect(f, meta_dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, sblock, sblock_flags) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTUNPROTECT, FAIL, "unable to close superblock")
+
+ /* If we have failed, make sure no entries are left in the
+ * metadata cache, so that it can be shut down and discarded.
+ */
+ if(ret_value < 0) {
+ /* Unpin and discard drvinfo cache entry */
+ if(f->shared->drvinfo) {
+ if(H5AC_unpin_entry(f->shared->drvinfo) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin driver info")
+
+ /* Evict the driver info block from the cache */
+ if(H5AC_expunge_entry(f, meta_dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge driver info block")
+ } /* end if */
+
+ /* Unpin & discard superblock */
+ if(sblock) {
+ /* Unpin superblock in cache */
+ if(H5AC_unpin_entry(sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock")
+
+ /* Evict the superblock from the cache */
+ if(H5AC_expunge_entry(f, meta_dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge superblock")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5F__super_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__super_init
+ *
+ * Purpose: Allocates the superblock for the file and initializes
+ * information about the superblock in memory. Writes extension
+ * messages if any are needed.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sept 15, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__super_init(H5F_t *f, hid_t dxpl_id)
+{
+ H5F_super_t *sblock = NULL; /* Superblock cache structure */
+ hbool_t sblock_in_cache = FALSE; /* Whether the superblock has been inserted into the metadata cache */
+ H5O_drvinfo_t *drvinfo = NULL; /* Driver info */
+ hbool_t drvinfo_in_cache = FALSE; /* Whether the driver info block has been inserted into the metadata cache */
+ H5P_genplist_t *plist; /* File creation property list */
+ H5P_genplist_t *dxpl = NULL;
+ H5AC_ring_t ring, orig_ring = H5AC_RING_INV;
+ hsize_t userblock_size; /* Size of userblock, in bytes */
+ hsize_t superblock_size; /* Size of superblock, in bytes */
+ size_t driver_size; /* Size of driver info block (bytes) */
+ unsigned super_vers = HDF5_SUPERBLOCK_VERSION_DEF; /* Superblock version for file */
+ H5O_loc_t ext_loc; /* Superblock extension object location */
+ hbool_t need_ext; /* Whether the superblock extension is needed */
+ hbool_t ext_created = FALSE; /* Whether the extension has been created */
+ hbool_t non_default_fs_settings = FALSE; /* Whether the file has non-default free-space settings */
+ herr_t ret_value = SUCCEED; /* Return Value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, H5AC__SUPERBLOCK_TAG, FAIL)
+
+ /* Allocate space for the superblock */
+ if(NULL == (sblock = H5FL_CALLOC(H5F_super_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize various address information */
+ sblock->base_addr = HADDR_UNDEF;
+ sblock->ext_addr = HADDR_UNDEF;
+ sblock->driver_addr = HADDR_UNDEF;
+ sblock->root_addr = HADDR_UNDEF;
+
+ /* Get the shared file creation property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Initialize sym_leaf_k */
+ if(H5P_get(plist, H5F_CRT_SYM_LEAF_NAME, &sblock->sym_leaf_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get byte number for object size")
+
+ /* Initialize btree_k */
+ if(H5P_get(plist, H5F_CRT_BTREE_RANK_NAME, &sblock->btree_k[0]) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes")
+
+ /* Check for non-default free-space settings */
+ if(!(f->shared->fs_strategy == H5F_FILE_SPACE_STRATEGY_DEF &&
+ f->shared->fs_persist == H5F_FREE_SPACE_PERSIST_DEF &&
+ f->shared->fs_threshold == H5F_FREE_SPACE_THRESHOLD_DEF &&
+ f->shared->fs_page_size == H5F_FILE_SPACE_PAGE_SIZE_DEF))
+ non_default_fs_settings = TRUE;
+
+ /* Bump superblock version if latest superblock version support is enabled */
+ if(H5F_USE_LATEST_FLAGS(f, H5F_LATEST_SUPERBLOCK))
+ super_vers = HDF5_SUPERBLOCK_VERSION_LATEST;
+ /* Bump superblock version to create superblock extension for SOHM info */
+ else if(f->shared->sohm_nindexes > 0)
+ super_vers = HDF5_SUPERBLOCK_VERSION_2;
+ /*
+ * Bump superblock version to create superblock extension for:
+ * -- non-default file space strategy or
+ * -- non-default persisting free-space or
+ * -- non-default free-space threshold or
+ * -- non-default page_size
+ */
+ else if(non_default_fs_settings)
+ super_vers = HDF5_SUPERBLOCK_VERSION_2;
+ /* Check for non-default indexed storage B-tree internal 'K' value
+ * and set the version # of the superblock to 1 if it is a non-default
+ * value.
+ */
+ else if(sblock->btree_k[H5B_CHUNK_ID] != HDF5_BTREE_CHUNK_IK_DEF)
+ super_vers = HDF5_SUPERBLOCK_VERSION_1;
+
+ /* If a newer superblock version is required, set it here */
+ if(super_vers != HDF5_SUPERBLOCK_VERSION_DEF) {
+ H5P_genplist_t *c_plist; /* Property list */
+
+ if(NULL == (c_plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property list")
+ if(H5P_set(c_plist, H5F_CRT_SUPER_VERS_NAME, &super_vers) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set superblock version")
+ } /* end if */
+
+ if(H5FD_set_paged_aggr(f->shared->lf, (hbool_t)H5F_PAGED_AGGR(f)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "failed to set paged_aggr status for file driver")
+
+ /*
+ * The superblock starts immediately after the user-defined
+ * header, which we have already insured is a proper size. The
+ * base address is set to the same thing as the superblock for
+ * now.
+ */
+ if(H5P_get(plist, H5F_CRT_USER_BLOCK_NAME, &userblock_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get userblock size")
+
+ /* Sanity check the userblock size vs. the file's allocation alignment */
+ if(userblock_size > 0) {
+ /* Set up the alignment to use for page or aggr fs */
+ hsize_t alignment = H5F_PAGED_AGGR(f) ? f->shared->fs_page_size : f->shared->alignment;
+
+ if(userblock_size < alignment)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "userblock size must be > file object alignment")
+ if(0 != (userblock_size % alignment))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "userblock size must be an integral multiple of file object alignment")
+ } /* end if */
+
+ sblock->base_addr = userblock_size;
+ sblock->status_flags = 0;
+
+ /* Reserve space for the userblock */
+ if(H5F__set_eoa(f, H5FD_MEM_SUPER, userblock_size) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set EOA value for userblock")
+
+ /* Set the base address for the file in the VFD now, after allocating
+ * space for userblock.
+ */
+ if(H5F__set_base_addr(f, sblock->base_addr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "failed to set base address for file driver")
+
+ /* Save a local copy of the superblock version number, size of addresses & offsets */
+ sblock->super_vers = super_vers;
+ sblock->sizeof_addr = f->shared->sizeof_addr;
+ sblock->sizeof_size = f->shared->sizeof_size;
+
+ /* Compute the size of the superblock */
+ superblock_size = (hsize_t)H5F_SUPERBLOCK_SIZE(sblock);
+
+ /* Compute the size of the driver information block */
+ H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t);
+
+ /* The following code sets driver_size to the valued needed
+ * for the driver info block, and sets the driver info block
+ * address regardless of the version of the superblock.
+ */
+ if(driver_size > 0) {
+ /* Add in the driver info header, for older superblocks */
+ /* Superblock versions >= 2 will put the driver info in a message
+ * and don't need the header -QAK, 1/4/2017
+ */
+ if(super_vers < HDF5_SUPERBLOCK_VERSION_2)
+ driver_size += H5F_DRVINFOBLOCK_HDR_SIZE;
+
+ /*
+ * The file driver information block begins immediately after the
+ * superblock. (relative to base address in file)
+ */
+ sblock->driver_addr = superblock_size;
+ } /* end if */
+
+ /*
+ * Allocate space for the superblock & driver info block.
+ * We do it with one allocation request because the superblock needs to be
+ * at the beginning of the file and only the first allocation request is
+ * required to return memory at format address zero.
+ */
+ if(super_vers < HDF5_SUPERBLOCK_VERSION_2)
+ superblock_size += driver_size;
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_SB, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Insert superblock into cache, pinned */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, sblock, H5AC__PIN_ENTRY_FLAG | H5AC__FLUSH_LAST_FLAG | H5AC__FLUSH_COLLECTIVELY_FLAG) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "can't add superblock to cache")
+ sblock_in_cache = TRUE;
+
+ /* Keep a copy of the superblock info */
+ f->shared->sblock = sblock;
+
+ /* Allocate space for the superblock */
+ if(HADDR_UNDEF == H5MF_alloc(f, H5FD_MEM_SUPER, dxpl_id, superblock_size))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for superblock")
+
+ /* set the drvinfo filed to NULL -- will overwrite this later if needed */
+ f->shared->drvinfo = NULL;
+
+ /*
+ * Determine if we will need a superblock extension
+ */
+
+ /* Files with SOHM indices always need the superblock extension */
+ if(f->shared->sohm_nindexes > 0) {
+ HDassert(super_vers >= HDF5_SUPERBLOCK_VERSION_2);
+ need_ext = TRUE;
+ } /* end if */
+ /* Files with non-default free space settings always need the superblock extension */
+ else if(non_default_fs_settings) {
+ HDassert(super_vers >= HDF5_SUPERBLOCK_VERSION_2);
+ need_ext = TRUE;
+ } /* end if */
+ /* If we're going to use a version of the superblock format which allows
+ * for the superblock extension, check for non-default values to store
+ * in it.
+ */
+ else if(super_vers >= HDF5_SUPERBLOCK_VERSION_2) {
+ /* Check for non-default v1 B-tree 'K' values to store */
+ if(sblock->btree_k[H5B_SNODE_ID] != HDF5_BTREE_SNODE_IK_DEF ||
+ sblock->btree_k[H5B_CHUNK_ID] != HDF5_BTREE_CHUNK_IK_DEF ||
+ sblock->sym_leaf_k != H5F_CRT_SYM_LEAF_DEF)
+ need_ext = TRUE;
+ /* Check for driver info to store */
+ else if(driver_size > 0)
+ need_ext = TRUE;
+ else
+ need_ext = FALSE;
+ } /* end if */
+ else
+ need_ext = FALSE;
+
+ /* Set the ring type in the DXPL */
+ ring = H5AC_RING_SBE;
+ if((H5P_set(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Create the superblock extension for "extra" superblock data, if necessary. */
+ if(need_ext) {
+ /* The superblock extension isn't actually a group, but the
+ * default group creation list should work fine.
+ * If we don't supply a size for the object header, HDF5 will
+ * allocate H5O_MIN_SIZE by default. This is currently
+ * big enough to hold the biggest possible extension, but should
+ * be tuned if more information is added to the superblock
+ * extension.
+ */
+ if(H5F_super_ext_create(f, dxpl_id, &ext_loc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "unable to create superblock extension")
+ ext_created = TRUE;
+
+ /* Create the Shared Object Header Message table and register it with
+ * the metadata cache, if this file supports shared messages.
+ */
+ if(f->shared->sohm_nindexes > 0) {
+ /* Initialize the shared message code & write the SOHM message to the extension */
+ if(H5SM_init(f, plist, &ext_loc, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create SOHM table")
+ } /* end if */
+
+ /* Check for non-default v1 B-tree 'K' values to store */
+ if(sblock->btree_k[H5B_SNODE_ID] != HDF5_BTREE_SNODE_IK_DEF ||
+ sblock->btree_k[H5B_CHUNK_ID] != HDF5_BTREE_CHUNK_IK_DEF ||
+ sblock->sym_leaf_k != H5F_CRT_SYM_LEAF_DEF) {
+ H5O_btreek_t btreek; /* v1 B-tree 'K' value message for superblock extension */
+
+ /* Write v1 B-tree 'K' value information to the superblock extension */
+ btreek.btree_k[H5B_CHUNK_ID] = sblock->btree_k[H5B_CHUNK_ID];
+ btreek.btree_k[H5B_SNODE_ID] = sblock->btree_k[H5B_SNODE_ID];
+ btreek.sym_leaf_k = sblock->sym_leaf_k;
+ if(H5O_msg_create(&ext_loc, H5O_BTREEK_ID, H5O_MSG_FLAG_CONSTANT | H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &btreek, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update v1 B-tree 'K' value header message")
+ } /* end if */
+
+ /* Check for driver info to store */
+ if(driver_size > 0) {
+ H5O_drvinfo_t info; /* Driver info */
+ uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */
+
+ /* Sanity check */
+ HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE);
+
+ /* Encode driver-specific data */
+ HDmemset(dbuf, 0, sizeof(dbuf));
+ if(H5FD_sb_encode(f->shared->lf, info.name, dbuf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information")
+
+ /* Write driver info information to the superblock extension */
+ info.len = driver_size;
+ info.buf = dbuf;
+ if(H5O_msg_create(&ext_loc, H5O_DRVINFO_ID, H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update driver info header message")
+
+ HDassert(FALSE == f->shared->drvinfo_sb_msg_exists);
+ f->shared->drvinfo_sb_msg_exists = TRUE;
+ } /* end if */
+
+ /* Check for non-default free-space info settings */
+ if(non_default_fs_settings) {
+ H5F_mem_page_t ptype;
+ H5O_fsinfo_t fsinfo; /* Free space manager info message */
+
+ /* Write free-space manager info message to superblock extension object header if needed */
+ fsinfo.strategy = f->shared->fs_strategy;
+ fsinfo.persist = f->shared->fs_persist;
+ fsinfo.threshold = f->shared->fs_threshold;
+ fsinfo.page_size = f->shared->fs_page_size;
+ fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres;
+ fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+ fsinfo.mapped = FALSE;
+
+ for(ptype = H5F_MEM_PAGE_SUPER; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF;
+
+ if(H5O_msg_create(&ext_loc, H5O_FSINFO_ID, H5O_MSG_FLAG_DONTSHARE | H5O_MSG_FLAG_MARK_IF_UNKNOWN, H5O_UPDATE_TIME, &fsinfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update free-space info header message")
+ } /* end if */
+ } /* end if */
+ else {
+ /* Check for creating an "old-style" driver info block */
+ if(driver_size > 0) {
+ /* Sanity check */
+ HDassert(H5F_addr_defined(sblock->driver_addr));
+
+ /* Allocate space for the driver info */
+ if(NULL == (drvinfo = (H5O_drvinfo_t *)H5MM_calloc(sizeof(H5O_drvinfo_t))))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "memory allocation failed for driver info message")
+
+ /* Set up driver info message */
+ /* (NOTE: All the actual information (name & driver information) is
+ * actually based on the VFD info in the file handle and
+ * will be encoded by the VFD's 'encode' callback, so it
+ * doesn't need to be set here. -QAK, 7/20/2013
+ */
+ H5_CHECKED_ASSIGN(drvinfo->len, size_t, H5FD_sb_size(f->shared->lf), hsize_t);
+
+ /* Insert driver info block into cache */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, drvinfo, H5AC__PIN_ENTRY_FLAG | H5AC__FLUSH_LAST_FLAG | H5AC__FLUSH_COLLECTIVELY_FLAG) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINS, FAIL, "can't add driver info block to cache")
+ drvinfo_in_cache = TRUE;
+ f->shared->drvinfo = drvinfo;
+ } /* end if */
+ else
+ HDassert(!H5F_addr_defined(sblock->driver_addr));
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Close superblock extension, if it was created */
+ if(ext_created && H5F_super_ext_close(f, &ext_loc, dxpl_id, ext_created) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close file's superblock extension")
+
+ /* Cleanup on failure */
+ if(ret_value < 0) {
+ /* Check if the driver info block has been allocated yet */
+ if(drvinfo) {
+ /* Check if we've cached it already */
+ if(drvinfo_in_cache) {
+ /* Unpin drvinfo in cache */
+ if(H5AC_unpin_entry(drvinfo) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin driver info")
+
+ /* Evict the driver info block from the cache */
+ if(H5AC_expunge_entry(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge driver info block")
+ } /* end if */
+ else
+ /* Free driver info block */
+ H5MM_xfree(drvinfo);
+ } /* end if */
+
+ /* Check if the superblock has been allocated yet */
+ if(sblock) {
+ /* Check if we've cached it already */
+ if(sblock_in_cache) {
+ /* Unpin superblock in cache */
+ if(H5AC_unpin_entry(sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock")
+
+ /* Evict the superblock from the cache */
+ if(H5AC_expunge_entry(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge superblock")
+ } /* end if */
+ else
+ /* Free superblock */
+ if(H5F__super_free(sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "unable to destroy superblock")
+
+ /* Reset variables in file structure */
+ f->shared->sblock = NULL;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5F__super_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_eoa_dirty
+ *
+ * Purpose: Mark the file's EOA info dirty
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * January 4, 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_eoa_dirty(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ /* Mark superblock dirty in cache, so change to EOA will get encoded */
+ if(H5F_super_dirty(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* If the driver information block exists, mark it dirty as well
+ * so that the change in eoa will be reflected there as well if
+ * appropriate.
+ */
+ if(f->shared->drvinfo) {
+ if(H5AC_mark_entry_dirty(f->shared->drvinfo) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark drvinfo as dirty")
+ } /* end if */
+ /* If the driver info is stored as a message, update that instead */
+ else if(f->shared->drvinfo_sb_msg_exists) {
+ if(H5F__update_super_ext_driver_msg(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark drvinfo message as dirty")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_eoa_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_dirty
+ *
+ * Purpose: Mark the file's superblock dirty
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * August 14, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_super_dirty(H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ /* Mark superblock dirty in cache, so change to EOA will get encoded */
+ if(H5AC_mark_entry_dirty(f->shared->sblock) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__super_free
+ *
+ * Purpose: Destroyer the file's superblock
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * April 1, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__super_free(H5F_super_t *sblock)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDassert(sblock);
+
+ /* Free root group symbol table entry, if any */
+ sblock->root_ent = (H5G_entry_t *)H5MM_xfree(sblock->root_ent);
+
+ /* Free superblock */
+ sblock = (H5F_super_t *)H5FL_FREE(H5F_super_t, sblock);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F__super_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__super_size
+ *
+ * Purpose: Get storage size of the superblock and superblock extension
+ *
+ * Return: Success: non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * July 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F__super_size(H5F_t *f, hid_t dxpl_id, hsize_t *super_size, hsize_t *super_ext_size)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ /* Set the superblock size */
+ if(super_size)
+ *super_size = (hsize_t)H5F_SUPERBLOCK_SIZE(f->shared->sblock);
+
+ /* Set the superblock extension size */
+ if(super_ext_size) {
+ if(H5F_addr_defined(f->shared->sblock->ext_addr)) {
+ H5O_loc_t ext_loc; /* "Object location" for superblock extension */
+ H5O_hdr_info_t hdr_info; /* Object info for superblock extension */
+
+ /* Set up "fake" object location for superblock extension */
+ H5O_loc_reset(&ext_loc);
+ ext_loc.file = f;
+ ext_loc.addr = f->shared->sblock->ext_addr;
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_SBE, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Get object header info for superblock extension */
+ if(H5O_get_hdr_info(&ext_loc, dxpl_id, &hdr_info) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to retrieve superblock extension info")
+
+ /* Set the superblock extension size */
+ *super_ext_size = hdr_info.space.total;
+ } /* end if */
+ else
+ /* Set the superblock extension size to zero */
+ *super_ext_size = (hsize_t)0;
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F__super_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_ext_write_msg()
+ *
+ * Purpose: Write the message with ID to the superblock extension
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_super_ext_write_msg(H5F_t *f, hid_t dxpl_id, unsigned id, void *mesg,
+ hbool_t may_create, unsigned mesg_flags)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ hbool_t ext_created = FALSE; /* Whether superblock extension was created */
+ hbool_t ext_opened = FALSE; /* Whether superblock extension was opened */
+ H5O_loc_t ext_loc; /* "Object location" for superblock extension */
+ htri_t status; /* Indicate whether the message exists or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_SBE, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Open/create the superblock extension object header */
+ if(H5F_addr_defined(f->shared->sblock->ext_addr)) {
+ if(H5F_super_ext_open(f, f->shared->sblock->ext_addr, &ext_loc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open file's superblock extension")
+ } /* end if */
+ else {
+ HDassert(may_create);
+ if(H5F_super_ext_create(f, dxpl_id, &ext_loc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "unable to create file's superblock extension")
+ ext_created = TRUE;
+ } /* end else */
+ HDassert(H5F_addr_defined(ext_loc.addr));
+ ext_opened = TRUE;
+
+ /* Check if message with ID does not exist in the object header */
+ if((status = H5O_msg_exists(&ext_loc, id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check object header for message or message exists")
+
+ /* Check for creating vs. writing */
+ if(may_create) {
+ if(status)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "Message should not exist")
+
+ /* Create the message with ID in the superblock extension */
+ if(H5O_msg_create(&ext_loc, id, (mesg_flags | H5O_MSG_FLAG_DONTSHARE), H5O_UPDATE_TIME, mesg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to create the message in object header")
+ } /* end if */
+ else {
+ if(!status)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "Message should exist")
+
+ /* Update the message with ID in the superblock extension */
+ if(H5O_msg_write(&ext_loc, id, (mesg_flags | H5O_MSG_FLAG_DONTSHARE), H5O_UPDATE_TIME, mesg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to write the message in object header")
+ } /* end else */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Close the superblock extension, if it was opened */
+ if(ext_opened && H5F_super_ext_close(f, &ext_loc, dxpl_id, ext_created) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close file's superblock extension")
+
+ /* Mark superblock dirty in cache, if superblock extension was created */
+ if(ext_created && H5AC_mark_entry_dirty(f->shared->sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_ext_write_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_super_ext_remove_msg
+ *
+ * Purpose: Remove the message with ID from the superblock extension
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_super_ext_remove_msg(H5F_t *f, hid_t dxpl_id, unsigned id)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5O_loc_t ext_loc; /* "Object location" for superblock extension */
+ hbool_t ext_opened = FALSE; /* Whether the superblock extension was opened */
+ int null_count = 0; /* # of null messages */
+ htri_t status; /* Indicate whether the message exists or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Make sure that the superblock extension object header exists */
+ HDassert(H5F_addr_defined(f->shared->sblock->ext_addr));
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_SBE, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Open superblock extension object header */
+ if(H5F_super_ext_open(f, f->shared->sblock->ext_addr, &ext_loc) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "error in starting file's superblock extension")
+ ext_opened = TRUE;
+
+ /* Check if message with ID exists in the object header */
+ if((status = H5O_msg_exists(&ext_loc, id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check object header for message")
+ else if(status) { /* message exists */
+ H5O_hdr_info_t hdr_info; /* Object header info for superblock extension */
+
+ /* Remove the message */
+ if(H5O_msg_remove(&ext_loc, id, H5O_ALL, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete free-space manager info message")
+
+ /* Get info for the superblock extension's object header */
+ if(H5O_get_hdr_info(&ext_loc, dxpl_id, &hdr_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve superblock extension info")
+
+ /* If the object header is an empty base chunk, remove superblock extension */
+ if(hdr_info.nchunks == 1) {
+ if((null_count = H5O_msg_count(&ext_loc, H5O_NULL_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "unable to count messages")
+ else if((unsigned)null_count == hdr_info.nmesgs) {
+ HDassert(H5F_addr_defined(ext_loc.addr));
+ if(H5O_delete(f, dxpl_id, ext_loc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "unable to count messages")
+ f->shared->sblock->ext_addr = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Close superblock extension object header, if opened */
+ if(ext_opened && H5F_super_ext_close(f, &ext_loc, dxpl_id, FALSE) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close file's superblock extension")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_super_ext_remove_msg() */
+
diff --git a/src/H5Fsuper_cache.c b/src/H5Fsuper_cache.c
new file mode 100644
index 0000000..76866db
--- /dev/null
+++ b/src/H5Fsuper_cache.c
@@ -0,0 +1,1090 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Fsuper_cache.c
+ * Aug 15 2009
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement file superblock & driver info metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5F__cache_superblock_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5F__cache_superblock_get_final_load_size(const void *image_ptr,
+ size_t image_len, void *udata, size_t *actual_len);
+static htri_t H5F__cache_superblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5F__cache_superblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5F__cache_superblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5F__cache_superblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5F__cache_superblock_free_icr(void *thing);
+
+static herr_t H5F__cache_drvrinfo_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5F__cache_drvrinfo_get_final_load_size(const void *image_ptr,
+ size_t image_len, void *udata, size_t *actual_len);
+static void *H5F__cache_drvrinfo_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5F__cache_drvrinfo_image_len(const void *thing, size_t *image_len);
+static herr_t H5F__cache_drvrinfo_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5F__cache_drvrinfo_free_icr(void *thing);
+
+/* Local encode/decode routines */
+static herr_t H5F__superblock_prefix_decode(H5F_super_t *sblock,
+ const uint8_t **image_ref, const H5F_superblock_cache_ud_t *udata,
+ hbool_t extend_eoa);
+static herr_t H5F__drvrinfo_prefix_decode(H5O_drvinfo_t *drvinfo, char *drv_name,
+ const uint8_t **image_ref, H5F_drvrinfo_cache_ud_t *udata,
+ hbool_t extend_eoa);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5F superblock inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_SUPERBLOCK[1] = {{
+ H5AC_SUPERBLOCK_ID, /* Metadata client ID */
+ "Superblock", /* Metadata client name (for debugging) */
+ H5FD_MEM_SUPER, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5F__cache_superblock_get_initial_load_size,/* 'get_initial_load_size' callback */
+ H5F__cache_superblock_get_final_load_size, /* 'get_final_load_size' callback */
+ H5F__cache_superblock_verify_chksum, /* 'verify_chksum' callback */
+ H5F__cache_superblock_deserialize, /* 'deserialize' callback */
+ H5F__cache_superblock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5F__cache_superblock_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5F__cache_superblock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5F driver info block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_DRVRINFO[1] = {{
+ H5AC_DRVRINFO_ID, /* Metadata client ID */
+ "Driver info block", /* Metadata client name (for debugging) */
+ H5FD_MEM_SUPER, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5F__cache_drvrinfo_get_initial_load_size, /* 'get_initial_load_size' callback */
+ H5F__cache_drvrinfo_get_final_load_size, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5F__cache_drvrinfo_deserialize, /* 'deserialize' callback */
+ H5F__cache_drvrinfo_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5F__cache_drvrinfo_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5F__cache_drvrinfo_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage the H5F_super_t struct */
+H5FL_EXTERN(H5F_super_t);
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__superblock_prefix_decode
+ *
+ * Purpose: Decode a superblock prefix
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * December 15, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__superblock_prefix_decode(H5F_super_t *sblock, const uint8_t **image_ref,
+ const H5F_superblock_cache_ud_t *udata, hbool_t extend_eoa)
+{
+ const uint8_t *image = (const uint8_t *)*image_ref; /* Pointer into raw data buffer */
+ htri_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(sblock);
+ HDassert(image_ref);
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Skip over signature (already checked when locating the superblock) */
+ image += H5F_SIGNATURE_LEN;
+
+ /* Superblock version */
+ sblock->super_vers = *image++;
+ if(sblock->super_vers > HDF5_SUPERBLOCK_VERSION_LATEST)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad superblock version number")
+
+ /* Sanity check */
+ HDassert(((size_t)(image - (const uint8_t *)*image_ref)) == H5F_SUPERBLOCK_FIXED_SIZE);
+
+ /* Determine the size of addresses & size of offsets, for computing the
+ * variable-sized portion of the superblock.
+ */
+ if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
+ sblock->sizeof_addr = image[4];
+ sblock->sizeof_size = image[5];
+ } /* end if */
+ else {
+ sblock->sizeof_addr = image[0];
+ sblock->sizeof_size = image[1];
+ } /* end else */
+ if(sblock->sizeof_addr != 2 && sblock->sizeof_addr != 4 &&
+ sblock->sizeof_addr != 8 && sblock->sizeof_addr != 16 && sblock->sizeof_addr != 32)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number in an address")
+ if(sblock->sizeof_size != 2 && sblock->sizeof_size != 4 &&
+ sblock->sizeof_size != 8 && sblock->sizeof_size != 16 && sblock->sizeof_size != 32)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number for object size")
+
+ /* Check for extending the EOA for the file */
+ if(extend_eoa) {
+ size_t variable_size; /* Variable size of superblock */
+
+ /* Determine the size of the variable-length part of the superblock */
+ variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(sblock->super_vers, sblock->sizeof_addr, sblock->sizeof_size);
+ HDassert(variable_size > 0);
+
+ /* Make certain we can read the variable-sized portion of the superblock */
+ if(H5F__set_eoa(udata->f, H5FD_MEM_SUPER, (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed")
+ } /* end if */
+
+ /* Update the image buffer pointer */
+ *image_ref = image;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__superblock_prefix_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__drvrinfo_prefix_decode
+ *
+ * Purpose: Decode a driver info prefix
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * December 15, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__drvrinfo_prefix_decode(H5O_drvinfo_t *drvrinfo, char *drv_name,
+ const uint8_t **image_ref, H5F_drvrinfo_cache_ud_t *udata,
+ hbool_t extend_eoa)
+{
+ const uint8_t *image = (const uint8_t *)*image_ref; /* Pointer into raw data buffer */
+ unsigned drv_vers; /* Version of driver info block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(drvrinfo);
+ HDassert(image_ref);
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Version number */
+ drv_vers = *image++;
+ if(drv_vers != HDF5_DRIVERINFO_VERSION_0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad driver information block version number")
+
+ image += 3; /* reserved bytes */
+
+ /* Driver info size */
+ UINT32DECODE(image, drvrinfo->len);
+
+ /* Driver name and/or version */
+ if(drv_name) {
+ HDmemcpy(drv_name, (const char *)image, (size_t)8);
+ drv_name[8] = '\0';
+ image += 8; /* advance past name/version */
+ } /* end if */
+
+ /* Extend the EOA if required so that we can read the complete driver info block */
+ if(extend_eoa) {
+ haddr_t eoa; /* Current EOA for the file */
+ haddr_t min_eoa; /* Minimum EOA needed for reading the driver info */
+
+ /* Get current EOA... */
+ eoa = H5FD_get_eoa(udata->f->shared->lf, H5FD_MEM_SUPER);
+ if(!H5F_addr_defined(eoa))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* ... if it is too small, extend it. */
+ min_eoa = udata->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE + drvrinfo->len;
+
+ /* If it grew, set it */
+ if(H5F_addr_gt(min_eoa, eoa))
+ if(H5FD_set_eoa(udata->f->shared->lf, H5FD_MEM_SUPER, min_eoa) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed")
+ } /* end if */
+
+ /* Update the image buffer pointer */
+ *image_ref = image;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__drvrinfo_prefix_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 17, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_superblock_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image_len);
+
+ /* Set the initial image length size */
+ *image_len = H5F_SUPERBLOCK_FIXED_SIZE + /* Fixed size of superblock */
+ H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F__cache_superblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_get_final_load_size
+ *
+ * Purpose: Compute the final size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * November 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_superblock_get_final_load_size(const void *_image, size_t image_len,
+ void *_udata, size_t *actual_len)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */
+ H5F_super_t sblock; /* Temporary file superblock */
+ htri_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+ HDassert(image_len >= H5F_SUPERBLOCK_FIXED_SIZE + 6);
+
+ /* Deserialize the file superblock's prefix */
+ if(H5F__superblock_prefix_decode(&sblock, &image, udata, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, FAIL, "can't decode file superblock prefix")
+
+ /* Save the version to be used in verify_chksum callback */
+ udata->super_vers = sblock.super_vers;
+
+ /* Set the final size for the cache image */
+ *actual_len = H5F_SUPERBLOCK_FIXED_SIZE +
+ (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(sblock.super_vers, sblock.sizeof_addr, sblock.sizeof_size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__cache_superblock_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5F__cache_superblock_verify_chksum(const void *_image, size_t len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* No checksum for version 0 & 1 */
+ if(udata->super_vers >= HDF5_SUPERBLOCK_VERSION_2) {
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__cache_superblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_deserialize
+ *
+ * Purpose: Loads an object from the disk.
+ *
+ * Return: Success: Pointer to new object
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 18 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5F__cache_superblock_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5F_super_t *sblock = NULL; /* File's superblock */
+ H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5F_super_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(len >= H5F_SUPERBLOCK_FIXED_SIZE + 6);
+
+ /* Allocate space for the superblock */
+ if(NULL == (sblock = H5FL_CALLOC(H5F_super_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Deserialize the file superblock's prefix */
+ if(H5F__superblock_prefix_decode(sblock, &image, udata, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode file superblock prefix")
+
+ /* Check for older version of superblock format */
+ if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
+ uint32_t status_flags; /* File status flags */
+ unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */
+ unsigned snode_btree_k; /* B-tree symbol table internal node 'K' value */
+ unsigned chunk_btree_k; /* B-tree chunk internal node 'K' value */
+
+ /* Freespace version (hard-wired) */
+ if(HDF5_FREESPACE_VERSION != *image++)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number")
+
+ /* Root group version number (hard-wired) */
+ if(HDF5_OBJECTDIR_VERSION != *image++)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number")
+
+ /* Skip over reserved byte */
+ image++;
+
+ /* Shared header version number (hard-wired) */
+ if(HDF5_SHAREDHEADER_VERSION != *image++)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number")
+
+ /* Skip over size of file addresses (already decoded) */
+ image++;
+ udata->f->shared->sizeof_addr = sblock->sizeof_addr; /* Keep a local copy also */
+
+ /* Skip over size of file sizes (already decoded) */
+ image++;
+ udata->f->shared->sizeof_size = sblock->sizeof_size; /* Keep a local copy also */
+
+ /* Skip over reserved byte */
+ image++;
+
+ /* Various B-tree sizes */
+ UINT16DECODE(image, sym_leaf_k);
+ if(sym_leaf_k == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank")
+ udata->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */
+
+ /* Need 'get' call to set other array values */
+ UINT16DECODE(image, snode_btree_k);
+ if(snode_btree_k == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes")
+ udata->btree_k[H5B_SNODE_ID] = snode_btree_k;
+
+ /*
+ * Delay setting the value in the property list until we've checked
+ * for the indexed storage B-tree internal 'K' value later.
+ */
+
+ /* File status flags (not really used yet) */
+ UINT32DECODE(image, status_flags);
+ HDassert(status_flags <= 255);
+ sblock->status_flags = (uint8_t)status_flags;
+ if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock")
+
+ /*
+ * If the superblock version # is greater than 0, read in the indexed
+ * storage B-tree internal 'K' value
+ */
+ if(sblock->super_vers > HDF5_SUPERBLOCK_VERSION_DEF) {
+ UINT16DECODE(image, chunk_btree_k);
+
+ /* Reserved bytes are present only in version 1 */
+ if(sblock->super_vers == HDF5_SUPERBLOCK_VERSION_1)
+ image += 2; /* reserved */
+ } /* end if */
+ else
+ chunk_btree_k = HDF5_BTREE_CHUNK_IK_DEF;
+ udata->btree_k[H5B_CHUNK_ID] = chunk_btree_k;
+
+ /* Remainder of "variable-sized" portion of superblock */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->driver_addr/*out*/);
+
+ /* Allocate space for the root group symbol table entry */
+ HDassert(!sblock->root_ent);
+ if(NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t))))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "can't allocate space for root group symbol table entry")
+
+ /* decode the root group symbol table entry */
+ if(H5G_ent_decode(udata->f, (const uint8_t **)&image, sblock->root_ent) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry")
+
+ /* Set the root group address to the correct value */
+ sblock->root_addr = sblock->root_ent->header;
+
+ /* This step is for h5repart tool only. If user wants to change file driver
+ * from family to sec2 while using h5repart, set the driver address to
+ * undefined to let the library ignore the family driver information saved
+ * in the superblock.
+ */
+ if(udata->ignore_drvrinfo && H5F_addr_defined(sblock->driver_addr)) {
+ /* Eliminate the driver info */
+ sblock->driver_addr = HADDR_UNDEF;
+ udata->drvrinfo_removed = TRUE;
+ } /* end if */
+
+ /* NOTE: Driver info block is decoded separately, later */
+
+ } /* end if */
+ else {
+ uint32_t read_chksum; /* Checksum read from file */
+
+ /* Skip over size of file addresses (already decoded) */
+ image++;
+ udata->f->shared->sizeof_addr = sblock->sizeof_addr; /* Keep a local copy also */
+
+ /* Skip over size of file sizes (already decoded) */
+ image++;
+ udata->f->shared->sizeof_size = sblock->sizeof_size; /* Keep a local copy also */
+
+ /* File status flags (not really used yet) */
+ sblock->status_flags = *image++;
+ if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock")
+
+ /* Base, superblock extension, end of file & root group object header addresses */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/);
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->root_addr/*out*/);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Decode checksum */
+ UINT32DECODE(image, read_chksum);
+
+ /* The Driver Information Block may not appear with the version
+ * 2 super block. Thus we set the driver_addr field of the in
+ * core representation of the super block HADDR_UNDEF to prevent
+ * any attempt to load the Driver Information Block.
+ */
+ sblock->driver_addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = sblock;
+
+done:
+ /* Release the [possibly partially initialized] superblock on error */
+ if(!ret_value && sblock)
+ if(H5F__super_free(sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTFREE, NULL, "unable to destroy superblock data")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__cache_superblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_superblock_image_len(const void *_thing, size_t *image_len)
+{
+ const H5F_super_t *sblock = (const H5F_super_t *)_thing; /* Pointer to the object */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(sblock);
+ HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5F_SUPERBLOCK_SIZE(sblock);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F__cache_superblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 19 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_superblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5F_super_t *sblock = (H5F_super_t *)_thing; /* Pointer to the object */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ haddr_t rel_eof; /* Relative EOF for file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(image);
+ HDassert(sblock);
+
+ /* Assert that the superblock is marked as being flushed last (and
+ collectively in parallel) */
+ /* (We'll rely on the cache to make sure it actually *is* flushed
+ last (and collectively in parallel), but this check doesn't hurt) */
+ HDassert(sblock->cache_info.flush_me_last);
+
+ /* Encode the common portion of the file superblock for all versions */
+ HDmemcpy(image, H5F_SIGNATURE, (size_t)H5F_SIGNATURE_LEN);
+ image += H5F_SIGNATURE_LEN;
+ *image++ = (uint8_t)sblock->super_vers;
+
+ /* Check for older version of superblock format */
+ if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
+ *image++ = (uint8_t)HDF5_FREESPACE_VERSION; /* (hard-wired) */
+ *image++ = (uint8_t)HDF5_OBJECTDIR_VERSION; /* (hard-wired) */
+ *image++ = 0; /* reserved*/
+
+ *image++ = (uint8_t)HDF5_SHAREDHEADER_VERSION; /* (hard-wired) */
+ *image++ = sblock->sizeof_addr;
+ *image++ = sblock->sizeof_size;
+ *image++ = 0; /* reserved */
+
+ UINT16ENCODE(image, sblock->sym_leaf_k);
+ UINT16ENCODE(image, sblock->btree_k[H5B_SNODE_ID]);
+ UINT32ENCODE(image, (uint32_t)sblock->status_flags);
+
+ /*
+ * Versions of the superblock >0 have the indexed storage B-tree
+ * internal 'K' value stored
+ */
+ if(sblock->super_vers > HDF5_SUPERBLOCK_VERSION_DEF) {
+ UINT16ENCODE(image, sblock->btree_k[H5B_CHUNK_ID]);
+ *image++ = 0; /*reserved */
+ *image++ = 0; /*reserved */
+ } /* end if */
+
+ /* Encode the base address */
+ H5F_addr_encode(f, &image, sblock->base_addr);
+
+ /* Encode the address of global free-space index */
+ H5F_addr_encode(f, &image, sblock->ext_addr);
+
+ /* Encode the end-of-file address. Note that at this point in time,
+ * the EOF value itself may not be reflective of the file's size, as
+ * we will eventually truncate the file to match the EOA value. As
+ * such, use the EOA value in its place, knowing that the current EOF
+ * value will ultimately match it. */
+ if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+ H5F_addr_encode(f, &image, (rel_eof + sblock->base_addr));
+
+ /* Encode the driver informaton block address */
+ H5F_addr_encode(f, &image, sblock->driver_addr);
+
+ /* Encode the root group object entry, including the cached stab info */
+ if(H5G_ent_encode(f, &image, sblock->root_ent) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTENCODE, FAIL, "can't encode root group symbol table entry")
+
+ /* NOTE: Driver info block is handled separately */
+
+ } /* end if */
+ else { /* sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 */
+ uint32_t chksum; /* Checksum temporary variable */
+ H5O_loc_t *root_oloc; /* Pointer to root group's object location */
+
+ /* Size of file addresses & offsets, and status flags */
+ *image++ = sblock->sizeof_addr;
+ *image++ = sblock->sizeof_size;
+ *image++ = sblock->status_flags;
+
+ /* Encode the base address */
+ H5F_addr_encode(f, &image, sblock->base_addr);
+
+ /* Encode the address of the superblock extension */
+ H5F_addr_encode(f, &image, sblock->ext_addr);
+
+ /* At this point in time, the EOF value itself may
+ * not be reflective of the file's size, since we'll eventually
+ * truncate it to match the EOA value. As such, use the EOA value
+ * in its place, knowing that the current EOF value will
+ * ultimately match it. */
+ if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+ H5F_addr_encode(f, &image, (rel_eof + sblock->base_addr));
+
+ /* Retrieve information for root group */
+ if(NULL == (root_oloc = H5G_oloc(f->shared->root_grp)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to retrieve root group information")
+
+ /* Encode address of root group's object header */
+ H5F_addr_encode(f, &image, root_oloc->addr);
+
+ /* Compute superblock checksum */
+ chksum = H5_checksum_metadata(_image, ((size_t)H5F_SUPERBLOCK_SIZE(sblock) - H5F_SIZEOF_CHKSUM), 0);
+
+ /* Superblock checksum */
+ UINT32ENCODE(image, chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == (size_t)H5F_SUPERBLOCK_SIZE(sblock));
+ } /* end else */
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F__cache_superblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_superblock_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_superblock_free_icr(void *_thing)
+{
+ H5F_super_t *sblock = (H5F_super_t *)_thing; /* Pointer to the object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(sblock);
+ HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK);
+
+ /* Destroy superblock */
+ if(H5F__super_free(sblock) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free superblock")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F__cache_superblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_get_initial_load_size
+ *
+ * Purpose: Compute the intiial size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_drvrinfo_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image_len);
+
+ /* Set the initial image length size */
+ *image_len = H5F_DRVINFOBLOCK_HDR_SIZE; /* Fixed size portion of driver info block */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F__cache_drvrinfo_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_get_final_load_size
+ *
+ * Purpose: Compute the final size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * November 17, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_drvrinfo_get_final_load_size(const void *_image, size_t image_len,
+ void *_udata, size_t *actual_len)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5F_drvrinfo_cache_ud_t *udata = (H5F_drvrinfo_cache_ud_t *)_udata; /* User data */
+ H5O_drvinfo_t drvrinfo; /* Driver info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+ HDassert(image_len == H5F_DRVINFOBLOCK_HDR_SIZE);
+
+ /* Deserialize the file driver info's prefix */
+ if(H5F__drvrinfo_prefix_decode(&drvrinfo, NULL, &image, udata, TRUE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, FAIL, "can't decode file driver info prefix")
+
+ /* Set the final size for the cache image */
+ *actual_len = H5F_DRVINFOBLOCK_HDR_SIZE + drvrinfo.len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__cache_drvrinfo_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_deserialize
+ *
+ * Purpose: Loads an object from the disk.
+ *
+ * Return: Success: Pointer to a new driver info struct
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5F__cache_drvrinfo_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5O_drvinfo_t *drvinfo = NULL; /* Driver info */
+ H5F_drvrinfo_cache_ud_t *udata = (H5F_drvrinfo_cache_ud_t *)_udata; /* User data */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ char drv_name[9]; /* Name of driver */
+ H5O_drvinfo_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(image);
+ HDassert(len >= H5F_DRVINFOBLOCK_HDR_SIZE);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Allocate space for the driver info */
+ if(NULL == (drvinfo = (H5O_drvinfo_t *)H5MM_calloc(sizeof(H5O_drvinfo_t))))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "memory allocation failed for driver info message")
+
+ /* Deserialize the file driver info's prefix */
+ if(H5F__drvrinfo_prefix_decode(drvinfo, drv_name, &image, udata, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode file driver info prefix")
+
+ /* Sanity check */
+ HDassert(len == (H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len));
+
+ /* Validate and decode driver information */
+ if(H5FD_sb_load(udata->f->shared->lf, drv_name, image) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "unable to decode driver information")
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = drvinfo;
+
+done:
+ /* Release the [possibly partially initialized] driver info message on error */
+ if(!ret_value && drvinfo)
+ H5MM_xfree(drvinfo);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F__cache_drvrinfo_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_drvrinfo_image_len(const void *_thing, size_t *image_len)
+{
+ const H5O_drvinfo_t *drvinfo = (const H5O_drvinfo_t *)_thing; /* Pointer to the object */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(drvinfo);
+ HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)(H5F_DRVINFOBLOCK_HDR_SIZE + /* Fixed-size portion of driver info block */
+ drvinfo->len); /* Variable-size portion of driver info block */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F__cache_drvrinfo_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_serialize
+ *
+ * Purpose: Flushes a dirty object to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_drvrinfo_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5O_drvinfo_t *drvinfo = (H5O_drvinfo_t *)_thing; /* Pointer to the object */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *dbuf; /* Pointer to beginning of driver info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(drvinfo);
+ HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO);
+ HDassert(len == (size_t)(H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len));
+
+ /* Save pointer to beginning of driver info */
+ dbuf = image;
+
+ /* Encode the driver information block */
+ *image++ = HDF5_DRIVERINFO_VERSION_0; /* Version */
+ *image++ = 0; /* reserved */
+ *image++ = 0; /* reserved */
+ *image++ = 0; /* reserved */
+
+ /* Driver info size, excluding header */
+ UINT32ENCODE(image, drvinfo->len);
+
+ /* Encode driver-specific data */
+ if(H5FD_sb_encode(f->shared->lf, (char *)image, dbuf + H5F_DRVINFOBLOCK_HDR_SIZE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information")
+
+ /* Advance buffer pointer past name & variable-sized portion of driver info */
+ image += 8 + drvinfo->len;
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F__cache_drvrinfo_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F__cache_drvrinfo_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 20, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F__cache_drvrinfo_free_icr(void *_thing)
+{
+ H5O_drvinfo_t *drvinfo = (H5O_drvinfo_t *)_thing; /* Pointer to the object */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(drvinfo);
+ HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO);
+
+ /* Destroy driver info message */
+ H5MM_xfree(drvinfo);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F__cache_drvrinfo_free_icr() */
+
diff --git a/src/H5Ftest.c b/src/H5Ftest.c
new file mode 100644
index 0000000..dd69b1e
--- /dev/null
+++ b/src/H5Ftest.c
@@ -0,0 +1,220 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ftest.c
+ * Jan 3 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File testing routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Fmodule.h" /* This source code file is part of the H5F module */
+#define H5F_TESTING /*suppress warning about H5F testing funcs*/
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#define H5G_TESTING /*suppress warning about H5G testing funcs*/
+#define H5SM_FRIEND /*suppress error about including H5SMpkg */
+#define H5SM_TESTING /*suppress warning about H5SM testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_sohm_mesg_count_test
+ *
+ * Purpose: Retrieve the number of shared messages of a given type in a file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Jan 3, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_sohm_mesg_count_test(hid_t file_id, unsigned type_id,
+ size_t *mesg_count)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Retrieve count for message type */
+ if(H5SM_get_mesg_count_test(file, H5AC_ind_read_dxpl_id, type_id, mesg_count) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve shared message count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_sohm_mesg_count_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_check_cached_stab_test
+ *
+ * Purpose: Check that a file's superblock contains a cached symbol
+ * table entry, that the entry matches that in the root
+ * group's object header, and check that the addresses are
+ * valid.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Mar 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_check_cached_stab_test(hid_t file_id)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Verify the cached stab info */
+ if(H5G__verify_cached_stab_test(H5G_oloc(file->shared->root_grp), file->shared->sblock->root_ent) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to verify cached symbol table info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_check_cached_stab_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_maxaddr_test
+ *
+ * Purpose: Retrieve the maximum address for a file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Jun 10, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_maxaddr_test(hid_t file_id, haddr_t *maxaddr)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Retrieve maxaddr for file */
+ *maxaddr = file->shared->maxaddr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_maxaddr_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_sbe_addr_test
+ *
+ * Purpose: Retrieve the address of a superblock extension's object header
+ * for a file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Jul 10, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_sbe_addr_test(hid_t file_id, haddr_t *sbe_addr)
+{
+ H5F_t *file; /* File info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Retrieve maxaddr for file */
+ *sbe_addr = file->shared->sblock->ext_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_sbe_addr_test() */
+
diff --git a/src/H5G.c b/src/H5G.c
new file mode 100644
index 0000000..10eb5ed
--- /dev/null
+++ b/src/H5G.c
@@ -0,0 +1,803 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5G.c
+ * Jul 18 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Symbol table functions. The functions that begin with
+ * `H5G_stab_' don't understand the naming system; they operate
+ * on a single symbol table at a time.
+ *
+ * The functions that begin with `H5G_node_' operate on the leaf
+ * nodes of a symbol table B-tree. They should be defined in
+ * the H5Gnode.c file.
+ *
+ * The remaining functions know how to traverse the group
+ * directed graph.
+ *
+ * Names: Object names are a slash-separated list of components. If
+ * the name begins with a slash then it's absolute, otherwise
+ * it's relative ("/foo/bar" is absolute while "foo/bar" is
+ * relative). Multiple consecutive slashes are treated as
+ * single slashes and trailing slashes are ignored. The special
+ * case `/' is the root group. Every file has a root group.
+ *
+ * API functions that look up names take a location ID and a
+ * name. The location ID can be a file ID or a group ID and the
+ * name can be relative or absolute.
+ *
+ * +--------------+----------- +--------------------------------+
+ * | Location ID | Name | Meaning |
+ * +--------------+------------+--------------------------------+
+ * | File ID | "/foo/bar" | Find `foo' within `bar' within |
+ * | | | the root group of the specified|
+ * | | | file. |
+ * +--------------+------------+--------------------------------+
+ * | File ID | "foo/bar" | Find `foo' within `bar' within |
+ * | | | the root group of the specified|
+ * | | | file. |
+ * +--------------+------------+--------------------------------+
+ * | File ID | "/" | The root group of the specified|
+ * | | | file. |
+ * +--------------+------------+--------------------------------+
+ * | File ID | "." | The root group of the specified|
+ * | | | the specified file. |
+ * +--------------+------------+--------------------------------+
+ * | Group ID | "/foo/bar" | Find `foo' within `bar' within |
+ * | | | the root group of the file |
+ * | | | containing the specified group.|
+ * +--------------+------------+--------------------------------+
+ * | Group ID | "foo/bar" | File `foo' within `bar' within |
+ * | | | the specified group. |
+ * +--------------+------------+--------------------------------+
+ * | Group ID | "/" | The root group of the file |
+ * | | | containing the specified group.|
+ * +--------------+------------+--------------------------------+
+ * | Group ID | "." | The specified group. |
+ * +--------------+------------+--------------------------------+
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Group ID class */
+static const H5I_class_t H5I_GROUP_CLS[1] = {{
+ H5I_GROUP, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5G_close /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5G_top_package_initialize_s = FALSE;
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__init_package
+ *
+ * Purpose: Initializes the H5G interface.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ * Notes: The group creation properties are registered in the property
+ * list interface initialization routine (H5P_init_package)
+ * so that the file creation property class can inherit from it
+ * correctly. (Which allows the file creation property list to
+ * control the group creation properties of the root group of
+ * a file) QAK - 24/10/2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Initialize the atom group for the group IDs */
+ if(H5I_register_type(H5I_GROUP_CLS) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Mark "top" of interface as initialized, too */
+ H5G_top_package_initialize_s = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_top_term_package
+ *
+ * Purpose: Close the "top" of the interface, releasing IDs, etc.
+ *
+ * Return: Success: Positive if anything is done that might
+ * affect other interfaces; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, September 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5G_top_package_initialize_s) {
+ if(H5I_nmembers(H5I_GROUP) > 0) {
+ (void)H5I_clear_type(H5I_GROUP, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Mark closed */
+ if(0 == n)
+ H5G_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5G_top_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_term_package
+ *
+ * Purpose: Terminates the H5G interface
+ *
+ * Note: Finishes shutting down the interface, after
+ * H5G_top_term_package() is called
+ *
+ * Return: Success: Positive if anything is done that might
+ * affect other interfaces; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity checks */
+ HDassert(0 == H5I_nmembers(H5I_GROUP));
+ HDassert(FALSE == H5G_top_package_initialize_s);
+
+ /* Destroy the group object id group */
+ n += (H5I_dec_type_ref(H5I_GROUP) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5G_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gcreate2
+ *
+ * Purpose: Creates a new group relative to LOC_ID, giving it the
+ * specified creation property list GCPL_ID and access
+ * property list GAPL_ID. The link to the new group is
+ * created with the LCPL_ID.
+ *
+ * Usage: H5Gcreate2(loc_id, char *name, lcpl_id, gcpl_id, gapl_id)
+ * hid_t loc_id; IN: File or group identifier
+ * const char *name; IN: Absolute or relative name of the new group
+ * hid_t lcpl_id; IN: Property list for link creation
+ * hid_t gcpl_id; IN: Property list for group creation
+ * hid_t gapl_id; IN: Property list for group access
+ *
+ * Return: Success: The object ID of a new, empty group open for
+ * writing. Call H5Gclose() when finished with
+ * the group.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gcreate2(hid_t loc_id, const char *name, hid_t lcpl_id, hid_t gcpl_id,
+ hid_t gapl_id)
+{
+ H5G_loc_t loc; /* Location to create group */
+ H5G_t *grp = NULL; /* New group created */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("i", "i*siii", loc_id, name, lcpl_id, gcpl_id, gapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == lcpl_id)
+ lcpl_id = H5P_LINK_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list")
+
+ /* Check group creation property list */
+ if(H5P_DEFAULT == gcpl_id)
+ gcpl_id = H5P_GROUP_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(gcpl_id, H5P_GROUP_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not group create property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&gapl_id, H5P_CLS_GACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Create the new group & get its ID */
+ if(NULL == (grp = H5G__create_named(&loc, name, lcpl_id, gcpl_id, gapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group")
+ if((ret_value = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ if(ret_value < 0)
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gcreate2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gcreate_anon
+ *
+ * Purpose: Creates a new group relative to LOC_ID, giving it the
+ * specified creation property list GCPL_ID and access
+ * property list GAPL_ID.
+ *
+ * The resulting ID should be linked into the file with
+ * H5Olink or it will be deleted when closed.
+ *
+ * Given the default setting, H5Gcreate_anon() followed by
+ * H5Olink() will have the same function as H5Gcreate2().
+ *
+ * Usage: H5Gcreate_anon(loc_id, char *name, gcpl_id, gapl_id)
+ * hid_t loc_id; IN: File or group identifier
+ * const char *name; IN: Absolute or relative name of the new group
+ * hid_t gcpl_id; IN: Property list for group creation
+ * hid_t gapl_id; IN: Property list for group access
+ *
+ * Example: To create missing groups "A" and "B01" along the given path "/A/B01/grp"
+ * hid_t create_id = H5Pcreate(H5P_GROUP_CREATE);
+ * int status = H5Pset_create_intermediate_group(create_id, TRUE);
+ * hid_t gid = H5Gcreate_anon(file_id, "/A/B01/grp", create_id, H5P_DEFAULT);
+ *
+ * Return: Success: The object ID of a new, empty group open for
+ * writing. Call H5Gclose() when finished with
+ * the group.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Peter Cao
+ * May 08, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gcreate_anon(hid_t loc_id, hid_t gcpl_id, hid_t gapl_id)
+{
+ H5G_loc_t loc;
+ H5G_t *grp = NULL;
+ H5G_obj_create_t gcrt_info; /* Information for group creation */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iii", loc_id, gcpl_id, gapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Check group creation property list */
+ if(H5P_DEFAULT == gcpl_id)
+ gcpl_id = H5P_GROUP_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(gcpl_id, H5P_GROUP_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not group create property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&gapl_id, H5P_CLS_GACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up group creation info */
+ gcrt_info.gcpl_id = gcpl_id;
+ gcrt_info.cache_type = H5G_NOTHING_CACHED;
+ HDmemset(&gcrt_info.cache, 0, sizeof(gcrt_info.cache));
+
+ /* Create the new group & get its ID */
+ if(NULL == (grp = H5G__create(loc.oloc->file, &gcrt_info, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group")
+ if((ret_value = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ /* Release the group's object header, if it was created */
+ if(grp) {
+ H5O_loc_t *oloc; /* Object location for group */
+
+ /* Get the new group's object location */
+ if(NULL == (oloc = H5G_oloc(grp)))
+ HDONE_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get object location of group")
+
+ /* Decrement refcount on group's object header in memory */
+ if(H5O_dec_rc_by_loc(oloc, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+ } /* end if */
+
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gcreate_anon() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gopen2
+ *
+ * Purpose: Opens an existing group for modification. When finished,
+ * call H5Gclose() to close it and release resources.
+ *
+ * This function allows the user the pass in a Group Access
+ * Property List, which H5Gopen1() does not.
+ *
+ * Return: Success: Object ID of the group.
+ * Failure: FAIL
+ *
+ * Programmer: James Laird
+ * Thursday, July 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gopen2(hid_t loc_id, const char *name, hid_t gapl_id)
+{
+ H5G_t *grp = NULL; /* Group opened */
+ H5G_loc_t loc; /* Location of parent for group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*si", loc_id, name, gapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&gapl_id, H5P_CLS_GACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the group */
+ if((grp = H5G__open_name(&loc, name, gapl_id, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+
+ /* Register an ID for the group */
+ if((ret_value = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ if(ret_value < 0) {
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gopen2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_create_plist
+ *
+ * Purpose: Returns a copy of the group creation property list.
+ *
+ * Return: Success: ID for a copy of the group creation
+ * property list. The property list ID should be
+ * released by calling H5Pclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 25, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gget_create_plist(hid_t group_id)
+{
+ H5G_t *group = NULL;
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", group_id);
+
+ /* Check args */
+ if(NULL == (group = (H5G_t *)H5I_object_verify(group_id, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ if((ret_value = H5G_get_create_plist(group)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_info
+ *
+ * Purpose: Retrieve information about a group.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_info(hid_t grp_id, H5G_info_t *grp_info)
+{
+ H5I_type_t id_type; /* Type of ID */
+ H5G_loc_t loc; /* Location of group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", grp_id, grp_info);
+
+ /* Check args */
+ id_type = H5I_get_type(grp_id);
+ if(!(H5I_GROUP == id_type || H5I_FILE == id_type))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument")
+ if(!grp_info)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Get group location */
+ if(H5G_loc(grp_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Retrieve the group's information */
+ if(H5G__obj_info(loc.oloc, grp_info/*out*/, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve group info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_info_by_name
+ *
+ * Purpose: Retrieve information about a group.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_info_by_name(hid_t loc_id, const char *name, H5G_info_t *grp_info,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ H5G_loc_t grp_loc; /* Location used to open group */
+ H5G_name_t grp_path; /* Opened object group hier. path */
+ H5O_loc_t grp_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Location at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*s*xi", loc_id, name, grp_info, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(!grp_info)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ H5G_loc_reset(&grp_loc);
+
+ /* Find the group object */
+ if(H5G_loc_find(&loc, name, &grp_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ loc_found = TRUE;
+
+ /* Retrieve the group's information */
+ if(H5G__obj_info(grp_loc.oloc, grp_info/*out*/, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve group info")
+
+done:
+ if(loc_found && H5G_loc_free(&grp_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_info_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_info_by_idx
+ *
+ * Purpose: Retrieve information about a group, according to the order
+ * of an index.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_info_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, H5G_info_t *grp_info, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ H5G_loc_t grp_loc; /* Location used to open group */
+ H5G_name_t grp_path; /* Opened object group hier. path */
+ H5O_loc_t grp_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIoh*xi", loc_id, group_name, idx_type, order, n, grp_info,
+ lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!grp_info)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ H5G_loc_reset(&grp_loc);
+
+ /* Find the object's location, according to the order in the index */
+ if(H5G_loc_find_by_idx(&loc, group_name, idx_type, order, n, &grp_loc/*out*/,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found")
+ loc_found = TRUE;
+
+ /* Retrieve the group's information */
+ if(H5G__obj_info(grp_loc.oloc, grp_info/*out*/, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve group info")
+
+done:
+ /* Release the object location */
+ if(loc_found && H5G_loc_free(&grp_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_info_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gclose
+ *
+ * Purpose: Closes the specified group. The group ID will no longer be
+ * valid for accessing the group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 31, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gclose(hid_t group_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", group_id);
+
+ /* Check args */
+ if(NULL == H5I_object_verify(group_id,H5I_GROUP))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /*
+ * Decrement the counter on the group atom. It will be freed if the count
+ * reaches zero.
+ */
+ if(H5I_dec_app_ref(group_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close group")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gflush
+ *
+ * Purpose: Flushes all buffers associated with a group to disk.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gflush(hid_t group_id)
+{
+ H5G_t *grp; /* Dataset for this operation */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", group_id);
+
+ /* Check args */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(group_id, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Flush object's metadata to file */
+ if(H5O_flush_common(&grp->oloc, group_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFLUSH, FAIL, "unable to flush group and object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Gflush */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Grefresh
+ *
+ * Purpose: Refreshes all buffers associated with a dataset.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * July 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Grefresh(hid_t group_id)
+{
+ H5G_t * grp = NULL;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", group_id);
+
+ /* Check args */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(group_id, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Call private function to refresh group object */
+ if ((H5O_refresh_metadata(group_id, grp->oloc, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to refresh group")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Grefresh */
+
diff --git a/src/H5Gbtree2.c b/src/H5Gbtree2.c
new file mode 100644
index 0000000..71d15e5
--- /dev/null
+++ b/src/H5Gbtree2.c
@@ -0,0 +1,538 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gbtree2.c
+ * Sep 9 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: v2 B-tree callbacks for indexing fields on links
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/*
+ * Data exchange structure for dense link storage. This structure is
+ * passed through the fractal heap layer to compare links.
+ */
+typedef struct H5G_fh_ud_cmp_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const char *name; /* Name of link to compare */
+ H5B2_found_t found_op; /* Callback when correct link is found */
+ void *found_op_data; /* Callback data when correct link is found */
+
+ /* upward */
+ int cmp; /* Comparison of two link names */
+} H5G_fh_ud_cmp_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* v2 B-tree function callbacks */
+
+/* v2 B-tree driver callbacks for 'creation order' index */
+static herr_t H5G_dense_btree2_corder_store(void *native, const void *udata);
+static herr_t H5G_dense_btree2_corder_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5G_dense_btree2_corder_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5G_dense_btree2_corder_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5G_dense_btree2_corder_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* v2 B-tree driver callbacks for 'name' index */
+static herr_t H5G_dense_btree2_name_store(void *native, const void *udata);
+static herr_t H5G__dense_btree2_name_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5G_dense_btree2_name_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5G_dense_btree2_name_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5G_dense_btree2_name_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* Fractal heap function callbacks */
+static herr_t H5G_dense_fh_name_cmp(const void *obj, size_t obj_len, void *op_data);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+/* v2 B-tree class for indexing 'name' field of links */
+const H5B2_class_t H5G_BT2_NAME[1]={{ /* B-tree class information */
+ H5B2_GRP_DENSE_NAME_ID, /* Type of B-tree */
+ "H5B2_GRP_DENSE_NAME_ID", /* Name of B-tree class */
+ sizeof(H5G_dense_bt2_name_rec_t), /* Size of native record */
+ NULL, /* Create client callback context */
+ NULL, /* Destroy client callback context */
+ H5G_dense_btree2_name_store, /* Record storage callback */
+ H5G__dense_btree2_name_compare, /* Record comparison callback */
+ H5G_dense_btree2_name_encode, /* Record encoding callback */
+ H5G_dense_btree2_name_decode, /* Record decoding callback */
+ H5G_dense_btree2_name_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for indexing 'creation order' field of links */
+const H5B2_class_t H5G_BT2_CORDER[1]={{ /* B-tree class information */
+ H5B2_GRP_DENSE_CORDER_ID, /* Type of B-tree */
+ "H5B2_GRP_DENSE_CORDER_ID", /* Name of B-tree class */
+ sizeof(H5G_dense_bt2_corder_rec_t), /* Size of native record */
+ NULL, /* Create client callback context */
+ NULL, /* Destroy client callback context */
+ H5G_dense_btree2_corder_store, /* Record storage callback */
+ H5G_dense_btree2_corder_compare, /* Record comparison callback */
+ H5G_dense_btree2_corder_encode, /* Record encoding callback */
+ H5G_dense_btree2_corder_decode, /* Record decoding callback */
+ H5G_dense_btree2_corder_debug /* Record debugging callback */
+}};
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_fh_name_cmp
+ *
+ * Purpose: Compares the name of a link in a fractal heap to another
+ * name
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_fh_name_cmp(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_cmp_t *udata = (H5G_fh_ud_cmp_t *)_udata; /* User data for 'op' callback */
+ H5O_link_t *lnk; /* Pointer to link created from heap object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information */
+ if(NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link")
+
+ /* Compare the string values */
+ udata->cmp = HDstrcmp(udata->name, lnk->name);
+
+ /* Check for correct link & callback to make */
+ if(udata->cmp == 0 && udata->found_op) {
+ if((udata->found_op)(lnk, udata->found_op_data) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link found callback failed")
+ } /* end if */
+
+ /* Release the space allocated for the link */
+ H5O_msg_free(H5O_LINK_ID, lnk);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_fh_name_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_name_store
+ *
+ * Purpose: Store user information into native record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, September 9, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_name_store(void *_nrecord, const void *_udata)
+{
+ const H5G_bt2_ud_ins_t *udata = (const H5G_bt2_ud_ins_t *)_udata;
+ H5G_dense_bt2_name_rec_t *nrecord = (H5G_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Copy user information info native record */
+ nrecord->hash = udata->common.name_hash;
+ HDmemcpy(nrecord->id, udata->id, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_name_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_btree2_name_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G__dense_btree2_name_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
+{
+ const H5G_bt2_ud_common_t *bt2_udata = (const H5G_bt2_ud_common_t *)_bt2_udata;
+ const H5G_dense_bt2_name_rec_t *bt2_rec = (const H5G_dense_bt2_name_rec_t *)_bt2_rec;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(bt2_udata);
+ HDassert(bt2_rec);
+
+#ifdef QAK
+{
+unsigned u;
+
+HDfprintf(stderr, "%s: bt2_udata = {'%s', %x}\n", "H5G__dense_btree2_name_compare", bt2_udata->name, (unsigned)bt2_udata->name_hash);
+HDfprintf(stderr, "%s: bt2_rec = {%x, ", "H5G__dense_btree2_name_compare", (unsigned)bt2_rec->hash);
+for(u = 0; u < H5G_DENSE_FHEAP_ID_LEN; u++)
+ HDfprintf(stderr, "%02x%s", bt2_rec->id[u], (u < (H5G_DENSE_FHEAP_ID_LEN - 1) ? " " : "}\n"));
+}
+#endif /* QAK */
+ /* Check hash value */
+ if(bt2_udata->name_hash < bt2_rec->hash)
+ *result = (-1);
+ else if(bt2_udata->name_hash > bt2_rec->hash)
+ *result = 1;
+ else {
+ H5G_fh_ud_cmp_t fh_udata; /* User data for fractal heap 'op' callback */
+
+ /* Sanity check */
+ HDassert(bt2_udata->name_hash == bt2_rec->hash);
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.name = bt2_udata->name;
+ fh_udata.found_op = bt2_udata->found_op;
+ fh_udata.found_op_data = bt2_udata->found_op_data;
+
+ /* up */
+ fh_udata.cmp = 0;
+
+ /* Check if the user's link and the B-tree's link have the same name */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, bt2_rec->id,
+ H5G_dense_fh_name_cmp, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+
+ /* Callback will set comparison value */
+ *result = fh_udata.cmp;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__dense_btree2_name_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_name_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_name_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ const H5G_dense_bt2_name_rec_t *nrecord = (const H5G_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Encode the record's fields */
+ UINT32ENCODE(raw, nrecord->hash)
+ HDmemcpy(raw, nrecord->id, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_name_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_name_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_name_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ H5G_dense_bt2_name_rec_t *nrecord = (H5G_dense_bt2_name_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Decode the record's fields */
+ UINT32DECODE(raw, nrecord->hash)
+ HDmemcpy(nrecord->id, raw, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_name_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_name_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_name_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5G_dense_bt2_name_rec_t *nrecord = (const H5G_dense_bt2_name_rec_t *)_nrecord;
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%x, ", indent, "", fwidth, "Record:",
+ (unsigned)nrecord->hash);
+ for(u = 0; u < H5G_DENSE_FHEAP_ID_LEN; u++)
+ HDfprintf(stderr, "%02x%s", nrecord->id[u], (u < (H5G_DENSE_FHEAP_ID_LEN - 1) ? " " : "}\n"));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_name_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_corder_store
+ *
+ * Purpose: Store user information into native record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_corder_store(void *_nrecord, const void *_udata)
+{
+ const H5G_bt2_ud_ins_t *udata = (const H5G_bt2_ud_ins_t *)_udata;
+ H5G_dense_bt2_corder_rec_t *nrecord = (H5G_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Copy user information info native record */
+ nrecord->corder = udata->common.corder;
+ HDmemcpy(nrecord->id, udata->id, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_corder_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_corder_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_corder_compare(const void *_bt2_udata, const void *_bt2_rec, int *result)
+{
+ const H5G_bt2_ud_common_t *bt2_udata = (const H5G_bt2_ud_common_t *)_bt2_udata;
+ const H5G_dense_bt2_corder_rec_t *bt2_rec = (const H5G_dense_bt2_corder_rec_t *)_bt2_rec;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(bt2_udata);
+ HDassert(bt2_rec);
+
+#ifdef QAK
+{
+unsigned u;
+
+HDfprintf(stderr, "%s: bt2_udata->corder = %Hd\n", "H5G_dense_btree2_corder_compare", (hsize_t)bt2_udata->corder);
+HDfprintf(stderr, "%s: bt2_rec = {%Hu, ", "H5G_dense_btree2_corder_compare", (hsize_t)bt2_rec->corder);
+for(u = 0; u < H5G_DENSE_FHEAP_ID_LEN; u++)
+ HDfprintf(stderr, "%02x%s", bt2_rec->id[u], (u < (H5G_DENSE_FHEAP_ID_LEN - 1) ? " " : "}\n"));
+}
+#endif /* QAK */
+ /* Check creation order value */
+ if(bt2_udata->corder < bt2_rec->corder)
+ *result = -1;
+ else if(bt2_udata->corder > bt2_rec->corder)
+ *result = 1;
+ else
+ *result = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_corder_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_corder_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_corder_encode(uint8_t *raw, const void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ const H5G_dense_bt2_corder_rec_t *nrecord = (const H5G_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Encode the record's fields */
+ INT64ENCODE(raw, nrecord->corder)
+ HDmemcpy(raw, nrecord->id, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_corder_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_corder_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_corder_decode(const uint8_t *raw, void *_nrecord, void H5_ATTR_UNUSED *ctx)
+{
+ H5G_dense_bt2_corder_rec_t *nrecord = (H5G_dense_bt2_corder_rec_t *)_nrecord;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Decode the record's fields */
+ INT64DECODE(raw, nrecord->corder)
+ HDmemcpy(nrecord->id, raw, (size_t)H5G_DENSE_FHEAP_ID_LEN);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_corder_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_btree2_corder_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_btree2_corder_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5G_dense_bt2_corder_rec_t *nrecord = (const H5G_dense_bt2_corder_rec_t *)_nrecord;
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%llu, ", indent, "", fwidth, "Record:",
+ (unsigned long long)nrecord->corder);
+ for(u = 0; u < H5G_DENSE_FHEAP_ID_LEN; u++)
+ HDfprintf(stderr, "%02x%s", nrecord->id[u], (u < (H5G_DENSE_FHEAP_ID_LEN - 1) ? " " : "}\n"));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5G_dense_btree2_corder_debug() */
+
diff --git a/src/H5Gcache.c b/src/H5Gcache.c
new file mode 100644
index 0000000..65115a5
--- /dev/null
+++ b/src/H5Gcache.c
@@ -0,0 +1,350 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gcache.c
+ * Feb 5 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement group metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5G_NODE_VERS 1 /* Symbol table node version number */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5G__cache_node_get_initial_load_size(void *udata, size_t *image_len);
+static void *H5G__cache_node_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5G__cache_node_image_len(const void *thing, size_t *image_len);
+static herr_t H5G__cache_node_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5G__cache_node_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Symbol table nodes inherit cache-like properties from H5AC */
+const H5AC_class_t H5AC_SNODE[1] = {{
+ H5AC_SNODE_ID, /* Metadata client ID */
+ "Symbol table node", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5G__cache_node_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5G__cache_node_deserialize, /* 'deserialize' callback */
+ H5G__cache_node_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5G__cache_node_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5G__cache_node_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/* Declare extern the free list to manage the H5G_node_t struct */
+H5FL_EXTERN(H5G_node_t);
+
+/* Declare extern the free list to manage sequences of H5G_entry_t's */
+H5FL_SEQ_EXTERN(H5G_entry_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__cache_node_get_initial_load_size()
+ *
+ * Purpose: Determine the size of the on-disk image of the node, and
+ * return this value in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G__cache_node_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5F_t *f = (H5F_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)(H5G_NODE_SIZE(f));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__cache_node_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__cache_node_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of a symbol table
+ * node, allocate an instance of H5G_node_t, load the contence of the
+ * image into it, and return a pointer to the instance.
+ *
+ * Note that deserializing the image requires access to the file
+ * pointer, which is not included in the parameter list for this
+ * callback. Finesse this issue by passing in the file pointer
+ * twice to the H5AC_protect() call -- once as the file pointer
+ * proper, and again as the user data
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5G__cache_node_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5F_t *f = (H5F_t *)_udata; /* User data for callback */
+ H5G_node_t *sym = NULL; /* Symbol table node created */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer to image to deserialize */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(f);
+ HDassert(dirty);
+
+ /* Allocate symbol table data structures */
+ if(NULL == (sym = H5FL_CALLOC(H5G_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ sym->node_size = (size_t)(H5G_NODE_SIZE(f));
+ if(NULL == (sym->entry = H5FL_SEQ_CALLOC(H5G_entry_t, (size_t)(2 * H5F_SYM_LEAF_K(f)))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* magic */
+ if(HDmemcmp(image, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "bad symbol table node signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* version */
+ if(H5G_NODE_VERS != *image++)
+ HGOTO_ERROR(H5E_SYM, H5E_VERSION, NULL, "bad symbol table node version")
+
+ /* reserved */
+ image++;
+
+ /* number of symbols */
+ UINT16DECODE(image, sym->nsyms);
+
+ /* entries */
+ if(H5G__ent_decode_vec(f, &image, sym->entry, sym->nsyms) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, NULL, "unable to decode symbol table entries")
+
+ /* Set return value */
+ ret_value = sym;
+
+done:
+ if(!ret_value)
+ if(sym && H5G__node_free(sym) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, NULL, "unable to destroy symbol table node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__cache_node_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__cache_node_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk and return
+ * it in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G__cache_node_image_len(const void *_thing, size_t *image_len)
+{
+ const H5G_node_t *sym = (const H5G_node_t *)_thing; /* Pointer to object */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(sym);
+ HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sym->cache_info.type == H5AC_SNODE);
+ HDassert(image_len);
+
+ *image_len = sym->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__cache_node_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__cache_node_serialize
+ *
+ * Purpose: Given a correctly sized buffer and an instace of H5G_node_t,
+ * serialize the contents of the instance of H5G_node_t, and write
+ * this data into the supplied buffer. This buffer will be written
+ * to disk.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G__cache_node_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5G_node_t *sym = (H5G_node_t *)_thing; /* Pointer to object */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image);
+ HDassert(sym);
+ HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(sym->cache_info.type == H5AC_SNODE);
+ HDassert(len == sym->node_size);
+
+ /* magic number */
+ HDmemcpy(image, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* version number */
+ *image++ = H5G_NODE_VERS;
+
+ /* reserved */
+ *image++ = 0;
+
+ /* number of symbols */
+ UINT16ENCODE(image, sym->nsyms);
+
+ /* entries */
+ if(H5G__ent_encode_vec(f, &image, sym->entry, sym->nsyms) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't serialize")
+
+ /* Clear rest of symbol table node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__cache_node_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__cache_node_free_icr
+ *
+ * Purpose: Destroys a symbol table node in memory.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G__cache_node_free_icr(void *_thing)
+{
+ H5G_node_t *sym = (H5G_node_t *)_thing; /* Pointer to the object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(sym);
+ HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(sym->cache_info.type == H5AC_SNODE);
+
+ /* Destroy symbol table node */
+ if(H5G__node_free(sym) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to destroy symbol table node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__cache_node_free_icr() */
+
diff --git a/src/H5Gcompact.c b/src/H5Gcompact.c
new file mode 100644
index 0000000..d5698a8
--- /dev/null
+++ b/src/H5Gcompact.c
@@ -0,0 +1,646 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gcompact.c
+ * Sep 5 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for handling compact storage.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5MMprivate.h" /* Memory management */
+
+/* Private typedefs */
+
+/* User data for link message iteration when building link table */
+typedef struct {
+ H5G_link_table_t *ltable; /* Pointer to link table to build */
+ size_t curr_lnk; /* Current link to operate on */
+} H5G_iter_bt_t;
+
+/* User data for deleting a link in the link messages */
+typedef struct {
+ /* downward */
+ H5F_t *file; /* File that object header is located within */
+ hid_t dxpl_id; /* DXPL during insertion */
+ H5RS_str_t *grp_full_path_r;/* Full path for group of link */
+ const char *name; /* Link name to search for */
+} H5G_iter_rm_t;
+
+/* User data for link message iteration when querying link info */
+typedef struct {
+ /* downward */
+ const char *name; /* Name to search for */
+
+ /* upward */
+ H5O_link_t *lnk; /* Link struct to fill in */
+ hbool_t found; /* Flag to indicate that the object was found */
+} H5G_iter_lkp_t;
+
+/* Private macros */
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5G_compact_build_table_cb(const void *_mesg, unsigned idx, void *_udata);
+static herr_t H5G_compact_build_table(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ H5G_link_table_t *ltable);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_compact_build_table_cb
+ *
+ * Purpose: Callback routine for searching 'link' messages for a particular
+ * name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 5 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_compact_build_table_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */
+ H5G_iter_bt_t *udata = (H5G_iter_bt_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value=H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+ HDassert(udata->curr_lnk < udata->ltable->nlinks);
+
+ /* Copy link message into table */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, lnk, &(udata->ltable->lnks[udata->curr_lnk])))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+
+ /* Increment current link entry to operate on */
+ udata->curr_lnk++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_compact_build_table_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_compact_build_table
+ *
+ * Purpose: Builds a table containing a sorted (alphabetically) list of
+ * links for a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_compact_build_table(const H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, H5G_link_table_t *ltable)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(linfo);
+ HDassert(ltable);
+
+ /* Set size of table */
+ H5_CHECK_OVERFLOW(linfo->nlinks, hsize_t, size_t);
+ ltable->nlinks = (size_t)linfo->nlinks;
+
+ /* Allocate space for the table entries */
+ if(ltable->nlinks > 0) {
+ H5G_iter_bt_t udata; /* User data for iteration callback */
+ H5O_mesg_operator_t op; /* Message operator */
+
+ /* Allocate the link table */
+ if((ltable->lnks = (H5O_link_t *)H5MM_malloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set up user data for iteration */
+ udata.ltable = ltable;
+ udata.curr_lnk = 0;
+
+ /* Iterate through the link messages, adding them to the table */
+ op.op_type = H5O_MESG_OP_APP;
+ op.u.app_op = H5G_compact_build_table_cb;
+ if(H5O_msg_iterate(oloc, H5O_LINK_ID, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over link messages")
+
+ /* Sort link table in correct iteration order */
+ if(H5G__link_sort_table(ltable, idx_type, order) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages")
+ } /* end if */
+ else
+ ltable->lnks = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_compact_build_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_insert
+ *
+ * Purpose: Insert a new symbol into the table described by GRP_ENT in
+ * file F. The name of the new symbol is NAME and its symbol
+ * table entry is OBJ_ENT.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__compact_insert(const H5O_loc_t *grp_oloc, H5O_link_t *obj_lnk,
+ hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(obj_lnk);
+
+ /* Insert link message into group */
+ if(H5O_msg_create(grp_oloc, H5O_LINK_ID, 0, H5O_UPDATE_TIME, obj_lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_get_name_by_idx
+ *
+ * Purpose: Returns the name of objects in the group by giving index.
+ *
+ * Return: Success: Non-negative, length of name
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G__compact_get_name_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t idx, char* name, size_t size)
+{
+ H5G_link_table_t ltable = {0, NULL}; /* Link table */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Build table of all link messages */
+ if(H5G_compact_build_table(oloc, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table")
+
+ /* Check for going out of bounds */
+ if(idx >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Get the length of the name */
+ ret_value = (ssize_t)HDstrlen(ltable.lnks[idx].name);
+
+ /* Copy the name into the user's buffer, if given */
+ if(name) {
+ HDstrncpy(name, ltable.lnks[idx].name, MIN((size_t)(ret_value + 1), size));
+ if((size_t)ret_value >= size)
+ name[size - 1]='\0';
+ } /* end if */
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_get_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_compact_remove_common_cb
+ *
+ * Purpose: Common callback routine for deleting 'link' message for a
+ * particular name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 5 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_compact_remove_common_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */
+ H5G_iter_rm_t *udata = (H5G_iter_rm_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* If we've found the right link, get the object type */
+ if(HDstrcmp(lnk->name, udata->name) == 0) {
+ /* Replace path names for link being removed */
+ if(H5G__link_name_replace(udata->file, udata->dxpl_id, udata->grp_full_path_r, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get object type")
+
+ /* Stop the iteration, we found the correct link */
+ HGOTO_DONE(H5_ITER_STOP)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_compact_remove_common_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_remove
+ *
+ * Purpose: Remove NAME from links.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__compact_remove(const H5O_loc_t *oloc, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
+ const char *name)
+{
+ H5G_iter_rm_t udata; /* Data to pass through OH iteration */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(oloc && oloc->file);
+ HDassert(name && *name);
+
+ /* Initialize data to pass through object header iteration */
+ udata.file = oloc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.grp_full_path_r = grp_full_path_r;
+ udata.name = name;
+
+ /* Iterate over the link messages to delete the right one */
+ if(H5O_msg_remove_op(oloc, H5O_LINK_ID, H5O_FIRST, H5G_compact_remove_common_cb, &udata, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_remove_by_idx
+ *
+ * Purpose: Remove link from group, according to an index order.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__compact_remove_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n)
+{
+ H5G_link_table_t ltable = {0, NULL};/* Link table */
+ H5G_iter_rm_t udata; /* Data to pass through OH iteration */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(oloc && oloc->file);
+ HDassert(linfo);
+
+ /* Build table of all link messages, sorted according to desired order */
+ if(H5G_compact_build_table(oloc, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table")
+
+ /* Check for going out of bounds */
+ if(n >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index out of bound")
+
+ /* Initialize data to pass through object header iteration */
+ udata.file = oloc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.grp_full_path_r = grp_full_path_r;
+ udata.name = ltable.lnks[n].name;
+
+ /* Iterate over the link messages to delete the right one */
+ if(H5O_msg_remove_op(oloc, H5O_LINK_ID, H5O_FIRST, H5G_compact_remove_common_cb, &udata, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link message")
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_iterate
+ *
+ * Purpose: Iterate over the links in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__compact_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ H5G_lib_iterate_t op, void *op_data)
+{
+ H5G_link_table_t ltable = {0, NULL}; /* Link table */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(linfo);
+ HDassert(op);
+
+ /* Build table of all link messages */
+ if(H5G_compact_build_table(oloc, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table")
+
+ /* Iterate over links in table */
+ if((ret_value = H5G__link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_compact_lookup_cb
+ *
+ * Purpose: Callback routine for searching 'link' messages for a particular
+ * name & gettting object location for it
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 20 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_compact_lookup_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */
+ H5G_iter_lkp_t *udata = (H5G_iter_lkp_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* Check for name to get information */
+ if(HDstrcmp(lnk->name, udata->name) == 0) {
+ if(udata->lnk) {
+ /* Copy link information */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, lnk, udata->lnk))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+ } /* end if */
+
+ /* Indicate that the correct link was found */
+ udata->found = TRUE;
+
+ /* Stop iteration now */
+ HGOTO_DONE(H5_ITER_STOP)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_compact_lookup_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_lookup
+ *
+ * Purpose: Look up an object relative to a group, using link messages.
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 20 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G__compact_lookup(const H5O_loc_t *oloc, const char *name, H5O_link_t *lnk,
+ hid_t dxpl_id)
+{
+ H5G_iter_lkp_t udata; /* User data for iteration callback */
+ H5O_mesg_operator_t op; /* Message operator */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(lnk && oloc->file);
+ HDassert(name && *name);
+
+ /* Set up user data for iteration */
+ udata.name = name;
+ udata.lnk = lnk;
+ udata.found = FALSE;
+
+ /* Iterate through the link messages, adding them to the table */
+ op.op_type = H5O_MESG_OP_APP;
+ op.u.app_op = H5G_compact_lookup_cb;
+ if(H5O_msg_iterate(oloc, H5O_LINK_ID, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over link messages")
+
+ /* Determine if we found the link we were looking for */
+ ret_value = (htri_t)udata.found;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_lookup_by_idx
+ *
+ * Purpose: Look up an object in a group using link messages,
+ * according to the order of an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__compact_lookup_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, H5O_link_t *lnk)
+{
+ H5G_link_table_t ltable = {0, NULL};/* Link table */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(oloc && oloc->file);
+ HDassert(linfo);
+ HDassert(lnk);
+
+ /* Build table of all link messages, sorted according to desired order */
+ if(H5G_compact_build_table(oloc, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table")
+
+ /* Check for going out of bounds */
+ if(n >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index out of bound")
+
+ /* Copy link information */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, &ltable.lnks[n], lnk))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_lookup_by_idx() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__compact_get_type_by_idx
+ *
+ * Purpose: Returns the type of objects in the group by giving index.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5G__compact_get_type_by_idx(H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ hsize_t idx)
+{
+ H5G_link_table_t ltable = {0, NULL}; /* Link table */
+ H5G_obj_t ret_value = H5G_UNKNOWN; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Build table of all link messages */
+ if(H5G_compact_build_table(oloc, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_INC, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5G_UNKNOWN, "can't create link message table")
+
+ /* Check for going out of bounds */
+ if(idx >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, H5G_UNKNOWN, "index out of bound")
+
+ /* Determine type of object */
+ if(ltable.lnks[idx].type == H5L_TYPE_SOFT)
+ ret_value = H5G_LINK;
+ else if(ltable.lnks[idx].type >= H5L_TYPE_UD_MIN)
+ ret_value = H5G_UDLINK;
+ else if(ltable.lnks[idx].type == H5L_TYPE_HARD){
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+ H5O_type_t obj_type; /* Type of object at location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = oloc->file;
+ tmp_oloc.addr = ltable.lnks[idx].u.hard.addr;
+
+ /* Get the type of the object */
+ if(H5O_obj_type(&tmp_oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5G_UNKNOWN, "can't get object type")
+
+ /* Map to group object type */
+ if(H5G_UNKNOWN == (ret_value = H5G_map_obj_type(obj_type)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "can't determine object type")
+ } else {
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "unknown link type")
+ } /* end else */
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, H5G_UNKNOWN, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__compact_get_type_by_idx() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Gdense.c b/src/H5Gdense.c
new file mode 100644
index 0000000..4ae6800
--- /dev/null
+++ b/src/H5Gdense.c
@@ -0,0 +1,1890 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gdense.c
+ * Sep 9 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Routines for operating on "dense" link storage for a
+ * group in a file.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Fractal heap creation parameters for "dense" link storage */
+#define H5G_FHEAP_MAN_WIDTH 4
+#define H5G_FHEAP_MAN_START_BLOCK_SIZE 512
+#define H5G_FHEAP_MAN_MAX_DIRECT_SIZE (64 * 1024)
+#define H5G_FHEAP_MAN_MAX_INDEX 32
+#define H5G_FHEAP_MAN_START_ROOT_ROWS 1
+#define H5G_FHEAP_CHECKSUM_DBLOCKS TRUE
+#define H5G_FHEAP_MAX_MAN_SIZE (4 * 1024)
+
+/* v2 B-tree creation macros for 'name' field index */
+#define H5G_NAME_BT2_NODE_SIZE 512
+#define H5G_NAME_BT2_MERGE_PERC 40
+#define H5G_NAME_BT2_SPLIT_PERC 100
+
+/* v2 B-tree creation macros for 'corder' field index */
+#define H5G_CORDER_BT2_NODE_SIZE 512
+#define H5G_CORDER_BT2_MERGE_PERC 40
+#define H5G_CORDER_BT2_SPLIT_PERC 100
+
+/* Size of stack buffer for serialized link */
+#define H5G_LINK_BUF_SIZE 128
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Data exchange structure to use when building table of links in group */
+typedef struct {
+ H5G_link_table_t *ltable; /* Pointer to link table to build */
+ size_t curr_lnk; /* Current link to operate on */
+} H5G_dense_bt_ud_t;
+
+/*
+ * Data exchange structure to pass through the v2 B-tree layer for the
+ * H5B2_iterate function when iterating over densely stored links.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ hsize_t count; /* # of links examined */
+
+ /* downward (from application) */
+ hsize_t skip; /* Number of links to skip */
+ H5G_lib_iterate_t op; /* Callback for each link */
+ void *op_data; /* Callback data for each link */
+
+ /* upward */
+ int op_ret; /* Return value from callback */
+} H5G_bt2_ud_it_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when iterating over densely stored links.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+
+ /* upward */
+ H5O_link_t *lnk; /* Copy of link */
+} H5G_fh_ud_it_t;
+
+/*
+ * Data exchange structure for dense link storage. This structure is
+ * passed through the v2 B-tree layer when removing links.
+ */
+typedef struct {
+ /* downward */
+ H5G_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */
+ hbool_t rem_from_fheap; /* Whether to remove the link from the fractal heap */
+ haddr_t corder_bt2_addr; /* Address of v2 B-tree indexing creation order */
+ H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
+ hbool_t replace_names; /* Whether to replace the names of open objects */
+} H5G_bt2_ud_rm_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when removing a link from densely stored links.
+ */
+typedef struct {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ haddr_t corder_bt2_addr; /* Address of v2 B-tree indexing creation order */
+ H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
+ hbool_t replace_names; /* Whether to replace the names of open objects */
+} H5G_fh_ud_rm_t;
+
+/*
+ * Data exchange structure for dense link storage. This structure is
+ * passed through the v2 B-tree layer when removing links by index.
+ */
+typedef struct {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ H5_index_t idx_type; /* Primary index for removing link */
+ haddr_t other_bt2_addr; /* Address of "other" v2 B-tree indexing link */
+ H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
+} H5G_bt2_ud_rmbi_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when removing a link from densely stored links by index.
+ */
+typedef struct {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+
+ /* upward */
+ H5O_link_t *lnk; /* Pointer to link to remove */
+} H5G_fh_ud_rmbi_t;
+
+/*
+ * Data exchange structure to pass through the v2 B-tree layer for the
+ * H5B2_index function when retrieving the name of a link by index.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+
+ /* downward (from application) */
+ char *name; /* Name buffer to fill */
+ size_t name_size; /* Size of name buffer to fill */
+
+ /* upward */
+ ssize_t name_len; /* Full length of name */
+} H5G_bt2_ud_gnbi_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when retrieving the name of a link by index.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+
+ /* downward (from application) */
+ char *name; /* Name buffer to fill */
+ size_t name_size; /* Size of name buffer to fill */
+
+ /* upward */
+ ssize_t name_len; /* Full length of name */
+} H5G_fh_ud_gnbi_t;
+
+/*
+ * Data exchange structure to pass through the v2 B-tree layer for the
+ * H5B2_index function when retrieving a link by index.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+
+ /* upward */
+ H5O_link_t *lnk; /* Pointer to link */
+} H5G_bt2_ud_lbi_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when retrieving a link by index.
+ */
+typedef struct {
+ /* downward (internal) */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+
+ /* upward */
+ H5O_link_t *lnk; /* Pointer to link */
+} H5G_fh_ud_lbi_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_create
+ *
+ * Purpose: Creates dense link storage structures for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_create(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo,
+ const H5O_pline_t *pline)
+{
+ H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for names */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order */
+ size_t fheap_id_len; /* Fractal heap ID length */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* Set fractal heap creation parameters */
+/* XXX: Give some control of these to applications? */
+ HDmemset(&fheap_cparam, 0, sizeof(fheap_cparam));
+ fheap_cparam.managed.width = H5G_FHEAP_MAN_WIDTH;
+ fheap_cparam.managed.start_block_size = H5G_FHEAP_MAN_START_BLOCK_SIZE;
+ fheap_cparam.managed.max_direct_size = H5G_FHEAP_MAN_MAX_DIRECT_SIZE;
+ fheap_cparam.managed.max_index = H5G_FHEAP_MAN_MAX_INDEX;
+ fheap_cparam.managed.start_root_rows = H5G_FHEAP_MAN_START_ROOT_ROWS;
+ fheap_cparam.checksum_dblocks = H5G_FHEAP_CHECKSUM_DBLOCKS;
+ fheap_cparam.max_man_size = H5G_FHEAP_MAX_MAN_SIZE;
+ if(pline)
+ fheap_cparam.pline = *pline;
+
+ /* Create fractal heap for storing links */
+ if(NULL == (fheap = H5HF_create(f, dxpl_id, &fheap_cparam)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create fractal heap")
+
+ /* Retrieve the heap's address in the file */
+ if(H5HF_get_heap_addr(fheap, &(linfo->fheap_addr)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get fractal heap address")
+#ifdef QAK
+HDfprintf(stderr, "%s: linfo->fheap_addr = %a\n", FUNC, linfo->fheap_addr);
+#endif /* QAK */
+
+ /* Retrieve the heap's ID length in the file */
+ if(H5HF_get_id_len(fheap, &fheap_id_len) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length")
+ HDassert(fheap_id_len == H5G_DENSE_FHEAP_ID_LEN);
+#ifdef QAK
+HDfprintf(stderr, "%s: fheap_id_len = %Zu\n", FUNC, fheap_id_len);
+#endif /* QAK */
+
+ /* Create the name index v2 B-tree */
+ HDmemset(&bt2_cparam, 0, sizeof(bt2_cparam));
+ bt2_cparam.cls = H5G_BT2_NAME;
+ bt2_cparam.node_size = (size_t)H5G_NAME_BT2_NODE_SIZE;
+ H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t);
+ bt2_cparam.rrec_size = 4 + /* Name's hash value */
+ (uint32_t)fheap_id_len; /* Fractal heap ID */
+ bt2_cparam.split_percent = H5G_NAME_BT2_SPLIT_PERC;
+ bt2_cparam.merge_percent = H5G_NAME_BT2_MERGE_PERC;
+ if(NULL == (bt2_name = H5B2_create(f, dxpl_id, &bt2_cparam, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for name index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2_name, &(linfo->name_bt2_addr)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for name index")
+#ifdef QAK
+HDfprintf(stderr, "%s: linfo->name_bt2_addr = %a\n", FUNC, linfo->name_bt2_addr);
+#endif /* QAK */
+
+ /* Check if we should create a creation order index v2 B-tree */
+ if(linfo->index_corder) {
+ /* Create the creation order index v2 B-tree */
+ HDmemset(&bt2_cparam, 0, sizeof(bt2_cparam));
+ bt2_cparam.cls = H5G_BT2_CORDER;
+ bt2_cparam.node_size = (size_t)H5G_CORDER_BT2_NODE_SIZE;
+ H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t);
+ bt2_cparam.rrec_size = 8 + /* Creation order value */
+ (uint32_t)fheap_id_len; /* Fractal heap ID */
+ bt2_cparam.split_percent = H5G_CORDER_BT2_SPLIT_PERC;
+ bt2_cparam.merge_percent = H5G_CORDER_BT2_MERGE_PERC;
+ if(NULL == (bt2_corder = H5B2_create(f, dxpl_id, &bt2_cparam, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for creation order index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2_corder, &(linfo->corder_bt2_addr)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for creation order index")
+#ifdef QAK
+HDfprintf(stderr, "%s: linfo->corder_bt2_addr = %a\n", FUNC, linfo->corder_bt2_addr);
+#endif /* QAK */
+ } /* end if */
+
+done:
+ /* Close the open objects */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_insert
+ *
+ * Purpose: Insert a link into the dense link storage structures for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_insert(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ const H5O_link_t *lnk)
+{
+ H5G_bt2_ud_ins_t udata; /* User data for v2 B-tree insertion */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ size_t link_size; /* Size of serialized link in the heap */
+ H5WB_t *wb = NULL; /* Wrapped buffer for link data */
+ uint8_t link_buf[H5G_LINK_BUF_SIZE]; /* Buffer for serializing link */
+ void *link_ptr = NULL; /* Pointer to serialized link */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(lnk);
+#ifdef QAK
+HDfprintf(stderr, "%s: linfo->fheap_addr = %a\n", FUNC, linfo->fheap_addr);
+HDfprintf(stderr, "%s: linfo->name_bt2_addr = %a\n", FUNC, linfo->name_bt2_addr);
+#endif /* QAK */
+
+ /* Find out the size of buffer needed for serialized link */
+ if((link_size = H5O_msg_raw_size(f, H5O_LINK_ID, FALSE, lnk)) == 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size")
+#ifdef QAK
+HDfprintf(stderr, "%s: HDstrlen(lnk->name) = %Zu, link_size = %Zu\n", FUNC, HDstrlen(lnk->name), link_size);
+#endif /* QAK */
+
+ /* Wrap the local buffer for serialized link */
+ if(NULL == (wb = H5WB_wrap(link_buf, sizeof(link_buf))))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for link */
+ if(NULL == (link_ptr = H5WB_actual(wb, link_size)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Create serialized form of link */
+ if(H5O_msg_encode(f, H5O_LINK_ID, FALSE, (unsigned char *)link_ptr, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode link")
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Insert the serialized link into the fractal heap */
+ if(H5HF_insert(fheap, dxpl_id, link_size, link_ptr, udata.id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into fractal heap")
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, linfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Create the callback information for v2 B-tree record insertion */
+ udata.common.f = f;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.fheap = fheap;
+ udata.common.name = lnk->name;
+ udata.common.name_hash = H5_checksum_lookup3(lnk->name, HDstrlen(lnk->name), 0);
+ udata.common.corder = lnk->corder;
+ udata.common.found_op = NULL;
+ udata.common.found_op_data = NULL;
+ /* udata.id already set in H5HF_insert() call */
+
+ /* Insert link into 'name' tracking v2 B-tree */
+ if(H5B2_insert(bt2_name, dxpl_id, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree")
+
+ /* Check if we should create a creation order index v2 B-tree record */
+ if(linfo->index_corder) {
+ /* Open the creation order index v2 B-tree */
+ HDassert(H5F_addr_defined(linfo->corder_bt2_addr));
+ if(NULL == (bt2_corder = H5B2_open(f, dxpl_id, linfo->corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Insert the record into the creation order index v2 B-tree */
+ if(H5B2_insert(bt2_corder, dxpl_id, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_lookup_cb
+ *
+ * Purpose: Callback when a link is located in an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_lookup_cb(const void *_lnk, void *_user_lnk)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_lnk; /* Record from B-tree */
+ H5O_link_t *user_lnk = (H5O_link_t *)_user_lnk; /* User data from v2 B-tree link lookup */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(lnk);
+ HDassert(user_lnk);
+
+ /* Copy link information */
+ if(H5O_msg_copy(H5O_LINK_ID, lnk, user_lnk) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_lookup_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_lookup
+ *
+ * Purpose: Look up a link within a group that uses dense link storage
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G__dense_lookup(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ const char *name, H5O_link_t *lnk)
+{
+ H5G_bt2_ud_common_t udata; /* User data for v2 B-tree link lookup */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(name && *name);
+ HDassert(lnk);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, linfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Construct the user data for v2 B-tree callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.name = name;
+ udata.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0);
+ udata.found_op = H5G_dense_lookup_cb; /* v2 B-tree comparison callback */
+ udata.found_op_data = lnk;
+
+ /* Find & copy the named link in the 'name' index */
+ if((ret_value = H5B2_find(bt2_name, dxpl_id, &udata, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in name index")
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_lookup_by_idx_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator, to make copy of link when
+ * when lookup up a link by index
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_lookup_by_idx_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_lbi_t *udata = (H5G_fh_ud_lbi_t *)_udata; /* User data for fractal heap 'op' callback */
+ H5O_link_t *tmp_lnk = NULL; /* Temporary pointer to link */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information & keep a copy */
+ if(NULL == (tmp_lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link")
+
+ /* Copy link information */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, tmp_lnk, udata->lnk))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+
+done:
+ /* Release the space allocated for the link */
+ if(tmp_lnk)
+ H5O_msg_free(H5O_LINK_ID, tmp_lnk);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_lookup_by_idx_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_lookup_by_idx_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense link storage lookup by index
+ *
+ * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_lookup_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
+ H5G_bt2_ud_lbi_t *bt2_udata = (H5G_bt2_ud_lbi_t *)_bt2_udata; /* User data for callback */
+ H5G_fh_ud_lbi_t fh_udata; /* User data for fractal heap 'op' callback */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.lnk = bt2_udata->lnk;
+
+ /* Call fractal heap 'op' routine, to copy the link information */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, record->id,
+ H5G_dense_lookup_by_idx_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "link found callback failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_lookup_by_idx_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_lookup_by_idx
+ *
+ * Purpose: Look up a link within a group that uses dense link storage,
+ * according to the order of an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_lookup_by_idx(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, H5O_link_t *lnk)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_link_table_t ltable = {0, NULL}; /* Table of links */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(lnk);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Since names are hashed, getting them in strictly increasing or
+ * decreasing order requires building a table and sorting it.
+ * If the order is native, use the B-tree for names.
+ */
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links and the order is native, use the B-tree for names.
+ * Otherwise, build a table.
+ */
+ bt2_addr = linfo->corder_bt2_addr;
+ } /* end else */
+
+ /* If the order is native and there's no B-tree for indexing the links,
+ * use the B-tree for names instead of building a table to speed up the
+ * process.
+ */
+ if(order == H5_ITER_NATIVE && !H5F_addr_defined(bt2_addr)) {
+ bt2_addr = linfo->name_bt2_addr;
+ HDassert(H5F_addr_defined(bt2_addr));
+ } /* end if */
+
+ /* If there is an index defined for the field, use it */
+ if(H5F_addr_defined(bt2_addr)) {
+ H5G_bt2_ud_lbi_t udata; /* User data for v2 B-tree link lookup */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Construct the user data for v2 B-tree callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.lnk = lnk;
+
+ /* Find & copy the link in the appropriate index */
+ if(H5B2_index(bt2, dxpl_id, order, n, H5G_dense_lookup_by_idx_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in index")
+ } /* end if */
+ else { /* Otherwise, we need to build a table of the links and sort it */
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(f, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links")
+
+ /* Check for going out of bounds */
+ if(n >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Copy link information */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, &ltable.lnks[n], lnk))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_lookup_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_build_table_cb
+ *
+ * Purpose: Callback routine for building table of links from dense
+ * link storage.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sept 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_build_table_cb(const H5O_link_t *lnk, void *_udata)
+{
+ H5G_dense_bt_ud_t *udata = (H5G_dense_bt_ud_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+ HDassert(udata->curr_lnk < udata->ltable->nlinks);
+
+ /* Copy link information */
+ if(H5O_msg_copy(H5O_LINK_ID, lnk, &(udata->ltable->lnks[udata->curr_lnk])) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message")
+
+ /* Increment number of links stored */
+ udata->curr_lnk++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_build_table_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_build_table
+ *
+ * Purpose: Builds a table containing a sorted list of links for a group
+ *
+ * Note: Used for building table of links in non-native iteration order
+ * for an index
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 25, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_build_table(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, H5G_link_table_t *ltable)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(ltable);
+
+ /* Set size of table */
+ H5_CHECK_OVERFLOW(linfo->nlinks, /* From: */ hsize_t, /* To: */ size_t);
+ ltable->nlinks = (size_t)linfo->nlinks;
+
+ /* Allocate space for the table entries */
+ if(ltable->nlinks > 0) {
+ H5G_dense_bt_ud_t udata; /* User data for iteration callback */
+
+ /* Allocate the table to store the links */
+ if((ltable->lnks = (H5O_link_t *)H5MM_malloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set up user data for iteration */
+ udata.ltable = ltable;
+ udata.curr_lnk = 0;
+
+ /* Iterate over the links in the group, building a table of the link messages */
+ if(H5G__dense_iterate(f, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, H5G_dense_build_table_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
+
+ /* Sort link table in correct iteration order */
+ if(H5G__link_sort_table(ltable, idx_type, order) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages")
+ } /* end if */
+ else
+ ltable->lnks = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_build_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_iterate_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator, to make user's callback
+ * when iterating over links
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_iterate_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_it_t *udata = (H5G_fh_ud_it_t *)_udata; /* User data for fractal heap 'op' callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information & keep a copy */
+ /* (we make a copy instead of calling the user/library callback directly in
+ * this routine because this fractal heap 'op' callback routine is called
+ * with the direct block protected and if the callback routine invokes an
+ * HDF5 routine, it could attempt to re-protect that direct block for the
+ * heap, causing the HDF5 routine called to fail - QAK)
+ */
+ if(NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_iterate_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_iterate_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense link storage iterator
+ *
+ * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_iterate_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
+ H5G_bt2_ud_it_t *bt2_udata = (H5G_bt2_ud_it_t *)_bt2_udata; /* User data for callback */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check for skipping links */
+ if(bt2_udata->skip > 0)
+ --bt2_udata->skip;
+ else {
+ H5G_fh_ud_it_t fh_udata; /* User data for fractal heap 'op' callback */
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+
+ /* Call fractal heap 'op' routine, to copy the link information */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, record->id,
+ H5G_dense_iterate_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed")
+
+ /* Make the callback */
+ ret_value = (bt2_udata->op)(fh_udata.lnk, bt2_udata->op_data);
+
+ /* Release the space allocated for the link */
+ H5O_msg_free(H5O_LINK_ID, fh_udata.lnk);
+ } /* end else */
+
+ /* Increment the number of entries passed through */
+ /* (whether we skipped them or not) */
+ bt2_udata->count++;
+
+ /* Check for callback failure and pass along return value */
+ if(ret_value < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_iterate_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_iterate
+ *
+ * Purpose: Iterate over the objects in a group using dense link storage
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ H5G_lib_iterate_t op, void *op_data)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_link_table_t ltable = {0, NULL}; /* Table of links */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(op);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Since names are hashed, getting them in strictly increasing or
+ * decreasing order requires building a table and sorting it. If
+ * the order is native, use the B-tree for names.
+ */
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links and the order is native, use the B-tree for names.
+ * Otherwise, build a table.
+ */
+ bt2_addr = linfo->corder_bt2_addr;
+ } /* end else */
+
+ /* If the order is native and there's no B-tree for indexing the links,
+ * use the B-tree for names instead of building a table to speed up the
+ * process.
+ */
+ if(order == H5_ITER_NATIVE && !H5F_addr_defined(bt2_addr)) {
+ HDassert(H5F_addr_defined(linfo->name_bt2_addr));
+ bt2_addr = linfo->name_bt2_addr;
+ } /* end if */
+
+ /* Check on iteration order */
+ if(order == H5_ITER_NATIVE) {
+ H5G_bt2_ud_it_t udata; /* User data for iterator callback */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(bt2_addr));
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Construct the user data for v2 B-tree iterator callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.skip = skip;
+ udata.count = 0;
+ udata.op = op;
+ udata.op_data = op_data;
+
+ /* Iterate over the records in the v2 B-tree's "native" order */
+ /* (by hash of name) */
+ if((ret_value = H5B2_iterate(bt2, dxpl_id, H5G_dense_iterate_bt2_cb, &udata)) < 0)
+ HERROR(H5E_SYM, H5E_BADITER, "link iteration failed");
+
+ /* Update the last link examined, if requested */
+ if(last_lnk)
+ *last_lnk = udata.count;
+ } /* end if */
+ else {
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(f, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links")
+
+ /* Iterate over links in table */
+ if((ret_value = H5G__link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_get_name_by_idx_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator, to retrieve name according
+ * to an index
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 19 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_get_name_by_idx_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_gnbi_t *udata = (H5G_fh_ud_gnbi_t *)_udata; /* User data for fractal heap 'op' callback */
+ H5O_link_t *lnk; /* Pointer to link created from heap object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information */
+ if(NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link")
+
+ /* Get the length of the name */
+ udata->name_len = (ssize_t)HDstrlen(lnk->name);
+
+ /* Copy the name into the user's buffer, if given */
+ if(udata->name) {
+ HDstrncpy(udata->name, lnk->name, MIN((size_t)(udata->name_len + 1), udata->name_size));
+ if((size_t)udata->name_len >= udata->name_size)
+ udata->name[udata->name_size - 1] = '\0';
+ } /* end if */
+
+ /* Release the space allocated for the link */
+ H5O_msg_free(H5O_LINK_ID, lnk);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_get_name_by_idx_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_get_name_by_idx_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense link storage 'get name by idx' call
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 19 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_get_name_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
+ H5G_bt2_ud_gnbi_t *bt2_udata = (H5G_bt2_ud_gnbi_t *)_bt2_udata; /* User data for callback */
+ H5G_fh_ud_gnbi_t fh_udata; /* User data for fractal heap 'op' callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Prepare user data for callback */
+ /* down */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.name = bt2_udata->name;
+ fh_udata.name_size = bt2_udata->name_size;
+
+ /* Call fractal heap 'op' routine, to perform user callback */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, record->id,
+ H5G_dense_get_name_by_idx_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link found callback failed")
+
+ /* Set the name's full length to return */
+ bt2_udata->name_len = fh_udata.name_len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_get_name_by_idx_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_get_name_by_idx
+ *
+ * Purpose: Returns the name of objects in the group by giving index.
+ *
+ * Return: Success: Non-negative, length of name
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 19 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G__dense_get_name_by_idx(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, char *name,
+ size_t size)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_link_table_t ltable = {0, NULL}; /* Table of links */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Since names are hashed, getting them in strictly increasing or
+ * decreasing order requires building a table and sorting it. If
+ * the order is native, use the B-tree for names.
+ */
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links and the order is native, use the B-tree for names.
+ * Otherwise, build a table.
+ */
+ bt2_addr = linfo->corder_bt2_addr;
+ } /* end else */
+
+ /* If the order is native and there's no B-tree for indexing the links,
+ * use the B-tree for names instead of building a table to speed up the
+ * process.
+ */
+ if(order == H5_ITER_NATIVE && !H5F_addr_defined(bt2_addr)) {
+ bt2_addr = linfo->name_bt2_addr;
+ HDassert(H5F_addr_defined(bt2_addr));
+ } /* end if */
+
+ /* If there is an index defined for the field, use it */
+ if(H5F_addr_defined(bt2_addr)) {
+ H5G_bt2_ud_gnbi_t udata; /* User data for v2 B-tree callback */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.name = name;
+ udata.name_size = size;
+
+ /* Retrieve the name according to the v2 B-tree's index order */
+ if(H5B2_index(bt2, dxpl_id, order, n, H5G_dense_get_name_by_idx_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLIST, FAIL, "can't locate object in v2 B-tree")
+
+ /* Set return value */
+ ret_value = udata.name_len;
+ } /* end if */
+ else { /* Otherwise, we need to build a table of the links and sort it */
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(f, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links")
+
+ /* Check for going out of bounds */
+ if(n >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Get the length of the name */
+ ret_value = (ssize_t)HDstrlen(ltable.lnks[n].name);
+
+ /* Copy the name into the user's buffer, if given */
+ if(name) {
+ HDstrncpy(name, ltable.lnks[n].name, MIN((size_t)(ret_value + 1), size));
+ if((size_t)ret_value >= size)
+ name[size - 1]='\0';
+ } /* end if */
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_get_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_remove_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator when removing links
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_remove_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_rm_t *udata = (H5G_fh_ud_rm_t *)_udata; /* User data for fractal heap 'op' callback */
+ H5O_link_t *lnk = NULL; /* Pointer to link created from heap object */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information */
+ if(NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link")
+
+ /* Check for removing the link from the creation order index */
+ if(H5F_addr_defined(udata->corder_bt2_addr)) {
+ H5G_bt2_ud_common_t bt2_udata; /* Info for B-tree callbacks */
+
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(udata->f, udata->dxpl_id, udata->corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ HDassert(lnk->corder_valid);
+ bt2_udata.corder = lnk->corder;
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove(bt2, udata->dxpl_id, &bt2_udata, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from creation order index v2 B-tree")
+ } /* end if */
+
+ /* Replace open objects' names, if requested */
+ if(udata->replace_names)
+ if(H5G__link_name_replace(udata->f, udata->dxpl_id, udata->grp_full_path_r, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects")
+
+ /* Perform the deletion action on the link, if requested */
+ /* (call message "delete" callback directly: *ick* - QAK) */
+ if(H5O_link_delete(udata->f, udata->dxpl_id, NULL, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link")
+
+done:
+ /* Release resources */
+ if(bt2 && H5B2_close(bt2, udata->dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index")
+ if(lnk)
+ H5O_msg_free(H5O_LINK_ID, lnk);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_remove_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_remove_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense link storage record removal
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_remove_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
+ H5G_bt2_ud_rm_t *bt2_udata = (H5G_bt2_ud_rm_t *)_bt2_udata; /* User data for callback */
+ H5G_fh_ud_rm_t fh_udata; /* User data for fractal heap 'op' callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set up the user data for fractal heap 'op' callback */
+ fh_udata.f = bt2_udata->common.f;
+ fh_udata.dxpl_id = bt2_udata->common.dxpl_id;
+ fh_udata.corder_bt2_addr = bt2_udata->corder_bt2_addr;
+ fh_udata.grp_full_path_r = bt2_udata->grp_full_path_r;
+ fh_udata.replace_names = bt2_udata->replace_names;
+
+ /* Call fractal heap 'op' routine, to perform user callback */
+ if(H5HF_op(bt2_udata->common.fheap, bt2_udata->common.dxpl_id, record->id,
+ H5G_dense_remove_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed")
+
+ /* Remove record from fractal heap, if requested */
+ if(bt2_udata->rem_from_fheap)
+ if(H5HF_remove(bt2_udata->common.fheap, bt2_udata->common.dxpl_id, record->id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_remove_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_remove
+ *
+ * Purpose: Remove a link from the dense storage of a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_remove(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5RS_str_t *grp_full_path_r, const char *name)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(name && *name);
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, linfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata.common.f = f;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.fheap = fheap;
+ udata.common.name = name;
+ udata.common.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0);
+ udata.common.found_op = NULL;
+ udata.common.found_op_data = NULL;
+ udata.rem_from_fheap = TRUE;
+ udata.corder_bt2_addr = linfo->corder_bt2_addr;
+ udata.grp_full_path_r = grp_full_path_r;
+ udata.replace_names = TRUE;
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove(bt2, dxpl_id, &udata, H5G_dense_remove_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from name index v2 B-tree")
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_remove_by_idx_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator when removing links by index
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_remove_by_idx_fh_cb(const void *obj, size_t H5_ATTR_UNUSED obj_len, void *_udata)
+{
+ H5G_fh_ud_rmbi_t *udata = (H5G_fh_ud_rmbi_t *)_udata; /* User data for fractal heap 'op' callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode link information */
+ if(NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_LINK_ID, (const unsigned char *)obj)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, H5_ITER_ERROR, "can't decode link")
+
+ /* Can't operate on link here because the fractal heap block is locked */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_remove_by_idx_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_dense_remove_by_idx_bt2_cb
+ *
+ * Purpose: v2 B-tree callback for dense link storage record removal by index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
+{
+ H5G_bt2_ud_rmbi_t *bt2_udata = (H5G_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */
+ H5G_fh_ud_rmbi_t fh_udata; /* User data for fractal heap 'op' callback */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ const uint8_t *heap_id; /* Heap ID for link */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Determine the index being used */
+ if(bt2_udata->idx_type == H5_INDEX_NAME) {
+ const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
+
+ /* Set the heap ID to operate on */
+ heap_id = record->id;
+ } /* end if */
+ else {
+ const H5G_dense_bt2_corder_rec_t *record = (const H5G_dense_bt2_corder_rec_t *)_record;
+
+ HDassert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER);
+
+ /* Set the heap ID to operate on */
+ heap_id = record->id;
+ } /* end else */
+
+ /* Set up the user data for fractal heap 'op' callback */
+ fh_udata.f = bt2_udata->f;
+ fh_udata.dxpl_id = bt2_udata->dxpl_id;
+ fh_udata.lnk = NULL;
+
+ /* Call fractal heap 'op' routine, to perform user callback */
+ if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, heap_id,
+ H5G_dense_remove_by_idx_fh_cb, &fh_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed")
+ HDassert(fh_udata.lnk);
+
+ /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */
+ if(H5F_addr_defined(bt2_udata->other_bt2_addr)) {
+ H5G_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */
+
+ /* Determine the index being used */
+ if(bt2_udata->idx_type == H5_INDEX_NAME) {
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ other_bt2_udata.corder = fh_udata.lnk->corder;
+ } /* end if */
+ else {
+ HDassert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER);
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ other_bt2_udata.f = bt2_udata->f;
+ other_bt2_udata.dxpl_id = bt2_udata->dxpl_id;
+ other_bt2_udata.fheap = bt2_udata->fheap;
+ other_bt2_udata.name = fh_udata.lnk->name;
+ other_bt2_udata.name_hash = H5_checksum_lookup3(fh_udata.lnk->name, HDstrlen(fh_udata.lnk->name), 0);
+ other_bt2_udata.found_op = NULL;
+ other_bt2_udata.found_op_data = NULL;
+ } /* end else */
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(bt2_udata->f, bt2_udata->dxpl_id, bt2_udata->other_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for 'other' index")
+
+ /* Set the common information for the v2 B-tree remove operation */
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove(bt2, bt2_udata->dxpl_id, &other_bt2_udata, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, H5_ITER_ERROR, "unable to remove link from 'other' index v2 B-tree")
+ } /* end if */
+
+ /* Replace open objects' names */
+ if(H5G__link_name_replace(bt2_udata->f, bt2_udata->dxpl_id, bt2_udata->grp_full_path_r, fh_udata.lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects")
+
+ /* Perform the deletion action on the link */
+ /* (call link message "delete" callback directly: *ick* - QAK) */
+ if(H5O_link_delete(bt2_udata->f, bt2_udata->dxpl_id, NULL, fh_udata.lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link")
+
+ /* Release the space allocated for the link */
+ H5O_msg_free(H5O_LINK_ID, fh_udata.lnk);
+
+ /* Remove record from fractal heap */
+ if(H5HF_remove(bt2_udata->fheap, bt2_udata->dxpl_id, heap_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap")
+
+done:
+ /* Release resources */
+ if(bt2 && H5B2_close(bt2, bt2_udata->dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for 'other' index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_dense_remove_by_idx_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_remove_by_idx
+ *
+ * Purpose: Remove a link from the dense storage of a group, according to
+ * to the offset in an indexed order
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_remove_by_idx(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5RS_str_t *grp_full_path_r, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t n)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_link_table_t ltable = {0, NULL}; /* Table of links */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* Determine the address of the index to use */
+ if(idx_type == H5_INDEX_NAME) {
+ /* Since names are hashed, getting them in strictly increasing or
+ * decreasing order requires building a table and sorting it. If
+ * the order is native, use the B-tree for names.
+ */
+ bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+
+ /* This address may not be defined if creation order is tracked, but
+ * there's no index on it. If there's no v2 B-tree that indexes
+ * the links and the order is native, use the B-tree for names.
+ * Otherwise, build a table.
+ */
+ bt2_addr = linfo->corder_bt2_addr;
+ } /* end else */
+
+ /* If the order is native and there's no B-tree for indexing the links,
+ * use the B-tree for names instead of building a table to speed up the
+ * process.
+ */
+ if(order == H5_ITER_NATIVE && !H5F_addr_defined(bt2_addr)) {
+ bt2_addr = linfo->name_bt2_addr;
+ HDassert(H5F_addr_defined(bt2_addr));
+ } /* end if */
+
+ /* If there is an index defined for the field, use it */
+ if(H5F_addr_defined(bt2_addr)) {
+ H5G_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index")
+
+ /* Set up the user data for the v2 B-tree 'remove by index' callback */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.fheap = fheap;
+ udata.idx_type = idx_type;
+ udata.other_bt2_addr = idx_type == H5_INDEX_NAME ? linfo->corder_bt2_addr : linfo->name_bt2_addr;
+ udata.grp_full_path_r = grp_full_path_r;
+
+ /* Remove the record from the name index v2 B-tree */
+ if(H5B2_remove_by_idx(bt2, dxpl_id, order, n, H5G_dense_remove_by_idx_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from indexed v2 B-tree")
+ } /* end if */
+ else { /* Otherwise, we need to build a table of the links and sort it */
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(f, dxpl_id, linfo, idx_type, order, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links")
+
+ /* Check for going out of bounds */
+ if(n >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Remove the appropriate link from the dense storage */
+ if(H5G__dense_remove(f, dxpl_id, linfo, grp_full_path_r, ltable.lnks[n].name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from dense storage")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index")
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_delete
+ *
+ * Purpose: Delete the dense storage for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__dense_delete(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo, hbool_t adj_link)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* Check if we are to adjust the ref. count for all the links */
+ /* (we adjust the ref. count when deleting a group and we _don't_ adjust
+ * the ref. count when transitioning back to compact storage)
+ */
+ if(adj_link) {
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5G_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, linfo->fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up the user data for the v2 B-tree 'record remove' callback */
+ udata.common.f = f;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.fheap = fheap;
+ udata.common.name = NULL;
+ udata.common.name_hash = 0;
+ udata.common.found_op = NULL;
+ udata.common.found_op_data = NULL;
+ udata.rem_from_fheap = FALSE; /* handled in "bulk" below by deleting entire heap */
+ udata.corder_bt2_addr = linfo->corder_bt2_addr;
+ udata.grp_full_path_r = NULL;
+ udata.replace_names = FALSE;
+
+ /* Delete the name index, adjusting the ref. count on links removed */
+ if(H5B2_delete(f, dxpl_id, linfo->name_bt2_addr, NULL, H5G_dense_remove_bt2_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index")
+
+ /* Close the fractal heap */
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+ } /* end if */
+ else {
+ /* Delete the name index, without adjusting the ref. count on the links */
+ if(H5B2_delete(f, dxpl_id, linfo->name_bt2_addr, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index")
+ } /* end else */
+ linfo->name_bt2_addr = HADDR_UNDEF;
+
+ /* Check if we should delete the creation order index v2 B-tree */
+ if(linfo->index_corder) {
+ /* Delete the creation order index, without adjusting the ref. count on the links */
+ HDassert(H5F_addr_defined(linfo->corder_bt2_addr));
+ if(H5B2_delete(f, dxpl_id, linfo->corder_bt2_addr, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for creation order index")
+ linfo->corder_bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else
+ HDassert(!H5F_addr_defined(linfo->corder_bt2_addr));
+
+ /* Delete the fractal heap */
+ if(H5HF_delete(f, dxpl_id, linfo->fheap_addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
+ linfo->fheap_addr = HADDR_UNDEF;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_delete() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__dense_get_type_by_idx
+ *
+ * Purpose: Returns the type of objects in the group by giving index.
+ *
+ * Note: This routine assumes a lookup on the link name index in
+ * increasing order and isn't currently set up to be as
+ * flexible as other routines in this code module, because
+ * the H5Gget_objtype_by_idx that it's supporting is
+ * deprecated.
+ *
+ * Return: Success: Non-negative, object type
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 19 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5G__dense_get_type_by_idx(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo,
+ hsize_t idx)
+{
+ H5G_link_table_t ltable = {0, NULL}; /* Table of links */
+ H5G_obj_t ret_value = H5G_UNKNOWN; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(f, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_INC, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5G_UNKNOWN, "error building table of links")
+
+ /* Check for going out of bounds */
+ if(idx >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5G_UNKNOWN, "index out of bound")
+
+ /* Determine type of object */
+ if(ltable.lnks[idx].type == H5L_TYPE_SOFT)
+ ret_value = H5G_LINK;
+ else if(ltable.lnks[idx].type >= H5L_TYPE_UD_MIN)
+ ret_value = H5G_UDLINK;
+ else if(ltable.lnks[idx].type == H5L_TYPE_HARD) {
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+ H5O_type_t obj_type; /* Type of object at location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = f;
+ tmp_oloc.addr = ltable.lnks[idx].u.hard.addr;
+
+ /* Get the type of the object */
+ if(H5O_obj_type(&tmp_oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5G_UNKNOWN, "can't get object type")
+
+ /* Map to group object type */
+ if(H5G_UNKNOWN == (ret_value = H5G_map_obj_type(obj_type)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "can't determine object type")
+ } else {
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "unknown link type")
+ } /* end else */
+
+done:
+ /* Release link table */
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, H5G_UNKNOWN, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__dense_get_type_by_idx() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c
new file mode 100644
index 0000000..228fb9c
--- /dev/null
+++ b/src/H5Gdeprec.c
@@ -0,0 +1,1149 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gdeprec.c
+ * June 21 2006
+ * James Laird <jlaird@ncsa.uiuc.edu>
+ *
+ * Purpose: Deprecated functions from the H5G interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+/* User data for path traversal routine for getting object info */
+typedef struct {
+ H5G_stat_t *statbuf; /* Stat buffer about object */
+ hbool_t follow_link; /* Whether we are following a link or not */
+ H5F_t *loc_file; /* Pointer to the file the location is in */
+ hid_t dxpl_id; /* Dataset transfer property list */
+} H5G_trav_goi_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5G_link_hard(hid_t cur_loc_id, const char *cur_name,
+ hid_t new_loc_id, const char *new_name);
+static herr_t H5G_move(hid_t src_loc_id, const char *src_name,
+ hid_t dst_loc_id, const char *dst_name);
+static herr_t H5G_get_objinfo_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5G_get_objinfo(const H5G_loc_t *loc, const char *name,
+ hbool_t follow_link, H5G_stat_t *statbuf/*out*/, hid_t dxpl_id);
+static H5G_obj_t H5G_obj_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx,
+ hid_t dxpl_id);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_map_obj_type
+ *
+ * Purpose: Maps the object type to the older "group" object type
+ *
+ * Return: Object type (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5G_map_obj_type(H5O_type_t obj_type)
+{
+ H5G_obj_t ret_value = H5G_UNKNOWN; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Map object type to older "group" object type */
+ switch(obj_type) {
+ case H5O_TYPE_GROUP:
+ ret_value = H5G_GROUP;
+ break;
+
+ case H5O_TYPE_DATASET:
+ ret_value = H5G_DATASET;
+ break;
+
+ case H5O_TYPE_NAMED_DATATYPE:
+ ret_value = H5G_TYPE;
+ break;
+
+ case H5O_TYPE_UNKNOWN:
+ case H5O_TYPE_NTYPES:
+ default:
+ ret_value = H5G_UNKNOWN;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_map_obj_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gcreate1
+ *
+ * Purpose: Creates a new group relative to LOC_ID and gives it the
+ * specified NAME. The group is opened for write access
+ * and it's object ID is returned.
+ *
+ * The optional SIZE_HINT specifies how much file space to
+ * reserve to store the names that will appear in this
+ * group. If a non-positive value is supplied for the SIZE_HINT
+ * then a default size is chosen.
+ *
+ * Note: Deprecated in favor of H5Gcreate2
+ *
+ * Return: Success: The object ID of a new, empty group open for
+ * writing. Call H5Gclose() when finished with
+ * the group.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 24, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gcreate1(hid_t loc_id, const char *name, size_t size_hint)
+{
+ H5G_loc_t loc; /* Location to create group */
+ H5G_t *grp = NULL; /* New group created */
+ hid_t tmp_gcpl = (-1); /* Temporary group creation property list */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*sz", loc_id, name, size_hint);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name given")
+
+ /* Check if we need to create a non-standard GCPL */
+ if(size_hint > 0) {
+ H5P_genplist_t *gc_plist; /* Property list created */
+ H5O_ginfo_t ginfo; /* Group info property */
+
+ /* Get the default property list */
+ if(NULL == (gc_plist = (H5P_genplist_t *)H5I_object(H5P_GROUP_CREATE_DEFAULT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Make a copy of the default property list */
+ if((tmp_gcpl = H5P_copy_plist(gc_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to copy the creation property list")
+
+ /* Get pointer to the copied property list */
+ if(NULL == (gc_plist = (H5P_genplist_t *)H5I_object(tmp_gcpl)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the group info property */
+ if(H5P_get(gc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Set the non-default local heap size hint */
+ H5_CHECKED_ASSIGN(ginfo.lheap_size_hint, uint32_t, size_hint, size_t);
+ if(H5P_set(gc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set group info")
+ } /* end if */
+ else
+ tmp_gcpl = H5P_GROUP_CREATE_DEFAULT;
+
+ /* Create the new group & get its ID */
+ if(NULL == (grp = H5G__create_named(&loc, name, H5P_LINK_CREATE_DEFAULT,
+ tmp_gcpl, H5P_GROUP_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group")
+ if((ret_value = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ if(tmp_gcpl > 0 && tmp_gcpl != H5P_GROUP_CREATE_DEFAULT)
+ if(H5I_dec_ref(tmp_gcpl) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release property list")
+
+ if(ret_value < 0)
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gcreate1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gopen1
+ *
+ * Purpose: Opens an existing group for modification. When finished,
+ * call H5Gclose() to close it and release resources.
+ *
+ * Note: Deprecated in favor of H5Gopen2
+ *
+ * Return: Success: Object ID of the group.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 31, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Gopen1(hid_t loc_id, const char *name)
+{
+ H5G_t *grp = NULL; /* Group opened */
+ H5G_loc_t loc; /* Location of parent for group */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "i*s", loc_id, name);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Open the group */
+ if((grp = H5G__open_name(&loc, name, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+
+ /* Register an atom for the group */
+ if((ret_value = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ if(ret_value < 0) {
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gopen1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Glink
+ *
+ * Purpose: Creates a link between two existing objects. The new
+ * APIs to do this are H5Lcreate_hard and H5Lcreate_soft.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, const char *new_name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iLl*s*s", cur_loc_id, type, cur_name, new_name);
+
+ /* Check arguments */
+ if(!cur_name || !*cur_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!new_name || !*new_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified")
+
+ if(type == H5L_TYPE_HARD) {
+ if((ret_value = H5G_link_hard(cur_loc_id, cur_name, H5L_SAME_LOC, new_name)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "couldn't create link")
+ } /* end if */
+ else if(type == H5L_TYPE_SOFT) {
+ H5G_loc_t cur_loc; /* Group location for new link */
+
+ /* Finish checking arguments */
+ if(H5G_loc(cur_loc_id, &cur_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Create the link */
+ if(H5L_create_soft(cur_name, &cur_loc, new_name, H5P_DEFAULT, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+ } /* end else if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not a valid link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Glink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Glink2
+ *
+ * Purpose: Creates a link between two existing objects. The new
+ * APIs to do this are H5Lcreate_hard and H5Lcreate_soft.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type,
+ hid_t new_loc_id, const char *new_name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*sLli*s", cur_loc_id, cur_name, type, new_loc_id, new_name);
+
+ /* Check arguments */
+ if(!cur_name || !*cur_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!new_name || !*new_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified")
+
+ if(type == H5L_TYPE_HARD) {
+ if((ret_value = H5G_link_hard(cur_loc_id, cur_name, new_loc_id, new_name)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "couldn't create link")
+ } /* end if */
+ else if(type == H5L_TYPE_SOFT) {
+ H5G_loc_t new_loc; /* Group location for new link */
+
+ /* Soft links only need one location, the new_loc_id, but it's possible that
+ * new_loc_id is H5L_SAME_LOC */
+ if(new_loc_id == H5L_SAME_LOC)
+ new_loc_id = cur_loc_id;
+
+ /* Finish checking arguments */
+ if(H5G_loc(new_loc_id, &new_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Create the link */
+ if(H5L_create_soft(cur_name, &new_loc, new_name, H5P_DEFAULT, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+ } /* end else if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Glink2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_hard
+ *
+ * Purpose: Creates a hard link from NEW_NAME to CUR_NAME.
+ *
+ * CUR_NAME must name an existing object. CUR_NAME and
+ * NEW_NAME are interpreted relative to CUR_LOC_ID and
+ * NEW_LOC_ID, which are either file IDs or group IDs.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_link_hard(hid_t cur_loc_id, const char *cur_name, hid_t new_loc_id,
+ const char *new_name)
+{
+ H5G_loc_t cur_loc, *cur_loc_p; /* Information about current link's group */
+ H5G_loc_t new_loc, *new_loc_p; /* Information about new link's group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Finish checking arguments */
+ if(cur_loc_id == H5L_SAME_LOC && new_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not be both H5L_SAME_LOC")
+ if(cur_loc_id != H5L_SAME_LOC && H5G_loc(cur_loc_id, &cur_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(new_loc_id != H5L_SAME_LOC && H5G_loc(new_loc_id, &new_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Set up current & new location pointers */
+ cur_loc_p = &cur_loc;
+ new_loc_p = &new_loc;
+ if(cur_loc_id == H5L_SAME_LOC)
+ cur_loc_p = new_loc_p;
+ else if(new_loc_id == H5L_SAME_LOC)
+ new_loc_p = cur_loc_p;
+ else if(cur_loc_p->oloc->file != new_loc_p->oloc->file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should be in the same file.")
+
+ /* Create the link */
+ if(H5L_create_hard(cur_loc_p, cur_name, new_loc_p, new_name,
+ H5P_DEFAULT, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_link_hard() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gmove
+ *
+ * Purpose: Moves and renames a link. The new API to do this is H5Lmove.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gmove(hid_t src_loc_id, const char *src_name, const char *dst_name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*s", src_loc_id, src_name, dst_name);
+
+ /* Call common routine to move the link */
+ if(H5G_move(src_loc_id, src_name, H5L_SAME_LOC, dst_name) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "couldn't move link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gmove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gmove2
+ *
+ * Purpose: Moves and renames a link. The new API to do this is H5Lmove.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*si*s", src_loc_id, src_name, dst_loc_id, dst_name);
+
+ /* Call common routine to move the link */
+ if(H5G_move(src_loc_id, src_name, dst_loc_id, dst_name) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "couldn't move link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gmove2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_move
+ *
+ * Purpose: Renames an object within an HDF5 file and moves it to a new
+ * group. The original name SRC is unlinked from the group graph
+ * and then inserted with the new name DST (which can specify a
+ * new path for the object) as an atomic operation. The names
+ * are interpreted relative to SRC_LOC_ID and
+ * DST_LOC_ID, which are either file IDs or group ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_move(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name)
+{
+ H5G_loc_t src_loc, *src_loc_p; /* Group info for source location */
+ H5G_loc_t dst_loc, *dst_loc_p; /* Group info for destination location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ if(src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not both be H5L_SAME_LOC")
+ if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(dst_loc_id != H5L_SAME_LOC && H5G_loc(dst_loc_id, &dst_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!src_name || !*src_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!dst_name || !*dst_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified")
+
+ /* Set up src & dst location pointers */
+ src_loc_p = &src_loc;
+ dst_loc_p = &dst_loc;
+ if(src_loc_id == H5L_SAME_LOC)
+ src_loc_p = dst_loc_p;
+ else if(dst_loc_id == H5L_SAME_LOC)
+ dst_loc_p = src_loc_p;
+
+ /* Move the link */
+ if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, FALSE, H5P_DEFAULT,
+ H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTMOVE, FAIL, "unable to move link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_move() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gunlink
+ *
+ * Purpose: Removes a link. The new API is H5Ldelete/H5Ldelete_by_idx.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gunlink(hid_t loc_id, const char *name)
+{
+ H5G_loc_t loc; /* Group's location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", loc_id, name);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Call H5L routine... */
+ if(H5L_delete(&loc, name, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL, "couldn't delete link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gunlink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_linkval
+ *
+ * Purpose: Retrieve's a soft link's data. The new API is
+ * H5Lget_val/H5Lget_val_by_idx.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_linkval(hid_t loc_id, const char *name, size_t size, char *buf/*out*/)
+{
+ H5G_loc_t loc; /* Group's location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*szx", loc_id, name, size, buf);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ /* Call the new link routine which provides this capability */
+ if(H5L_get_val(&loc, name, buf, size, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "couldn't get link info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_linkval() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gset_comment
+ *
+ * Purpose: Gives the specified object a comment. The COMMENT string
+ * should be a null terminated string. An object can have only
+ * one comment at a time. Passing NULL for the COMMENT argument
+ * will remove the comment property from the object.
+ *
+ * Note: Deprecated in favor of H5Oset_comment/H5Oset_comment_by_name
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 20, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gset_comment(hid_t loc_id, const char *name, const char *comment)
+{
+ H5G_loc_t loc;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*s", loc_id, name, comment);
+
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ if(H5G_loc_set_comment(&loc, name, comment, H5P_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to set comment value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gset_comment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_comment
+ *
+ * Purpose: Return at most BUFSIZE characters of the comment for the
+ * specified object. If BUFSIZE is large enough to hold the
+ * entire comment then the comment string will be null
+ * terminated, otherwise it will not. If the object does not
+ * have a comment value then no bytes are copied to the BUF
+ * buffer.
+ *
+ * Note: Deprecated in favor of H5Oget_comment/H5Oget_comment_by_name
+ *
+ * Return: Success: Number of characters in the comment counting
+ * the null terminator. The value returned may
+ * be larger than the BUFSIZE argument.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 20, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Gget_comment(hid_t loc_id, const char *name, size_t bufsize, char *buf)
+{
+ H5G_loc_t loc;
+ int ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Is", "i*sz*s", loc_id, name, bufsize, buf);
+
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(bufsize > 0 && !buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no buffer specified")
+
+ if((ret_value = (int)H5G_loc_get_comment(&loc, name, buf, bufsize, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to get comment value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_comment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Giterate
+ *
+ * Purpose: Iterates over the entries of a group. The LOC_ID and NAME
+ * identify the group over which to iterate and IDX indicates
+ * where to start iterating (zero means at the beginning). The
+ * OPERATOR is called for each member and the iteration
+ * continues until the operator returns non-zero or all members
+ * are processed. The operator is passed a group ID for the
+ * group being iterated, a member name, and OP_DATA for each
+ * member.
+ *
+ * Note: Deprecated in favor of H5Literate
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 23, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Giterate(hid_t loc_id, const char *name, int *idx_p, H5G_iterate_t op,
+ void *op_data)
+{
+ H5G_link_iterate_t lnk_op; /* Link operator */
+ hsize_t last_obj; /* Index of last object looked at */
+ hsize_t idx; /* Internal location to hold index */
+ herr_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*s*Isx*x", loc_id, name, idx_p, op, op_data);
+
+ /* Check args */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_p && *idx_p < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified")
+
+ /* Set number of objects looked at to zero */
+ last_obj = 0;
+ idx = (hsize_t)(idx_p == NULL ? 0 : *idx_p);
+
+ /* Build link operator info */
+ lnk_op.op_type = H5G_LINK_OP_OLD;
+ lnk_op.op_func.op_old = op;
+
+ /* Call private function. */
+ if((ret_value = H5G_iterate(loc_id, name, H5_INDEX_NAME, H5_ITER_INC, idx, &last_obj, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group iteration failed")
+
+ /* Set the index we stopped at */
+ if(idx_p)
+ *idx_p = (int)last_obj;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Giterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_num_objs
+ *
+ * Purpose: Returns the number of objects in the group. It iterates
+ * all B-tree leaves and sum up total number of group members.
+ *
+ * Note: Deprecated in favor of H5Gget_info
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_num_objs(hid_t loc_id, hsize_t *num_objs)
+{
+ H5G_loc_t loc; /* Location of object */
+ H5G_info_t grp_info; /* Group information */
+ H5O_type_t obj_type; /* Type of object at location */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", loc_id, num_objs);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location ID")
+ if(H5O_obj_type(loc.oloc, &obj_type, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object type")
+ if(obj_type != H5O_TYPE_GROUP)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+ if(!num_objs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad pointer to # of objects")
+
+ /* Retrieve information about the group */
+ if(H5G__obj_info(loc.oloc, &grp_info, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "can't determine")
+
+ /* Set the number of objects [sic: links] in the group */
+ *num_objs = grp_info.nlinks;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_num_objs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_objinfo
+ *
+ * Purpose: Returns information about an object. If FOLLOW_LINK is
+ * non-zero then all symbolic links are followed; otherwise all
+ * links except the last component of the name are followed.
+ *
+ * Note: Deprecated in favor of H5Lget_info/H5Oget_info
+ *
+ * Return: Non-negative on success, with the fields of STATBUF (if
+ * non-null) initialized. Negative on failure.
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Gget_objinfo(hid_t loc_id, const char *name, hbool_t follow_link,
+ H5G_stat_t *statbuf/*out*/)
+{
+ H5G_loc_t loc;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*sbx", loc_id, name, follow_link, statbuf);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ /* Get info */
+ if(H5G_get_objinfo(&loc, name, follow_link, statbuf, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "cannot stat object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_objinfo() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_objinfo_cb
+ *
+ * Purpose: Callback for retrieving info about an object. This routine
+ * gets the info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_get_objinfo_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_trav_goi_t *udata = (H5G_trav_goi_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(lnk == NULL && obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "'%s' doesn't exist", name)
+
+ /* Only modify user's buffer if it's available */
+ if(udata->statbuf) {
+ H5G_stat_t *statbuf = udata->statbuf; /* Convenience pointer for statbuf */
+
+ /* Common code to retrieve the file's fileno */
+ if(H5F_get_fileno((obj_loc ? obj_loc : grp_loc)->oloc->file, &statbuf->fileno[0]) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "unable to read fileno")
+
+ /* Info for soft and UD links is gotten by H5L_get_info. If we have
+ * a hard link, follow it and get info on the object
+ */
+ if(udata->follow_link || !lnk || (lnk->type == H5L_TYPE_HARD)) {
+ H5O_info_t oinfo; /* Object information */
+
+ /* Go retrieve the object information */
+ /* (don't need index & heap info) */
+ HDassert(obj_loc);
+ if(H5O_get_info(obj_loc->oloc, udata->dxpl_id, FALSE, &oinfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get object info")
+
+ /* Get mapped object type */
+ statbuf->type = H5G_map_obj_type(oinfo.type);
+
+ /* Get object number (i.e. address) for object */
+ statbuf->objno[0] = (unsigned long)(oinfo.addr);
+#if H5_SIZEOF_UINT64_T > H5_SIZEOF_LONG
+ statbuf->objno[1] = (unsigned long)(oinfo.addr >> 8 * sizeof(long));
+#else
+ statbuf->objno[1] = 0;
+#endif
+ /* Get # of hard links pointing to object */
+ statbuf->nlink = oinfo.rc;
+
+ /* Get modification time for object */
+ statbuf->mtime = oinfo.ctime;
+
+ /* Retrieve the object header information */
+ statbuf->ohdr.size = oinfo.hdr.space.total;
+ statbuf->ohdr.free = oinfo.hdr.space.free;
+ statbuf->ohdr.nmesgs = oinfo.hdr.nmesgs;
+ statbuf->ohdr.nchunks = oinfo.hdr.nchunks;
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_objinfo_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_objinfo
+ *
+ * Purpose: Returns information about an object.
+ *
+ * Return: Success: Non-negative with info about the object
+ * returned through STATBUF if it isn't the null
+ * pointer.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_get_objinfo(const H5G_loc_t *loc, const char *name, hbool_t follow_link,
+ H5G_stat_t *statbuf/*out*/, hid_t dxpl_id)
+{
+ H5G_trav_goi_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Reset stat buffer, if one was given */
+ if(statbuf)
+ HDmemset(statbuf, 0, sizeof(H5G_stat_t));
+
+ /* Set up user data for retrieving information */
+ udata.statbuf = statbuf;
+ udata.follow_link = follow_link;
+ udata.loc_file = loc->oloc->file;
+ udata.dxpl_id = dxpl_id;
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ if(H5G_traverse(loc, name, (unsigned)(follow_link ? H5G_TARGET_NORMAL : H5G_TARGET_SLINK|H5G_TARGET_UDLINK),
+ H5G_get_objinfo_cb, &udata, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
+
+ /* If we're pointing at a soft or UD link, get the real link length and type */
+ if(statbuf && follow_link == 0) {
+ H5L_info_t linfo; /* Link information buffer */
+ herr_t ret;
+
+ /* Get information about link to the object. If this fails, e.g.
+ * because the object is ".", just treat the object as a hard link. */
+ H5E_BEGIN_TRY {
+ ret = H5L_get_info(loc, name, &linfo, H5P_DEFAULT, dxpl_id);
+ } H5E_END_TRY
+
+ if(ret >= 0 && linfo.type != H5L_TYPE_HARD) {
+ statbuf->linklen = linfo.u.val_size;
+ if(linfo.type == H5L_TYPE_SOFT)
+ statbuf->type = H5G_LINK;
+ else { /* UD link. H5L_get_info checked for invalid link classes */
+ HDassert(linfo.type >= H5L_TYPE_UD_MIN && linfo.type <= H5L_TYPE_MAX);
+ statbuf->type = H5G_UDLINK;
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_objinfo() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_objname_by_idx
+ *
+ * Purpose: Returns the name of objects in the group by giving index.
+ * If `name' is non-NULL then write up to `size' bytes into that
+ * buffer and always return the length of the entry name.
+ * Otherwise `size' is ignored and the function does not store the name,
+ * just returning the number of characters required to store the name.
+ * If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
+ * is unchanged and the function returns a negative value.
+ * If a zero is returned for the name's length, then there is no name
+ * associated with the ID.
+ *
+ * Note: Deprecated in favor of H5Lget_name_by_idx
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char *name, size_t size)
+{
+ H5G_loc_t loc; /* Object location */
+ H5O_type_t obj_type; /* Type of object at location */
+ ssize_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "ih*sz", loc_id, idx, name, size);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location ID")
+ if(H5O_obj_type(loc.oloc, &obj_type, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get object type")
+ if(obj_type != H5O_TYPE_GROUP)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Call internal function */
+ if((ret_value = H5G_obj_get_name_by_idx(loc.oloc, H5_INDEX_NAME, H5_ITER_INC, idx, name, size, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "can't get object name")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_objname_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Gget_objtype_by_idx
+ *
+ * Purpose: Returns the type of objects in the group by giving index.
+ *
+ * Note: Deprecated in favor of H5Lget_info/H5Oget_info
+ *
+ * Return: Success: H5G_GROUP(1), H5G_DATASET(2), H5G_TYPE(3)
+ * Failure: H5G_UNKNOWN
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5Gget_objtype_by_idx(hid_t loc_id, hsize_t idx)
+{
+ H5G_loc_t loc; /* Object location */
+ H5O_type_t obj_type; /* Type of object at location */
+ H5G_obj_t ret_value;
+
+ FUNC_ENTER_API(H5G_UNKNOWN)
+ H5TRACE2("Go", "ih", loc_id, idx);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "not a location ID")
+ if(H5O_obj_type(loc.oloc, &obj_type, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5G_UNKNOWN, "can't get object type")
+ if(obj_type != H5O_TYPE_GROUP)
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "not a group")
+
+ /* Call internal function*/
+ if((ret_value = H5G_obj_get_type_by_idx(loc.oloc, idx, H5AC_ind_read_dxpl_id)) == H5G_UNKNOWN)
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, H5G_UNKNOWN, "can't get object type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Gget_objtype_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_get_type_by_idx
+ *
+ * Purpose: Private function for H5Gget_objtype_by_idx.
+ * Returns the type of objects in the group by giving index.
+ *
+ * Return: Success: H5G_GROUP(1), H5G_DATASET(2), H5G_TYPE(3)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5G_obj_t
+H5G_obj_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ H5G_obj_t ret_value = H5G_UNKNOWN; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oloc->addr, H5G_UNKNOWN)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5G_UNKNOWN, "can't check for link info message")
+ if(linfo_exists) {
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Get the object's name from the dense link storage */
+ if((ret_value = H5G__dense_get_type_by_idx(oloc->file, dxpl_id, &linfo, idx)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "can't locate type")
+ } /* end if */
+ else {
+ /* Get the object's type from the link messages */
+ if((ret_value = H5G__compact_get_type_by_idx(oloc, dxpl_id, &linfo, idx)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "can't locate type")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Get the object's type from the symbol table */
+ if((ret_value = H5G__stab_get_type_by_idx(oloc, idx, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "can't locate type")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, H5G_UNKNOWN)
+} /* end H5G_obj_get_type_by_idx() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Gent.c b/src/H5Gent.c
new file mode 100644
index 0000000..b781fae
--- /dev/null
+++ b/src/H5Gent.c
@@ -0,0 +1,605 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, September 19, 1997
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare extern the PQ free list for the wrapped strings */
+H5FL_BLK_EXTERN(str_buf);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_decode_vec
+ *
+ * Purpose: Same as H5G_ent_decode() except it does it for an array of
+ * symbol table entries.
+ *
+ * Return: Success: Non-negative, with *pp pointing to the first byte
+ * after the last symbol.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__ent_decode_vec(const H5F_t *f, const uint8_t **pp, H5G_entry_t *ent, unsigned n)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+ HDassert(ent);
+
+ /* decode entries */
+ for(u = 0; u < n; u++)
+ if(H5G_ent_decode(f, pp, ent + u) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__ent_decode_vec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_ent_decode
+ *
+ * Purpose: Decodes a symbol table entry pointed to by `*pp'.
+ *
+ * Return: Success: Non-negative with *pp pointing to the first byte
+ * following the symbol table entry.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_ent_decode(const H5F_t *f, const uint8_t **pp, H5G_entry_t *ent)
+{
+ const uint8_t *p_ret = *pp;
+ uint32_t tmp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+ HDassert(ent);
+
+ /* decode header */
+ H5F_DECODE_LENGTH(f, *pp, ent->name_off);
+ H5F_addr_decode(f, pp, &(ent->header));
+ UINT32DECODE(*pp, tmp);
+ *pp += 4; /*reserved*/
+ ent->type = (H5G_cache_type_t)tmp;
+
+ /* decode scratch-pad */
+ switch(ent->type) {
+ case H5G_NOTHING_CACHED:
+ break;
+
+ case H5G_CACHED_STAB:
+ HDassert(2 * H5F_SIZEOF_ADDR(f) <= H5G_SIZEOF_SCRATCH);
+ H5F_addr_decode(f, pp, &(ent->cache.stab.btree_addr));
+ H5F_addr_decode(f, pp, &(ent->cache.stab.heap_addr));
+ break;
+
+ case H5G_CACHED_SLINK:
+ UINT32DECODE(*pp, ent->cache.slink.lval_offset);
+ break;
+
+ case H5G_CACHED_ERROR:
+ case H5G_NCACHED:
+ default:
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown symbol table entry cache type")
+ } /* end switch */
+
+ *pp = p_ret + H5G_SIZEOF_ENTRY_FILE(f);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_ent_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_encode_vec
+ *
+ * Purpose: Same as H5G_ent_encode() except it does it for an array of
+ * symbol table entries.
+ *
+ * Return: Success: Non-negative, with *pp pointing to the first byte
+ * after the last symbol.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__ent_encode_vec(const H5F_t *f, uint8_t **pp, const H5G_entry_t *ent, unsigned n)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+ HDassert(ent);
+
+ /* encode entries */
+ for(u = 0; u < n; u++)
+ if(H5G_ent_encode(f, pp, ent + u) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__ent_encode_vec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_ent_encode
+ *
+ * Purpose: Encodes the specified symbol table entry into the buffer
+ * pointed to by *pp.
+ *
+ * Return: Success: Non-negative, with *pp pointing to the first byte
+ * after the symbol table entry.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 18 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_ent_encode(const H5F_t *f, uint8_t **pp, const H5G_entry_t *ent)
+{
+ uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY_FILE(f);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+
+ /* Check for actual entry to encode */
+ if(ent) {
+ /* encode header */
+ H5F_ENCODE_LENGTH(f, *pp, ent->name_off);
+ H5F_addr_encode(f, pp, ent->header);
+ UINT32ENCODE(*pp, ent->type);
+ UINT32ENCODE(*pp, 0); /*reserved*/
+
+ /* encode scratch-pad */
+ switch(ent->type) {
+ case H5G_NOTHING_CACHED:
+ break;
+
+ case H5G_CACHED_STAB:
+ HDassert(2 * H5F_SIZEOF_ADDR(f) <= H5G_SIZEOF_SCRATCH);
+ H5F_addr_encode(f, pp, ent->cache.stab.btree_addr);
+ H5F_addr_encode(f, pp, ent->cache.stab.heap_addr);
+ break;
+
+ case H5G_CACHED_SLINK:
+ UINT32ENCODE(*pp, ent->cache.slink.lval_offset);
+ break;
+
+ case H5G_CACHED_ERROR:
+ case H5G_NCACHED:
+ default:
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown symbol table entry cache type")
+ } /* end switch */
+ } /* end if */
+ else {
+ H5F_ENCODE_LENGTH(f, *pp, 0);
+ H5F_addr_encode(f, pp, HADDR_UNDEF);
+ UINT32ENCODE(*pp, H5G_NOTHING_CACHED);
+ UINT32ENCODE(*pp, 0); /*reserved*/
+ } /* end else */
+
+ /* fill with zero */
+ if(*pp < p_ret)
+ HDmemset(*pp, 0, (size_t)(p_ret - *pp));
+ *pp = p_ret;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_ent_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_copy
+ *
+ * Purpose: Do a deep copy of symbol table entries
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Pedro Vicente
+ * pvn@ncsa.uiuc.edu
+ * ???day, August ??, 2002
+ *
+ * Notes: 'depth' parameter determines how much of the group entry
+ * structure we want to copy. The values are:
+ * H5_COPY_SHALLOW - Copy all the fields from the source
+ * to the destination, including the user path and
+ * canonical path. (Destination "takes ownership" of
+ * user and canonical paths)
+ * H5_COPY_DEEP - Copy all the fields from the source to
+ * the destination, deep copying the user and canonical
+ * paths.
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5G__ent_copy(H5G_entry_t *dst, const H5G_entry_t *src, H5_copy_depth_t depth)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check arguments */
+ HDassert(src);
+ HDassert(dst);
+ HDassert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP);
+
+ /* Copy the top level information */
+ HDmemcpy(dst, src, sizeof(H5G_entry_t));
+
+ /* Deep copy the names */
+ if(depth == H5_COPY_DEEP) {
+ /* Nothing currently */
+ ;
+ } else if(depth == H5_COPY_SHALLOW) {
+ /* Discarding 'const' qualifier OK - QAK */
+ H5G__ent_reset((H5G_entry_t *)src);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5G__ent_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_reset
+ *
+ * Purpose: Reset a symbol table entry to an empty state
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * ?day, August ??, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5G__ent_reset(H5G_entry_t *ent)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check arguments */
+ HDassert(ent);
+
+ /* Clear the symbol table entry to an empty state */
+ HDmemset(ent, 0, sizeof(H5G_entry_t));
+ ent->header = HADDR_UNDEF;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5G__ent_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_convert
+ *
+ * Purpose: Convert a link to a symbol table entry
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 20 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__ent_convert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, const char *name,
+ const H5O_link_t *lnk, H5O_type_t obj_type, const void *crt_info,
+ H5G_entry_t *ent)
+{
+ size_t name_offset; /* Offset of name in heap */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(heap);
+ HDassert(name);
+ HDassert(lnk);
+
+ /* Reset the new entry */
+ H5G__ent_reset(ent);
+
+ /*
+ * Add the new name to the heap.
+ */
+ name_offset = H5HL_insert(f, dxpl_id, heap, HDstrlen(name) + 1, name);
+ if(0 == name_offset || UFAIL == name_offset)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert symbol name into heap")
+ ent->name_off = name_offset;
+
+ /* Build correct information for symbol table entry based on link type */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ if(obj_type == H5O_TYPE_GROUP) {
+ const H5G_obj_create_t *gcrt_info = (const H5G_obj_create_t *)crt_info;
+
+ ent->type = gcrt_info->cache_type;
+ if(ent->type != H5G_NOTHING_CACHED)
+ ent->cache = gcrt_info->cache;
+#ifndef NDEBUG
+ else {
+ /* Make sure there is no stab message in the target object
+ */
+ H5O_loc_t targ_oloc; /* Location of link target */
+ htri_t stab_exists; /* Whether the target symbol table exists */
+
+ /* Build target object location */
+ if(H5O_loc_reset(&targ_oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location")
+ targ_oloc.file = f;
+ targ_oloc.addr = lnk->u.hard.addr;
+
+ /* Check if a symbol table message exists */
+ if((stab_exists = H5O_msg_exists(&targ_oloc, H5O_STAB_ID,
+ dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for STAB message")
+
+ HDassert(!stab_exists);
+ } /* end else */
+#endif /* NDEBUG */
+ } /* end if */
+ else if(obj_type == H5O_TYPE_UNKNOWN){
+ /* Try to retrieve symbol table information for caching */
+ H5O_loc_t targ_oloc; /* Location of link target */
+ H5O_t *oh; /* Link target object header */
+ H5O_stab_t stab; /* Link target symbol table */
+ htri_t stab_exists; /* Whether the target symbol table exists */
+
+ /* Build target object location */
+ if(H5O_loc_reset(&targ_oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location")
+ targ_oloc.file = f;
+ targ_oloc.addr = lnk->u.hard.addr;
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(&targ_oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect target object header")
+
+ /* Check if a symbol table message exists */
+ if((stab_exists = H5O_msg_exists_oh(oh, H5O_STAB_ID)) < 0) {
+ if(H5O_unprotect(&targ_oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET)
+ < 0)
+ HERROR(H5E_SYM, H5E_CANTUNPROTECT, "unable to release object header");
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for STAB message")
+ } /* end if */
+
+ if(stab_exists) {
+ /* Read symbol table message */
+ if(NULL == H5O_msg_read_oh(f, dxpl_id, oh, H5O_STAB_ID,
+ &stab)) {
+ if(H5O_unprotect(&targ_oloc, dxpl_id, oh,
+ H5AC__NO_FLAGS_SET) < 0)
+ HERROR(H5E_SYM, H5E_CANTUNPROTECT, "unable to release object header");
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read STAB message")
+ } /* end if */
+
+ /* Cache symbol table message */
+ ent->type = H5G_CACHED_STAB;
+ ent->cache.stab.btree_addr = stab.btree_addr;
+ ent->cache.stab.heap_addr = stab.heap_addr;
+ } /* end if */
+ else
+ /* No symbol table message, don't cache anything */
+ ent->type = H5G_NOTHING_CACHED;
+
+ if(H5O_unprotect(&targ_oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET)
+ < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+ } /* end else */
+ else
+ ent->type = H5G_NOTHING_CACHED;
+
+ ent->header = lnk->u.hard.addr;
+ break;
+
+ case H5L_TYPE_SOFT:
+ {
+ size_t lnk_offset; /* Offset to sym-link value */
+
+ /* Insert link value into local heap */
+ if(UFAIL == (lnk_offset = H5HL_insert(f, dxpl_id, heap,
+ HDstrlen(lnk->u.soft.name) + 1, lnk->u.soft.name)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to write link value to local heap")
+
+ ent->type = H5G_CACHED_SLINK;
+ ent->cache.slink.lval_offset = lnk_offset;
+ } /* end case */
+ break;
+
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_MAX:
+ default:
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__ent_convert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_debug
+ *
+ * Purpose: Prints debugging information about a symbol table entry.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 29 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__ent_debug(const H5G_entry_t *ent, FILE *stream, int indent, int fwidth,
+ const H5HL_t *heap)
+{
+ const char *lval = NULL;
+ int nested_indent, nested_fwidth;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Calculate the indent & field width values for nested information */
+ nested_indent = indent + 3;
+ nested_fwidth = MAX(0, fwidth - 3);
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Name offset into private heap:",
+ (unsigned long) (ent->name_off));
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Object header address:", ent->header);
+
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth,
+ "Cache info type:");
+ switch(ent->type) {
+ case H5G_NOTHING_CACHED:
+ HDfprintf(stream, "Nothing Cached\n");
+ break;
+
+ case H5G_CACHED_STAB:
+ HDfprintf(stream, "Symbol Table\n");
+
+ HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth,
+ "Cached entry information:");
+ HDfprintf(stream, "%*s%-*s %a\n", nested_indent, "", nested_fwidth,
+ "B-tree address:", ent->cache.stab.btree_addr);
+
+ HDfprintf(stream, "%*s%-*s %a\n", nested_indent, "", nested_fwidth,
+ "Heap address:", ent->cache.stab.heap_addr);
+ break;
+
+ case H5G_CACHED_SLINK:
+ HDfprintf(stream, "Symbolic Link\n");
+ HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth,
+ "Cached information:");
+ HDfprintf(stream, "%*s%-*s %lu\n", nested_indent, "", nested_fwidth,
+ "Link value offset:",
+ (unsigned long)(ent->cache.slink.lval_offset));
+ if(heap) {
+ lval = (const char *)H5HL_offset_into(heap, ent->cache.slink.lval_offset);
+ HDfprintf(stream, "%*s%-*s %s\n", nested_indent, "", nested_fwidth,
+ "Link value:",
+ lval);
+ } /* end if */
+ else
+ HDfprintf(stream, "%*s%-*s\n", nested_indent, "", nested_fwidth, "Warning: Invalid heap address given, name not displayed!");
+ break;
+
+ case H5G_CACHED_ERROR:
+ case H5G_NCACHED:
+ default:
+ HDfprintf(stream, "*** Unknown symbol type %d\n", ent->type);
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__ent_debug() */
+
diff --git a/src/H5Gint.c b/src/H5Gint.c
new file mode 100644
index 0000000..6d33716
--- /dev/null
+++ b/src/H5Gint.c
@@ -0,0 +1,1273 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gint.c
+ * April 5 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: General use, "internal" routines for groups.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for path traversal routine for "insertion file" routine */
+typedef struct {
+ H5G_loc_t *loc; /* Pointer to the location for insertion */
+} H5G_trav_ins_t;
+
+/* User data for application-style iteration over links in a group */
+typedef struct {
+ hid_t gid; /* The group ID for the application callback */
+ H5G_link_iterate_t lnk_op; /* Application callback */
+ void *op_data; /* Application's op data */
+} H5G_iter_appcall_ud_t;
+
+/* User data for recursive traversal over links from a group */
+typedef struct {
+ hid_t gid; /* The group ID for the starting group */
+ H5G_loc_t *curr_loc; /* Location of starting group */
+ hid_t lapl_id; /* LAPL for walking across links */
+ hid_t dxpl_id; /* DXPL for operations */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Iteration order within index */
+ H5SL_t *visited; /* Skip list for tracking visited nodes */
+ char *path; /* Path name of the link */
+ size_t curr_path_len; /* Current length of the path in the buffer */
+ size_t path_buf_size; /* Size of path buffer */
+ H5L_iterate_t op; /* Application callback */
+ void *op_data; /* Application's op data */
+} H5G_iter_visit_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5G_open_oid(H5G_t *grp, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5G_t struct */
+H5FL_DEFINE(H5G_t);
+H5FL_DEFINE(H5G_shared_t);
+
+/* Declare the free list to manage H5_obj_t's */
+H5FL_DEFINE(H5_obj_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__create_named
+ *
+ * Purpose: Internal routine to create a new "named" group.
+ *
+ * Return: Success: Non-NULL, pointer to new group object.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_t *
+H5G__create_named(const H5G_loc_t *loc, const char *name, hid_t lcpl_id,
+ hid_t gcpl_id, hid_t gapl_id, hid_t dxpl_id)
+{
+ H5O_obj_create_t ocrt_info; /* Information for object creation */
+ H5G_obj_create_t gcrt_info; /* Information for group creation */
+ H5G_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(lcpl_id != H5P_DEFAULT);
+ HDassert(gcpl_id != H5P_DEFAULT);
+ HDassert(gapl_id != H5P_DEFAULT);
+ HDassert(dxpl_id != H5P_DEFAULT);
+
+ /* Set up group creation info */
+ gcrt_info.gcpl_id = gcpl_id;
+ gcrt_info.cache_type = H5G_NOTHING_CACHED;
+ HDmemset(&gcrt_info.cache, 0, sizeof(gcrt_info.cache));
+
+ /* Set up object creation information */
+ ocrt_info.obj_type = H5O_TYPE_GROUP;
+ ocrt_info.crt_info = &gcrt_info;
+ ocrt_info.new_obj = NULL;
+
+ /* Create the new group and link it to its parent group */
+ if(H5L_link_object(loc, name, &ocrt_info, lcpl_id, gapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "unable to create and link to group")
+ HDassert(ocrt_info.new_obj);
+
+ /* Set the return value */
+ ret_value = (H5G_t *)ocrt_info.new_obj;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__create_named() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__create
+ *
+ * Purpose: Creates a new empty group with the specified name. The name
+ * is either an absolute name or is relative to LOC.
+ *
+ * Return: Success: A handle for the group. The group is opened
+ * and should eventually be close by calling
+ * H5G_close().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_t *
+H5G__create(H5F_t *file, H5G_obj_create_t *gcrt_info, hid_t dxpl_id)
+{
+ H5G_t *grp = NULL; /*new group */
+ unsigned oloc_init = 0; /* Flag to indicate that the group object location was created successfully */
+ H5G_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(file);
+ HDassert(gcrt_info->gcpl_id != H5P_DEFAULT);
+ HDassert(dxpl_id != H5P_DEFAULT);
+
+ /* create an open group */
+ if(NULL == (grp = H5FL_CALLOC(H5G_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(NULL == (grp->shared = H5FL_CALLOC(H5G_shared_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Create the group object header */
+ if(H5G__obj_create(file, dxpl_id, gcrt_info, &(grp->oloc)/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "unable to create group object header")
+ oloc_init = 1; /* Indicate that the object location information is valid */
+
+ /* Add group to list of open objects in file */
+ if(H5FO_top_incr(grp->oloc.file, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINC, NULL, "can't incr object ref. count")
+ if(H5FO_insert(grp->oloc.file, grp->oloc.addr, grp->shared, TRUE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, NULL, "can't insert group into list of open objects")
+
+ /* Set the count of times the object is opened */
+ grp->shared->fo_count = 1;
+
+ /* Set return value */
+ ret_value = grp;
+
+done:
+ if(ret_value == NULL) {
+ /* Check if we need to release the file-oriented symbol table info */
+ if(oloc_init) {
+ if(H5O_dec_rc_by_loc(&(grp->oloc), dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDEC, NULL, "unable to decrement refcount on newly created object")
+ if(H5O_close(&(grp->oloc), NULL) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, NULL, "unable to release object header")
+ if(H5O_delete(file, dxpl_id, grp->oloc.addr) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDELETE, NULL, "unable to delete object header")
+ } /* end if */
+ if(grp != NULL) {
+ if(grp->shared != NULL)
+ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
+ grp = H5FL_FREE(H5G_t, grp);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__open_name
+ *
+ * Purpose: Opens an existing group by name.
+ *
+ * Return: Success: Ptr to a new group.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 27, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_t *
+H5G__open_name(const H5G_loc_t *loc, const char *name, hid_t gapl_id,
+ hid_t dxpl_id)
+{
+ H5G_t *grp = NULL; /* Group to open */
+ H5G_loc_t grp_loc; /* Location used to open group */
+ H5G_name_t grp_path; /* Opened object group hier. path */
+ H5O_loc_t grp_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Location at 'name' found */
+ H5O_type_t obj_type; /* Type of object at location */
+ H5G_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Set up opened group location to fill in */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ H5G_loc_reset(&grp_loc);
+
+ /* Find the group object using the gapl passed in */
+ if(H5G_loc_find(loc, name, &grp_loc/*out*/, gapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "group not found")
+ loc_found = TRUE;
+
+ /* Check that the object found is the correct type */
+ if(H5O_obj_type(&grp_oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, NULL, "can't get object type")
+ if(obj_type != H5O_TYPE_GROUP)
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, NULL, "not a group")
+
+ /* Open the group */
+ if((grp = H5G_open(&grp_loc, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, NULL, "unable to open group")
+
+ /* Set return value */
+ ret_value = grp;
+
+done:
+ if(!ret_value) {
+ if(loc_found && H5G_loc_free(&grp_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, NULL, "can't free location")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__open_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_open
+ *
+ * Purpose: Opens an existing group. The group should eventually be
+ * closed by calling H5G_close().
+ *
+ * Return: Success: Ptr to a new group.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_t *
+H5G_open(const H5G_loc_t *loc, hid_t dxpl_id)
+{
+ H5G_t *grp = NULL; /* Group opened */
+ H5G_shared_t *shared_fo; /* Shared group object */
+ H5G_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check args */
+ HDassert(loc);
+
+ /* Allocate the group structure */
+ if(NULL == (grp = H5FL_CALLOC(H5G_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate space for group")
+
+ /* Shallow copy (take ownership) of the group location object */
+ if(H5O_loc_copy(&(grp->oloc), loc->oloc, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, NULL, "can't copy object location")
+ if(H5G_name_copy(&(grp->path), loc->path, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, NULL, "can't copy path")
+
+ /* Check if group was already open */
+ if((shared_fo = (H5G_shared_t *)H5FO_opened(grp->oloc.file, grp->oloc.addr)) == NULL) {
+
+ /* Clear any errors from H5FO_opened() */
+ H5E_clear_stack(NULL);
+
+ /* Open the group object */
+ if(H5G_open_oid(grp, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "not found")
+
+ /* Add group to list of open objects in file */
+ if(H5FO_insert(grp->oloc.file, grp->oloc.addr, grp->shared, FALSE) < 0) {
+ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, NULL, "can't insert group into list of open objects")
+ } /* end if */
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(grp->oloc.file, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINC, NULL, "can't increment object count")
+
+ /* Set open object count */
+ grp->shared->fo_count = 1;
+ } /* end if */
+ else {
+ /* Point to shared group info */
+ grp->shared = shared_fo;
+
+ /* Increment shared reference count */
+ shared_fo->fo_count++;
+
+ /* Check if the object has been opened through the top file yet */
+ if(H5FO_top_count(grp->oloc.file, grp->oloc.addr) == 0) {
+ /* Open the object through this top file */
+ if(H5O_open(&(grp->oloc)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, NULL, "unable to open object header")
+ } /* end if */
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(grp->oloc.file, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINC, NULL, "can't increment object count")
+ } /* end else */
+
+ /* Set return value */
+ ret_value = grp;
+
+done:
+ if(!ret_value && grp) {
+ H5O_loc_free(&(grp->oloc));
+ H5G_name_free(&(grp->path));
+ grp = H5FL_FREE(H5G_t, grp);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_open_oid
+ *
+ * Purpose: Opens an existing group. The group should eventually be
+ * closed by calling H5G_close().
+ *
+ * Return: Success: Ptr to a new group.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, March 17, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_open_oid(H5G_t *grp, hid_t dxpl_id)
+{
+ hbool_t obj_opened = FALSE;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(grp);
+
+ /* Allocate the shared information for the group */
+ if(NULL == (grp->shared = H5FL_CALLOC(H5G_shared_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Grab the object header */
+ if(H5O_open(&(grp->oloc)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ obj_opened = TRUE;
+
+ /* Check if this object has the right message(s) to be treated as a group */
+ if((H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id) <= 0)
+ && (H5O_msg_exists(&(grp->oloc), H5O_LINFO_ID, dxpl_id) <= 0))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "not a group")
+
+done:
+ if(ret_value < 0) {
+ if(obj_opened)
+ H5O_close(&(grp->oloc), NULL);
+ if(grp->shared)
+ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_open_oid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_close
+ *
+ * Purpose: Closes the specified group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_close(H5G_t *grp)
+{
+ hbool_t corked; /* Whether the group is corked or not */
+ hbool_t file_closed = TRUE; /* H5O_close also closed the file? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+ HDassert(grp->shared->fo_count > 0);
+
+ --grp->shared->fo_count;
+
+ if(0 == grp->shared->fo_count) {
+ HDassert(grp != H5G_rootof(H5G_fileof(grp)));
+
+ /* Uncork cache entries with object address tag */
+ if(H5AC_cork(grp->oloc.file, grp->oloc.addr, H5AC__GET_CORKED, &corked) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status")
+ if(corked)
+ if(H5AC_cork(grp->oloc.file, grp->oloc.addr, H5AC__UNCORK, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUNCORK, FAIL, "unable to uncork an object")
+
+ /* Remove the group from the list of opened objects in the file */
+ if(H5FO_top_decr(grp->oloc.file, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+ if(H5FO_delete(grp->oloc.file, H5AC_ind_read_dxpl_id, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't remove group from list of open objects")
+ if(H5O_close(&(grp->oloc), &file_closed) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close")
+
+ /* Evict group metadata if evicting on close */
+ if(!file_closed && H5F_SHARED(grp->oloc.file) && H5F_EVICT_ON_CLOSE(grp->oloc.file)) {
+ if(H5AC_flush_tagged_metadata(grp->oloc.file, grp->oloc.addr, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
+ if(H5AC_evict_tagged_metadata(grp->oloc.file, grp->oloc.addr, FALSE, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict tagged metadata")
+ } /* end if */
+
+ /* Free memory */
+ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
+ } else {
+ /* Decrement the ref. count for this object in the top file */
+ if(H5FO_top_decr(grp->oloc.file, grp->oloc.addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+
+ /* Check reference count for this object in the top file */
+ if(H5FO_top_count(grp->oloc.file, grp->oloc.addr) == 0) {
+ if(H5O_close(&(grp->oloc), NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close")
+ } /* end if */
+ else
+ /* Free object location (i.e. "unhold" the file if appropriate) */
+ if(H5O_loc_free(&(grp->oloc)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "problem attempting to free location")
+
+ /* If this group is a mount point and the mount point is the last open
+ * reference to the group, then attempt to close down the file hierarchy
+ */
+ if(grp->shared->mounted && grp->shared->fo_count == 1) {
+ /* Attempt to close down the file hierarchy */
+ if(H5F_try_close(grp->oloc.file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
+ } /* end if */
+ } /* end else */
+
+ if(H5G_name_free(&(grp->path)) < 0) {
+ grp = H5FL_FREE(H5G_t, grp);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't free group entry name")
+ } /* end if */
+
+ grp = H5FL_FREE(H5G_t, grp);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_oloc
+ *
+ * Purpose: Returns a pointer to the object location for a group.
+ *
+ * Return: Success: Ptr to group entry
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 24, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_loc_t *
+H5G_oloc(H5G_t *grp)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(grp ? &(grp->oloc) : NULL)
+} /* end H5G_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_nameof
+ *
+ * Purpose: Returns a pointer to the hier. name for a group.
+ *
+ * Return: Success: Ptr to hier. name
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_name_t *
+H5G_nameof(H5G_t *grp)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(grp ? &(grp->path) : NULL)
+} /* end H5G_nameof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_fileof
+ *
+ * Purpose: Returns the file to which the specified group belongs.
+ *
+ * Return: Success: File pointer.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 24, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5G_fileof(H5G_t *grp)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(grp);
+
+ FUNC_LEAVE_NOAPI(grp->oloc.file)
+} /* end H5G_fileof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_shared_count
+ *
+ * Purpose: Queries the group object's "shared count"
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 5, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_get_shared_count(H5G_t *grp)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+
+ FUNC_LEAVE_NOAPI(grp->shared->fo_count)
+} /* end H5G_get_shared_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_mount
+ *
+ * Purpose: Sets the 'mounted' flag for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_mount(H5G_t *grp)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+ HDassert(grp->shared->mounted == FALSE);
+
+ /* Set the 'mounted' flag */
+ grp->shared->mounted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_mount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_mounted
+ *
+ * Purpose: Retrieves the 'mounted' flag for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 15, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5G_mounted(H5G_t *grp)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+
+ FUNC_LEAVE_NOAPI(grp->shared->mounted)
+} /* end H5G_mounted() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_unmount
+ *
+ * Purpose: Resets the 'mounted' flag for a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_unmount(H5G_t *grp)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+ HDassert(grp->shared->mounted == TRUE);
+
+ /* Reset the 'mounted' flag */
+ grp->shared->mounted = FALSE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_unmount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_iterate_cb
+ *
+ * Purpose: Callback function for iterating over links in a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Oct 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_iterate_cb(const H5O_link_t *lnk, void *_udata)
+{
+ H5G_iter_appcall_ud_t *udata = (H5G_iter_appcall_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = H5_ITER_ERROR; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(lnk);
+ HDassert(udata);
+
+ switch(udata->lnk_op.op_type) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ case H5G_LINK_OP_OLD:
+ /* Make the old-type application callback */
+ ret_value = (udata->lnk_op.op_func.op_old)(udata->gid, lnk->name, udata->op_data);
+ break;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ case H5G_LINK_OP_NEW:
+ {
+ H5L_info_t info; /* Link info */
+
+ /* Retrieve the info for the link */
+ if(H5G_link_to_info(lnk, &info) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
+
+ /* Make the application callback */
+ ret_value = (udata->lnk_op.op_func.op_new)(udata->gid, lnk->name, &info, udata->op_data);
+ }
+ break;
+
+ default:
+ HDassert(0 && "Unknown link op type?!?");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_iterate
+ *
+ * Purpose: Private function for iterating over links in a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Oct 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_iterate(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ const H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t loc; /* Location of parent for group */
+ hid_t gid = -1; /* ID of group to iterate over */
+ H5G_t *grp = NULL; /* Pointer to group data structure to iterate over */
+ H5G_iter_appcall_ud_t udata; /* User data for callback */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(group_name);
+ HDassert(last_lnk);
+ HDassert(lnk_op && lnk_op->op_func.op_new);
+
+ /*
+ * Open the group on which to operate. We also create a group ID which
+ * we can pass to the application-defined operator.
+ */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(NULL == (grp = H5G__open_name(&loc, group_name, lapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((gid = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+ /* Set up user data for callback */
+ udata.gid = gid;
+ udata.lnk_op = *lnk_op;
+ udata.op_data = op_data;
+
+ /* Call the real group iteration routine */
+ if((ret_value = H5G__obj_iterate(&(grp->oloc), idx_type, order, skip, last_lnk, H5G_iterate_cb, &udata, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "error iterating over links")
+
+done:
+ /* Release the group opened */
+ if(gid > 0) {
+ if(H5I_dec_app_ref(gid) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close group")
+ } /* end if */
+ else if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_free_visit_visited
+ *
+ * Purpose: Free the key for an object visited during a group traversal
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Nov 4, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_free_visit_visited(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *operator_data/*in,out*/)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ item = H5FL_FREE(H5_obj_t, item);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_free_visit_visited() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_visit_cb
+ *
+ * Purpose: Callback function for recursively visiting links from a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 4, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_visit_cb(const H5O_link_t *lnk, void *_udata)
+{
+ H5G_iter_visit_ud_t *udata = (H5G_iter_visit_ud_t *)_udata; /* User data for callback */
+ H5L_info_t info; /* Link info */
+ H5G_loc_t obj_loc; /* Location of object */
+ H5G_name_t obj_path; /* Object's group hier. path */
+ H5O_loc_t obj_oloc; /* Object's object location */
+ hbool_t obj_found = FALSE; /* Object at 'name' found */
+ size_t old_path_len = udata->curr_path_len; /* Length of path before appending this link's name */
+ size_t link_name_len; /* Length of link's name */
+ size_t len_needed; /* Length of path string needed */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* Check if we will need more space to store this link's relative path */
+ /* ("+2" is for string terminator and possible '/' for group separator later) */
+ link_name_len = HDstrlen(lnk->name);
+ len_needed = udata->curr_path_len + link_name_len + 2;
+ if(len_needed > udata->path_buf_size) {
+ void *new_path; /* Pointer to new path buffer */
+
+ /* Attempt to allocate larger buffer for path */
+ if(NULL == (new_path = H5MM_realloc(udata->path, len_needed)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate path string")
+ udata->path = (char *)new_path;
+ udata->path_buf_size = len_needed;
+ } /* end if */
+
+ /* Build the link's relative path name */
+ HDassert(udata->path[old_path_len] == '\0');
+ HDstrncpy(&(udata->path[old_path_len]), lnk->name, link_name_len + 1);
+ udata->curr_path_len += link_name_len;
+
+ /* Construct the link info from the link message */
+ if(H5G_link_to_info(lnk, &info) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
+
+ /* Make the application callback */
+ ret_value = (udata->op)(udata->gid, udata->path, &info, udata->op_data);
+
+ /* Check for doing more work */
+ if(ret_value == H5_ITER_CONT && lnk->type == H5L_TYPE_HARD) {
+ H5_obj_t obj_pos; /* Object "position" for this object */
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object using the LAPL passed in */
+ /* (Correctly handles mounted files) */
+ if(H5G_loc_find(udata->curr_loc, lnk->name, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+ obj_found = TRUE;
+
+ /* Construct unique "position" for this object */
+ H5F_GET_FILENO(obj_oloc.file, obj_pos.fileno);
+ obj_pos.addr = obj_oloc.addr;
+
+ /* Check if we've seen the object the link references before */
+ if(NULL == H5SL_search(udata->visited, &obj_pos)) {
+ H5O_type_t otype; /* Basic object type (group, dataset, etc.) */
+ unsigned rc; /* Reference count of object */
+
+ /* Get the object's reference count and type */
+ if(H5O_get_rc_and_type(&obj_oloc, udata->dxpl_id, &rc, &otype) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info")
+
+ /* If its ref count is > 1, we add it to the list of visited objects */
+ /* (because it could come up again during traversal) */
+ if(rc > 1) {
+ H5_obj_t *new_node; /* New object node for visited list */
+
+ /* Allocate new object "position" node */
+ if((new_node = H5FL_MALLOC(H5_obj_t)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate object node")
+
+ /* Set node information */
+ *new_node = obj_pos;
+
+ /* Add to list of visited objects */
+ if(H5SL_insert(udata->visited, new_node, new_node) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert object node into visited list")
+ } /* end if */
+
+ /* If it's a group, we recurse into it */
+ if(otype == H5O_TYPE_GROUP) {
+ H5G_loc_t *old_loc = udata->curr_loc; /* Pointer to previous group location info */
+ H5_index_t idx_type = udata->idx_type; /* Type of index to use */
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+
+ /* Add the path separator to the current path */
+ HDassert(udata->path[udata->curr_path_len] == '\0');
+ HDstrncpy(&(udata->path[udata->curr_path_len]), "/", (size_t)2);
+ udata->curr_path_len++;
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(&obj_oloc, &linfo, udata->dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ /* Switch to name order for this group */
+ idx_type = H5_INDEX_NAME;
+ } /* end if */
+ else
+ HDassert(idx_type == H5_INDEX_NAME);
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ /* Switch to name order for this group */
+ idx_type = H5_INDEX_NAME;
+ } /* end if */
+
+ /* Point to this group's location info */
+ udata->curr_loc = &obj_loc;
+
+ /* Iterate over links in group */
+ ret_value = H5G__obj_iterate(&obj_oloc, idx_type, udata->order, (hsize_t)0, NULL, H5G_visit_cb, udata, udata->dxpl_id);
+
+ /* Restore location */
+ udata->curr_loc = old_loc;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Reset path back to incoming path */
+ udata->path[old_path_len] = '\0';
+ udata->curr_path_len = old_path_len;
+
+ /* Release resources */
+ if(obj_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_visit_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_visit
+ *
+ * Purpose: Recursively visit all the links in a group and all
+ * the groups that are linked to from that group. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Each _link_ reachable from the initial group will only be
+ * visited once. However, because an object may be reached from
+ * more than one link, the visitation may call the application's
+ * callback with more than one link that points to a particular
+ * _object_.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ *
+ *
+ * Programmer: Quincey Koziol
+ * November 4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, H5L_iterate_t op, void *op_data, hid_t lapl_id,
+ hid_t dxpl_id)
+{
+ H5G_iter_visit_ud_t udata; /* User data for callback */
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ hid_t gid = (-1); /* Group ID */
+ H5G_t *grp = NULL; /* Group opened */
+ H5G_loc_t loc; /* Location of group passed in */
+ H5G_loc_t start_loc; /* Location of starting group */
+ unsigned rc; /* Reference count of object */
+ herr_t ret_value = FAIL; /* Return value */
+
+ /* Portably clear udata struct (before FUNC_ENTER) */
+ HDmemset(&udata, 0, sizeof(udata));
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Open the group to begin visiting within */
+ if((grp = H5G__open_name(&loc, group_name, lapl_id, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+
+ /* Register an ID for the starting group */
+ if((gid = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+ /* Get the location of the starting group */
+ if(H5G_loc(gid, &start_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Set up user data */
+ udata.gid = gid;
+ udata.curr_loc = &start_loc;
+ udata.lapl_id = lapl_id;
+ udata.dxpl_id = dxpl_id;
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.op = op;
+ udata.op_data = op_data;
+
+ /* Allocate space for the path name */
+ if(NULL == (udata.path = H5MM_strdup("")))
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't allocate path name buffer")
+ udata.path_buf_size = 1;
+ udata.curr_path_len = 0;
+
+ /* Create skip list to store visited object information */
+ if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, NULL)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects")
+
+ /* Get the group's reference count */
+ if(H5O_get_rc_and_type(&grp->oloc, dxpl_id, &rc, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get object info")
+
+ /* If its ref count is > 1, we add it to the list of visited objects */
+ /* (because it could come up again during traversal) */
+ if(rc > 1) {
+ H5_obj_t *obj_pos; /* New object node for visited list */
+
+ /* Allocate new object "position" node */
+ if((obj_pos = H5FL_MALLOC(H5_obj_t)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't allocate object node")
+
+ /* Construct unique "position" for this object */
+ H5F_GET_FILENO(grp->oloc.file, obj_pos->fileno);
+ obj_pos->addr = grp->oloc.addr;
+
+ /* Add to list of visited objects */
+ if(H5SL_insert(udata.visited, obj_pos, obj_pos) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert object node into visited list")
+ } /* end if */
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(&(grp->oloc), &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ /* Switch to name order for this group */
+ idx_type = H5_INDEX_NAME;
+ } /* end if */
+ else
+ HDassert(idx_type == H5_INDEX_NAME);
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ /* Switch to name order for this group */
+ idx_type = H5_INDEX_NAME;
+ } /* end if */
+
+ /* Call the link iteration routine */
+ if((ret_value = H5G__obj_iterate(&(grp->oloc), idx_type, order, (hsize_t)0, NULL, H5G_visit_cb, &udata, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't visit links")
+
+done:
+ /* Release user data resources */
+ H5MM_xfree(udata.path);
+ if(udata.visited)
+ H5SL_destroy(udata.visited, H5G_free_visit_visited, NULL);
+
+ /* Release the group opened */
+ if(gid > 0) {
+ if(H5I_dec_app_ref(gid) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close group")
+ } /* end if */
+ else if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_visit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_create_plist
+ *
+ * Purpose: Private function for H5Gget_create_plist
+ *
+ * Return: Success: ID for a copy of the group creation
+ * property list. The property list ID should be
+ * released by calling H5Pclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 25, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5G_get_create_plist(H5G_t *grp)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t ginfo_exists;
+ htri_t linfo_exists;
+ htri_t pline_exists;
+ H5P_genplist_t *gcpl_plist;
+ H5P_genplist_t *new_plist;
+ hid_t new_gcpl_id = FAIL;
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Copy the default group creation property list */
+ if(NULL == (gcpl_plist = (H5P_genplist_t *)H5I_object(H5P_LST_GROUP_CREATE_ID_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get default group creation property list")
+ if((new_gcpl_id = H5P_copy_plist(gcpl_plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to copy the creation property list")
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(new_gcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Retrieve any object creation properties */
+ if(H5O_get_create_plist(&grp->oloc, H5AC_ind_read_dxpl_id, new_plist) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object creation info")
+
+ /* Check for the group having a group info message */
+ if((ginfo_exists = H5O_msg_exists(&(grp->oloc), H5O_GINFO_ID, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(ginfo_exists) {
+ H5O_ginfo_t ginfo; /* Group info message */
+
+ /* Read the group info */
+ if(NULL == H5O_msg_read(&(grp->oloc), H5O_GINFO_ID, &ginfo, H5AC_ind_read_dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")
+
+ /* Set the group info for the property list */
+ if(H5P_set(new_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set group info")
+ } /* end if */
+
+ /* Check for the group having a link info message */
+ if((linfo_exists = H5G__obj_get_linfo(&(grp->oloc), &linfo, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(linfo_exists) {
+ /* Set the link info for the property list */
+ if(H5P_set(new_plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set link info")
+ } /* end if */
+
+ /* Check for the group having a pipeline message */
+ if((pline_exists = H5O_msg_exists(&(grp->oloc), H5O_PLINE_ID, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(pline_exists) {
+ H5O_pline_t pline; /* Pipeline message */
+
+ /* Read the pipeline */
+ if(NULL == H5O_msg_read(&(grp->oloc), H5O_PLINE_ID, &pline, H5AC_ind_read_dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link pipeline")
+
+ /* Set the pipeline for the property list */
+ if(H5P_poke(new_plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set link pipeline")
+ } /* end if */
+
+ /* Set the return value */
+ ret_value = new_gcpl_id;
+
+done:
+ if(ret_value < 0) {
+ if(new_gcpl_id > 0)
+ if(H5I_dec_app_ref(new_gcpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "can't free")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_create_plist() */
diff --git a/src/H5Glink.c b/src/H5Glink.c
new file mode 100644
index 0000000..d246ee7
--- /dev/null
+++ b/src/H5Glink.c
@@ -0,0 +1,567 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Glink.c
+ * Nov 13 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Functions for handling links in groups.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static int H5G_link_cmp_name_inc(const void *lnk1, const void *lnk2);
+static int H5G_link_cmp_name_dec(const void *lnk1, const void *lnk2);
+static int H5G_link_cmp_corder_inc(const void *lnk1, const void *lnk2);
+static int H5G_link_cmp_corder_dec(const void *lnk1, const void *lnk2);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_cmp_name_inc
+ *
+ * Purpose: Callback routine for comparing two link names, in
+ * increasing alphabetic order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * first argument is considered to be respectively less than,
+ * equal to, or greater than the second. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ * (i.e. same as strcmp())
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 5 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_link_cmp_name_inc(const void *lnk1, const void *lnk2)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(HDstrcmp(((const H5O_link_t *)lnk1)->name, ((const H5O_link_t *)lnk2)->name))
+} /* end H5G_link_cmp_name_inc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_cmp_name_dec
+ *
+ * Purpose: Callback routine for comparing two link names, in
+ * decreasing alphabetic order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * second argument is considered to be respectively less than,
+ * equal to, or greater than the first. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ * (i.e. opposite strcmp())
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_link_cmp_name_dec(const void *lnk1, const void *lnk2)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(HDstrcmp(((const H5O_link_t *)lnk2)->name, ((const H5O_link_t *)lnk1)->name))
+} /* end H5G_link_cmp_name_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_cmp_corder_inc
+ *
+ * Purpose: Callback routine for comparing two link creation orders, in
+ * increasing order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * first argument is considered to be respectively less than,
+ * equal to, or greater than the second. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_link_cmp_corder_inc(const void *lnk1, const void *lnk2)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
+ ret_value = -1;
+ else if(((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
+ ret_value = 1;
+ else
+ ret_value = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_link_cmp_corder_inc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_cmp_corder_dec
+ *
+ * Purpose: Callback routine for comparing two link creation orders, in
+ * decreasing order
+ *
+ * Return: An integer less than, equal to, or greater than zero if the
+ * second argument is considered to be respectively less than,
+ * equal to, or greater than the first. If two members compare
+ * as equal, their order in the sorted array is undefined.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_link_cmp_corder_dec(const void *lnk1, const void *lnk2)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
+ ret_value = 1;
+ else if(((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
+ ret_value = -1;
+ else
+ ret_value = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_link_cmp_corder_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__ent_to_link
+ *
+ * Purpose: Convert a symbol table entry to a link
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 16 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__ent_to_link(H5O_link_t *lnk, const H5HL_t *heap,
+ const H5G_entry_t *ent, const char *name)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(heap);
+ HDassert(ent);
+ HDassert(name);
+
+ /* Set (default) common info for link */
+ lnk->cset = H5F_DEFAULT_CSET;
+ lnk->corder = 0;
+ lnk->corder_valid = FALSE; /* Creation order not valid for this link */
+ lnk->name = H5MM_xstrdup(name);
+ HDassert(lnk->name);
+
+ /* Object is a symbolic or hard link */
+ if(ent->type == H5G_CACHED_SLINK) {
+ const char *s; /* Pointer to link value */
+
+ s = (const char *)H5HL_offset_into(heap, ent->cache.slink.lval_offset);
+ HDassert(s);
+
+ /* Copy the link value */
+ lnk->u.soft.name = H5MM_xstrdup(s);
+
+ /* Set link type */
+ lnk->type = H5L_TYPE_SOFT;
+ } /* end if */
+ else {
+ /* Set address of object */
+ lnk->u.hard.addr = ent->header;
+
+ /* Set link type */
+ lnk->type = H5L_TYPE_HARD;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__ent_to_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_link_to_info
+ *
+ * Purpose: Retrieve information from a link object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_link_to_info(const H5O_link_t *lnk, H5L_info_t *info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(lnk);
+
+ /* Get information from the link */
+ if(info) {
+ info->cset = lnk->cset;
+ info->corder = lnk->corder;
+ info->corder_valid = lnk->corder_valid;
+ info->type = lnk->type;
+
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ info->u.address = lnk->u.hard.addr;
+ break;
+
+ case H5L_TYPE_SOFT:
+ info->u.val_size = HDstrlen(lnk->u.soft.name) + 1; /*count the null terminator*/
+ break;
+
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_MAX:
+ default:
+ {
+ const H5L_class_t *link_class; /* User-defined link class */
+
+ if(lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "unknown link class")
+
+ /* User-defined link; call its query function to get the link udata size. */
+ /* Get the link class for this type of link. It's okay if the class
+ * isn't registered, though--we just can't give any more information
+ * about it
+ */
+ link_class = H5L_find_class(lnk->type);
+
+ if(link_class != NULL && link_class->query_func != NULL) {
+ ssize_t cb_ret; /* Return value from UD callback */
+
+ /* Call the link's query routine to retrieve the user-defined link's value size */
+ /* (in case the query routine packs/unpacks the link value in some way that changes its size) */
+ if((cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, NULL, (size_t)0)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query buffer size callback returned failure")
+
+ info->u.val_size = (size_t)cb_ret;
+ } /* end if */
+ else
+ info->u.val_size = 0;
+ } /* end case */
+ } /* end switch */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_link_to_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__link_to_loc
+ *
+ * Purpose: Build group location from group and link object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 20 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__link_to_loc(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(obj_loc);
+
+ /*
+ * Build location from the link
+ */
+
+ /* Check for unknown library-internal link */
+ if(lnk->type > H5L_TYPE_BUILTIN_MAX && lnk->type < H5L_TYPE_UD_MIN)
+ HGOTO_ERROR(H5E_SYM, H5E_UNSUPPORTED, FAIL, "unknown link type")
+
+ /* Build object's group hier. location */
+ if(H5G_name_set(grp_loc->path, obj_loc->path, lnk->name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name")
+
+ /* Set the object location, if it's a hard link set the address also */
+ obj_loc->oloc->file = grp_loc->oloc->file;
+ obj_loc->oloc->holding_file = FALSE;
+ if(lnk->type == H5L_TYPE_HARD)
+ obj_loc->oloc->addr = lnk->u.hard.addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__link_to_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__link_sort_table
+ *
+ * Purpose: Sort table containing a list of links for a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type,
+ H5_iter_order_t order)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDassert(ltable);
+
+ /* Pick appropriate sorting routine */
+ if(idx_type == H5_INDEX_NAME) {
+ if(order == H5_ITER_INC)
+ HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_name_inc);
+ else if(order == H5_ITER_DEC)
+ HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_name_dec);
+ else
+ HDassert(order == H5_ITER_NATIVE);
+ } /* end if */
+ else {
+ HDassert(idx_type == H5_INDEX_CRT_ORDER);
+ if(order == H5_ITER_INC)
+ HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_corder_inc);
+ else if(order == H5_ITER_DEC)
+ HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_corder_dec);
+ else
+ HDassert(order == H5_ITER_NATIVE);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__link_sort_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__link_iterate_table
+ *
+ * Purpose: Iterate over table containing a list of links for a group,
+ * making appropriate callbacks
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
+ hsize_t *last_lnk, const H5G_lib_iterate_t op, void *op_data)
+{
+ size_t u; /* Local index variable */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDassert(ltable);
+ HDassert(op);
+
+ /* Skip over links, if requested */
+ if(last_lnk)
+ *last_lnk += skip;
+
+ /* Iterate over link messages */
+ H5_CHECKED_ASSIGN(u, size_t, skip, hsize_t)
+ for(; u < ltable->nlinks && !ret_value; u++) {
+ /* Make the callback */
+ ret_value = (op)(&(ltable->lnks[u]), op_data);
+
+ /* Increment the number of entries passed through */
+ if(last_lnk)
+ (*last_lnk)++;
+ } /* end for */
+
+ /* Check for callback failure and pass along return value */
+ if(ret_value < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__link_iterate_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__link_release_table
+ *
+ * Purpose: Release table containing a list of links for a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__link_release_table(H5G_link_table_t *ltable)
+{
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(ltable);
+
+ /* Release link info, if any */
+ if(ltable->nlinks > 0) {
+ /* Free link message information */
+ for(u = 0; u < ltable->nlinks; u++)
+ if(H5O_msg_reset(H5O_LINK_ID, &(ltable->lnks[u])) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link message")
+
+ /* Free table of links */
+ H5MM_xfree(ltable->lnks);
+ } /* end if */
+ else
+ HDassert(ltable->lnks == NULL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__link_release_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__link_name_replace
+ *
+ * Purpose: Determine the type of object referred to (for hard links) or
+ * the link type (for soft links and user-defined links).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__link_name_replace(H5F_t *file, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
+ const H5O_link_t *lnk)
+{
+ H5RS_str_t *obj_path_r = NULL; /* Full path for link being removed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(file);
+
+ /* Search the open IDs and replace names for unlinked object */
+ if(grp_full_path_r) {
+ obj_path_r = H5G_build_fullpath_refstr_str(grp_full_path_r, lnk->name);
+ if(H5G_name_replace(lnk, H5G_NAME_DELETE, file, obj_path_r, NULL, NULL, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to replace name")
+ } /* end if */
+
+done:
+ if(obj_path_r)
+ H5RS_decr(obj_path_r);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__link_name_replace() */
+
diff --git a/src/H5Gloc.c b/src/H5Gloc.c
new file mode 100644
index 0000000..c011cdf
--- /dev/null
+++ b/src/H5Gloc.c
@@ -0,0 +1,938 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gloc.c
+ * Sep 13 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for working with group "locations"
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Aprivate.h" /* Attributes */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for looking up an object in a group */
+typedef struct {
+ /* upward */
+ H5G_loc_t *loc; /* Group location to set */
+} H5G_loc_fnd_t;
+
+/* User data for checking if an object exists */
+typedef struct {
+ /* upward */
+ htri_t exists; /* Whether the object exists */
+} H5G_loc_exists_t;
+
+/* User data for looking up an object in a group by index */
+typedef struct {
+ /* downward */
+ hid_t lapl_id; /* LAPL to use for operation */
+ hid_t dxpl_id; /* DXPL to use for operation */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Iteration order within index */
+ hsize_t n; /* Offset within index */
+
+ /* upward */
+ H5G_loc_t *loc; /* Group location to set */
+} H5G_loc_fbi_t;
+
+/* User data for getting an object's info in a group */
+typedef struct {
+ /* downward */
+ hid_t dxpl_id; /* DXPL to use for operation */
+ hbool_t want_ih_info; /* Whether to retrieve the index & heap info */
+
+ /* upward */
+ H5O_info_t *oinfo; /* Object information to retrieve */
+} H5G_loc_info_t;
+
+/* User data for setting an object's comment in a group */
+typedef struct {
+ /* downward */
+ hid_t dxpl_id; /* DXPL to use for operation */
+ const char *comment; /* Object comment buffer */
+
+ /* upward */
+} H5G_loc_sc_t;
+
+/* User data for getting an object's comment in a group */
+typedef struct {
+ /* downward */
+ hid_t dxpl_id; /* DXPL to use for operation */
+ char *comment; /* Object comment buffer */
+ size_t bufsize; /* Size of object comment buffer */
+
+ /* upward */
+ ssize_t comment_size; /* Actual size of object comment */
+} H5G_loc_gc_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Group traversal callbacks */
+static herr_t H5G_loc_find_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata,
+ H5G_own_loc_t *own_loc);
+static herr_t H5G_loc_find_by_idx_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata,
+ H5G_own_loc_t *own_loc);
+static herr_t H5G_loc_set_comment_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata,
+ H5G_own_loc_t *own_loc);
+static herr_t H5G_loc_get_comment_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata,
+ H5G_own_loc_t *own_loc);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc
+ *
+ * Purpose: Given an object ID return a location for the object.
+ *
+ * Return: Success: Group pointer.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc(hid_t loc_id, H5G_loc_t *loc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ switch(H5I_get_type(loc_id)) {
+ case H5I_FILE:
+ {
+ H5F_t *f;
+
+ /* Get the file struct */
+ if(NULL == (f = (H5F_t *)H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file ID")
+
+ /* Construct a group location for root group of the file */
+ if(H5G_root_loc(f, loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file")
+ } /* end case */
+ break;
+
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of property list")
+
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of error class, message or stack")
+
+ case H5I_GROUP:
+ {
+ H5G_t *group;
+
+ if(NULL == (group = (H5G_t *)H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group ID")
+ if(NULL == (loc->oloc = H5G_oloc(group)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of group")
+ if(NULL == (loc->path = H5G_nameof(group)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of group")
+ } /* end case */
+ break;
+
+ case H5I_DATATYPE:
+ {
+ H5T_t *dt;
+
+ if(NULL == (dt = (H5T_t *)H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid type ID")
+ if(NULL == (loc->oloc = H5T_oloc(dt)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of datatype")
+ if(NULL == (loc->path = H5T_nameof(dt)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of datatype")
+ } /* end case */
+ break;
+
+ case H5I_DATASPACE:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of dataspace")
+
+ case H5I_DATASET:
+ {
+ H5D_t *dset;
+
+ if(NULL == (dset = (H5D_t *)H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid data ID")
+ if(NULL == (loc->oloc = H5D_oloc(dset)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of dataset")
+ if(NULL == (loc->path = H5D_nameof(dset)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of dataset")
+ } /* end case */
+ break;
+
+ case H5I_ATTR:
+ {
+ H5A_t *attr;
+
+ if(NULL == (attr = (H5A_t *)H5I_object(loc_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid attribute ID")
+ if(NULL == (loc->oloc = H5A_oloc(attr)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of attribute")
+ if(NULL == (loc->path = H5A_nameof(attr)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of attribute")
+ } /* end case */
+ break;
+
+ case H5I_REFERENCE:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of reference")
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_VFL:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object ID")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_copy
+ *
+ * Purpose: Copy over information for a location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_copy(H5G_loc_t *dst, const H5G_loc_t *src, H5_copy_depth_t depth)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(dst);
+ HDassert(src);
+
+ /* Copy components of the location */
+ if(H5O_loc_copy(dst->oloc, src->oloc, depth) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to copy entry")
+ if(H5G_name_copy(dst->path, src->path, depth) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to copy path")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_reset
+ *
+ * Purpose: Reset information for a location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_reset(H5G_loc_t *loc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+
+ /* Reset components of the location */
+ if(H5O_loc_reset(loc->oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset entry")
+ if(H5G_name_reset(loc->path) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset path")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_free
+ *
+ * Purpose: Free information for a location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_free(H5G_loc_t *loc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+
+ /* Reset components of the location */
+ if(H5G_name_free(loc->path) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to free path")
+ if(H5O_loc_free(loc->oloc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to free object header location")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_find_cb
+ *
+ * Purpose: Callback for retrieving object location for an object in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 17, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_find_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_fnd_t *udata = (H5G_loc_fnd_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid object */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object '%s' doesn't exist", name)
+
+ /* Take ownership of the object's group location */
+ /* (Group traversal callbacks are responsible for either taking ownership
+ * of the group location for the object, or freeing it. - QAK)
+ */
+ H5G_loc_copy(udata->loc, obj_loc, H5_COPY_SHALLOW);
+ *own_loc = H5G_OWN_OBJ_LOC;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_find_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_find
+ *
+ * Purpose: Find a symbol from a location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_find(const H5G_loc_t *loc, const char *name, H5G_loc_t *obj_loc/*out*/,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_fnd_t udata; /* User data for traversal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(obj_loc);
+
+ /* Set up user data for locating object */
+ udata.loc = obj_loc;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G_loc_find_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_find_by_idx_cb
+ *
+ * Purpose: Callback for retrieving object location for an object in a group
+ * according to the order within an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_find_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_fbi_t *udata = (H5G_loc_fbi_t *)_udata; /* User data passed in */
+ H5O_link_t fnd_lnk; /* Link within group */
+ hbool_t lnk_copied = FALSE; /* Whether the link was copied */
+ size_t links_left = H5L_NUM_LINKS; /* # of links left to traverse */
+ hbool_t obj_loc_valid = FALSE; /* Flag to indicate that the object location is valid */
+ hbool_t obj_exists = FALSE; /* Whether the object exists (unused) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Query link */
+ if(H5G_obj_lookup_by_idx(obj_loc->oloc, udata->idx_type, udata->order,
+ udata->n, &fnd_lnk, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "link not found")
+ lnk_copied = TRUE;
+
+ /* Build the initial object location for the link */
+ if(H5G__link_to_loc(obj_loc, &fnd_lnk, udata->loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot initialize object location")
+ obj_loc_valid = TRUE;
+
+ /* Perform any special traversals that the link needs */
+ /* (soft links, user-defined links, file mounting, etc.) */
+ /* (may modify the object location) */
+ if(H5G__traverse_special(obj_loc, &fnd_lnk, H5G_TARGET_NORMAL, &links_left, TRUE, udata->loc, &obj_exists, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "special link traversal failed")
+
+done:
+ /* Reset the link information, if we have a copy */
+ if(lnk_copied)
+ H5O_msg_reset(H5O_LINK_ID, &fnd_lnk);
+
+ /* Release the object location if we failed after copying it */
+ if(ret_value < 0 && obj_loc_valid)
+ if(H5G_loc_free(udata->loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_find_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_find_by_idx
+ *
+ * Purpose: Find a symbol from a location, according to the order in an index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 20, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_find_by_idx(H5G_loc_t *loc, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, H5G_loc_t *obj_loc/*out*/, hid_t lapl_id,
+ hid_t dxpl_id)
+{
+ H5G_loc_fbi_t udata; /* User data for traversal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(group_name && *group_name);
+ HDassert(obj_loc);
+
+ /* Set up user data for locating object */
+ udata.dxpl_id = dxpl_id;
+ udata.lapl_id = lapl_id;
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.n = n;
+ udata.loc = obj_loc;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, group_name, H5G_TARGET_NORMAL, H5G_loc_find_by_idx_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_find_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__loc_insert
+ *
+ * Purpose: Insert an object at a location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__loc_insert(H5G_loc_t *grp_loc, const char *name, H5G_loc_t *obj_loc,
+ H5O_type_t obj_type, const void *crt_info, hid_t dxpl_id)
+{
+ H5O_link_t lnk; /* Link for object to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args. */
+ HDassert(grp_loc);
+ HDassert(name && *name);
+ HDassert(obj_loc);
+
+ /* Create link object for the object location */
+ lnk.type = H5L_TYPE_HARD;
+ lnk.cset = H5F_DEFAULT_CSET;
+ lnk.corder = 0; /* Will be reset if the group is tracking creation order */
+ lnk.corder_valid = FALSE; /* Indicate that the creation order isn't valid (yet) */
+ /* Casting away const OK -QAK */
+ lnk.name = (char *)name;
+ lnk.u.hard.addr = obj_loc->oloc->addr;
+
+ /* Insert new group into current group's symbol table */
+ if(H5G_obj_insert(grp_loc->oloc, name, &lnk, TRUE, obj_type, crt_info,
+ dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert object")
+
+ /* Set the name of the object location */
+ if(H5G_name_set(grp_loc->path, obj_loc->path, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__loc_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_exists_cb
+ *
+ * Purpose: Callback for checking if an object exists
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 2, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_exists_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_exists_t *udata = (H5G_loc_exists_t *)_udata; /* User data passed in */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check if the name in this group resolved to a valid object */
+ if(obj_loc == NULL)
+ if(lnk)
+ udata->exists = FALSE;
+ else
+ udata->exists = FAIL;
+ else
+ udata->exists = TRUE;
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_loc_exists_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_exists
+ *
+ * Purpose: Check if an object actually exists at a location
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 2, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G_loc_exists(const H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_exists_t udata; /* User data for traversal callback */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up user data for locating object */
+ udata.exists = FALSE;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, H5G_TARGET_EXISTS, H5G_loc_exists_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't check if object exists")
+
+ /* Set return value */
+ ret_value = udata.exists;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_info_cb
+ *
+ * Purpose: Callback for retrieving object info for an object in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 23, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_info_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_info_t *udata = (H5G_loc_info_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Query object information */
+ if(H5O_get_info(obj_loc->oloc, udata->dxpl_id, udata->want_ih_info, udata->oinfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object info")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_info_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_info
+ *
+ * Purpose: Retrieve the information for an object from a group location
+ * and path to that object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 23, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_info(H5G_loc_t *loc, const char *name, hbool_t want_ih_info, H5O_info_t *oinfo/*out*/,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_info_t udata; /* User data for traversal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(oinfo);
+
+ /* Set up user data for locating object */
+ udata.dxpl_id = dxpl_id;
+ udata.want_ih_info = want_ih_info;
+ udata.oinfo = oinfo;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G_loc_info_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_set_comment_cb
+ *
+ * Purpose: Callback for (re)setting object comment for an object in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 30, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_set_comment_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_sc_t *udata = (H5G_loc_sc_t *)_udata; /* User data passed in */
+ H5O_name_t comment; /* Object header "comment" message */
+ htri_t exists; /* Whether a "comment" message already exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Check for existing comment message */
+ if((exists = H5O_msg_exists(obj_loc->oloc, H5O_NAME_ID, udata->dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header")
+
+ /* Remove the previous comment message if any */
+ if(exists)
+ if(H5O_msg_remove(obj_loc->oloc, H5O_NAME_ID, 0, TRUE, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete existing comment object header message")
+
+ /* Add the new message */
+ if(udata->comment && *udata->comment) {
+ /* Casting away const OK -QAK */
+ comment.s = (char *)udata->comment;
+ if(H5O_msg_create(obj_loc->oloc, H5O_NAME_ID, 0, H5O_UPDATE_TIME, &comment, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to set comment object header message")
+ } /* end if */
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_set_comment_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_set_comment
+ *
+ * Purpose: (Re)set the information for an object from a group location
+ * and path to that object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 30, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_loc_set_comment(H5G_loc_t *loc, const char *name, const char *comment,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_sc_t udata; /* User data for traversal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up user data for locating object */
+ udata.dxpl_id = dxpl_id;
+ udata.comment = comment;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G_loc_set_comment_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_set_comment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_get_comment_cb
+ *
+ * Purpose: Callback for retrieving object comment for an object in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 30, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_loc_get_comment_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_loc_gc_t *udata = (H5G_loc_gc_t *)_udata; /* User data passed in */
+ H5O_name_t comment; /* Object header "comment" message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Query object comment */
+ comment.s = NULL;
+ if(NULL == H5O_msg_read(obj_loc->oloc, H5O_NAME_ID, &comment, udata->dxpl_id)) {
+ if(udata->comment && udata->bufsize > 0)
+ udata->comment[0] = '\0';
+ udata->comment_size = 0;
+ } else {
+ if(udata->comment && udata->bufsize)
+ HDstrncpy(udata->comment, comment.s, udata->bufsize);
+ udata->comment_size = (ssize_t)HDstrlen(comment.s);
+ H5O_msg_reset(H5O_NAME_ID, &comment);
+ } /* end else */
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_get_comment_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_loc_get_comment
+ *
+ * Purpose: Retrieve the information for an object from a group location
+ * and path to that object
+ *
+ * Return: Success: Number of bytes in the comment excluding the
+ * null terminator. Zero if the object has no
+ * comment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 30, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G_loc_get_comment(H5G_loc_t *loc, const char *name, char *comment/*out*/,
+ size_t bufsize, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_gc_t udata; /* User data for traversal callback */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args. */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up user data for locating object */
+ udata.dxpl_id = dxpl_id;
+ udata.comment = comment;
+ udata.bufsize = bufsize;
+ udata.comment_size = (-1);
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G_loc_get_comment_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+ /* Set the return value */
+ ret_value = udata.comment_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_loc_get_comment() */
+
diff --git a/src/H5Gmodule.h b/src/H5Gmodule.h
new file mode 100644
index 0000000..19ea982
--- /dev/null
+++ b/src/H5Gmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5G package. Including this header means that the source file
+ * is part of the H5G package.
+ */
+#ifndef _H5Gmodule_H
+#define _H5Gmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5G_MODULE
+#define H5_MY_PKG H5G
+#define H5_MY_PKG_ERR H5E_SYM
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Gmodule_H */
+
diff --git a/src/H5Gname.c b/src/H5Gname.c
new file mode 100644
index 0000000..7b53668
--- /dev/null
+++ b/src/H5Gname.c
@@ -0,0 +1,1349 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gname.c
+ * Sep 12 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for handling group hierarchy paths.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory wrappers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Struct used by change name callback function */
+typedef struct H5G_names_t {
+ H5G_names_op_t op; /* Operation performed on file */
+ H5F_t *src_file; /* Top file in src location's mounted file hier. */
+ H5RS_str_t *src_full_path_r; /* Source location's full path */
+ H5F_t *dst_file; /* Destination location's file */
+ H5RS_str_t *dst_full_path_r; /* Destination location's full path */
+} H5G_names_t;
+
+/* Info to pass to the iteration function when building name */
+typedef struct H5G_gnba_iter_t {
+ /* In */
+ const H5O_loc_t *loc; /* The location of the object we're looking for */
+ hid_t lapl_id; /* LAPL for operations */
+ hid_t dxpl_id; /* DXPL for operations */
+
+ /* Out */
+ char *path; /* Name of the object */
+} H5G_gnba_iter_t;
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static htri_t H5G_common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r);
+static H5RS_str_t *H5G_build_fullpath(const char *prefix, const char *name);
+#ifdef NOT_YET
+static H5RS_str_t *H5G_build_fullpath_refstr_refstr(const H5RS_str_t *prefix_r, const H5RS_str_t *name_r);
+#endif /* NOT_YET */
+static herr_t H5G_name_move_path(H5RS_str_t **path_r_ptr,
+ const char *full_suffix, const char *src_path, const char *dst_path);
+static int H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare extern the PQ free list for the wrapped strings */
+H5FL_BLK_EXTERN(str_buf);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__component
+ *
+ * Purpose: Returns the pointer to the first component of the
+ * specified name by skipping leading slashes. Returns
+ * the size in characters of the component through SIZE_P not
+ * counting leading slashes or the null terminator.
+ *
+ * Return: Success: Ptr into NAME.
+ *
+ * Failure: Ptr to the null terminator of NAME.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+const char *
+H5G__component(const char *name, size_t *size_p)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(name);
+
+ while ('/' == *name)
+ name++;
+ if (size_p)
+ *size_p = HDstrcspn(name, "/");
+
+ FUNC_LEAVE_NOAPI(name)
+} /* end H5G__component() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_normalize
+ *
+ * Purpose: Returns a pointer to a new string which has duplicate and
+ * trailing slashes removed from it.
+ *
+ * Return: Success: Ptr to normalized name.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, August 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5G_normalize(const char *name)
+{
+ char *norm; /* Pointer to the normalized string */
+ size_t s,d; /* Positions within the strings */
+ unsigned last_slash; /* Flag to indicate last character was a slash */
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(name);
+
+ /* Duplicate the name, to return */
+ if(NULL == (norm = H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for normalized string")
+
+ /* Walk through the characters, omitting duplicated '/'s */
+ s = d = 0;
+ last_slash = 0;
+ while(name[s] != '\0') {
+ if(name[s] == '/')
+ if(last_slash)
+ ;
+ else {
+ norm[d++] = name[s];
+ last_slash = 1;
+ } /* end else */
+ else {
+ norm[d++] = name[s];
+ last_slash = 0;
+ } /* end else */
+ s++;
+ } /* end while */
+
+ /* Terminate normalized string */
+ norm[d] = '\0';
+
+ /* Check for final '/' on normalized name & eliminate it */
+ if(d > 1 && last_slash)
+ norm[d - 1] = '\0';
+
+ /* Set return value */
+ ret_value = norm;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_normalize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_common_path
+ *
+ * Purpose: Determine if one path is a valid prefix of another path
+ *
+ * Return: TRUE for valid prefix, FALSE for not a valid prefix, FAIL
+ * on error
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: September 24, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5G_common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r)
+{
+ const char *fullpath; /* Pointer to actual fullpath string */
+ const char *prefix; /* Pointer to actual prefix string */
+ size_t nchars1,nchars2; /* Number of characters in components */
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get component of each name */
+ fullpath=H5RS_get_str(fullpath_r);
+ HDassert(fullpath);
+ fullpath=H5G__component(fullpath,&nchars1);
+ HDassert(fullpath);
+ prefix=H5RS_get_str(prefix_r);
+ HDassert(prefix);
+ prefix=H5G__component(prefix,&nchars2);
+ HDassert(prefix);
+
+ /* Check if we have a real string for each component */
+ while(*fullpath && *prefix) {
+ /* Check that the components we found are the same length */
+ if(nchars1==nchars2) {
+ /* Check that the two components are equal */
+ if(HDstrncmp(fullpath,prefix,nchars1)==0) {
+ /* Advance the pointers in the names */
+ fullpath+=nchars1;
+ prefix+=nchars2;
+
+ /* Get next component of each name */
+ fullpath=H5G__component(fullpath,&nchars1);
+ HDassert(fullpath);
+ prefix=H5G__component(prefix,&nchars2);
+ HDassert(prefix);
+ } /* end if */
+ else
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else
+ HGOTO_DONE(FALSE)
+ } /* end while */
+
+ /* If we reached the end of the prefix path to check, it must be a valid prefix */
+ if(*prefix=='\0')
+ ret_value=TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_common_path() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_build_fullpath
+ *
+ * Purpose: Build a full path from a prefix & base pair of strings
+ *
+ * Return: Pointer to reference counted string on success, NULL on error
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: August 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5RS_str_t *
+H5G_build_fullpath(const char *prefix, const char *name)
+{
+ char *full_path; /* Full user path built */
+ size_t orig_path_len; /* Original length of the path */
+ size_t path_len; /* Length of the path */
+ size_t name_len; /* Length of the name */
+ unsigned need_sep; /* Flag to indicate if separator is needed */
+ H5RS_str_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(prefix);
+ HDassert(name);
+
+ /* Get the length of the prefix */
+ orig_path_len = path_len = HDstrlen(prefix);
+
+ /* Determine if there is a trailing separator in the name */
+ if(prefix[path_len - 1] == '/')
+ need_sep = 0;
+ else
+ need_sep = 1;
+
+ /* Add in the length needed for the '/' separator and the relative path */
+ name_len = HDstrlen(name);
+ path_len += name_len + need_sep;
+
+ /* Allocate space for the path */
+ if(NULL == (full_path = (char *)H5FL_BLK_MALLOC(str_buf, path_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Build full path */
+ HDstrncpy(full_path, prefix, orig_path_len + 1);
+ if(need_sep)
+ HDstrncat(full_path, "/", (size_t)1);
+ HDstrncat(full_path, name, name_len);
+
+ /* Create reference counted string for path */
+ if(NULL == (ret_value = H5RS_own(full_path)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_build_fullpath() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_build_fullpath_refstr_str
+ *
+ * Purpose: Append an object path to an existing ref-counted path
+ *
+ * Return: Success: Non-NULL, combined path
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ * Tuesday, October 11, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5RS_str_t *
+H5G_build_fullpath_refstr_str(H5RS_str_t *prefix_r, const char *name)
+{
+ const char *prefix; /* Pointer to raw string for path */
+ H5RS_str_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(prefix_r);
+ HDassert(name);
+
+ /* Get the raw string for the user path */
+ prefix = H5RS_get_str(prefix_r);
+ HDassert(prefix);
+
+ /* Create reference counted string for path */
+ ret_value = H5G_build_fullpath(prefix, name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_build_fullpath_refstr_str() */
+
+#ifdef NOT_YET
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_build_refstr_refstr
+ *
+ * Purpose: Build a full path from a prefix & base pair of reference counted
+ * strings
+ *
+ * Return: Pointer to reference counted string on success, NULL on error
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: August 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5RS_str_t *
+H5G_build_fullpath_refstr_refstr(const H5RS_str_t *prefix_r, const H5RS_str_t *name_r)
+{
+ const char *prefix; /* Pointer to raw string of prefix */
+ const char *name; /* Pointer to raw string of name */
+ H5RS_str_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get the pointer to the prefix */
+ prefix = H5RS_get_str(prefix_r);
+
+ /* Get the pointer to the raw src user path */
+ name = H5RS_get_str(name_r);
+
+ /* Create reference counted string for path */
+ ret_value = H5G_build_fullpath(prefix, name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_build_fullpath_refstr_refstr() */
+#endif /* NOT_YET */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__name_init
+ *
+ * Purpose: Set the initial path for a group hierarchy name
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__name_init(H5G_name_t *name, const char *path)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check arguments */
+ HDassert(name);
+
+ /* Set the initial paths for a name object */
+ name->full_path_r = H5RS_create(path);
+ HDassert(name->full_path_r);
+ name->user_path_r = H5RS_create(path);
+ HDassert(name->user_path_r);
+ name->obj_hidden = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__name_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_set
+ *
+ * Purpose: Set the name of a symbol entry OBJ, located at LOC
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * Thursday, August 22, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_name_set(const H5G_name_t *loc, H5G_name_t *obj, const char *name)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(loc);
+ HDassert(obj);
+ HDassert(name);
+
+ /* Free & reset the object's previous paths info (if they exist) */
+ H5G_name_free(obj);
+
+ /* Create the object's full path, if a full path exists in the location */
+ if(loc->full_path_r) {
+ /* Go build the new full path */
+ if((obj->full_path_r = H5G_build_fullpath_refstr_str(loc->full_path_r, name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name")
+ } /* end if */
+
+ /* Create the object's user path, if a user path exists in the location */
+ if(loc->user_path_r) {
+ /* Go build the new user path */
+ if((obj->user_path_r = H5G_build_fullpath_refstr_str(loc->user_path_r, name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_name_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_copy
+ *
+ * Purpose: Do a copy of group hier. names
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ * Notes: 'depth' parameter determines how much of the group entry
+ * structure we want to copy. The depths are:
+ * H5_COPY_SHALLOW - Copy all the fields from the source
+ * to the destination, including the user path and
+ * canonical path. (Destination "takes ownership" of
+ * user and canonical paths)
+ * H5_COPY_DEEP - Copy all the fields from the source to
+ * the destination, deep copying the user and canonical
+ * paths.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5_copy_depth_t depth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(src);
+ HDassert(dst);
+#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
+ HDassert(dst->full_path_r == NULL);
+ HDassert(dst->user_path_r == NULL);
+#endif /* H5_USING_MEMCHECKER */
+ HDassert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP);
+
+ /* Copy the top level information */
+ HDmemcpy(dst, src, sizeof(H5G_name_t));
+
+ /* Deep copy the names */
+ if(depth == H5_COPY_DEEP) {
+ dst->full_path_r = H5RS_dup(src->full_path_r);
+ dst->user_path_r = H5RS_dup(src->user_path_r);
+ } else {
+ /* Discarding 'const' qualifier OK - QAK */
+ H5G_name_reset((H5G_name_t *)src);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_name_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_name
+ *
+ * Purpose: Gets a name of an object from its ID.
+ *
+ * Notes: Internal routine for H5Iget_name().
+
+ * Return: Success: Non-negative, length of name
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 13, 2005
+ *
+ * Modifications: Leon Arber
+ * Oct. 18, 2006
+ * Added functionality to get the name for a reference.
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G_get_name(const H5G_loc_t *loc, char *name/*out*/, size_t size,
+ hbool_t *cached, hid_t lapl_id, hid_t dxpl_id)
+{
+ ssize_t len = 0; /* Length of object's name */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(loc);
+
+ /* If the user path is available and it's not "hidden", use it */
+ if(loc->path->user_path_r != NULL && loc->path->obj_hidden == 0) {
+ len = H5RS_len(loc->path->user_path_r);
+
+ if(name) {
+ HDstrncpy(name, H5RS_get_str(loc->path->user_path_r), MIN((size_t)(len + 1), size));
+ if((size_t)len >= size)
+ name[size - 1] = '\0';
+ } /* end if */
+
+ /* Indicate that the name is cached, if requested */
+ /* (Currently only used for testing - QAK, 2010/07/26) */
+ if(cached)
+ *cached = TRUE;
+ } /* end if */
+ else if(!loc->path->obj_hidden) {
+ hid_t file;
+
+ /* Retrieve file ID for name search */
+ if((file = H5F_get_id(loc->oloc->file, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get file ID")
+
+ /* Search for name of object */
+ if((len = H5G_get_name_by_addr(file, lapl_id, dxpl_id, loc->oloc, name, size)) < 0) {
+ H5I_dec_ref(file);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine name")
+ } /* end if */
+
+ /* Close file ID used for search */
+ if(H5I_dec_ref(file) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCLOSEFILE, FAIL, "can't determine name")
+
+ /* Indicate that the name is _not_ cached, if requested */
+ /* (Currently only used for testing - QAK, 2010/07/26) */
+ if(cached)
+ *cached = FALSE;
+ } /* end else */
+
+ /* Set return value */
+ ret_value = len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_reset
+ *
+ * Purpose: Reset a group hierarchy name to an empty state
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_name_reset(H5G_name_t *name)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(name);
+
+ /* Clear the group hier. name to an empty state */
+ HDmemset(name, 0, sizeof(H5G_name_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_name_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_free
+ *
+ * Purpose: Free the 'ID to name' buffers.
+ *
+ * Return: Success
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ *
+ * Date: August 22, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_name_free(H5G_name_t *name)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(name);
+
+ if(name->full_path_r) {
+ H5RS_decr(name->full_path_r);
+ name->full_path_r = NULL;
+ } /* end if */
+ if(name->user_path_r) {
+ H5RS_decr(name->user_path_r);
+ name->user_path_r = NULL;
+ } /* end if */
+ name->obj_hidden = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_name_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_move_path
+ *
+ * Purpose: Update a user or canonical path after an object moves
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_name_move_path(H5RS_str_t **path_r_ptr, const char *full_suffix, const char *src_path,
+ const char *dst_path)
+{
+ const char *path; /* Path to update */
+ size_t path_len; /* Length of path */
+ size_t full_suffix_len; /* Length of full suffix */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(path_r_ptr && *path_r_ptr);
+ HDassert(full_suffix);
+ HDassert(src_path);
+ HDassert(dst_path);
+
+ /* Get pointer to path to update */
+ path = H5RS_get_str(*path_r_ptr);
+ HDassert(path);
+
+ /* Check if path needs to be updated */
+ full_suffix_len = HDstrlen(full_suffix);
+ path_len = HDstrlen(path);
+ if(full_suffix_len < path_len) {
+ const char *dst_suffix; /* Destination suffix that changes */
+ size_t dst_suffix_len; /* Length of destination suffix */
+ const char *src_suffix; /* Source suffix that changes */
+ size_t path_prefix_len; /* Length of path prefix */
+ const char *path_prefix2; /* 2nd prefix for path */
+ size_t path_prefix2_len; /* Length of 2nd path prefix */
+ const char *common_prefix; /* Common prefix for src & dst paths */
+ size_t common_prefix_len; /* Length of common prefix */
+ char *new_path; /* Pointer to new path */
+ size_t new_path_len; /* Length of new path */
+
+
+ /* Compute path prefix before full suffix*/
+ path_prefix_len = path_len - full_suffix_len;
+
+ /* Determine the common prefix for src & dst paths */
+ common_prefix = src_path;
+ common_prefix_len = 0;
+ /* Find first character that is different */
+ while(*(src_path + common_prefix_len) == *(dst_path + common_prefix_len))
+ common_prefix_len++;
+ /* Back up to previous '/' */
+ while(*(common_prefix + common_prefix_len) != '/')
+ common_prefix_len--;
+ /* Include '/' */
+ common_prefix_len++;
+
+ /* Determine source suffix */
+ src_suffix = src_path + (common_prefix_len - 1);
+
+ /* Determine destination suffix */
+ dst_suffix = dst_path + (common_prefix_len - 1);
+ dst_suffix_len = HDstrlen(dst_suffix);
+
+ /* Compute path prefix before src suffix*/
+ path_prefix2 = path;
+ path_prefix2_len = path_prefix_len - HDstrlen(src_suffix);
+
+ /* Allocate space for the new path */
+ new_path_len = path_prefix2_len + dst_suffix_len + full_suffix_len;
+ if(NULL == (new_path = (char *)H5FL_BLK_MALLOC(str_buf, new_path_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the new path */
+ if(path_prefix2_len > 0) {
+ HDstrncpy(new_path, path_prefix2, path_prefix2_len + 1);
+ HDstrncpy(new_path + path_prefix2_len, dst_suffix, dst_suffix_len + 1);
+ } /* end if */
+ else
+ HDstrncpy(new_path, dst_suffix, dst_suffix_len + 1);
+ if(full_suffix_len > 0)
+ HDstrncat(new_path, full_suffix, full_suffix_len);
+
+ /* Release previous path */
+ H5RS_decr(*path_r_ptr);
+
+ /* Take ownership of the new full path */
+ *path_r_ptr = H5RS_own(new_path);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_name_move_path() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_replace_cb
+ *
+ * Purpose: H5I_iterate callback function to replace group entry names
+ *
+ * Return: Success: 0, Failure: -1
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ *
+ * Date: June 5, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key)
+{
+ const H5G_names_t *names = (const H5G_names_t *)key; /* Get operation's information */
+ H5O_loc_t *oloc; /* Object location for object that the ID refers to */
+ H5G_name_t *obj_path; /* Pointer to group hier. path for obj */
+ H5F_t *top_obj_file; /* Top file in object's mounted file hier. */
+ hbool_t obj_in_child = FALSE; /* Flag to indicate that the object is in the child mount hier. */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(obj_ptr);
+
+ /* Get the symbol table entry */
+ switch(H5I_get_type(obj_id)) {
+ case H5I_GROUP:
+ oloc = H5G_oloc((H5G_t *)obj_ptr);
+ obj_path = H5G_nameof((H5G_t *)obj_ptr);
+ break;
+
+ case H5I_DATASET:
+ oloc = H5D_oloc((H5D_t *)obj_ptr);
+ obj_path = H5D_nameof((H5D_t *)obj_ptr);
+ break;
+
+ case H5I_DATATYPE:
+ /* Avoid non-named datatypes */
+ if(!H5T_is_named((H5T_t *)obj_ptr))
+ HGOTO_DONE(SUCCEED) /* Do not exit search over IDs */
+
+ oloc = H5T_oloc((H5T_t *)obj_ptr);
+ obj_path = H5T_nameof((H5T_t *)obj_ptr);
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object")
+ } /* end switch */
+ HDassert(oloc);
+ HDassert(obj_path);
+
+ /* Check if the object has a full path still */
+ if(!obj_path->full_path_r)
+ HGOTO_DONE(SUCCEED) /* No need to look at object, it's path is already invalid */
+
+ /* Find the top file in object's mount hier. */
+ if(H5F_PARENT(oloc->file)) {
+ /* Check if object is in child file (for mount & unmount operations) */
+ if(names->dst_file && H5F_SAME_SHARED(oloc->file, names->dst_file))
+ obj_in_child = TRUE;
+
+ /* Find the "top" file in the chain of mounted files */
+ top_obj_file = H5F_PARENT(oloc->file);
+ while(H5F_PARENT(top_obj_file) != NULL) {
+ /* Check if object is in child mount hier. (for mount & unmount operations) */
+ if(names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file))
+ obj_in_child = TRUE;
+
+ top_obj_file = H5F_PARENT(top_obj_file);
+ } /* end while */
+ } /* end if */
+ else
+ top_obj_file = oloc->file;
+
+ /* Check if object is in top of child mount hier. (for mount & unmount operations) */
+ if(names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file))
+ obj_in_child = TRUE;
+
+ /* Check if the object is in same file mount hier. */
+ if(!H5F_SAME_SHARED(top_obj_file, names->src_file))
+ HGOTO_DONE(SUCCEED) /* No need to look at object, it's path is already invalid */
+
+ switch(names->op) {
+ /*-------------------------------------------------------------------------
+ * H5G_NAME_MOUNT
+ *-------------------------------------------------------------------------
+ */
+ case H5G_NAME_MOUNT:
+ /* Check if object is in child mount hier. */
+ if(obj_in_child) {
+ const char *full_path; /* Full path of current object */
+ const char *src_path; /* Full path of source object */
+ size_t src_path_len; /* Length of source full path */
+ char *new_full_path; /* New full path of object */
+ size_t new_full_len; /* Length of new full path */
+
+ /* Get pointers to paths of interest */
+ full_path = H5RS_get_str(obj_path->full_path_r);
+ src_path = H5RS_get_str(names->src_full_path_r);
+ src_path_len = HDstrlen(src_path);
+
+ /* Build new full path */
+
+ /* Allocate space for the new full path */
+ new_full_len = src_path_len + HDstrlen(full_path);
+ if(NULL == (new_full_path = (char *)H5FL_BLK_MALLOC(str_buf, new_full_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the new full path */
+ HDstrncpy(new_full_path, src_path, src_path_len + 1);
+ HDstrncat(new_full_path, full_path, new_full_len);
+
+ /* Release previous full path */
+ H5RS_decr(obj_path->full_path_r);
+
+ /* Take ownership of the new full path */
+ obj_path->full_path_r = H5RS_own(new_full_path);
+ } /* end if */
+ /* Object must be in parent mount file hier. */
+ else {
+ /* Check if the source is along the entry's path */
+ /* (But not actually the entry itself) */
+ if(H5G_common_path(obj_path->full_path_r, names->src_full_path_r) &&
+ H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) {
+ /* Hide the user path */
+ (obj_path->obj_hidden)++;
+ } /* end if */
+ } /* end else */
+ break;
+
+ /*-------------------------------------------------------------------------
+ * H5G_NAME_UNMOUNT
+ *-------------------------------------------------------------------------
+ */
+ case H5G_NAME_UNMOUNT:
+ if(obj_in_child) {
+ const char *full_path; /* Full path of current object */
+ const char *full_suffix; /* Full path after source path */
+ size_t full_suffix_len; /* Length of full path after source path */
+ const char *src_path; /* Full path of source object */
+ char *new_full_path; /* New full path of object */
+
+ /* Get pointers to paths of interest */
+ full_path = H5RS_get_str(obj_path->full_path_r);
+ src_path = H5RS_get_str(names->src_full_path_r);
+
+ /* Construct full path suffix */
+ full_suffix = full_path + HDstrlen(src_path);
+ full_suffix_len = HDstrlen(full_suffix);
+
+ /* Build new full path */
+
+ /* Create the new full path */
+ if(NULL == (new_full_path = (char *)H5FL_BLK_MALLOC(str_buf, full_suffix_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDstrncpy(new_full_path, full_suffix, full_suffix_len + 1);
+
+ /* Release previous full path */
+ H5RS_decr(obj_path->full_path_r);
+
+ /* Take ownership of the new full path */
+ obj_path->full_path_r = H5RS_own(new_full_path);
+
+ /* Check if the object's user path should be invalidated */
+ if(obj_path->user_path_r && HDstrlen(new_full_path) < (size_t)H5RS_len(obj_path->user_path_r)) {
+ /* Free user path */
+ H5RS_decr(obj_path->user_path_r);
+ obj_path->user_path_r = NULL;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Check if file being unmounted was hiding the object */
+ if(H5G_common_path(obj_path->full_path_r, names->src_full_path_r) &&
+ H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) {
+ /* Un-hide the user path */
+ (obj_path->obj_hidden)--;
+ } /* end if */
+ } /* end else */
+ break;
+
+ /*-------------------------------------------------------------------------
+ * H5G_NAME_DELETE
+ *-------------------------------------------------------------------------
+ */
+ case H5G_NAME_DELETE:
+ /* Check if the location being unlinked is in the path for the current object */
+ if(H5G_common_path(obj_path->full_path_r, names->src_full_path_r)) {
+ /* Free paths for object */
+ H5G_name_free(obj_path);
+ } /* end if */
+ break;
+
+ /*-------------------------------------------------------------------------
+ * H5G_NAME_MOVE
+ *-------------------------------------------------------------------------
+ */
+ case H5G_NAME_MOVE: /* Link move case, check for relative names case */
+ /* Check if the src object moved is in the current object's path */
+ if(H5G_common_path(obj_path->full_path_r, names->src_full_path_r)) {
+ const char *full_path; /* Full path of current object */
+ const char *full_suffix; /* Suffix of full path, after src_path */
+ size_t full_suffix_len; /* Length of suffix of full path after src_path*/
+ char *new_full_path; /* New full path of object */
+ size_t new_full_len; /* Length of new full path */
+ const char *src_path; /* Full path of source object */
+ const char *dst_path; /* Full path of destination object */
+ size_t dst_path_len; /* Length of destination's full path */
+
+ /* Sanity check */
+ HDassert(names->dst_full_path_r);
+
+ /* Get pointers to paths of interest */
+ full_path = H5RS_get_str(obj_path->full_path_r);
+ src_path = H5RS_get_str(names->src_full_path_r);
+ dst_path = H5RS_get_str(names->dst_full_path_r);
+ dst_path_len = HDstrlen(dst_path);
+
+ /* Make certain that the source and destination names are full (not relative) paths */
+ HDassert(*src_path == '/');
+ HDassert(*dst_path == '/');
+
+ /* Get pointer to "full suffix" */
+ full_suffix = full_path + HDstrlen(src_path);
+ full_suffix_len = HDstrlen(full_suffix);
+
+ /* Update the user path, if one exists */
+ if(obj_path->user_path_r)
+ if(H5G_name_move_path(&(obj_path->user_path_r), full_suffix, src_path, dst_path) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name")
+
+ /* Build new full path */
+
+ /* Allocate space for the new full path */
+ new_full_len = dst_path_len + full_suffix_len;
+ if(NULL == (new_full_path = (char *)H5FL_BLK_MALLOC(str_buf, new_full_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the new full path */
+ HDstrncpy(new_full_path, dst_path, dst_path_len + 1);
+ HDstrncat(new_full_path, full_suffix, full_suffix_len);
+
+ /* Release previous full path */
+ H5RS_decr(obj_path->full_path_r);
+
+ /* Take ownership of the new full path */
+ obj_path->full_path_r = H5RS_own(new_full_path);
+ } /* end if */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid operation")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5G_name_replace_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_name_replace
+ *
+ * Purpose: Search the list of open IDs and replace names according to a
+ * particular operation. The operation occured on the
+ * SRC_FILE/SRC_FULL_PATH_R object. The new name (if there is
+ * one) is NEW_NAME_R. Additional entry location information
+ * (currently only needed for the 'move' operation) is passed in
+ * DST_FILE/DST_FULL_PATH_R.
+ *
+ * Return: Success: 0, Failure: -1
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ *
+ * Date: June 11, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_name_replace(const H5O_link_t *lnk, H5G_names_op_t op, H5F_t *src_file,
+ H5RS_str_t *src_full_path_r, H5F_t *dst_file, H5RS_str_t *dst_full_path_r,
+ hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ HDassert(src_file);
+
+ /* Check if the object we are manipulating has a path */
+ if(src_full_path_r) {
+ hbool_t search_group = FALSE; /* Flag to indicate that groups are to be searched */
+ hbool_t search_dataset = FALSE; /* Flag to indicate that datasets are to be searched */
+ hbool_t search_datatype = FALSE; /* Flag to indicate that datatypes are to be searched */
+
+ /* Check for particular link to operate on */
+ if(lnk) {
+ /* Look up the object type for each type of link */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ {
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+ H5O_type_t obj_type; /* Type of object at location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = src_file;
+ tmp_oloc.addr = lnk->u.hard.addr;
+
+ /* Get the type of the object */
+ if(H5O_obj_type(&tmp_oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object type")
+
+ /* Determine which type of objects to operate on */
+ switch(obj_type) {
+ case H5O_TYPE_GROUP:
+ /* Search and replace names through group IDs */
+ search_group = TRUE;
+ break;
+
+ case H5O_TYPE_DATASET:
+ /* Search and replace names through dataset IDs */
+ search_dataset = TRUE;
+ break;
+
+ case H5O_TYPE_NAMED_DATATYPE:
+ /* Search and replace names through datatype IDs */
+ search_datatype = TRUE;
+ break;
+
+ case H5O_TYPE_UNKNOWN:
+ case H5O_TYPE_NTYPES:
+ /* Search and replace names through datatype IDs */
+ default:
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "not valid object type")
+ } /* end switch */
+ } /* end case */
+ break;
+
+ case H5L_TYPE_SOFT:
+ /* Symbolic links might resolve to any object, so we need to search all IDs */
+ search_group = search_dataset = search_datatype = TRUE;
+ break;
+
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_MAX:
+ default: /* User-defined link */
+ /* Check for unknown library-defined link type */
+ if(lnk->type < H5L_TYPE_UD_MIN)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown link type")
+
+ /* User-defined & external links automatically wipe out
+ * names (because it would be too much work to track them),
+ * so there's no point in searching them.
+ */
+ break;
+ } /* end switch */
+ } /* end if */
+ else {
+ /* We pass NULL as link pointer when we need to search all IDs */
+ search_group = search_dataset = search_datatype = TRUE;
+ } /* end else */
+
+ /* Check if we need to operate on the objects affected */
+ if(search_group || search_dataset || search_datatype) {
+ H5G_names_t names; /* Structure to hold operation information for callback */
+
+ /* Find top file in src location's mount hierarchy */
+ while(H5F_PARENT(src_file))
+ src_file = H5F_PARENT(src_file);
+
+ /* Set up common information for callback */
+ names.src_file = src_file;
+ names.src_full_path_r = src_full_path_r;
+ names.dst_file = dst_file;
+ names.dst_full_path_r = dst_full_path_r;
+ names.op = op;
+
+ /* Search through group IDs */
+ if(search_group)
+ if(H5I_iterate(H5I_GROUP, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over groups")
+
+ /* Search through dataset IDs */
+ if(search_dataset)
+ if(H5I_iterate(H5I_DATASET, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datasets")
+
+ /* Search through datatype IDs */
+ if(search_datatype)
+ if(H5I_iterate(H5I_DATATYPE, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datatypes")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_name_replace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_name_by_addr_cb
+ *
+ * Purpose: Callback for retrieving object's name by address
+ *
+ * Return: Positive if path is for object desired
+ * 0 if not correct object
+ * negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * November 4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_get_name_by_addr_cb(hid_t gid, const char *path, const H5L_info_t *linfo,
+ void *_udata)
+{
+ H5G_gnba_iter_t *udata = (H5G_gnba_iter_t *)_udata; /* User data for iteration */
+ H5G_loc_t obj_loc; /* Location of object */
+ H5G_name_t obj_path; /* Object's group hier. path */
+ H5O_loc_t obj_oloc; /* Object's object location */
+ hbool_t obj_found = FALSE; /* Object at 'path' found */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(path);
+ HDassert(linfo);
+ HDassert(udata->loc);
+ HDassert(udata->path == NULL);
+
+ /* Check for hard link with correct address */
+ if(linfo->type == H5L_TYPE_HARD && udata->loc->addr == linfo->u.address) {
+ H5G_loc_t grp_loc; /* Location of group */
+
+ /* Get group's location */
+ if(H5G_loc(gid, &grp_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "bad group location")
+
+ /* Set up opened object location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object */
+ if(H5G_loc_find(&grp_loc, path, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+ obj_found = TRUE;
+
+ /* Check for object in same file (handles mounted files) */
+ /* (re-verify address, in case we traversed a file mount) */
+ if(udata->loc->addr == obj_loc.oloc->addr && udata->loc->file == obj_loc.oloc->file) {
+ if(NULL == (udata->path = H5MM_strdup(path)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, H5_ITER_ERROR, "can't duplicate path string")
+
+ /* We found a match so we return immediately */
+ HGOTO_DONE(H5_ITER_STOP)
+ } /* end if */
+ } /* end if */
+
+done:
+ if(obj_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_name_by_addr_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_get_name_by_addr
+ *
+ * Purpose: Tries to figure out the path to an object from it's address
+ *
+ * Return: returns size of path name, and copies it into buffer
+ * pointed to by name if that buffer is big enough.
+ * 0 if it cannot find the path
+ * negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * November 4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G_get_name_by_addr(hid_t file, hid_t lapl_id, hid_t dxpl_id, const H5O_loc_t *loc,
+ char *name, size_t size)
+{
+ H5G_gnba_iter_t udata; /* User data for iteration */
+ H5G_loc_t root_loc; /* Root group's location */
+ hbool_t found_obj = FALSE; /* If we found the object */
+ herr_t status; /* Status from iteration */
+ ssize_t ret_value = -1; /* Return value */
+
+ /* Portably clear udata struct (before FUNC_ENTER) */
+ HDmemset(&udata, 0, sizeof(udata));
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Construct the link info for the file's root group */
+ if(H5G_loc(file, &root_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get root group's location")
+
+ /* Check for root group being the object looked for */
+ if(root_loc.oloc->addr == loc->addr && root_loc.oloc->file == loc->file) {
+ if(NULL == (udata.path = H5MM_strdup("")))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "can't duplicate path string")
+ found_obj = TRUE;
+ } /* end if */
+ else {
+ /* Set up user data for iterator */
+ udata.loc = loc;
+ udata.lapl_id = lapl_id;
+ udata.dxpl_id = dxpl_id;
+ udata.path = NULL;
+
+ /* Visit all the links in the file */
+ if((status = H5G_visit(file, "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5G_get_name_by_addr_cb, &udata, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group traversal failed while looking for object name")
+ else if(status > 0)
+ found_obj = TRUE;
+ } /* end else */
+
+ /* Check for finding the object */
+ if(found_obj) {
+ /* Set the length of the full path */
+ ret_value = (ssize_t)(HDstrlen(udata.path) + 1); /* Length of path + 1 (for "/") */
+
+ /* If there's a buffer provided, copy into it, up to the limit of its size */
+ if(name) {
+ /* Copy the initial path separator */
+ HDstrncpy(name, "/", (size_t)2);
+
+ /* Append the rest of the path */
+ /* (less one character, for the initial path separator) */
+ HDstrncat(name, udata.path, (size - 2));
+ if((size_t)ret_value >= size)
+ name[size - 1] = '\0';
+ } /* end if */
+ } /* end if */
+ else
+ ret_value = 0;
+
+done:
+ /* Release resources */
+ H5MM_xfree(udata.path);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_get_name_by_addr() */
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
new file mode 100644
index 0000000..20924ee
--- /dev/null
+++ b/src/H5Gnode.c
@@ -0,0 +1,1580 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gnode.c
+ * Jun 26 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Functions for handling symbol table nodes. A
+ * symbol table node is a small collection of symbol
+ * table entries. A B-tree usually points to the
+ * symbol table nodes for any given symbol table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/*
+ * Each key field of the B-link tree that points to symbol table
+ * nodes consists of this structure...
+ */
+typedef struct H5G_node_key_t {
+ size_t offset; /*offset into heap for name */
+} H5G_node_key_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* B-tree callbacks */
+static H5UC_t *H5G_node_get_shared(const H5F_t *f, const void *_udata);
+static herr_t H5G_node_create(H5F_t *f, hid_t dxpl_id, H5B_ins_t op, void *_lt_key,
+ void *_udata, void *_rt_key,
+ haddr_t *addr_p/*out*/);
+static int H5G_node_cmp2(void *_lt_key, void *_udata, void *_rt_key);
+static int H5G_node_cmp3(void *_lt_key, void *_udata, void *_rt_key);
+static htri_t H5G_node_found(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_lt_key,
+ void *_udata);
+static H5B_ins_t H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key,
+ hbool_t *lt_key_changed, void *_md_key,
+ void *_udata, void *_rt_key,
+ hbool_t *rt_key_changed,
+ haddr_t *new_node_p/*out*/);
+static H5B_ins_t H5G_node_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *lt_key,
+ hbool_t *lt_key_changed, void *udata,
+ void *rt_key, hbool_t *rt_key_changed);
+static herr_t H5G_node_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key);
+static herr_t H5G_node_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key);
+static herr_t H5G_node_debug_key(FILE *stream, int indent, int fwidth,
+ const void *key, const void *udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5G inherits B-tree like properties from H5B */
+H5B_class_t H5B_SNODE[1] = {{
+ H5B_SNODE_ID, /*id */
+ sizeof(H5G_node_key_t), /*sizeof_nkey */
+ H5G_node_get_shared, /*get_shared */
+ H5G_node_create, /*new */
+ H5G_node_cmp2, /*cmp2 */
+ H5G_node_cmp3, /*cmp3 */
+ H5G_node_found, /*found */
+ H5G_node_insert, /*insert */
+ TRUE, /*follow min branch? */
+ TRUE, /*follow max branch? */
+ H5B_RIGHT, /*critical key */
+ H5G_node_remove, /*remove */
+ H5G_node_decode_key, /*decode */
+ H5G_node_encode_key, /*encode */
+ H5G_node_debug_key /*debug */
+}};
+
+/* Declare a free list to manage the H5G_node_t struct */
+H5FL_DEFINE(H5G_node_t);
+
+/* Declare a free list to manage sequences of H5G_entry_t's */
+H5FL_SEQ_DEFINE(H5G_entry_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_get_shared
+ *
+ * Purpose: Returns the shared B-tree info for the specified UDATA.
+ *
+ * Return: Success: Pointer to the raw B-tree page for this
+ file's groups
+ *
+ * Failure: Can't fail
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5UC_t *
+H5G_node_get_shared(const H5F_t *f, const void H5_ATTR_UNUSED *_udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+
+ /* Return the pointer to the ref-count object */
+ FUNC_LEAVE_NOAPI(H5F_GRP_BTREE_SHARED(f))
+} /* end H5G_node_get_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_decode_key
+ *
+ * Purpose: Decodes a raw key into a native key.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 8 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_node_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key)
+{
+ H5G_node_key_t *key = (H5G_node_key_t *) _key;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(shared);
+ HDassert(raw);
+ HDassert(key);
+
+ H5F_DECODE_LENGTH_LEN(raw, key->offset, shared->sizeof_len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_node_decode_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_encode_key
+ *
+ * Purpose: Encodes a native key into a raw key.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 8 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_node_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key)
+{
+ const H5G_node_key_t *key = (const H5G_node_key_t *) _key;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(shared);
+ HDassert(raw);
+ HDassert(key);
+
+ H5F_ENCODE_LENGTH_LEN(raw, key->offset, shared->sizeof_len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_node_encode_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_debug_key
+ *
+ * Purpose: Prints a key.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 28, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_node_debug_key(FILE *stream, int indent, int fwidth, const void *_key,
+ const void *_udata)
+{
+ const H5G_node_key_t *key = (const H5G_node_key_t *) _key;
+ const H5G_bt_common_t *udata = (const H5G_bt_common_t *) _udata;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(key);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Heap offset:",
+ (unsigned)key->offset);
+
+ if(udata->heap) {
+ const char *s;
+
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Name:");
+
+ s = (const char *)H5HL_offset_into(udata->heap, key->offset);
+ HDfprintf(stream, "%s\n", s);
+ } /* end if */
+ else
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Cannot get name; heap address not specified\n");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_node_debug_key() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_free
+ *
+ * Purpose: Destroy a symbol table node in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 15 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__node_free(H5G_node_t *sym)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sym);
+
+ /* Verify that node is clean */
+ HDassert(sym->cache_info.is_dirty == FALSE);
+
+ if(sym->entry)
+ sym->entry = H5FL_SEQ_FREE(H5G_entry_t, sym->entry);
+ sym = H5FL_FREE(H5G_node_t, sym);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__node_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_create
+ *
+ * Purpose: Creates a new empty symbol table node. This function is
+ * called by the B-tree insert function for an empty tree. It
+ * is also called internally to split a symbol node with LT_KEY
+ * and RT_KEY null pointers.
+ *
+ * Return: Success: Non-negative. The address of symbol table
+ * node is returned through the ADDR_P argument.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_node_create(H5F_t *f, hid_t dxpl_id, H5B_ins_t H5_ATTR_UNUSED op, void *_lt_key,
+ void H5_ATTR_UNUSED *_udata, void *_rt_key, haddr_t *addr_p/*out*/)
+{
+ H5G_node_key_t *lt_key = (H5G_node_key_t *)_lt_key;
+ H5G_node_key_t *rt_key = (H5G_node_key_t *)_rt_key;
+ H5G_node_t *sym = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5B_INS_FIRST == op);
+
+ if(NULL == (sym = H5FL_CALLOC(H5G_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ sym->node_size = H5G_NODE_SIZE(f);
+ if(HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, dxpl_id, (hsize_t)sym->node_size)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to allocate file space")
+ if(NULL == (sym->entry = H5FL_SEQ_CALLOC(H5G_entry_t, (size_t)(2 * H5F_SYM_LEAF_K(f)))))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_SNODE, *addr_p, sym, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to cache symbol table leaf node")
+ /*
+ * The left and right symbols in an empty tree are both the
+ * empty string stored at offset zero by the H5G functions. This
+ * allows the comparison functions to work correctly without knowing
+ * that there are no symbols.
+ */
+ if(lt_key)
+ lt_key->offset = 0;
+ if(rt_key)
+ rt_key->offset = 0;
+
+done:
+ if(ret_value < 0) {
+ if(sym != NULL) {
+ if(sym->entry != NULL)
+ sym->entry = H5FL_SEQ_FREE(H5G_entry_t, sym->entry);
+ sym = H5FL_FREE(H5G_node_t, sym);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_cmp2
+ *
+ * Purpose: Compares two keys from a B-tree node (LT_KEY and RT_KEY).
+ * The UDATA pointer supplies extra data not contained in the
+ * keys (in this case, the heap address).
+ *
+ * Return: Success: negative if LT_KEY is less than RT_KEY.
+ *
+ * positive if LT_KEY is greater than RT_KEY.
+ *
+ * zero if LT_KEY and RT_KEY are equal.
+ *
+ * Failure: FAIL (same as LT_KEY<RT_KEY)
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_node_cmp2(void *_lt_key, void *_udata, void *_rt_key)
+{
+ H5G_bt_common_t *udata = (H5G_bt_common_t *) _udata;
+ H5G_node_key_t *lt_key = (H5G_node_key_t *) _lt_key;
+ H5G_node_key_t *rt_key = (H5G_node_key_t *) _rt_key;
+ const char *s1, *s2;
+ const char *base; /* Base of heap */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(udata && udata->heap);
+ HDassert(lt_key);
+ HDassert(rt_key);
+
+ /* Get base address of heap */
+ base = (const char *)H5HL_offset_into(udata->heap, (size_t)0);
+ HDassert(base);
+
+ /* Get pointers to string names */
+ s1 = base + lt_key->offset;
+ s2 = base + rt_key->offset;
+
+ /* Set return value */
+ ret_value = HDstrcmp(s1, s2);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G_node_cmp2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_cmp3
+ *
+ * Purpose: Compares two keys from a B-tree node (LT_KEY and RT_KEY)
+ * against another key (not necessarily the same type)
+ * pointed to by UDATA.
+ *
+ * Return: Success: negative if the UDATA key is less than
+ * or equal to the LT_KEY
+ *
+ * positive if the UDATA key is greater
+ * than the RT_KEY.
+ *
+ * zero if the UDATA key falls between
+ * the LT_KEY (exclusive) and the
+ * RT_KEY (inclusive).
+ *
+ * Failure: FAIL (same as UDATA < LT_KEY)
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_node_cmp3(void *_lt_key, void *_udata, void *_rt_key)
+{
+ H5G_bt_common_t *udata = (H5G_bt_common_t *) _udata;
+ H5G_node_key_t *lt_key = (H5G_node_key_t *) _lt_key;
+ H5G_node_key_t *rt_key = (H5G_node_key_t *) _rt_key;
+ const char *s;
+ const char *base; /* Base of heap */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(udata && udata->heap);
+ HDassert(lt_key);
+ HDassert(rt_key);
+
+ /* Get base address of heap */
+ base = (const char *)H5HL_offset_into(udata->heap, (size_t)0);
+ HDassert(base);
+
+ /* left side */
+ s = base + lt_key->offset;
+ if(HDstrcmp(udata->name, s) <= 0)
+ ret_value = (-1);
+ else {
+ /* right side */
+ s = base + rt_key->offset;
+ if(HDstrcmp(udata->name, s) > 0)
+ ret_value = 1;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_cmp3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_found
+ *
+ * Purpose: The B-tree search engine has found the symbol table node
+ * which contains the requested symbol if the symbol exists.
+ * This function should examine that node for the symbol and
+ * return information about the symbol through the UDATA
+ * structure which contains the symbol name on function
+ * entry.
+ *
+ * If the operation flag in UDATA is H5G_OPER_FIND, then
+ * the entry is copied from the symbol table to the UDATA
+ * entry field. Otherwise the entry is copied from the
+ * UDATA entry field to the symbol table.
+ *
+ * Return: Success: Non-negative (TRUE/FALSE) if found and data
+ * returned through the UDATA pointer.
+ *
+ * Failure: Negative if not found.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 23 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5G_node_found(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void H5_ATTR_UNUSED *_lt_key,
+ void *_udata)
+{
+ H5G_bt_lkp_t *udata = (H5G_bt_lkp_t *)_udata;
+ H5G_node_t *sn = NULL;
+ unsigned lt = 0, idx = 0, rt;
+ int cmp = 1;
+ const char *s;
+ const char *base; /* Base of heap */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata && udata->common.heap);
+
+ /*
+ * Load the symbol table node for exclusive access.
+ */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table node")
+
+ /* Get base address of heap */
+ base = (const char *)H5HL_offset_into(udata->common.heap, (size_t)0);
+ HDassert(base);
+
+ /*
+ * Binary search.
+ */
+ rt = sn->nsyms;
+ while(lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+ s = base + sn->entry[idx].name_off;
+ cmp = HDstrcmp(udata->common.name, s);
+
+ if (cmp < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+
+ if(cmp)
+ HGOTO_DONE(FALSE)
+
+ /* Call user's callback operator */
+ if((udata->op)(&sn->entry[idx], udata->op_data) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iterator callback failed")
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to release symbol table node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_insert
+ *
+ * Purpose: The B-tree insertion engine has found the symbol table node
+ * which should receive the new symbol/address pair. This
+ * function adds it to that node unless it already existed.
+ *
+ * If the node has no room for the symbol then the node is
+ * split into two nodes. The original node contains the
+ * low values and the new node contains the high values.
+ * The new symbol table entry is added to either node as
+ * appropriate. When a split occurs, this function will
+ * write the maximum key of the low node to the MID buffer
+ * and return the address of the new node.
+ *
+ * If the new key is larger than RIGHT then update RIGHT
+ * with the new key.
+ *
+ * Return: Success: An insertion command for the caller, one of
+ * the H5B_INS_* constants. The address of the
+ * new node, if any, is returned through the
+ * NEW_NODE_P argument. NEW_NODE_P might not be
+ * initialized if the return value is
+ * H5B_INS_NOOP.
+ *
+ * Failure: H5B_INS_ERROR, NEW_NODE_P might not be
+ * initialized.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 24 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ void H5_ATTR_UNUSED *_lt_key, hbool_t H5_ATTR_UNUSED *lt_key_changed,
+ void *_md_key, void *_udata,
+ void *_rt_key, hbool_t *rt_key_changed,
+ haddr_t *new_node_p)
+{
+ H5G_node_key_t *md_key = (H5G_node_key_t *) _md_key;
+ H5G_node_key_t *rt_key = (H5G_node_key_t *) _rt_key;
+ H5G_bt_ins_t *udata = (H5G_bt_ins_t *) _udata;
+ H5G_node_t *sn = NULL, *snrt = NULL;
+ unsigned sn_flags = H5AC__NO_FLAGS_SET, snrt_flags = H5AC__NO_FLAGS_SET;
+ const char *s;
+ const char *base; /* Base of heap */
+ unsigned lt = 0, rt; /* Binary search cntrs */
+ int cmp = 1, idx = -1;
+ H5G_node_t *insert_into = NULL; /*node that gets new entry*/
+ H5G_entry_t ent; /* Entry to insert in node */
+ H5B_ins_t ret_value = H5B_INS_ERROR;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(md_key);
+ HDassert(rt_key);
+ HDassert(udata && udata->common.heap);
+ HDassert(new_node_p);
+
+ /*
+ * Load the symbol node.
+ */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node")
+
+ /* Get base address of heap */
+ base = (const char *)H5HL_offset_into(udata->common.heap, (size_t)0);
+ HDassert(base);
+
+ /*
+ * Where does the new symbol get inserted? We use a binary search.
+ */
+ rt = sn->nsyms;
+ while(lt < rt) {
+ idx = (int)((lt + rt) / 2);
+ s = base + sn->entry[idx].name_off;
+
+ /* Check if symbol is already present */
+ if(0 == (cmp = HDstrcmp(udata->common.name, s)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5B_INS_ERROR, "symbol is already present in symbol table")
+
+ if (cmp < 0)
+ rt = (unsigned)idx;
+ else
+ lt = (unsigned)(idx + 1);
+ } /* end while */
+ idx += cmp > 0 ? 1 : 0;
+
+ /* Convert link information & name to symbol table entry */
+ if(H5G__ent_convert(f, dxpl_id, udata->common.heap, udata->common.name,
+ udata->lnk, udata->obj_type, udata->crt_info, &ent) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5B_INS_ERROR, "unable to convert link")
+
+ /* Determine where to place entry in node */
+ if(sn->nsyms >= 2 * H5F_SYM_LEAF_K(f)) {
+ /*
+ * The node is full. Split it into a left and right
+ * node and return the address of the new right node (the
+ * left node is at the same address as the original node).
+ */
+ ret_value = H5B_INS_RIGHT;
+
+ /* The right node */
+ if(H5G_node_create(f, dxpl_id, H5B_INS_FIRST, NULL, NULL, NULL, new_node_p/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to split symbol table node")
+
+ if(NULL == (snrt = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, *new_node_p, f, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to split symbol table node")
+
+ HDmemcpy(snrt->entry, sn->entry + H5F_SYM_LEAF_K(f),
+ H5F_SYM_LEAF_K(f) * sizeof(H5G_entry_t));
+ snrt->nsyms = H5F_SYM_LEAF_K(f);
+ snrt_flags |= H5AC__DIRTIED_FLAG;
+
+ /* The left node */
+ HDmemset(sn->entry + H5F_SYM_LEAF_K(f), 0,
+ H5F_SYM_LEAF_K(f) * sizeof(H5G_entry_t));
+ sn->nsyms = H5F_SYM_LEAF_K(f);
+ sn_flags |= H5AC__DIRTIED_FLAG;
+
+ /* The middle key */
+ md_key->offset = sn->entry[sn->nsyms - 1].name_off;
+
+ /* Where to insert the new entry? */
+ if(idx <= (int)H5F_SYM_LEAF_K(f)) {
+ insert_into = sn;
+ if(idx == (int)H5F_SYM_LEAF_K(f))
+ md_key->offset = ent.name_off;
+ } /* end if */
+ else {
+ idx -= (int)H5F_SYM_LEAF_K(f);
+ insert_into = snrt;
+ if(idx == (int)H5F_SYM_LEAF_K(f)) {
+ rt_key->offset = ent.name_off;
+ *rt_key_changed = TRUE;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Where to insert the new entry? */
+ ret_value = H5B_INS_NOOP;
+ sn_flags |= H5AC__DIRTIED_FLAG;
+ insert_into = sn;
+ if(idx == (int)sn->nsyms) {
+ rt_key->offset = ent.name_off;
+ *rt_key_changed = TRUE;
+ } /* end if */
+ } /* end else */
+
+ /* Move entries down to make room for new entry */
+ HDassert(idx >= 0);
+ HDmemmove(insert_into->entry + idx + 1, insert_into->entry + idx,
+ (insert_into->nsyms - (unsigned)idx) * sizeof(H5G_entry_t));
+
+ /* Copy new entry into table */
+ H5G__ent_copy(&(insert_into->entry[idx]), &ent, H5_COPY_SHALLOW);
+
+ /* Increment # of symbols in table */
+ insert_into->nsyms += 1;
+
+done:
+ if(snrt && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, *new_node_p, snrt, snrt_flags) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node")
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, sn_flags) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_remove
+ *
+ * Purpose: The B-tree removal engine has found the symbol table node
+ * which should contain the name which is being removed. This
+ * function removes the name from the symbol table and
+ * decrements the link count on the object to which the name
+ * points.
+ *
+ * If the udata->name parameter is set to NULL, then remove
+ * all entries in this symbol table node. This only occurs
+ * during the deletion of the entire group, so don't bother
+ * freeing individual name entries in the local heap, the group's
+ * symbol table removal code will just free the entire local
+ * heap eventually. Do reduce the link counts for each object
+ * however.
+ *
+ * Return: Success: If all names are removed from the symbol
+ * table node then H5B_INS_REMOVE is returned;
+ * otherwise H5B_INS_NOOP is returned.
+ *
+ * Failure: H5B_INS_ERROR
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 24, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_ins_t
+H5G_node_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key/*in,out*/,
+ hbool_t H5_ATTR_UNUSED *lt_key_changed/*out*/,
+ void *_udata/*in,out*/, void *_rt_key/*in,out*/,
+ hbool_t *rt_key_changed/*out*/)
+{
+ H5G_node_key_t *lt_key = (H5G_node_key_t *)_lt_key;
+ H5G_node_key_t *rt_key = (H5G_node_key_t *)_rt_key;
+ H5G_bt_rm_t *udata = (H5G_bt_rm_t *)_udata;
+ H5G_node_t *sn = NULL;
+ unsigned sn_flags = H5AC__NO_FLAGS_SET;
+ unsigned lt = 0, rt, idx = 0;
+ int cmp = 1;
+ H5B_ins_t ret_value = H5B_INS_ERROR;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(lt_key);
+ HDassert(rt_key);
+ HDassert(udata && udata->common.heap);
+
+ /* Load the symbol table */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node")
+
+ /* "Normal" removal of a single entry from the symbol table node */
+ if(udata->common.name != NULL) {
+ H5O_link_t lnk; /* Constructed link for replacement */
+ size_t link_name_len; /* Length of string in local heap */
+ const char *base; /* Base of heap */
+
+ /* Get base address of heap */
+ base = (const char *)H5HL_offset_into(udata->common.heap, (size_t)0);
+
+ /* Find the name with a binary search */
+ rt = sn->nsyms;
+ while(lt < rt && cmp) {
+ const char *s; /* Pointer to string in local heap */
+
+ idx = (lt + rt) / 2;
+ s = base + sn->entry[idx].name_off;
+ cmp = HDstrcmp(udata->common.name, s);
+ if(cmp < 0)
+ rt = idx;
+ else
+ lt = idx + 1;
+ } /* end while */
+
+ if(cmp)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5B_INS_ERROR, "name not found")
+
+ /* Get a pointer to the name of the link */
+ if(NULL == (lnk.name = (char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].name_off)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get link name")
+ link_name_len = HDstrlen(lnk.name) + 1;
+
+ /* Set up rest of link structure */
+ lnk.corder_valid = FALSE;
+ lnk.corder = 0;
+ lnk.cset = H5T_CSET_ASCII;
+ if(sn->entry[idx].type == H5G_CACHED_SLINK) {
+ lnk.type = H5L_TYPE_SOFT;
+ lnk.u.soft.name = (char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].cache.slink.lval_offset);
+ } /* end if */
+ else {
+ lnk.type = H5L_TYPE_HARD;
+ HDassert(H5F_addr_defined(sn->entry[idx].header));
+ lnk.u.hard.addr = sn->entry[idx].header;
+ } /* end else */
+
+ /* Replace any object names */
+ if(H5G__link_name_replace(f, dxpl_id, udata->grp_full_path_r, &lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get object type")
+
+ /* Decrement the ref. count for hard links */
+ if(lnk.type == H5L_TYPE_HARD) {
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = f;
+ tmp_oloc.addr = lnk.u.hard.addr;
+
+ if(H5O_link(&tmp_oloc, -1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to decrement object link count")
+ } /* end if */
+ else {
+ /* Remove the soft link's value from the local heap */
+ if(lnk.u.soft.name) {
+ size_t soft_link_len; /* Length of string in local heap */
+
+ soft_link_len = HDstrlen(lnk.u.soft.name) + 1;
+ if(H5HL_remove(f, dxpl_id, udata->common.heap, sn->entry[idx].cache.slink.lval_offset, soft_link_len) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to remove soft link from local heap")
+ } /* end if */
+ } /* end else */
+
+ /* Remove the link's name from the local heap */
+ if(H5HL_remove(f, dxpl_id, udata->common.heap, sn->entry[idx].name_off, link_name_len) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to remove link name from local heap")
+
+ /* Remove the entry from the symbol table node */
+ if(1 == sn->nsyms) {
+ /*
+ * We are about to remove the only symbol in this node. Free this
+ * node and indicate that the pointer to this node in the B-tree
+ * should be removed also.
+ */
+ HDassert(0 == idx);
+ sn->nsyms = 0;
+ sn_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+ ret_value = H5B_INS_REMOVE;
+ } else if(0 == idx) {
+ /*
+ * We are about to remove the left-most entry from the symbol table
+ * node but there are other entries to the right. No key values
+ * change.
+ */
+ sn->nsyms -= 1;
+ sn_flags |= H5AC__DIRTIED_FLAG;
+ HDmemmove(sn->entry + idx, sn->entry + idx + 1,
+ (sn->nsyms-idx) * sizeof(H5G_entry_t));
+ ret_value = H5B_INS_NOOP;
+ } else if (idx + 1 == sn->nsyms) {
+ /*
+ * We are about to remove the right-most entry from the symbol table
+ * node but there are other entries to the left. The right key
+ * should be changed to reflect the new right-most entry.
+ */
+ sn->nsyms -= 1;
+ sn_flags |= H5AC__DIRTIED_FLAG;
+ rt_key->offset = sn->entry[sn->nsyms - 1].name_off;
+ *rt_key_changed = TRUE;
+ ret_value = H5B_INS_NOOP;
+ } else {
+ /*
+ * We are about to remove an entry from the middle of a symbol table
+ * node.
+ */
+ sn->nsyms -= 1;
+ sn_flags |= H5AC__DIRTIED_FLAG;
+ HDmemmove(sn->entry + idx, sn->entry + idx + 1,
+ (sn->nsyms - idx) * sizeof(H5G_entry_t));
+ ret_value = H5B_INS_NOOP;
+ } /* end else */
+ } /* end if */
+ /* Remove all entries from node, during B-tree deletion */
+ else {
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = f;
+
+ /* Reduce the link count for all entries in this node */
+ for(idx = 0; idx < sn->nsyms; idx++) {
+ if(!(H5G_CACHED_SLINK == sn->entry[idx].type)) {
+ /* Decrement the reference count */
+ HDassert(H5F_addr_defined(sn->entry[idx].header));
+ tmp_oloc.addr = sn->entry[idx].header;
+
+ if(H5O_link(&tmp_oloc, -1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to decrement object link count")
+ } /* end if */
+ } /* end for */
+
+ /*
+ * We are about to remove all the symbols in this node. Free this
+ * node and indicate that the pointer to this node in the B-tree
+ * should be removed also.
+ */
+ sn->nsyms = 0;
+ sn_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+ ret_value = H5B_INS_REMOVE;
+ } /* end else */
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, sn_flags) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_iterate
+ *
+ * Purpose: This function gets called during a group iterate operation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 24 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G__node_iterate(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ H5G_bt_it_it_t *udata = (H5G_bt_it_it_t *)_udata;
+ H5G_node_t *sn = NULL;
+ H5G_entry_t *ents; /* Pointer to entries in this node */
+ unsigned u; /* Local index variable */
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata && udata->heap);
+
+ /* Protect the symbol table node & local heap while we iterate over entries */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node")
+
+ /*
+ * Iterate over the symbol table node entries.
+ */
+ for(u = 0, ents = sn->entry; u < sn->nsyms && ret_value == H5_ITER_CONT; u++) {
+ if(udata->skip > 0)
+ --udata->skip;
+ else {
+ H5O_link_t lnk; /* Link for entry */
+ const char *name; /* Pointer to link name in heap */
+
+ /* Get the pointer to the name of the link in the heap */
+ name = (const char *)H5HL_offset_into(udata->heap, ents[u].name_off);
+ HDassert(name);
+
+ /* Convert the entry to a link */
+ if(H5G__ent_to_link(&lnk, udata->heap, &ents[u], name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR, "unable to convert symbol table entry to link")
+
+ /* Make the callback */
+ ret_value = (udata->op)(&lnk, udata->op_data);
+
+ /* Release memory for link object */
+ if(H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, H5_ITER_ERROR, "unable to release link message")
+ } /* end else */
+
+ /* Increment the number of entries passed through */
+ /* (whether we skipped them or not) */
+ if(udata->final_ent)
+ (*udata->final_ent)++;
+ } /* end for */
+ if(ret_value < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+
+done:
+ /* Release resources */
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_sumup
+ *
+ * Purpose: This function gets called during a group iterate operation
+ * to return total number of members in the group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G__node_sumup(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ hsize_t *num_objs = (hsize_t *)_udata;
+ H5G_node_t *sn = NULL;
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(num_objs);
+
+ /* Find the object node and add the number of symbol entries. */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node")
+
+ *num_objs += sn->nsyms;
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_sumup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_by_idx
+ *
+ * Purpose: This function gets called during a group iterate operation
+ * to return object name by giving idx.
+ *
+ * Return: 0 if object isn't found in this node; 1 if object is found;
+ * Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G__node_by_idx(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ H5G_bt_it_idx_common_t *udata = (H5G_bt_it_idx_common_t *)_udata;
+ H5G_node_t *sn = NULL;
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+
+ /* Get a pointer to the symbol table node */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node");
+
+ /* Find the node, locate the object symbol table entry and retrieve the name */
+ if(udata->idx >= udata->num_objs && udata->idx < (udata->num_objs + sn->nsyms)) {
+ hsize_t ent_idx; /* Entry index in this node */
+
+ /* Compute index of entry */
+ ent_idx = udata->idx - udata->num_objs;
+
+ /* Call 'by index' callback */
+ HDassert(udata->op);
+ if((udata->op)(&sn->entry[ent_idx], udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "'by index' callback failed")
+
+ /* Indicate that we found the entry we are interested in */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+ else
+ udata->num_objs += sn->nsyms;
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_init
+ *
+ * Purpose: This function gets called during a file opening to initialize
+ * global information about group B-tree nodes for file.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Jul 5, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__node_init(H5F_t *f)
+{
+ H5B_shared_t *shared; /* Shared B-tree node info */
+ size_t sizeof_rkey; /* Size of raw (disk) key */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(f);
+
+ /* Set the raw key size */
+ sizeof_rkey = H5F_SIZEOF_SIZE(f); /*name offset */
+
+ /* Allocate & initialize global info for the shared structure */
+ if(NULL == (shared = H5B_shared_new(f, H5B_SNODE, sizeof_rkey)))
+ HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed for shared B-tree info")
+
+ /* Set up the "local" information for this file's groups */
+ /* <none> */
+
+ /* Make shared B-tree info reference counted */
+ if(H5F_SET_GRP_BTREE_SHARED(f, H5UC_create(shared, H5B_shared_free)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create ref-count wrapper for shared B-tree info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_close
+ *
+ * Purpose: This function gets called during a file close to shutdown
+ * global information about group B-tree nodes for file.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Jul 5, 2004
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_node_close(const H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(f);
+
+ /* Free the raw B-tree node buffer */
+ if(H5F_GRP_BTREE_SHARED(f))
+ H5UC_DEC(H5F_GRP_BTREE_SHARED(f));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_node_close */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_copy
+ *
+ * Purpose: This function gets called during a group iterate operation
+ * to copy objects of this node into a new location.
+ *
+ * Return: 0(zero) on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * Sept 10, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G__node_copy(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ H5G_bt_it_cpy_t *udata = (H5G_bt_it_cpy_t *)_udata;
+ const H5O_loc_t *src_oloc = udata->src_oloc;
+ H5O_copy_t *cpy_info = udata->cpy_info;
+ H5HL_t *heap = NULL;
+ H5G_node_t *sn = NULL;
+ unsigned int i; /* Local index variable */
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+
+ /* load the symbol table into memory from the source file */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node")
+
+ /* get the base address of the heap */
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, udata->src_heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "unable to protect symbol name")
+
+ /* copy object in this node one by one */
+ for(i = 0; i < sn->nsyms; i++) {
+ H5G_entry_t *src_ent = &(sn->entry[i]); /* Convenience variable to refer to current source group entry */
+ H5O_link_t lnk; /* Link to insert */
+ const char *name; /* Name of source object */
+ H5G_entry_t tmp_src_ent; /* Temperary copy. Change will not affect the cache */
+ H5O_type_t obj_type = H5O_TYPE_UNKNOWN; /* Target object type */
+ H5G_copy_file_ud_t *cpy_udata; /* Copy file udata */
+ H5G_obj_create_t gcrt_info; /* Group creation info */
+
+ /* expand soft link */
+ if(H5G_CACHED_SLINK == src_ent->type && cpy_info->expand_soft_link) {
+ H5O_info_t oinfo; /* Information about object pointed to by soft link */
+ H5G_loc_t grp_loc; /* Group location holding soft link */
+ H5G_name_t grp_path; /* Path for group holding soft link */
+ char *link_name; /* Pointer to value of soft link */
+
+ /* Make a temporary copy, so that it will not change the info in the cache */
+ HDmemcpy(&tmp_src_ent, src_ent, sizeof(H5G_entry_t));
+
+ /* Set up group location for soft link to start in */
+ H5G_name_reset(&grp_path);
+ grp_loc.path = &grp_path;
+ grp_loc.oloc = (H5O_loc_t *)src_oloc;
+
+ /* Get pointer to link value in local heap */
+ link_name = (char *)H5HL_offset_into(heap, tmp_src_ent.cache.slink.lval_offset);
+
+ /* Check if the object pointed by the soft link exists in the source file */
+ if(H5G_loc_info(&grp_loc, link_name, FALSE, &oinfo, H5P_DEFAULT, dxpl_id) >= 0) {
+ tmp_src_ent.header = oinfo.addr;
+ src_ent = &tmp_src_ent;
+ } /* end if */
+ else
+ H5E_clear_stack(NULL); /* discard any errors from a dangling soft link */
+ } /* if ((H5G_CACHED_SLINK == src_ent->type)... */
+
+ /* Check if object in source group is a hard link */
+ if(H5F_addr_defined(src_ent->header)) {
+ H5O_loc_t new_dst_oloc; /* Copied object location in destination */
+ H5O_loc_t tmp_src_oloc; /* Temporary object location for source object */
+
+ /* Set up copied object location to fill in */
+ H5O_loc_reset(&new_dst_oloc);
+ new_dst_oloc.file = udata->dst_file;
+
+ /* Build temporary object location for source */
+ H5O_loc_reset(&tmp_src_oloc);
+ tmp_src_oloc.file = f;
+ tmp_src_oloc.addr = src_ent->header;
+
+ /* Copy the shared object from source to destination */
+ if(H5O_copy_header_map(&tmp_src_oloc, &new_dst_oloc, dxpl_id,
+ cpy_info, TRUE, &obj_type, (void **)&cpy_udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy object")
+
+ /* Set up object creation info for symbol table insertion. Only
+ * case so far is for inserting old-style groups (for caching stab
+ * info). */
+ if(obj_type == H5O_TYPE_GROUP) {
+ gcrt_info.gcpl_id = H5P_DEFAULT;
+ gcrt_info.cache_type = cpy_udata->cache_type;
+ gcrt_info.cache = cpy_udata->cache;
+ } /* end if */
+
+ /* Construct link information for eventual insertion */
+ lnk.type = H5L_TYPE_HARD;
+ lnk.u.hard.addr = new_dst_oloc.addr;
+ } /* ( H5F_addr_defined(src_ent->header)) */
+ else if(H5G_CACHED_SLINK == src_ent->type) {
+ /* it is a soft link */
+ /* Set object type to unknown */
+ obj_type = H5O_TYPE_UNKNOWN;
+
+ /* Construct link information for eventual insertion */
+ lnk.type = H5L_TYPE_SOFT;
+ lnk.u.soft.name = (char *)H5HL_offset_into(heap, src_ent->cache.slink.lval_offset);
+ } /* else if */
+ else
+ HDassert(0 && "Unknown entry type");
+
+ /* Set up common link data */
+ lnk.cset = H5F_DEFAULT_CSET; /* XXX: Allow user to set this */
+ lnk.corder = 0; /* Creation order is not tracked for old-style links */
+ lnk.corder_valid = FALSE; /* Creation order is not valid */
+ /* lnk.name = name; */ /* This will be set in callback */
+
+ /* Determine name of source object */
+ name = (const char *)H5HL_offset_into(heap, src_ent->name_off);
+ HDassert(name);
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(dxpl_id, H5AC__COPIED_TAG, H5_ITER_ERROR);
+
+ /* Insert the new object in the destination file's group */
+ /* (Don't increment the link count - that's already done above for hard links) */
+ if(H5G__stab_insert_real(udata->dst_file, udata->dst_stab, name, &lnk,
+ obj_type, (obj_type == H5O_TYPE_GROUP ? &gcrt_info : NULL),
+ dxpl_id) < 0)
+ HGOTO_ERROR_TAG(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "unable to insert the name")
+
+ /* Reset metadata tag */
+ H5_END_TAG(H5_ITER_ERROR);
+
+ } /* end of for (i=0; i<sn->nsyms; i++) */
+
+done:
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to unprotect symbol name")
+
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_build_table
+ *
+ * Purpose: B-link tree callback for building table of links
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 19 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5G__node_build_table(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ H5G_bt_it_bt_t *udata = (H5G_bt_it_bt_t *)_udata;
+ H5G_node_t *sn = NULL; /* Symbol table node */
+ unsigned u; /* Local index variable */
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata && udata->heap);
+
+ /*
+ * Save information about the symbol table node since we can't lock it
+ * because we're about to call an application function.
+ */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node")
+
+ /* Check if the link table needs to be extended */
+ if((udata->ltable->nlinks + sn->nsyms) >= udata->alloc_nlinks) {
+ size_t na = MAX((udata->ltable->nlinks + sn->nsyms), (udata->alloc_nlinks * 2)); /* Double # of links allocated */
+ H5O_link_t *x; /* Pointer to larger array of links */
+
+ /* Re-allocate the link table */
+ if(NULL == (x = (H5O_link_t *)H5MM_realloc(udata->ltable->lnks, sizeof(H5O_link_t) * na)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed")
+ udata->ltable->lnks = x;
+ } /* end if */
+
+ /* Iterate over the symbol table node entries, adding to link table */
+ for(u = 0; u < sn->nsyms; u++) {
+ const char *name; /* Pointer to link name in heap */
+ size_t linkno; /* Link allocated */
+
+ /* Get pointer to link's name in the heap */
+ name = (const char *)H5HL_offset_into(udata->heap, sn->entry[u].name_off);
+ HDassert(name);
+
+ /* Determine the link to operate on in the table */
+ linkno = udata->ltable->nlinks++;
+
+ /* Convert the entry to a link */
+ if(H5G__ent_to_link(&udata->ltable->lnks[linkno], udata->heap, &sn->entry[u], name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR, "unable to convert symbol table entry to link")
+ } /* end for */
+
+done:
+ /* Release the locked items */
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__node_build_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__node_iterate_size
+ *
+ * Purpose: This function gets called by H5B_iterate_helper()
+ * to gather storage info for SNODs.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * Jun 19 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__node_iterate_size(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, const void H5_ATTR_UNUSED *_lt_key, haddr_t H5_ATTR_UNUSED addr,
+ const void H5_ATTR_UNUSED *_rt_key, void *_udata)
+{
+ hsize_t *stab_size = (hsize_t *)_udata; /* User data */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(stab_size);
+
+ *stab_size += H5G_NODE_SIZE(f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G__node_iterate_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_node_debug
+ *
+ * Purpose: Prints debugging information about a symbol table node
+ * or a B-tree node for a symbol table B-tree.
+ *
+ * Return: 0(zero) on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 4 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent,
+ int fwidth, haddr_t heap_addr)
+{
+ H5G_node_t *sn = NULL;
+ H5HL_t *heap = NULL;
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Pin the heap down in memory */
+ if(heap_addr > 0 && H5F_addr_defined(heap_addr))
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table heap")
+
+ /*
+ * If we couldn't load the symbol table node, then try loading the
+ * B-tree node.
+ */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) {
+ H5G_bt_common_t udata; /*data to pass through B-tree */
+
+ H5E_clear_stack(NULL); /* discard that error */
+ udata.heap = heap;
+ if(H5B_debug(f, dxpl_id, addr, stream, indent, fwidth, H5B_SNODE, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to debug B-tree node");
+ } /* end if */
+ else {
+ fprintf(stream, "%*sSymbol Table Node...\n", indent, "");
+ fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Dirty:",
+ sn->cache_info.is_dirty ? "Yes" : "No");
+ fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Size of Node (in bytes):", (unsigned)sn->node_size);
+ fprintf(stream, "%*s%-*s %u of %u\n", indent, "", fwidth,
+ "Number of Symbols:",
+ sn->nsyms, (unsigned)(2 * H5F_SYM_LEAF_K(f)));
+
+ indent += 3;
+ fwidth = MAX(0, fwidth - 3);
+ for(u = 0; u < sn->nsyms; u++) {
+ fprintf(stream, "%*sSymbol %u:\n", indent - 3, "", u);
+
+ if(heap) {
+ const char *s = (const char *)H5HL_offset_into(heap, sn->entry[u].name_off);
+
+ if(s)
+ fprintf(stream, "%*s%-*s `%s'\n", indent, "", fwidth, "Name:", s);
+ } /* end if */
+ else
+ fprintf(stream, "%*s%-*s\n", indent, "", fwidth, "Warning: Invalid heap address given, name not displayed!");
+
+ H5G__ent_debug(sn->entry + u, stream, indent, fwidth, heap);
+ } /* end for */
+ } /* end if */
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to release symbol table node")
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_node_debug() */
+
diff --git a/src/H5Gobj.c b/src/H5Gobj.c
new file mode 100644
index 0000000..d2dc83b
--- /dev/null
+++ b/src/H5Gobj.c
@@ -0,0 +1,1227 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gobj.c
+ * Sep 5 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for abstract handling of objects in groups.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for object header iterator when converting link messages to dense
+ * link storage
+ */
+typedef struct {
+ H5F_t *f; /* Pointer to file for insertion */
+ haddr_t oh_addr; /* Address of the object header */
+ hid_t dxpl_id; /* DXPL during insertion */
+ H5O_linfo_t *linfo; /* Pointer to link info */
+} H5G_obj_oh_it_ud1_t;
+
+/* User data for link iterator when converting dense link storage to link
+ * messages
+ */
+typedef struct {
+ H5O_link_t *lnk_table; /* Array of links to convert */
+ size_t nlinks; /* Number of links converted */
+ size_t alloc_links; /* Size of link table */
+} H5G_obj_lnk_it_ud1_t;
+
+/* User data for symbol table iterator when converting old-format group to
+ * a new-format group
+ */
+typedef struct {
+ const H5O_loc_t *grp_oloc; /* Pointer to group for insertion */
+ hid_t dxpl_id; /* DXPL during insertion */
+} H5G_obj_stab_it_ud1_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5G_obj_compact_to_dense_cb(const void *_mesg, unsigned idx,
+ void *_udata);
+static herr_t H5G_obj_remove_update_linfo(const H5O_loc_t *oloc, H5O_linfo_t *linfo,
+ hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_create
+ *
+ * Purpose: Create an object header for a group and update object location info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__obj_create(H5F_t *f, hid_t dxpl_id, H5G_obj_create_t *gcrt_info,
+ H5O_loc_t *oloc/*out*/)
+{
+ H5P_genplist_t *gc_plist; /* Group creation property list */
+ H5O_ginfo_t ginfo; /* Group info */
+ H5O_linfo_t linfo; /* Link info */
+ H5O_pline_t pline; /* Pipeline */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(oloc);
+
+ /* Get the property list */
+ if(NULL == (gc_plist = (H5P_genplist_t *)H5I_object(gcrt_info->gcpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the group info property */
+ if(H5P_get(gc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Get the link info property */
+ if(H5P_get(gc_plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Get the pipeline property */
+ if(H5P_peek(gc_plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Call the "real" group creation routine now */
+ if(H5G__obj_create_real(f, dxpl_id, &ginfo, &linfo, &pline, gcrt_info, oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "unable to create group")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__obj_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_create_real
+ *
+ * Purpose: Create an object header for a group and update object location info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__obj_create_real(H5F_t *f, hid_t dxpl_id, const H5O_ginfo_t *ginfo,
+ const H5O_linfo_t *linfo, const H5O_pline_t *pline,
+ H5G_obj_create_t *gcrt_info, H5O_loc_t *oloc/*out*/)
+{
+ size_t hdr_size; /* Size of object header to request */
+ hbool_t use_latest_format; /* Flag indicating the new group format should be used */
+ hid_t gcpl_id = gcrt_info->gcpl_id; /* Group creation property list ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ginfo);
+ HDassert(linfo);
+ HDassert(pline);
+ HDassert(oloc);
+
+ /* Check for invalid access request */
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "no write intent on file")
+
+ /* Check for using the latest version of the group format */
+ /* (add more checks for creating "new format" groups when needed) */
+ if(H5F_USE_LATEST_FLAGS(f, H5F_LATEST_STYLE_GROUP) || linfo->track_corder
+ || (pline && pline->nused))
+ use_latest_format = TRUE;
+ else
+ use_latest_format = FALSE;
+
+ /* Make certain that the creation order is being tracked if an index is
+ * going to be built on it.
+ */
+ if(linfo->index_corder && !linfo->track_corder)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "must track creation order to create index for it")
+
+ /* Check if we should be using the latest version of the group format */
+ if(use_latest_format) {
+ H5O_link_t lnk; /* Temporary link message info for computing message size */
+ char null_char = '\0'; /* Character for creating null string */
+ size_t ginfo_size; /* Size of the group info message */
+ size_t linfo_size; /* Size of the link info message */
+ size_t pline_size = 0; /* Size of the pipeline message */
+ size_t link_size; /* Size of a link message */
+
+ /* Calculate message size infomation, for creating group's object header */
+ linfo_size = H5O_msg_size_f(f, gcpl_id, H5O_LINFO_ID, linfo, (size_t)0);
+ HDassert(linfo_size);
+
+ ginfo_size = H5O_msg_size_f(f, gcpl_id, H5O_GINFO_ID, ginfo, (size_t)0);
+ HDassert(ginfo_size);
+
+ if(pline && pline->nused) {
+ pline_size = H5O_msg_size_f(f, gcpl_id, H5O_PLINE_ID, pline, (size_t)0);
+ HDassert(pline_size);
+ } /* end if */
+
+ lnk.type = H5L_TYPE_HARD;
+ lnk.corder = 0;
+ lnk.corder_valid = linfo->track_corder;
+ lnk.cset = H5T_CSET_ASCII;
+ lnk.name = &null_char;
+ link_size = H5O_msg_size_f(f, gcpl_id, H5O_LINK_ID, &lnk, (size_t)ginfo->est_name_len);
+ HDassert(link_size);
+
+ /* Compute size of header to use for creation */
+ hdr_size = linfo_size +
+ ginfo_size +
+ pline_size +
+ (ginfo->est_num_entries * link_size);
+ } /* end if */
+ else
+ hdr_size = (size_t)(4 + 2 * H5F_SIZEOF_ADDR(f));
+
+ /*
+ * Create group's object header. It has a zero link count
+ * since nothing refers to it yet. The link count will be
+ * incremented if the object is added to the group directed graph.
+ */
+ if(H5O_create(f, dxpl_id, hdr_size, (size_t)1, gcpl_id, oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create header")
+
+ /* Check for format of group to create */
+ if(use_latest_format) {
+ /* Insert link info message */
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_create(oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, (void *)linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+ /* Insert group info message */
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_create(oloc, H5O_GINFO_ID, H5O_MSG_FLAG_CONSTANT, 0, (void *)ginfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+ /* Insert pipeline message */
+ if(pline && pline->nused)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_create(oloc, H5O_PLINE_ID, H5O_MSG_FLAG_CONSTANT, 0, (void *)pline, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+ } /* end if */
+ else {
+ H5O_stab_t stab; /* Symbol table message */
+
+ /* The group doesn't currently have a 'stab' message, go create one */
+ if(H5G__stab_create(oloc, dxpl_id, ginfo, &stab) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create symbol table")
+
+ /* Cache the symbol table information */
+ gcrt_info->cache_type = H5G_CACHED_STAB;
+ gcrt_info->cache.stab.btree_addr = stab.btree_addr;
+ gcrt_info->cache.stab.heap_addr = stab.heap_addr;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__obj_create_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_get_linfo
+ *
+ * Purpose: Retrieves the "link info" message for an object. Also
+ * sets the number of links correctly, if it isn't set up yet.
+ *
+ * Return: Success: TRUE/FALSE whether message was found & retrieved
+ * Failure: FAIL if error occurred
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 11 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G__obj_get_linfo(const H5O_loc_t *grp_oloc, H5O_linfo_t *linfo, hid_t dxpl_id)
+{
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc);
+ HDassert(linfo);
+
+ /* Check for the group having a link info message */
+ if((ret_value = H5O_msg_exists(grp_oloc, H5O_LINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(ret_value) {
+ /* Retrieve the "link info" structure */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_LINFO_ID, linfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "link info message not present")
+
+ /* Check if we don't know how many links there are */
+ if(linfo->nlinks == HSIZET_MAX) {
+ /* Check if we are using "dense" link storage */
+ if(H5F_addr_defined(linfo->fheap_addr)) {
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(grp_oloc->file, dxpl_id, linfo->name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Retrieve # of records in "name" B-tree */
+ /* (should be same # of records in all indices) */
+ if(H5B2_get_nrec(bt2_name, &linfo->nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve # of records in index")
+ } /* end if */
+ else {
+ /* Retrieve # of links from object header */
+ if(H5O_get_nlinks(grp_oloc, dxpl_id, &linfo->nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve # of links for object")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__obj_get_linfo() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_compact_to_dense_cb
+ *
+ * Purpose: Callback routine for converting "compact" to "dense"
+ * link storage form.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_obj_compact_to_dense_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */
+ H5G_obj_oh_it_ud1_t *udata = (H5G_obj_oh_it_ud1_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(udata->dxpl_id, udata->oh_addr, FAIL)
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* Insert link into dense link storage */
+ if(H5G__dense_insert(udata->f, udata->dxpl_id, udata->linfo, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into dense storage")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_compact_to_dense_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_stab_to_new_cb
+ *
+ * Purpose: Callback routine for converting "symbol table" link storage to
+ * "new format" storage (either "compact" or "dense" storage).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sept 16 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_obj_stab_to_new_cb(const H5O_link_t *lnk, void *_udata)
+{
+ H5G_obj_stab_it_ud1_t *udata = (H5G_obj_stab_it_ud1_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* Insert link into group */
+ /* (Casting away const OK - QAK) */
+ if(H5G_obj_insert(udata->grp_oloc, lnk->name, (H5O_link_t *)lnk, FALSE,
+ H5O_TYPE_UNKNOWN, NULL, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert link into group")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_stab_to_new_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_insert
+ *
+ * Purpose: Insert a new symbol into the group described by GRP_OLOC.
+ * file F. The name of the new symbol is NAME and its symbol
+ * table entry is OBJ_LNK. Increment the reference
+ * count for the object the link points if OBJ_LNK is a hard link
+ * and ADJ_LINK is true.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_insert(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *obj_lnk,
+ hbool_t adj_link, H5O_type_t obj_type, const void *crt_info, hid_t dxpl_id)
+{
+ H5O_pline_t tmp_pline; /* Pipeline message */
+ H5O_pline_t *pline = NULL; /* Pointer to pipeline message */
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ hbool_t use_old_format; /* Whether to use 'old format' (symbol table) for insertions or not */
+ hbool_t use_new_dense = FALSE; /* Whether to use "dense" form of 'new format' group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+ HDassert(obj_lnk);
+
+ /* Check if we have information about the number of objects in this group */
+ /* (by attempting to get the link info message for this group) */
+ if((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ H5O_ginfo_t ginfo; /* Group info message */
+ size_t link_msg_size; /* Size of new link message in the file */
+
+ /* Using the new format for groups */
+ use_old_format = FALSE;
+
+ /* Check for tracking creation order on this group's links */
+ if(linfo.track_corder) {
+ /* Set the creation order for the new link & indicate that it's valid */
+ obj_lnk->corder = linfo.max_corder;
+ obj_lnk->corder_valid = TRUE;
+
+ /* Increment the max. creation order used in the group */
+ linfo.max_corder++;
+ } /* end if */
+
+ /* Get the link's message size */
+ if((link_msg_size = H5O_msg_raw_size(grp_oloc->file, H5O_LINK_ID, FALSE, obj_lnk)) == 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size")
+
+ /* Get the group info */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_GINFO_ID, &ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")
+
+ /* If there's still a small enough number of links, use the 'link' message */
+ /* (If the encoded form of the link is too large to fit into an object
+ * header message, convert to using dense link storage instead of link messages)
+ */
+ if(H5F_addr_defined(linfo.fheap_addr))
+ use_new_dense = TRUE;
+ else if(linfo.nlinks < ginfo.max_compact && link_msg_size < H5O_MESG_MAX_SIZE)
+ use_new_dense = FALSE;
+ else {
+ htri_t pline_exists; /* Whether the pipeline message exists */
+ H5G_obj_oh_it_ud1_t udata; /* User data for iteration */
+ H5O_mesg_operator_t op; /* Message operator */
+
+ /* Get the pipeline message, if it exists */
+ if((pline_exists = H5O_msg_exists(grp_oloc, H5O_PLINE_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(pline_exists) {
+ if(NULL == H5O_msg_read(grp_oloc, H5O_PLINE_ID, &tmp_pline, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link pipeline")
+ pline = &tmp_pline;
+ } /* end if */
+
+ /* The group doesn't currently have "dense" storage for links */
+ if(H5G__dense_create(grp_oloc->file, dxpl_id, &linfo, pline) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create 'dense' form of new format group")
+
+ /* Set up user data for object header message iteration */
+ udata.f = grp_oloc->file;
+ udata.oh_addr = grp_oloc->addr;
+ udata.dxpl_id = dxpl_id;
+ udata.linfo = &linfo;
+
+ /* Iterate over the 'link' messages, inserting them into the dense link storage */
+ op.op_type = H5O_MESG_OP_APP;
+ op.u.app_op = H5G_obj_compact_to_dense_cb;
+ if(H5O_msg_iterate(grp_oloc, H5O_LINK_ID, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links")
+
+ /* Remove all the 'link' messages */
+ if(H5O_msg_remove(grp_oloc, H5O_LINK_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link messages")
+
+ use_new_dense = TRUE;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check for new-style link information */
+ if(obj_lnk->cset != H5T_CSET_ASCII || obj_lnk->type > H5L_TYPE_BUILTIN_MAX) {
+ H5O_linfo_t new_linfo = H5G_CRT_LINK_INFO_DEF; /* Link information */
+ H5O_ginfo_t new_ginfo = H5G_CRT_GROUP_INFO_DEF; /* Group information */
+ H5G_obj_stab_it_ud1_t udata; /* User data for iteration */
+
+ /* Convert group to "new format" group, in order to hold the information */
+
+ /* Insert link info message */
+ if(H5O_msg_create(grp_oloc, H5O_LINFO_ID, 0, 0, &new_linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+ /* Insert group info message */
+ if(H5O_msg_create(grp_oloc, H5O_GINFO_ID, H5O_MSG_FLAG_CONSTANT, H5O_UPDATE_TIME, &new_ginfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+ /* Set up user data for iteration */
+ udata.grp_oloc = grp_oloc;
+ udata.dxpl_id = dxpl_id;
+
+ /* Iterate through all links in "old format" group and insert them into new format */
+ if(H5G__stab_iterate(grp_oloc, dxpl_id, H5_ITER_NATIVE, (hsize_t)0, NULL, H5G_obj_stab_to_new_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over old format links")
+
+ /* Remove the symbol table message from the group */
+ if(H5O_msg_remove(grp_oloc, H5O_STAB_ID, 0, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete old format link storage")
+
+ /* Recursively call this routine to insert the new link, since the
+ * group is in the "new format" now and the link info should be
+ * set up, etc.
+ */
+ if(H5G_obj_insert(grp_oloc, name, obj_lnk, adj_link, obj_type,
+ crt_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into group")
+
+ /* Done with insertion now */
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+ else
+ use_old_format = TRUE;
+ } /* end if */
+
+ /* Insert into symbol table or "dense" storage */
+ if(use_old_format) {
+ /* Insert into symbol table */
+ if(H5G__stab_insert(grp_oloc, name, obj_lnk, obj_type, crt_info, dxpl_id)
+ < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry into symbol table")
+ } /* end if */
+ else {
+ if(use_new_dense) {
+ /* Insert into dense link storage */
+ if(H5G__dense_insert(grp_oloc->file, dxpl_id, &linfo, obj_lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into dense storage")
+ } /* end if */
+ else {
+ /* Insert with link message */
+ if(H5G__compact_insert(grp_oloc, obj_lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link as link message")
+ } /* end else */
+ } /* end else */
+
+ /* Increment the number of objects in this group */
+ if(!use_old_format) {
+ linfo.nlinks++;
+ if(H5O_msg_write(grp_oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message")
+ } /* end if */
+
+ /* Increment link count on object, if requested and it's a hard link */
+ if(adj_link && obj_lnk->type == H5L_TYPE_HARD) {
+ H5O_loc_t obj_oloc; /* Object location */
+ H5O_loc_reset(&obj_oloc);
+
+ /* Create temporary object location */
+ obj_oloc.file = grp_oloc->file;
+ obj_oloc.addr = obj_lnk->u.hard.addr;
+
+ /* Increment reference count for object */
+ if(H5O_link(&obj_oloc, 1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "unable to increment hard link count")
+ } /* end if */
+
+done:
+ /* Free any space used by the pipeline message */
+ if(pline && H5O_msg_reset(H5O_PLINE_ID, pline) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "can't release pipeline")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_iterate
+ *
+ * Purpose: Private function for H5Giterate.
+ * Iterates over objects in a group
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Oct 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__obj_iterate(const H5O_loc_t *grp_oloc,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ H5G_lib_iterate_t op, void *op_data, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(grp_oloc);
+ HDassert(op);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for going out of bounds */
+ if(skip > 0 && (size_t)skip >= linfo.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group")
+ } /* end if */
+
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Iterate over the links in the group, building a table of the link messages */
+ if((ret_value = H5G__dense_iterate(grp_oloc->file, dxpl_id, &linfo, idx_type, order, skip, last_lnk, op, op_data)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over dense links")
+ } /* end if */
+ else {
+ /* Get the object's name from the link messages */
+ if((ret_value = H5G__compact_iterate(grp_oloc, dxpl_id, &linfo, idx_type, order, skip, last_lnk, op, op_data)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over compact links")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query")
+
+ /* Iterate over symbol table */
+ if((ret_value = H5G__stab_iterate(grp_oloc, dxpl_id, order, skip, last_lnk, op, op_data)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over symbol table")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__obj_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_info
+ *
+ * Purpose: Retrieve information about a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__obj_info(H5O_loc_t *oloc, H5G_info_t *grp_info, hid_t dxpl_id)
+{
+ H5G_t *grp = NULL; /* Group to query */
+ H5G_loc_t grp_loc; /* Entry of group to be queried */
+ H5G_name_t grp_path; /* Group hier. path */
+ H5O_loc_t grp_oloc; /* Group object location */
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(grp_info);
+
+ /* Set up group location to fill in */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ H5G_loc_reset(&grp_loc);
+
+ /* Deep copy (duplicate) of the group location object */
+ if(H5O_loc_copy(&grp_oloc, oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "can't copy object location")
+
+ /* Open the group */
+ if(NULL == (grp = H5G_open(&grp_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found")
+
+ /* Get information from the group */
+ grp_info->mounted = H5G_MOUNTED(grp);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Retrieve the information about the links */
+ grp_info->nlinks = linfo.nlinks;
+ grp_info->max_corder = linfo.max_corder;
+
+ /* Check if the group is using compact or dense storage for its links */
+ if(H5F_addr_defined(linfo.fheap_addr))
+ grp_info->storage_type = H5G_STORAGE_TYPE_DENSE;
+ else
+ grp_info->storage_type = H5G_STORAGE_TYPE_COMPACT;
+ } /* end if */
+ else {
+ /* Get the number of objects in this group by iterating over symbol table */
+ if(H5G__stab_count(oloc, &grp_info->nlinks, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "can't count objects")
+
+ /* Set the other information about the group */
+ grp_info->storage_type = H5G_STORAGE_TYPE_SYMBOL_TABLE;
+ grp_info->max_corder = 0;
+ } /* end else */
+
+done:
+ /* Clean up resources */
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "unable to close queried group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__obj_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_get_name_by_idx
+ *
+ * Purpose: Returns the name of link in a group by giving index.
+ *
+ * Return: Success: Non-negative, length of name
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G_obj_get_name_by_idx(const H5O_loc_t *oloc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, char* name, size_t size, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc && oloc->file);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group")
+ } /* end if */
+
+ /* Check for dense link storage */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Get the object's name from the dense link storage */
+ if((ret_value = H5G__dense_get_name_by_idx(oloc->file, dxpl_id, &linfo, idx_type, order, n, name, size)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name")
+ } /* end if */
+ else {
+ /* Get the object's name from the link messages */
+ if((ret_value = H5G__compact_get_name_by_idx(oloc, dxpl_id, &linfo, idx_type, order, n, name, size)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query")
+
+ /* Get the object's name from the symbol table */
+ if((ret_value = H5G__stab_get_name_by_idx(oloc, order, n, name, size, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_get_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_remove_update_linfo
+ *
+ * Purpose: Update the link info after removing a link from a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_obj_remove_update_linfo(const H5O_loc_t *oloc, H5O_linfo_t *linfo, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(linfo);
+
+ /* Decrement # of links in group */
+ linfo->nlinks--;
+
+ /* Reset the creation order min/max if there's no more links in group */
+ if(linfo->nlinks == 0)
+ linfo->max_corder = 0;
+
+ /* Check for transitioning out of dense storage, if we are using it */
+ if(H5F_addr_defined(linfo->fheap_addr)) {
+ /* Check if there's no more links */
+ if(linfo->nlinks == 0) {
+ /* Delete the dense storage */
+ if(H5G__dense_delete(oloc->file, dxpl_id, linfo, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete dense link storage")
+ } /* end if */
+ /* Check for switching back to compact storage */
+ else {
+ H5O_ginfo_t ginfo; /* Group info message */
+
+ /* Get the group info */
+ if(NULL == H5O_msg_read(oloc, H5O_GINFO_ID, &ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")
+
+ /* Check if we should switch from dense storage back to link messages */
+ if(linfo->nlinks < ginfo.min_dense) {
+ struct H5O_t *oh = NULL; /* Pointer to group's object header */
+ H5G_link_table_t ltable; /* Table of links */
+ hbool_t can_convert = TRUE; /* Whether converting to link messages is possible */
+ size_t u; /* Local index */
+
+ /* Build the table of links for this group */
+ if(H5G__dense_build_table(oloc->file, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, &ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(oloc, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTPIN, FAIL, "unable to pin group object header")
+
+ /* Inspect links in table for ones that can't be converted back
+ * into link message form (currently only links which can't fit
+ * into an object header message)
+ */
+ for(u = 0; u < linfo->nlinks; u++)
+ if(H5O_msg_size_oh(oloc->file, oh, H5O_LINK_ID, &(ltable.lnks[u]), (size_t)0) >= H5O_MESG_MAX_SIZE) {
+ can_convert = FALSE;
+ break;
+ } /* end if */
+
+ /* If ok, insert links as link messages */
+ if(can_convert) {
+ /* Insert link messages into group */
+ for(u = 0; u < linfo->nlinks; u++)
+ if(H5O_msg_append_oh(oloc->file, dxpl_id, oh, H5O_LINK_ID, 0, H5O_UPDATE_TIME, &(ltable.lnks[u])) < 0) {
+ /* Release object header */
+ if(H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTUNPIN, FAIL, "unable to unpin group object header")
+
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+ } /* end if */
+
+ /* Remove the dense storage */
+ if(H5G__dense_delete(oloc->file, dxpl_id, linfo, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete dense link storage")
+ } /* end if */
+
+ /* Release object header */
+ if(H5O_unpin(oh) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUNPIN, FAIL, "unable to unpin group object header")
+
+ /* Free link table information */
+ if(H5G__link_release_table(&ltable) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Update link info in the object header */
+ if(H5O_msg_write(oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_remove_update_linfo() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_remove
+ *
+ * Purpose: Remove a link from a group.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_remove(const H5O_loc_t *oloc, H5RS_str_t *grp_full_path_r, const char *name, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ hbool_t use_old_format; /* Whether to use 'old format' (symbol table) for deletion or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(name && *name);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Using the new format for groups */
+ use_old_format = FALSE;
+
+ /* Check for dense or compact storage */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Remove object from the dense link storage */
+ if(H5G__dense_remove(oloc->file, dxpl_id, &linfo, grp_full_path_r, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end if */
+ else {
+ /* Remove object from the link messages */
+ if(H5G__compact_remove(oloc, dxpl_id, grp_full_path_r, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Using the old format for groups */
+ use_old_format = TRUE;
+
+ /* Remove object from the symbol table */
+ if(H5G__stab_remove(oloc, dxpl_id, grp_full_path_r, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end else */
+
+ /* Update link info for a new-style group */
+ if(!use_old_format)
+ if(H5G_obj_remove_update_linfo(oloc, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUPDATE, FAIL, "unable to update link info")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_remove_by_idx
+ *
+ * Purpose: Remove a link from a group, according to the order within an index.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_remove_by_idx(const H5O_loc_t *grp_oloc, H5RS_str_t *grp_full_path_r,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ hbool_t use_old_format; /* Whether to use 'old format' (symbol table) for deletion or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(grp_oloc && grp_oloc->file);
+
+ /* Attempt to get the link info for this group */
+ if((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group")
+ } /* end if */
+
+ /* Using the new format for groups */
+ use_old_format = FALSE;
+
+ /* Check for dense or compact storage */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Remove object from the dense link storage */
+ if(H5G__dense_remove_by_idx(grp_oloc->file, dxpl_id, &linfo, grp_full_path_r, idx_type, order, n) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end if */
+ else {
+ /* Remove object from compact link storage */
+ if(H5G__compact_remove_by_idx(grp_oloc, dxpl_id, &linfo, grp_full_path_r, idx_type, order, n) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query")
+
+ /* Using the old format for groups */
+ use_old_format = TRUE;
+
+ /* Remove object from the symbol table */
+ if(H5G__stab_remove_by_idx(grp_oloc, dxpl_id, grp_full_path_r, order, n) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end else */
+
+ /* Update link info for a new-style group */
+ if(!use_old_format) {
+ if(H5G_obj_remove_update_linfo(grp_oloc, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUPDATE, FAIL, "unable to update link info")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__obj_lookup
+ *
+ * Purpose: Look up a link in a group, using the name as the key.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G__obj_lookup(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk,
+ hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+
+ /* Attempt to get the link info message for this group */
+ if((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for dense link storage */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Get the object's info from the dense link storage */
+ if((ret_value = H5G__dense_lookup(grp_oloc->file, dxpl_id, &linfo, name, lnk)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end if */
+ else {
+ /* Get the object's info from the link messages */
+ if((ret_value = H5G__compact_lookup(grp_oloc, name, lnk, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Get the object's info from the symbol table */
+ if((ret_value = H5G__stab_lookup(grp_oloc, name, lnk, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__obj_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_lookup_by_idx
+ *
+ * Purpose: Look up link info in a group, according to an order within an
+ * index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, H5O_link_t *lnk, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info message exists */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+
+ /* Attempt to get the link info message for this group */
+ if((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message")
+ if(linfo_exists) {
+ /* Check for creation order tracking, if creation order index lookup requested */
+ if(idx_type == H5_INDEX_CRT_ORDER) {
+ /* Check if creation order is tracked */
+ if(!linfo.track_corder)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group")
+ } /* end if */
+
+ /* Check for dense link storage */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Get the link from the dense storage */
+ if(H5G__dense_lookup_by_idx(grp_oloc->file, dxpl_id, &linfo, idx_type, order, n, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end if */
+ else {
+ /* Get the link from the link messages */
+ if(H5G__compact_lookup_by_idx(grp_oloc, dxpl_id, &linfo, idx_type, order, n, lnk) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Can only perform name lookups on groups with symbol tables */
+ if(idx_type != H5_INDEX_NAME)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query")
+
+ /* Get the object's info from the symbol table */
+ if(H5G__stab_lookup_by_idx(grp_oloc, order, n, lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G_obj_lookup_by_idx() */
+
diff --git a/src/H5Goh.c b/src/H5Goh.c
new file mode 100644
index 0000000..977fc2d
--- /dev/null
+++ b/src/H5Goh.c
@@ -0,0 +1,417 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Object headers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static void *H5O_group_get_copy_file_udata(void);
+static void H5O_group_free_copy_file_udata(void *udata);
+static htri_t H5O_group_isa(H5O_t *loc);
+static hid_t H5O_group_open(const H5G_loc_t *obj_loc, hid_t lapl_id,
+ hid_t dxpl_id, hbool_t app_ref);
+static void *H5O_group_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc,
+ hid_t dxpl_id);
+static H5O_loc_t *H5O_group_get_oloc(hid_t obj_id);
+static herr_t H5O_group_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh,
+ H5_ih_info_t *bh_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* This message derives from H5O object class */
+const H5O_obj_class_t H5O_OBJ_GROUP[1] = {{
+ H5O_TYPE_GROUP, /* object type */
+ "group", /* object name, for debugging */
+ H5O_group_get_copy_file_udata, /* get 'copy file' user data */
+ H5O_group_free_copy_file_udata, /* free 'copy file' user data */
+ H5O_group_isa, /* "isa" message */
+ H5O_group_open, /* open an object of this class */
+ H5O_group_create, /* create an object of this class */
+ H5O_group_get_oloc, /* get an object header location for an object */
+ H5O_group_bh_info, /* get the index & heap info for an object */
+ NULL /* flush an opened object of this class */
+}};
+
+/* Declare the external free list to manage the H5O_ginfo_t struct */
+H5FL_DEFINE(H5G_copy_file_ud_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_get_copy_file_udata
+ *
+ * Purpose: Allocates the user data needed for copying a group's
+ * object header from file to file.
+ *
+ * Return: Success: Non-NULL pointer to user data
+ *
+ * Failure: NULL
+ *
+ * Programmer: Neil Fortner
+ * Thursday, July 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_group_get_copy_file_udata(void)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate space for the 'copy file' user data for copying groups.
+ * Currently this is only a ginfo, so there is no specific struct type for
+ * this operation. */
+ if(NULL == (ret_value = H5FL_CALLOC(H5G_copy_file_ud_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_group_get_copy_file_udata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_free_copy_file_udata
+ *
+ * Purpose: Release the user data needed for copying a group's
+ * object header from file to file.
+ *
+ * Return: <none>
+ *
+ * Programmer: Neil Fortner
+ * Thursday, July 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5O_group_free_copy_file_udata(void *_udata)
+{
+ H5G_copy_file_ud_t *udata = (H5G_copy_file_ud_t *)_udata;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(udata);
+
+ /* Free the ginfo struct (including nested data structs) */
+ H5O_msg_free(H5O_PLINE_ID, udata->common.src_pline);
+
+ /* Release space for 'copy file' user data (ginfo struct) */
+ udata = H5FL_FREE(H5G_copy_file_ud_t, udata);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5O_group_free_copy_file_udata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_isa
+ *
+ * Purpose: Determines if an object has the requisite messages for being
+ * a group.
+ *
+ * Return: Success: TRUE if the required group messages are
+ * present; FALSE otherwise.
+ *
+ * Failure: FAIL if the existence of certain messages
+ * cannot be determined.
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_group_isa(struct H5O_t *oh)
+{
+ htri_t stab_exists; /* Whether the 'stab' message is in the object header */
+ htri_t linfo_exists; /* Whether the 'linfo' message is in the object header */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(oh);
+
+ /* Check for any of the messages that indicate a group */
+ if((stab_exists = H5O_msg_exists_oh(oh, H5O_STAB_ID)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header")
+ if((linfo_exists = H5O_msg_exists_oh(oh, H5O_LINFO_ID)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header")
+
+ ret_value = (stab_exists > 0 || linfo_exists > 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_group_isa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_open
+ *
+ * Purpose: Open a group at a particular location
+ *
+ * Return: Success: Open object identifier
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hid_t
+H5O_group_open(const H5G_loc_t *obj_loc, hid_t H5_ATTR_UNUSED lapl_id, hid_t dxpl_id, hbool_t app_ref)
+{
+ H5G_t *grp = NULL; /* Group opened */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(obj_loc);
+
+ /* Open the group */
+ if(NULL == (grp = H5G_open(obj_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+
+ /* Register an ID for the group */
+ if((ret_value = H5I_register(H5I_GROUP, grp, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+done:
+ if(ret_value < 0)
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_group_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_create
+ *
+ * Purpose: Create a group in a file
+ *
+ * Return: Success: Pointer to the group data structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 10, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_group_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ H5G_obj_create_t *crt_info = (H5G_obj_create_t *)_crt_info; /* Group creation parameters */
+ H5G_t *grp = NULL; /* New group created */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(crt_info);
+ HDassert(obj_loc);
+
+ /* Create the the group */
+ if(NULL == (grp = H5G__create(f, crt_info, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "unable to create group")
+
+ /* Set up the new group's location */
+ if(NULL == (obj_loc->oloc = H5G_oloc(grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get object location of group")
+ if(NULL == (obj_loc->path = H5G_nameof(grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get path of group")
+
+ /* Set the return value */
+ ret_value = grp;
+
+done:
+ if(ret_value == NULL)
+ if(grp && H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, NULL, "unable to release group")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_group_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_get_oloc
+ *
+ * Purpose: Retrieve the object header location for an open object
+ *
+ * Return: Success: Pointer to object header location
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_loc_t *
+H5O_group_get_oloc(hid_t obj_id)
+{
+ H5G_t *grp; /* Group opened */
+ H5O_loc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get the group */
+ if(NULL == (grp = (H5G_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADATOM, NULL, "couldn't get object from ID")
+
+ /* Get the group's object header location */
+ if(NULL == (ret_value = H5G_oloc(grp)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_group_get_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_group_bh_info
+ *
+ * Purpose: Retrieve storage for 1.8 btree and heap
+ * Retrieve storage for 1.6 btree and heap via H5G_stab_bh_info()
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * July 12 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_group_bh_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info)
+{
+ htri_t exists; /* Flag if header message of interest exists */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* Sanity check */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(oh);
+ HDassert(bh_info);
+
+ /* Check for "new style" group info */
+ if((exists = H5O_msg_exists_oh(oh, H5O_LINFO_ID)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header")
+ if(exists > 0) {
+ H5O_linfo_t linfo; /* Link info message */
+
+ /* Get "new style" group info */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_LINFO_ID, &linfo))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't read LINFO message")
+
+ /* Check if name index available */
+ if(H5F_addr_defined(linfo.name_bt2_addr)) {
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(loc->file, dxpl_id, linfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Get name index B-tree size */
+ if(H5B2_size(bt2_name, dxpl_id, &bh_info->index_size) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info for name index")
+ } /* end if */
+
+ /* Check if creation order index available */
+ if(H5F_addr_defined(linfo.corder_bt2_addr)) {
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(loc->file, dxpl_id, linfo.corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Get creation order index B-tree size */
+ if(H5B2_size(bt2_corder, dxpl_id, &bh_info->index_size) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info for creation order index")
+ } /* end if */
+
+ /* Get fractal heap size, if available */
+ if(H5F_addr_defined(linfo.fheap_addr)) {
+ /* Open the fractal heap for links */
+ if(NULL == (fheap = H5HF_open(loc->file, dxpl_id, linfo.fheap_addr)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Get heap storage size */
+ if(H5HF_size(fheap, dxpl_id, &bh_info->heap_size) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve fractal heap storage info")
+ } /* end if */
+ } /* end if */
+ else {
+ H5O_stab_t stab; /* Info about symbol table */
+
+ /* Must be "old style" group, get symbol table message */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_STAB_ID, &stab))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't find LINFO nor STAB messages")
+
+ /* Get symbol table size info */
+ if(H5G__stab_bh_size(loc->file, dxpl_id, &stab, bh_info) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve symbol table size info")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_group_bh_info() */
+
diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h
new file mode 100644
index 0000000..76bf08b
--- /dev/null
+++ b/src/H5Gpkg.h
@@ -0,0 +1,531 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, September 18, 1997
+ *
+ * Purpose: This file contains declarations which are visible
+ * only within the H5G package. Source files outside the
+ * H5G package should include H5Gprivate.h instead.
+ */
+#if !(defined H5G_FRIEND || defined H5G_MODULE)
+#error "Do not include this file outside the H5G package!"
+#endif
+
+#ifndef _H5Gpkg_H
+#define _H5Gpkg_H
+
+/* Get package's private header */
+#include "H5Gprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5B2private.h" /* v2 B-trees */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5HFprivate.h" /* Fractal heaps */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5SLprivate.h" /* Skip lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Standard length of fractal heap ID for link */
+#define H5G_DENSE_FHEAP_ID_LEN 7
+
+/* Size of a symbol table node on disk */
+#define H5G_NODE_SIZE(f) ( \
+ /* General metadata fields */ \
+ H5_SIZEOF_MAGIC \
+ + 1 /* Version */ \
+ + 1 /* Reserved */ \
+ + 2 /* Number of symbols */ \
+ \
+ /* Entries */ \
+ + ((2 * H5F_SYM_LEAF_K(f)) * (unsigned)H5G_SIZEOF_ENTRY_FILE(f)) \
+ )
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/*
+ * Various types of object header information can be cached in a symbol
+ * table entry (it's normal home is the object header to which the entry
+ * points). This datatype determines what (if anything) is cached in the
+ * symbol table entry.
+ */
+typedef enum H5G_cache_type_t {
+ H5G_CACHED_ERROR = -1, /*force enum to be signed */
+ H5G_NOTHING_CACHED = 0, /*nothing is cached, must be 0 */
+ H5G_CACHED_STAB = 1, /*symbol table, `stab' */
+ H5G_CACHED_SLINK = 2, /*symbolic link */
+
+ H5G_NCACHED /*THIS MUST BE LAST */
+} H5G_cache_type_t;
+
+/*
+ * A symbol table entry caches these parameters from object header
+ * messages... The values are entered into the symbol table when an object
+ * header is created (by hand) and are extracted from the symbol table with a
+ * callback function registered in H5O_init_interface(). Be sure to update
+ * H5G_ent_decode(), H5G_ent_encode(), and H5G__ent_debug() as well.
+ */
+typedef union H5G_cache_t {
+ struct {
+ haddr_t btree_addr; /*file address of symbol table B-tree*/
+ haddr_t heap_addr; /*file address of stab name heap */
+ } stab;
+
+ struct {
+ size_t lval_offset; /*link value offset */
+ } slink;
+} H5G_cache_t;
+
+/*
+ * A symbol table entry. The two important fields are `name_off' and
+ * `header'. The remaining fields are used for caching information that
+ * also appears in the object header to which this symbol table entry
+ * points.
+ */
+struct H5G_entry_t {
+ H5G_cache_type_t type; /*type of information cached */
+ H5G_cache_t cache; /*cached data from object header */
+ size_t name_off; /*offset of name within name heap */
+ haddr_t header; /*file address of object header */
+};
+
+/*
+ * A symbol table node is a collection of symbol table entries. It can
+ * be thought of as the lowest level of the B-link tree that points to
+ * a collection of symbol table entries that belong to a specific symbol
+ * table or group.
+ */
+typedef struct H5G_node_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions, _must_ be */
+ /* first field in structure */
+ size_t node_size; /* Size of node on disk */
+ unsigned nsyms; /* Number of symbols */
+ H5G_entry_t *entry; /* Array of symbol table entries */
+} H5G_node_t;
+
+/*
+ * Shared information for all open group objects
+ */
+struct H5G_shared_t {
+ int fo_count; /* open file object count */
+ hbool_t mounted; /* Group is mount point */
+};
+
+/*
+ * A group handle passed around through layers of the library within and
+ * above the H5G layer.
+ */
+struct H5G_t {
+ H5G_shared_t *shared; /* Shared file object data */
+ H5O_loc_t oloc; /* Object location for group */
+ H5G_name_t path; /* Group hierarchy path */
+};
+
+/* Link iteration operator for internal library callbacks */
+typedef herr_t (*H5G_lib_iterate_t)(const H5O_link_t *lnk, void *op_data);
+
+/* Data structure to hold table of links for a group */
+typedef struct {
+ size_t nlinks; /* # of links in table */
+ H5O_link_t *lnks; /* Pointer to array of links */
+} H5G_link_table_t;
+
+/*
+ * Common data exchange structure for symbol table nodes. This structure is
+ * passed through the B-link tree layer to the methods for the objects
+ * to which the B-link tree points.
+ *
+ * It's also used for B-tree iterators which require no additional info.
+ *
+ */
+typedef struct H5G_bt_common_t {
+ /* downward */
+ const char *name; /*points to temporary memory */
+ H5HL_t *heap; /*symbol table heap */
+} H5G_bt_common_t;
+
+/*
+ * Data exchange structure for symbol table nodes. This structure is
+ * passed through the B-link tree layer to the insert method for entries.
+ */
+typedef struct H5G_bt_ins_t {
+ /* downward */
+ H5G_bt_common_t common; /* Common info for B-tree user data (must be first) */
+ const H5O_link_t *lnk; /* Link to insert into table */
+ H5O_type_t obj_type; /* Type of object being inserted */
+ const void *crt_info; /* Creation info for object being inserted */
+} H5G_bt_ins_t;
+
+/*
+ * Data exchange structure for symbol table nodes. This structure is
+ * passed through the B-link tree layer to the remove method for entries.
+ */
+typedef struct H5G_bt_rm_t {
+ /* downward */
+ H5G_bt_common_t common; /* Common info for B-tree user data (must be first) */
+ H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
+} H5G_bt_rm_t;
+
+/* Typedef for B-tree 'find' operation */
+typedef herr_t (*H5G_bt_find_op_t)(const H5G_entry_t *ent/*in*/, void *operator_data/*in,out*/);
+
+/*
+ * Data exchange structure for symbol table nodes. This structure is
+ * passed through the B-link tree layer to the 'find' method for entries.
+ */
+typedef struct H5G_bt_lkp_t {
+ /* downward */
+ H5G_bt_common_t common; /* Common info for B-tree user data (must be first) */
+ H5G_bt_find_op_t op; /* Operator to call when correct entry is found */
+ void *op_data; /* Data to pass to operator */
+
+ /* upward */
+} H5G_bt_lkp_t;
+
+/*
+ * Data exchange structure to pass through the B-tree layer for the
+ * H5B_iterate function.
+ */
+typedef struct H5G_bt_it_it_t {
+ /* downward */
+ H5HL_t *heap; /*symbol table heap */
+ hsize_t skip; /*initial entries to skip */
+ H5G_lib_iterate_t op; /*iteration operator */
+ void *op_data; /*user-defined operator data */
+
+ /* upward */
+ hsize_t *final_ent; /*final entry looked at */
+} H5G_bt_it_it_t;
+
+/* Data passed through B-tree iteration for copying copy symbol table content */
+typedef struct H5G_bt_it_cpy_t {
+ const H5O_loc_t *src_oloc; /* Source object location */
+ haddr_t src_heap_addr; /* Heap address of the source symbol table */
+ H5F_t *dst_file; /* File of destination group */
+ const H5O_stab_t *dst_stab; /* Symbol table message for destination group */
+ H5O_copy_t *cpy_info; /* Information for copy operation */
+} H5G_bt_it_cpy_t;
+
+/* Common information for "by index" lookups in symbol tables */
+typedef struct H5G_bt_it_idx_common_t {
+ /* downward */
+ hsize_t idx; /* Index of group member to be queried */
+ hsize_t num_objs; /* The number of objects having been traversed */
+ H5G_bt_find_op_t op; /* Operator to call when correct entry is found */
+} H5G_bt_it_idx_common_t;
+
+/* Data passed through B-tree iteration for building a table of the links */
+typedef struct H5G_bt_it_bt_t {
+ /* downward */
+ size_t alloc_nlinks; /* Number of links allocated in table */
+ H5HL_t *heap; /* Symbol table heap */
+
+ /* upward */
+ H5G_link_table_t *ltable; /* Link table to add information to */
+} H5G_bt_it_bt_t;
+
+/* Typedefs for "new format" groups */
+/* (fractal heap & v2 B-tree info) */
+
+/* Typedef for native 'name' field index records in the v2 B-tree */
+/* (Keep 'id' field first so generic record handling in callbacks works) */
+typedef struct H5G_dense_bt2_name_rec_t {
+ uint8_t id[H5G_DENSE_FHEAP_ID_LEN]; /* Heap ID for link */
+ uint32_t hash; /* Hash of 'name' field value */
+} H5G_dense_bt2_name_rec_t;
+
+/* Typedef for native 'creation order' field index records in the v2 B-tree */
+/* (Keep 'id' field first so generic record handling in callbacks works) */
+typedef struct H5G_dense_bt2_corder_rec_t {
+ uint8_t id[H5G_DENSE_FHEAP_ID_LEN]; /* Heap ID for link */
+ int64_t corder; /* 'creation order' field value */
+} H5G_dense_bt2_corder_rec_t;
+
+/*
+ * Common data exchange structure for dense link storage. This structure is
+ * passed through the v2 B-tree layer to the methods for the objects
+ * to which the v2 B-tree points.
+ */
+typedef struct H5G_bt2_ud_common_t {
+ /* downward */
+ H5F_t *f; /* Pointer to file that fractal heap is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5HF_t *fheap; /* Fractal heap handle */
+ const char *name; /* Name of link to compare */
+ uint32_t name_hash; /* Hash of name of link to compare */
+ int64_t corder; /* Creation order value of link to compare */
+ H5B2_found_t found_op; /* Callback when correct link is found */
+ void *found_op_data; /* Callback data when correct link is found */
+} H5G_bt2_ud_common_t;
+
+/*
+ * Data exchange structure for dense link storage. This structure is
+ * passed through the v2 B-tree layer when inserting links.
+ */
+typedef struct H5G_bt2_ud_ins_t {
+ /* downward */
+ H5G_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */
+ uint8_t id[H5G_DENSE_FHEAP_ID_LEN]; /* Heap ID of link to insert */
+} H5G_bt2_ud_ins_t;
+
+/* Typedef for group creation operation */
+typedef struct H5G_obj_create_t{
+ hid_t gcpl_id; /* Group creation property list */
+ H5G_cache_type_t cache_type; /* Type of symbol table entry cache */
+ H5G_cache_t cache; /* Cached data for symbol table entry */
+} H5G_obj_create_t;
+
+/* Callback information for copying groups */
+typedef struct H5G_copy_file_ud_t {
+ H5O_copy_file_ud_common_t common; /* Shared information (must be first) */
+ H5G_cache_type_t cache_type; /* Type of symbol table entry cache */
+ H5G_cache_t cache; /* Cached data for symbol table entry */
+} H5G_copy_file_ud_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/*
+ * This is the class identifier to give to the B-tree functions.
+ */
+H5_DLLVAR H5B_class_t H5B_SNODE[1];
+
+/* The v2 B-tree class for indexing 'name' field on links */
+H5_DLLVAR const H5B2_class_t H5G_BT2_NAME[1];
+
+/* The v2 B-tree class for indexing 'creation order' field on links */
+H5_DLLVAR const H5B2_class_t H5G_BT2_CORDER[1];
+
+/* Free list for managing H5G_t structs */
+H5FL_EXTERN(H5G_t);
+
+/* Free list for managing H5G_shared_t structs */
+H5FL_EXTERN(H5G_shared_t);
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/*
+ * General group routines
+ */
+H5_DLL H5G_t *H5G__create(H5F_t *file, H5G_obj_create_t *gcrt_info,
+ hid_t dxpl_id);
+H5_DLL H5G_t *H5G__create_named(const H5G_loc_t *loc, const char *name,
+ hid_t lcpl_id, hid_t gcpl_id, hid_t gapl_id, hid_t dxpl_id);
+H5_DLL H5G_t *H5G__open_name(const H5G_loc_t *loc, const char *name,
+ hid_t gapl_id, hid_t dxpl_id);
+
+/*
+ * Group hierarchy traversal routines
+ */
+H5_DLL herr_t H5G__traverse_special(const H5G_loc_t *grp_loc,
+ const H5O_link_t *lnk, unsigned target, size_t *nlinks, hbool_t last_comp,
+ H5G_loc_t *obj_loc, hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id);
+
+/*
+ * Utility functions
+ */
+H5_DLL const char *H5G__component(const char *name, size_t *size_p);
+
+/*
+ * Functions that understand symbol tables but not names. The
+ * functions that understand names are exported to the rest of
+ * the library and appear in H5Gprivate.h.
+ */
+H5_DLL herr_t H5G__stab_create(H5O_loc_t *grp_oloc, hid_t dxpl_id,
+ const H5O_ginfo_t *ginfo, H5O_stab_t *stab);
+H5_DLL herr_t H5G__stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint, hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_insert(const H5O_loc_t *grp_oloc, const char *name,
+ H5O_link_t *obj_lnk, H5O_type_t obj_type, const void *crt_info,
+ hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_insert_real(H5F_t *f, const H5O_stab_t *stab,
+ const char *name, H5O_link_t *obj_lnk, H5O_type_t obj_type,
+ const void *crt_info, hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab);
+H5_DLL herr_t H5G__stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
+ hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data);
+H5_DLL herr_t H5G__stab_count(struct H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_bh_size(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab,
+ H5_ih_info_t *bh_info);
+H5_DLL ssize_t H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order,
+ hsize_t n, char* name, size_t size, hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_remove(const H5O_loc_t *oloc, hid_t dxpl_id,
+ H5RS_str_t *grp_full_path_r, const char *name);
+H5_DLL herr_t H5G__stab_remove_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ H5RS_str_t *grp_full_path_r, H5_iter_order_t order, hsize_t n);
+H5_DLL herr_t H5G__stab_lookup(const H5O_loc_t *grp_oloc, const char *name,
+ H5O_link_t *lnk, hid_t dxpl_id);
+H5_DLL herr_t H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order,
+ hsize_t n, H5O_link_t *lnk, hid_t dxpl_id);
+#ifndef H5_STRICT_FORMAT_CHECKS
+H5_DLL herr_t H5G__stab_valid(H5O_loc_t *grp_oloc, hid_t dxpl_id,
+ H5O_stab_t *alt_stab);
+#endif /* H5_STRICT_FORMAT_CHECKS */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL H5G_obj_t H5G__stab_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx,
+ hid_t dxpl_id);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+
+/*
+ * Functions that understand symbol table entries.
+ */
+H5_DLL void H5G__ent_copy(H5G_entry_t *dst, const H5G_entry_t *src,
+ H5_copy_depth_t depth);
+H5_DLL void H5G__ent_reset(H5G_entry_t *ent);
+H5_DLL herr_t H5G__ent_decode_vec(const H5F_t *f, const uint8_t **pp,
+ H5G_entry_t *ent, unsigned n);
+H5_DLL herr_t H5G__ent_encode_vec(const H5F_t *f, uint8_t **pp,
+ const H5G_entry_t *ent, unsigned n);
+H5_DLL herr_t H5G__ent_convert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap,
+ const char *name, const H5O_link_t *lnk, H5O_type_t obj_type,
+ const void *crt_info, H5G_entry_t *ent);
+H5_DLL herr_t H5G__ent_debug(const H5G_entry_t *ent, FILE * stream, int indent,
+ int fwidth, const H5HL_t *heap);
+
+/* Functions that understand symbol table nodes */
+H5_DLL herr_t H5G__node_init(H5F_t *f);
+H5_DLL int H5G__node_iterate(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL int H5G__node_sumup(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL int H5G__node_by_idx(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL int H5G__node_copy(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL int H5G__node_build_table(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL herr_t H5G__node_iterate_size(H5F_t *f, hid_t dxpl_id, const void *_lt_key, haddr_t addr,
+ const void *_rt_key, void *_udata);
+H5_DLL herr_t H5G__node_free(H5G_node_t *sym);
+
+/* Functions that understand links in groups */
+H5_DLL herr_t H5G__ent_to_link(H5O_link_t *lnk, const H5HL_t *heap,
+ const H5G_entry_t *ent, const char *name);
+H5_DLL herr_t H5G__link_to_loc(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc);
+H5_DLL herr_t H5G__link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type,
+ H5_iter_order_t order);
+H5_DLL herr_t H5G__link_iterate_table(const H5G_link_table_t *ltable,
+ hsize_t skip, hsize_t *last_lnk, const H5G_lib_iterate_t op, void *op_data);
+H5_DLL herr_t H5G__link_release_table(H5G_link_table_t *ltable);
+H5_DLL herr_t H5G__link_name_replace(H5F_t *file, hid_t dxpl_id,
+ H5RS_str_t *grp_full_path_r, const H5O_link_t *lnk);
+
+/* Functions that understand "compact" link storage */
+H5_DLL herr_t H5G__compact_insert(const H5O_loc_t *grp_oloc, H5O_link_t *obj_lnk,
+ hid_t dxpl_id);
+H5_DLL ssize_t H5G__compact_get_name_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t idx, char *name, size_t size);
+H5_DLL herr_t H5G__compact_remove(const H5O_loc_t *oloc, hid_t dxpl_id,
+ H5RS_str_t *grp_full_path_r, const char *name);
+H5_DLL herr_t H5G__compact_remove_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n);
+H5_DLL herr_t H5G__compact_iterate(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data);
+H5_DLL htri_t H5G__compact_lookup(const H5O_loc_t *grp_oloc, const char *name,
+ H5O_link_t *lnk, hid_t dxpl_id);
+H5_DLL herr_t H5G__compact_lookup_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t n, H5O_link_t *lnk);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL H5G_obj_t H5G__compact_get_type_by_idx(H5O_loc_t *oloc, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, hsize_t idx);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/* Functions that understand "dense" link storage */
+H5_DLL herr_t H5G__dense_build_table(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, H5G_link_table_t *ltable);
+H5_DLL herr_t H5G__dense_create(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo,
+ const H5O_pline_t *pline);
+H5_DLL herr_t H5G__dense_insert(H5F_t *f, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, const H5O_link_t *lnk);
+H5_DLL htri_t H5G__dense_lookup(H5F_t *f, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, const char *name, H5O_link_t *lnk);
+H5_DLL herr_t H5G__dense_lookup_by_idx(H5F_t *f, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t n, H5O_link_t *lnk);
+H5_DLL herr_t H5G__dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ H5G_lib_iterate_t op, void *op_data);
+H5_DLL ssize_t H5G__dense_get_name_by_idx(H5F_t *f, hid_t dxpl_id,
+ H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ char *name, size_t size);
+H5_DLL herr_t H5G__dense_remove(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
+ H5RS_str_t *grp_full_path_r, const char *name);
+H5_DLL herr_t H5G__dense_remove_by_idx(H5F_t *f, hid_t dxpl_id,
+ const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n);
+H5_DLL herr_t H5G__dense_delete(H5F_t *f, hid_t dxpl_id, H5O_linfo_t *linfo,
+ hbool_t adj_link);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL H5G_obj_t H5G__dense_get_type_by_idx(H5F_t *f, hid_t dxpl_id,
+ H5O_linfo_t *linfo, hsize_t idx);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/* Functions that understand group objects */
+H5_DLL herr_t H5G__obj_create(H5F_t *f, hid_t dxpl_id,
+ H5G_obj_create_t *gcrt_info, H5O_loc_t *oloc/*out*/);
+H5_DLL herr_t H5G__obj_create_real(H5F_t *f, hid_t dxpl_id,
+ const H5O_ginfo_t *ginfo, const H5O_linfo_t *linfo,
+ const H5O_pline_t *pline, H5G_obj_create_t *gcrt_info,
+ H5O_loc_t *oloc/*out*/);
+H5_DLL htri_t H5G__obj_get_linfo(const H5O_loc_t *grp_oloc, H5O_linfo_t *linfo,
+ hid_t dxpl_id);
+H5_DLL herr_t H5G__obj_iterate(const H5O_loc_t *grp_oloc,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ H5G_lib_iterate_t op, void *op_data, hid_t dxpl_id);
+H5_DLL herr_t H5G__obj_info(H5O_loc_t *oloc, H5G_info_t *grp_info, hid_t dxpl_id);
+H5_DLL htri_t H5G__obj_lookup(const H5O_loc_t *grp_oloc, const char *name,
+ H5O_link_t *lnk, hid_t dxpl_id);
+
+/*
+ * These functions operate on group hierarchy names.
+ */
+H5_DLL herr_t H5G__name_init(H5G_name_t *name, const char *path);
+
+/*
+ * These functions operate on group "locations"
+ */
+H5_DLL herr_t H5G__loc_insert(H5G_loc_t *grp_loc, const char *name,
+ H5G_loc_t *obj_loc, H5O_type_t obj_type, const void *crt_info, hid_t dxpl_id);
+
+/* Testing functions */
+#ifdef H5G_TESTING
+H5_DLL htri_t H5G__is_empty_test(hid_t gid);
+H5_DLL htri_t H5G__has_links_test(hid_t gid, unsigned *nmsgs);
+H5_DLL htri_t H5G__has_stab_test(hid_t gid);
+H5_DLL htri_t H5G__is_new_dense_test(hid_t gid);
+H5_DLL herr_t H5G__new_dense_info_test(hid_t gid, hsize_t *name_count, hsize_t *corder_count);
+H5_DLL herr_t H5G__lheap_size_test(hid_t gid, size_t *lheap_size);
+H5_DLL herr_t H5G__user_path_test(hid_t obj_id, char *user_path, size_t *user_path_len, unsigned *user_path_hidden);
+H5_DLL herr_t H5G__verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent);
+H5_DLL herr_t H5G__verify_cached_stabs_test(hid_t gid);
+#endif /* H5G_TESTING */
+
+#endif /* _H5Gpkg_H */
+
diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h
new file mode 100644
index 0000000..c48e687
--- /dev/null
+++ b/src/H5Gprivate.h
@@ -0,0 +1,301 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gprivate.h
+ * Jul 11 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Library-visible declarations.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5Gprivate_H
+#define _H5Gprivate_H
+
+/* Include package's public header */
+#include "H5Gpublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Bprivate.h" /* B-trees */
+#include "H5Fprivate.h" /* File access */
+#include "H5RSprivate.h" /* Reference-counted strings */
+
+/*
+ * The disk size for a symbol table entry...
+ */
+#define H5G_SIZEOF_SCRATCH 16
+#define H5G_SIZEOF_ENTRY(sizeof_addr, sizeof_size) \
+ ((sizeof_size) + /*offset of name into heap */ \
+ (sizeof_addr) + /*address of object header */ \
+ 4 + /*entry type */ \
+ 4 + /*reserved */ \
+ H5G_SIZEOF_SCRATCH) /*scratch pad space */
+#define H5G_SIZEOF_ENTRY_FILE(F) \
+ H5G_SIZEOF_ENTRY(H5F_SIZEOF_ADDR(F), H5F_SIZEOF_SIZE(F))
+
+/* ========= Group Creation properties ============ */
+
+/* Defaults for link info values */
+#define H5G_CRT_LINFO_TRACK_CORDER FALSE
+#define H5G_CRT_LINFO_INDEX_CORDER FALSE
+#define H5G_CRT_LINFO_NLINKS 0
+#define H5G_CRT_LINFO_MAX_CORDER 0
+#define H5G_CRT_LINFO_LINK_FHEAP_ADDR HADDR_UNDEF
+#define H5G_CRT_LINFO_NAME_BT2_ADDR HADDR_UNDEF
+#define H5G_CRT_LINFO_CORDER_BT2_ADDR HADDR_UNDEF
+
+/* Definitions for link info settings */
+#define H5G_CRT_LINK_INFO_NAME "link info"
+#define H5G_CRT_LINK_INFO_SIZE sizeof(H5O_linfo_t)
+#define H5G_CRT_LINK_INFO_DEF {H5G_CRT_LINFO_TRACK_CORDER, \
+ H5G_CRT_LINFO_INDEX_CORDER, \
+ H5G_CRT_LINFO_MAX_CORDER, \
+ H5G_CRT_LINFO_CORDER_BT2_ADDR, \
+ H5G_CRT_LINFO_NLINKS, \
+ H5G_CRT_LINFO_LINK_FHEAP_ADDR, \
+ H5G_CRT_LINFO_NAME_BT2_ADDR \
+ }
+
+/* Defaults for group info values */
+#define H5G_CRT_GINFO_LHEAP_SIZE_HINT 0
+#define H5G_CRT_GINFO_STORE_LINK_PHASE_CHANGE FALSE
+#define H5G_CRT_GINFO_MAX_COMPACT 8
+#define H5G_CRT_GINFO_MIN_DENSE 6
+#define H5G_CRT_GINFO_STORE_EST_ENTRY_INFO FALSE
+#define H5G_CRT_GINFO_EST_NUM_ENTRIES 4
+#define H5G_CRT_GINFO_EST_NAME_LEN 8
+
+/* Definitions for group info settings */
+#define H5G_CRT_GROUP_INFO_NAME "group info"
+#define H5G_CRT_GROUP_INFO_SIZE sizeof(H5O_ginfo_t)
+#define H5G_CRT_GROUP_INFO_DEF {H5G_CRT_GINFO_LHEAP_SIZE_HINT, \
+ H5G_CRT_GINFO_STORE_LINK_PHASE_CHANGE, \
+ H5G_CRT_GINFO_MAX_COMPACT, \
+ H5G_CRT_GINFO_MIN_DENSE, \
+ H5G_CRT_GINFO_STORE_EST_ENTRY_INFO, \
+ H5G_CRT_GINFO_EST_NUM_ENTRIES, \
+ H5G_CRT_GINFO_EST_NAME_LEN \
+ }
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5G_MODULE
+#define H5G_MOUNTED(G) ((G)->shared->mounted)
+#else /* H5G_MODULE */
+#define H5G_MOUNTED(G) (H5G_mounted(G))
+#endif /* H5G_MODULE */
+
+/*
+ * During name lookups (see H5G_traverse()) we sometimes want information about
+ * a symbolic link or a mount point. The normal operation is to follow the
+ * symbolic link or mount point and return information about its target.
+ */
+#define H5G_TARGET_NORMAL 0x0000
+#define H5G_TARGET_SLINK 0x0001
+#define H5G_TARGET_MOUNT 0x0002
+#define H5G_TARGET_UDLINK 0x0004
+#define H5G_TARGET_EXISTS 0x0008
+#define H5G_CRT_INTMD_GROUP 0x0010
+
+/* Type of operation being performed for call to H5G_name_replace() */
+typedef enum {
+ H5G_NAME_MOVE = 0, /* H5*move call */
+ H5G_NAME_DELETE, /* H5Ldelete call */
+ H5G_NAME_MOUNT, /* H5Fmount call */
+ H5G_NAME_UNMOUNT /* H5Funmount call */
+} H5G_names_op_t;
+
+/* Status returned from traversal callbacks; whether the object location
+ * or group location need to be closed */
+#define H5G_OWN_NONE 0
+#define H5G_OWN_OBJ_LOC 1
+#define H5G_OWN_GRP_LOC 2
+#define H5G_OWN_BOTH 3
+typedef int H5G_own_loc_t;
+
+/* Structure to store information about the name an object was opened with */
+typedef struct {
+ H5RS_str_t *full_path_r; /* Path to object, as seen from root of current file mounting hierarchy */
+ H5RS_str_t *user_path_r; /* Path to object, as opened by user */
+ unsigned obj_hidden; /* Whether the object is visible in group hier. */
+} H5G_name_t;
+
+/* Forward declarations (for prototypes & struct definitions) */
+struct H5O_loc_t;
+struct H5O_link_t;
+
+/*
+ * The "location" of an object in a group hierarchy. This points to an object
+ * location and a group hierarchy path for the object.
+ */
+typedef struct {
+ struct H5O_loc_t *oloc; /* Object header location */
+ H5G_name_t *path; /* Group hierarchy path */
+} H5G_loc_t;
+
+/* Typedef for path traversal operations */
+/* grp_loc is the location of the group in which the targeted object is located.
+ * name is the last component of the object's name
+ * lnk is the link between the group and the object
+ * obj_loc is the target of the traversal (or NULL if the object doesn't exist)
+ * operator_data is whatever udata was supplied when H5G_traverse was called
+ * own_loc should be set to H5G_OWN_OBJ_LOC if this callback takes ownership of obj_loc,
+ * H5G_OWN_GRP_LOC if it takes ownership of grp_loc, and H5G_OWN_NONE if obj_loc and
+ * grp_loc need to be deleted.
+ */
+typedef herr_t (*H5G_traverse_t)(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const struct H5O_link_t *lnk/*in*/, H5G_loc_t *obj_loc/*out*/, void *operator_data/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+
+/* Describe kind of callback to make for each link */
+typedef enum H5G_link_iterate_op_type_t {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ H5G_LINK_OP_OLD, /* "Old" application callback */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ H5G_LINK_OP_NEW /* "New" application callback */
+} H5G_link_iterate_op_type_t;
+
+typedef struct {
+ H5G_link_iterate_op_type_t op_type;
+ union {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ H5G_iterate_t op_old; /* "Old" application callback for each link */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ H5L_iterate_t op_new; /* "New" application callback for each link */
+ } op_func;
+} H5G_link_iterate_t;
+
+typedef struct H5G_t H5G_t;
+typedef struct H5G_shared_t H5G_shared_t;
+typedef struct H5G_entry_t H5G_entry_t;
+
+/*
+ * Library prototypes... These are the ones that other packages routinely
+ * call.
+ */
+H5_DLL struct H5O_loc_t *H5G_oloc(H5G_t *grp);
+H5_DLL H5G_name_t * H5G_nameof(H5G_t *grp);
+H5_DLL H5F_t *H5G_fileof(H5G_t *grp);
+H5_DLL H5G_t *H5G_open(const H5G_loc_t *loc, hid_t dxpl_id);
+H5_DLL herr_t H5G_close(H5G_t *grp);
+H5_DLL herr_t H5G_get_shared_count(H5G_t *grp);
+H5_DLL herr_t H5G_mount(H5G_t *grp);
+H5_DLL hbool_t H5G_mounted(H5G_t *grp);
+H5_DLL herr_t H5G_unmount(H5G_t *grp);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL H5G_obj_t H5G_map_obj_type(H5O_type_t obj_type);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/*
+ * Utility functions
+ */
+H5_DLL char *H5G_normalize(const char *name);
+
+/*
+ * Group hierarchy traversal routines
+ */
+H5_DLL herr_t H5G_traverse(const H5G_loc_t *loc, const char *name,
+ unsigned target, H5G_traverse_t op, void *op_data, hid_t lapl_id,
+ hid_t dxpl_id);
+H5_DLL herr_t H5G_iterate(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+ const H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_visit(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data,
+ hid_t lapl_id, hid_t dxpl_id);
+
+/*
+ * Functions that understand links in groups
+ */
+H5_DLL herr_t H5G_link_to_info(const struct H5O_link_t *lnk, H5L_info_t *linfo);
+
+/*
+ * Functions that understand group objects
+ */
+H5_DLL herr_t H5G_obj_insert(const struct H5O_loc_t *grp_oloc, const char *name,
+ struct H5O_link_t *obj_lnk, hbool_t adj_link, H5O_type_t obj_type,
+ const void *crt_info, hid_t dxpl_id);
+H5_DLL ssize_t H5G_obj_get_name_by_idx(const struct H5O_loc_t *oloc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, char* name, size_t size, hid_t dxpl_id);
+H5_DLL herr_t H5G_obj_remove(const struct H5O_loc_t *oloc, H5RS_str_t *grp_full_path_r,
+ const char *name, hid_t dxpl_id);
+H5_DLL herr_t H5G_obj_remove_by_idx(const struct H5O_loc_t *grp_oloc, H5RS_str_t *grp_full_path_r,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t dxpl_id);
+H5_DLL herr_t H5G_obj_lookup_by_idx(const struct H5O_loc_t *grp_oloc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, struct H5O_link_t *lnk, hid_t dxpl_id);
+H5_DLL hid_t H5G_get_create_plist(H5G_t *grp);
+
+/*
+ * These functions operate on symbol table nodes.
+ */
+H5_DLL herr_t H5G_node_close(const H5F_t *f);
+H5_DLL herr_t H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream,
+ int indent, int fwidth, haddr_t heap);
+
+/*
+ * These functions operate on group object locations.
+ */
+H5_DLL herr_t H5G_ent_encode(const H5F_t *f, uint8_t **pp, const H5G_entry_t *ent);
+H5_DLL herr_t H5G_ent_decode(const H5F_t *f, const uint8_t **pp, H5G_entry_t *ent);
+
+/*
+ * These functions operate on group hierarchy names.
+ */
+H5_DLL herr_t H5G_name_set(const H5G_name_t *loc, H5G_name_t *obj, const char *name);
+H5_DLL herr_t H5G_name_replace(const struct H5O_link_t *lnk, H5G_names_op_t op,
+ H5F_t *src_file, H5RS_str_t *src_full_path_r, H5F_t *dst_file,
+ H5RS_str_t *dst_full_path_r, hid_t dxpl_id);
+H5_DLL herr_t H5G_name_reset(H5G_name_t *name);
+H5_DLL herr_t H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5_copy_depth_t depth);
+H5_DLL herr_t H5G_name_free(H5G_name_t *name);
+H5_DLL ssize_t H5G_get_name(const H5G_loc_t *loc, char *name/*out*/, size_t size,
+ hbool_t *cached, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL ssize_t H5G_get_name_by_addr(hid_t fid, hid_t lapl_id, hid_t dxpl_id,
+ const struct H5O_loc_t *loc, char* name, size_t size);
+H5_DLL H5RS_str_t *H5G_build_fullpath_refstr_str(H5RS_str_t *path_r, const char *name);
+
+/*
+ * These functions operate on group "locations"
+ */
+H5_DLL herr_t H5G_loc(hid_t loc_id, H5G_loc_t *loc);
+H5_DLL herr_t H5G_loc_copy(H5G_loc_t *dst, const H5G_loc_t *src, H5_copy_depth_t depth);
+H5_DLL herr_t H5G_loc_find(const H5G_loc_t *loc, const char *name,
+ H5G_loc_t *obj_loc/*out*/, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_loc_find_by_idx(H5G_loc_t *loc, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ H5G_loc_t *obj_loc/*out*/, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL htri_t H5G_loc_exists(const H5G_loc_t *loc, const char *name,
+ hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_loc_info(H5G_loc_t *loc, const char *name,
+ hbool_t want_ih_info, H5O_info_t *oinfo/*out*/, hid_t lapl_id,
+ hid_t dxpl_id);
+H5_DLL herr_t H5G_loc_set_comment(H5G_loc_t *loc, const char *name,
+ const char *comment, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL ssize_t H5G_loc_get_comment(H5G_loc_t *loc, const char *name,
+ char *comment/*out*/, size_t bufsize, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_loc_reset(H5G_loc_t *loc);
+H5_DLL herr_t H5G_loc_free(H5G_loc_t *loc);
+
+/*
+ * These functions operate on the root group
+ */
+H5_DLL herr_t H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t create_root);
+H5_DLL herr_t H5G_root_loc(H5F_t *f, H5G_loc_t *loc);
+H5_DLL herr_t H5G_root_free(H5G_t *grp);
+H5_DLL H5G_t *H5G_rootof(H5F_t *f);
+
+#endif /* _H5Gprivate_H */
+
diff --git a/src/H5Gpublic.h b/src/H5Gpublic.h
new file mode 100644
index 0000000..ab6f200
--- /dev/null
+++ b/src/H5Gpublic.h
@@ -0,0 +1,178 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gpublic.h
+ * Jul 11 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public declarations for the H5G package
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Gpublic_H
+#define _H5Gpublic_H
+
+/* System headers needed by this file */
+#include <sys/types.h>
+
+/* Public headers needed by this file */
+#include "H5public.h" /* Generic Functions */
+#include "H5Lpublic.h" /* Links */
+#include "H5Opublic.h" /* Object headers */
+#include "H5Tpublic.h" /* Datatypes */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/* Types of link storage for groups */
+typedef enum H5G_storage_type_t {
+ H5G_STORAGE_TYPE_UNKNOWN = -1, /* Unknown link storage type */
+ H5G_STORAGE_TYPE_SYMBOL_TABLE, /* Links in group are stored with a "symbol table" */
+ /* (this is sometimes called "old-style" groups) */
+ H5G_STORAGE_TYPE_COMPACT, /* Links are stored in object header */
+ H5G_STORAGE_TYPE_DENSE /* Links are stored in fractal heap & indexed with v2 B-tree */
+} H5G_storage_type_t;
+
+/* Information struct for group (for H5Gget_info/H5Gget_info_by_name/H5Gget_info_by_idx) */
+typedef struct H5G_info_t {
+ H5G_storage_type_t storage_type; /* Type of storage for links in group */
+ hsize_t nlinks; /* Number of links in group */
+ int64_t max_corder; /* Current max. creation order value for group */
+ hbool_t mounted; /* Whether group has a file mounted on it */
+} H5G_info_t;
+
+/********************/
+/* Public Variables */
+/********************/
+
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+H5_DLL hid_t H5Gcreate2(hid_t loc_id, const char *name, hid_t lcpl_id,
+ hid_t gcpl_id, hid_t gapl_id);
+H5_DLL hid_t H5Gcreate_anon(hid_t loc_id, hid_t gcpl_id, hid_t gapl_id);
+H5_DLL hid_t H5Gopen2(hid_t loc_id, const char *name, hid_t gapl_id);
+H5_DLL hid_t H5Gget_create_plist(hid_t group_id);
+H5_DLL herr_t H5Gget_info(hid_t loc_id, H5G_info_t *ginfo);
+H5_DLL herr_t H5Gget_info_by_name(hid_t loc_id, const char *name, H5G_info_t *ginfo,
+ hid_t lapl_id);
+H5_DLL herr_t H5Gget_info_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, H5G_info_t *ginfo,
+ hid_t lapl_id);
+H5_DLL herr_t H5Gclose(hid_t group_id);
+H5_DLL herr_t H5Gflush(hid_t group_id);
+H5_DLL herr_t H5Grefresh(hid_t group_id);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+/* Link definitions */
+#define H5G_SAME_LOC H5L_SAME_LOC
+#define H5G_LINK_ERROR H5L_TYPE_ERROR
+#define H5G_LINK_HARD H5L_TYPE_HARD
+#define H5G_LINK_SOFT H5L_TYPE_SOFT
+#define H5G_link_t H5L_type_t
+
+/* Macros for types of objects in a group (see H5G_obj_t definition) */
+#define H5G_NTYPES 256 /* Max possible number of types */
+#define H5G_NLIBTYPES 8 /* Number of internal types */
+#define H5G_NUSERTYPES (H5G_NTYPES - H5G_NLIBTYPES)
+#define H5G_USERTYPE(X) (8 + (X)) /* User defined types */
+
+
+/* Typedefs */
+
+/*
+ * An object has a certain type. The first few numbers are reserved for use
+ * internally by HDF5. Users may add their own types with higher values. The
+ * values are never stored in the file -- they only exist while an
+ * application is running. An object may satisfy the `isa' function for more
+ * than one type.
+ */
+typedef enum H5G_obj_t {
+ H5G_UNKNOWN = -1, /* Unknown object type */
+ H5G_GROUP, /* Object is a group */
+ H5G_DATASET, /* Object is a dataset */
+ H5G_TYPE, /* Object is a named data type */
+ H5G_LINK, /* Object is a symbolic link */
+ H5G_UDLINK, /* Object is a user-defined link */
+ H5G_RESERVED_5, /* Reserved for future use */
+ H5G_RESERVED_6, /* Reserved for future use */
+ H5G_RESERVED_7 /* Reserved for future use */
+} H5G_obj_t;
+
+/* Prototype for H5Giterate() operator */
+typedef herr_t (*H5G_iterate_t)(hid_t group, const char *name, void *op_data);
+
+/* Information about an object */
+typedef struct H5G_stat_t {
+ unsigned long fileno[2]; /*file number */
+ unsigned long objno[2]; /*object number */
+ unsigned nlink; /*number of hard links to object*/
+ H5G_obj_t type; /*basic object type */
+ time_t mtime; /*modification time */
+ size_t linklen; /*symbolic link value length */
+ H5O_stat_t ohdr; /* Object header information */
+} H5G_stat_t;
+
+
+/* Function prototypes */
+H5_DLL hid_t H5Gcreate1(hid_t loc_id, const char *name, size_t size_hint);
+H5_DLL hid_t H5Gopen1(hid_t loc_id, const char *name);
+H5_DLL herr_t H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name,
+ const char *new_name);
+H5_DLL herr_t H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type,
+ hid_t new_loc_id, const char *new_name);
+H5_DLL herr_t H5Gmove(hid_t src_loc_id, const char *src_name,
+ const char *dst_name);
+H5_DLL herr_t H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name);
+H5_DLL herr_t H5Gunlink(hid_t loc_id, const char *name);
+H5_DLL herr_t H5Gget_linkval(hid_t loc_id, const char *name, size_t size,
+ char *buf/*out*/);
+H5_DLL herr_t H5Gset_comment(hid_t loc_id, const char *name, const char *comment);
+H5_DLL int H5Gget_comment(hid_t loc_id, const char *name, size_t bufsize,
+ char *buf);
+H5_DLL herr_t H5Giterate(hid_t loc_id, const char *name, int *idx,
+ H5G_iterate_t op, void *op_data);
+H5_DLL herr_t H5Gget_num_objs(hid_t loc_id, hsize_t *num_objs);
+H5_DLL herr_t H5Gget_objinfo(hid_t loc_id, const char *name,
+ hbool_t follow_link, H5G_stat_t *statbuf/*out*/);
+H5_DLL ssize_t H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char* name,
+ size_t size);
+H5_DLL H5G_obj_t H5Gget_objtype_by_idx(hid_t loc_id, hsize_t idx);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Gpublic_H */
+
diff --git a/src/H5Groot.c b/src/H5Groot.c
new file mode 100644
index 0000000..fbc4f1a
--- /dev/null
+++ b/src/H5Groot.c
@@ -0,0 +1,412 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Groot.c
+ * Apr 8 2009
+ * Neil Fortner <nfortne2@hdfgroup.org>
+ *
+ * Purpose: Functions for operating on the root group.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property Lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_rootof
+ *
+ * Purpose: Return a pointer to the root group of the file. If the file
+ * is part of a virtual file then the root group of the virtual
+ * file is returned.
+ *
+ * Return: Success: Ptr to the root group of the file. Do not
+ * free the pointer -- it points directly into
+ * the file struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_t *
+H5G_rootof(H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Walk to top of mounted files */
+ while(f->parent)
+ f = f->parent;
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->root_grp);
+
+ /* Check to see if the root group was opened through a different
+ * "top" file, and switch it to point at the current "top" file.
+ */
+ if(f->shared->root_grp->oloc.file != f)
+ f->shared->root_grp->oloc.file = f;
+
+ FUNC_LEAVE_NOAPI(f->shared->root_grp)
+} /* end H5G_rootof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_mkroot
+ *
+ * Purpose: Creates a root group in an empty file and opens it. If a
+ * root group is already open then this function immediately
+ * returns. If ENT is non-null then it's the symbol table
+ * entry for an existing group which will be opened as the root
+ * group. Otherwise a new root group is created and then
+ * opened.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t create_root)
+{
+ H5G_loc_t root_loc; /* Root location information */
+ H5G_obj_create_t gcrt_info; /* Root group object creation info */
+ htri_t stab_exists = -1; /* Whether the symbol table exists */
+ hbool_t sblock_dirty = FALSE; /* Whether superblock was dirtied */
+ hbool_t path_init = FALSE; /* Whether path was initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->sblock);
+
+ /* Check if the root group is already initialized */
+ if(f->shared->root_grp)
+ HGOTO_DONE(SUCCEED)
+
+ /* Create information needed for group nodes */
+ if(H5G__node_init(f) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info")
+
+ /*
+ * Create the group pointer
+ */
+ if(NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) {
+ f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end if */
+
+ /* Initialize the root_loc structure to point to fields in the newly created
+ * f->shared->root_grp structure */
+ root_loc.oloc = &(f->shared->root_grp->oloc);
+ root_loc.path = &(f->shared->root_grp->path);
+ H5G_loc_reset(&root_loc);
+
+ /*
+ * If there is no root object then create one. The root group always starts
+ * with a hard link count of one since it's pointed to by the superblock.
+ */
+ if(create_root) {
+ /* Create root group */
+ /* (Pass the FCPL which is a sub-class of the group creation property class) */
+ gcrt_info.gcpl_id = f->shared->fcpl_id;
+ gcrt_info.cache_type = H5G_NOTHING_CACHED;
+ if(H5G__obj_create(f, dxpl_id, &gcrt_info, root_loc.oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry")
+ if(1 != H5O_link(root_loc.oloc, 1, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)")
+
+ /* Decrement refcount on root group's object header in memory */
+ if(H5O_dec_rc_by_loc(root_loc.oloc, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on root group's object header")
+
+ /* Mark superblock dirty, so root group info is flushed */
+ sblock_dirty = TRUE;
+
+ /* Create the root group symbol table entry */
+ HDassert(!f->shared->sblock->root_ent);
+ if(f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
+ /* Allocate space for the root group symbol table entry */
+ if(NULL == (f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry")
+
+ /* Initialize the root group symbol table entry */
+ f->shared->sblock->root_ent->type = gcrt_info.cache_type;
+ if(gcrt_info.cache_type != H5G_NOTHING_CACHED)
+ f->shared->sblock->root_ent->cache = gcrt_info.cache;
+ f->shared->sblock->root_ent->name_off = 0; /* No name (yet) */
+ f->shared->sblock->root_ent->header = root_loc.oloc->addr;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Create root group object location from f */
+ root_loc.oloc->addr = f->shared->sblock->root_addr;
+ root_loc.oloc->file = f;
+
+ /*
+ * Open the root object as a group.
+ */
+ if(H5O_open(root_loc.oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group")
+
+ /* Actions to take if the symbol table information is cached */
+ if(f->shared->sblock->root_ent && f->shared->sblock->root_ent->type == H5G_CACHED_STAB) {
+ /* Check for the situation where the symbol table is cached but does
+ * not exist. This can happen if, for example, an external link is
+ * added to the root group. */
+ if((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists")
+
+ /* Remove the cache if the stab does not exist */
+ if(!stab_exists)
+ f->shared->sblock->root_ent->type = H5G_NOTHING_CACHED;
+#ifndef H5_STRICT_FORMAT_CHECKS
+ /* If symbol table information is cached, check if we should replace the
+ * symbol table message with the cached symbol table information */
+ else if(H5F_INTENT(f) & H5F_ACC_RDWR) {
+ H5O_stab_t cached_stab;
+
+ /* Retrieve the cached symbol table information */
+ cached_stab.btree_addr = f->shared->sblock->root_ent->cache.stab.btree_addr;
+ cached_stab.heap_addr = f->shared->sblock->root_ent->cache.stab.heap_addr;
+
+ /* Check if the symbol table message is valid, and replace with the
+ * cached symbol table if necessary */
+ if(H5G__stab_valid(root_loc.oloc, dxpl_id, &cached_stab) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table")
+ } /* end if */
+#endif /* H5_STRICT_FORMAT_CHECKS */
+ } /* end if */
+ } /* end else */
+
+ /* Cache the root group's symbol table information in the root group symbol
+ * table entry. It will have been allocated by now if it needs to be
+ * present, so we don't need to check the superblock version. We do this if
+ * we have write access, the root entry has been allocated (i.e.
+ * super_vers < 2) and the stab info is not already cached. */
+ if((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != FALSE && f->shared->sblock->root_ent
+ && f->shared->sblock->root_ent->type != H5G_CACHED_STAB) {
+ H5O_stab_t stab; /* Symbol table */
+
+ /* Check if the stab message exists. It's possible for the root group
+ * to use the latest version while the superblock is an old version.
+ * If stab_exists is not -1 then we have already checked. */
+ if(stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists")
+
+ if(stab_exists) {
+ /* Read the root group's symbol table message */
+ if(NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message")
+
+ /* Update the root group symbol table entry */
+ f->shared->sblock->root_ent->type = H5G_CACHED_STAB;
+ f->shared->sblock->root_ent->cache.stab.btree_addr = stab.btree_addr;
+ f->shared->sblock->root_ent->cache.stab.heap_addr = stab.heap_addr;
+
+ /* Mark superblock dirty, so root group info is flushed */
+ sblock_dirty = TRUE;
+ } /* end if */
+ } /* end if */
+
+ /* Create the path names for the root group's entry */
+ H5G__name_init(root_loc.path, "/");
+ path_init = TRUE;
+
+ f->shared->root_grp->shared->fo_count = 1;
+ /* The only other open object should be the superblock extension, if it
+ * exists. Don't count either the superblock extension or the root group
+ * in the number of open objects in the file.
+ */
+ HDassert((1 == f->nopen_objs) ||
+ (2 == f->nopen_objs && HADDR_UNDEF != f->shared->sblock->ext_addr));
+ f->nopen_objs--;
+
+done:
+ /* In case of error, free various memory locations that may have been
+ * allocated */
+ if(ret_value < 0) {
+ if(f->shared->root_grp) {
+ if(path_init)
+ H5G_name_free(root_loc.path);
+ if(f->shared->root_grp->shared)
+ f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared);
+ f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
+ } /* end if */
+ if(f->shared->sblock)
+ f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_xfree(f->shared->sblock->root_ent);
+ } /* end if */
+
+ /* Mark superblock dirty in cache, if necessary */
+ if(sblock_dirty)
+ if(H5AC_mark_entry_dirty(f->shared->sblock) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_mkroot() */
+
+
+/*-------------------------------------------------------------------------
+* Function: H5G_root_free
+*
+* Purpose: Free memory used by an H5G_t struct (and its H5G_shared_t).
+* Does not close the group or decrement the reference count.
+* Used to free memory used by the root group.
+*
+* Return: Success: Non-negative
+* Failure: Negative
+*
+* Programmer: James Laird
+* Tuesday, September 7, 2004
+*
+*-------------------------------------------------------------------------
+*/
+herr_t
+H5G_root_free(H5G_t *grp)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(grp && grp->shared);
+ HDassert(grp->shared->fo_count > 0);
+
+ /* Free the path */
+ H5G_name_free(&(grp->path));
+
+ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
+ grp = H5FL_FREE(H5G_t, grp);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_root_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_root_loc
+ *
+ * Purpose: Construct a "group location" for the root group of a file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 5 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_root_loc(H5F_t *f, H5G_loc_t *loc)
+{
+ H5G_t *root_grp; /* Pointer to root group's info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(loc);
+
+ /* Retrieve the root group for the file */
+ root_grp = H5G_rootof(f);
+ HDassert(root_grp);
+
+ /* Build the group location for the root group */
+ if(NULL == (loc->oloc = H5G_oloc(root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (loc->path = H5G_nameof(root_grp)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Patch up root group's object location to reflect this file */
+ /* (Since the root group info is only stored once for files which
+ * share an underlying low-level file)
+ */
+ /* (but only for non-mounted files) */
+ if(!H5F_is_mount(f)) {
+ loc->oloc->file = f;
+ loc->oloc->holding_file = FALSE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_root_loc() */
+
diff --git a/src/H5Gstab.c b/src/H5Gstab.c
new file mode 100644
index 0000000..a239cfe
--- /dev/null
+++ b/src/H5Gstab.c
@@ -0,0 +1,1226 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, September 19, 1997
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for finding link information from B-tree */
+typedef struct {
+ /* downward */
+ const char *name; /* Name to search for */
+ H5HL_t *heap; /* Local heap for group */
+
+ /* upward */
+ H5O_link_t *lnk; /* Caller's link location */
+} H5G_stab_fnd_ud_t;
+
+/* Data passed through B-tree iteration for looking up a name by index */
+typedef struct H5G_bt_it_gnbi_t {
+ /* downward */
+ H5G_bt_it_idx_common_t common; /* Common information for "by index" lookup */
+ H5HL_t *heap; /*symbol table heap */
+
+ /* upward */
+ char *name; /*member name to be returned */
+} H5G_bt_it_gnbi_t;
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+/* Data passed through B-tree iteration for looking up a type by index */
+typedef struct H5G_bt_it_gtbi_t {
+ /* downward */
+ H5G_bt_it_idx_common_t common; /* Common information for "by index" lookup */
+ H5F_t *f; /* Pointer to file that symbol table is in */
+ hid_t dxpl_id; /* DXPL for operation */
+
+ /* upward */
+ H5G_obj_t type; /*member type to be returned */
+} H5G_bt_it_gtbi_t;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/* Data passed through B-tree iteration for looking up a link by index */
+typedef struct H5G_bt_it_lbi_t {
+ /* downward */
+ H5G_bt_it_idx_common_t common; /* Common information for "by index" lookup */
+ H5HL_t *heap; /*symbol table heap */
+
+ /* upward */
+ H5O_link_t *lnk; /*link to be returned */
+ hbool_t found; /*whether we found the link */
+} H5G_bt_it_lbi_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_create_components
+ *
+ * Purpose: Creates the components for a new, empty, symbol table (name heap
+ * and B-tree). The caller can specify an initial size for the
+ * name heap.
+ *
+ * In order for the B-tree to operate correctly, the first
+ * item in the heap is the empty string, and must appear at
+ * heap offset zero.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Nov 7 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint, hid_t dxpl_id)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ size_t name_offset; /* Offset of "" name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(stab);
+ HDassert(size_hint > 0);
+
+ /* Create the B-tree */
+ if(H5B_create(f, dxpl_id, H5B_SNODE, NULL, &(stab->btree_addr)/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create B-tree")
+
+ /* Create symbol table private heap */
+ if(H5HL_create(f, dxpl_id, size_hint, &(stab->heap_addr)/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create heap")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Insert name into the heap */
+ if(UFAIL == (name_offset = H5HL_insert(f, dxpl_id, heap, (size_t)1, "")))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert name into heap")
+
+ /*
+ * B-tree's won't work if the first name isn't at the beginning
+ * of the heap.
+ */
+ HDassert(0 == name_offset);
+
+done:
+ /* Release resources */
+ if(heap && FAIL == H5HL_unprotect(heap))
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_create_components() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_create
+ *
+ * Purpose: Creates a new empty symbol table (object header, name heap,
+ * and B-tree). The caller can specify an initial size for the
+ * name heap. The object header of the group is opened for
+ * write access.
+ *
+ * In order for the B-tree to operate correctly, the first
+ * item in the heap is the empty string, and must appear at
+ * heap offset zero.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 1 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_create(H5O_loc_t *grp_oloc, hid_t dxpl_id, const H5O_ginfo_t *ginfo,
+ H5O_stab_t *stab)
+{
+ size_t heap_hint; /* Local heap size hint */
+ size_t size_hint; /* Local heap size hint */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(grp_oloc);
+ HDassert(stab);
+
+ /* Adjust the size hint, if necessary */
+ if(ginfo->lheap_size_hint == 0)
+ heap_hint = 8 + /* "null" name inserted for B-tree */
+ (ginfo->est_num_entries * H5HL_ALIGN(ginfo->est_name_len + 1)) + /* estimated size of names for links, aligned for inserting into local heap */
+ H5HL_SIZEOF_FREE(grp_oloc->file); /* Free list entry in local heap */
+ else
+ heap_hint = ginfo->lheap_size_hint;
+ size_hint = MAX(heap_hint, H5HL_SIZEOF_FREE(grp_oloc->file) + 2);
+
+ /* Go create the B-tree & local heap */
+ if(H5G__stab_create_components(grp_oloc->file, stab, size_hint, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create symbol table components")
+
+ /*
+ * Insert the symbol table message into the object header and the symbol
+ * table entry.
+ */
+ if(H5O_msg_create(grp_oloc, H5O_STAB_ID, 0, H5O_UPDATE_TIME, stab, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__stab_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_insert_real
+ *
+ * Purpose: Insert a new symbol into a table.
+ * The name of the new symbol is NAME and its symbol
+ * table entry is OBJ_LNK.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@uiuc.edu
+ * Nov 7 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_insert_real(H5F_t *f, const H5O_stab_t *stab, const char *name,
+ H5O_link_t *obj_lnk, H5O_type_t obj_type, const void *crt_info,
+ hid_t dxpl_id)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5G_bt_ins_t udata; /* Data to pass through B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(stab);
+ HDassert(name && *name);
+ HDassert(obj_lnk);
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Initialize data to pass through B-tree */
+ udata.common.name = name;
+ udata.common.heap = heap;
+ udata.lnk = obj_lnk;
+ udata.obj_type = obj_type;
+ udata.crt_info = crt_info;
+
+ /* Insert into symbol table */
+ if(H5B_insert(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_insert_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_insert
+ *
+ * Purpose: Insert a new symbol into the table described by GRP_ENT in
+ * file F. The name of the new symbol is NAME and its symbol
+ * table entry is OBJ_ENT.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 1 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_insert(const H5O_loc_t *grp_oloc, const char *name,
+ H5O_link_t *obj_lnk, H5O_type_t obj_type, const void *crt_info,
+ hid_t dxpl_id)
+{
+ H5O_stab_t stab; /* Symbol table message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+ HDassert(obj_lnk);
+
+ /* Retrieve symbol table message */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table")
+
+ if(H5G__stab_insert_real(grp_oloc->file, &stab, name, obj_lnk, obj_type,
+ crt_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "unable to insert the name")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, H5_ITER_ERROR)
+} /* end H5G__stab_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_remove
+ *
+ * Purpose: Remove NAME from a symbol table.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 17, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_remove(const H5O_loc_t *loc, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
+ const char *name)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5O_stab_t stab; /*symbol table message */
+ H5G_bt_rm_t udata; /*data to pass through B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(loc && loc->file);
+ HDassert(name && *name);
+
+ /* Read in symbol table message */
+ if(NULL == H5O_msg_read(loc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(loc->file, dxpl_id, stab.heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Initialize data to pass through B-tree */
+ udata.common.name = name;
+ udata.common.heap = heap;
+ udata.grp_full_path_r = grp_full_path_r;
+
+ /* Remove from symbol table */
+ if(H5B_remove(loc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_remove_by_idx
+ *
+ * Purpose: Remove NAME from a symbol table, according to the name index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, November 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_remove_by_idx(const H5O_loc_t *grp_oloc, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
+ H5_iter_order_t order, hsize_t n)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5O_stab_t stab; /* Symbol table message */
+ H5G_bt_rm_t udata; /* Data to pass through B-tree */
+ H5O_link_t obj_lnk; /* Object's link within group */
+ hbool_t lnk_copied = FALSE; /* Whether the link was copied */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(grp_oloc && grp_oloc->file);
+
+ /* Look up name of link to remove, by index */
+ if(H5G__stab_lookup_by_idx(grp_oloc, order, n, &obj_lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get link information")
+ lnk_copied = TRUE;
+
+ /* Read in symbol table message */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Initialize data to pass through B-tree */
+ udata.common.name = obj_lnk.name;
+ udata.common.heap = heap;
+ udata.grp_full_path_r = grp_full_path_r;
+
+ /* Remove link from symbol table */
+ if(H5B_remove(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ /* Reset the link information, if we have a copy */
+ if(lnk_copied)
+ H5O_msg_reset(H5O_LINK_ID, &obj_lnk);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_delete
+ *
+ * Purpose: Delete entire symbol table information from file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5G_bt_rm_t udata; /*data to pass through B-tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(f);
+ HDassert(stab);
+ HDassert(H5F_addr_defined(stab->btree_addr));
+ HDassert(H5F_addr_defined(stab->heap_addr));
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Set up user data for B-tree deletion */
+ udata.common.name = NULL;
+ udata.common.heap = heap;
+
+ /* Delete entire B-tree */
+ if(H5B_delete(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table B-tree")
+
+ /* Release resources */
+ if(H5HL_unprotect(heap) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+ heap = NULL;
+
+ /* Delete local heap for names */
+ if(H5HL_delete(f, dxpl_id, stab->heap_addr) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table heap")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_iterate
+ *
+ * Purpose: Iterate over the objects in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
+ hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data)
+{
+ H5HL_t *heap = NULL; /* Local heap for group */
+ H5O_stab_t stab; /* Info about symbol table */
+ H5G_link_table_t ltable = {0, NULL}; /* Link table */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(op);
+
+ /* Get the B-tree info */
+ if(NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Check on iteration order */
+ /* ("native" iteration order is increasing for this link storage mechanism) */
+ if(order != H5_ITER_DEC) {
+ H5G_bt_it_it_t udata; /* User data to pass to B-tree callback */
+
+ /* Build udata to pass through H5B_iterate() to H5G__node_iterate() */
+ udata.heap = heap;
+ udata.skip = skip;
+ udata.final_ent = last_lnk;
+ udata.op = op;
+ udata.op_data = op_data;
+
+ /* Iterate over the group members */
+ if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_iterate, &udata)) < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+
+ /* Check for too high of a starting index (ex post facto :-) */
+ /* (Skipping exactly as many entries as are in the group is currently an error) */
+ if(skip > 0 && skip >= *last_lnk)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+ } /* end if */
+ else {
+ H5G_bt_it_bt_t udata; /* User data to pass to B-tree callback */
+
+ /* Build udata to pass through H5B_iterate() to H5G__node_build_table() */
+ udata.alloc_nlinks = 0;
+ udata.heap = heap;
+ udata.ltable = &ltable;
+
+ /* Iterate over the group members */
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_build_table, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to build link table")
+
+ /* Check for skipping out of bounds */
+ if(skip > 0 && (size_t)skip >= ltable.nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
+
+ /* Sort link table in correct iteration order */
+ if(H5G__link_sort_table(&ltable, H5_INDEX_NAME, order) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages")
+
+ /* Iterate over links in table */
+ if((ret_value = H5G__link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
+ HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+ if(ltable.lnks && H5G__link_release_table(&ltable) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__stab_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_count
+ *
+ * Purpose: Count the # of links in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_count(H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id)
+{
+ H5O_stab_t stab; /* Info about symbol table */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, oloc->addr, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(num_objs);
+
+ /* Reset the number of objects in the group */
+ *num_objs = 0;
+
+ /* Get the B-tree info */
+ if(NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
+
+ /* Iterate over the group members */
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_sumup, num_objs) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__stab_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_bh_size
+ *
+ * Purpose: Retrieve storage for btree and heap (1.6)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * June 25 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_bh_size(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab,
+ H5_ih_info_t *bh_info)
+{
+ hsize_t snode_size; /* Symbol table node size */
+ H5B_info_t bt_info; /* B-tree node info */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(stab);
+ HDassert(bh_info);
+
+ /* Set up user data for B-tree iteration */
+ snode_size = 0;
+
+ /* Get the B-tree & symbol table node size info */
+ if(H5B_get_info(f, dxpl_id, H5B_SNODE, stab->btree_addr, &bt_info, H5G__node_iterate_size, &snode_size) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+ /* Add symbol table & B-tree node sizes to index info */
+ bh_info->index_size += snode_size + bt_info.size;
+
+ /* Get the size of the local heap for the group */
+ if(H5HL_heapsize(f, dxpl_id, stab->heap_addr, &(bh_info->heap_size)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_bh_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_stab_get_name_by_idx_cb
+ *
+ * Purpose: Callback for B-tree iteration 'by index' info query to
+ * retrieve the name of a link
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_stab_get_name_by_idx_cb(const H5G_entry_t *ent, void *_udata)
+{
+ H5G_bt_it_gnbi_t *udata = (H5G_bt_it_gnbi_t *)_udata;
+ size_t name_off; /* Offset of name in heap */
+ const char *name; /* Pointer to name string in heap */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(ent);
+ HDassert(udata && udata->heap);
+
+ /* Get name offset in heap */
+ name_off = ent->name_off;
+ name = (const char *)H5HL_offset_into(udata->heap, name_off);
+ HDassert(name);
+ udata->name = H5MM_strdup(name);
+ HDassert(udata->name);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_stab_get_name_by_idx_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_get_name_by_idx
+ *
+ * Purpose: Returns the name of objects in the group by giving index.
+ *
+ * Return: Success: Non-negative, length of name
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t n,
+ char* name, size_t size, hid_t dxpl_id)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5O_stab_t stab; /* Info about local heap & B-tree */
+ H5G_bt_it_gnbi_t udata; /* Iteration information */
+ hbool_t udata_valid = FALSE; /* Whether iteration information is valid */
+ ssize_t ret_value = -1; /* Return value */
+
+ /* Portably clear udata struct (before FUNC_ENTER) */
+ HDmemset(&udata, 0, sizeof(udata));
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Get the B-tree & local heap info */
+ if(NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Remap index for decreasing iteration order */
+ if(order == H5_ITER_DEC) {
+ hsize_t nlinks = 0; /* Number of links in group */
+
+ /* Iterate over the symbol table nodes, to count the links */
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_sumup, &nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+ /* Map decreasing iteration order index to increasing iteration order index */
+ n = nlinks - (n + 1);
+ } /* end if */
+
+ /* Set iteration information */
+ udata.common.idx = n;
+ udata.common.num_objs = 0;
+ udata.common.op = H5G_stab_get_name_by_idx_cb;
+ udata.heap = heap;
+ udata.name = NULL;
+ udata_valid = TRUE;
+
+ /* Iterate over the group members */
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_by_idx, &udata) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed")
+
+ /* If we don't know the name now, we almost certainly went out of bounds */
+ if(udata.name == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "index out of bound")
+
+ /* Get the length of the name */
+ ret_value = (ssize_t)HDstrlen(udata.name);
+
+ /* Copy the name into the user's buffer, if given */
+ if(name) {
+ HDstrncpy(name, udata.name, MIN((size_t)(ret_value + 1), size));
+ if((size_t)ret_value >= size)
+ name[size - 1]='\0';
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ /* Free the duplicated name */
+ if(udata_valid && udata.name != NULL)
+ H5MM_xfree(udata.name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_get_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_stab_lookup_cb
+ *
+ * Purpose: B-tree 'find' callback to retrieve location for an object
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_stab_lookup_cb(const H5G_entry_t *ent, void *_udata)
+{
+ H5G_stab_fnd_ud_t *udata = (H5G_stab_fnd_ud_t *)_udata; /* 'User data' passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check for setting link info */
+ if(udata->lnk)
+ /* Convert the entry to a link */
+ if(H5G__ent_to_link(udata->lnk, udata->heap, ent, udata->name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, FAIL, "unable to convert symbol table entry to link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_stab_lookup_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_lookup
+ *
+ * Purpose: Look up an object relative to a group, using symbol table
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 20 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5G__stab_lookup(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk,
+ hid_t dxpl_id)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5G_bt_lkp_t bt_udata; /* Data to pass through B-tree */
+ H5G_stab_fnd_ud_t udata; /* 'User data' to give to callback */
+ H5O_stab_t stab; /* Symbol table message */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+ HDassert(lnk);
+
+ /* Retrieve the symbol table message for the group */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Set up user data to pass to 'find' operation callback */
+ udata.name = name;
+ udata.lnk = lnk;
+ udata.heap = heap;
+
+ /* Set up the user data for actual B-tree find operation */
+ bt_udata.common.name = name;
+ bt_udata.common.heap = heap;
+ bt_udata.op = H5G_stab_lookup_cb;
+ bt_udata.op_data = &udata;
+
+ /* Search the B-tree */
+ if((ret_value = H5B_find(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &bt_udata)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_stab_lookup_by_idx_cb
+ *
+ * Purpose: Callback for B-tree iteration 'by index' info query to
+ * retrieve the link
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 9, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_stab_lookup_by_idx_cb(const H5G_entry_t *ent, void *_udata)
+{
+ H5G_bt_it_lbi_t *udata = (H5G_bt_it_lbi_t *)_udata;
+ const char *name; /* Pointer to name string in heap */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(ent);
+ HDassert(udata && udata->heap);
+
+ /* Get a pointer to the link name */
+ name = (const char *)H5HL_offset_into(udata->heap, ent->name_off);
+ HDassert(name);
+
+ /* Convert the entry to a link */
+ if(H5G__ent_to_link(udata->lnk, udata->heap, ent, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, FAIL, "unable to convert symbol table entry to link")
+ udata->found = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_stab_lookup_by_idx_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_lookup_by_idx
+ *
+ * Purpose: Look up an object in a group, according to the name index
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_t n,
+ H5O_link_t *lnk, hid_t dxpl_id)
+{
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ H5G_bt_it_lbi_t udata; /* Iteration information */
+ H5O_stab_t stab; /* Symbol table message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(lnk);
+
+ /* Get the B-tree & local heap info */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap")
+
+ /* Remap index for decreasing iteration order */
+ if(order == H5_ITER_DEC) {
+ hsize_t nlinks = 0; /* Number of links in group */
+
+ /* Iterate over the symbol table nodes, to count the links */
+ if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_sumup, &nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+ /* Map decreasing iteration order index to increasing iteration order index */
+ n = nlinks - (n + 1);
+ } /* end if */
+
+ /* Set iteration information */
+ udata.common.idx = n;
+ udata.common.num_objs = 0;
+ udata.common.op = H5G_stab_lookup_by_idx_cb;
+ udata.heap = heap;
+ udata.lnk = lnk;
+ udata.found = FALSE;
+
+ /* Iterate over the group members */
+ if(H5B_iterate(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_by_idx, &udata) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed")
+
+ /* If we didn't find the link, we almost certainly went out of bounds */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "index out of bound")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__stab_lookup_by_idx() */
+
+#ifndef H5_STRICT_FORMAT_CHECKS
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_valid
+ *
+ * Purpose: Verify that a group's symbol table message is valid. If
+ * provided, the addresses in alt_stab will be tried if the
+ * addresses in the group's stab message are invalid, and
+ * the stab message will be updated if necessary.
+ *
+ * NOTE: This function is only called when strict format
+ * checks are disabled. This is so that, when strict
+ * format checks are enabled, errors in the symbol table
+ * messages are not fixed by this function and are instead
+ * reported by the library.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Mar 17, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__stab_valid(H5O_loc_t *grp_oloc, hid_t dxpl_id, H5O_stab_t *alt_stab)
+{
+ H5O_stab_t stab; /* Current symbol table */
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ hbool_t changed = FALSE; /* Whether stab has been modified */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* Read the symbol table message */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message");
+
+ /* Check if the symbol table message's b-tree address is valid */
+ if(H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr) < 0) {
+ /* Address is invalid, try the b-tree address in the alternate symbol
+ * table message */
+ if(!alt_stab || H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, alt_stab->btree_addr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to locate b-tree")
+ else {
+ /* The alternate symbol table's b-tree address is valid. Adjust the
+ * symbol table message in the group. */
+ stab.btree_addr = alt_stab->btree_addr;
+ changed = TRUE;
+ } /* end else */
+ } /* end if */
+
+ /* Check if the symbol table message's heap address is valid */
+ if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) {
+ /* Address is invalid, try the heap address in the alternate symbol
+ * table message */
+ if(!alt_stab || NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, alt_stab->heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "unable to locate heap")
+ else {
+ /* The alternate symbol table's heap address is valid. Adjust the
+ * symbol table message in the group. */
+ stab.heap_addr = alt_stab->heap_addr;
+ changed = TRUE;
+ } /* end else */
+ } /* end if */
+
+ /* Update the symbol table message and clear errors if necessary */
+ if(changed) {
+ H5E_clear_stack(NULL);
+ if(H5O_msg_write(grp_oloc, H5O_STAB_ID, 0, H5O_UPDATE_TIME | H5O_UPDATE_FORCE, &stab, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to correct symbol table message")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__stab_valid */
+#endif /* H5_STRICT_FORMAT_CHECKS */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_stab_get_type_by_idx_cb
+ *
+ * Purpose: Callback for B-tree iteration 'by index' info query to
+ * retrieve the type of an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_stab_get_type_by_idx_cb(const H5G_entry_t *ent, void *_udata)
+{
+ H5G_bt_it_gtbi_t *udata = (H5G_bt_it_gtbi_t *)_udata;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(ent);
+ HDassert(udata);
+
+ /* Check for a soft link */
+ switch(ent->type) {
+ case H5G_CACHED_SLINK:
+ udata->type = H5G_LINK;
+ break;
+
+ case H5G_CACHED_ERROR:
+ case H5G_NOTHING_CACHED:
+ case H5G_CACHED_STAB:
+ case H5G_NCACHED:
+ default:
+ {
+ H5O_loc_t tmp_oloc; /* Temporary object location */
+ H5O_type_t obj_type; /* Type of object at location */
+
+ /* Build temporary object location */
+ tmp_oloc.file = udata->f;
+ HDassert(H5F_addr_defined(ent->header));
+ tmp_oloc.addr = ent->header;
+
+ /* Get the type of the object */
+ if(H5O_obj_type(&tmp_oloc, &obj_type, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object type")
+ udata->type = H5G_map_obj_type(obj_type);
+ }
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_stab_get_type_by_idx_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__stab_get_type_by_idx
+ *
+ * Purpose: Private function for H5Gget_objtype_by_idx.
+ * Returns the type of objects in the group by giving index.
+ *
+ * Return: Success: H5G_GROUP(1), H5G_DATASET(2), H5G_TYPE(3)
+ *
+ * Failure: UNKNOWN
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5G__stab_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx, hid_t dxpl_id)
+{
+ H5O_stab_t stab; /* Info about local heap & B-tree */
+ H5G_bt_it_gtbi_t udata; /* User data for B-tree callback */
+ H5G_obj_t ret_value = H5G_UNKNOWN; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, oloc->addr, H5G_UNKNOWN)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Get the B-tree & local heap info */
+ if(NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "unable to determine local heap address")
+
+ /* Set iteration information */
+ udata.common.idx = idx;
+ udata.common.num_objs = 0;
+ udata.common.op = H5G_stab_get_type_by_idx_cb;
+ udata.f = oloc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.type = H5G_UNKNOWN;
+
+ /* Iterate over the group members */
+ if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, H5G__node_by_idx, &udata) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "iteration operator failed")
+
+ /* If we don't know the type now, we almost certainly went out of bounds */
+ if(udata.type == H5G_UNKNOWN)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "index out of bound")
+
+ /* Set the return value */
+ ret_value = udata.type;
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, H5G_UNKNOWN)
+} /* end H5G__stab_get_type_by_idx() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Gtest.c b/src/H5Gtest.c
new file mode 100644
index 0000000..7271cdc
--- /dev/null
+++ b/src/H5Gtest.c
@@ -0,0 +1,813 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, October 17, 2005
+ *
+ * Purpose: Group testing functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+#define H5G_TESTING /*suppress warning about H5G testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__is_empty_test
+ PURPOSE
+ Determine whether a group contains no objects
+ USAGE
+ htri_t H5G__is_empty_test(gid)
+ hid_t gid; IN: group to check
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the group has no link messages and no symbol table message
+ and no "dense" link storage
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5G__is_empty_test(hid_t gid)
+{
+ H5G_t *grp = NULL; /* Pointer to group */
+ htri_t msg_exists = FALSE; /* Indicate that a header message is present */
+ htri_t linfo_exists = FALSE;/* Indicate that the 'link info' message is present */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* "New format" checks */
+
+ /* Check if the group has any link messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_LINK_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0) {
+ /* Sanity check that new group format shouldn't have old messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and link messages found")
+
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* Check for a link info message */
+ if((linfo_exists = H5O_msg_exists(&(grp->oloc), H5O_LINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(linfo_exists > 0) {
+ H5O_linfo_t linfo; /* Link info message */
+
+ /* Sanity check that new group format shouldn't have old messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and link info messages found")
+
+ /* Get the link info */
+ if(H5G__obj_get_linfo(&(grp->oloc), &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Check for 'dense' link storage file addresses being defined */
+ if(H5F_addr_defined(linfo.fheap_addr))
+ HGOTO_DONE(FALSE)
+ if(H5F_addr_defined(linfo.name_bt2_addr))
+ HGOTO_DONE(FALSE)
+ if(H5F_addr_defined(linfo.corder_bt2_addr))
+ HGOTO_DONE(FALSE)
+
+ /* Check for link count */
+ if(linfo.nlinks > 0)
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* "Old format" checks */
+
+ /* Check if the group has a symbol table message */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0) {
+ H5O_stab_t stab; /* Info about local heap & B-tree */
+ hsize_t nlinks; /* Number of links in the group */
+
+ /* Sanity check that old group format shouldn't have new messages */
+ if(linfo_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and link info messages found")
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_GINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and group info messages found")
+
+ /* Get the B-tree & local heap info */
+ if(NULL == H5O_msg_read(&(grp->oloc), H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read symbol table message")
+
+ /* Get the count of links in the group */
+ if(H5G__stab_count(&(grp->oloc), &nlinks, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to count links")
+
+ /* Check for link count */
+ if(nlinks > 0)
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__is_empty_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__has_links_test
+ PURPOSE
+ Determine whether a group contains link messages
+ USAGE
+ htri_t H5G__has_links_test(gid)
+ hid_t gid; IN: group to check
+ unsigned *nmsgs; OUT: # of link messages in header
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the group has link messages and how many.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5G__has_links_test(hid_t gid, unsigned *nmsgs)
+{
+ H5G_t *grp = NULL; /* Pointer to group */
+ htri_t msg_exists = 0; /* Indicate that a header message is present */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Check if the group has any link messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_LINK_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists == 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check if the group has a symbol table message */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and link messages found")
+
+ /* Check if we should retrieve the number of link messages */
+ if(nmsgs) {
+ int msg_count; /* Number of messages of a type */
+
+ /* Check how many link messages there are */
+ if((msg_count = H5O_msg_count(&(grp->oloc), H5O_LINK_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "unable to count link messages")
+ *nmsgs = (unsigned)msg_count;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__has_links_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__has_stab_test
+ PURPOSE
+ Determine whether a group contains a symbol table message
+ USAGE
+ htri_t H5G__has_stab_test(gid)
+ hid_t gid; IN: group to check
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the group has a symbol table message.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5G__has_stab_test(hid_t gid)
+{
+ H5G_t *grp = NULL; /* Pointer to group */
+ htri_t msg_exists = 0; /* Indicate that a header message is present */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Check if the group has a symbol table message */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists == 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check if the group has any link messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_LINK_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "both symbol table and link messages found")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__has_stab_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__is_new_dense_test
+ PURPOSE
+ Determine whether a group is in the "new" format and dense
+ USAGE
+ htri_t H5G__is_new_dense_test(gid)
+ hid_t gid; IN: group to check
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the group is in the "new" format for groups (link messages/
+ fractal heap+v2 B-tree) and if it is in "dense" storage form (ie. it has
+ a name B-tree index).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5G__is_new_dense_test(hid_t gid)
+{
+ H5G_t *grp = NULL; /* Pointer to group */
+ htri_t msg_exists = 0; /* Indicate that a header message is present */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Check if the group has a symbol table message */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check if the group has any link messages */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_LINK_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check if the group has link info message */
+ if((msg_exists = H5O_msg_exists(&(grp->oloc), H5O_LINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+ if(msg_exists > 0) {
+ H5O_linfo_t linfo; /* Link info message */
+
+ /* Get the link info */
+ if(H5G__obj_get_linfo(&(grp->oloc), &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Check for 'dense' link storage file addresses being defined */
+ if(!H5F_addr_defined(linfo.fheap_addr))
+ HGOTO_DONE(FALSE)
+ if(!H5F_addr_defined(linfo.name_bt2_addr))
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__is_new_dense_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__new_dense_info_test
+ PURPOSE
+ Retrieve information about the state of the new "dense" storage for groups
+ USAGE
+ herr_t H5G__new_dense_info_test(gid, name_count, corder_count)
+ hid_t gid; IN: group to check
+ hsize_t *name_count; OUT: Number of links in name index
+ hsize_t *corder_count; OUT: Number of links in creation order index
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Currently, just retrieves the number of links in each index and returns
+ them.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5G__new_dense_info_test(hid_t gid, hsize_t *name_count, hsize_t *corder_count)
+{
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ H5O_linfo_t linfo; /* Link info message */
+ H5G_t *grp = NULL; /* Pointer to group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(dxpl_id, grp->oloc.addr, FAIL);
+
+ /* Get the link info */
+ if(H5G__obj_get_linfo(&(grp->oloc), &linfo, dxpl_id) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Check for 'dense' link storage file addresses being defined */
+ if(!H5F_addr_defined(linfo.fheap_addr))
+ HGOTO_DONE_TAG(FAIL, FAIL)
+ if(!H5F_addr_defined(linfo.name_bt2_addr))
+ HGOTO_DONE_TAG(FAIL, FAIL)
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(grp->oloc.file, dxpl_id, linfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Retrieve # of records in name index */
+ if(H5B2_get_nrec(bt2_name, name_count) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from name index")
+
+ /* Check if there is a creation order index */
+ if(H5F_addr_defined(linfo.corder_bt2_addr)) {
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(grp->oloc.file, dxpl_id, linfo.corder_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Retrieve # of records in creation order index */
+ if(H5B2_get_nrec(bt2_corder, corder_count) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from creation order index")
+ } /* end if */
+ else
+ *corder_count = 0;
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__new_dense_info_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__lheap_size_test
+ PURPOSE
+ Determine the size of a local heap for a group
+ USAGE
+ herr_t H5G__lheap_size_test(gid, lheap_size)
+ hid_t gid; IN: group to check
+ size_t *lheap_size; OUT: Size of local heap
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the size of the local heap for a group
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5G__lheap_size_test(hid_t gid, size_t *lheap_size)
+{
+ H5G_t *grp = NULL; /* Pointer to group */
+ H5O_stab_t stab; /* Symbol table message */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Get group structure */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Make certain the group has a symbol table message */
+ if(NULL == H5O_msg_read(&(grp->oloc), H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read symbol table message")
+
+ /* Check the size of the local heap for the group */
+ if(H5HL_get_size(grp->oloc.file, dxpl_id, stab.heap_addr, lheap_size) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't query local heap size")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__lheap_size_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5G__user_path_test
+ PURPOSE
+ Retrieve the user path for an ID
+ USAGE
+ herr_t H5G__user_path_test(obj_id, user_path, user_path_len)
+ hid_t obj_id; IN: ID to check
+ char *user_path; OUT: Pointer to buffer for User path
+ size_t *user_path_len; OUT: Size of user path
+ unsigned *obj_hidden; OUT: Whether object is hidden
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the user path for an ID. A zero for the length is returned in
+ the case of no user path.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5G__user_path_test(hid_t obj_id, char *user_path, size_t *user_path_len, unsigned *obj_hidden)
+{
+ void *obj_ptr; /* Pointer to object for ID */
+ H5G_name_t *obj_path; /* Pointer to group hier. path for obj */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(user_path_len);
+ HDassert(obj_hidden);
+
+ /* Get pointer to object for ID */
+ if(NULL == (obj_ptr = H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get object for ID")
+
+ /* Get the symbol table entry */
+ switch(H5I_get_type(obj_id)) {
+ case H5I_GROUP:
+ obj_path = H5G_nameof((H5G_t *)obj_ptr);
+ break;
+
+ case H5I_DATASET:
+ obj_path = H5D_nameof((H5D_t *)obj_ptr);
+ break;
+
+ case H5I_DATATYPE:
+ /* Avoid non-named datatypes */
+ if(!H5T_is_named((H5T_t *)obj_ptr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a named datatype")
+
+ obj_path = H5T_nameof((H5T_t *)obj_ptr);
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object type")
+ } /* end switch */
+ HDassert(obj_path);
+
+ /* Retrieve a copy of the user path and put it into the buffer */
+ if(obj_path->user_path_r) {
+ ssize_t len = H5RS_len(obj_path->user_path_r);
+
+ /* Set the user path, if given */
+ if(user_path)
+ HDstrncpy(user_path, H5RS_get_str(obj_path->user_path_r), (size_t)(len + 1));
+
+ /* Set the length of the path */
+ *user_path_len = (size_t)len;
+
+ /* Set the user path hidden flag */
+ *obj_hidden = obj_path->obj_hidden;
+ } /* end if */
+ else {
+ *user_path_len = 0;
+ *obj_hidden = 0;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5G__user_path_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__verify_cached_stab_test
+ *
+ * Purpose: Check that a that the provided group entry contains a
+ * cached symbol table entry, that the entry matches that in
+ * the provided group's object header, and check that the
+ * addresses are valid.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Mar 31, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent)
+{
+ H5O_stab_t stab; /* Symbol table */
+ H5HL_t *heap = NULL; /* Pointer to local heap */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_TAG(dxpl_id, grp_oloc->addr, FAIL)
+
+ /* Verify that stab info is cached in ent */
+ if(ent->type != H5G_CACHED_STAB)
+ HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "symbol table information is not cached")
+
+ /* Read the symbol table message from the group */
+ if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message")
+
+ /* Verify that the cached symbol table info matches the symbol table message
+ * in the object header */
+ if((ent->cache.stab.btree_addr != stab.btree_addr)
+ || (ent->cache.stab.heap_addr != stab.heap_addr))
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "cached stab info does not match object header")
+
+ /* Verify that the btree address is valid */
+ if(H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "b-tree address is invalid")
+
+ /* Verify that the heap address is valid */
+ if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "heap address is invalid")
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5G__verify_cached_stab_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_verify_cached_stabs_test_cb
+ *
+ * Purpose: Verify that all entries in this node contain cached symbol
+ * table information if and only if the entry refers to a
+ * group with a symbol table, and that that information is
+ * correct.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Apr 8, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5G_verify_cached_stabs_test_cb(H5F_t *f, hid_t dxpl_id,
+ const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const void H5_ATTR_UNUSED *_rt_key,
+ void H5_ATTR_UNUSED *udata)
+{
+ H5G_node_t *sn = NULL;
+ H5O_loc_t targ_oloc;
+ H5O_t *targ_oh = NULL;
+ htri_t stab_exists;
+ H5O_stab_t stab;
+ unsigned i;
+ int ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Load the node */
+ if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node")
+
+ /* Check each target object to see if its stab message (if present) matches
+ * the cached stab (if present). If one exists, both must exist. */
+ /* Initialize constant fields in target oloc */
+ targ_oloc.file = f;
+ targ_oloc.holding_file = FALSE;
+
+ /* Iterate over entries */
+ for(i=0; i<sn->nsyms; i++) {
+ /* Update oloc address */
+ targ_oloc.addr = sn->entry[i].header;
+
+ /* Load target object header */
+ if(NULL == (targ_oh = H5O_protect(&targ_oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to protect target object header")
+
+ /* Check if a symbol table message exists */
+ if((stab_exists = H5O_msg_exists_oh(targ_oh, H5O_STAB_ID)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "unable to check for STAB message")
+
+ if(stab_exists) {
+ /* Read symbol table message */
+ if(NULL == H5O_msg_read_oh(f, dxpl_id, targ_oh, H5O_STAB_ID, &stab))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to read STAB message")
+
+ /* Check if the stab matches the cached stab info */
+ if(sn->entry[i].type != H5G_CACHED_STAB)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "STAB message is not cached in group node")
+
+ if((sn->entry[i].cache.stab.btree_addr != stab.btree_addr)
+ || (sn->entry[i].cache.stab.heap_addr != stab.heap_addr))
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "cached symbol table information is incorrect")
+ } /* end if */
+ else if(sn->entry[i].type == H5G_CACHED_STAB)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "nonexistent STAB message is cached")
+
+ /* Unprotect target object */
+ if(H5O_unprotect(&targ_oloc, dxpl_id, targ_oh, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
+ targ_oh = NULL;
+ } /* end for */
+
+done:
+ if(sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header")
+
+ if(targ_oh) {
+ HDassert(ret_value == H5_ITER_ERROR);
+ if(H5O_unprotect(&targ_oloc, dxpl_id, targ_oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_verify_cached_stabs_test_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__verify_cached_stabs_test
+ *
+ * Purpose: If the provided group contains a symbol table, verifies
+ * that all links in the group contain cached symbol table
+ * information if and only if the link points to a group
+ * with a symbol table, and that that information is correct.
+ * If the provided group does not contain a symbol table,
+ * does nothing.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * April 6 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__verify_cached_stabs_test(hid_t gid)
+{
+ H5G_t *grp = NULL; /* Group */
+ htri_t stab_exists;
+ H5O_stab_t stab; /* Symbol table message */
+ H5G_bt_common_t udata = {NULL, NULL}; /* Dummy udata so H5B_iterate doesn't freak out */
+ haddr_t prev_tag = HADDR_UNDEF; /* Previous metadata tag */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* transfer property list used for this operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(gid >= 0);
+
+ /* Check args */
+ if(NULL == (grp = (H5G_t *)H5I_object_verify(gid, H5I_GROUP)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group")
+
+ /* Set up metadata tagging */
+ if(H5AC_tag(dxpl_id, grp->oloc.addr, &prev_tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag")
+
+ /* Check for group having a symbol table message */
+ /* Check for the group having a group info message */
+ if((stab_exists = H5O_msg_exists(&(grp->oloc), H5O_STAB_ID,
+ dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to read object header")
+
+ /* No need to check anything if the symbol table doesn't exist */
+ if(!stab_exists)
+ HGOTO_DONE(SUCCEED);
+
+ /* Read the stab */
+ if(NULL == H5O_msg_read(&(grp->oloc), H5O_STAB_ID, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get symbol table info")
+
+ /* Iterate over the b-tree, checking validity of cached information */
+ if((ret_value = H5B_iterate(grp->oloc.file, dxpl_id, H5B_SNODE,
+ stab.btree_addr, H5G_verify_cached_stabs_test_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "iteration operator failed");
+
+ /* Reset metadata tagging */
+ if(H5AC_tag(dxpl_id, prev_tag, NULL) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__verify_cached_stabs_test() */
+
diff --git a/src/H5Gtraverse.c b/src/H5Gtraverse.c
new file mode 100644
index 0000000..ff1206e
--- /dev/null
+++ b/src/H5Gtraverse.c
@@ -0,0 +1,875 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gtraverse.c
+ * Sep 13 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for traversing group hierarchy
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for path traversal routine */
+typedef struct {
+ /* down */
+ hbool_t chk_exists; /* Flag to indicate we are checking if object exists */
+
+ /* up */
+ H5G_loc_t *obj_loc; /* Object location */
+ hbool_t exists; /* Indicate if object exists */
+} H5G_trav_slink_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5G_traverse_slink_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5G_traverse_ud(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5G_traverse_slink(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5G_traverse_real(const H5G_loc_t *loc, const char *name,
+ unsigned target, size_t *nlinks, H5G_traverse_t op, void *op_data,
+ hid_t lapl_id, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_slink_cb
+ *
+ * Purpose: Callback for soft link traversal. This routine sets the
+ * correct information for the object location.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_slink_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_trav_slink_t *udata = (H5G_trav_slink_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check for dangling soft link */
+ if(obj_loc == NULL) {
+ if(udata->chk_exists)
+ udata->exists = FALSE;
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found")
+ } /* end if */
+ else {
+ /* Copy new location information for resolved object */
+ H5O_loc_copy(udata->obj_loc->oloc, obj_loc->oloc, H5_COPY_DEEP);
+
+ /* Indicate that the object exists */
+ udata->exists = TRUE;
+ } /* end else */
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_slink_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_link_ud
+ *
+ * Purpose: Callback for user-defined link traversal. Sets up a
+ * location ID and passes it to the user traversal callback.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_ud(const H5G_loc_t *grp_loc/*in,out*/, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t _lapl_id, hid_t dxpl_id)
+{
+ const H5L_class_t *link_class; /* User-defined link class */
+ hid_t cb_return = -1; /* The ID the user-defined callback returned */
+ H5G_loc_t grp_loc_copy;
+ H5G_name_t grp_path_copy;
+ H5O_loc_t grp_oloc_copy;
+ H5G_loc_t new_loc; /* Group location for newly opened external object */
+ H5G_t *grp;
+ hid_t lapl_id = (-1); /* LAPL local to this routine */
+ H5P_genplist_t *lapl; /* LAPL with nlinks set */
+ hid_t cur_grp = (-1);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(lnk->type >= H5L_TYPE_UD_MIN);
+ HDassert(obj_loc);
+ HDassert(nlinks);
+ HDassert(_lapl_id >= 0);
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(lnk->type)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTREGISTERED, FAIL, "unable to get UD link class")
+
+ /* Set up location for user-defined callback. Use a copy of our current
+ * grp_loc. */
+ grp_loc_copy.path = &grp_path_copy;
+ grp_loc_copy.oloc = &grp_oloc_copy;
+ H5G_loc_reset(&grp_loc_copy);
+ if(H5G_loc_copy(&grp_loc_copy, grp_loc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ /* Create a group ID to pass to the user-defined callback */
+ if(NULL == (grp = H5G_open(&grp_loc_copy, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((cur_grp = H5I_register(H5I_GROUP, grp, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+ /* Check for generic default property list and use link access default if so */
+ if(_lapl_id == H5P_DEFAULT) {
+ HDassert(H5P_LINK_ACCESS_DEFAULT != -1);
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(H5P_LINK_ACCESS_DEFAULT)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get default property list")
+ } /* end if */
+ else {
+ /* Get the underlying property list passed in */
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(_lapl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get property list from ID")
+ } /* end else */
+
+ /* Copy the property list passed in */
+ if((lapl_id = H5P_copy_plist(lapl, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy property list")
+
+ /* Get the underlying property list copy */
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get property list from ID")
+
+ /* Record number of soft links left to traverse in the property list. */
+ if(H5P_set(lapl, H5L_ACS_NLINKS_NAME, nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set nlink info")
+
+ /* User-defined callback function */
+ cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, lapl_id);
+
+ /* Check for failing to locate the object */
+ if(cb_return < 0) {
+ /* Check if we just needed to know if the object exists */
+ if(target & H5G_TARGET_EXISTS) {
+ /* Clear any errors from the stack */
+ H5E_clear_stack(NULL);
+
+ /* Indicate that the object doesn't exist */
+ *obj_exists = FALSE;
+
+ /* Get out now */
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+ /* else, we really needed to open the object */
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "traversal callback returned invalid ID")
+ } /* end if */
+
+ /* Get the object location information from the ID the user callback returned */
+ if(H5G_loc(cb_return, &new_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ /* Release any previous location information for the object */
+ H5G_loc_free(obj_loc);
+
+ /* Copy new object's location information */
+ H5G_loc_copy(obj_loc, &new_loc, H5_COPY_DEEP);
+
+ /* Hold the file open until we free this object header (otherwise the
+ * object location will be invalidated when the file closes).
+ */
+ if(H5O_loc_hold_file(obj_loc->oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+ /* We have a copy of the location and we're holding the file open.
+ * Close the open ID the user passed back.
+ */
+ if(H5I_dec_ref(cb_return) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ cb_return = (hid_t)(-1);
+
+done:
+ /* Close location given to callback. */
+ if(cur_grp > 0 && H5I_dec_ref(cur_grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom for current location")
+
+ if(ret_value < 0 && cb_return > 0 && H5I_dec_ref(cb_return) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+
+ /* Close the LAPL, if we copied one */
+ if(lapl_id > 0 && H5I_dec_ref(lapl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close copied link access property list")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_ud() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_slink
+ *
+ * Purpose: Traverses symbolic link. The link head appears in the group
+ * whose entry is GRP_LOC and the link tail entry is OBJ_LOC.
+ *
+ * Return: Success: Non-negative, OBJ_LOC will contain information
+ * about the object to which the link points
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, April 10, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_slink(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_trav_slink_t udata; /* User data to pass to link traversal callback */
+ H5G_name_t tmp_obj_path; /* Temporary copy of object's path */
+ hbool_t tmp_obj_path_set = FALSE; /* Flag to indicate that tmp object path is initialized */
+ H5O_loc_t tmp_grp_oloc; /* Temporary copy of group entry */
+ H5G_name_t tmp_grp_path; /* Temporary copy of group's path */
+ H5G_loc_t tmp_grp_loc; /* Temporary copy of group's location */
+ hbool_t tmp_grp_loc_set = FALSE; /* Flag to indicate that tmp group location is initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(lnk->type == H5L_TYPE_SOFT);
+ HDassert(nlinks);
+
+ /* Set up temporary location */
+ tmp_grp_loc.oloc = &tmp_grp_oloc;
+ tmp_grp_loc.path = &tmp_grp_path;
+
+ /* Portably initialize the temporary objects */
+ H5G_loc_reset(&tmp_grp_loc);
+ H5G_name_reset(&tmp_obj_path);
+
+ /* Clone the group location, so we can track the names properly */
+ /* ("tracking the names properly" means to ignore the effects of the
+ * link traversal on the object's & group's paths - QAK)
+ */
+ H5G_loc_copy(&tmp_grp_loc, grp_loc, H5_COPY_DEEP);
+ tmp_grp_loc_set = TRUE;
+
+ /* Hold the object's group hier. path to restore later */
+ /* (Part of "tracking the names properly") */
+ H5G_name_copy(&tmp_obj_path, obj_loc->path, H5_COPY_SHALLOW);
+ tmp_obj_path_set = TRUE;
+
+ /* Set up user data for traversal callback */
+ udata.chk_exists = (target & H5G_TARGET_EXISTS) ? TRUE : FALSE;
+ udata.exists = FALSE;
+ udata.obj_loc = obj_loc;
+
+ /* Traverse the link */
+ if(H5G_traverse_real(&tmp_grp_loc, lnk->u.soft.name, target, nlinks, H5G_traverse_slink_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link")
+
+ /* Pass back information about whether the object exists */
+ *obj_exists = udata.exists;
+
+done:
+ /* Restore object's group hier. path */
+ if(tmp_obj_path_set) {
+ H5G_name_free(obj_loc->path);
+ H5G_name_copy(obj_loc->path, &tmp_obj_path, H5_COPY_SHALLOW);
+ } /* end if */
+
+ /* Release cloned copy of group location */
+ if(tmp_grp_loc_set)
+ H5G_loc_free(&tmp_grp_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_slink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__traverse_special
+ *
+ * Purpose: Handle traversing special link situations
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__traverse_special(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ unsigned target, size_t *nlinks, hbool_t last_comp,
+ H5G_loc_t *obj_loc, hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(obj_loc);
+ HDassert(nlinks);
+
+ /*
+ * If we found a symbolic link then we should follow it. But if this
+ * is the last component of the name and the H5G_TARGET_SLINK bit of
+ * TARGET is set then we don't follow it.
+ */
+ if(H5L_TYPE_SOFT == lnk->type &&
+ (0 == (target & H5G_TARGET_SLINK) || !last_comp)) {
+ if((*nlinks)-- <= 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NLINKS, FAIL, "too many links")
+ if(H5G_traverse_slink(grp_loc, lnk, obj_loc, (target & H5G_TARGET_EXISTS), nlinks, obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "symbolic link traversal failed")
+ } /* end if */
+
+ /*
+ * If we found a user-defined link then we should follow it. But if this
+ * is the last component of the name and the H5G_TARGET_UDLINK bit of
+ * TARGET is set then we don't follow it.
+ */
+ if(lnk->type >= H5L_TYPE_UD_MIN &&
+ (0 == (target & H5G_TARGET_UDLINK) || !last_comp) ) {
+ if((*nlinks)-- <= 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NLINKS, FAIL, "too many links")
+ if(H5G_traverse_ud(grp_loc, lnk, obj_loc, (target & H5G_TARGET_EXISTS), nlinks, obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "user-defined link traversal failed")
+ } /* end if */
+
+ /*
+ * Resolve mount points to the mounted group. Do not do this step if
+ * the H5G_TARGET_MOUNT bit of TARGET is set and this is the last
+ * component of the name.
+ *
+ * (If this link is a hard link, try to perform mount point traversal)
+ *
+ * (Note that the soft and external link traversal above can change
+ * the status of the object (into a hard link), so don't use an 'else'
+ * statement here. -QAK)
+ */
+ if(H5F_addr_defined(obj_loc->oloc->addr) &&
+ (0 == (target & H5G_TARGET_MOUNT) || !last_comp)) {
+ if(H5F_traverse_mount(obj_loc->oloc/*in,out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "mount point traversal failed")
+ } /* end if */
+
+ /* If the grp_loc is the only thing holding an external file open
+ * and obj_loc is in the same file, obj_loc should also hold the
+ * file open so that closing the grp_loc doesn't close the file.
+ */
+ if(grp_loc->oloc->holding_file && grp_loc->oloc->file == obj_loc->oloc->file)
+ if(H5O_loc_hold_file(obj_loc->oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__traverse_special() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_real
+ *
+ * Purpose: Internal version of path traversal routine
+ *
+ * Return: Success: Non-negative if name can be fully resolved.
+ *
+ * Failure: Negative if the name could not be fully
+ * resolved.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_real(const H5G_loc_t *_loc, const char *name, unsigned target,
+ size_t *nlinks, H5G_traverse_t op, void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t loc; /* Location of start object */
+ H5O_loc_t grp_oloc; /* Object loc. for current group */
+ H5G_name_t grp_path; /* Path for current group */
+ H5G_loc_t grp_loc; /* Location of group */
+ H5O_loc_t obj_oloc; /* Object found */
+ H5G_name_t obj_path; /* Path for object found */
+ H5G_loc_t obj_loc; /* Location of object */
+ size_t nchars; /* component name length */
+ H5O_link_t lnk; /* Link information for object */
+ hbool_t link_valid = FALSE; /* Flag to indicate that the link information is valid */
+ hbool_t obj_loc_valid = FALSE; /* Flag to indicate that the object location is valid */
+ H5G_own_loc_t own_loc = H5G_OWN_NONE; /* Enum to indicate whether callback took ownership of locations*/
+ hbool_t group_copy = FALSE; /* Flag to indicate that the group entry is copied */
+ char comp_buf[1024]; /* Temporary buffer for path components */
+ char *comp; /* Pointer to buffer for path components */
+ H5WB_t *wb = NULL; /* Wrapped buffer for temporary buffer */
+ hbool_t last_comp = FALSE; /* Flag to indicate that a component is the last component in the name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check parameters */
+ HDassert(_loc);
+ HDassert(name);
+ HDassert(nlinks);
+ HDassert(op);
+
+ /*
+ * Where does the searching start? For absolute names it starts at the
+ * root of the file; for relative names it starts at CWG.
+ */
+ /* Check if we need to get the root group's entry */
+ if('/' == *name) {
+ H5G_t *root_grp; /* Temporary pointer to root group of file */
+
+ /* Look up root group for starting location */
+ root_grp = H5G_rootof(_loc->oloc->file);
+ HDassert(root_grp);
+
+ /* Set the location entry to the root group's info */
+ loc.oloc = &(root_grp->oloc);
+ loc.path = &(root_grp->path);
+ } /* end if */
+ else {
+ loc.oloc = _loc->oloc;
+ loc.path = _loc->path;
+ } /* end else */
+
+ /* Set up group & object locations */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+
+#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
+ /* Clear group location */
+ if(H5G_loc_reset(&grp_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset location")
+#endif /* H5_USING_MEMCHECKER */
+
+ /* Deep copy of the starting location to group location */
+ if(H5G_loc_copy(&grp_loc, &loc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to copy location")
+ group_copy = TRUE;
+
+ /* Clear object location */
+ if(H5G_loc_reset(&obj_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset location")
+
+ /* Wrap the local buffer for serialized header info */
+ if(NULL == (wb = H5WB_wrap(comp_buf, sizeof(comp_buf))))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough */
+ if(NULL == (comp = (char *)H5WB_actual(wb, (HDstrlen(name) + 1))))
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Traverse the path */
+ while((name = H5G__component(name, &nchars)) && *name) {
+ const char *s; /* Temporary string pointer */
+ htri_t lookup_status; /* Status from object lookup */
+ hbool_t obj_exists; /* Whether the object exists */
+
+ /*
+ * Copy the component name into a null-terminated buffer so
+ * we can pass it down to the other symbol table functions.
+ */
+ HDmemcpy(comp, name, nchars);
+ comp[nchars] = '\0';
+
+ /*
+ * The special name `.' is a no-op.
+ */
+ if('.' == comp[0] && !comp[1]) {
+ name += nchars;
+ continue;
+ } /* end if */
+
+ /* Check if this is the last component of the name */
+ if(!((s = H5G__component(name + nchars, NULL)) && *s))
+ last_comp = TRUE;
+
+ /* If there's valid information in the link, reset it */
+ if(link_valid) {
+ H5O_msg_reset(H5O_LINK_ID, &lnk);
+ link_valid = FALSE;
+ } /* end if */
+
+ /* Get information for object in current group */
+ if((lookup_status = H5G__obj_lookup(grp_loc.oloc, comp, &lnk/*out*/, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't look up component")
+ obj_exists = FALSE;
+
+ /* If the lookup was OK, build object location and traverse special links, etc. */
+ if(lookup_status) {
+ /* Sanity check link and indicate it's valid */
+ HDassert(lnk.type >= H5L_TYPE_HARD);
+ HDassert(!HDstrcmp(comp, lnk.name));
+ link_valid = TRUE;
+
+ /* Build object location from the link */
+ if(H5G__link_to_loc(&grp_loc, &lnk, &obj_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot initialize object location")
+ obj_loc_valid = TRUE;
+
+ /* Assume object exists */
+ obj_exists = TRUE;
+
+ /* Perform any special traversals that the link needs */
+ /* (soft links, user-defined links, file mounting, etc.) */
+ if(H5G__traverse_special(&grp_loc, &lnk, target, nlinks, last_comp, &obj_loc, &obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "special link traversal failed")
+ } /* end if */
+
+ /* Check for last component in name provided */
+ if(last_comp) {
+ H5O_link_t *cb_lnk; /* Pointer to link info for callback */
+ H5G_loc_t *cb_loc; /* Pointer to object location for callback */
+
+ /* Set callback parameters appropriately, based on link being found */
+ if(lookup_status) {
+ cb_lnk = &lnk;
+ if(obj_exists)
+ cb_loc = &obj_loc;
+ else
+ cb_loc = NULL;
+ } /* end if */
+ else {
+ HDassert(!obj_loc_valid);
+ cb_lnk = NULL;
+ cb_loc = NULL;
+ } /* end else */
+
+ /* Call 'operator' routine */
+ if((op)(&grp_loc, comp, cb_lnk, cb_loc, op_data, &own_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CALLBACK, FAIL, "traversal operator failed")
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Handle lookup failures now */
+ if(!lookup_status) {
+ /* If an intermediate group doesn't exist & flag is set, create the group */
+ if(target & H5G_CRT_INTMD_GROUP) {
+ const H5O_ginfo_t def_ginfo = H5G_CRT_GROUP_INFO_DEF; /* Default group info settings */
+ const H5O_linfo_t def_linfo = H5G_CRT_LINK_INFO_DEF; /* Default link info settings */
+ const H5O_pline_t def_pline = H5O_CRT_PIPELINE_DEF; /* Default filter pipeline settings */
+ H5O_ginfo_t par_ginfo; /* Group info settings for parent group */
+ H5O_linfo_t par_linfo; /* Link info settings for parent group */
+ H5O_pline_t par_pline; /* Filter pipeline settings for parent group */
+ H5O_linfo_t tmp_linfo; /* Temporary link info settings */
+ htri_t exists; /* Whether a group or link info message exists */
+ const H5O_ginfo_t *ginfo; /* Group info settings for new group */
+ const H5O_linfo_t *linfo; /* Link info settings for new group */
+ const H5O_pline_t *pline; /* Filter pipeline settings for new group */
+ H5G_obj_create_t gcrt_info; /* Group creation info */
+
+ /* Check for the parent group having a group info message */
+ /* (OK if not found) */
+ if((exists = H5O_msg_exists(grp_loc.oloc, H5O_GINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Get the group info for parent group */
+ if(NULL == H5O_msg_read(grp_loc.oloc, H5O_GINFO_ID, &par_ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "group info message not present")
+
+ /* Use parent group info settings */
+ ginfo = &par_ginfo;
+ } /* end if */
+ else
+ /* Use default group info settings */
+ ginfo = &def_ginfo;
+
+ /* Check for the parent group having a link info message */
+ /* (OK if not found) */
+ /* Get the link info for parent group */
+ if((exists = H5G__obj_get_linfo(grp_loc.oloc, &par_linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Only keep the creation order information from the parent
+ * group's link info
+ */
+ HDmemcpy(&tmp_linfo, &def_linfo, sizeof(H5O_linfo_t));
+ tmp_linfo.track_corder = par_linfo.track_corder;
+ tmp_linfo.index_corder = par_linfo.index_corder;
+ linfo = &tmp_linfo;
+ } /* end if */
+ else
+ /* Use default link info settings */
+ linfo = &def_linfo;
+
+ /* Check for the parent group having a filter pipeline message */
+ /* (OK if not found) */
+ if((exists = H5O_msg_exists(grp_loc.oloc, H5O_PLINE_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Get the filter pipeline for parent group */
+ if(NULL == H5O_msg_read(grp_loc.oloc, H5O_PLINE_ID, &par_pline, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "filter pipeline message not present")
+
+ /* Use parent filter pipeline settings */
+ pline = &par_pline;
+ } /* end if */
+ else
+ /* Use default filter pipeline settings */
+ pline = &def_pline;
+
+ /* Create the intermediate group */
+/* XXX: Should we allow user to control the group creation params here? -QAK */
+ gcrt_info.gcpl_id = H5P_GROUP_CREATE_DEFAULT;
+ gcrt_info.cache_type = H5G_NOTHING_CACHED;
+ HDmemset(&gcrt_info.cache, 0, sizeof(gcrt_info.cache));
+ if(H5G__obj_create_real(grp_oloc.file, dxpl_id, ginfo, linfo, pline, &gcrt_info, obj_loc.oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry")
+
+ /* Insert new group into current group's symbol table */
+ if(H5G__loc_insert(&grp_loc, comp, &obj_loc, H5O_TYPE_GROUP, &gcrt_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert intermediate group")
+
+ /* Decrement refcount on intermediate group's object header in memory */
+ if(H5O_dec_rc_by_loc(obj_loc.oloc, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+
+ /* Close new group */
+ if(H5O_close(obj_loc.oloc, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close")
+
+ /* If the parent group was holding the file open, the
+ * newly-created group should, as well.
+ */
+ if(grp_loc.oloc->holding_file)
+ if(H5O_loc_hold_file(obj_loc.oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+ /* Reset any non-default object header messages */
+ if(ginfo != &def_ginfo)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_GINFO_ID, (void *)ginfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset group info message")
+ if(linfo != &def_linfo)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_LINFO_ID, (void *)linfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset link info message")
+ if(pline != &def_pline)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_PLINE_ID, (void *)pline) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset I/O pipeline message")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found")
+ } /* end if */
+
+ /*
+ * Advance to the next component of the path.
+ */
+
+ /* Transfer "ownership" of the object's information to the group object */
+ H5G_loc_free(&grp_loc);
+ H5G_loc_copy(&grp_loc, &obj_loc, H5_COPY_SHALLOW);
+ H5G_loc_reset(&obj_loc);
+ obj_loc_valid = FALSE;
+
+ /* Advance to next component in string */
+ name += nchars;
+ } /* end while */
+
+ /* Call 'operator' routine */
+ /* If we've fallen through to here, the name must be something like just '.'
+ * and we should issue the callback on that. -QAK
+ * Since we don't have a group location or a link to the object we pass in
+ * NULL.
+ */
+ HDassert(group_copy);
+ if((op)(NULL, ".", NULL, &grp_loc, op_data, &own_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "traversal operator failed")
+
+ /* If the callback took ownership of the object location, it actually has
+ * ownership of grp_loc. It shouldn't have tried to take ownership of
+ * the "group location", which was NULL. */
+ HDassert(!(own_loc & H5G_OWN_GRP_LOC));
+ if(own_loc & H5G_OWN_OBJ_LOC)
+ own_loc |= H5G_OWN_GRP_LOC;
+
+done:
+ /* If there's been an error, the callback doesn't really get ownership of
+ * any location and we should close them both */
+ if(ret_value < 0)
+ own_loc = H5G_OWN_NONE;
+
+ /* Free all open locations. This also closes any open external files. */
+ if(obj_loc_valid && !(own_loc & H5G_OWN_OBJ_LOC))
+ H5G_loc_free(&obj_loc);
+ if(group_copy && !(own_loc & H5G_OWN_GRP_LOC))
+ H5G_loc_free(&grp_loc);
+
+ /* If there's valid information in the link, reset it */
+ if(link_valid)
+ if(H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset link message")
+
+ /* Release temporary component buffer */
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't release wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse
+ *
+ * Purpose: Traverse a path from a location & perform an operation when
+ * the last component of the name is reached.
+ *
+ * Return: Success: Non-negative if path can be fully traversed.
+ * Failure: Negative if the path could not be fully
+ * traversed.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 13 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_traverse(const H5G_loc_t *loc, const char *name, unsigned target, H5G_traverse_t op,
+ void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+ size_t nlinks; /* Link countdown value */
+ H5P_genplist_t *lapl; /* Property list with value for nlinks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no name given")
+ if(!loc)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no starting location")
+ if(!op)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no operation provided")
+ HDassert(lapl_id >= 0);
+
+ /* Set nlinks value from property list, if it exists */
+ if(lapl_id == H5P_DEFAULT)
+ nlinks = H5L_NUM_LINKS;
+ else {
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+ if(H5P_get(lapl, H5L_ACS_NLINKS_NAME, &nlinks) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of links")
+ } /* end else */
+
+ /* Set up invalid tag. This is a precautionary step only. Setting an invalid
+ tag here will ensure that no metadata accessed while doing the traversal
+ is given an improper tag, unless another one is specifically set up
+ first. This will ensure we're not accidentally tagging something we
+ shouldn't be during the traversal. Note that for best tagging assertion
+ coverage, setting H5C_DO_TAGGING_SANITY_CHECKS is advised. */
+ H5_BEGIN_TAG(dxpl_id, H5AC__INVALID_TAG, FAIL);
+
+ /* Go perform "real" traversal */
+ if(H5G_traverse_real(loc, name, target, &nlinks, op, op_data, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_NOTFOUND, FAIL, "internal path traversal failed")
+
+ /* Reset tag after traversal */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse() */
+
diff --git a/src/H5HF.c b/src/H5HF.c
new file mode 100644
index 0000000..6c09969
--- /dev/null
+++ b/src/H5HF.c
@@ -0,0 +1,952 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HF.c
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Implements a "fractal heap" for storing variable-
+ * length objects in a file.
+ *
+ * Please see the documentation in:
+ * doc/html/TechNotes/FractalHeap.html for a full description
+ * of how they work, etc.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FOprivate.h" /* File objects */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HF_t struct */
+H5FL_DEFINE_STATIC(H5HF_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_op_read
+ *
+ * Purpose: Performs a 'read' operation for a heap 'op' callback
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_op_read(const void *obj, size_t obj_len, void *op_data)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Perform "read", using memcpy() */
+ HDmemcpy(op_data, obj, obj_len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_op_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_op_write
+ *
+ * Purpose: Performs a 'write' operation for a heap 'op' callback
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_op_write(const void *obj, size_t obj_len, void *op_data)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Perform "write", using memcpy() */
+ HDmemcpy((void *)obj, op_data, obj_len); /* Casting away const OK -QAK */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_op_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_create
+ *
+ * Purpose: Creates a new empty fractal heap in the file.
+ *
+ * Return: Pointer to heap wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_t *
+H5HF_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam)
+{
+ H5HF_t *fh = NULL; /* Pointer to new fractal heap */
+ H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
+ haddr_t fh_addr; /* Heap header address */
+ H5HF_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+ /* Create shared fractal heap header */
+ if(HADDR_UNDEF == (fh_addr = H5HF_hdr_create(f, dxpl_id, cparam)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create fractal heap header")
+
+ /* Allocate fractal heap wrapper */
+ if(NULL == (fh = H5FL_MALLOC(H5HF_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info")
+
+ /* Lock the heap header into memory */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header")
+
+ /* Point fractal heap wrapper at header and bump it's ref count */
+ fh->hdr = hdr;
+ if(H5HF_hdr_incr(fh->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
+
+ /* Increment # of files using this heap header */
+ if(H5HF_hdr_fuse_incr(fh->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment file reference count on shared heap header")
+
+ /* Set file pointer for this heap open context */
+ fh->f = f;
+
+ /* Set the return value */
+ ret_value = fh;
+
+done:
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header")
+ if(!ret_value && fh)
+ if(H5HF_close(fh, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_open
+ *
+ * Purpose: Opens an existing fractal heap in the file.
+ *
+ * Return: Pointer to heap wrapper on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_t *
+H5HF_open(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr)
+{
+ H5HF_t *fh = NULL; /* Pointer to new fractal heap */
+ H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
+ H5HF_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fh_addr));
+
+ /* Load the heap header into memory */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header")
+
+ /* Check for pending heap deletion */
+ if(hdr->pending_delete)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, NULL, "can't open fractal heap pending deletion")
+
+ /* Create fractal heap info */
+ if(NULL == (fh = H5FL_MALLOC(H5HF_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info")
+
+ /* Point fractal heap wrapper at header */
+ fh->hdr = hdr;
+ if(H5HF_hdr_incr(fh->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
+
+ /* Increment # of files using this heap header */
+ if(H5HF_hdr_fuse_incr(fh->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment file reference count on shared heap header")
+
+ /* Set file pointer for this heap open context */
+ fh->f = f;
+
+ /* Set the return value */
+ ret_value = fh;
+
+done:
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header")
+ if(!ret_value && fh)
+ if(H5HF_close(fh, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_id_len
+ *
+ * Purpose: Get the size of IDs for entries in a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_id_len(H5HF_t *fh, size_t *id_len_p)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id_len_p);
+
+ /* Retrieve the ID length for entries in this heap */
+ *id_len_p = fh->hdr->id_len;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_get_id_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_heap_addr
+ *
+ * Purpose: Get the address of a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_heap_addr(const H5HF_t *fh, haddr_t *heap_addr_p)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(heap_addr_p);
+
+ /* Retrieve the heap header address for this heap */
+ *heap_addr_p = fh->hdr->heap_addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_get_heap_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_insert
+ *
+ * Purpose: Insert a new object into a fractal heap.
+ *
+ * Return: Non-negative on success (with heap ID of new object
+ * filled in), negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_insert(H5HF_t *fh, hid_t dxpl_id, size_t size, const void *obj,
+ void *id/*out*/)
+{
+ H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(fh);
+ HDassert(obj);
+ HDassert(id);
+
+ /* Check arguments */
+ if(size == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "can't insert 0-sized objects")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Get the fractal heap header */
+ hdr = fh->hdr;
+
+ /* Check for 'huge' object */
+ if(size > hdr->max_man_size) {
+ /* Store 'huge' object in heap */
+ /* (Casting away const OK - QAK) */
+ if(H5HF_huge_insert(hdr, dxpl_id, size, (void *)obj, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'huge' object in fractal heap")
+ } /* end if */
+ /* Check for 'tiny' object */
+ else if(size <= hdr->tiny_max_len) {
+ /* Store 'tiny' object in heap */
+ if(H5HF_tiny_insert(hdr, size, obj, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'tiny' object in fractal heap")
+ } /* end if */
+ else {
+ /* Check if we are in "append only" mode, or if there's enough room for the object */
+ if(hdr->write_once) {
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'write once' managed blocks not supported yet")
+ } /* end if */
+ else {
+ /* Allocate space for object in 'managed' heap */
+ if(H5HF_man_insert(hdr, dxpl_id, size, obj, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'managed' object in fractal heap")
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_obj_len
+ *
+ * Purpose: Get the size of an entry in a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_obj_len(H5HF_t *fh, hid_t dxpl_id, const void *_id, size_t *obj_len_p)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(obj_len_p);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ if(H5HF_man_get_obj_len(fh->hdr, id, obj_len_p) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'managed' object's length")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ if(H5HF_huge_get_obj_len(fh->hdr, dxpl_id, id, obj_len_p) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's length")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ if(H5HF_tiny_get_obj_len(fh->hdr, id, obj_len_p) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'tiny' object's length")
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_get_obj_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_obj_off
+ *
+ * Purpose: Get the offset of an entry in a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 20 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_obj_off(H5HF_t *fh, hid_t dxpl_id, const void *_id, hsize_t *obj_off_p)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(obj_off_p);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ H5HF__man_get_obj_off(fh->hdr, id, obj_off_p);
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ /* Huge objects are located directly in the file */
+ if(H5HF__huge_get_obj_off(fh->hdr, dxpl_id, id, obj_off_p) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's offset")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ /* Tiny objects are not stored in the heap */
+ *obj_off_p = (hsize_t)0;
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_get_obj_off() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_read
+ *
+ * Purpose: Read an object from a fractal heap into a buffer
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_read(H5HF_t *fh, hid_t dxpl_id, const void *_id, void *obj/*out*/)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ /* Read object from managed heap blocks */
+ if(H5HF_man_read(fh->hdr, dxpl_id, id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ /* Read 'huge' object from file */
+ if(H5HF_huge_read(fh->hdr, dxpl_id, id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'huge' object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ /* Read 'tiny' object from file */
+ if(H5HF_tiny_read(fh->hdr, id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'tiny' object from fractal heap")
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_write
+ *
+ * Purpose: Write an object from a buffer into a fractal heap
+ *
+ * Notes: Writing objects in "managed" heap blocks is only storage
+ * method currently supported. (Which could be expanded to
+ * 'huge' and 'tiny' objects, with some work)
+ *
+ * Also, assumes that the 'op' routine modifies the data, and
+ * marks data to be written back to disk, even if 'op' routine
+ * didn't actually change anything. (Which could be modified
+ * to pass "did_modify" flag to callback, if necessary)
+ *
+ * Also, assumes that object to write is same size as object in
+ * heap.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_write(H5HF_t *fh, hid_t dxpl_id, void *_id, hbool_t H5_ATTR_UNUSED *id_changed,
+ const void *obj)
+{
+ uint8_t *id = (uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ /* Operate on object from managed heap blocks */
+ /* (ID can't change and modifying object is "easy" to manage) */
+ if(H5HF_man_write(fh->hdr, dxpl_id, id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'managed' heap object")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ /* Operate on "huge" object */
+ if(H5HF_huge_write(fh->hdr, dxpl_id, id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'huge' heap object")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ /* Check for writing a 'tiny' object */
+ /* (which isn't supported yet - ID will change) */
+ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'tiny' object not supported yet")
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_op
+ *
+ * Purpose: Perform an operation directly on a heap object
+ *
+ * Note: The library routines currently assume that the 'op' callback
+ * won't modify the object. This can easily be changed later for
+ * "managed" heap objects, and, with some difficulty, for 'huge'
+ * and 'tiny' heap objects.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sept 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_op(H5HF_t *fh, hid_t dxpl_id, const void *_id, H5HF_operator_t op,
+ void *op_data)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(op);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ /* Operate on object from managed heap blocks */
+ if(H5HF_man_op(fh->hdr, dxpl_id, id, op, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ /* Operate on 'huge' object from file */
+ if(H5HF_huge_op(fh->hdr, dxpl_id, id, op, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'huge' object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ /* Operate on 'tiny' object from file */
+ if(H5HF_tiny_op(fh->hdr, id, op, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'tiny' object from fractal heap")
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_remove
+ *
+ * Purpose: Remove an object from a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_remove(H5HF_t *fh, hid_t dxpl_id, const void *_id)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(fh->hdr);
+ HDassert(id);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ /* Remove object from managed heap blocks */
+ if(H5HF_man_remove(fh->hdr, dxpl_id, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ /* Remove 'huge' object from file & v2 B-tree tracker */
+ if(H5HF_huge_remove(fh->hdr, dxpl_id, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'huge' object from fractal heap")
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ /* Remove 'tiny' object from heap statistics */
+ if(H5HF_tiny_remove(fh->hdr, id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'tiny' object from fractal heap")
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_close
+ *
+ * Purpose: Close a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_close(H5HF_t *fh, hid_t dxpl_id)
+{
+ hbool_t pending_delete = FALSE; /* Whether the heap is pending deletion */
+ haddr_t heap_addr = HADDR_UNDEF; /* Address of heap (for deletion) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+
+ /* Decrement file reference & check if this is the last open fractal heap using the shared heap header */
+ if(0 == H5HF_hdr_fuse_decr(fh->hdr)) {
+ /* Set the shared heap header's file context for this operation */
+ fh->hdr->f = fh->f;
+
+ /* Close the free space information */
+ /* (Can't put this in header "destroy" routine, because it has
+ * pointers to indirect blocks in the heap, which would create
+ * a reference loop and the objects couldn't be removed from
+ * the metadata cache - QAK)
+ */
+ if(H5HF_space_close(fh->hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
+
+ /* Reset the block iterator, if necessary */
+ /* (Can't put this in header "destroy" routine, because it has
+ * pointers to indirect blocks in the heap, which would create
+ * a reference loop and the objects couldn't be removed from
+ * the metadata cache - QAK)
+ */
+ if(H5HF_man_iter_ready(&fh->hdr->next_block))
+ if(H5HF_man_iter_reset(&fh->hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
+
+ /* Shut down the huge object information */
+ /* (Can't put this in header "destroy" routine, because it has
+ * has the address of an object in the file, which might be
+ * modified by the shutdown routine - QAK)
+ */
+ if(H5HF_huge_term(fh->hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release 'huge' object info")
+
+ /* Check for pending heap deletion */
+ if(fh->hdr->pending_delete) {
+ /* Set local info, so heap deletion can occur after decrementing the
+ * header's ref count
+ */
+ pending_delete = TRUE;
+ heap_addr = fh->hdr->heap_addr;
+ } /* end if */
+ } /* end if */
+
+ /* Decrement the reference count on the heap header */
+ /* (don't put in H5HF_hdr_fuse_decr() as the heap header may be evicted
+ * immediately -QAK)
+ */
+ if(H5HF_hdr_decr(fh->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
+
+ /* Check for pending heap deletion */
+ if(pending_delete) {
+ H5HF_hdr_t *hdr; /* Another pointer to fractal heap header */
+
+ /* Lock the heap header into memory */
+ if(NULL == (hdr = H5HF_hdr_protect(fh->f, dxpl_id, heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /* Delete heap, starting with header (unprotects header) */
+ if(H5HF_hdr_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
+ } /* end if */
+
+done:
+ /* Release the fractal heap wrapper */
+ fh = H5FL_FREE(H5HF_t, fh);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_delete
+ *
+ * Purpose: Delete a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_delete(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr)
+{
+ H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fh_addr));
+
+ /* Lock the heap header into memory */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /* Check for files using shared heap header */
+ if(hdr->file_rc)
+ hdr->pending_delete = TRUE;
+ else {
+ /* Delete heap now, starting with header (unprotects header) */
+ if(H5HF_hdr_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
+ hdr = NULL;
+ } /* end if */
+
+done:
+ /* Unprotect the header, if an error occurred */
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_delete() */
+
diff --git a/src/H5HFbtree2.c b/src/H5HFbtree2.c
new file mode 100644
index 0000000..2d35368
--- /dev/null
+++ b/src/H5HFbtree2.c
@@ -0,0 +1,1072 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFbtree2.c
+ * Aug 7 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: v2 B-tree callbacks for "huge" object tracker
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* v2 B-tree client callback context */
+typedef struct H5HF_huge_bt2_ctx_t {
+ uint8_t sizeof_size; /* Size of file sizes */
+ uint8_t sizeof_addr; /* Size of file addresses */
+} H5HF_huge_bt2_ctx_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/* v2 B-tree driver callbacks */
+
+/* Common callbacks */
+static void *H5HF__huge_bt2_crt_context(void *udata);
+static herr_t H5HF__huge_bt2_dst_context(void *ctx);
+
+/* Callbacks for indirect objects */
+static herr_t H5HF__huge_bt2_indir_store(void *native, const void *udata);
+static herr_t H5HF__huge_bt2_indir_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5HF__huge_bt2_indir_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_indir_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_indir_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* Callbacks for filtered indirect objects */
+static herr_t H5HF__huge_bt2_filt_indir_store(void *native, const void *udata);
+static herr_t H5HF__huge_bt2_filt_indir_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5HF__huge_bt2_filt_indir_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_filt_indir_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_filt_indir_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* Callbacks for direct objects */
+static herr_t H5HF__huge_bt2_dir_store(void *native, const void *udata);
+static herr_t H5HF__huge_bt2_dir_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5HF__huge_bt2_dir_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_dir_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_dir_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/* Callbacks for filtered direct objects */
+static herr_t H5HF__huge_bt2_filt_dir_store(void *native, const void *udata);
+static herr_t H5HF__huge_bt2_filt_dir_compare(const void *rec1, const void *rec2, int *result);
+static herr_t H5HF__huge_bt2_filt_dir_encode(uint8_t *raw, const void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_filt_dir_decode(const uint8_t *raw, void *native,
+ void *ctx);
+static herr_t H5HF__huge_bt2_filt_dir_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+/*********************/
+/* Package Variables */
+/*********************/
+/* v2 B-tree class for indirectly accessed 'huge' objects */
+const H5B2_class_t H5HF_HUGE_BT2_INDIR[1]={{ /* B-tree class information */
+ H5B2_FHEAP_HUGE_INDIR_ID, /* Type of B-tree */
+ "H5B2_FHEAP_HUGE_INDIR_ID", /* Name of B-tree class */
+ sizeof(H5HF_huge_bt2_indir_rec_t), /* Size of native record */
+ H5HF__huge_bt2_crt_context, /* Create client callback context */
+ H5HF__huge_bt2_dst_context, /* Destroy client callback context */
+ H5HF__huge_bt2_indir_store, /* Record storage callback */
+ H5HF__huge_bt2_indir_compare, /* Record comparison callback */
+ H5HF__huge_bt2_indir_encode, /* Record encoding callback */
+ H5HF__huge_bt2_indir_decode, /* Record decoding callback */
+ H5HF__huge_bt2_indir_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for indirectly accessed, filtered 'huge' objects */
+const H5B2_class_t H5HF_HUGE_BT2_FILT_INDIR[1]={{ /* B-tree class information */
+ H5B2_FHEAP_HUGE_FILT_INDIR_ID, /* Type of B-tree */
+ "H5B2_FHEAP_HUGE_FILT_INDIR_ID", /* Name of B-tree class */
+ sizeof(H5HF_huge_bt2_filt_indir_rec_t), /* Size of native record */
+ H5HF__huge_bt2_crt_context, /* Create client callback context */
+ H5HF__huge_bt2_dst_context, /* Destroy client callback context */
+ H5HF__huge_bt2_filt_indir_store, /* Record storage callback */
+ H5HF__huge_bt2_filt_indir_compare, /* Record comparison callback */
+ H5HF__huge_bt2_filt_indir_encode, /* Record encoding callback */
+ H5HF__huge_bt2_filt_indir_decode, /* Record decoding callback */
+ H5HF__huge_bt2_filt_indir_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for directly accessed 'huge' objects */
+const H5B2_class_t H5HF_HUGE_BT2_DIR[1]={{ /* B-tree class information */
+ H5B2_FHEAP_HUGE_DIR_ID, /* Type of B-tree */
+ "H5B2_FHEAP_HUGE_DIR_ID", /* Name of B-tree class */
+ sizeof(H5HF_huge_bt2_dir_rec_t), /* Size of native record */
+ H5HF__huge_bt2_crt_context, /* Create client callback context */
+ H5HF__huge_bt2_dst_context, /* Destroy client callback context */
+ H5HF__huge_bt2_dir_store, /* Record storage callback */
+ H5HF__huge_bt2_dir_compare, /* Record comparison callback */
+ H5HF__huge_bt2_dir_encode, /* Record encoding callback */
+ H5HF__huge_bt2_dir_decode, /* Record decoding callback */
+ H5HF__huge_bt2_dir_debug /* Record debugging callback */
+}};
+
+/* v2 B-tree class for directly accessed, filtered 'huge' objects */
+const H5B2_class_t H5HF_HUGE_BT2_FILT_DIR[1]={{ /* B-tree class information */
+ H5B2_FHEAP_HUGE_FILT_DIR_ID, /* Type of B-tree */
+ "H5B2_FHEAP_HUGE_FILT_DIR_ID", /* Name of B-tree class */
+ sizeof(H5HF_huge_bt2_filt_dir_rec_t), /* Size of native record */
+ H5HF__huge_bt2_crt_context, /* Create client callback context */
+ H5HF__huge_bt2_dst_context, /* Destroy client callback context */
+ H5HF__huge_bt2_filt_dir_store, /* Record storage callback */
+ H5HF__huge_bt2_filt_dir_compare, /* Record comparison callback */
+ H5HF__huge_bt2_filt_dir_encode, /* Record encoding callback */
+ H5HF__huge_bt2_filt_dir_decode, /* Record decoding callback */
+ H5HF__huge_bt2_filt_dir_debug /* Record debugging callback */
+}};
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HF_huge_bt2_ctx_t struct */
+H5FL_DEFINE_STATIC(H5HF_huge_bt2_ctx_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_crt_context
+ *
+ * Purpose: Create client callback context
+ *
+ * Note: Common to all 'huge' v2 B-tree clients
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HF__huge_bt2_crt_context(void *_f)
+{
+ H5F_t *f = (H5F_t *)_f; /* User data for building callback context */
+ H5HF_huge_bt2_ctx_t *ctx; /* Callback context structure */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Allocate callback context */
+ if(NULL == (ctx = H5FL_MALLOC(H5HF_huge_bt2_ctx_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate callback context")
+
+ /* Determine the size of addresses & lengths in the file */
+ ctx->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ ctx->sizeof_size = H5F_SIZEOF_SIZE(f);
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__huge_bt2_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dst_context
+ *
+ * Purpose: Destroy client callback context
+ *
+ * Note: Common to all 'huge' v2 B-tree clients
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dst_context(void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Release callback context */
+ ctx = H5FL_FREE(H5HF_huge_bt2_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_found
+ *
+ * Purpose: Retrieve record for indirectly accessed 'huge' object, when
+ * it's found in the v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_indir_found(const void *nrecord, void *op_data)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ *(H5HF_huge_bt2_indir_rec_t *)op_data = *(const H5HF_huge_bt2_indir_rec_t *)nrecord;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_remove
+ *
+ * Purpose: Free space for indirectly accessed 'huge' object, as v2 B-tree
+ * is being deleted or v2 B-tree node is removed
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_indir_remove(const void *nrecord, void *_udata)
+{
+ H5HF_huge_remove_ud_t *udata = (H5HF_huge_remove_ud_t *)_udata; /* User callback data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Free the space in the file for the object being removed */
+ if(H5MF_xfree(udata->hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, udata->dxpl_id, ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->addr, ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free space for huge object on disk")
+
+ /* Set the length of the object removed */
+ udata->obj_len = ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__huge_bt2_indir_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_store
+ *
+ * Purpose: Store native information into record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_indir_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5HF_huge_bt2_indir_rec_t *)nrecord = *(const H5HF_huge_bt2_indir_rec_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_indir_compare(const void *_rec1, const void *_rec2, int *result)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *result = (int)(((const H5HF_huge_bt2_indir_rec_t *)_rec1)->id -
+ ((const H5HF_huge_bt2_indir_rec_t *)_rec2)->id);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_indir_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5HF_huge_bt2_indir_rec_t *nrecord = (const H5HF_huge_bt2_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, nrecord->addr);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->id, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_indir_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5HF_huge_bt2_indir_rec_t *nrecord = (H5HF_huge_bt2_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &nrecord->addr);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->id, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_indir_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_indir_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_huge_bt2_indir_rec_t *nrecord = (const H5HF_huge_bt2_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%a, %Hu, %Hu}\n", indent, "", fwidth, "Record:",
+ nrecord->addr, nrecord->len, nrecord->id);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_indir_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_found
+ *
+ * Purpose: Retrieve record for indirectly accessed, filtered 'huge' object,
+ * when it's found in the v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_filt_indir_found(const void *nrecord, void *op_data)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ *(H5HF_huge_bt2_filt_indir_rec_t *)op_data = *(const H5HF_huge_bt2_filt_indir_rec_t *)nrecord;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_remove
+ *
+ * Purpose: Free space for indirectly accessed, filtered 'huge' object, as
+ * v2 B-tree is being deleted or v2 B-tree node is removed
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_filt_indir_remove(const void *nrecord, void *_udata)
+{
+ H5HF_huge_remove_ud_t *udata = (H5HF_huge_remove_ud_t *)_udata; /* User callback data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Free the space in the file for the object being removed */
+ if(H5MF_xfree(udata->hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, udata->dxpl_id, ((const H5HF_huge_bt2_filt_indir_rec_t *)nrecord)->addr, ((const H5HF_huge_bt2_filt_indir_rec_t *)nrecord)->len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free space for huge object on disk")
+
+ /* Set the length of the object removed */
+ udata->obj_len = ((const H5HF_huge_bt2_filt_indir_rec_t *)nrecord)->obj_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__huge_bt2_filt_indir_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_store
+ *
+ * Purpose: Store native information into record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_indir_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5HF_huge_bt2_filt_indir_rec_t *)nrecord = *(const H5HF_huge_bt2_filt_indir_rec_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_indir_compare(const void *_rec1, const void *_rec2, int *result)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *result = (int)(((const H5HF_huge_bt2_filt_indir_rec_t *)_rec1)->id -
+ ((const H5HF_huge_bt2_filt_indir_rec_t *)_rec2)->id);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_indir_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5HF_huge_bt2_filt_indir_rec_t *nrecord = (const H5HF_huge_bt2_filt_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, nrecord->addr);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ UINT32ENCODE(raw, nrecord->filter_mask);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->obj_size, ctx->sizeof_size);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->id, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_indir_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5HF_huge_bt2_filt_indir_rec_t *nrecord = (H5HF_huge_bt2_filt_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &nrecord->addr);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ UINT32DECODE(raw, nrecord->filter_mask);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->obj_size, ctx->sizeof_size);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->id, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_indir_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_indir_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_huge_bt2_filt_indir_rec_t *nrecord = (const H5HF_huge_bt2_filt_indir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%a, %Hu, %x, %Hu, %Hu}\n", indent, "", fwidth, "Record:",
+ nrecord->addr, nrecord->len, nrecord->filter_mask, nrecord->obj_size, nrecord->id);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_indir_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_remove
+ *
+ * Purpose: Free space for directly accessed 'huge' object, as v2 B-tree
+ * is being deleted or v2 B-tree node is being removed
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_dir_remove(const void *nrecord, void *_udata)
+{
+ H5HF_huge_remove_ud_t *udata = (H5HF_huge_remove_ud_t *)_udata; /* User callback data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Free the space in the file for the object being removed */
+ if(H5MF_xfree(udata->hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, udata->dxpl_id, ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->addr, ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free space for huge object on disk")
+
+ /* Set the length of the object removed */
+ udata->obj_len = ((const H5HF_huge_bt2_indir_rec_t *)nrecord)->len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__huge_bt2_dir_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_store
+ *
+ * Purpose: Store native information into record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dir_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5HF_huge_bt2_dir_rec_t *)nrecord = *(const H5HF_huge_bt2_dir_rec_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dir_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dir_compare(const void *_rec1, const void *_rec2, int *result)
+{
+ const H5HF_huge_bt2_dir_rec_t *rec1 = (const H5HF_huge_bt2_dir_rec_t *)_rec1;
+ const H5HF_huge_bt2_dir_rec_t *rec2 = (const H5HF_huge_bt2_dir_rec_t *)_rec2;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(rec1->addr < rec2->addr)
+ *result = -1;
+ else if(rec1->addr > rec2->addr)
+ *result = 1;
+ else if(rec1->len < rec2->len)
+ *result = -1;
+ else if(rec1->len > rec2->len)
+ *result = 1;
+ else
+ *result = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dir_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dir_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5HF_huge_bt2_dir_rec_t *nrecord = (const H5HF_huge_bt2_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, nrecord->addr);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dir_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dir_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5HF_huge_bt2_dir_rec_t *nrecord = (H5HF_huge_bt2_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &nrecord->addr);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dir_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_dir_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 7, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_dir_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_huge_bt2_dir_rec_t *nrecord = (const H5HF_huge_bt2_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%a, %Hu}\n", indent, "", fwidth, "Record:",
+ nrecord->addr, nrecord->len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_dir_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_found
+ *
+ * Purpose: Retrieve record for directly accessed, filtered 'huge' object,
+ * when it's found in the v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_filt_dir_found(const void *nrecord, void *op_data)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ *(H5HF_huge_bt2_filt_dir_rec_t *)op_data = *(const H5HF_huge_bt2_filt_dir_rec_t *)nrecord;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_found() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_remove
+ *
+ * Purpose: Free space for directly accessed, filtered 'huge' object, as
+ * v2 B-tree is being deleted or v2 B-tree node is removed
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_bt2_filt_dir_remove(const void *nrecord, void *_udata)
+{
+ H5HF_huge_remove_ud_t *udata = (H5HF_huge_remove_ud_t *)_udata; /* User callback data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Free the space in the file for the object being removed */
+ if(H5MF_xfree(udata->hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, udata->dxpl_id, ((const H5HF_huge_bt2_filt_dir_rec_t *)nrecord)->addr, ((const H5HF_huge_bt2_filt_dir_rec_t *)nrecord)->len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free space for huge object on disk")
+
+ /* Set the length of the object removed */
+ udata->obj_len = ((const H5HF_huge_bt2_filt_dir_rec_t *)nrecord)->obj_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__huge_bt2_filt_dir_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_store
+ *
+ * Purpose: Store native information into record for v2 B-tree
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_dir_store(void *nrecord, const void *udata)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ *(H5HF_huge_bt2_filt_dir_rec_t *)nrecord = *(const H5HF_huge_bt2_filt_dir_rec_t *)udata;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_store() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_compare
+ *
+ * Purpose: Compare two native information records, according to some key
+ *
+ * Return: <0 if rec1 < rec2
+ * =0 if rec1 == rec2
+ * >0 if rec1 > rec2
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_dir_compare(const void *_rec1, const void *_rec2, int *result)
+{
+ const H5HF_huge_bt2_filt_dir_rec_t *rec1 = (const H5HF_huge_bt2_filt_dir_rec_t *)_rec1;
+ const H5HF_huge_bt2_filt_dir_rec_t *rec2 = (const H5HF_huge_bt2_filt_dir_rec_t *)_rec2;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(rec1->addr < rec2->addr)
+ *result = -1;
+ else if(rec1->addr > rec2->addr)
+ *result = 1;
+ else if(rec1->len < rec2->len)
+ *result = -1;
+ else if(rec1->len > rec2->len)
+ *result = 1;
+ else
+ *result = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_compare() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_encode
+ *
+ * Purpose: Encode native information into raw form for storing on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_dir_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5HF_huge_bt2_filt_dir_rec_t *nrecord = (const H5HF_huge_bt2_filt_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Encode the record's fields */
+ H5F_addr_encode_len(ctx->sizeof_addr, &raw, nrecord->addr);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ UINT32ENCODE(raw, nrecord->filter_mask);
+ H5F_ENCODE_LENGTH_LEN(raw, nrecord->obj_size, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_decode
+ *
+ * Purpose: Decode raw disk form of record into native form
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_dir_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
+{
+ H5HF_huge_bt2_ctx_t *ctx = (H5HF_huge_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5HF_huge_bt2_filt_dir_rec_t *nrecord = (H5HF_huge_bt2_filt_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Decode the record's fields */
+ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &nrecord->addr);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->len, ctx->sizeof_size);
+ UINT32DECODE(raw, nrecord->filter_mask);
+ H5F_DECODE_LENGTH_LEN(raw, nrecord->obj_size, ctx->sizeof_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_bt2_filt_dir_debug
+ *
+ * Purpose: Debug native form of record
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__huge_bt2_filt_dir_debug(FILE *stream, int indent, int fwidth,
+ const void *_nrecord, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_huge_bt2_filt_dir_rec_t *nrecord = (const H5HF_huge_bt2_filt_dir_rec_t *)_nrecord;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDfprintf(stream, "%*s%-*s {%a, %Hu, %x, %Hu}\n", indent, "", fwidth, "Record:",
+ nrecord->addr, nrecord->len, nrecord->filter_mask, nrecord->obj_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF__huge_bt2_filt_dir_debug() */
+
diff --git a/src/H5HFcache.c b/src/H5HFcache.c
new file mode 100644
index 0000000..f957e2e
--- /dev/null
+++ b/src/H5HFcache.c
@@ -0,0 +1,3511 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFcache.c
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Implement fractal heap metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Fractal heap format version #'s */
+#define H5HF_HDR_VERSION 0 /* Header */
+#define H5HF_DBLOCK_VERSION 0 /* Direct block */
+#define H5HF_IBLOCK_VERSION 0 /* Indirect block */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Local encode/decode routines */
+static herr_t H5HF__hdr_prefix_decode(H5HF_hdr_t *hdr, const uint8_t **image_ref);
+static herr_t H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable);
+static herr_t H5HF__dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dtable);
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5HF__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5HF__cache_hdr_get_final_load_size(const void *image_ptr,
+ size_t image_len, void *udata, size_t *actual_len);
+static htri_t H5HF__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5HF__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HF__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5HF__cache_hdr_pre_serialize(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags);
+static herr_t H5HF__cache_hdr_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HF__cache_hdr_free_icr(void *thing);
+
+static herr_t H5HF__cache_iblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5HF__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5HF__cache_iblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HF__cache_iblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5HF__cache_iblock_pre_serialize(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags);
+static herr_t H5HF__cache_iblock_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HF__cache_iblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5HF__cache_iblock_free_icr(void *thing);
+
+static herr_t H5HF__cache_dblock_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5HF__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5HF__cache_dblock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HF__cache_dblock_image_len(const void *thing, size_t *image_len);
+static herr_t H5HF__cache_dblock_pre_serialize(H5F_t *f, hid_t dxpl_id,
+ void *thing, haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len,
+ unsigned *flags);
+static herr_t H5HF__cache_dblock_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HF__cache_dblock_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5HF__cache_dblock_free_icr(void *thing);
+
+/* Debugging Function Prototypes */
+#ifndef NDEBUG
+static herr_t H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
+ H5HF_hdr_t *hdr, hbool_t *fd_clean, hbool_t *clean);
+static herr_t H5HF__cache_verify_iblock_descendants_clean(H5F_t *f,
+ hid_t dxpl_id, haddr_t fd_parent_addr, H5HF_indirect_t *iblock,
+ unsigned *iblock_status, hbool_t *fd_clean, hbool_t *clean);
+static herr_t H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f,
+ haddr_t fd_parent_addr, H5HF_indirect_t *iblock, hbool_t *fd_clean,
+ hbool_t *clean, hbool_t *has_dblocks);
+static herr_t H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f,
+ hid_t dxpl_id, haddr_t fd_parent_addr, H5HF_indirect_t *iblock,
+ hbool_t *fd_clean, hbool_t *clean, hbool_t *has_iblocks);
+#endif /* NDEBUG */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5HF header inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FHEAP_HDR[1] = {{
+ H5AC_FHEAP_HDR_ID, /* Metadata client ID */
+ "fractal heap header", /* Metadata client name (for debugging) */
+ H5FD_MEM_FHEAP_HDR, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5HF__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ H5HF__cache_hdr_get_final_load_size, /* 'get_final_load_size' callback */
+ H5HF__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5HF__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5HF__cache_hdr_image_len, /* 'image_len' callback */
+ H5HF__cache_hdr_pre_serialize, /* 'pre_serialize' callback */
+ H5HF__cache_hdr_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5HF__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5HF indirect block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FHEAP_IBLOCK[1] = {{
+ H5AC_FHEAP_IBLOCK_ID, /* Metadata client ID */
+ "fractal heap indirect block", /* Metadata client name (for debugging) */
+ H5FD_MEM_FHEAP_IBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5HF__cache_iblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5HF__cache_iblock_verify_chksum, /* 'verify_chksum' callback */
+ H5HF__cache_iblock_deserialize, /* 'deserialize' callback */
+ H5HF__cache_iblock_image_len, /* 'image_len' callback */
+ H5HF__cache_iblock_pre_serialize, /* 'pre_serialize' callback */
+ H5HF__cache_iblock_serialize, /* 'serialize' callback */
+ H5HF__cache_iblock_notify, /* 'notify' callback */
+ H5HF__cache_iblock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5HF direct block inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_FHEAP_DBLOCK[1] = {{
+ H5AC_FHEAP_DBLOCK_ID, /* Metadata client ID */
+ "fractal heap direct block", /* Metadata client name (for debugging) */
+ H5FD_MEM_FHEAP_DBLOCK, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5HF__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5HF__cache_dblock_verify_chksum, /* 'verify_chksum' callback */
+ H5HF__cache_dblock_deserialize, /* 'deserialize' callback */
+ H5HF__cache_dblock_image_len, /* 'image_len' callback */
+ H5HF__cache_dblock_pre_serialize, /* 'pre_serialize' callback */
+ H5HF__cache_dblock_serialize, /* 'serialize' callback */
+ H5HF__cache_dblock_notify, /* 'notify' callback */
+ H5HF__cache_dblock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage heap direct block data to/from disk */
+H5FL_BLK_DEFINE(direct_block);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__hdr_prefix_decode()
+ *
+ * Purpose: Decode a fractal heap header's prefix
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * December 15, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__hdr_prefix_decode(H5HF_hdr_t *hdr, const uint8_t **image_ref)
+{
+ const uint8_t *image = *image_ref; /* Pointer into into supplied image */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(hdr);
+ HDassert(image);
+
+ /* Magic number */
+ if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "wrong fractal heap header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5HF_HDR_VERSION)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong fractal heap header version")
+
+ /* General heap information */
+ UINT16DECODE(image, hdr->id_len); /* Heap ID length */
+ UINT16DECODE(image, hdr->filter_len); /* I/O filters' encoded length */
+
+ /* Update the image buffer pointer */
+ *image_ref = image;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__hdr_prefix_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__dtable_decode
+ *
+ * Purpose: Decodes the metadata for a doubling table
+ *
+ * Return: Success: Pointer to a new fractal heap
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dtable)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(pp && *pp);
+ HDassert(dtable);
+
+ /* Table width */
+ UINT16DECODE(*pp, dtable->cparam.width);
+
+ /* Starting block size */
+ H5F_DECODE_LENGTH(f, *pp, dtable->cparam.start_block_size);
+
+ /* Maximum direct block size */
+ H5F_DECODE_LENGTH(f, *pp, dtable->cparam.max_direct_size);
+
+ /* Maximum heap size (as # of bits) */
+ UINT16DECODE(*pp, dtable->cparam.max_index);
+
+ /* Starting # of rows in root indirect block */
+ UINT16DECODE(*pp, dtable->cparam.start_root_rows);
+
+ /* Address of table */
+ H5F_addr_decode(f, pp, &(dtable->table_addr));
+
+ /* Current # of rows in root indirect block */
+ UINT16DECODE(*pp, dtable->curr_root_rows);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__dtable_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__dtable_encode
+ *
+ * Purpose: Encodes the metadata for a doubling table
+ *
+ * Return: Success: Pointer to a new fractal heap
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(pp && *pp);
+ HDassert(dtable);
+
+ /* Table width */
+ UINT16ENCODE(*pp, dtable->cparam.width);
+
+ /* Starting block size */
+ H5F_ENCODE_LENGTH(f, *pp, dtable->cparam.start_block_size);
+
+ /* Maximum direct block size */
+ H5F_ENCODE_LENGTH(f, *pp, dtable->cparam.max_direct_size);
+
+ /* Maximum heap size (as # of bits) */
+ UINT16ENCODE(*pp, dtable->cparam.max_index);
+
+ /* Starting # of rows in root indirect block */
+ UINT16ENCODE(*pp, dtable->cparam.start_root_rows);
+
+ /* Address of root direct/indirect block */
+ H5F_addr_encode(f, pp, dtable->table_addr);
+
+ /* Current # of rows in root indirect block */
+ UINT16ENCODE(*pp, dtable->curr_root_rows);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__dtable_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_get_initial_load_size()
+ *
+ * Purpose: Determine the size of the fractal heap header on disk,
+ * and set *image_len to this value.
+ *
+ * Note also that the value returned by this function presumes that
+ * there is no I/O filtering data in the header. If there is, the
+ * size reported will be too small, and H5C_load_entry()
+ * will have to make two tries to load the fractal heap header.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* Pointer to user data */
+ H5HF_hdr_t dummy_hdr; /* Dummy header -- to compute size */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(image_len);
+
+ /* Set the internal parameters for the heap */
+ dummy_hdr.f = udata->f;
+ dummy_hdr.sizeof_size = H5F_SIZEOF_SIZE(udata->f);
+ dummy_hdr.sizeof_addr = H5F_SIZEOF_ADDR(udata->f);
+
+ /* Compute the 'base' size of the fractal heap header on disk */
+ *image_len = (size_t)H5HF_HEADER_SIZE(&dummy_hdr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_get_final_load_size()
+ *
+ * Purpose: Determine the final size of the fractal heap header on disk,
+ * and set *actual_len to this value.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_get_final_load_size(const void *_image, size_t image_len,
+ void *_udata, size_t *actual_len)
+{
+ H5HF_hdr_t hdr; /* Temporary fractal heap header */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into into supplied image */
+ H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+
+ /* Deserialize the fractal heap header's prefix */
+ if(H5HF__hdr_prefix_decode(&hdr, &image) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, FAIL, "can't decode fractal heap header prefix")
+
+ /* Check for I/O filter info on this heap */
+ if(hdr.filter_len > 0)
+ /* Compute the extra heap header size */
+ *actual_len += (size_t)(H5F_SIZEOF_SIZE(udata->f) /* Size of size for filtered root direct block */
+ + (unsigned)4 /* Size of filter mask for filtered root direct block */
+ + hdr.filter_len); /* Size of encoded I/O filter info */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_deserialize
+ *
+ * Purpose: Given a buffer containing an on disk image of a fractal heap
+ * header block, allocate an instance of H5HF_hdr_t, load the contents
+ * of the buffer into into the new instance of H5HF_hdr_t, and then
+ * return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5HF_hdr_t *hdr = NULL; /* Fractal heap info */
+ H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* User data for callback */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into into supplied image */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint8_t heap_flags; /* Status flags for heap */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(dirty);
+
+ /* Allocate space for the fractal heap data structure */
+ if(NULL == (hdr = H5HF_hdr_alloc(udata->f)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Deserialize the fractal heap header's prefix */
+ if(H5HF__hdr_prefix_decode(hdr, &image) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode fractal heap header prefix")
+
+ /* Heap status flags */
+ /* (bit 0: "huge" object IDs have wrapped) */
+ /* (bit 1: checksum direct blocks) */
+ heap_flags = *image++;
+ hdr->huge_ids_wrapped = heap_flags & H5HF_HDR_FLAGS_HUGE_ID_WRAPPED;
+ hdr->checksum_dblocks = heap_flags & H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS;
+
+ /* "Huge" object information */
+ UINT32DECODE(image, hdr->max_man_size); /* Max. size of "managed" objects */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */
+ H5F_addr_decode(udata->f, &image, &hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */
+
+ /* "Managed" object free space information */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */
+ H5F_addr_decode(udata->f, &image, &hdr->fs_addr); /* Address of free section header */
+
+ /* Heap statistics */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->man_size);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->man_alloc_size);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->man_iter_off);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->man_nobjs);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->huge_size);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->huge_nobjs);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_size);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_nobjs);
+
+ /* Managed objects' doubling-table info */
+ if(H5HF__dtable_decode(hdr->f, &image, &(hdr->man_dtable)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, NULL, "unable to encode managed obj. doubling table info")
+
+ /* Set the fractal heap header's 'base' size */
+ hdr->heap_size = (size_t)H5HF_HEADER_SIZE(hdr);
+
+ /* Sanity check */
+ /* (allow for checksum not decoded yet) */
+ HDassert((size_t)(image - (const uint8_t *)_image) == (hdr->heap_size - H5HF_SIZEOF_CHKSUM));
+
+ /* Check for I/O filter information to decode */
+ if(hdr->filter_len > 0) {
+ H5O_pline_t *pline; /* Pipeline information from the header on disk */
+
+ /* Sanity check */
+ HDassert(len > hdr->heap_size); /* A header with filter info is > than a standard header */
+
+ /* Compute the heap header's size */
+ hdr->heap_size += (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */
+ + (unsigned)4 /* Size of filter mask for filtered root direct block */
+ + hdr->filter_len); /* Size of encoded I/O filter info */
+
+ /* Decode the size of a filtered root direct block */
+ H5F_DECODE_LENGTH(udata->f, image, hdr->pline_root_direct_size);
+
+ /* Decode the filter mask for a filtered root direct block */
+ UINT32DECODE(image, hdr->pline_root_direct_filter_mask);
+
+ /* Decode I/O filter information */
+ if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(hdr->f, udata->dxpl_id, NULL, H5O_PLINE_ID, image)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode I/O pipeline filters")
+
+ /* Advance past filter info to checksum */
+ image += hdr->filter_len;
+
+ /* Copy the information into the header's I/O pipeline structure */
+ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &(hdr->pline)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOPY, NULL, "can't copy I/O filter pipeline")
+
+ /* Release the space allocated for the I/O pipeline filters */
+ H5O_msg_free(H5O_PLINE_ID, pline);
+ } /* end if */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == hdr->heap_size);
+
+ /* Finish initialization of heap header */
+ if(H5HF_hdr_finish_init(hdr) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't finish initializing shared fractal heap header")
+
+ /* Set return value */
+ ret_value = (void *)hdr;
+
+done:
+ if(!ret_value && hdr)
+ if(H5HF_hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_image_len
+ *
+ * Purpose: Return the actual size of the fractal heap header on
+ * disk image.
+ *
+ * If the header contains filter information, this size will be
+ * larger than the value returned by H5HF__cache_hdr_get_initial_load_size().
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HF_hdr_t *hdr = (const H5HF_hdr_t *)_thing; /* Fractal heap info */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(image_len);
+
+ *image_len = hdr->heap_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_pre_serialize
+ *
+ * Purpose: As best I can tell, fractal heap header blocks are always
+ * allocated in real file space. Thus this routine simply verifies
+ * this, verifies that the len parameter contains the expected
+ * value, and returns an error if either of these checks fail.
+ *
+ * When compiled in debug mode, the function also verifies that all
+ * indirect and direct blocks that are children of the header are
+ * either clean, or not in the metadata cache.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_pre_serialize(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ void *_thing, haddr_t addr, size_t len, haddr_t H5_ATTR_UNUSED *new_addr,
+ size_t H5_ATTR_UNUSED *new_len, unsigned *flags)
+{
+ H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(addr == hdr->heap_addr);
+ HDassert(new_addr);
+ HDassert(new_len);
+ HDassert(flags);
+
+#ifndef NDEBUG
+{
+ hbool_t descendants_clean = TRUE;
+ hbool_t fd_children_clean = TRUE;
+
+ /* Verify that flush dependencies are working correctly. Do this
+ * by verifying that either:
+ *
+ * 1) the header has a root iblock, and that the root iblock and all
+ * of its children are clean, or
+ *
+ * 2) The header has a root dblock, which is clean, or
+ *
+ * 3) The heap is empty, and thus the header has neither a root
+ * iblock no a root dblock. In this case, the flush ordering
+ * constraint is met by default.
+ *
+ * Do this with a call to H5HF__cache_verify_hdr_descendants_clean().
+ *
+ * Note that decendants need not be clean if the pre_serialize call
+ * is made during a cache serialization instead of an entry or cache
+ * flush.
+ *
+ * Note also that with the recent change in the definition of flush
+ * dependency, not all decendants need be clean -- only direct flush
+ * dependency children.
+ *
+ * Finally, observe that the H5HF__cache_verify_hdr_descendants_clean()
+ * call still looks for dirty descendants. At present we do not check
+ * this value.
+ */
+ if(H5HF__cache_verify_hdr_descendants_clean((H5F_t *)f, dxpl_id, hdr, &fd_children_clean, &descendants_clean) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.")
+ HDassert(fd_children_clean);
+}
+#endif /* NDEBUG */
+
+ if(H5F_IS_TMP_ADDR(f, addr))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "addr in temporary space?!?.");
+
+ if(len != hdr->heap_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "unexpected image len.");
+
+ *flags = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_pre_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_serialize
+ *
+ * Purpose: Construct the on disk image of the header, and place it in
+ * the buffer pointed to by image. Return SUCCEED on success,
+ * and FAIL on failure.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t heap_flags; /* Status flags for heap */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image);
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(len == hdr->heap_size);
+
+ /* Set the shared heap header's file context for this operation */
+ hdr->f = f;
+
+ /* Magic number */
+ HDmemcpy(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5HF_HDR_VERSION;
+
+ /* General heap information */
+ UINT16ENCODE(image, hdr->id_len); /* Heap ID length */
+ UINT16ENCODE(image, hdr->filter_len); /* I/O filters' encoded length */
+
+ /* Heap status flags */
+ /* (bit 0: "huge" object IDs have wrapped) */
+ /* (bit 1: checksum direct blocks) */
+ heap_flags = 0;
+ heap_flags = (uint8_t)(heap_flags | (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0));
+ heap_flags = (uint8_t)(heap_flags | (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0));
+ *image++ = heap_flags;
+
+ /* "Huge" object information */
+ UINT32ENCODE(image, hdr->max_man_size); /* Max. size of "managed" objects */
+ H5F_ENCODE_LENGTH(f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */
+ H5F_addr_encode(f, &image, hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */
+
+ /* "Managed" object free space information */
+ H5F_ENCODE_LENGTH(f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */
+ H5F_addr_encode(f, &image, hdr->fs_addr); /* Address of free section header */
+
+ /* Heap statistics */
+ H5F_ENCODE_LENGTH(f, image, hdr->man_size);
+ H5F_ENCODE_LENGTH(f, image, hdr->man_alloc_size);
+ H5F_ENCODE_LENGTH(f, image, hdr->man_iter_off);
+ H5F_ENCODE_LENGTH(f, image, hdr->man_nobjs);
+ H5F_ENCODE_LENGTH(f, image, hdr->huge_size);
+ H5F_ENCODE_LENGTH(f, image, hdr->huge_nobjs);
+ H5F_ENCODE_LENGTH(f, image, hdr->tiny_size);
+ H5F_ENCODE_LENGTH(f, image, hdr->tiny_nobjs);
+
+ /* Managed objects' doubling-table info */
+ if(H5HF__dtable_encode(hdr->f, &image, &(hdr->man_dtable)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "unable to encode managed obj. doubling table info")
+
+ /* Check for I/O filter information to encode */
+ if(hdr->filter_len > 0) {
+ /* Encode the size of a filtered root direct block */
+ H5F_ENCODE_LENGTH(f, image, hdr->pline_root_direct_size);
+
+ /* Encode the filter mask for a filtered root direct block */
+ UINT32ENCODE(image, hdr->pline_root_direct_filter_mask);
+
+ /* Encode I/O filter information */
+ if(H5O_msg_encode(hdr->f, H5O_PLINE_ID, FALSE, image, &(hdr->pline)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "can't encode I/O pipeline fiters")
+ image += hdr->filter_len;
+ } /* end if */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_hdr_free_icr
+ *
+ * Purpose: Free the in core representation of the fractal heap header.
+ *
+ * This routine frees just the header itself, not the
+ * associated version 2 B-Tree, the associated Free Space Manager,
+ * nor the indirect/direct block tree that is rooted in the header.
+ *
+ * This routine also does not free the file space that may
+ * be allocated to the header.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_hdr_free_icr(void *_thing)
+{
+ H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(hdr->rc == 0);
+
+ if(H5HF_hdr_free(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "unable to release fractal heap header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_get_initial_load_size()
+ *
+ * Purpose: Compute the size of the on disk image of the indirect
+ * block, and place this value in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(udata->par_info);
+ HDassert(udata->par_info->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5HF_MAN_INDIRECT_SIZE(udata->par_info->hdr, *udata->nrows);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_iblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_verify_chksum() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of the indirect
+ * block, allocate an instance of H5HF_indirect_t, load the data
+ * in the buffer into this new instance, and return a pointer to
+ * it.
+ *
+ * As best I can tell, the size of the indirect block image is fully
+ * know before the image is loaded, so this function should succeed
+ * unless the image is corrupt or memory allocation fails.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */
+ H5HF_indirect_t *iblock = NULL; /* Indirect block info */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ haddr_t heap_addr; /* Address of heap header in the file */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned u; /* Local index variable */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(dirty);
+ hdr = udata->par_info->hdr;
+ HDassert(hdr->f);
+
+ /* Set the shared heap header's file context for this operation */
+ hdr->f = udata->f;
+
+ /* Allocate space for the fractal heap indirect block */
+ if(NULL == (iblock = H5FL_CALLOC(H5HF_indirect_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Share common heap information */
+ iblock->hdr = hdr;
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
+
+ /* Set block's internal information */
+ iblock->rc = 0;
+ iblock->nrows = *udata->nrows;
+ iblock->nchildren = 0;
+
+ /* Compute size of indirect block */
+ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
+
+ /* sanity check */
+ HDassert(iblock->size == len);
+
+ /* Magic number */
+ if(HDmemcmp(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap indirect block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5HF_IBLOCK_VERSION)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version")
+
+ /* Address of heap that owns this block */
+ H5F_addr_decode(udata->f, &image, &heap_addr);
+ if(H5F_addr_ne(heap_addr, hdr->heap_addr))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block")
+
+ /* Address of parent block */
+ iblock->parent = udata->par_info->iblock;
+ /* this copy of the parent pointer is needed by the notify callback so */
+ /* that it can take down flush dependencies on eviction even if */
+ /* the parent pointer has been nulled out. JRM -- 5/18/14 */
+ iblock->fd_parent = udata->par_info->iblock;
+ iblock->par_entry = udata->par_info->entry;
+ if(iblock->parent) {
+ /* Share parent block */
+ if(H5HF_iblock_incr(iblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
+
+ /* Set max. # of rows in this block */
+ iblock->max_rows = iblock->nrows;
+ } /* end if */
+ else {
+ /* Set max. # of rows in this block */
+ iblock->max_rows = hdr->man_dtable.max_root_rows;
+ } /* end else */
+
+ /* Offset of heap within the heap's address space */
+ UINT64DECODE_VAR(image, iblock->block_off, hdr->heap_off_size);
+
+ /* Allocate & decode child block entry tables */
+ HDassert(iblock->nrows > 0);
+ if(NULL == (iblock->ents = H5FL_SEQ_MALLOC(H5HF_indirect_ent_t, (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct entries")
+
+ if(hdr->filter_len > 0) {
+ unsigned dir_rows; /* Number of direct rows in this indirect block */
+
+ /* Compute the number of direct rows for this indirect block */
+ dir_rows = MIN(iblock->nrows, hdr->man_dtable.max_direct_rows);
+
+ /* Allocate indirect block filtered entry array */
+ if(NULL == (iblock->filt_ents = H5FL_SEQ_MALLOC(H5HF_indirect_filt_ent_t, (size_t)(dir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for block entries")
+ } /* end if */
+ else
+ iblock->filt_ents = NULL;
+
+ for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) {
+ /* Decode child block address */
+ H5F_addr_decode(udata->f, &image, &(iblock->ents[u].addr));
+
+ /* Check for heap with I/O filters */
+ if(hdr->filter_len > 0) {
+ /* Sanity check */
+ HDassert(iblock->filt_ents);
+
+ /* Decode extra information for direct blocks */
+ if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) {
+ /* Size of filtered direct block */
+ H5F_DECODE_LENGTH(udata->f, image, iblock->filt_ents[u].size);
+
+ /* Sanity check */
+ /* (either both the address & size are defined or both are
+ * not defined)
+ */
+ HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size)
+ || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0));
+
+ /* I/O filter mask for filtered direct block */
+ UINT32DECODE(image, iblock->filt_ents[u].filter_mask);
+ } /* end if */
+ } /* end if */
+
+ /* Count child blocks */
+ if(H5F_addr_defined(iblock->ents[u].addr)) {
+ iblock->nchildren++;
+ iblock->max_child = u;
+ } /* end if */
+ } /* end for */
+
+ /* Sanity check */
+ HDassert(iblock->nchildren); /* indirect blocks w/no children should have been deleted */
+
+ /* checksum verification already done by verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size);
+
+ /* Check if we have any indirect block children */
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned indir_rows;/* Number of indirect rows in this indirect block */
+
+ /* Compute the number of indirect rows for this indirect block */
+ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
+
+ /* Allocate & initialize child indirect block pointer array */
+ if(NULL == (iblock->child_iblocks = H5FL_SEQ_CALLOC(H5HF_indirect_ptr_t, (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for block entries")
+ } /* end if */
+ else
+ iblock->child_iblocks = NULL;
+
+ /* Set return value */
+ ret_value = (void *)iblock;
+
+done:
+ if(!ret_value && iblock)
+ if(H5HF_man_iblock_dest(iblock) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap indirect block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_image_len
+ *
+ * Purpose: Return the size of the on disk image of the iblock.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HF_indirect_t *iblock = (const H5HF_indirect_t *)_thing; /* Indirect block info */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(image_len);
+
+ *image_len = iblock->size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_iblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_pre_serialize
+ *
+ * Purpose: The primary objective of this function is to determine if the
+ * indirect block is currently allocated in temporary file space,
+ * and if so, to move it to real file space before the entry is
+ * serialized.
+ *
+ * In debug compiles, this function also verifies that all
+ * immediate flush dependency children of this indirect block
+ * are either clean or are not in cache.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
+ haddr_t addr, size_t H5_ATTR_UNUSED len, haddr_t *new_addr,
+ size_t H5_ATTR_UNUSED *new_len, unsigned *flags)
+{
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(iblock->cache_info.size == iblock->size);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(H5F_addr_eq(iblock->addr, addr));
+ HDassert(new_addr);
+ HDassert(new_len);
+ HDassert(flags);
+ hdr = iblock->hdr;
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+
+#ifndef NDEBUG
+{
+ hbool_t descendants_clean = TRUE;
+ hbool_t fd_children_clean = TRUE;
+ unsigned iblock_status = 0;
+
+ /* verify that flush dependencies are working correctly. Do this
+ * by verifying that all immediate flush dependency children of this
+ * iblock are clean.
+ */
+ if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
+
+ /* since the current iblock is the guest of honor in a flush, we know
+ * that it is locked into the cache for the duration of the call. Hence
+ * there is no need to check to see if it is pinned or protected, or to
+ * protect it if it is not.
+ */
+ if(H5HF__cache_verify_iblock_descendants_clean((H5F_t *)f, dxpl_id, iblock->addr, iblock, &iblock_status, &fd_children_clean, &descendants_clean) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.")
+ HDassert(fd_children_clean);
+}
+#endif /* NDEBUG */
+
+ /* Check to see if we must re-allocate the iblock from temporary to
+ * normal (AKA real) file space.
+ */
+ if(H5F_IS_TMP_ADDR(f, addr)) {
+ haddr_t iblock_addr;
+
+ /* Allocate 'normal' space for the new indirect block on disk */
+ if(HADDR_UNDEF == (iblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+
+ /* Sanity check */
+ HDassert(!H5F_addr_eq(iblock->addr, iblock_addr));
+
+ /* Let the metadata cache know the block moved */
+ if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_IBLOCK, iblock->addr, iblock_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block")
+
+ /* Update the internal address for the block */
+ iblock->addr = iblock_addr;
+
+ /* Check for root indirect block */
+ if(NULL == iblock->parent) {
+ /* Update information about indirect block's location */
+ hdr->man_dtable.table_addr = iblock_addr;
+
+ /* Mark that heap header was modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end if */
+ else {
+ H5HF_indirect_t *par_iblock; /* Parent indirect block */
+ unsigned par_entry; /* Entry in parent indirect block */
+
+ /* Get parent information */
+ par_iblock = iblock->parent;
+ par_entry = iblock->par_entry;
+
+ /* Update information about indirect block's location */
+ par_iblock->ents[par_entry].addr = iblock_addr;
+
+ /* Mark that parent was modified */
+ if(H5HF_iblock_dirty(par_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end if */
+
+ *new_addr = iblock_addr;
+ *flags = H5AC__SERIALIZE_MOVED_FLAG;
+ } /* end if */
+ else
+ *flags = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_pre_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_serialize
+ *
+ * Purpose: Given a pointer to an iblock, and a pointer to a buffer of
+ * the appropriate size, write the contents of the iblock to the
+ * buffer in format appropriate for writing to disk.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+#ifndef NDEBUG
+ unsigned nchildren = 0; /* Track # of children */
+ size_t max_child = 0; /* Track max. child entry used */
+#endif /* NDEBUG */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image);
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(iblock->cache_info.size == iblock->size);
+ HDassert(len == iblock->size);
+
+ /* Indirect block must be in 'normal' file space */
+ HDassert(!H5F_IS_TMP_ADDR(f, iblock->addr));
+ HDassert(H5F_addr_eq(iblock->addr, iblock->cache_info.addr));
+
+ /* Get the pointer to the shared heap header */
+ hdr = iblock->hdr;
+
+ /* Set the shared heap header's file context for this operation */
+ hdr->f = f;
+
+ /* Magic number */
+ HDmemcpy(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5HF_IBLOCK_VERSION;
+
+ /* Address of heap header for heap which owns this block */
+ H5F_addr_encode(f, &image, hdr->heap_addr);
+
+ /* Offset of block in heap */
+ UINT64ENCODE_VAR(image, iblock->block_off, hdr->heap_off_size);
+
+ /* Encode indirect block-specific fields */
+ for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) {
+ /* Encode child block address */
+ H5F_addr_encode(f, &image, iblock->ents[u].addr);
+
+ /* Check for heap with I/O filters */
+ if(hdr->filter_len > 0) {
+ /* Sanity check */
+ HDassert(iblock->filt_ents);
+
+ /* Encode extra information for direct blocks */
+ if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) {
+ /* Sanity check */
+ /* (either both the address & size are defined or both are
+ * not defined)
+ */
+ HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size)
+ || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0));
+
+ /* Size of filtered direct block */
+ H5F_ENCODE_LENGTH(f, image, iblock->filt_ents[u].size);
+
+ /* I/O filter mask for filtered direct block */
+ UINT32ENCODE(image, iblock->filt_ents[u].filter_mask);
+ } /* end if */
+ } /* end if */
+
+#ifndef NDEBUG
+ /* Count child blocks */
+ if(H5F_addr_defined(iblock->ents[u].addr)) {
+ nchildren++;
+ if(u > max_child)
+ max_child = u;
+ } /* end if */
+#endif /* NDEBUG */
+ } /* end for */
+
+ /* Compute checksum */
+ metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity checks */
+ HDassert((size_t)(image - (uint8_t *)_image) == iblock->size);
+#ifndef NDEBUG
+ HDassert(nchildren == iblock->nchildren);
+ HDassert(max_child == iblock->max_child);
+#endif /* NDEBUG */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_notify
+ *
+ * Purpose: This function is used to create and destroy flush dependency
+ * relationships between iblocks and their parents as indirect blocks
+ * are loaded / inserted and evicted from the metadata cache.
+ *
+ * In general, the parent will be another iblock, but it may be the
+ * header if the iblock in question is the root iblock.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(iblock->hdr);
+
+ if(action == H5AC_NOTIFY_ACTION_BEFORE_EVICT)
+ HDassert((iblock->parent == iblock->fd_parent) || ((NULL == iblock->parent) && (iblock->fd_parent)));
+
+ /* further sanity checks */
+ if(iblock->parent == NULL) {
+ /* pointer from hdr to root iblock will not be set up unless */
+ /* the fractal heap has already pinned the hdr. Do what */
+ /* sanity checking we can. */
+ if((iblock->block_off == 0) && (iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED))
+ HDassert(iblock->hdr->root_iblock == iblock);
+ } /* end if */
+ else {
+ /* if this is a child iblock, verify that the pointers are */
+ /* either uninitialized or set up correctly. */
+ H5HF_indirect_t *par_iblock = iblock->parent;
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(par_iblock->child_iblocks);
+ HDassert(iblock->par_entry >= (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width));
+
+ /* Compute index in parent's child iblock pointer array */
+ indir_idx = iblock->par_entry - (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width);
+
+ /* The pointer to iblock in the parent may not be set yet -- */
+ /* verify that it is either NULL, or that it has been set to */
+ /* iblock. */
+ HDassert((NULL == par_iblock->child_iblocks[indir_idx]) || (par_iblock->child_iblocks[indir_idx] == iblock));
+ } /* end else */
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ if(iblock->parent) { /* this is a child iblock */
+ /* create flush dependency with parent iblock */
+ if(H5AC_create_flush_dependency(iblock->parent, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end if */
+ else { /* this is the root iblock */
+ /* create flush dependency with header */
+ if(H5AC_create_flush_dependency(iblock->hdr, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end else */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ if(iblock->fd_parent) { /* this is a child iblock */
+ /* destroy flush dependency with parent iblock */
+ if(H5AC_destroy_flush_dependency(iblock->fd_parent, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ } /* end if */
+ else { /* this is the root iblock */
+ /* destroy flush dependency with header */
+ if(H5AC_destroy_flush_dependency(iblock->hdr, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ } /* end else */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_iblock_free_icr
+ *
+ * Purpose: Unlink the supplied instance of H5HF_indirect_t from the
+ * fractal heap and free its memory.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_iblock_free_icr(void *thing)
+{
+ H5HF_indirect_t *iblock = (H5HF_indirect_t *)thing; /* Fractal heap indirect block to free */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(iblock->rc == 0);
+ HDassert(iblock->hdr);
+
+ /* Destroy fractal heap indirect block */
+ if(H5HF_man_iblock_dest(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_iblock_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_get_initial_load_size()
+ *
+ * Purpose: Determine the size of the direct block on disk image, and
+ * return it in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ const H5HF_dblock_cache_ud_t *udata = (const H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */
+ const H5HF_parent_t *par_info; /* Pointer to parent information */
+ const H5HF_hdr_t *hdr; /* Shared fractal heap information */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(image_len);
+
+ /* Convenience variables */
+ par_info = (const H5HF_parent_t *)(&(udata->par_info));
+ HDassert(par_info);
+ hdr = par_info->hdr;
+ HDassert(hdr);
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /* Check for root direct block */
+ if(par_info->iblock == NULL)
+ /* filtered root direct block */
+ *image_len = hdr->pline_root_direct_size;
+ else
+ /* filtered direct block */
+ *image_len = par_info->iblock->filt_ents[par_info->entry].size;
+ } /* end if */
+ else
+ *image_len = udata->dblock_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_dblock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF__cache_dblock_verify_chksum(const void *_image, size_t len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */
+ void *read_buf = NULL; /* Pointer to buffer to read in */
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_parent_t *par_info; /* Pointer to parent information */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ size_t chk_size; /* The size for validating checksum */
+ uint8_t *chk_p; /* Pointer to the area for validating checksum */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ par_info = (H5HF_parent_t *)(&(udata->par_info));
+ HDassert(par_info);
+ hdr = par_info->hdr;
+ HDassert(hdr);
+
+ /* Get out if data block is not checksummed */
+ if(!(hdr->checksum_dblocks))
+ HGOTO_DONE(TRUE);
+
+ if(hdr->filter_len > 0) {
+ size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */
+ unsigned filter_mask; /* Excluded filters for direct block */
+ H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */
+
+ /* Allocate buffer to perform I/O filtering on and copy image into
+ * it. Must do this as H5Z_pipeline() may re-size the buffer
+ * provided to it.
+ */
+ if(NULL == (read_buf = H5MM_malloc(len)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer")
+
+ /* Set up parameters for filter pipeline */
+ nbytes = len;
+ filter_mask = udata->filter_mask;
+ HDmemcpy(read_buf, image, len);
+
+ /* Push direct block data through I/O filter pipeline */
+ if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &len, &read_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "output pipeline failed")
+
+ /* Update info about direct block */
+ udata->decompressed = TRUE;
+ len = nbytes;
+ } /* end if */
+ else
+ read_buf = (void *)image; /* Casting away const OK - QAK */
+
+ /* Decode checksum */
+ chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM);
+ chk_p = (uint8_t *)read_buf + chk_size;
+
+ /* Metadata checksum */
+ UINT32DECODE(chk_p, stored_chksum);
+
+ chk_p -= H5HF_SIZEOF_CHKSUM;
+
+ /* Reset checksum field, for computing the checksum */
+ /* (Casting away const OK - QAK) */
+ HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM);
+
+ /* Compute checksum on entire direct block */
+ computed_chksum = H5_checksum_metadata(read_buf, len, 0);
+
+ /* Restore the checksum */
+ UINT32ENCODE(chk_p, stored_chksum)
+
+ /* Verify checksum */
+ if(stored_chksum != computed_chksum)
+ HGOTO_DONE(FALSE);
+
+ /* Save the decompressed data to be used later in deserialize callback */
+ if(hdr->filter_len > 0) {
+ /* Sanity check */
+ HDassert(udata->decompressed);
+ HDassert(len == udata->dblock_size);
+
+ /* Allocate block buffer */
+ if(NULL == (udata->dblk = H5FL_BLK_MALLOC(direct_block, (size_t)len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy un-filtered data into block's buffer */
+ HDmemcpy(udata->dblk, read_buf, len);
+ } /* end if */
+
+done:
+ /* Release the read buffer */
+ if(read_buf && read_buf != image)
+ H5MM_xfree(read_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of a direct
+ * block, allocate an instance of H5HF_direct_t, load the data
+ * in the buffer into this new instance, and return a pointer to
+ * it.
+ *
+ * As best I can tell, the size of the direct block image is fully
+ * know before the image is loaded, so this function should succeed
+ * unless the image is corrupt or memory allocation fails.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */
+ H5HF_parent_t *par_info; /* Pointer to parent information */
+ H5HF_direct_t *dblock = NULL; /* Direct block info */
+ const uint8_t *image = (const uint8_t *)_image;/* Pointer into raw data buffer */
+ void *read_buf = NULL; /* Pointer to buffer to decompress */
+ haddr_t heap_addr; /* Address of heap header in the file */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ par_info = (H5HF_parent_t *)(&(udata->par_info));
+ HDassert(par_info);
+ hdr = par_info->hdr;
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(dirty);
+
+ /* Allocate space for the fractal heap direct block */
+ if(NULL == (dblock = H5FL_CALLOC(H5HF_direct_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Set the shared heap header's file context for this operation */
+ hdr->f = udata->f;
+
+ /* Share common heap information */
+ dblock->hdr = hdr;
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
+
+ /* Set block's internal information */
+ dblock->size = udata->dblock_size;
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /* Direct block is already decompressed in verify_chksum callback */
+ if(udata->decompressed) {
+ /* Sanity check */
+ HDassert(udata->dblk);
+
+ /* Take ownership of the decompressed direct block */
+ dblock->blk = udata->dblk;
+ udata->dblk = NULL;
+ } /* end if */
+ else {
+ H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */
+ size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */
+ unsigned filter_mask; /* Excluded filters for direct block */
+
+ /* Sanity check */
+ HDassert(udata->dblk == NULL);
+
+ /* Allocate buffer to perform I/O filtering on and copy image into
+ * it. Must do this as H5Z_pipeline() may resize the buffer
+ * provided to it.
+ */
+ if(NULL == (read_buf = H5MM_malloc(len)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for pipeline buffer")
+
+ /* Copy compressed image into buffer */
+ HDmemcpy(read_buf, image, len);
+
+ /* Push direct block data through I/O filter pipeline */
+ nbytes = len;
+ filter_mask = udata->filter_mask;
+ if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &len, &read_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, NULL, "output pipeline failed")
+
+ /* Sanity check */
+ HDassert(nbytes == dblock->size);
+
+ /* Copy un-filtered data into block's buffer */
+ HDmemcpy(dblock->blk, read_buf, dblock->size);
+ } /* end if */
+ } /* end if */
+ else {
+ /* Sanity checks */
+ HDassert(udata->dblk == NULL);
+ HDassert(!udata->decompressed);
+
+ /* Allocate block buffer */
+/* XXX: Change to using free-list factories */
+ if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy image to dblock->blk */
+ HDassert(dblock->size == len);
+ HDmemcpy(dblock->blk, image, dblock->size);
+ } /* end else */
+
+ /* Start decoding direct block */
+ image = dblock->blk;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap direct block signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5HF_DBLOCK_VERSION)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version")
+
+ /* Address of heap that owns this block (just for file integrity checks) */
+ H5F_addr_decode(udata->f, &image, &heap_addr);
+ if(H5F_addr_ne(heap_addr, hdr->heap_addr))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block")
+
+ /* Address of parent block */
+ dblock->parent = par_info->iblock;
+ dblock->fd_parent = par_info->iblock;
+ dblock->par_entry = par_info->entry;
+ if(dblock->parent) {
+ /* Share parent block */
+ if(H5HF_iblock_incr(dblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
+ } /* end if */
+
+ /* Offset of heap within the heap's address space */
+ UINT64DECODE_VAR(image, dblock->block_off, hdr->heap_off_size);
+
+ /* Decode checksum on direct block, if requested */
+ if(hdr->checksum_dblocks) {
+ uint32_t stored_chksum; /* Metadata checksum value */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+ } /* end if */
+
+ /* Sanity check */
+ HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr));
+
+ /* Set return value */
+ ret_value = (void *)dblock;
+
+done:
+ /* Release the read buffer */
+ if(read_buf)
+ H5MM_xfree(read_buf);
+
+ /* Cleanup on error */
+ if(!ret_value && dblock)
+ if(H5HF_man_dblock_dest(dblock) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_image_len
+ *
+ * Purpose: Report the actual size of the direct block image on disk.
+ * Note that this value will probably be incorrect if compression
+ * is enabled and the entry is dirty.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HF_direct_t *dblock = (const H5HF_direct_t *)_thing; /* Direct block info */
+ const H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ size_t size;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK);
+ HDassert(image_len);
+
+ /* Set up convenience variables */
+ hdr = dblock->hdr;
+ HDassert(hdr);
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /*
+ * If the data is available, set to the compressed
+ * size of the direct block -- otherwise set it equal to the
+ * uncompressed size.
+ *
+ * We have three possible scenarios here.
+ *
+ * First, the block may never have been flushed. In this
+ * case, both dblock->file_size and the size stored in the
+ * parent (either the header or the parent iblock) will all
+ * be zero. In this case, return the uncompressed size
+ * stored in dblock->size as the size.
+ *
+ * Second, the block may have just been serialized, in which
+ * case, dblock->file_size should be zero, and the correct
+ * on disk size should be stored in the parent (again, either
+ * the header or the parent iblock as case may be).
+ *
+ * Third, we may be in the process of discarding this
+ * dblock without writing it. In this case, dblock->file_size
+ * should be non-zero and have the correct size. Note that
+ * in this case, the direct block will have been detached,
+ * and thus looking up the parent will likely return incorrect
+ * data.
+ */
+ if(dblock->file_size != 0)
+ size = dblock->file_size;
+ else {
+ const H5HF_indirect_t *par_iblock = dblock->parent; /* Parent iblock */
+
+ if(par_iblock)
+ size = par_iblock->filt_ents[dblock->par_entry].size;
+ else
+ size = hdr->pline_root_direct_size;
+
+ if(size == 0)
+ size = dblock->size;
+ } /* end else */
+ } /* end if */
+ else
+ size = dblock->size;
+
+ /* Set the image size */
+ HDassert(size > 0);
+ *image_len = size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF__cache_dblock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_pre_serialize
+ *
+ * Purpose: In principle, the purpose of this function is to determine
+ * the size and location of the disk image of the target direct
+ * block. In this case, the uncompressed size of the block is
+ * fixed, but since the direct block could be compressed,
+ * we may need to compute and report the compressed size.
+ *
+ * This is a bit sticky in the case of a direct block when I/O
+ * filters are enabled, as the size of the compressed version
+ * of the on disk image is not known until the direct block has
+ * been run through the filters. Further, the location of the
+ * on disk image may change if the compressed size of the image
+ * changes as well.
+ *
+ * To complicate matters further, the direct block may have been
+ * initially allocated in temporary (AKA imaginary) file space.
+ * In this case, we must relocate the direct block's on-disk
+ * image to "real" file space regardless of whether it has changed
+ * size.
+ *
+ * One simplifying factor is the direct block's "blk" field,
+ * which contains a pointer to a buffer which (with the exception
+ * of a small header) contains the on disk image in uncompressed
+ * form.
+ *
+ * To square this particular circle, this function does
+ * everything the serialize function usually does, with the
+ * exception of copying the image into the image buffer provided
+ * to the serialize function by the metadata cache. The data to
+ * copy is provided to the serialize function in a buffer pointed
+ * to by the write_buf field.
+ *
+ * If I/O filters are enabled, on exit,
+ * H5HF__cache_dblock_pre_serialize() sets the write_buf field to
+ * point to a buffer containing the filtered image of the direct
+ * block. The serialize function should free this block, and set
+ * the write_buf field to NULL after copying it into the image
+ * buffer provided by the metadata cache.
+ *
+ * If I/O filters are not enabled, this function prepares
+ * the buffer pointed to by the blk field for copying to the
+ * image buffer provided by the metadata cache, and sets the
+ * write_buf field equal to the blk field. In this case, the
+ * serialize function should simply set the write_buf field to
+ * NULL after copying the direct block image into the image
+ * buffer.
+ *
+ * In both of the above cases, the length of the buffer pointed
+ * to by write_buf is provided in the write_len field. This
+ * field must contain 0 on entry to this function, and should
+ * be set back to 0 at the end of the serialize function.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_pre_serialize(H5F_t *f, hid_t dxpl_id, void *_thing,
+ haddr_t addr, size_t len, haddr_t *new_addr, size_t *new_len, unsigned *flags)
+{
+ hbool_t at_tmp_addr; /* Flag to indicate direct block is */
+ /* at temporary address */
+ haddr_t dblock_addr;
+ H5HF_hdr_t *hdr; /* Shared fractal heap information */
+ H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */
+ H5HF_indirect_t *par_iblock; /* Parent indirect block */
+ unsigned par_entry = 0; /* Entry in parent indirect block */
+ void *write_buf; /* Pointer to buffer to write out */
+ size_t write_size; /* Size of buffer to write out */
+ uint8_t *image; /* Pointer into raw data buffer */
+ unsigned dblock_flags = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK);
+ HDassert(dblock->write_buf == NULL);
+ HDassert(dblock->write_size == 0);
+ HDassert(dblock->cache_info.size == len);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(new_addr);
+ HDassert(new_len);
+ HDassert(flags);
+
+ /* Set up local variables */
+ hdr = dblock->hdr;
+ dblock_addr = addr; /* will update dblock_addr if we move the block */
+
+ /* Set the shared heap header's file context for this operation */
+ hdr->f = (H5F_t *)f;
+
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+
+ if(dblock->parent) {
+ /* this is the common case, in which the direct block is the child
+ * of an indirect block. Set up the convenience variables we will
+ * need if the address and/or compressed size of the on disk image
+ * of the direct block changes, and do some sanity checking in
+ * passing.
+ */
+ par_iblock = dblock->parent;
+ par_entry = dblock->par_entry;
+
+ HDassert(par_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(par_iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr));
+ } /* end if */
+ else {
+ /* the direct block is a root direct block -- just set par_iblock
+ * to NULL, as the field will not be used.
+ */
+ par_iblock = NULL;
+ } /* end else */
+
+ at_tmp_addr = H5F_IS_TMP_ADDR(f, addr);
+
+ /* Begin by preping the direct block to be written to disk. Do
+ * this by writing the correct magic number, the dblock version,
+ * the address of the header, the offset of the block in the heap,
+ * and the checksum at the beginning of the block.
+ */
+
+ HDassert(dblock->blk);
+ image = dblock->blk;
+
+ /* Magic number */
+ HDmemcpy(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5HF_DBLOCK_VERSION;
+
+ /* Address of heap header for heap which owns this block */
+ H5F_addr_encode(f, &image, hdr->heap_addr);
+
+ /* Offset of block in heap */
+ UINT64ENCODE_VAR(image, dblock->block_off, hdr->heap_off_size);
+
+ /* Metadata checksum */
+ if(hdr->checksum_dblocks) {
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ /* Clear the checksum field, to compute the checksum */
+ HDmemset(image, 0, (size_t)H5HF_SIZEOF_CHKSUM);
+
+ /* Compute checksum on entire direct block */
+ metadata_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+ } /* end if */
+
+ /* at this point, dblock->blk should point to an uncompressed image of
+ * the direct block. If I/O filters are not enabled, this image should
+ * be ready to hand off to the metadata cache.
+ */
+
+ /* Sanity check */
+ HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr));
+
+ /* If I/O filters are enabled on this heap, we must run the direct block
+ * image through the filters to obtain the image that we will hand off
+ * to the metadata cache.
+ */
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */
+ size_t nbytes; /* Number of bytes used */
+ unsigned filter_mask = 0; /* Filter mask for block */
+
+ /* Allocate buffer to perform I/O filtering on */
+ write_size = dblock->size;
+ if(NULL == (write_buf = H5MM_malloc(write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer")
+
+ /* Copy the direct block's image into the buffer to compress */
+ HDmemcpy(write_buf, dblock->blk, write_size);
+
+ /* Push direct block data through I/O filter pipeline */
+ nbytes = write_size;
+ if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &write_size, &write_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "output pipeline failed")
+
+ /* Use the compressed number of bytes as the size to write */
+ write_size = nbytes;
+
+ /* If the size and/or location of the on disk image of the
+ * direct block changes, we must touch up its parent to reflect
+ * these changes. Do this differently depending on whether the
+ * direct block's parent is an indirect block or (rarely) the
+ * fractal heap header. In this case, the direct block is known
+ * as a root direct block.
+ */
+
+ /* Check for root direct block */
+ if(dblock->parent == NULL) {
+ hbool_t hdr_changed = FALSE; /* Whether the header info changed */
+
+ /* Sanity check */
+ HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr));
+ HDassert(hdr->pline_root_direct_size > 0);
+
+ /* Check if the filter mask changed */
+ if(hdr->pline_root_direct_filter_mask != filter_mask) {
+ hdr->pline_root_direct_filter_mask = filter_mask;
+ hdr_changed = TRUE;
+ } /* end if */
+
+ /* verify that the cache's last record of the compressed
+ * size matches the heap's last record. This value will
+ * likely change shortly.
+ */
+ HDassert(len == hdr->pline_root_direct_size);
+
+ /* Check if we need to re-size the block on disk */
+ if(hdr->pline_root_direct_size != write_size || at_tmp_addr) {
+ /* Check if the direct block is NOT currently allocated
+ * in temp. file space
+ *
+ * (temp. file space does not need to be freed)
+ */
+ if(!at_tmp_addr)
+ /* Release direct block's current disk space */
+ if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)hdr->pline_root_direct_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block")
+
+ /* Allocate space for the compressed direct block */
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+
+ /* Update information about compressed direct block's
+ * location & size
+ */
+ HDassert(hdr->man_dtable.table_addr == addr);
+ HDassert(hdr->pline_root_direct_size == len);
+ hdr->man_dtable.table_addr = dblock_addr;
+ hdr->pline_root_direct_size = write_size;
+
+ /* Note that heap header was modified */
+ hdr_changed = TRUE;
+ } /* end if */
+
+ /* Check if heap header was modified */
+ if(hdr_changed)
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end if */
+ else { /* the direct block's parent is an indirect block */
+ hbool_t par_changed = FALSE; /* Whether the parent's infochanged */
+
+ /* Sanity check */
+ HDassert(par_iblock);
+ HDassert(par_iblock->filt_ents[par_entry].size > 0);
+
+ /* Check if the filter mask changed */
+ if(par_iblock->filt_ents[par_entry].filter_mask != filter_mask) {
+ par_iblock->filt_ents[par_entry].filter_mask = filter_mask;
+ par_changed = TRUE;
+ } /* end if */
+
+ /* verify that the cache's last record of the compressed
+ * size matches the heap's last record. This value will
+ * likely change shortly.
+ */
+ HDassert(len == par_iblock->filt_ents[par_entry].size);
+
+ /* Check if we need to re-size the block on disk */
+ if(par_iblock->filt_ents[par_entry].size != write_size || at_tmp_addr) {
+ /* Check if the direct block is NOT currently allocated
+ * in temp. file space
+ *
+ * (temp. file space does not need to be freed)
+ */
+ if(!at_tmp_addr)
+ /* Release direct block's current disk space */
+ if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)par_iblock->filt_ents[par_entry].size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block")
+
+ /* Allocate space for the compressed direct block */
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+
+ /* Update information about compressed direct block's
+ * location & size
+ */
+ HDassert(par_iblock->ents[par_entry].addr == addr);
+ HDassert(par_iblock->filt_ents[par_entry].size == len);
+ par_iblock->ents[par_entry].addr = dblock_addr;
+ par_iblock->filt_ents[par_entry].size = write_size;
+
+ /* Note that parent was modified */
+ par_changed = TRUE;
+ } /* end if */
+
+ /* Check if parent was modified */
+ if(par_changed)
+ if(H5HF_iblock_dirty(par_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end else */
+ } /* end if */
+ else {
+ /* I/O filters are not enabled -- thus all we need to do is check to
+ * see if the direct block is in temporary (AKA imaginary) file
+ * space, and move it to real file space if it is.
+ *
+ * As in the I/O filters case above, we will have to touch up the
+ * direct blocks parent if the direct block is relocated.
+ *
+ * Recall that temporary file space need not be freed, which
+ * simplifies matters slightly.
+ */
+ write_buf = dblock->blk;
+ write_size = dblock->size;
+
+ /* Check to see if we must re-allocate direct block from 'temp.'
+ * to 'normal' file space
+ */
+ if(at_tmp_addr) {
+ /* Allocate 'normal' space for the direct block */
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+
+ /* Check for root direct block */
+ if(NULL == dblock->parent) {
+ /* Sanity checks */
+ HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr));
+ HDassert(!H5F_addr_eq(hdr->man_dtable.table_addr, dblock_addr));
+
+ /* Update information about direct block's location */
+ hdr->man_dtable.table_addr = dblock_addr;
+
+ /* Mark that heap header was modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end if */
+ else { /* the direct block's parent is an indirect block */
+ /* Sanity checks */
+ HDassert(par_iblock);
+ HDassert(par_iblock->ents);
+ HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr));
+ HDassert(!H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr));
+
+ /* Update information about direct block's location */
+ par_iblock->ents[par_entry].addr = dblock_addr;
+
+ /* Mark that parent was modified */
+ if(H5HF_iblock_dirty(par_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end else */
+ } /* end if */
+ } /* end else */
+
+ /* At this point, write_buf points to a buffer containing the image
+ * of the direct block that is ready to copy into the image buffer,
+ * and write_size contains the length of this buffer.
+ *
+ * Also, if image size or address has changed, the direct block's
+ * parent has been modified to reflect the change.
+ *
+ * Now, make note of the pointer and length of the above buffer for
+ * use by the serialize function.
+ */
+ dblock->write_buf = (uint8_t *)write_buf;
+ dblock->write_size = write_size;
+
+ /* finally, pass data back to the metadata cache as appropriate */
+ if(!H5F_addr_eq(addr, dblock_addr)) {
+ dblock_flags |= H5AC__SERIALIZE_MOVED_FLAG;
+ *new_addr = dblock_addr;
+ } /* end if */
+
+ if((hdr->filter_len > 0) && (len != write_size)) {
+ dblock_flags |= H5AC__SERIALIZE_RESIZED_FLAG;
+ *new_len = write_size;
+ } /* end if */
+
+ *flags = dblock_flags;
+
+ /* final sanity check */
+ HDassert(dblock->write_buf);
+ HDassert(dblock->write_size > 0);
+
+done:
+ /* discard the write buf if we have an error */
+ if(write_buf && (write_buf != dblock->blk) && (dblock->write_buf == NULL))
+ H5MM_xfree(write_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_pre_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_serialize
+ *
+ * Purpose: In principle, this function is supposed to construct the on
+ * disk image of the direct block, and place that image in the
+ * image buffer provided by the metadata cache.
+ *
+ * However, since there are cases in which the pre_serialize
+ * function has to construct the on disk image to determine its size
+ * and address, this function simply copies the image prepared by
+ * the pre-serialize function into the supplied image buffer, and
+ * discards a buffer if necessary.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_serialize(const H5F_t *f, void *image, size_t len,
+ void *_thing)
+{
+ H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK);
+ HDassert((dblock->blk != dblock->write_buf) || (dblock->cache_info.size == dblock->size));
+ HDassert(dblock->write_buf);
+ HDassert(dblock->write_size > 0);
+ HDassert((dblock->blk != dblock->write_buf) || (dblock->write_size == dblock->size));
+ HDassert(dblock->write_size == len);
+
+ /* Copy the image from *(dblock->write_buf) to *image */
+ HDmemcpy(image, dblock->write_buf, dblock->write_size);
+
+ /* Free *(dblock->write_buf) if it was allocated by the
+ * pre-serialize function
+ */
+ if(dblock->write_buf != dblock->blk)
+ H5MM_xfree(dblock->write_buf);
+
+ /* Reset the write_buf and write_size fields */
+ dblock->write_buf = NULL;
+ dblock->write_size = 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_notify
+ *
+ * Purpose: Setup / takedown flush dependencies as direct blocks
+ * are loaded / inserted and evicted from the metadata cache.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK);
+ HDassert(dblock->hdr);
+ HDassert((dblock->fd_parent) ||
+ ((dblock->hdr->man_dtable.curr_root_rows == 0) && (dblock->block_off == (hsize_t)0)));
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ HDassert(dblock->parent == dblock->fd_parent);
+ if(dblock->parent) { /* this is a leaf dblock */
+ /* create flush dependency with parent iblock */
+ if(H5AC_create_flush_dependency(dblock->parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end if */
+ else { /* this is a root dblock */
+ /* create flush dependency with header */
+ if(H5AC_create_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ } /* end else */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ HDassert((dblock->parent == dblock->fd_parent) ||
+ ((NULL == dblock->parent) && (dblock->fd_parent)));
+ if(dblock->fd_parent) { /* this is a leaf dblock */
+ /* destroy flush dependency with parent iblock */
+ if(H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ } /* end if */
+ else { /* this is a root dblock */
+ /* destroy flush dependency with header */
+ if(H5AC_destroy_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ } /* end else */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__cache_dblock_free_icr
+ *
+ * Purpose: Free the in core memory allocated to the supplied direct
+ * block.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF__cache_dblock_free_icr(void *_thing)
+{
+ H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(dblock);
+ HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK);
+
+ /* Destroy fractal heap direct block */
+ if(H5HF_man_dblock_dest(dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__cache_dblock_free_icr() */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF__cache_verify_hdr_descendants_clean
+ *
+ * Purpose: Sanity checking routine that verifies that all indirect
+ * and direct blocks that are descendants of the supplied
+ * instance of H5HF_hdr_t are clean. Set *clean to
+ * TRUE if this is the case, and to FALSE otherwise.
+ *
+ * Update -- 8/24/15
+ *
+ * With the advent of the metadata cache image feature, it is
+ * possible for the pre-serialize and serialize calls to be
+ * invoked outside of a flush. While this serialization
+ * observes flush dependencies for the order of serialization,
+ * the entries are not written to disk, and hence dirty entries
+ * remain dirty.
+ *
+ * To address this, updated the sanity checks in this function
+ * to treat entries whose images are up to date as clean if
+ * a cache serialization is in progress.
+ *
+ * Update -- 9/29/16
+ *
+ * The implementation of flush dependencies has been changed.
+ * Prior to this change, a flush dependency parent could be
+ * flushed if and only if all its flush dependency decendants
+ * were clean. In the new definition, a flush dependency
+ * parent can be flushed if all its immediate flush dependency
+ * children are clean, regardless of any other dirty
+ * decendants.
+ *
+ * Further, metadata cache entries are now allowed to have
+ * multiple flush dependency parents.
+ *
+ * This means that the fractal heap is no longer ncessarily
+ * flushed from the bottom up.
+ *
+ * For example, it is now possible for a dirty fractal heap
+ * header to be flushed before a dirty dblock, as long as the
+ * there in an interviening iblock, and the header has no
+ * dirty immediate flush dependency children.
+ *
+ * Also, I gather that under some circumstances, a dblock
+ * will be direct a flush dependency child both of the iblock
+ * that points to it, and of the fractal heap header.
+ *
+ * As a result of these changes, the functionality of these
+ * sanity checking routines has been modified significantly.
+ * Instead of scanning the fractal heap from a starting point
+ * down, and verifying that there were no dirty entries, the
+ * functions now scan downward from the starting point and
+ * verify that there are no dirty flush dependency children
+ * of the specified flush dependency parent. In passing,
+ * they also walk the data structure, and verify it.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id,
+ H5HF_hdr_t *hdr, hbool_t *fd_clean, hbool_t *clean)
+{
+ hbool_t fd_exists = FALSE; /* whether flush dependency exists. */
+ haddr_t hdr_addr; /* Address of header */
+ unsigned hdr_status = 0; /* Header cache entry status */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(hdr);
+ HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR);
+ HDassert(fd_clean);
+ HDassert(clean);
+ hdr_addr = hdr->cache_info.addr;
+ HDassert(hdr_addr == hdr->heap_addr);
+
+ if(H5AC_get_entry_status(f, hdr_addr, &hdr_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get hdr status")
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+
+ /* We have three basic scenarios we have to deal with:
+ *
+ * The first, and most common case, is that there is a root iblock.
+ * In this case we need to verify that the root iblock and all its
+ * children are clean.
+ *
+ * The second, and much less common case, is that in which the
+ * the fractal heap contains only one direct block, which is
+ * pointed to by hdr->man_dtable.table_addr. In this case, all we
+ * need to do is verify that the root direct block is clean.
+ *
+ * Finally, it is possible that the fractal heap is empty, and
+ * has neither a root indirect block nor a root direct block.
+ * In this case, we have nothing to do.
+ */
+
+ /* There are two ways in which we can arrive at the first scenario.
+ *
+ * By far the most common is when hdr->root_iblock contains a pointer
+ * to the root iblock -- in this case the root iblock is almost certainly
+ * pinned, although we can't count on that.
+ *
+ * However, it is also possible that there is a root iblock that
+ * is no longer pointed to by the header. In this case, the on
+ * disk address of the iblock will be in hdr->man_dtable.table_addr
+ * and hdr->man_dtable.curr_root_rows will contain a positive value.
+ *
+ * Since the former case is far and away the most common, we don't
+ * worry too much about efficiency in the second case.
+ */
+ if(hdr->root_iblock ||
+ ((hdr->man_dtable.curr_root_rows > 0) &&
+ (HADDR_UNDEF != hdr->man_dtable.table_addr))) {
+ H5HF_indirect_t *root_iblock = hdr->root_iblock;
+ haddr_t root_iblock_addr;
+ unsigned root_iblock_status = 0;
+ hbool_t root_iblock_in_cache;
+
+ /* make note of the on disk address of the root iblock */
+ if(root_iblock == NULL)
+ /* hdr->man_dtable.table_addr must contain address of root
+ * iblock. Check to see if it is in cache. If it is,
+ * protect it and put its address in root_iblock.
+ */
+ root_iblock_addr = hdr->man_dtable.table_addr;
+ else
+ root_iblock_addr = root_iblock->addr;
+
+ /* get the status of the root iblock */
+ HDassert(root_iblock_addr != HADDR_UNDEF);
+ if(H5AC_get_entry_status(f, root_iblock_addr, &root_iblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get root iblock status")
+
+ root_iblock_in_cache = ( (root_iblock_status & H5AC_ES__IN_CACHE) != 0);
+ HDassert(root_iblock_in_cache || (root_iblock == NULL));
+
+ if(!root_iblock_in_cache) { /* we are done */
+ *clean = TRUE;
+ *fd_clean = TRUE;
+ } /* end if */
+ else if((root_iblock_status & H5AC_ES__IS_DIRTY) &&
+ (((root_iblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
+ (!H5AC_get_serialization_in_progress(f)))) {
+ *clean = FALSE;
+
+ /* verify that a flush dependency exists between the header and
+ * the root inode.
+ */
+ if(H5AC_flush_dependency_exists(f, hdr->heap_addr, root_iblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+ HDassert(fd_exists);
+
+ *fd_clean = FALSE;
+ } /* end else-if */
+ else { /* must examine children */
+ hbool_t unprotect_root_iblock = FALSE;
+
+ /* At this point, the root iblock may be pinned, protected,
+ * both, or neither, and we may or may not have a pointer
+ * to root iblock in memory.
+ *
+ * Before we call H5HF__cache_verify_iblock_descendants_clean(),
+ * we must ensure that the root iblock is either pinned or
+ * protected or both, and that we have a pointer to it.
+ * Do this as follows:
+ */
+ if(root_iblock == NULL) { /* we don't have ptr to root iblock */
+ if(0 == (root_iblock_status & H5AC_ES__IS_PROTECTED)) {
+ /* just protect the root iblock -- this will give us
+ * the pointer we need to proceed, and ensure that
+ * it is locked into the metadata cache for the
+ * duration.
+ *
+ * Note that the udata is only used in the load callback.
+ * While the fractal heap makes heavy use of the udata
+ * in this case, since we know that the entry is in cache,
+ * we can pass NULL udata.
+ *
+ * The tag specified in the dxpl we received
+ * as a parameter (via dxpl_id) may not be correct.
+ * Grab the (hopefully) correct tag from the header,
+ * and load it into the dxpl via the H5_BEGIN_TAG and
+ * H5_END_TAG macros. Note that any error bracked by
+ * these macros must be reported with HGOTO_ERROR_TAG.
+ */
+ H5_BEGIN_TAG(dxpl_id, hdr->heap_addr, FAIL)
+
+ if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
+
+ H5_END_TAG(FAIL)
+
+ unprotect_root_iblock = TRUE;
+ } /* end if */
+ else {
+ /* the root iblock is protected, and we have no
+ * legitimate way of getting a pointer to it.
+ *
+ * We square this circle by using the
+ * H5AC_get_entry_ptr_from_addr() to get the needed
+ * pointer.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided there when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Assuming that the flush dependency code is working
+ * as it should, the only reason for the root iblock to
+ * be unpinned is if none of its children are in cache.
+ * This unfortunately means that if it is protected and
+ * not pinned, the fractal heap is in the process of loading
+ * or inserting one of its children. The obvious
+ * implication is that there is a significant chance that
+ * the root iblock is in an unstable state.
+ *
+ * All this suggests that using
+ * H5AC_get_entry_ptr_from_addr() to obtain the pointer
+ * to the protected root iblock is questionable here.
+ * However, since this is test/debugging code, I expect
+ * that we will use this approach until it causes problems,
+ * or we think of a better way.
+ */
+ if(H5AC_get_entry_ptr_from_addr(f, root_iblock_addr, (void **)(&root_iblock)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "H5AC_get_entry_ptr_from_addr() failed.")
+ HDassert(root_iblock);
+ } /* end else */
+ } /* end if */
+ else { /* root_iblock != NULL */
+ /* we have the pointer to the root iblock. Protect it
+ * if it is neither pinned nor protected -- otherwise we
+ * are ready to go.
+ */
+ H5HF_indirect_t * iblock = NULL;
+
+ if(((root_iblock_status & H5AC_ES__IS_PINNED) == 0) &&
+ ((root_iblock_status & H5AC_ES__IS_PROTECTED) == 0)) {
+ /* the root iblock is neither pinned nor protected -- hence
+ * we must protect it before we proceed
+ *
+ * Note that the udata is only used in the load callback.
+ * While the fractal heap makes heavy use of the udata
+ * in this case, since we know that the entry is in cache,
+ * we can pass NULL udata.
+ *
+ * The tag associated specified in the dxpl we received
+ * as a parameter (via dxpl_id) may not be correct.
+ * Grab the (hopefully) correct tag from the header,
+ * and load it into the dxpl via the H5_BEGIN_TAG and
+ * H5_END_TAG macros. Note that any error bracked by
+ * these macros must be reported with HGOTO_ERROR_TAG.
+ */
+ H5_BEGIN_TAG(dxpl_id, hdr->heap_addr, FAIL)
+
+ if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
+
+ H5_END_TAG(FAIL)
+
+ unprotect_root_iblock = TRUE;
+ HDassert(iblock == root_iblock);
+ } /* end if */
+ } /* end else */
+
+ /* at this point, one way or another, the root iblock is locked
+ * in memory for the duration of the call. Do some sanity checks,
+ * and then call H5HF__cache_verify_iblock_descendants_clean().
+ */
+ HDassert(root_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(root_iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+
+ if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, hdr->heap_addr, root_iblock, &root_iblock_status, fd_clean, clean) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify root iblock & descendants clean.")
+
+ /* Unprotect the root indirect block if required */
+ if(unprotect_root_iblock) {
+ HDassert(root_iblock);
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, root_iblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "H5AC_unprotect() faild.")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else if((hdr->man_dtable.curr_root_rows == 0) &&
+ (HADDR_UNDEF != hdr->man_dtable.table_addr)) {
+ haddr_t root_dblock_addr;
+ unsigned root_dblock_status = 0;
+ hbool_t in_cache;
+ hbool_t type_ok;
+
+ /* this is scenario 2 -- we have a root dblock */
+ root_dblock_addr = hdr->man_dtable.table_addr;
+ if(H5AC_get_entry_status(f, root_dblock_addr, &root_dblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get root dblock status")
+
+ if(root_dblock_status & H5AC_ES__IN_CACHE) {
+ if(H5AC_verify_entry_type(f, root_dblock_addr, &H5AC_FHEAP_DBLOCK[0], &in_cache, &type_ok) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check dblock type")
+ HDassert(in_cache);
+ if(!type_ok)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "root dblock addr doesn't refer to a dblock?!?")
+
+ /* If a root dblock is in cache, it must have a flush
+ * dependency relationship with the header, and it
+ * may not be the parent in any flush dependency
+ * relationship.
+ *
+ * We don't test this fully, but we will verify that
+ * the root iblock is a child in a flush dependency
+ * relationship with the header.
+ */
+ if(H5AC_flush_dependency_exists(f, hdr->heap_addr, root_dblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+ if(!fd_exists)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "root dblock is not a flush dep parent of header.")
+
+ if(0 != (root_dblock_status & H5AC_ES__IS_FLUSH_DEP_PARENT))
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "root dblock in cache and is a flush dep parent.")
+
+ *clean = !((root_dblock_status & H5AC_ES__IS_DIRTY) &&
+ (((root_dblock_status &
+ H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
+ (!H5AC_get_serialization_in_progress(f))));
+
+ *fd_clean = *clean;
+ } /* end if */
+ else { /* root dblock not in cache */
+ *fd_clean = TRUE;
+ *clean = TRUE;
+ } /* end else */
+ } /* end else-if */
+ else {
+ /* this is scenario 3 -- the fractal heap is empty, and we
+ * have nothing to do.
+ */
+ *fd_clean = TRUE;
+ *clean = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__cache_verify_hdr_descendants_clean() */
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF__cache_verify_iblock_descendants_clean
+ *
+ * Purpose: Sanity checking routine that verifies that all indirect
+ * and direct blocks that are decendents of the supplied
+ * instance of H5HF_indirect_t are clean. Set *clean
+ * to TRUE if this is the case, and to FALSE otherwise.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: At its top level call, this function is
+ * intended to be called from H5HF_cache_iblock_flush(),
+ * and thus presumes that the supplied indirect block
+ * is in cache. Any other use of this function and
+ * its descendants must insure that this assumption is
+ * met.
+ *
+ * Note that this function and
+ * H5HF__cache_verify_descendant_iblocks_clean() are
+ * recursive co-routines.
+ *
+ * Update -- 9/29/16
+ *
+ * The implementation of flush dependencies has been changed.
+ * Prior to this change, a flush dependency parent could be
+ * flushed if and only if all its flush dependency decendants
+ * were clean. In the new definition, a flush dependency
+ * parent can be flushed if all its immediate flush dependency
+ * children are clean, regardless of any other dirty
+ * decendants.
+ *
+ * Further, metadata cache entries are now allowed to have
+ * multiple flush dependency parents.
+ *
+ * This means that the fractal heap is no longer ncessarily
+ * flushed from the bottom up.
+ *
+ * For example, it is now possible for a dirty fractal heap
+ * header to be flushed before a dirty dblock, as long as the
+ * there in an interviening iblock, and the header has no
+ * dirty immediate flush dependency children.
+ *
+ * Also, I gather that under some circumstances, a dblock
+ * will be direct a flush dependency child both of the iblock
+ * that points to it, and of the fractal heap header.
+ *
+ * As a result of these changes, the functionality of these
+ * sanity checking routines has been modified significantly.
+ * Instead of scanning the fractal heap from a starting point
+ * down, and verifying that there were no dirty entries, the
+ * functions now scan downward from the starting point and
+ * verify that there are no dirty flush dependency children
+ * of the specified flush dependency parent. In passing,
+ * they also walk the data structure, and verify it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF__cache_verify_iblock_descendants_clean(H5F_t *f, hid_t dxpl_id,
+ haddr_t fd_parent_addr, H5HF_indirect_t *iblock, unsigned *iblock_status,
+ hbool_t * fd_clean, hbool_t *clean)
+{
+ hbool_t has_dblocks = FALSE;
+ hbool_t has_iblocks = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fd_parent_addr));
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(iblock_status);
+ HDassert(fd_clean);
+ HDassert(*fd_clean);
+ HDassert(clean); /* note that *clean need not be TRUE */
+
+ if((*fd_clean) && H5HF__cache_verify_iblocks_dblocks_clean(f, fd_parent_addr, iblock, fd_clean, clean, &has_dblocks) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify dblocks clean.")
+
+ if((*fd_clean) && H5HF__cache_verify_descendant_iblocks_clean(f, dxpl_id, fd_parent_addr, iblock, fd_clean, clean, &has_iblocks) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify iblocks clean.")
+
+ /* verify that flush dependency setup is plausible */
+ if(0 == (*iblock_status & H5AC_ES__IS_FLUSH_DEP_CHILD))
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "iblock is not a flush dep child.")
+ if(((has_dblocks || has_iblocks)) && (0 == (*iblock_status & H5AC_ES__IS_FLUSH_DEP_PARENT)))
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "iblock has children and is not a flush dep parent.")
+ if(((has_dblocks || has_iblocks)) && (0 == (*iblock_status & H5AC_ES__IS_PINNED)))
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "iblock has children and is not pinned.")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__cache_verify_iblock_descendants_clean() */
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF__cache_verify_iblocks_dblocks_clean
+ *
+ * Purpose: Sanity checking routine that attempts to verify that all
+ * direct blocks pointed to by the supplied indirect block
+ * are either clean, or not in the cache.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: This function presumes that the supplied
+ * iblock is in the cache, and will not be removed
+ * during the call. Caller must ensure that this is
+ * the case before the call.
+ *
+ * Update -- 8/24/15
+ *
+ * With the advent of the metadata cache image feature, it is
+ * possible for the pre-serialize and serialize calls to be
+ * invoked outside of a flush. While this serialization
+ * observes flush dependencies for the order of serialization,
+ * the entries are not written to disk, and hence dirty entries
+ * remain dirty.
+ *
+ * To address this, updated the sanity checks in this function
+ * to treat entries whose images are up to date as clean if
+ * a cache serialization is in progress.
+ *
+ * Update -- 9/29/16
+ *
+ * The implementation of flush dependencies has been changed.
+ * Prior to this change, a flush dependency parent could be
+ * flushed if and only if all its flush dependency decendants
+ * were clean. In the new definition, a flush dependency
+ * parent can be flushed if all its immediate flush dependency
+ * children are clean, regardless of any other dirty
+ * decendants.
+ *
+ * Further, metadata cache entries are now allowed to have
+ * multiple flush dependency parents.
+ *
+ * This means that the fractal heap is no longer ncessarily
+ * flushed from the bottom up.
+ *
+ * For example, it is now possible for a dirty fractal heap
+ * header to be flushed before a dirty dblock, as long as the
+ * there in an interviening iblock, and the header has no
+ * dirty immediate flush dependency children.
+ *
+ * Also, I gather that under some circumstances, a dblock
+ * will be direct a flush dependency child both of the iblock
+ * that points to it, and of the fractal heap header.
+ *
+ * As a result of these changes, the functionality of these
+ * sanity checking routines has been modified significantly.
+ * Instead of scanning the fractal heap from a starting point
+ * down, and verifying that there were no dirty entries, the
+ * functions now scan downward from the starting point and
+ * verify that there are no dirty flush dependency children
+ * of the specified flush dependency parent. In passing,
+ * they also walk the data structure, and verify it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF__cache_verify_iblocks_dblocks_clean(H5F_t *f, haddr_t fd_parent_addr,
+ H5HF_indirect_t *iblock, hbool_t *fd_clean, hbool_t *clean,
+ hbool_t *has_dblocks)
+{
+ unsigned num_direct_rows;
+ unsigned max_dblock_index;
+ unsigned i;
+ haddr_t iblock_addr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fd_parent_addr));
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(fd_clean);
+ HDassert(*fd_clean);
+ HDassert(clean); /* note that *clean need not be true */
+ HDassert(has_dblocks);
+
+ i = 0;
+ num_direct_rows = MIN(iblock->nrows, iblock->hdr->man_dtable.max_direct_rows);
+ HDassert(num_direct_rows <= iblock->nrows);
+ max_dblock_index = (num_direct_rows * iblock->hdr->man_dtable.cparam.width) - 1;
+ iblock_addr = iblock->addr;
+ HDassert(H5F_addr_defined(iblock_addr));
+
+ while((*fd_clean) && (i <= max_dblock_index)) {
+ haddr_t dblock_addr;
+
+ dblock_addr = iblock->ents[i].addr;
+ if(H5F_addr_defined(dblock_addr)) {
+ hbool_t in_cache;
+ hbool_t type_ok;
+
+ if(H5AC_verify_entry_type(f, dblock_addr, &H5AC_FHEAP_DBLOCK[0], &in_cache, &type_ok) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check dblock type")
+
+ if(in_cache) { /* dblock is in cache */
+ hbool_t fd_exists;
+ unsigned dblock_status = 0;
+
+ if(!type_ok)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "dblock addr doesn't refer to a dblock?!?")
+
+ if(H5AC_get_entry_status(f, dblock_addr, &dblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get dblock status")
+
+ HDassert(dblock_status & H5AC_ES__IN_CACHE);
+
+ *has_dblocks = TRUE;
+
+ if((dblock_status & H5AC_ES__IS_DIRTY) &&
+ (((dblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
+ (!H5AC_get_serialization_in_progress(f)))) {
+ *clean = FALSE;
+
+ if(H5AC_flush_dependency_exists(f, fd_parent_addr, dblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+
+ if(fd_exists)
+ *fd_clean = FALSE;
+ } /* end if */
+
+ /* If a child dblock is in cache, it must have a flush
+ * dependency relationship with this iblock. Test this
+ * here.
+ */
+ if(H5AC_flush_dependency_exists(f, iblock_addr, dblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+
+ if(!fd_exists)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "dblock in cache and not a flush dep child of iblock.")
+ } /* end if */
+ } /* end if */
+
+ i++;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__cache_verify_iblocks_dblocks_clean() */
+#endif /* NDEBUG */
+
+
+/*------------------------------------------------------------------------
+ * Function: H5HF__cache_verify_descendant_iblocks_clean
+ *
+ * Purpose: Sanity checking routine that attempts to verify that all
+ * direct blocks pointed to by the supplied indirect block
+ * are either clean, or not in the cache.
+ *
+ * In passing, the function also does a cursory check to
+ * spot any obvious errors in the flush dependency setup.
+ * If any problems are found, the function returns failure.
+ * Note that these checks are not exhaustive, thus passing
+ * them does not mean that the flush dependencies are
+ * correct -- only that there is nothing obviously wrong
+ * with them.
+ *
+ * WARNING: This function presumes that the supplied
+ * iblock is in the cache, and will not be removed
+ * during the call. Caller must ensure that this is
+ * the case before the call.
+ *
+ * Update -- 8/24/15
+ *
+ * With the advent of the metadata cache image feature, it is
+ * possible for the pre-serialize and serialize calls to be
+ * invoked outside of a flush. While this serialization
+ * observes flush dependencies for the order of serialization,
+ * the entries are not written to disk, and hence dirty entries
+ * remain dirty.
+ *
+ * To address this, updated the sanity checks in this function
+ * to treat entries whose images are up to date as clean if
+ * a cache serialization is in progress.
+ *
+ * Update -- 9/29/16
+ *
+ * The implementation of flush dependencies has been changed.
+ * Prior to this change, a flush dependency parent could be
+ * flushed if and only if all its flush dependency decendants
+ * were clean. In the new definition, a flush dependency
+ * parent can be flushed if all its immediate flush dependency
+ * children are clean, regardless of any other dirty
+ * decendants.
+ *
+ * Further, metadata cache entries are now allowed to have
+ * multiple flush dependency parents.
+ *
+ * This means that the fractal heap is no longer ncessarily
+ * flushed from the bottom up.
+ *
+ * For example, it is now possible for a dirty fractal heap
+ * header to be flushed before a dirty dblock, as long as the
+ * there in an interviening iblock, and the header has no
+ * dirty immediate flush dependency children.
+ *
+ * Also, I gather that under some circumstances, a dblock
+ * will be direct a flush dependency child both of the iblock
+ * that points to it, and of the fractal heap header.
+ *
+ * As a result of these changes, the functionality of these
+ * sanity checking routines has been modified significantly.
+ * Instead of scanning the fractal heap from a starting point
+ * down, and verifying that there were no dirty entries, the
+ * functions now scan downward from the starting point and
+ * verify that there are no dirty flush dependency children
+ * of the specified flush dependency parent. In passing,
+ * they also walk the data structure, and verify it.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/25/14
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NDEBUG
+static herr_t
+H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_id,
+ haddr_t fd_parent_addr, H5HF_indirect_t *iblock, hbool_t *fd_clean,
+ hbool_t *clean, hbool_t *has_iblocks)
+{
+ unsigned first_iblock_index;
+ unsigned last_iblock_index;
+ unsigned num_direct_rows;
+ unsigned i;
+ haddr_t iblock_addr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fd_parent_addr));
+ HDassert(iblock);
+ HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(fd_clean);
+ HDassert(*fd_clean);
+ HDassert(clean); /* note that *clean need not be true */
+ HDassert(has_iblocks);
+ num_direct_rows = MIN(iblock->nrows, iblock->hdr->man_dtable.max_direct_rows);
+ HDassert(num_direct_rows <= iblock->nrows);
+
+ iblock_addr = iblock->addr;
+ first_iblock_index = num_direct_rows * iblock->hdr->man_dtable.cparam.width;
+ last_iblock_index = (iblock->nrows * iblock->hdr->man_dtable.cparam.width) - 1;
+
+ i = first_iblock_index;
+ while((*fd_clean) && (i <= last_iblock_index)) {
+ haddr_t child_iblock_addr = iblock->ents[i].addr;
+
+ if(H5F_addr_defined(child_iblock_addr)) {
+ unsigned child_iblock_status = 0;
+
+ if(H5AC_get_entry_status(f, child_iblock_addr, &child_iblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status")
+
+ if(child_iblock_status & H5AC_ES__IN_CACHE) {
+ hbool_t fd_exists;
+
+ *has_iblocks = TRUE;
+
+ if((child_iblock_status & H5AC_ES__IS_DIRTY) &&
+ (((child_iblock_status & H5AC_ES__IMAGE_IS_UP_TO_DATE) == 0) ||
+ (!H5AC_get_serialization_in_progress(f)))) {
+
+ *clean = FALSE;
+
+ if(H5AC_flush_dependency_exists(f, fd_parent_addr, child_iblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+
+ if(fd_exists)
+ *fd_clean = FALSE;
+ } /* end if */
+
+ /* if the child iblock is in cache and *fd_clean is TRUE,
+ * we must continue to explore down the fractal heap tree
+ * structure to verify that all descendant blocks that are
+ * flush dependency children of the entry at parent_addr are
+ * either clean, or not in the metadata cache. We do this
+ * with a recursive call to
+ * H5HF__cache_verify_iblock_descendants_clean().
+ * However, we can't make this call unless the child iblock
+ * is somehow locked into the cache -- typically via either
+ * pinning or protecting.
+ *
+ * If the child iblock is pinned, we can look up its pointer
+ * on the current iblock's pinned child iblock list, and
+ * and use that pointer in the recursive call.
+ *
+ * If the entry is unprotected and unpinned, we simply
+ * protect it.
+ *
+ * If, however, the the child iblock is already protected,
+ * but not pinned, we have a bit of a problem, as we have
+ * no legitimate way of looking up its pointer in memory.
+ *
+ * To solve this problem, I have added a new metadata cache
+ * call to obtain the pointer.
+ *
+ * WARNING: This call should be used only in debugging
+ * routines, and it should be avoided there when
+ * possible.
+ *
+ * Further, if we ever multi-thread the cache,
+ * this routine will have to be either discarded
+ * or heavily re-worked.
+ *
+ * Finally, keep in mind that the entry whose
+ * pointer is obtained in this fashion may not
+ * be in a stable state.
+ *
+ * Assuming that the flush dependency code is working
+ * as it should, the only reason for the child entry to
+ * be unpinned is if none of its children are in cache.
+ * This unfortunately means that if it is protected and
+ * not pinned, the fractal heap is in the process of loading
+ * or inserting one of its children. The obvious implication
+ * is that there is a significant chance that the child
+ * iblock is in an unstable state.
+ *
+ * All this suggests that using the new call to obtain the
+ * pointer to the protected child iblock is questionable
+ * here. However, since this is test/debugging code, I
+ * expect that we will use this approach until it causes
+ * problems, or we think of a better way.
+ */
+ if(*fd_clean) {
+ H5HF_indirect_t *child_iblock = NULL;
+ hbool_t unprotect_child_iblock = FALSE;
+
+ if(0 == (child_iblock_status & H5AC_ES__IS_PINNED)) {
+ /* child iblock is not pinned */
+ if(0 == (child_iblock_status & H5AC_ES__IS_PROTECTED)) {
+ /* child iblock is unprotected, and unpinned */
+ /* protect it. Note that the udata is only */
+ /* used in the load callback. While the */
+ /* fractal heap makes heavy use of the udata */
+ /* in this case, since we know that the */
+ /* entry is in cache, we can pass NULL udata */
+ /* */
+ /* The tag associated specified in the dxpl */
+ /* we received as a parameter (via dxpl_id) */
+ /* may not be correct. */
+ /* */
+ /* Grab the (hopefully) correct tag from the */
+ /* parent iblock, and load it into the dxpl */
+ /* via the H5_BEGIN_TAG and H5_END_TAG */
+ /* macros. Note that any error bracked by */
+ /* these macros must be reported with */
+ /* HGOTO_ERROR_TAG. */
+
+ H5_BEGIN_TAG(dxpl_id, iblock->hdr->heap_addr, FAIL)
+
+ if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR_TAG(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.")
+
+ H5_END_TAG(FAIL)
+
+ unprotect_child_iblock = TRUE;
+ } /* end if */
+ else {
+ /* child iblock is protected -- use */
+ /* H5AC_get_entry_ptr_from_addr() to get a */
+ /* pointer to the entry. This is very slimy -- */
+ /* come up with a better solution. */
+ if(H5AC_get_entry_ptr_from_addr(f, child_iblock_addr, (void **)(&child_iblock)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "H5AC_get_entry_ptr_from_addr() faild.")
+ HDassert(child_iblock);
+ } /* end else */
+ } /* end if */
+ else {
+ /* child iblock is pinned -- look it up in the */
+ /* parent iblocks child_iblocks array. */
+ HDassert(iblock->child_iblocks);
+ child_iblock = iblock->child_iblocks[i - first_iblock_index];
+ } /* end else */
+
+ /* At this point, one way or another we should have
+ * a pointer to the child iblock. Verify that we
+ * that we have the correct one.
+ */
+ HDassert(child_iblock);
+ HDassert(child_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(child_iblock->cache_info.type == H5AC_FHEAP_IBLOCK);
+ HDassert(child_iblock->addr == child_iblock_addr);
+
+ /* now make the recursive call */
+ if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, fd_parent_addr, child_iblock, &child_iblock_status, fd_clean, clean) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify child iblock clean.")
+
+ /* if iblock_addr != fd_parent_addr, verify that a flush
+ * dependency relationship exists between iblock and
+ * the child iblock.
+ */
+ if(fd_parent_addr != iblock_addr) {
+ if(H5AC_flush_dependency_exists(f, iblock_addr, child_iblock_addr, &fd_exists) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't check flush dependency")
+
+ if(!fd_exists)
+ HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "iblock is not a flush dep parent of child_iblock.")
+ } /* end if */
+
+ /* if we protected the child iblock, unprotect it now */
+ if(unprotect_child_iblock) {
+ if(H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, child_iblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "H5AC_unprotect() faild.")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ i++;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF__cache_verify_descendant_iblocks_clean() */
+#endif /* NDEBUG */
+
diff --git a/src/H5HFdbg.c b/src/H5HFdbg.c
new file mode 100644
index 0000000..279de1e
--- /dev/null
+++ b/src/H5HFdbg.c
@@ -0,0 +1,932 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFdbg.c
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Dump debugging information about a fractal heap
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+#define H5HF_DEBUGGING /* Need access to fractal heap debugging routines */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for direct block debugging iterator callback */
+typedef struct {
+ FILE *stream; /* Stream for output */
+ int indent; /* Indention amount */
+ int fwidth; /* Field width mount */
+ haddr_t dblock_addr; /* Direct block's address */
+ hsize_t dblock_size; /* Direct block's size */
+ uint8_t *marker; /* 'Marker' array for free space */
+ size_t sect_count; /* Number of free space sections in block */
+ size_t amount_free; /* Amount of free space in block */
+} H5HF_debug_iter_ud1_t;
+
+/* User data for free space section iterator callback */
+typedef struct {
+ H5FS_t *fspace; /* Free space manager */
+ FILE *stream; /* Stream for output */
+ int indent; /* Indention amount */
+ int fwidth; /* Field width mount */
+} H5HF_debug_iter_ud2_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5HF_dtable_debug(const H5HF_dtable_t *dtable, FILE *stream,
+ int indent, int fwidth);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_id_print
+ *
+ * Purpose: Prints a fractal heap ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 20 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_id_print(H5HF_t *fh, hid_t dxpl_id, const void *_id, FILE *stream, int indent, int fwidth)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+ uint8_t id_flags; /* Heap ID flag bits */
+ hsize_t obj_off; /* Offset of object */
+ size_t obj_len; /* Length of object */
+ char id_type; /* Character for the type of heap ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(id);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Get the ID flags */
+ id_flags = *id;
+
+ /* Check for correct heap ID version */
+ if((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
+
+ /* Check type of object in heap */
+ if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
+ id_type = 'M';
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
+ id_type = 'H';
+ } /* end if */
+ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
+ id_type = 'T';
+ } /* end if */
+ else {
+HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
+ } /* end else */
+
+ /* Get the length of the heap object */
+ if(H5HF_get_obj_len(fh, dxpl_id, id, &obj_len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve heap ID length")
+
+ /* Get the offset of the heap object */
+ if(H5HF_get_obj_off(fh, dxpl_id, id, &obj_off) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve heap ID length")
+
+ /* Display the heap ID */
+ HDfprintf(stream, "%*s%-*s (%c, %Hu, %Zu)\n", indent, "", fwidth,
+ "Heap ID info: (type, offset, length)",
+ id_type, obj_off, obj_len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_id_print() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_debug
+ *
+ * Purpose: Prints debugging info about a doubling table
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 28 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_dtable_debug(const H5HF_dtable_t *dtable, FILE *stream, int indent, int fwidth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /*
+ * Print the values.
+ */
+ /* Creation parameter values */
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Doubling table width:",
+ dtable->cparam.width);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Starting block size:",
+ dtable->cparam.start_block_size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Max. direct block size:",
+ dtable->cparam.max_direct_size);
+ HDfprintf(stream, "%*s%-*s %u (bits)\n", indent, "", fwidth,
+ "Max. index size:",
+ dtable->cparam.max_index);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Starting # of rows in root indirect block:",
+ dtable->cparam.start_root_rows);
+
+ /* Run-time varying parameter values */
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Table's root address:",
+ dtable->table_addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Current # of rows in root indirect block:",
+ dtable->curr_root_rows);
+
+ /* Computed values */
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. # of rows in root indirect block:",
+ dtable->max_root_rows);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. # of direct rows in any indirect block:",
+ dtable->max_direct_rows);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "# of bits for IDs in first row:",
+ dtable->first_row_bits);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "# of IDs in first row:",
+ dtable->num_id_first_row);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_dtable_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_print
+ *
+ * Purpose: Prints info about a fractal heap header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 23 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5HF_hdr_print(const H5HF_hdr_t *hdr, hid_t dxpl_id, hbool_t dump_internal, FILE *stream, int indent, int fwidth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFractal Heap Header...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Heap is:",
+ hdr->man_dtable.curr_root_rows > 0 ? "Indirect" : "Direct");
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Objects stored in 'debugging' format:",
+ hdr->debug_objs);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "'Write once' flag:",
+ hdr->write_once);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "'Huge' object IDs have wrapped:",
+ hdr->huge_ids_wrapped);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Free space in managed blocks:",
+ hdr->total_man_free);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Managed space data block size:",
+ hdr->man_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Total managed space allocated:",
+ hdr->man_alloc_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Offset of managed space iterator:",
+ hdr->man_iter_off);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of managed objects in heap:",
+ hdr->man_nobjs);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of free space manager for managed blocks:",
+ hdr->fs_addr);
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Max. size of managed object:",
+ (unsigned long)hdr->max_man_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "'Huge' object space used:",
+ hdr->huge_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of 'huge' objects in heap:",
+ hdr->huge_nobjs);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "ID of next 'huge' object:",
+ hdr->huge_next_id);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of v2 B-tree for 'huge' objects:",
+ hdr->huge_bt2_addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "'Tiny' object space used:",
+ hdr->tiny_size);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of 'tiny' objects in heap:",
+ hdr->tiny_nobjs);
+
+ HDfprintf(stream, "%*sManaged Objects Doubling-Table Info...\n", indent, "");
+ H5HF_dtable_debug(&hdr->man_dtable, stream, indent + 3, MAX(0, fwidth - 3));
+
+ /* Print information about I/O filters */
+ if(hdr->filter_len > 0) {
+ HDfprintf(stream, "%*sI/O filter Info...\n", indent, "");
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Compressed size of root direct block:",
+ hdr->pline_root_direct_size);
+ HDfprintf(stream, "%*s%-*s %x\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Filter mask for root direct block:",
+ hdr->pline_root_direct_filter_mask);
+ } /* end if */
+ H5O_debug_id(H5O_PLINE_ID, hdr->f, dxpl_id, &(hdr->pline), stream,
+ indent + 3, MAX(0, fwidth - 3));
+ } /* end if */
+
+ /* Print internal (runtime) information, if requested */
+ if(dump_internal) {
+ HDfprintf(stream, "%*sFractal Heap Header Internal Information:\n", indent, "");
+
+ /* Dump root iblock, if there is one */
+ HDfprintf(stream, "%*s%-*s %x\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Root indirect block flags:",
+ hdr->root_iblock_flags);
+ HDfprintf(stream, "%*s%-*s %p\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Root indirect block pointer:",
+ hdr->root_iblock);
+ if(hdr->root_iblock)
+ H5HF_iblock_print(hdr->root_iblock, dump_internal, stream, indent + 3, fwidth);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5HF_hdr_print() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_debug
+ *
+ * Purpose: Prints debugging info about a fractal heap header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth)
+{
+ H5HF_hdr_t *hdr = NULL; /* Fractal heap header info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Load the fractal heap header */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /* Print the information about the heap's header */
+ H5HF_hdr_print(hdr, dxpl_id, FALSE, stream, indent, fwidth);
+
+done:
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dblock_debug_cb
+ *
+ * Purpose: Detect free space within a direct block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_dblock_debug_cb(H5FS_section_info_t *_sect, void *_udata)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
+ H5HF_debug_iter_ud1_t *udata = (H5HF_debug_iter_ud1_t *)_udata; /* User data for callbacks */
+ haddr_t sect_start, sect_end; /* Section's beginning and ending offsets */
+ haddr_t dblock_start, dblock_end; /* Direct block's beginning and ending offsets */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(udata);
+
+ /* Set up some local variables, for convenience */
+ sect_start = sect->sect_info.addr;
+ sect_end = (sect->sect_info.addr + sect->sect_info.size) - 1;
+ HDassert(sect_end >= sect_start);
+ dblock_start = udata->dblock_addr;
+ dblock_end = (udata->dblock_addr + udata->dblock_size) - 1;
+ HDassert(dblock_end >= dblock_start);
+
+ /* Check for overlap between free space section & direct block */
+ if((sect_start <= dblock_end && sect_end >=dblock_start) || /* section within or overlaps w/beginning of direct block*/
+ (sect_start <= dblock_end && sect_end >=dblock_end)) { /* section overlaps w/end of direct block */
+ char temp_str[32]; /* Temporary string for formatting */
+ size_t start, end; /* Start & end of the overlapping area */
+ size_t len; /* Length of the overlapping area */
+ size_t overlap; /* Track any overlaps */
+ size_t u; /* Local index variable */
+
+ /* Calculate the starting & ending */
+ if(sect_start < dblock_start)
+ start = 0;
+ else
+ H5_CHECKED_ASSIGN(start, size_t, (sect_start - dblock_start), hsize_t)
+ if(sect_end > dblock_end)
+ H5_CHECKED_ASSIGN(end, size_t, udata->dblock_size, hsize_t)
+ else
+ H5_CHECKED_ASSIGN(end, size_t, ((sect_end - dblock_start) + 1), hsize_t)
+
+ /* Calculate the length */
+ len = end - start;
+
+ HDsnprintf(temp_str, sizeof(temp_str), "Section #%u:", (unsigned)udata->sect_count);
+ HDfprintf(udata->stream, "%*s%-*s %8Zu, %8Zu\n", udata->indent + 3, "", MAX(0, udata->fwidth - 9),
+ temp_str,
+ start, len);
+ udata->sect_count++;
+
+ /* Mark this node's free space & check for overlaps w/other sections */
+ overlap = 0;
+ for(u = start; u < end; u++) {
+ if(udata->marker[u])
+ overlap++;
+ udata->marker[u] = 1;
+ } /* end for */
+
+ /* Flag overlaps */
+ if (overlap)
+ fprintf(udata->stream, "***THAT FREE BLOCK OVERLAPPED A PREVIOUS ONE!\n");
+ else
+ udata->amount_free += len;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_dblock_debug_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dblock_debug
+ *
+ * Purpose: Prints debugging info about a fractal heap direct block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 28 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream,
+ int indent, int fwidth, haddr_t hdr_addr, size_t block_size)
+{
+ H5HF_hdr_t *hdr = NULL; /* Fractal heap header info */
+ H5HF_direct_t *dblock = NULL; /* Fractal heap direct block info */
+ size_t blk_prefix_size; /* Size of prefix for block */
+ size_t amount_free; /* Amount of free space in block */
+ uint8_t *marker = NULL; /* Track free space for block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(block_size > 0);
+
+ /* Load the fractal heap header */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /*
+ * Load the heap direct block
+ */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, addr, block_size, NULL, 0, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap direct block")
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFractal Heap Direct Block...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of fractal heap that owns this block:",
+ hdr->heap_addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Offset of direct block in heap:",
+ dblock->block_off);
+ blk_prefix_size = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Size of block header:",
+ blk_prefix_size);
+
+ /* Allocate space for the free space markers */
+ if(NULL == (marker = (uint8_t *)H5MM_calloc(dblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the free space information for the heap */
+ if(H5HF_space_start(hdr, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
+
+ /* If there is a free space manager for the heap, check for sections that overlap this block */
+ if(hdr->fspace) {
+ H5HF_debug_iter_ud1_t udata; /* User data for callbacks */
+
+ /* Prepare user data for section iteration callback */
+ udata.stream = stream;
+ udata.indent = indent;
+ udata.fwidth = fwidth;
+ udata.dblock_addr = dblock->block_off;
+ udata.dblock_size = block_size;
+ udata.marker = marker;
+ udata.sect_count = 0;
+ udata.amount_free = 0;
+
+ /* Print header */
+ HDfprintf(stream, "%*sFree Blocks (offset, size):\n", indent, "");
+
+ /* Iterate over the free space sections, to detect overlaps with this block */
+ if(H5FS_sect_iterate(f, dxpl_id, hdr->fspace, H5HF_dblock_debug_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't iterate over heap's free space")
+
+ /* Close the free space information */
+ if(H5HF_space_close(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
+
+ /* Keep the amount of space free */
+ amount_free = udata.amount_free;
+
+ /* Check for no free space */
+ if(amount_free == 0)
+ HDfprintf(stream, "%*s<none>\n", indent + 3, "");
+ } /* end if */
+ else
+ amount_free = 0;
+
+ HDfprintf(stream, "%*s%-*s %.2f%%\n", indent, "", fwidth,
+ "Percent of available space for data used:",
+ ((double)100.0f * (double)((dblock->size - blk_prefix_size) - amount_free) / (double)(dblock->size - blk_prefix_size)));
+
+ /*
+ * Print the data in a VMS-style octal dump.
+ */
+ H5_buffer_dump(stream, indent, dblock->blk, marker, (size_t)0, dblock->size);
+
+done:
+ if(dblock && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_DBLOCK, addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap direct block")
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, hdr_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap header")
+ H5MM_xfree(marker);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_dblock_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_print
+ *
+ * Purpose: Prints debugging info about a fractal heap indirect block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 23 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5HF_iblock_print(const H5HF_indirect_t *iblock,
+ hbool_t dump_internal, FILE *stream, int indent, int fwidth)
+{
+ const H5HF_hdr_t *hdr; /* Pointer to heap's header */
+ char temp_str[64]; /* Temporary string, for formatting */
+ size_t u, v; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(iblock->hdr);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Set up convenience variables */
+ hdr = iblock->hdr;
+
+ /* Print opening message */
+ HDfprintf(stream, "%*sFractal Heap Indirect Block...\n", indent, "");
+
+ /*
+ * Print the values.
+ */
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of fractal heap that owns this block:",
+ hdr->heap_addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Offset of indirect block in heap:",
+ iblock->block_off);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Size of indirect block:",
+ iblock->size);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Current # of rows:",
+ iblock->nrows);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. # of rows:",
+ iblock->max_rows);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max direct block rows:",
+ hdr->man_dtable.max_direct_rows);
+
+ /* Print the entry tables */
+ if(hdr->filter_len > 0)
+ HDfprintf(stream, "%*sDirect Block Entries: (address/compressed size/filter mask)\n", indent, "");
+ else
+ HDfprintf(stream, "%*sDirect Block Entries: (address)\n", indent, "");
+ for(u = 0; u < hdr->man_dtable.max_direct_rows && u < iblock->nrows; u++) {
+ HDsnprintf(temp_str, sizeof(temp_str), "Row #%u: (block size: %lu)", (unsigned)u, (unsigned long)hdr->man_dtable.row_block_size[u]);
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str);
+ for(v = 0; v < hdr->man_dtable.cparam.width; v++) {
+ size_t off = (u * hdr->man_dtable.cparam.width) + v;
+
+ HDsnprintf(temp_str, sizeof(temp_str), "Col #%u:", (unsigned)v);
+ if(hdr->filter_len > 0)
+ HDfprintf(stream, "%*s%-*s %9a/%6Zu/%x\n", indent + 6, "", MAX(0, fwidth - 6),
+ temp_str,
+ iblock->ents[off].addr,
+ iblock->filt_ents[off].size,
+ iblock->filt_ents[off].filter_mask);
+ else
+ HDfprintf(stream, "%*s%-*s %9a\n", indent + 6, "", MAX(0, fwidth - 6),
+ temp_str,
+ iblock->ents[off].addr);
+ } /* end for */
+ } /* end for */
+ HDfprintf(stream, "%*sIndirect Block Entries:\n", indent, "");
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned first_row_bits; /* Number of bits used bit addresses in first row */
+ unsigned num_indirect_rows; /* Number of rows of blocks in each indirect block */
+
+ first_row_bits = H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size) +
+ H5VM_log2_of2(hdr->man_dtable.cparam.width);
+ for(u = hdr->man_dtable.max_direct_rows; u < iblock->nrows; u++) {
+ num_indirect_rows = (H5VM_log2_gen(hdr->man_dtable.row_block_size[u]) - first_row_bits) + 1;
+ HDsnprintf(temp_str, sizeof(temp_str), "Row #%u: (# of rows: %u)", (unsigned)u, num_indirect_rows);
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ temp_str);
+ for(v = 0; v < hdr->man_dtable.cparam.width; v++) {
+ size_t off = (u * hdr->man_dtable.cparam.width) + v;
+
+ HDsnprintf(temp_str, sizeof(temp_str), "Col #%u:", (unsigned)v);
+ HDfprintf(stream, "%*s%-*s %9a\n", indent + 6, "", MAX(0, fwidth - 6),
+ temp_str,
+ iblock->ents[off].addr);
+ } /* end for */
+ } /* end for */
+ } /* end if */
+ else
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ "<none>");
+
+ /* Print internal (runtime) information, if requested */
+ if(dump_internal) {
+ HDfprintf(stream, "%*sFractal Indirect Block Internal Information:\n", indent, "");
+
+ /* Print general information */
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Reference count:",
+ iblock->rc);
+
+ /* Print parent's information */
+ HDfprintf(stream, "%*s%-*s %p\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Parent indirect block address:",
+ iblock->parent);
+ if(iblock->parent)
+ H5HF_iblock_print(iblock->parent, TRUE, stream, indent + 6, fwidth);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5HF_iblock_print() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_debug
+ *
+ * Purpose: Prints debugging info about a fractal heap indirect block.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream,
+ int indent, int fwidth, haddr_t hdr_addr, unsigned nrows)
+{
+ H5HF_hdr_t *hdr = NULL; /* Fractal heap header info */
+ H5HF_indirect_t *iblock = NULL; /* Fractal heap direct block info */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+ HDassert(H5F_addr_defined(hdr_addr));
+ HDassert(nrows > 0);
+
+ /* Load the fractal heap header */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /*
+ * Load the heap indirect block
+ */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, addr, nrows, NULL, 0, FALSE, H5AC__READ_ONLY_FLAG, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap indirect block")
+
+ /* Print the information about the heap's indirect block */
+ H5HF_iblock_print(iblock, FALSE, stream, indent, fwidth);
+
+done:
+ if(iblock && H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap direct block")
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, hdr_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sects_debug_cb
+ *
+ * Purpose: Prints debugging info about a free space section for a fractal heap.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sects_debug_cb(H5FS_section_info_t *_sect, void *_udata)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
+ H5HF_debug_iter_ud2_t *udata = (H5HF_debug_iter_ud2_t *)_udata; /* User data for callbacks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(udata);
+
+ /* Print generic section information */
+ HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth,
+ "Section type:",
+ (sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE ? "single" :
+ (sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ? "first row" :
+ (sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW ? "normal row" : "unknown"))));
+ HDfprintf(udata->stream, "%*s%-*s %a\n", udata->indent, "", udata->fwidth,
+ "Section address:",
+ sect->sect_info.addr);
+ HDfprintf(udata->stream, "%*s%-*s %Hu\n", udata->indent, "", udata->fwidth,
+ "Section size:",
+ sect->sect_info.size);
+#ifdef QAK
+ HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth,
+ "Section state:",
+ (sect->sect_info.state == H5FS_SECT_LIVE ? "live" : "serialized"));
+#endif /* QAK */
+
+ /* Dump section-specific debugging information */
+ if(H5FS_sect_debug(udata->fspace, _sect, udata->stream, udata->indent + 3, MAX(0, udata->fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't dump section's debugging info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sects_debug_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sects_debug
+ *
+ * Purpose: Prints debugging info about free space sections for a fractal heap.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr,
+ FILE *stream, int indent, int fwidth)
+{
+ H5HF_hdr_t *hdr = NULL; /* Fractal heap header info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(fh_addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Load the fractal heap header */
+ if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
+
+ /* Initialize the free space information for the heap */
+ if(H5HF_space_start(hdr, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
+
+ /* If there is a free space manager for the heap, iterate over them */
+ if(hdr->fspace) {
+ H5HF_debug_iter_ud2_t udata; /* User data for callbacks */
+
+ /* Prepare user data for section iteration callback */
+ udata.fspace = hdr->fspace;
+ udata.stream = stream;
+ udata.indent = indent;
+ udata.fwidth = fwidth;
+
+ /* Iterate over all the free space sections */
+ if(H5FS_sect_iterate(f, dxpl_id, hdr->fspace, H5HF_sects_debug_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't iterate over heap's free space")
+
+ /* Close the free space information */
+ if(H5HF_space_close(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
+ } /* end if */
+
+done:
+ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sects_debug() */
+
diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c
new file mode 100644
index 0000000..4496962
--- /dev/null
+++ b/src/H5HFdblock.c
@@ -0,0 +1,730 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFdblock.c
+ * Apr 10 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Direct block routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5HF_direct_t struct */
+H5FL_DEFINE(H5HF_direct_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_create
+ *
+ * Purpose: Allocate & initialize a managed direct block
+ *
+ * Return: Pointer to new direct block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblock,
+ unsigned par_entry, haddr_t *addr_p, H5HF_free_section_t **ret_sec_node)
+{
+ H5HF_free_section_t *sec_node; /* Pointer to free space section for block */
+ H5HF_direct_t *dblock = NULL; /* Pointer to direct block */
+ haddr_t dblock_addr; /* Direct block's address */
+ size_t free_space; /* Free space in new block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /*
+ * Allocate file and memory data structures.
+ */
+ if(NULL == (dblock = H5FL_MALLOC(H5HF_direct_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fractal heap direct block")
+
+ /* Reset the metadata cache info for the heap header */
+ HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Share common heap information */
+ dblock->hdr = hdr;
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
+
+ /* Set info for direct block */
+ if(par_iblock) {
+ unsigned par_row = par_entry / hdr->man_dtable.cparam.width; /* Row for block */
+
+ /* Compute offset & size, based on parent's information */
+ dblock->block_off = par_iblock->block_off;
+ dblock->block_off += hdr->man_dtable.row_block_off[par_row];
+ dblock->block_off += hdr->man_dtable.row_block_size[par_row] * (par_entry % hdr->man_dtable.cparam.width);
+ H5_CHECKED_ASSIGN(dblock->size, size_t, hdr->man_dtable.row_block_size[par_row], hsize_t);
+ } /* end if */
+ else {
+ /* Must be the root direct block */
+ dblock->block_off = 0;
+ dblock->size = hdr->man_dtable.cparam.start_block_size;
+ } /* end else */
+ dblock->file_size = 0;
+ free_space = dblock->size - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+
+ /* Allocate buffer for block */
+/* XXX: Change to using free-list factories */
+ if((dblock->blk = H5FL_BLK_MALLOC(direct_block, dblock->size)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDmemset(dblock->blk, 0, dblock->size);
+
+ dblock->write_buf = NULL;
+ dblock->write_size = 0;
+
+ /* Allocate [temporary] space for the direct block on disk */
+ if(H5F_USE_TMP_SPACE(hdr->f)) {
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)dblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+ } /* end if */
+ else {
+ if(HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)dblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+ } /* end else */
+
+ /* Attach to parent indirect block, if there is one */
+ dblock->parent = par_iblock;
+ dblock->fd_parent = par_iblock;
+ if(dblock->parent)
+ if(H5HF_man_iblock_attach(dblock->parent, par_entry, dblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach direct block to parent indirect block")
+ dblock->par_entry = par_entry;
+
+ /* Create a new 'single' section for the free space in the block */
+ if(NULL == (sec_node = H5HF_sect_single_new((dblock->block_off + H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)),
+ free_space, dblock->parent, dblock->par_entry)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for new direct block's free space")
+
+ /* Check what to do with section node */
+ if(ret_sec_node)
+ /* Pass back the pointer to the section instead of adding it to the free list */
+ *ret_sec_node = sec_node;
+ else {
+ /* Add new free space to the heap's list of space */
+ if(H5HF_space_add(hdr, dxpl_id, sec_node, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
+ } /* end else */
+
+ /* Cache the new fractal heap direct block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap direct block to cache")
+
+ /* Increase the allocated heap size */
+ if(H5HF_hdr_inc_alloc(hdr, dblock->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size")
+
+ /* Set the address of of direct block, if requested */
+ if(addr_p)
+ *addr_p = dblock_addr;
+
+done:
+ if(ret_value < 0)
+ if(dblock)
+ if(H5HF_man_dblock_dest(dblock) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_destroy
+ *
+ * Purpose: Destroy a managed direct block
+ *
+ * Note: This routine does _not_ insert a range section for the
+ * destroyed direct block, that must be handled by the
+ * caller.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_direct_t *dblock,
+ haddr_t dblock_addr)
+{
+ hsize_t dblock_size; /* Size of direct block on disk */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting indirect block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(dblock);
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /* Check for root direct block */
+ if(dblock->parent == NULL)
+ /* Get direct block's actual size */
+ dblock_size = (hsize_t)hdr->pline_root_direct_size;
+ else {
+ H5HF_indirect_t *par_iblock; /* Parent indirect block */
+ unsigned par_entry; /* Entry in parent indirect block */
+
+ /* Get parent information */
+ par_iblock = dblock->parent;
+ par_entry = dblock->par_entry;
+
+ /* Get direct block's actual size */
+ dblock_size = (hsize_t)par_iblock->filt_ents[par_entry].size;
+ } /* end else */
+ } /* end if */
+ else
+ dblock_size = (hsize_t)dblock->size;
+
+ /* Check for root direct block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ /* Sanity check */
+ HDassert(hdr->man_dtable.table_addr == dblock_addr);
+ HDassert(hdr->man_dtable.cparam.start_block_size == dblock->size);
+
+ /* Sanity check block iterator */
+ HDassert(!H5HF_man_iter_ready(&hdr->next_block));
+
+ /* Reset root pointer information */
+ hdr->man_dtable.table_addr = HADDR_UNDEF;
+
+ /* Reset header information back to "empty heap" state */
+ if(H5HF_hdr_empty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty")
+ } /* end if */
+ else {
+ /* Adjust heap statistics */
+ hdr->man_alloc_size -= dblock->size;
+
+ /* Check for this direct block being the highest in the heap */
+ if((dblock->block_off + dblock->size) == hdr->man_iter_off) {
+ /* Move 'next block' iterator backwards (may shrink heap) */
+ if(H5HF_hdr_reverse_iter(hdr, dxpl_id, dblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reverse 'next block' iterator")
+ } /* end if */
+#if 0
+ else {
+ unsigned par_row, par_col; /* Row & column in parent indirect block */
+
+ /* Compute row & column in parent indirect block */
+ par_row = dblock->par_entry / hdr->man_dtable.cparam.width;
+ par_col = dblock->par_entry % hdr->man_dtable.cparam.width;
+
+ /* Add a 'range' section for the space in the destroyed block */
+ if(H5HF_sect_range_add(hdr, dxpl_id, dblock->block_off, hdr->man_dtable.row_tot_dblock_free[par_row],
+ dblock->parent, par_row, par_col, 1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't create range section for direct block being destroyed")
+ } /* end else */
+#endif /* 0 */
+
+ /* Detach from parent indirect block */
+ if(dblock->parent) {
+ if(H5HF_man_iblock_detach(dblock->parent, dxpl_id, dblock->par_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block");
+ dblock->parent = NULL;
+ dblock->par_entry = 0;
+ } /* end if */
+ } /* end else */
+
+ /* Indicate that the indirect block should be deleted */
+ dblock->file_size = dblock_size;
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG;
+
+ /* If the dblock is in real file space, also tell the cache to free its file space */
+ if (!H5F_IS_TMP_ADDR(hdr->f, dblock_addr))
+ cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+done:
+ /* Unprotect the indirect block, with appropriate flags */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, cache_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_destroy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_new
+ *
+ * Purpose: Create a direct block large enough to hold an object of
+ * the requested size
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_new(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t request,
+ H5HF_free_section_t **ret_sec_node)
+{
+ haddr_t dblock_addr; /* Address of new direct block */
+ size_t min_dblock_size; /* Min. size of direct block to allocate */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(request > 0);
+
+ /* Compute the min. size of the direct block needed to fulfill the request */
+ if(request < hdr->man_dtable.cparam.start_block_size)
+ min_dblock_size = hdr->man_dtable.cparam.start_block_size;
+ else {
+ min_dblock_size = ((size_t)1) << (1 + H5VM_log2_gen((uint64_t)request));
+ HDassert(min_dblock_size <= hdr->man_dtable.cparam.max_direct_size);
+ } /* end else */
+
+ /* Adjust the size of block needed to fulfill request, with overhead */
+ if(min_dblock_size < H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) + request)
+ min_dblock_size *= 2;
+
+ /* Check if this is the first block in the heap */
+ if(!H5F_addr_defined(hdr->man_dtable.table_addr) &&
+ min_dblock_size == hdr->man_dtable.cparam.start_block_size) {
+ /* Create new direct block at starting offset */
+ if(H5HF_man_dblock_create(dxpl_id, hdr, NULL, 0, &dblock_addr, ret_sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
+
+ /* Point root at new direct block */
+ hdr->man_dtable.curr_root_rows = 0;
+ hdr->man_dtable.table_addr = dblock_addr;
+ if(hdr->filter_len > 0) {
+ hdr->pline_root_direct_size = hdr->man_dtable.cparam.start_block_size;
+ hdr->pline_root_direct_filter_mask = 0;
+ } /* end if */
+
+ /* Extend heap to cover new direct block */
+ if(H5HF_hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size, (hssize_t)hdr->man_dtable.row_tot_dblock_free[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
+ } /* end if */
+ /* Root entry already exists, allocate direct block from root indirect block */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block to create */
+ unsigned next_row; /* Iterator's next block row */
+ unsigned next_entry; /* Iterator's next block entry */
+ size_t next_size; /* Size of next direct block to create */
+
+ /* Update iterator to reflect any previous increments as well as allow for requested direct block size */
+ if(H5HF_hdr_update_iter(hdr, dxpl_id, min_dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "unable to update block iterator")
+
+ /* Retrieve information about current iterator position */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+ HDassert(next_row < iblock->nrows);
+ H5_CHECKED_ASSIGN(next_size, size_t, hdr->man_dtable.row_block_size[next_row], hsize_t);
+
+ /* Check for skipping over blocks */
+ if(min_dblock_size > next_size) {
+HDfprintf(stderr, "%s: Skipping direct block sizes not supported, min_dblock_size = %Zu, next_size = %Zu\n", FUNC, min_dblock_size, next_size);
+HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "skipping direct block sizes not supported yet")
+ } /* end if */
+
+ /* Advance "next block" iterator to next direct block entry */
+ if(H5HF_hdr_inc_iter(hdr, (hsize_t)next_size, 1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment 'next block' iterator")
+
+ /* Create new direct block at current location*/
+ if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, next_entry, &dblock_addr, ret_sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_protect
+ *
+ * Purpose: Convenience wrapper around H5AC_protect on a direct block
+ * (Use H5AC_unprotect to unprotect it for now)
+ *
+ * Return: Pointer to direct block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_direct_t *
+H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr,
+ size_t dblock_size, H5HF_indirect_t *par_iblock, unsigned par_entry,
+ unsigned flags)
+{
+ H5HF_direct_t *dblock; /* Direct block from cache */
+ H5HF_dblock_cache_ud_t udata; /* parent and other infor for deserializing direct block */
+ H5HF_direct_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(dblock_addr));
+ HDassert(dblock_size > 0);
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up parent info */
+ udata.par_info.hdr = hdr;
+ udata.par_info.iblock = par_iblock;
+ udata.par_info.entry = par_entry;
+
+ /* set up the file pointer in the user data */
+ udata.f = hdr->f;
+
+ /* set up the direct block size */
+ udata.dblock_size = dblock_size;
+
+ /* compute the on disk image size -- observe that odi_size and
+ * dblock_size will be identical if there is no filtering.
+ */
+ if(hdr->filter_len > 0) {
+ if(par_iblock == NULL) {
+ udata.odi_size = hdr->pline_root_direct_size;
+ udata.filter_mask = hdr->pline_root_direct_filter_mask;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr));
+
+ /* Set up parameters to read filtered direct block */
+ udata.odi_size = par_iblock->filt_ents[par_entry].size;
+ udata.filter_mask = par_iblock->filt_ents[par_entry].filter_mask;
+ } /* end else */
+ } /* end if */
+ else {
+ udata.odi_size = dblock_size;
+ udata.filter_mask = 0;
+ } /* end else */
+
+ /* Reset compression context info */
+ udata.decompressed = FALSE;
+ udata.dblk = NULL;
+
+ /* Protect the direct block */
+ if(NULL == (dblock = (H5HF_direct_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, &udata, flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap direct block")
+
+ /* Set the return value */
+ ret_value = dblock;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_locate
+ *
+ * Purpose: Locate a direct block in a managed heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off,
+ H5HF_indirect_t **ret_iblock, unsigned *ret_entry, hbool_t *ret_did_protect,
+ unsigned flags)
+{
+ haddr_t iblock_addr; /* Indirect block's address */
+ H5HF_indirect_t *iblock; /* Pointer to indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ unsigned row, col; /* Row & column for object's block */
+ unsigned entry; /* Entry of block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(hdr->man_dtable.curr_root_rows); /* Only works for heaps with indirect root block */
+ HDassert(ret_iblock);
+ HDassert(ret_did_protect);
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Look up row & column for object */
+ if(H5HF_dtable_lookup(&hdr->man_dtable, obj_off, &row, &col) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object")
+
+ /* Set initial indirect block info */
+ iblock_addr = hdr->man_dtable.table_addr;
+
+ /* Lock root indirect block */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, hdr->man_dtable.curr_root_rows, NULL, 0, FALSE, flags, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Check for indirect block row */
+ while(row >= hdr->man_dtable.max_direct_rows) {
+ H5HF_indirect_t *new_iblock; /* Pointer to new indirect block */
+ hbool_t new_did_protect; /* Whether we protected the indirect block or not */
+ unsigned nrows; /* Number of rows in new indirect block */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting parent indirect block */
+
+ /* Compute # of rows in child indirect block */
+ nrows = (H5VM_log2_gen(hdr->man_dtable.row_block_size[row]) - hdr->man_dtable.first_row_bits) + 1;
+ HDassert(nrows < iblock->nrows); /* child must be smaller than parent */
+
+ /* Compute indirect block's entry */
+ entry = (row * hdr->man_dtable.cparam.width) + col;
+
+ /* Locate child indirect block */
+ iblock_addr = iblock->ents[entry].addr;
+
+ /* Check if we need to (re-)create the child indirect block */
+ if(!H5F_addr_defined(iblock_addr)) {
+ if(H5HF_man_iblock_create(hdr, dxpl_id, iblock, entry, nrows, nrows, &iblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block")
+
+ /* Indicate that the parent indirect block was modified */
+ cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Lock child indirect block */
+ if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, iblock, entry, FALSE, flags, &new_did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Release the current indirect block */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, cache_flags, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ /* Switch variables to use new indirect block */
+ iblock = new_iblock;
+ did_protect = new_did_protect;
+
+ /* Look up row & column in new indirect block for object */
+ if(H5HF_dtable_lookup(&hdr->man_dtable, (obj_off - iblock->block_off), &row, &col) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object")
+ HDassert(row < iblock->nrows); /* child must be smaller than parent */
+ } /* end while */
+
+ /* Set return parameters */
+ if(ret_entry)
+ *ret_entry = (row * hdr->man_dtable.cparam.width) + col;
+ *ret_iblock = iblock;
+ *ret_did_protect = did_protect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_locate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_delete
+ *
+ * Purpose: Delete a managed direct block
+ *
+ * Note: This routine does _not_ modify any indirect block that points
+ * to this direct block, it is assumed that the whole heap is
+ * being deleted. (H5HF_man_dblock_destroy modifies the indirect
+ * block)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_delete(H5F_t *f, hid_t dxpl_id, haddr_t dblock_addr,
+ hsize_t dblock_size)
+{
+ unsigned dblock_status = 0; /* Direct block's status in the metadata cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(H5F_addr_defined(dblock_addr));
+
+ /* Check the direct block's status in the metadata cache */
+ if(H5AC_get_entry_status(f, dblock_addr, &dblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for direct block")
+
+ /* If the direct block is in the cache, expunge it now */
+ if(dblock_status & H5AC_ES__IN_CACHE) {
+ /* Sanity checks on direct block */
+ HDassert(!(dblock_status & H5AC_ES__IS_PINNED));
+ HDassert(!(dblock_status & H5AC_ES__IS_PROTECTED));
+
+ /* Evict the direct block from the metadata cache */
+ if(H5AC_expunge_entry(f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove direct block from cache")
+ } /* end if */
+
+ /* Check if the direct block is NOT currently allocated in temp. file space */
+ /* (temp. file space does not need to be freed) */
+ if(!H5F_IS_TMP_ADDR(f, dblock_addr)) {
+ /* Release direct block's disk space */
+ /* (XXX: Under the best of circumstances, this block's space in the file
+ * would be freed in the H5AC_expunge_entry() call above (and the
+ * H5AC__FREE_FILE_SPACE_FLAG used there), but since the direct
+ * block structure might have a different size on disk than in
+ * the heap's 'abstract' address space, we would need to set the
+ * "file_size" field for the direct block structure. In order to
+ * do that, we'd have to protect/unprotect the direct block and
+ * that would add a bunch of unnecessary overhead to the process,
+ * so we just release the file space here, directly. When the
+ * revised metadata cache is operating, it will "know" the file
+ * size of each entry in the cache and we can the the
+ * H5AC_expunge_entry() method. -QAK)
+ */
+ if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, dblock_addr, dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_dest
+ *
+ * Purpose: Destroys a fractal heap direct block in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_dest(H5HF_direct_t *dblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dblock);
+
+ /* Decrement reference count on shared fractal heap info */
+ HDassert(dblock->hdr != NULL);
+ if(H5HF_hdr_decr(dblock->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
+ if(dblock->parent)
+ if(H5HF_iblock_decr(dblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Free block's buffer */
+ dblock->blk = H5FL_BLK_FREE(direct_block, dblock->blk);
+
+ /* Free fractal heap direct block info */
+ dblock = H5FL_FREE(H5HF_direct_t, dblock);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_dest() */
+
diff --git a/src/H5HFdtable.c b/src/H5HFdtable.c
new file mode 100644
index 0000000..563e8c5
--- /dev/null
+++ b/src/H5HFdtable.c
@@ -0,0 +1,370 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFdtable.c
+ * Apr 10 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: "Doubling table" routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_init
+ *
+ * Purpose: Initialize values for doubling table
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_dtable_init(H5HF_dtable_t *dtable)
+{
+ hsize_t tmp_block_size; /* Temporary block size */
+ hsize_t acc_block_off; /* Accumulated block offset */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+
+ /* Compute/cache some values */
+ dtable->start_bits = H5VM_log2_of2((uint32_t)dtable->cparam.start_block_size);
+ dtable->first_row_bits = dtable->start_bits + H5VM_log2_of2(dtable->cparam.width);
+ dtable->max_root_rows = (dtable->cparam.max_index - dtable->first_row_bits) + 1;
+ dtable->max_direct_bits = H5VM_log2_of2((uint32_t)dtable->cparam.max_direct_size);
+ dtable->max_direct_rows = (dtable->max_direct_bits - dtable->start_bits) + 2;
+ dtable->num_id_first_row = dtable->cparam.start_block_size * dtable->cparam.width;
+ dtable->max_dir_blk_off_size = H5HF_SIZEOF_OFFSET_LEN(dtable->cparam.max_direct_size);
+
+ /* Build table of block sizes for each row */
+ if(NULL == (dtable->row_block_size = (hsize_t *)H5MM_malloc(dtable->max_root_rows * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create doubling table block size table")
+ if(NULL == (dtable->row_block_off = (hsize_t *)H5MM_malloc(dtable->max_root_rows * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create doubling table block offset table")
+ if(NULL == (dtable->row_tot_dblock_free = (hsize_t *)H5MM_malloc(dtable->max_root_rows * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create doubling table total direct block free space table")
+ if(NULL == (dtable->row_max_dblock_free = (size_t *)H5MM_malloc(dtable->max_root_rows * sizeof(size_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create doubling table max. direct block free space table")
+ tmp_block_size = dtable->cparam.start_block_size;
+ acc_block_off = dtable->cparam.start_block_size * dtable->cparam.width;
+ dtable->row_block_size[0] = dtable->cparam.start_block_size;
+ dtable->row_block_off[0] = 0;
+ for(u = 1; u < dtable->max_root_rows; u++) {
+ dtable->row_block_size[u] = tmp_block_size;
+ dtable->row_block_off[u] = acc_block_off;
+ tmp_block_size *= 2;
+ acc_block_off *= 2;
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_dtable_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_lookup
+ *
+ * Purpose: Compute the row & col of an offset in a doubling-table
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_dtable_lookup(const H5HF_dtable_t *dtable, hsize_t off, unsigned *row, unsigned *col)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+ HDassert(row);
+ HDassert(col);
+#ifdef QAK
+HDfprintf(stderr, "%s: off = %Hu\n", "H5HF_dtable_lookup", off);
+#endif /* QAK */
+
+ /* Check for offset in first row */
+ if(off < dtable->num_id_first_row) {
+ *row = 0;
+ H5_CHECKED_ASSIGN(*col, unsigned, (off / dtable->cparam.start_block_size), hsize_t);
+ } /* end if */
+ else {
+ unsigned high_bit = H5VM_log2_gen(off); /* Determine the high bit in the offset */
+ hsize_t off_mask = ((hsize_t)1) << high_bit; /* Compute mask for determining column */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: high_bit = %u, off_mask = %Hu\n", "H5HF_dtable_lookup", high_bit, off_mask);
+#endif /* QAK */
+ *row = (high_bit - dtable->first_row_bits) + 1;
+ H5_CHECKED_ASSIGN(*col, unsigned, ((off - off_mask) / dtable->row_block_size[*row]), hsize_t);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_dtable_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_dest
+ *
+ * Purpose: Release information for doubling table
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_dtable_dest(H5HF_dtable_t *dtable)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+
+ /* Free the block size lookup table for the doubling table */
+ H5MM_xfree(dtable->row_block_size);
+
+ /* Free the block offset lookup table for the doubling table */
+ H5MM_xfree(dtable->row_block_off);
+
+ /* Free the total direct block free space lookup table for the doubling table */
+ H5MM_xfree(dtable->row_tot_dblock_free);
+
+ /* Free the max. direct block free space lookup table for the doubling table */
+ H5MM_xfree(dtable->row_max_dblock_free);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_dtable_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_size_to_row
+ *
+ * Purpose: Compute row that can hold block of a certain size
+ *
+ * Return: Non-negative on success (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_dtable_size_to_row(const H5HF_dtable_t *dtable, size_t block_size)
+{
+ unsigned row = 0; /* Row where block will fit */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+
+ if(block_size == dtable->cparam.start_block_size)
+ row = 0;
+ else
+ row = (H5VM_log2_of2((uint32_t)block_size) - H5VM_log2_of2((uint32_t)dtable->cparam.start_block_size)) + 1;
+
+ FUNC_LEAVE_NOAPI(row)
+} /* end H5HF_dtable_size_to_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_size_to_rows
+ *
+ * Purpose: Compute # of rows of indirect block of a given size
+ *
+ * Return: Non-negative on success (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_dtable_size_to_rows(const H5HF_dtable_t *dtable, hsize_t size)
+{
+ unsigned rows = 0; /* # of rows required for indirect block */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+
+ rows = (H5VM_log2_gen(size) - dtable->first_row_bits) + 1;
+
+ FUNC_LEAVE_NOAPI(rows)
+} /* end H5HF_dtable_size_to_rows() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_dtable_span_size
+ *
+ * Purpose: Compute the size covered by a span of entries
+ *
+ * Return: Non-zero span size on success/zero on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5HF_dtable_span_size(const H5HF_dtable_t *dtable, unsigned start_row,
+ unsigned start_col, unsigned num_entries)
+{
+ unsigned start_entry; /* Entry for first block covered */
+ unsigned end_row; /* Row for last block covered */
+ unsigned end_col; /* Column for last block covered */
+ unsigned end_entry; /* Entry for last block covered */
+ hsize_t acc_span_size = 0; /* Accumulated span size */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dtable);
+ HDassert(num_entries > 0);
+
+ /* Compute starting entry */
+ start_entry = (start_row * dtable->cparam.width) + start_col;
+
+ /* Compute ending entry, column & row */
+ end_entry = (start_entry + num_entries) - 1;
+ end_row = end_entry / dtable->cparam.width;
+ end_col = end_entry % dtable->cparam.width;
+#ifdef QAK
+HDfprintf(stderr, "%s: start_row = %u, start_col = %u, start_entry = %u\n", "H5HF_sect_indirect_span_size", start_row, start_col, start_entry);
+HDfprintf(stderr, "%s: end_row = %u, end_col = %u, end_entry = %u\n", "H5HF_sect_indirect_span_size", end_row, end_col, end_entry);
+#endif /* QAK */
+
+ /* Initialize accumulated span size */
+ acc_span_size = 0;
+
+ /* Compute span size covered */
+
+ /* Check for multi-row span */
+ if(start_row != end_row) {
+ /* Accomodate partial starting row */
+ if(start_col > 0) {
+ acc_span_size = dtable->row_block_size[start_row] *
+ (dtable->cparam.width - start_col);
+ start_row++;
+ } /* end if */
+
+ /* Accumulate full rows */
+ while(start_row < end_row) {
+ acc_span_size += dtable->row_block_size[start_row] *
+ dtable->cparam.width;
+ start_row++;
+ } /* end while */
+
+ /* Accomodate partial ending row */
+ acc_span_size += dtable->row_block_size[start_row] *
+ (end_col + 1);
+ } /* end if */
+ else {
+ /* Span is in same row */
+ acc_span_size = dtable->row_block_size[start_row] *
+ ((end_col - start_col) + 1);
+ } /* end else */
+
+#ifdef QAK
+HDfprintf(stderr, "%s: acc_span_size = %Hu\n", "H5HF_dtable_span_size", acc_span_size);
+#endif /* QAK */
+ FUNC_LEAVE_NOAPI(acc_span_size)
+} /* end H5HF_sect_indirect_span_size() */
+
diff --git a/src/H5HFhdr.c b/src/H5HFhdr.c
new file mode 100644
index 0000000..2f01ce6
--- /dev/null
+++ b/src/H5HFhdr.c
@@ -0,0 +1,1524 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFhdr.c
+ * Apr 10 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Heap header routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+#ifndef NDEBUG
+/* Limit on the size of the max. direct block size */
+/* (This is limited to 32-bits currently, because I think it's unlikely to
+ * need to be larger, the 32-bit limit for H5VM_log2_of2(n), and
+ * some offsets/sizes are encoded with a maxiumum of 32-bits - QAK)
+ */
+#define H5HF_MAX_DIRECT_SIZE_LIMIT ((hsize_t)2 * 1024 * 1024 * 1024)
+
+/* Limit on the width of the doubling table */
+/* (This is limited to 16-bits currently, because I think it's unlikely to
+ * need to be larger, and its encoded with a maxiumum of 16-bits - QAK)
+ */
+#define H5HF_WIDTH_LIMIT (64 * 1024)
+#endif /* NDEBUG */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5HF_hdr_t struct */
+H5FL_DEFINE_STATIC(H5HF_hdr_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_alloc
+ *
+ * Purpose: Allocate shared fractal heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_hdr_t *
+H5HF_hdr_alloc(H5F_t *f)
+{
+ H5HF_hdr_t *hdr = NULL; /* Shared fractal heap header */
+ H5HF_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+
+ /* Allocate space for the shared information */
+ if(NULL == (hdr = H5FL_CALLOC(H5HF_hdr_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "allocation failed for fractal heap shared header")
+
+ /* Set the internal parameters for the heap */
+ hdr->f = f;
+ hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
+ hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
+
+ /* Set the return value */
+ ret_value = hdr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_free_space
+ *
+ * Purpose: Compute direct block free space, for indirect blocks of
+ * different sizes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_hdr_compute_free_space(H5HF_hdr_t *hdr, unsigned iblock_row)
+{
+ hsize_t acc_heap_size; /* Accumumated heap space */
+ hsize_t iblock_size; /* Size of indirect block to calculate for */
+ hsize_t acc_dblock_free; /* Accumumated direct block free space */
+ size_t max_dblock_free; /* Max. direct block free space */
+ unsigned curr_row; /* Current row in block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(iblock_row >= hdr->man_dtable.max_direct_rows);
+
+ /* Set the free space in direct blocks */
+ acc_heap_size = 0;
+ acc_dblock_free = 0;
+ max_dblock_free = 0;
+ iblock_size = hdr->man_dtable.row_block_size[iblock_row];
+ curr_row = 0;
+ while(acc_heap_size < iblock_size) {
+ acc_heap_size += hdr->man_dtable.row_block_size[curr_row] *
+ hdr->man_dtable.cparam.width;
+ acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[curr_row] *
+ hdr->man_dtable.cparam.width;
+ if(hdr->man_dtable.row_max_dblock_free[curr_row] > max_dblock_free)
+ max_dblock_free = hdr->man_dtable.row_max_dblock_free[curr_row];
+ curr_row++;
+ } /* end while */
+
+ /* Set direct block free space values for indirect block */
+ hdr->man_dtable.row_tot_dblock_free[iblock_row] = acc_dblock_free;
+ hdr->man_dtable.row_max_dblock_free[iblock_row] = max_dblock_free;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_compute_free_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_finish_init_phase1
+ *
+ * Purpose: First phase to finish initializing info in shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_finish_init_phase1(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Compute/cache some values */
+ hdr->heap_off_size = (uint8_t)H5HF_SIZEOF_OFFSET_BITS(hdr->man_dtable.cparam.max_index);
+ if(H5HF_dtable_init(&hdr->man_dtable) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize doubling table info")
+
+ /* Set the size of heap IDs */
+ hdr->heap_len_size = (uint8_t)MIN(hdr->man_dtable.max_dir_blk_off_size,
+ H5VM_limit_enc_size((uint64_t)hdr->max_man_size));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_finish_init_phase1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_finish_init_phase2
+ *
+ * Purpose: Second phase to finish initializing info in shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_finish_init_phase2(H5HF_hdr_t *hdr)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Set the free space in direct blocks */
+ for(u = 0; u < hdr->man_dtable.max_root_rows; u++) {
+ if(u < hdr->man_dtable.max_direct_rows) {
+ hdr->man_dtable.row_tot_dblock_free[u] = hdr->man_dtable.row_block_size[u] -
+ H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ H5_CHECKED_ASSIGN(hdr->man_dtable.row_max_dblock_free[u], size_t, hdr->man_dtable.row_tot_dblock_free[u], hsize_t);
+ } /* end if */
+ else
+ if(H5HF_hdr_compute_free_space(hdr, u) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize direct block free space for indirect block")
+ } /* end for */
+
+ /* Initialize the block iterator for searching for free space */
+ if(H5HF_man_iter_init(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize space search block iterator")
+
+ /* Initialize the information for tracking 'huge' objects */
+ if(H5HF_huge_init(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking huge objects")
+
+ /* Initialize the information for tracking 'tiny' objects */
+ if(H5HF_tiny_init(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize info for tracking tiny objects")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_finish_init_phase2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_finish_init
+ *
+ * Purpose: Finish initializing info in shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_finish_init(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* First phase of header final initialization */
+ if(H5HF_hdr_finish_init_phase1(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #1 of header final initialization")
+
+ /* Second phase of header final initialization */
+ if(H5HF_hdr_finish_init_phase2(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't finish phase #2 of header final initialization")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_finish_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_create
+ *
+ * Purpose: Create new fractal heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5HF_hdr_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam)
+{
+ H5HF_hdr_t *hdr = NULL; /* The new fractal heap header information */
+ size_t dblock_overhead; /* Direct block's overhead */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(cparam);
+
+#ifndef NDEBUG
+ /* Check for valid parameters */
+ if(cparam->managed.width == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width must be greater than zero")
+ if(cparam->managed.width > H5HF_WIDTH_LIMIT)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width too large")
+ if(!POWER_OF_TWO(cparam->managed.width))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "width not power of two")
+ if(cparam->managed.start_block_size == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size must be greater than zero")
+ if(!POWER_OF_TWO(cparam->managed.start_block_size))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "starting block size not power of two")
+ if(cparam->managed.max_direct_size == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size must be greater than zero")
+ if(cparam->managed.max_direct_size > H5HF_MAX_DIRECT_SIZE_LIMIT)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size too large")
+ if(!POWER_OF_TWO(cparam->managed.max_direct_size))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size not power of two")
+ if(cparam->managed.max_direct_size < cparam->max_man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size not large enough to hold all managed blocks")
+ if(cparam->managed.max_index == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size must be greater than zero")
+#endif /* NDEBUG */
+
+ /* Allocate & basic initialization for the shared header */
+ if(NULL == (hdr = H5HF_hdr_alloc(f)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "can't allocate space for shared heap info")
+
+#ifndef NDEBUG
+ if(cparam->managed.max_index > (unsigned)(8 * hdr->sizeof_size))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. heap size too large for file")
+#endif /* NDEBUG */
+
+ /* Set the creation parameters for the heap */
+ hdr->max_man_size = cparam->max_man_size;
+ hdr->checksum_dblocks = cparam->checksum_dblocks;
+ HDmemcpy(&(hdr->man_dtable.cparam), &(cparam->managed), sizeof(H5HF_dtable_cparam_t));
+
+ /* Set root table address to indicate that the heap is empty currently */
+ hdr->man_dtable.table_addr = HADDR_UNDEF;
+
+ /* Set free list header address to indicate that the heap is empty currently */
+ hdr->fs_addr = HADDR_UNDEF;
+
+ /* Set "huge" object tracker v2 B-tree address to indicate that there aren't any yet */
+ hdr->huge_bt2_addr = HADDR_UNDEF;
+
+ /* First phase of header final initialization */
+ /* (doesn't need ID length set up) */
+ if(H5HF_hdr_finish_init_phase1(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "can't finish phase #1 of header final initialization")
+
+ /* Copy any I/O filter pipeline */
+ /* (This code is not in the "finish init phase" routines because those
+ * routines are also called from the cache 'load' callback, and the filter
+ * length is already set in that case (its stored in the header on disk))
+ */
+ if(cparam->pline.nused > 0) {
+ /* Check if the filters in the DCPL can be applied to this dataset */
+ if(H5Z_can_apply_direct(&(cparam->pline)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "I/O filters can't operate on this heap")
+
+ /* Mark the filters as checked */
+ hdr->checked_filters = TRUE;
+
+ /* Make the "set local" filter callbacks for this dataset */
+ if(H5Z_set_local_direct(&(cparam->pline)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to set local filter parameters")
+
+ /* Copy the I/O filter pipeline from the creation parameters to the header */
+ if(NULL == H5O_msg_copy(H5O_PLINE_ID, &(cparam->pline), &(hdr->pline)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOPY, HADDR_UNDEF, "can't copy I/O filter pipeline")
+
+ /* Pay attention to the latest version flag for the file */
+ if(H5F_USE_LATEST_FLAGS(hdr->f, H5F_LATEST_PLINE_MSG))
+ /* Set the latest version for the I/O pipeline message */
+ if(H5O_pline_set_latest_version(&(hdr->pline)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, HADDR_UNDEF, "can't set latest version of I/O filter pipeline")
+
+ /* Compute the I/O filters' encoded size */
+ if(0 == (hdr->filter_len = (unsigned)H5O_msg_raw_size(hdr->f, H5O_PLINE_ID, FALSE, &(hdr->pline))))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGETSIZE, HADDR_UNDEF, "can't get I/O filter pipeline size")
+
+ /* Compute size of header on disk */
+ hdr->heap_size = H5HF_HEADER_SIZE(hdr) /* Base header size */
+ + hdr->sizeof_size /* Size of size for filtered root direct block */
+ + 4 /* Size of filter mask for filtered root direct block */
+ + hdr->filter_len; /* Size of encoded I/O filter info */
+ } /* end if */
+ else {
+ /* Set size of header on disk */
+ hdr->heap_size = H5HF_HEADER_SIZE(hdr);
+
+ /* Mark filters as checked, for performance reasons */
+ hdr->checked_filters = TRUE;
+ } /* end else */
+
+ /* Set the length of IDs in the heap */
+ /* (This code is not in the "finish init phase" routines because those
+ * routines are also called from the cache 'load' callback, and the ID
+ * length is already set in that case (its stored in the header on disk))
+ */
+ switch(cparam->id_len) {
+ case 0: /* Set the length of heap IDs to just enough to hold the offset & length of 'normal' objects in the heap */
+ hdr->id_len = (unsigned)1 + hdr->heap_off_size + hdr->heap_len_size;
+ break;
+
+ case 1: /* Set the length of heap IDs to just enough to hold the information needed to directly access 'huge' objects in the heap */
+ if(hdr->filter_len > 0)
+ hdr->id_len = (unsigned)1 /* ID flags */
+ + hdr->sizeof_addr /* Address of filtered object */
+ + hdr->sizeof_size /* Length of filtered object */
+ + 4 /* Filter mask for filtered object */
+ + hdr->sizeof_size; /* Size of de-filtered object in memory */
+ else
+ hdr->id_len = (unsigned)1 /* ID flags */
+ + hdr->sizeof_addr /* Address of object */
+ + hdr->sizeof_size; /* Length of object */
+ break;
+
+ default: /* Use the requested size for the heap ID */
+ /* Check boundaries */
+ if(cparam->id_len < (1 + hdr->heap_off_size + hdr->heap_len_size))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF, "ID length not large enough to hold object IDs")
+ else if(cparam->id_len > H5HF_MAX_ID_LEN)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, HADDR_UNDEF, "ID length too large to store tiny object lengths")
+
+ /* Use the requested size for the heap ID */
+ hdr->id_len = cparam->id_len;
+ break;
+ } /* end switch */
+
+ /* Second phase of header final initialization */
+ /* (needs ID and filter lengths set up) */
+ if(H5HF_hdr_finish_init_phase2(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "can't finish phase #2 of header final initialization")
+
+ /* Extra checking for possible gap between max. direct block size minus
+ * overhead and "huge" object size */
+ dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ if((cparam->managed.max_direct_size - dblock_overhead) < cparam->max_man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, HADDR_UNDEF, "max. direct block size not large enough to hold all managed blocks")
+
+ /* Allocate space for the header on disk */
+ if(HADDR_UNDEF == (hdr->heap_addr = H5MF_alloc(f, H5FD_MEM_FHEAP_HDR, dxpl_id, (hsize_t)hdr->heap_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for fractal heap header")
+
+ /* Cache the new fractal heap header */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, HADDR_UNDEF, "can't add fractal heap header to cache")
+
+ /* Set address of heap header to return */
+ ret_value = hdr->heap_addr;
+
+done:
+ if(!H5F_addr_defined(ret_value) && hdr)
+ if(H5HF_hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, HADDR_UNDEF, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_protect
+ *
+ * Purpose: Convenience wrapper around H5AC_protect on an indirect block
+ *
+ * Return: Pointer to indirect block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 5 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_hdr_t *
+H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)
+{
+ H5HF_hdr_cache_ud_t cache_udata; /* User-data for callback */
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ H5HF_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Set up userdata for protect call */
+ cache_udata.f = f;
+ cache_udata.dxpl_id = dxpl_id;
+
+ /* Lock the heap header into memory */
+ if(NULL == (hdr = (H5HF_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_HDR, addr, &cache_udata, flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header")
+
+ /* Set the header's address */
+ hdr->heap_addr = addr;
+
+ /* Update header's file pointer */
+ hdr->f = f;
+
+ /* Set the return value */
+ ret_value = hdr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_incr
+ *
+ * Purpose: Increment component reference count on shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_incr(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Mark header as un-evictable when a block is depending on it */
+ if(hdr->rc == 0)
+ if(H5AC_pin_protected_entry(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap header")
+
+ /* Increment reference count on shared header */
+ hdr->rc++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_decr
+ *
+ * Purpose: Decrement component reference count on shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_decr(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->rc);
+
+ /* Decrement reference count on shared header */
+ hdr->rc--;
+
+ /* Mark header as evictable again when no child blocks depend on it */
+ if(hdr->rc == 0) {
+ HDassert(hdr->file_rc == 0);
+ if(H5AC_unpin_entry(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap header")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_fuse_incr
+ *
+ * Purpose: Increment file reference count on shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 1 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_fuse_incr(H5HF_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Increment file reference count on shared header */
+ hdr->file_rc++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_hdr_fuse_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_fuse_decr
+ *
+ * Purpose: Decrement file reference count on shared heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 1 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5HF_hdr_fuse_decr(H5HF_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(hdr->file_rc);
+
+ /* Decrement file reference count on shared header */
+ hdr->file_rc--;
+
+ FUNC_LEAVE_NOAPI(hdr->file_rc)
+} /* end H5HF_hdr_fuse_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_dirty
+ *
+ * Purpose: Mark heap header as dirty
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_dirty(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Resize pinned header in cache if I/O filter is present. */
+ if(hdr->filter_len > 0) {
+ if(H5AC_resize_entry(hdr, (size_t)hdr->heap_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap header")
+ } /* end if */
+
+ /* Mark header as dirty in cache */
+ if(H5AC_mark_entry_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_adj_free
+ *
+ * Purpose: Adjust the free space for a heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_adj_free(H5HF_hdr_t *hdr, ssize_t amt)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Update heap header */
+ HDassert(amt > 0 || hdr->total_man_free >= (hsize_t)-amt);
+ hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + amt);
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_adj_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_adjust_heap
+ *
+ * Purpose: Adjust heap space
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Set the total managed space in heap */
+ hdr->man_size = new_size;
+
+ /* Adjust the free space in direct blocks */
+ HDassert(extra_free > 0 || hdr->total_man_free >= (hsize_t)-extra_free);
+ hdr->total_man_free = (hsize_t)((hssize_t)hdr->total_man_free + extra_free);
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_adjust_heap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_inc_alloc
+ *
+ * Purpose: Increase allocated size of heap
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 23 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(alloc_size);
+
+ /* Update the "allocated" size within the heap */
+ hdr->man_alloc_size += alloc_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_hdr_inc_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_start_iter
+ *
+ * Purpose: Start "next block" iterator at an offset/entry in the heap
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 30 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(iblock);
+
+ /* Set up "next block" iterator at correct location */
+ if(H5HF_man_iter_start_entry(hdr, &hdr->next_block, iblock, curr_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator")
+
+ /* Set the offset of the iterator in the heap */
+ hdr->man_iter_off = curr_off;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_start_iter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_reset_iter
+ *
+ * Purpose: Reset "next block" iterator
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Reset "next block" iterator */
+ if(H5HF_man_iter_reset(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
+
+ /* Set the offset of the iterator in the heap */
+ hdr->man_iter_off = curr_off;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_reset_iter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_skip_blocks
+ *
+ * Purpose: Add skipped direct blocks to free space for heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 3 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *iblock,
+ unsigned start_entry, unsigned nentries)
+{
+ unsigned row, col; /* Row & column of entry */
+ hsize_t sect_size; /* Size of section in heap space */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(iblock);
+ HDassert(nentries);
+
+ /* Compute the span within the heap to skip */
+ row = start_entry / hdr->man_dtable.cparam.width;
+ col = start_entry % hdr->man_dtable.cparam.width;
+ sect_size = H5HF_dtable_span_size(&hdr->man_dtable, row, col, nentries);
+ HDassert(sect_size > 0);
+
+ /* Advance the new block iterator */
+ if(H5HF_hdr_inc_iter(hdr, sect_size, nentries) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size")
+
+ /* Add 'indirect' section for blocks skipped in this row */
+ if(H5HF_sect_indirect_add(hdr, dxpl_id, iblock, start_entry, nentries) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section for indirect block's free space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_skip_blocks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_update_iter
+ *
+ * Purpose: Update state of heap to account for current iterator
+ * position.
+ *
+ * Note: Creates necessary indirect blocks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_update_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(min_dblock_size > 0);
+
+ /* Check for creating first indirect block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ if(H5HF_man_iblock_root_create(hdr, dxpl_id, min_dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to create root indirect block")
+ } /* end if */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block */
+ hbool_t walked_up, walked_down; /* Condition variables for finding direct block location */
+ unsigned next_row; /* Iterator's next block row */
+ unsigned next_entry; /* Iterator's next block entry */
+ unsigned min_dblock_row; /* Minimum row for direct block size request */
+
+ /* Compute min. row for direct block requested */
+ min_dblock_row = H5HF_dtable_size_to_row(&hdr->man_dtable, min_dblock_size);
+
+ /* Initialize block iterator, if necessary */
+ if(!H5HF_man_iter_ready(&hdr->next_block)) {
+ /* Start iterator with previous offset of iterator */
+ if(H5HF_man_iter_start_offset(hdr, dxpl_id, &hdr->next_block, hdr->man_iter_off) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location")
+ } /* end if */
+
+ /* Get information about current iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+
+ /* Check for skipping over blocks in the current block */
+ if(min_dblock_row > next_row && next_row < iblock->nrows) {
+ unsigned min_entry; /* Min entry for direct block requested */
+ unsigned skip_entries; /* Number of entries to skip in the current block */
+
+ /* Compute the number of entries to skip in the current block */
+ min_entry = min_dblock_row * hdr->man_dtable.cparam.width;
+ if(min_dblock_row >= iblock->nrows)
+ skip_entries = (iblock->nrows * hdr->man_dtable.cparam.width) - next_entry;
+ else
+ skip_entries = min_entry - next_entry;
+
+ /* Add skipped direct blocks to heap's free space */
+ if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, next_entry, skip_entries) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
+
+ /* Get information about new iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+ } /* end if */
+
+ do {
+ /* Reset conditions for leaving loop */
+ walked_up = walked_down = FALSE;
+
+ /* Check for walking off end of indirect block */
+ /* (walk up iterator) */
+ while(next_row >= iblock->nrows) {
+ /* Check for needing to expand root indirect block */
+ if(iblock->parent == NULL) {
+ if(H5HF_man_iblock_root_double(hdr, dxpl_id, min_dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to double root indirect block")
+ } /* end if */
+ else {
+ /* Move iterator up one level */
+ if(H5HF_man_iter_up(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location")
+
+ /* Increment location of next block at this level */
+ if(H5HF_man_iter_next(hdr, &hdr->next_block, 1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't advance fractal heap block location")
+ } /* end else */
+
+ /* Get information about new iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+
+ /* Indicate that we walked up */
+ walked_up = TRUE;
+ } /* end while */
+
+ /* Check for walking into child indirect block */
+ /* (walk down iterator) */
+ if(next_row >= hdr->man_dtable.max_direct_rows) {
+ unsigned child_nrows; /* Number of rows in new indirect block */
+
+ HDassert(!H5F_addr_defined(iblock->ents[next_entry].addr));
+
+ /* Compute # of rows in next child indirect block to use */
+ child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[next_row]);
+
+ /* Check for skipping over indirect blocks */
+ /* (that don't have direct blocks large enough to hold direct block size requested) */
+ if(hdr->man_dtable.row_block_size[child_nrows - 1] < min_dblock_size) {
+ unsigned child_rows_needed; /* Number of rows needed to hold direct block */
+ unsigned child_entry; /* Entry of child indirect block */
+
+ /* Compute # of rows needed in child indirect block */
+ child_rows_needed = (H5VM_log2_of2((uint32_t)min_dblock_size) - H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size)) + 2;
+ HDassert(child_rows_needed > child_nrows);
+ child_entry = (next_row + (child_rows_needed - child_nrows)) * hdr->man_dtable.cparam.width;
+ if(child_entry > (iblock->nrows * hdr->man_dtable.cparam.width))
+ child_entry = iblock->nrows * hdr->man_dtable.cparam.width;
+
+ /* Add skipped indirect blocks to heap's free space */
+ if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, next_entry, (child_entry - next_entry)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
+ } /* end if */
+ else {
+ H5HF_indirect_t *new_iblock; /* Pointer to new indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ haddr_t new_iblock_addr; /* New indirect block's address */
+
+ /* Allocate new indirect block */
+ if(H5HF_man_iblock_create(hdr, dxpl_id, iblock, next_entry, child_nrows, child_nrows, &new_iblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block")
+
+ /* Lock new indirect block */
+ if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_iblock_addr, child_nrows, iblock, next_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Move iterator down one level (pins indirect block) */
+ if(H5HF_man_iter_down(&hdr->next_block, new_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location")
+
+ /* Check for skipping over rows and add free section for skipped rows */
+ if(min_dblock_size > hdr->man_dtable.cparam.start_block_size) {
+ unsigned new_entry; /* Entry of direct block which is large enough */
+
+ /* Compute entry for direct block size requested */
+ new_entry = hdr->man_dtable.cparam.width * min_dblock_row;
+
+ /* Add skipped blocks to heap's free space */
+ if(H5HF_hdr_skip_blocks(hdr, dxpl_id, new_iblock, 0, new_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
+ } /* end if */
+
+ /* Unprotect child indirect block */
+ if(H5HF_man_iblock_unprotect(new_iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ } /* end else */
+
+ /* Get information about new iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+
+ /* Indicate that we walked down */
+ walked_down = TRUE;
+ } /* end if */
+ } while(walked_down || walked_up);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_update_iter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_inc_iter
+ *
+ * Purpose: Advance "next block" iterator
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 23 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(nentries);
+
+ /* Advance the iterator for the current location within the indirect block */
+ if(hdr->next_block.curr)
+ if(H5HF_man_iter_next(hdr, &hdr->next_block, nentries) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location")
+
+ /* Increment the offset of the iterator in the heap */
+ hdr->man_iter_off += adv_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_inc_iter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_reverse_iter
+ *
+ * Purpose: Walk "next block" iterator backwards until the correct
+ * location to allocate next block from is found
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr)
+{
+ H5HF_indirect_t *iblock; /* Indirect block where iterator is located */
+ unsigned curr_entry; /* Current entry for iterator */
+ hbool_t walked_down; /* Loop flag */
+ hbool_t walked_up; /* Loop flag */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Initialize block iterator, if necessary */
+ if(!H5HF_man_iter_ready(&hdr->next_block))
+ /* Start iterator with previous offset of iterator */
+ if(H5HF_man_iter_start_offset(hdr, dxpl_id, &hdr->next_block, hdr->man_iter_off) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location")
+
+ /* Walk backwards through heap, looking for direct block to place iterator after */
+
+ /* Get information about current iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information")
+
+ /* Move current iterator position backwards once */
+ curr_entry--;
+
+ /* Search backwards in the heap address space for direct block to latch onto */
+ do {
+ int tmp_entry; /* Temp. entry for iterator (use signed value to detect errors) */
+
+ /* Reset loop flags */
+ walked_down = FALSE;
+ walked_up = FALSE;
+
+ /* Walk backwards through entries, until we find one that has a child */
+ /* (Skip direct block that will be deleted, if we find it) */
+ tmp_entry = (int)curr_entry;
+ while(tmp_entry >= 0 &&
+ (H5F_addr_eq(iblock->ents[tmp_entry].addr, dblock_addr) ||
+ !H5F_addr_defined(iblock->ents[tmp_entry].addr)))
+ tmp_entry--;
+ /* Check for no earlier blocks in this indirect block */
+ if(tmp_entry < 0) {
+ /* Check for parent of current indirect block */
+ if(iblock->parent) {
+ /* Move iterator to parent of current block */
+ if(H5HF_man_iter_up(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to move current block iterator location up")
+
+ /* Get information about current iterator location */
+ if(H5HF_man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information")
+
+ /* Move current iterator position backwards once */
+ curr_entry--;
+
+ /* Note that we walked up */
+ walked_up = TRUE;
+ } /* end if */
+ else {
+ /* Reset iterator offset */
+ hdr->man_iter_off = 0;
+
+ /* Reset 'next block' iterator */
+ if(H5HF_man_iter_reset(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
+ } /* end else */
+ } /* end if */
+ else {
+ unsigned row; /* Row for entry */
+
+ curr_entry = (unsigned)tmp_entry;
+
+ /* Check if entry is for a direct block */
+ row = curr_entry / hdr->man_dtable.cparam.width;
+ if(row < hdr->man_dtable.max_direct_rows) {
+ /* Increment entry to empty location */
+ curr_entry++;
+
+ /* Set the current location of the iterator to next entry after the existing direct block */
+ if(H5HF_man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location")
+
+ /* Update iterator offset */
+ hdr->man_iter_off = iblock->block_off;
+ hdr->man_iter_off += hdr->man_dtable.row_block_off[curr_entry / hdr->man_dtable.cparam.width];
+ hdr->man_iter_off += hdr->man_dtable.row_block_size[curr_entry / hdr->man_dtable.cparam.width] * (curr_entry % hdr->man_dtable.cparam.width);
+ } /* end if */
+ else {
+ H5HF_indirect_t *child_iblock; /* Pointer to child indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ unsigned child_nrows; /* # of rows in child block */
+
+ /* Compute # of rows in next child indirect block to use */
+ child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[row]);
+
+ /* Lock child indirect block */
+ if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock->ents[curr_entry].addr, child_nrows, iblock, curr_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Set the current location of the iterator */
+ if(H5HF_man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location")
+
+ /* Walk down into child indirect block (pins child block) */
+ if(H5HF_man_iter_down(&hdr->next_block, child_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location")
+
+ /* Update iterator location */
+ iblock = child_iblock;
+ curr_entry = (child_iblock->nrows * hdr->man_dtable.cparam.width) - 1;
+
+ /* Unprotect child indirect block */
+ if(H5HF_man_iblock_unprotect(child_iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ /* Note that we walked down */
+ walked_down = TRUE;
+ } /* end else */
+ } /* end else */
+ } while(walked_down || walked_up);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_reverse_iter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_empty
+ *
+ * Purpose: Reset heap header to 'empty heap' state
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_empty(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+
+ /* Reset block iterator, if necessary */
+ if(H5HF_man_iter_ready(&hdr->next_block)) {
+ if(H5HF_man_iter_reset(&hdr->next_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
+ } /* end if */
+
+ /* Shrink managed heap size */
+ hdr->man_size = 0;
+ hdr->man_alloc_size = 0;
+
+ /* Reset the 'next block' iterator location */
+ hdr->man_iter_off = 0;
+
+ /* Reset the free space in direct blocks */
+ hdr->total_man_free = 0;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_empty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_free
+ *
+ * Purpose: Free shared fractal heap header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 27 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_free(H5HF_hdr_t *hdr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Free the block size lookup table for the doubling table */
+ if(H5HF_dtable_dest(&hdr->man_dtable) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap doubling table")
+
+ /* Release any I/O pipeline filter information */
+ if(hdr->pline.nused)
+ if(H5O_msg_reset(H5O_PLINE_ID, &(hdr->pline)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to reset I/O pipeline message")
+
+ /* Free the shared info itself */
+ hdr = H5FL_FREE(H5HF_hdr_t, hdr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_hdr_delete
+ *
+ * Purpose: Delete a fractal heap, starting with the header
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 5 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_hdr_delete(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(!hdr->file_rc);
+
+#ifndef NDEBUG
+{
+ unsigned hdr_status = 0; /* Heap header's status in the metadata cache */
+
+ /* Check the heap header's status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, hdr->heap_addr, &hdr_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for heap header")
+
+ /* Sanity checks on heap header */
+ HDassert(hdr_status & H5AC_ES__IN_CACHE);
+ HDassert(hdr_status & H5AC_ES__IS_PROTECTED);
+} /* end block */
+#endif /* NDEBUG */
+
+ /* Check for free space manager for heap */
+ /* (must occur before attempting to delete the heap, so indirect blocks
+ * will get unpinned)
+ */
+ if(H5F_addr_defined(hdr->fs_addr)) {
+ /* Delete free space manager for heap */
+ if(H5HF_space_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap free space manager")
+ } /* end if */
+
+ /* Check for root direct/indirect block */
+ if(H5F_addr_defined(hdr->man_dtable.table_addr)) {
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ hsize_t dblock_size; /* Size of direct block */
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ dblock_size = (hsize_t)hdr->pline_root_direct_size;
+
+ /* Reset the header's pipeline information */
+ hdr->pline_root_direct_size = 0;
+ hdr->pline_root_direct_filter_mask = 0;
+ } /* end else */
+ else
+ dblock_size = (hsize_t)hdr->man_dtable.cparam.start_block_size;
+
+ /* Delete root direct block */
+ if(H5HF_man_dblock_delete(hdr->f, dxpl_id, hdr->man_dtable.table_addr, dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root direct block")
+ } /* end if */
+ else {
+ /* Delete root indirect block */
+ if(H5HF_man_iblock_delete(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root indirect block")
+ } /* end else */
+ } /* end if */
+
+ /* Check for 'huge' objects in heap */
+ if(H5F_addr_defined(hdr->huge_bt2_addr)) {
+ /* Delete huge objects in heap and their tracker */
+ if(H5HF_huge_delete(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap 'huge' objects and tracker")
+ } /* end if */
+
+ /* Indicate that the heap header should be deleted & file space freed */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+done:
+ /* Unprotect the header with appropriate flags */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, cache_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_hdr_delete() */
+
diff --git a/src/H5HFhuge.c b/src/H5HFhuge.c
new file mode 100644
index 0000000..b2a1e68
--- /dev/null
+++ b/src/H5HFhuge.c
@@ -0,0 +1,1199 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFhuge.c
+ * Aug 7 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Routines for "huge" objects in fractal heap
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* v2 B-tree creation macros */
+#define H5HF_HUGE_BT2_NODE_SIZE 512
+#define H5HF_HUGE_BT2_SPLIT_PERC 100
+#define H5HF_HUGE_BT2_MERGE_PERC 40
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Local v2 B-tree operations */
+static herr_t H5HF_huge_bt2_create(H5HF_hdr_t *hdr, hid_t dxpl_id);
+
+/* Local 'huge' object support routines */
+static hsize_t H5HF_huge_new_id(H5HF_hdr_t *hdr);
+static herr_t H5HF_huge_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ const uint8_t *id, hbool_t is_read, H5HF_operator_t op, void *op_data);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_bt2_create
+ *
+ * Purpose: Create the v2 B-tree for tracking the huge objects in the heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_huge_bt2_create(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Compute the size of 'raw' records on disk */
+ /* (Note: the size for huge IDs could be set to 'huge_id_size', instead
+ * of 'sizeof_size', but that would make the v2 B-tree callback routines
+ * depend on the heap header, which makes the v2 B-tree flush routines
+ * difficult to write. "Waste" an extra byte or for small heaps (where
+ * the 'huge_id_size' is < 'sizeof_size' in order to make this easier -QAK)
+ */
+ if(hdr->huge_ids_direct) {
+ if(hdr->filter_len > 0) {
+ bt2_cparam.rrec_size = (size_t)((unsigned)hdr->sizeof_addr /* Address of object */
+ + (unsigned)hdr->sizeof_size /* Length of object */
+ + (unsigned)4 /* Filter mask for filtered object */
+ + (unsigned)hdr->sizeof_size); /* Size of de-filtered object in memory */
+ bt2_cparam.cls = H5HF_HUGE_BT2_FILT_DIR;
+ } /* end if */
+ else {
+ bt2_cparam.rrec_size = (size_t)((unsigned)hdr->sizeof_addr /* Address of object */
+ + (unsigned)hdr->sizeof_size); /* Length of object */
+ bt2_cparam.cls = H5HF_HUGE_BT2_DIR;
+ } /* end else */
+ } /* end if */
+ else {
+ if(hdr->filter_len > 0) {
+ bt2_cparam.rrec_size = (size_t)((unsigned)hdr->sizeof_addr /* Address of filtered object */
+ + (unsigned)hdr->sizeof_size /* Length of filtered object */
+ + (unsigned)4 /* Filter mask for filtered object */
+ + (unsigned)hdr->sizeof_size /* Size of de-filtered object in memory */
+ + (unsigned)hdr->sizeof_size); /* Unique ID for object */
+ bt2_cparam.cls = H5HF_HUGE_BT2_FILT_INDIR;
+ } /* end if */
+ else {
+ bt2_cparam.rrec_size = (size_t)((unsigned)hdr->sizeof_addr /* Address of object */
+ + (unsigned)hdr->sizeof_size /* Length of object */
+ + (unsigned)hdr->sizeof_size); /* Unique ID for object */
+ bt2_cparam.cls = H5HF_HUGE_BT2_INDIR;
+ } /* end else */
+ } /* end else */
+ bt2_cparam.node_size = (size_t)H5HF_HUGE_BT2_NODE_SIZE;
+ bt2_cparam.split_percent = H5HF_HUGE_BT2_SPLIT_PERC;
+ bt2_cparam.merge_percent = H5HF_HUGE_BT2_MERGE_PERC;
+
+ /* Create v2 B-tree for tracking 'huge' objects */
+ if(NULL == (hdr->huge_bt2 = H5B2_create(hdr->f, dxpl_id, &bt2_cparam, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking 'huge' heap objects")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(hdr->huge_bt2, &hdr->huge_bt2_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get v2 B-tree address for tracking 'huge' heap objects")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_bt2_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_init
+ *
+ * Purpose: Initialize information for tracking 'huge' objects
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_init(H5HF_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Compute information about 'huge' objects for the heap */
+
+ /* Check if we can completely hold the 'huge' object's offset & length in
+ * the file in the heap ID (which will speed up accessing it) and we don't
+ * have any I/O pipeline filters.
+ */
+#ifdef QAK
+HDfprintf(stderr, "%s: hdr->id_len = %u\n", "H5HF_huge_init", (unsigned)hdr->id_len);
+HDfprintf(stderr, "%s: hdr->filter_len = %u\n", "H5HF_huge_init", (unsigned)hdr->filter_len);
+#endif /* QAK */
+ if(hdr->filter_len > 0) {
+ if((hdr->id_len - 1) >= (unsigned)(hdr->sizeof_addr + hdr->sizeof_size + 4 + hdr->sizeof_size)) {
+ /* Indicate that v2 B-tree doesn't have to be used to locate object */
+ hdr->huge_ids_direct = TRUE;
+
+ /* Set the size of 'huge' object IDs */
+ hdr->huge_id_size = (uint8_t)(hdr->sizeof_addr + hdr->sizeof_size + hdr->sizeof_size);
+ } /* end if */
+ else
+ /* Indicate that v2 B-tree must be used to access object */
+ hdr->huge_ids_direct = FALSE;
+ } /* end if */
+ else {
+ if((hdr->sizeof_addr + hdr->sizeof_size) <= (hdr->id_len - 1)) {
+ /* Indicate that v2 B-tree doesn't have to be used to locate object */
+ hdr->huge_ids_direct = TRUE;
+
+ /* Set the size of 'huge' object IDs */
+ hdr->huge_id_size = (uint8_t)(hdr->sizeof_addr + hdr->sizeof_size);
+ } /* end if */
+ else
+ /* Indicate that v2 B-tree must be used to locate object */
+ hdr->huge_ids_direct = FALSE;
+ } /* end else */
+ if(!hdr->huge_ids_direct) {
+ /* Set the size and maximum value of 'huge' object ID */
+ if((hdr->id_len - 1) < sizeof(hsize_t)) {
+ hdr->huge_id_size = (uint8_t)(hdr->id_len - 1);
+ hdr->huge_max_id = ((hsize_t)1 << (hdr->huge_id_size * 8)) - 1;
+ } /*end if */
+ else {
+ hdr->huge_id_size = sizeof(hsize_t);
+ hdr->huge_max_id = HSIZET_MAX;
+ } /* end else */
+ } /* end if */
+ hdr->huge_bt2 = NULL;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_huge_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_new_id
+ *
+ * Purpose: Determine a new ID for an indirectly accessed 'huge' object
+ * (either filtered or not)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5HF_huge_new_id(H5HF_hdr_t *hdr)
+{
+ hsize_t new_id; /* New object's ID */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check for wrapping around 'huge' object ID space */
+ if(hdr->huge_ids_wrapped)
+ /* Fail for now - eventually should iterate through v2 B-tree, looking for available ID */
+ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, 0, "wrapping 'huge' object IDs not supported yet")
+ else {
+ /* Get new 'huge' object ID to use for object */
+ /* (avoids using ID 0) */
+ new_id = ++hdr->huge_next_id;
+
+ /* Check for wrapping 'huge' object IDs around */
+ if(hdr->huge_next_id == hdr->huge_max_id)
+ hdr->huge_ids_wrapped = TRUE;
+ } /* end else */
+
+ /* Set return value */
+ ret_value = new_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_new_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_insert
+ *
+ * Purpose: Insert a 'huge' object into the file and track it
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t obj_size, void *obj,
+ void *_id)
+{
+ uint8_t *id = (uint8_t *)_id; /* Pointer to ID buffer */
+ haddr_t obj_addr; /* Address of object in the file */
+ void *write_buf; /* Pointer to buffer to write */
+ size_t write_size; /* Size of [possibly filtered] object written to file */
+ unsigned filter_mask = 0; /* Filter mask for object (only used for filtered objects) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef QAK
+HDfprintf(stderr, "%s: obj_size = %Zu\n", FUNC, obj_size);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(obj_size > hdr->max_man_size);
+ HDassert(obj);
+ HDassert(id);
+
+ /* Check if the v2 B-tree for tracking 'huge' heap objects has been created yet */
+ if(!H5F_addr_defined(hdr->huge_bt2_addr)) {
+ /* Go create (& open) v2 B-tree */
+ if(H5HF_huge_bt2_create(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+ else {
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+ } /* end else */
+ HDassert(hdr->huge_bt2);
+
+ /* Check for I/O pipeline filter on heap */
+ if(hdr->filter_len > 0) {
+ H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */
+ size_t nbytes; /* Number of bytes used */
+
+ /* Allocate buffer to perform I/O filtering on */
+ write_size = obj_size;
+ if(NULL == (write_buf = H5MM_malloc(write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer")
+ HDmemcpy(write_buf, obj, write_size);
+
+ /* Push direct block data through I/O filter pipeline */
+ nbytes = write_size;
+ if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_NO_EDC,
+ filter_cb, &nbytes, &write_size, &write_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "output pipeline failed")
+#ifdef QAK
+HDfprintf(stderr, "%s: nbytes = %Zu, write_size = %Zu, write_buf = %p\n", FUNC, nbytes, write_size, write_buf);
+HDfprintf(stderr, "%s: obj_size = %Zu, obj = %p\n", FUNC, obj_size, obj);
+#endif /* QAK */
+
+ /* Update size of object on disk */
+ write_size = nbytes;
+ } /* end if */
+ else {
+ write_buf = obj;
+ write_size = obj_size;
+ } /* end else */
+
+ /* Allocate space in the file for storing the 'huge' object */
+ if(HADDR_UNDEF == (obj_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, dxpl_id, (hsize_t)write_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap huge object")
+
+ /* Write the object's data to disk */
+ if(H5F_block_write(hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, obj_addr, write_size, H5AC_rawdata_dxpl_id, write_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "writing 'huge' object to file failed")
+
+ /* Release buffer for writing, if we had one */
+ if(write_buf != obj) {
+ HDassert(hdr->filter_len > 0);
+ H5MM_xfree(write_buf);
+ } /* end if */
+
+ /* Perform different actions for directly & indirectly accessed 'huge' objects */
+ if(hdr->huge_ids_direct) {
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_dir_rec_t obj_rec; /* Record for tracking object */
+
+ /* Initialize record for tracking object in v2 B-tree */
+ obj_rec.addr = obj_addr;
+ obj_rec.len = write_size;
+ obj_rec.filter_mask = filter_mask;
+ obj_rec.obj_size = obj_size;
+#ifdef QAK
+HDfprintf(stderr, "%s: obj_rec = {%a, %Hu, %x, %Hu}\n", FUNC, obj_rec.addr, obj_rec.len, obj_rec.filter_mask, obj_rec.obj_size);
+#endif /* QAK */
+
+ /* Insert record for object in v2 B-tree */
+ if(H5B2_insert(hdr->huge_bt2, dxpl_id, &obj_rec) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "couldn't insert object tracking record in v2 B-tree")
+
+ /* Encode ID for user */
+ *id++ = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_HUGE;
+ H5F_addr_encode(hdr->f, &id, obj_addr);
+ H5F_ENCODE_LENGTH(hdr->f, id, (hsize_t)write_size);
+ UINT32ENCODE(id, filter_mask);
+ H5F_ENCODE_LENGTH(hdr->f, id, (hsize_t)obj_size);
+ } /* end if */
+ else {
+ H5HF_huge_bt2_dir_rec_t obj_rec; /* Record for tracking object */
+
+ /* Initialize record for tracking object in v2 B-tree */
+ obj_rec.addr = obj_addr;
+ obj_rec.len = write_size;
+#ifdef QAK
+HDfprintf(stderr, "%s: obj_rec = {%a, %Hu}\n", FUNC, obj_rec.addr, obj_rec.len);
+#endif /* QAK */
+
+ /* Insert record for object in v2 B-tree */
+ if(H5B2_insert(hdr->huge_bt2, dxpl_id, &obj_rec) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "couldn't insert object tracking record in v2 B-tree")
+
+ /* Encode ID for user */
+ *id++ = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_HUGE;
+ H5F_addr_encode(hdr->f, &id, obj_addr);
+ H5F_ENCODE_LENGTH(hdr->f, id, (hsize_t)write_size);
+ } /* end if */
+ } /* end if */
+ else {
+ H5HF_huge_bt2_filt_indir_rec_t filt_indir_rec; /* Record for tracking filtered object */
+ H5HF_huge_bt2_indir_rec_t indir_rec; /* Record for tracking non-filtered object */
+ void *ins_rec; /* Pointer to record to insert */
+ hsize_t new_id; /* New ID for object */
+
+ /* Get new ID for object */
+ if(0 == (new_id = H5HF_huge_new_id(hdr)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't generate new ID for object")
+
+ if(hdr->filter_len > 0) {
+ /* Initialize record for object in v2 B-tree */
+ filt_indir_rec.addr = obj_addr;
+ filt_indir_rec.len = write_size;
+ filt_indir_rec.filter_mask = filter_mask;
+ filt_indir_rec.obj_size = obj_size;
+ filt_indir_rec.id = new_id;
+#ifdef QAK
+HDfprintf(stderr, "%s: filt_indir_rec = {%a, %Hu, %x, %Hu, %Hu}\n", FUNC, filt_indir_rec.addr, filt_indir_rec.len, filt_indir_rec.filter_mask, filt_indir_rec.obj_size, filt_indir_rec.id);
+#endif /* QAK */
+
+ /* Set pointer to record to insert */
+ ins_rec = &filt_indir_rec;
+ } /* end if */
+ else {
+ /* Initialize record for object in v2 B-tree */
+ indir_rec.addr = obj_addr;
+ indir_rec.len = write_size;
+ indir_rec.id = new_id;
+#ifdef QAK
+HDfprintf(stderr, "%s: indir_rec = {%a, %Hu, %Hu}\n", FUNC, indir_rec.addr, indir_rec.len, indir_rec.id);
+#endif /* QAK */
+
+ /* Set pointer to record to insert */
+ ins_rec = &indir_rec;
+ } /* end else */
+
+ /* Insert record for tracking object in v2 B-tree */
+ if(H5B2_insert(hdr->huge_bt2, dxpl_id, ins_rec) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "couldn't insert object tracking record in v2 B-tree")
+
+ /* Encode ID for user */
+ *id++ = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_HUGE;
+ UINT64ENCODE_VAR(id, new_id, hdr->huge_id_size)
+ } /* end else */
+
+ /* Update statistics about heap */
+ hdr->huge_size += obj_size;
+ hdr->huge_nobjs++;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_get_obj_len
+ *
+ * Purpose: Get the size of a 'huge' object in a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_get_obj_len(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ size_t *obj_len_p)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+ HDassert(id);
+ HDassert(obj_len_p);
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Check if 'huge' object ID encodes address & length directly */
+ if(hdr->huge_ids_direct) {
+ if(hdr->filter_len > 0) {
+ /* Skip over filtered object info */
+ id += hdr->sizeof_addr + hdr->sizeof_size + 4;
+
+ /* Retrieve the object's length */
+ H5F_DECODE_LENGTH(hdr->f, id, *obj_len_p);
+ } /* end if */
+ else {
+ /* Skip over object offset in file */
+ id += hdr->sizeof_addr;
+
+ /* Retrieve the object's length */
+ H5F_DECODE_LENGTH(hdr->f, id, *obj_len_p);
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_filt_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_filt_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's length */
+ *obj_len_p = (size_t)found_rec.obj_size;
+ } /* end if */
+ else {
+ H5HF_huge_bt2_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's length */
+ *obj_len_p = (size_t)found_rec.len;
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_get_obj_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__huge_get_obj_off
+ *
+ * Purpose: Get the offset of a 'huge' object in a fractal heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF__huge_get_obj_off(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ hsize_t *obj_off_p)
+{
+ haddr_t obj_addr; /* Object's address in the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+ HDassert(id);
+ HDassert(obj_off_p);
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Check if 'huge' object ID encodes address & length directly */
+ if(hdr->huge_ids_direct) {
+ /* Retrieve the object's address (common) */
+ H5F_addr_decode(hdr->f, &id, &obj_addr);
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_filt_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_filt_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's address & length */
+ obj_addr = found_rec.addr;
+ } /* end if */
+ else {
+ H5HF_huge_bt2_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's address & length */
+ obj_addr = found_rec.addr;
+ } /* end else */
+ } /* end else */
+
+ /* Set the value to return */
+ *obj_off_p = (hsize_t)obj_addr;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF__huge_get_obj_off() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_op_real
+ *
+ * Purpose: Internal routine to perform an operation on a 'huge' object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_huge_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ hbool_t is_read, H5HF_operator_t op, void *op_data)
+{
+ void *read_buf = NULL; /* Pointer to buffer for reading */
+ haddr_t obj_addr; /* Object's address in the file */
+ size_t obj_size = 0; /* Object's size in the file */
+ unsigned filter_mask = 0; /* Filter mask for object (only used for filtered objects) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(is_read || op);
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Check for 'huge' object ID that encodes address & length directly */
+ if(hdr->huge_ids_direct) {
+ /* Retrieve the object's address and length (common) */
+ H5F_addr_decode(hdr->f, &id, &obj_addr);
+ H5F_DECODE_LENGTH(hdr->f, id, obj_size);
+
+ /* Retrieve extra information needed for filtered objects */
+ if(hdr->filter_len > 0)
+ UINT32DECODE(id, filter_mask);
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_filt_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_filt_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's address & length */
+ obj_addr = found_rec.addr;
+ H5_CHECKED_ASSIGN(obj_size, size_t, found_rec.len, hsize_t);
+ filter_mask = found_rec.filter_mask;
+ } /* end if */
+ else {
+ H5HF_huge_bt2_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's address & length */
+ obj_addr = found_rec.addr;
+ H5_CHECKED_ASSIGN(obj_size, size_t, found_rec.len, hsize_t);
+ } /* end else */
+ } /* end else */
+
+ /* Set up buffer for reading */
+ if(hdr->filter_len > 0 || !is_read) {
+ if(NULL == (read_buf = H5MM_malloc((size_t)obj_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer")
+ } /* end if */
+ else
+ read_buf = op_data;
+
+ /* Read the object's (possibly filtered) data from the file */
+ /* (reads directly into application's buffer if no filters are present) */
+ if(H5F_block_read(hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, obj_addr, (size_t)obj_size, H5AC_rawdata_dxpl_id, read_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_READERROR, FAIL, "can't read 'huge' object's data from the file")
+
+ /* Check for I/O pipeline filter on heap */
+ if(hdr->filter_len > 0) {
+ H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */
+ size_t read_size; /* Object's size in the file */
+ size_t nbytes; /* Number of bytes used */
+
+ /* De-filter the object */
+ read_size = nbytes = obj_size;
+ if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_NO_EDC, filter_cb, &nbytes, &read_size, &read_buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "input filter failed")
+ obj_size = nbytes;
+ } /* end if */
+
+ /* Perform correct operation on buffer read in */
+ if(is_read) {
+ /* Copy object to user's buffer if there's filters on heap data */
+ /* (if there's no filters, the object was read directly into the user's buffer) */
+ if(hdr->filter_len > 0)
+ HDmemcpy(op_data, read_buf, (size_t)obj_size);
+ } /* end if */
+ else {
+ /* Call the user's 'op' callback */
+ if(op(read_buf, (size_t)obj_size, op_data) < 0) {
+ /* Release buffer */
+ read_buf = H5MM_xfree(read_buf);
+
+ /* Indicate error */
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "application's callback failed")
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the buffer for reading */
+ if(read_buf && read_buf != op_data)
+ read_buf = H5MM_xfree(read_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_op_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_write
+ *
+ * Purpose: Write a 'huge' object to the heap
+ *
+ * Note: This implementation somewhat limited: it doesn't handle
+ * heaps with filters, which would require re-compressing the
+ * huge object and probably changing the address of the object
+ * on disk (and possibly the heap ID for "direct" huge IDs).
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 21 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ const void *obj)
+{
+ haddr_t obj_addr; /* Object's address in the file */
+ size_t obj_size; /* Object's size in the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Check for filters on the heap */
+ if(hdr->filter_len > 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'huge' object with filters not supported yet")
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Check for 'huge' object ID that encodes address & length directly */
+ if(hdr->huge_ids_direct) {
+ /* Retrieve the object's address and length (common) */
+ H5F_addr_decode(hdr->f, &id, &obj_addr);
+ H5F_DECODE_LENGTH(hdr->f, id, obj_size);
+ } /* end if */
+ else {
+ H5HF_huge_bt2_indir_rec_t found_rec; /* Record found from tracking object */
+ H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Sanity check */
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Look up object in v2 B-tree */
+ if(H5B2_find(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_indir_found, &found_rec) != TRUE)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree")
+
+ /* Retrieve the object's address & length */
+ obj_addr = found_rec.addr;
+ H5_CHECKED_ASSIGN(obj_size, size_t, found_rec.len, hsize_t);
+ } /* end else */
+
+ /* Write the object's data to the file */
+ /* (writes directly from application's buffer) */
+ if(H5F_block_write(hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, obj_addr, obj_size, H5AC_rawdata_dxpl_id, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "writing 'huge' object to file failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_read
+ *
+ * Purpose: Read a 'huge' object from the heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sept 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_read(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, void *obj)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Call the internal 'op' routine */
+ if(H5HF_huge_op_real(hdr, dxpl_id, id, TRUE, NULL, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_op
+ *
+ * Purpose: Operate directly on a 'huge' object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sept 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_op(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ H5HF_operator_t op, void *op_data)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(op);
+
+ /* Call the internal 'op' routine routine */
+ if(H5HF_huge_op_real(hdr, dxpl_id, id, FALSE, op, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_remove
+ *
+ * Purpose: Remove a 'huge' object from the file and the v2 B-tree tracker
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id)
+{
+ H5HF_huge_remove_ud_t udata; /* User callback data for v2 B-tree remove call */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+ HDassert(id);
+
+ /* Check if v2 B-tree is open yet */
+ if(NULL == hdr->huge_bt2) {
+ /* Open existing v2 B-tree */
+ if(NULL == (hdr->huge_bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' heap objects")
+ } /* end if */
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Set up the common callback info */
+ udata.hdr = hdr;
+ udata.dxpl_id = dxpl_id;
+
+ /* Check for 'huge' object ID that encodes address & length directly */
+ if(hdr->huge_ids_direct) {
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_dir_rec_t search_rec; /* Record for searching for object */
+
+ /* Retrieve the object's address and length */
+ /* (used as key in v2 B-tree record) */
+ H5F_addr_decode(hdr->f, &id, &search_rec.addr);
+ H5F_DECODE_LENGTH(hdr->f, id, search_rec.len);
+
+ /* Remove the record for tracking the 'huge' object from the v2 B-tree */
+ /* (space in the file for the object is freed in the 'remove' callback) */
+ if(H5B2_remove(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_filt_dir_remove, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree")
+ } /* end if */
+ else {
+ H5HF_huge_bt2_dir_rec_t search_rec; /* Record for searching for object */
+
+ /* Retrieve the object's address and length */
+ /* (used as key in v2 B-tree record) */
+ H5F_addr_decode(hdr->f, &id, &search_rec.addr);
+ H5F_DECODE_LENGTH(hdr->f, id, search_rec.len);
+
+ /* Remove the record for tracking the 'huge' object from the v2 B-tree */
+ /* (space in the file for the object is freed in the 'remove' callback) */
+ if(H5B2_remove(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_dir_remove, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree")
+ } /* end else */
+ } /* end if */
+ else {
+ if(hdr->filter_len > 0) {
+ H5HF_huge_bt2_filt_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Remove the record for tracking the 'huge' object from the v2 B-tree */
+ /* (space in the file for the object is freed in the 'remove' callback) */
+ if(H5B2_remove(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_filt_indir_remove, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree")
+ } /* end if */
+ else {
+ H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */
+
+ /* Get ID for looking up 'huge' object in v2 B-tree */
+ UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size)
+
+ /* Remove the record for tracking the 'huge' object from the v2 B-tree */
+ /* (space in the file for the object is freed in the 'remove' callback) */
+ if(H5B2_remove(hdr->huge_bt2, dxpl_id, &search_rec, H5HF__huge_bt2_indir_remove, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree")
+ } /* end else */
+ } /* end else */
+
+ /* Update statistics about heap */
+ hdr->huge_size -= udata.obj_len;
+ hdr->huge_nobjs--;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_term
+ *
+ * Purpose: Shut down the information for tracking 'huge' objects
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_term(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check if v2 B-tree index is open */
+ if(hdr->huge_bt2) {
+ /* Sanity check */
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+
+ /* Close v2 B-tree index */
+ if(H5B2_close(hdr->huge_bt2, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree")
+ hdr->huge_bt2 = NULL;
+ } /* end if */
+
+ /* Check if there are no more 'huge' objects in the heap and delete the
+ * v2 B-tree that tracks them, if so
+ */
+ if(H5F_addr_defined(hdr->huge_bt2_addr) && hdr->huge_nobjs == 0) {
+ /* Sanity check */
+ HDassert(hdr->huge_size == 0);
+
+ /* Delete the v2 B-tree */
+ /* (any v2 B-tree class will work here) */
+ if(H5B2_delete(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree")
+
+ /* Reset the information about 'huge' objects in the file */
+ hdr->huge_bt2_addr = HADDR_UNDEF;
+ hdr->huge_next_id = 0;
+ hdr->huge_ids_wrapped = FALSE;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_term() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_huge_delete
+ *
+ * Purpose: Delete all the 'huge' objects in the heap, and the v2 B-tree
+ * tracker for them
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_huge_delete(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ H5HF_huge_remove_ud_t udata; /* User callback data for v2 B-tree remove call */
+ H5B2_remove_t op; /* Callback for v2 B-tree removal */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(hdr->huge_bt2_addr));
+ HDassert(hdr->huge_nobjs);
+ HDassert(hdr->huge_size);
+
+ /* Set up the callback info */
+ udata.hdr = hdr;
+ udata.dxpl_id = dxpl_id;
+
+ /* Set the v2 B-tree callback operator */
+ if(hdr->huge_ids_direct) {
+ if(hdr->filter_len > 0)
+ op = H5HF__huge_bt2_filt_dir_remove;
+ else
+ op = H5HF__huge_bt2_dir_remove;
+ } /* end if */
+ else {
+ if(hdr->filter_len > 0)
+ op = H5HF__huge_bt2_filt_indir_remove;
+ else
+ op = H5HF__huge_bt2_indir_remove;
+ } /* end else */
+
+ /* Delete the v2 B-tree */
+ if(H5B2_delete(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f, op, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_huge_delete() */
+
diff --git a/src/H5HFiblock.c b/src/H5HFiblock.c
new file mode 100644
index 0000000..11abce0
--- /dev/null
+++ b/src/H5HFiblock.c
@@ -0,0 +1,1781 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFiblock.c
+ * Apr 10 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Indirect block routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5HF_iblock_pin(H5HF_indirect_t *iblock);
+static herr_t H5HF_iblock_unpin(H5HF_indirect_t *iblock);
+static herr_t H5HF_man_iblock_root_halve(H5HF_indirect_t *root_iblock, hid_t dxpl_id);
+static herr_t H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5HF_indirect_t struct */
+H5FL_DEFINE(H5HF_indirect_t);
+
+/* Declare a free list to manage the H5HF_indirect_ent_t sequence information */
+H5FL_SEQ_DEFINE(H5HF_indirect_ent_t);
+
+/* Declare a free list to manage the H5HF_indirect_filt_ent_t sequence information */
+H5FL_SEQ_DEFINE(H5HF_indirect_filt_ent_t);
+
+/* Declare a free list to manage the H5HF_indirect_t * sequence information */
+H5FL_SEQ_DEFINE(H5HF_indirect_ptr_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_pin
+ *
+ * Purpose: Pin an indirect block in memory
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_iblock_pin(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(iblock);
+
+ /* Mark block as un-evictable */
+ if(H5AC_pin_protected_entry(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap indirect block")
+
+ /* If this indirect block has a parent, update it's child iblock pointer */
+ if(iblock->parent) {
+ H5HF_indirect_t *par_iblock = iblock->parent; /* Parent indirect block */
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(par_iblock->child_iblocks);
+ HDassert(iblock->par_entry >= (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width));
+
+ /* Compute index in parent's child iblock pointer array */
+ indir_idx = iblock->par_entry - (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width);
+
+ /* Set pointer to pinned indirect block in parent */
+ HDassert(par_iblock->child_iblocks[indir_idx] == NULL);
+ par_iblock->child_iblocks[indir_idx] = iblock;
+ } /* end if */
+ else {
+ /* Check for pinning the root indirect block */
+ if(iblock->block_off == 0) {
+ /* Sanity check - shouldn't be recursively pinning root indirect block */
+ HDassert(0 == (iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED));
+
+ /* Check if we should set the root iblock pointer */
+ if(0 == iblock->hdr->root_iblock_flags) {
+ HDassert(NULL == iblock->hdr->root_iblock);
+ iblock->hdr->root_iblock = iblock;
+ } /* end if */
+
+ /* Indicate that the root indirect block is pinned */
+ iblock->hdr->root_iblock_flags |= H5HF_ROOT_IBLOCK_PINNED;
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_pin() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_unpin
+ *
+ * Purpose: Unpin an indirect block in the metadata cache
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_iblock_unpin(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* If this indirect block has a parent, reset it's child iblock pointer */
+ if(iblock->parent) {
+ H5HF_indirect_t *par_iblock = iblock->parent; /* Parent indirect block */
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(par_iblock->child_iblocks);
+ HDassert(iblock->par_entry >= (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width));
+
+ /* Compute index in parent's child iblock pointer array */
+ indir_idx = iblock->par_entry - (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width);
+
+ /* Reset pointer to pinned child indirect block in parent */
+ HDassert(par_iblock->child_iblocks[indir_idx]);
+ par_iblock->child_iblocks[indir_idx] = NULL;
+ } /* end if */
+ else {
+ /* Check for root indirect block */
+ if(iblock->block_off == 0) {
+ /* Sanity check - shouldn't be recursively unpinning root indirect block */
+ HDassert(iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PINNED);
+
+ /* Check if we should reset the root iblock pointer */
+ if(H5HF_ROOT_IBLOCK_PINNED == iblock->hdr->root_iblock_flags) {
+ HDassert(NULL != iblock->hdr->root_iblock);
+ iblock->hdr->root_iblock = NULL;
+ } /* end if */
+
+ /* Indicate that the root indirect block is unpinned */
+ iblock->hdr->root_iblock_flags &= (unsigned)(~(H5HF_ROOT_IBLOCK_PINNED));
+ } /* end if */
+ } /* end else */
+
+ /* Mark block as evictable again */
+ if(H5AC_unpin_entry(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap indirect block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_unpin() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_incr
+ *
+ * Purpose: Increment reference count on shared indirect block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_iblock_incr(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(iblock);
+ HDassert(iblock->block_off == 0 || iblock->parent);
+
+ /* Mark block as un-evictable when a child block is depending on it */
+ if(iblock->rc == 0)
+ if(H5HF_iblock_pin(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin fractal heap indirect block")
+
+ /* Increment reference count on shared indirect block */
+ iblock->rc++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_incr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_decr
+ *
+ * Purpose: Decrement reference count on shared indirect block
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_iblock_decr(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* Decrement reference count on shared indirect block */
+ iblock->rc--;
+
+ /* Mark block as evictable again when no child blocks depend on it */
+ if(iblock->rc == 0) {
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ haddr_t iblock_addr; /* Address of fractal heap */
+ hbool_t expunge_iblock = FALSE; /* Whether to expunge indirect block from heap */
+
+ /* Set up convenience variables */
+ hdr = iblock->hdr;
+ iblock_addr = iblock->addr;
+
+ if(iblock->nchildren == 0) {
+ /* Check for deleting root indirect block (and no root direct block) */
+ if(iblock->block_off == 0 && hdr->man_dtable.curr_root_rows > 0) {
+ /* Reset root pointer information */
+ hdr->man_dtable.curr_root_rows = 0;
+ hdr->man_dtable.table_addr = HADDR_UNDEF;
+
+ /* Reset header information back to "empty heap" state */
+ if(H5HF_hdr_empty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty")
+ } /* end if */
+
+ /* Detach from parent indirect block */
+ if(iblock->parent) {
+ /* Detach from parent indirect block */
+ if(H5HF_man_iblock_detach(iblock->parent, H5AC_ind_read_dxpl_id, iblock->par_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block")
+ iblock->parent = NULL;
+ iblock->par_entry = 0;
+ } /* end if */
+
+ /* Mark indirect block for removal from the metadata cache */
+ expunge_iblock = TRUE;
+ } /* end if */
+
+ /* Unpin the indirect block */
+ if(H5HF_iblock_unpin(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap indirect block")
+
+ /* Check for expunging the indirect block from the metadata cache */
+ if(expunge_iblock) {
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+
+ /* if the indirect block is in real file space, tell
+ * the cache to free its file space.
+ */
+ if (!H5F_IS_TMP_ADDR(hdr->f, iblock_addr))
+ cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+ if(H5AC_expunge_entry(hdr->f, H5AC_ind_read_dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, cache_flags) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove indirect block from cache")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_iblock_dirty
+ *
+ * Purpose: Mark indirect block as dirty
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_iblock_dirty(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(iblock);
+
+ /* Mark indirect block as dirty in cache */
+ if(H5AC_mark_entry_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap indirect block as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_iblock_dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_root_create
+ *
+ * Purpose: Create root indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size)
+{
+ H5HF_indirect_t *iblock; /* Pointer to indirect block */
+ haddr_t iblock_addr; /* Indirect block's address */
+ hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
+ hbool_t have_direct_block; /* Flag to indicate a direct block already exists */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ unsigned nrows; /* Number of rows for root indirect block */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check for allocating entire root indirect block initially */
+ if(hdr->man_dtable.cparam.start_root_rows == 0)
+ nrows = hdr->man_dtable.max_root_rows;
+ else {
+ unsigned rows_needed; /* Number of rows needed to get to direct block size */
+ unsigned block_row_off; /* Row offset from larger block sizes */
+
+ nrows = hdr->man_dtable.cparam.start_root_rows;
+
+ block_row_off = H5VM_log2_of2((uint32_t)min_dblock_size) - H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size);
+ if(block_row_off > 0)
+ block_row_off++; /* Account for the pair of initial rows of the initial block size */
+ rows_needed = 1 + block_row_off;
+ if(nrows < rows_needed)
+ nrows = rows_needed;
+ } /* end else */
+
+ /* Allocate root indirect block */
+ if(H5HF_man_iblock_create(hdr, dxpl_id, NULL, 0, nrows, hdr->man_dtable.max_root_rows, &iblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block")
+
+ /* Move current direct block (used as root) into new indirect block */
+
+ /* Lock new indirect block */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, NULL, 0, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Check if there's already a direct block as root) */
+ have_direct_block = H5F_addr_defined(hdr->man_dtable.table_addr);
+ if(have_direct_block) {
+ H5HF_direct_t *dblock; /* Pointer to direct block to query */
+
+ /* Lock first (root) direct block */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.cparam.start_block_size, NULL, 0, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
+
+ /* Attach direct block to new root indirect block */
+ dblock->parent = iblock;
+ dblock->fd_parent = iblock;
+ dblock->par_entry = 0;
+
+ /* destroy flush dependency between direct block and header */
+ if(H5AC_destroy_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* create flush dependency between direct block and new root indirect block */
+ if(H5AC_create_flush_dependency(dblock->parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+ if(H5HF_man_iblock_attach(iblock, 0, hdr->man_dtable.table_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach root direct block to parent indirect block")
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /* Set the pipeline filter information from the header */
+ iblock->filt_ents[0].size = hdr->pline_root_direct_size;
+ iblock->filt_ents[0].filter_mask = hdr->pline_root_direct_filter_mask;
+
+ /* Reset the header's pipeline information */
+ hdr->pline_root_direct_size = 0;
+ hdr->pline_root_direct_filter_mask = 0;
+ } /* end if */
+
+ /* Scan free space sections to set any 'parent' pointers to new indirect block */
+ if(H5HF_space_create_root(hdr, dxpl_id, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set free space section info to new root indirect block")
+
+ /* Unlock first (previously the root) direct block */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
+ dblock = NULL;
+ } /* end if */
+
+ /* Start iterator at correct location */
+ if(H5HF_hdr_start_iter(hdr, iblock, (hsize_t)(have_direct_block ? hdr->man_dtable.cparam.start_block_size : 0), have_direct_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator")
+
+ /* Check for skipping over direct blocks, in order to get to large enough block */
+ if(min_dblock_size > hdr->man_dtable.cparam.start_block_size) {
+ /* Add skipped blocks to heap's free space */
+ if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, have_direct_block,
+ ((nrows - 1) * hdr->man_dtable.cparam.width) - have_direct_block) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
+ } /* end if */
+
+ /* Mark indirect block as modified */
+ if(H5HF_iblock_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Unprotect root indirect block (it's pinned by the iterator though) */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__DIRTIED_FLAG, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ iblock = NULL;
+
+ /* Point heap header at new indirect block */
+ hdr->man_dtable.curr_root_rows = nrows;
+ hdr->man_dtable.table_addr = iblock_addr;
+
+ /* Compute free space in direct blocks referenced from entries in root indirect block */
+ acc_dblock_free = 0;
+ for(u = 0; u < nrows; u++)
+ acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[u] * hdr->man_dtable.cparam.width;
+
+ /* Account for potential initial direct block */
+ if(have_direct_block)
+ acc_dblock_free -= hdr->man_dtable.row_tot_dblock_free[0];
+
+ /* Extend heap to cover new root indirect block */
+ if(H5HF_hdr_adjust_heap(hdr, hdr->man_dtable.row_block_off[nrows], (hssize_t)acc_dblock_free) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_root_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_root_double
+ *
+ * Purpose: Double size of root indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_root_double(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size)
+{
+ H5HF_indirect_t *iblock; /* Pointer to root indirect block */
+ haddr_t new_addr; /* New address of indirect block */
+ hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
+ hsize_t next_size; /* The previous value of the "next size" for the new block iterator */
+ hsize_t old_iblock_size; /* Old size of indirect block */
+ unsigned next_row; /* The next row to allocate block in */
+ unsigned next_entry; /* The previous value of the "next entry" for the new block iterator */
+ unsigned new_next_entry = 0;/* The new value of the "next entry" for the new block iterator */
+ unsigned min_nrows = 0; /* Min. # of direct rows */
+ unsigned old_nrows; /* Old # of rows */
+ unsigned new_nrows; /* New # of rows */
+ hbool_t skip_direct_rows = FALSE; /* Whether we are skipping direct rows */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get "new block" iterator information */
+ if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
+ next_size = hdr->man_dtable.row_block_size[next_row];
+
+ /* Make certain the iterator is at the root indirect block */
+ HDassert(iblock->parent == NULL);
+ HDassert(iblock->block_off == 0);
+
+ /* Keep this for later */
+ old_nrows = iblock->nrows;
+
+ /* Check for skipping over direct block rows */
+ if(iblock->nrows < hdr->man_dtable.max_direct_rows && min_dblock_size > next_size) {
+ /* Sanity check */
+ HDassert(min_dblock_size > hdr->man_dtable.cparam.start_block_size);
+
+ /* Set flag */
+ skip_direct_rows = TRUE;
+
+ /* Make certain we allocate at least the required row for the block requested */
+ min_nrows = 1 + H5HF_dtable_size_to_row(&hdr->man_dtable, min_dblock_size);
+
+ /* Set the information for the next block, of the appropriate size */
+ new_next_entry = (min_nrows - 1) * hdr->man_dtable.cparam.width;
+ } /* end if */
+
+ /* Compute new # of rows in indirect block */
+ new_nrows = MAX(min_nrows, MIN(2 * iblock->nrows, iblock->max_rows));
+
+ /* Check if the indirect block is NOT currently allocated in temp. file space */
+ /* (temp. file space does not need to be freed) */
+ if(!H5F_IS_TMP_ADDR(hdr->f, iblock->addr)) {
+/* Currently, the old block data is "thrown away" after the space is reallocated,
+* to avoid data copy in H5MF_realloc() call by just free'ing the space and
+* allocating new space.
+*
+* This also keeps the file smaller, by freeing the space and then
+* allocating new space, instead of vice versa (in H5MF_realloc).
+*
+* QAK - 3/14/2006
+*/
+ /* Free previous indirect block disk space */
+ if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space")
+ } /* end if */
+
+ /* Compute size of buffer needed for new indirect block */
+ iblock->nrows = new_nrows;
+ old_iblock_size = iblock->size;
+ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
+
+ /* Allocate [temporary] space for the new indirect block on disk */
+ if(H5F_USE_TMP_SPACE(hdr->f)) {
+ if(HADDR_UNDEF == (new_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end if */
+ else {
+ if(HADDR_UNDEF == (new_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end else */
+
+ /* Resize pinned indirect block in the cache, if its changed size */
+ if(old_iblock_size != iblock->size) {
+ if(H5AC_resize_entry(iblock, (size_t)iblock->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap indirect block")
+ } /* end if */
+
+ /* Move object in cache, if it actually was relocated */
+ if(H5F_addr_ne(iblock->addr, new_addr)) {
+ if(H5AC_move_entry(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move fractal heap root indirect block")
+ iblock->addr = new_addr;
+ } /* end if */
+
+ /* Re-allocate child block entry array */
+ if(NULL == (iblock->ents = H5FL_SEQ_REALLOC(H5HF_indirect_ent_t, iblock->ents, (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for direct entries")
+
+ /* Check for skipping over rows and add free section for skipped rows */
+ if(skip_direct_rows) {
+ /* Add skipped blocks to heap's free space */
+ if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, next_entry, (new_next_entry - next_entry)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space")
+ } /* end if */
+
+ /* Initialize new direct block entries in rows added */
+ acc_dblock_free = 0;
+ for(u = (old_nrows * hdr->man_dtable.cparam.width); u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) {
+ unsigned row = (unsigned)(u / hdr->man_dtable.cparam.width); /* Row for current entry */
+
+ iblock->ents[u].addr = HADDR_UNDEF;
+ acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[row];
+ } /* end for */
+
+ /* Check for needing to re-allocate filtered entry array */
+ if(hdr->filter_len > 0 && old_nrows < hdr->man_dtable.max_direct_rows) {
+ unsigned dir_rows; /* Number of direct rows in this indirect block */
+
+ /* Compute the number of direct rows for this indirect block */
+ dir_rows = MIN(iblock->nrows, hdr->man_dtable.max_direct_rows);
+ HDassert(dir_rows > old_nrows);
+
+ /* Re-allocate filtered direct block entry array */
+ if(NULL == (iblock->filt_ents = H5FL_SEQ_REALLOC(H5HF_indirect_filt_ent_t, iblock->filt_ents, (size_t)(dir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
+
+ /* Initialize new entries allocated */
+ for(u = (old_nrows * hdr->man_dtable.cparam.width); u < (dir_rows * hdr->man_dtable.cparam.width); u++) {
+ iblock->filt_ents[u].size = 0;
+ iblock->filt_ents[u].filter_mask = 0;
+ } /* end for */
+ } /* end if */
+
+ /* Check for needing to re-allocate child iblock pointer array */
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned indir_rows; /* Number of indirect rows in this indirect block */
+ unsigned old_indir_rows; /* Previous number of indirect rows in this indirect block */
+
+ /* Compute the number of direct rows for this indirect block */
+ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
+
+ /* Re-allocate child indirect block array */
+ if(NULL == (iblock->child_iblocks = H5FL_SEQ_REALLOC(H5HF_indirect_ptr_t, iblock->child_iblocks, (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
+
+ /* Compute the previous # of indirect rows in this block */
+ if(old_nrows < hdr->man_dtable.max_direct_rows)
+ old_indir_rows = 0;
+ else
+ old_indir_rows = old_nrows - hdr->man_dtable.max_direct_rows;
+
+ /* Initialize new entries allocated */
+ for(u = (old_indir_rows * hdr->man_dtable.cparam.width); u < (indir_rows * hdr->man_dtable.cparam.width); u++)
+ iblock->child_iblocks[u] = NULL;
+ } /* end if */
+
+ /* Mark indirect block as dirty */
+ if(H5HF_iblock_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Update other shared header info */
+ hdr->man_dtable.curr_root_rows = new_nrows;
+ hdr->man_dtable.table_addr = new_addr;
+
+ /* Extend heap to cover new root indirect block */
+ if(H5HF_hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1], (hssize_t)acc_dblock_free) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_root_double() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_root_halve
+ *
+ * Purpose: Halve size of root indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jun 12 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_man_iblock_root_halve(H5HF_indirect_t *iblock, hid_t dxpl_id)
+{
+ H5HF_hdr_t *hdr = iblock->hdr; /* Pointer to heap header */
+ haddr_t new_addr; /* New address of indirect block */
+ hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */
+ hsize_t old_size; /* Old size of indirect block */
+ unsigned max_child_row; /* Row for max. child entry */
+ unsigned old_nrows; /* Old # of rows */
+ unsigned new_nrows; /* New # of rows */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(iblock);
+ HDassert(iblock->parent == NULL);
+ HDassert(hdr);
+
+ /* Compute maximum row used by child of indirect block */
+ max_child_row = iblock->max_child / hdr->man_dtable.cparam.width;
+
+ /* Compute new # of rows in root indirect block */
+ new_nrows = (unsigned)1 << (1 + H5VM_log2_gen((uint64_t)max_child_row));
+
+ /* Check if the indirect block is NOT currently allocated in temp. file space */
+ /* (temp. file space does not need to be freed) */
+ if(!H5F_IS_TMP_ADDR(hdr->f, iblock->addr)) {
+/* Currently, the old block data is "thrown away" after the space is reallocated,
+* to avoid data copy in H5MF_realloc() call by just free'ing the space and
+* allocating new space.
+*
+* This also keeps the file smaller, by freeing the space and then
+* allocating new space, instead of vice versa (in H5MF_realloc).
+*
+* QAK - 6/12/2006
+*/
+ /* Free previous indirect block disk space */
+ if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space")
+ } /* end if */
+
+ /* Compute free space in rows to delete */
+ acc_dblock_free = 0;
+ for(u = new_nrows; u < iblock->nrows; u++)
+ acc_dblock_free += hdr->man_dtable.row_tot_dblock_free[u] * hdr->man_dtable.cparam.width;
+
+ /* Compute size of buffer needed for new indirect block */
+ old_nrows = iblock->nrows;
+ iblock->nrows = new_nrows;
+ old_size = iblock->size;
+ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
+
+ /* Allocate [temporary] space for the new indirect block on disk */
+ if(H5F_USE_TMP_SPACE(hdr->f)) {
+ if(HADDR_UNDEF == (new_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end if */
+ else {
+ if(HADDR_UNDEF == (new_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end else */
+
+ /* Resize pinned indirect block in the cache, if it has changed size */
+ if(old_size != iblock->size) {
+ if(H5AC_resize_entry(iblock, (size_t)iblock->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize fractal heap indirect block")
+ } /* end if */
+
+ /* Move object in cache, if it actually was relocated */
+ if(H5F_addr_ne(iblock->addr, new_addr)) {
+ if(H5AC_move_entry(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSPLIT, FAIL, "unable to move fractal heap root indirect block")
+ iblock->addr = new_addr;
+ } /* end if */
+
+ /* Re-allocate child block entry array */
+ if(NULL == (iblock->ents = H5FL_SEQ_REALLOC(H5HF_indirect_ent_t, iblock->ents, (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct entries")
+
+ /* Check for needing to re-allocate filtered entry array */
+ if(hdr->filter_len > 0 && new_nrows < hdr->man_dtable.max_direct_rows) {
+ /* Re-allocate filtered direct block entry array */
+ if(NULL == (iblock->filt_ents = H5FL_SEQ_REALLOC(H5HF_indirect_filt_ent_t, iblock->filt_ents, (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
+ } /* end if */
+
+ /* Check for needing to re-allocate child iblock pointer array */
+ if(old_nrows > hdr->man_dtable.max_direct_rows) {
+ /* Check for shrinking away child iblock pointer array */
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned indir_rows; /* Number of indirect rows in this indirect block */
+
+ /* Compute the number of direct rows for this indirect block */
+ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
+
+ /* Re-allocate child indirect block array */
+ if(NULL == (iblock->child_iblocks = H5FL_SEQ_REALLOC(H5HF_indirect_ptr_t, iblock->child_iblocks, (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for filtered direct entries")
+ } /* end if */
+ else
+ iblock->child_iblocks = (H5HF_indirect_ptr_t *)H5FL_SEQ_FREE(H5HF_indirect_ptr_t, iblock->child_iblocks);
+ } /* end if */
+
+ /* Mark indirect block as dirty */
+ if(H5HF_iblock_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Update other shared header info */
+ hdr->man_dtable.curr_root_rows = new_nrows;
+ hdr->man_dtable.table_addr = new_addr;
+
+ /* Shrink heap to only cover new root indirect block */
+ if(H5HF_hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1], -(hssize_t)acc_dblock_free) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce space to cover root direct block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_root_halve() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_root_revert
+ *
+ * Purpose: Revert root indirect block back to root direct block
+ *
+ * Note: Any sections left pointing to the old root indirect block
+ * will be cleaned up by the free space manager
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id)
+{
+ H5HF_hdr_t *hdr; /* Pointer to heap's header */
+ H5HF_direct_t *dblock = NULL; /* Pointer to new root indirect block */
+ haddr_t dblock_addr; /* Direct block's address in the file */
+ size_t dblock_size; /* Direct block's size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(root_iblock);
+
+ /* Set up local convenience variables */
+ hdr = root_iblock->hdr;
+ dblock_addr = root_iblock->ents[0].addr;
+ dblock_size = hdr->man_dtable.cparam.start_block_size;
+
+ /* Get pointer to last direct block */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, root_iblock, 0, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
+ HDassert(dblock->parent == root_iblock);
+ HDassert(dblock->par_entry == 0);
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0) {
+ /* Set the header's pipeline information from the indirect block */
+ hdr->pline_root_direct_size = root_iblock->filt_ents[0].size;
+ hdr->pline_root_direct_filter_mask = root_iblock->filt_ents[0].filter_mask;
+ } /* end if */
+
+ /* Detach direct block from parent */
+ if(H5HF_man_iblock_detach(dblock->parent, dxpl_id, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach direct block from parent indirect block")
+ dblock->parent = NULL;
+ dblock->par_entry = 0;
+
+ /* destroy flush dependency between old root iblock and new root direct block*/
+ if(H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, \
+ "unable to destroy flush dependency")
+
+
+ /* create flush dependency between header and new root direct block */
+ if(H5AC_create_flush_dependency(dblock->hdr, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEPEND, FAIL, \
+ "unable to create flush dependency")
+
+ dblock->fd_parent = NULL;
+
+ /* Point root at direct block */
+ hdr->man_dtable.curr_root_rows = 0;
+ hdr->man_dtable.table_addr = dblock_addr;
+
+ /* Reset 'next block' iterator */
+ if(H5HF_hdr_reset_iter(hdr, (hsize_t)dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
+
+ /* Extend heap to just cover first direct block */
+ if(H5HF_hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size, (hssize_t)hdr->man_dtable.row_tot_dblock_free[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
+
+ /* Scan free space sections to reset any 'parent' pointers */
+ if(H5HF_space_revert_root(hdr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESET, FAIL, "can't reset free space section info")
+
+
+done:
+ if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_root_revert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_alloc_row
+ *
+ * Purpose: Allocate a "single" section for an object, out of a
+ * "row" section.
+ *
+ * Note: Creates necessary direct & indirect blocks
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_alloc_row(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t **sec_node)
+{
+ H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
+ H5HF_free_section_t *old_sec_node = *sec_node; /* Pointer to old indirect section node */
+ unsigned dblock_entry; /* Entry for direct block */
+ hbool_t iblock_held = FALSE; /* Flag to indicate that indirect block is held */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sec_node && old_sec_node);
+ HDassert(old_sec_node->u.row.row < hdr->man_dtable.max_direct_rows);
+
+ /* Check for serialized section */
+ if(old_sec_node->sect_info.state == H5FS_SECT_SERIALIZED) {
+ /* Revive indirect section */
+ if(H5HF_sect_row_revive(hdr, dxpl_id, old_sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
+ } /* end if */
+
+ /* Get a pointer to the indirect block covering the section */
+ if(NULL == (iblock = H5HF_sect_row_get_iblock(old_sec_node)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve indirect block for row section")
+
+ /* Hold indirect block in memory, until direct block can point to it */
+ if(H5HF_iblock_incr(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+ iblock_held = TRUE;
+
+ /* Reduce (& possibly re-add) 'row' section */
+ if(H5HF_sect_row_reduce(hdr, dxpl_id, old_sec_node, &dblock_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce row section node")
+
+ /* Create direct block & single section */
+ if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, dblock_entry, NULL, sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
+
+done:
+ /* Release hold on indirect block */
+ if(iblock_held)
+ if(H5HF_iblock_decr(iblock) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_alloc_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_create
+ *
+ * Purpose: Allocate & initialize a managed indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *par_iblock,
+ unsigned par_entry, unsigned nrows, unsigned max_rows, haddr_t *addr_p)
+{
+ H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(nrows > 0);
+ HDassert(addr_p);
+
+ /*
+ * Allocate file and memory data structures.
+ */
+ if(NULL == (iblock = H5FL_MALLOC(H5HF_indirect_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fractal heap indirect block")
+
+ /* Reset the metadata cache info for the heap header */
+ HDmemset(&iblock->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Share common heap information */
+ iblock->hdr = hdr;
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
+
+ /* Set info for direct block */
+ iblock->rc = 0;
+ iblock->nrows = nrows;
+ iblock->max_rows = max_rows;
+
+ /* Compute size of buffer needed for indirect block */
+ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows);
+
+ /* Allocate child block entry array */
+ if(NULL == (iblock->ents = H5FL_SEQ_MALLOC(H5HF_indirect_ent_t, (size_t)(iblock->nrows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
+
+ /* Initialize indirect block entry tables */
+ for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++)
+ iblock->ents[u].addr = HADDR_UNDEF;
+
+ /* Check for I/O filters to apply to this heap */
+ if(hdr->filter_len > 0) {
+ unsigned dir_rows; /* Number of direct rows in this indirect block */
+
+ /* Compute the number of direct rows for this indirect block */
+ dir_rows = MIN(iblock->nrows, hdr->man_dtable.max_direct_rows);
+
+ /* Allocate & initialize indirect block filtered entry array */
+ if(NULL == (iblock->filt_ents = H5FL_SEQ_CALLOC(H5HF_indirect_filt_ent_t, (size_t)(dir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
+ } /* end if */
+ else
+ iblock->filt_ents = NULL;
+
+ /* Check if we have any indirect block children */
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned indir_rows; /* Number of indirect rows in this indirect block */
+
+ /* Compute the number of indirect rows for this indirect block */
+ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows;
+
+ /* Allocate & initialize child indirect block pointer array */
+ if(NULL == (iblock->child_iblocks = H5FL_SEQ_CALLOC(H5HF_indirect_ptr_t, (size_t)(indir_rows * hdr->man_dtable.cparam.width))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for block entries")
+ } /* end if */
+ else
+ iblock->child_iblocks = NULL;
+
+ /* Allocate [temporary] space for the indirect block on disk */
+ if(H5F_USE_TMP_SPACE(hdr->f)) {
+ if(HADDR_UNDEF == (*addr_p = H5MF_alloc_tmp(hdr->f, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end if */
+ else {
+ if(HADDR_UNDEF == (*addr_p = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block")
+ } /* end else */
+ iblock->addr = *addr_p;
+
+ /* Attach to parent indirect block, if there is one */
+ iblock->parent = par_iblock;
+ iblock->fd_parent = par_iblock; /* this copy of the parent pointer is */
+ /* needed by the notify callback so */
+ /* that it can take down flush */
+ /* dependencies on eviction even if */
+ /* the parent pointer has been nulled */
+ /* out. JRM -- 5/18/14 */
+ iblock->par_entry = par_entry;
+ if(iblock->parent) {
+ /* Attach new block to parent */
+ if(H5HF_man_iblock_attach(iblock->parent, par_entry, *addr_p) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach indirect block to parent indirect block")
+
+ /* Compute the indirect block's offset in the heap's address space */
+ /* (based on parent's block offset) */
+ iblock->block_off = par_iblock->block_off;
+ iblock->block_off += hdr->man_dtable.row_block_off[par_entry / hdr->man_dtable.cparam.width];
+ iblock->block_off += hdr->man_dtable.row_block_size[par_entry / hdr->man_dtable.cparam.width] * (par_entry % hdr->man_dtable.cparam.width);
+ } /* end if */
+ else
+ iblock->block_off = 0; /* Must be the root indirect block... */
+
+ /* Update indirect block's statistics */
+ iblock->nchildren = 0;
+ iblock->max_child = 0;
+
+ /* Cache the new indirect block */
+ if(H5AC_insert_entry(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, *addr_p, iblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap indirect block to cache")
+
+done:
+ if(ret_value < 0)
+ if(iblock)
+ if(H5HF_man_iblock_dest(iblock) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_protect
+ *
+ * Purpose: Convenience wrapper around H5AC_protect on an indirect block
+ *
+ * Return: Pointer to indirect block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_indirect_t *
+H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr,
+ unsigned iblock_nrows, H5HF_indirect_t *par_iblock, unsigned par_entry,
+ hbool_t must_protect, unsigned flags, hbool_t *did_protect)
+{
+ H5HF_parent_t par_info; /* Parent info for loading block */
+ H5HF_indirect_t *iblock = NULL; /* Indirect block from cache */
+ hbool_t should_protect = FALSE; /* Whether we should protect the indirect block or not */
+ H5HF_indirect_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(iblock_addr));
+ HDassert(iblock_nrows > 0);
+ HDassert(did_protect);
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Check if we are allowed to use existing pinned iblock pointer */
+ if(!must_protect) {
+ /* Check for this block already being pinned */
+ if(par_iblock) {
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(par_iblock->child_iblocks);
+ HDassert(par_entry >= (hdr->man_dtable.max_direct_rows
+ * hdr->man_dtable.cparam.width));
+
+ /* Compute index in parent's child iblock pointer array */
+ indir_idx = par_entry - (hdr->man_dtable.max_direct_rows
+ * hdr->man_dtable.cparam.width);
+
+ /* Check for pointer to pinned indirect block in parent */
+ if(par_iblock->child_iblocks[indir_idx])
+ iblock = par_iblock->child_iblocks[indir_idx];
+ else
+ should_protect = TRUE;
+ } /* end if */
+ else {
+ /* Check for root indirect block */
+ if(H5F_addr_eq(iblock_addr, hdr->man_dtable.table_addr)) {
+ /* Check for valid pointer to pinned indirect block in root */
+ if(H5HF_ROOT_IBLOCK_PINNED == hdr->root_iblock_flags) {
+ /* Sanity check */
+ HDassert(NULL != hdr->root_iblock);
+
+ /* Return the pointer to the pinned root indirect block */
+ iblock = hdr->root_iblock;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(NULL == hdr->root_iblock);
+
+ should_protect = TRUE;
+ } /* end else */
+ } /* end if */
+ else
+ should_protect = TRUE;
+ } /* end else */
+ } /* end if */
+
+ /* Check for protecting indirect block */
+ if(must_protect || should_protect) {
+ H5HF_iblock_cache_ud_t cache_udata; /* User-data for callback */
+
+ /* Set up parent info */
+ par_info.hdr = hdr;
+ par_info.iblock = par_iblock;
+ par_info.entry = par_entry;
+
+ /* Set up user data for protect call */
+ cache_udata.f = hdr->f;
+ cache_udata.par_info = &par_info;
+ cache_udata.nrows = &iblock_nrows;
+
+ /* Protect the indirect block */
+ if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, &cache_udata, flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap indirect block")
+
+ /* Set the indirect block's address */
+ iblock->addr = iblock_addr;
+
+ /* Check for root indirect block */
+ if(iblock->block_off == 0) {
+ /* Sanity check - shouldn't be recursively protecting root indirect block */
+ HDassert(0 == (hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PROTECTED));
+
+ /* Check if we should set the root iblock pointer */
+ if(0 == hdr->root_iblock_flags) {
+ HDassert(NULL == hdr->root_iblock);
+ hdr->root_iblock = iblock;
+ } /* end if */
+
+ /* Indicate that the root indirect block is protected */
+ hdr->root_iblock_flags |= H5HF_ROOT_IBLOCK_PROTECTED;
+ } /* end if */
+
+ /* Indicate that the indirect block was protected */
+ *did_protect = TRUE;
+ } /* end if */
+ else
+ /* Indicate that the indirect block was _not_ protected */
+ *did_protect = FALSE;
+
+ /* Set the return value */
+ ret_value = iblock;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_unprotect
+ *
+ * Purpose: Convenience wrapper around H5AC_unprotect on an indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_unprotect(H5HF_indirect_t *iblock, hid_t dxpl_id,
+ unsigned cache_flags, hbool_t did_protect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+
+ /* Check if we previously protected this indirect block */
+ /* (as opposed to using an existing pointer to a pinned child indirect block) */
+ if(did_protect) {
+ /* Check for root indirect block */
+ if(iblock->block_off == 0) {
+ /* Sanity check - shouldn't be recursively unprotecting root indirect block */
+ HDassert(iblock->hdr->root_iblock_flags & H5HF_ROOT_IBLOCK_PROTECTED);
+
+ /* Check if we should reset the root iblock pointer */
+ if(H5HF_ROOT_IBLOCK_PROTECTED == iblock->hdr->root_iblock_flags) {
+ HDassert(NULL != iblock->hdr->root_iblock);
+ iblock->hdr->root_iblock = NULL;
+ } /* end if */
+
+ /* Indicate that the root indirect block is unprotected */
+ iblock->hdr->root_iblock_flags &= (unsigned)(~(H5HF_ROOT_IBLOCK_PROTECTED));
+ } /* end if */
+
+ /* Unprotect the indirect block */
+ if(H5AC_unprotect(iblock->hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock->addr, iblock, cache_flags) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_attach
+ *
+ * Purpose: Attach a child block (direct or indirect) to an indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 30 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry, haddr_t child_addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(H5F_addr_defined(child_addr));
+ HDassert(!H5F_addr_defined(iblock->ents[entry].addr));
+
+ /* Increment the reference count on this indirect block */
+ if(H5HF_iblock_incr(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+
+ /* Point at the child block */
+ iblock->ents[entry].addr = child_addr;
+
+ /* Check for I/O filters on this heap */
+ if(iblock->hdr->filter_len > 0) {
+ unsigned row; /* Row for entry */
+
+ /* Sanity check */
+ HDassert(iblock->filt_ents);
+
+ /* Compute row for entry */
+ row = entry / iblock->hdr->man_dtable.cparam.width;
+
+ /* If this is a direct block, set its initial size */
+ if(row < iblock->hdr->man_dtable.max_direct_rows)
+ iblock->filt_ents[entry].size = iblock->hdr->man_dtable.row_block_size[row];
+ } /* end if */
+
+ /* Check for max. entry used */
+ if(entry > iblock->max_child)
+ iblock->max_child = entry;
+
+ /* Increment the # of child blocks */
+ iblock->nchildren++;
+
+ /* Mark indirect block as modified */
+ if(H5HF_iblock_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_attach() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_detach
+ *
+ * Purpose: Detach a child block (direct or indirect) from an indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_detach(H5HF_indirect_t *iblock, hid_t dxpl_id, unsigned entry)
+{
+ unsigned row; /* Row for entry */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(iblock->nchildren);
+
+ /* Reset address of entry */
+ iblock->ents[entry].addr = HADDR_UNDEF;
+
+ /* Compute row for entry */
+ row = entry / iblock->hdr->man_dtable.cparam.width;
+
+ /* Check for I/O filters on this heap */
+ if(iblock->hdr->filter_len > 0) {
+ /* Sanity check */
+ HDassert(iblock->filt_ents);
+
+ /* If this is a direct block, reset its initial size */
+ if(row < iblock->hdr->man_dtable.max_direct_rows) {
+ iblock->filt_ents[entry].size = 0;
+ iblock->filt_ents[entry].filter_mask = 0;
+ } /* end if */
+ } /* end if */
+
+ /* Check for indirect block being detached */
+ if(row >= iblock->hdr->man_dtable.max_direct_rows) {
+ unsigned indir_idx; /* Index in parent's child iblock pointer array */
+
+ /* Sanity check */
+ HDassert(iblock->child_iblocks);
+
+ /* Compute index in child iblock pointer array */
+ indir_idx = entry - (iblock->hdr->man_dtable.max_direct_rows
+ * iblock->hdr->man_dtable.cparam.width);
+
+ /* Sanity check */
+ HDassert(iblock->child_iblocks[indir_idx]);
+
+ /* Reset pointer to child indirect block in parent */
+ iblock->child_iblocks[indir_idx] = NULL;
+ } /* end if */
+
+ /* Decrement the # of child blocks */
+ /* (If the number of children drop to 0, the indirect block will be
+ * removed from the heap when its ref. count drops to zero and the
+ * metadata cache calls the indirect block destructor)
+ */
+ iblock->nchildren--;
+
+ /* Reduce the max. entry used, if necessary */
+ if(entry == iblock->max_child) {
+ if(iblock->nchildren > 0)
+ while(!H5F_addr_defined(iblock->ents[iblock->max_child].addr))
+ iblock->max_child--;
+ else
+ iblock->max_child = 0;
+ } /* end if */
+
+ /* If this is the root indirect block handle some special cases */
+ if(iblock->block_off == 0) {
+ /* If the number of children drops to 1, and that child is the first
+ * direct block in the heap, convert the heap back to using a root
+ * direct block
+ */
+ if(iblock->nchildren == 1 && H5F_addr_defined(iblock->ents[0].addr))
+ if(H5HF_man_iblock_root_revert(iblock, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't convert root indirect block back to root direct block")
+
+ /* Check for reducing size of root indirect block */
+ if(iblock->nchildren > 0 && iblock->hdr->man_dtable.cparam.start_root_rows != 0
+ && entry > iblock->max_child) {
+ unsigned max_child_row; /* Row for max. child entry */
+
+ /* Compute information needed for determining whether to reduce size of root indirect block */
+ max_child_row = iblock->max_child / iblock->hdr->man_dtable.cparam.width;
+
+ /* Check if the root indirect block should be reduced */
+ if(iblock->nrows > 1 && max_child_row <= (iblock->nrows / 2))
+ if(H5HF_man_iblock_root_halve(iblock, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce size of root indirect block")
+ } /* end if */
+ } /* end if */
+
+ /* Mark indirect block as modified */
+ if(H5HF_iblock_dirty(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Decrement the reference count on this indirect block */
+ /* (should be last, so that potential 'unpin' on this indirect block
+ * doesn't invalidate the 'iblock' variable)
+ */
+ if(H5HF_iblock_decr(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_detach() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_entry_addr
+ *
+ * Purpose: Retrieve the address of an indirect block's child
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_entry_addr(H5HF_indirect_t *iblock, unsigned entry, haddr_t *child_addr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(child_addr);
+
+ /* Retrieve address of entry */
+ *child_addr = iblock->ents[entry].addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iblock_entry_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_delete
+ *
+ * Purpose: Delete a managed indirect block
+ *
+ * Note: This routine does _not_ modify any indirect block that points
+ * to this indirect block, it is assumed that the whole heap is
+ * being deleted in a top-down fashion.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_delete(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr,
+ unsigned iblock_nrows, H5HF_indirect_t *par_iblock, unsigned par_entry)
+{
+ H5HF_indirect_t *iblock; /* Pointer to indirect block */
+ unsigned row, col; /* Current row & column in indirect block */
+ unsigned entry; /* Current entry in row */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(iblock_addr));
+ HDassert(iblock_nrows > 0);
+
+ /* Lock indirect block */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, par_iblock, par_entry, TRUE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+ HDassert(iblock->nchildren > 0);
+ HDassert(did_protect == TRUE);
+
+ /* Iterate over rows in this indirect block */
+ entry = 0;
+ for(row = 0; row < iblock->nrows; row++) {
+ /* Iterate over entries in this row */
+ for(col = 0; col < hdr->man_dtable.cparam.width; col++, entry++) {
+ /* Check for child entry at this position */
+ if(H5F_addr_defined(iblock->ents[entry].addr)) {
+ hsize_t row_block_size; /* The size of blocks in this row */
+
+ /* Get the row's block size */
+ row_block_size = (hsize_t)hdr->man_dtable.row_block_size[row];
+
+ /* Are we in a direct or indirect block row */
+ if(row < hdr->man_dtable.max_direct_rows) {
+ hsize_t dblock_size; /* Size of direct block on disk */
+
+ /* Check for I/O filters on this heap */
+ if(hdr->filter_len > 0)
+ dblock_size = iblock->filt_ents[entry].size;
+ else
+ dblock_size = row_block_size;
+
+ /* Delete child direct block */
+ if(H5HF_man_dblock_delete(hdr->f, dxpl_id, iblock->ents[entry].addr, dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap child direct block")
+ } /* end if */
+ else {
+ unsigned child_nrows; /* Number of rows in new indirect block */
+
+ /* Compute # of rows in next child indirect block to use */
+ child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, row_block_size);
+
+ /* Delete child indirect block */
+ if(H5HF_man_iblock_delete(hdr, dxpl_id, iblock->ents[entry].addr, child_nrows, iblock, entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap child indirect block")
+ } /* end else */
+ } /* end if */
+ } /* end for */
+ } /* end row */
+
+#ifndef NDEBUG
+{
+ unsigned iblock_status = 0; /* Indirect block's status in the metadata cache */
+
+ /* Check the indirect block's status in the metadata cache */
+ if(H5AC_get_entry_status(hdr->f, iblock_addr, &iblock_status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for indirect block")
+
+ /* Check if indirect block is pinned */
+ HDassert(!(iblock_status & H5AC_ES__IS_PINNED));
+}
+#endif /* NDEBUG */
+
+ /* Indicate that the indirect block should be deleted */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG;
+
+ /* If the indirect block is in real file space, tell
+ * the cache to free its file space as well.
+ */
+ if (!H5F_IS_TMP_ADDR(hdr->f, iblock_addr))
+ cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
+
+done:
+ /* Unprotect the indirect block, with appropriate flags */
+ if(iblock && H5HF_man_iblock_unprotect(iblock, dxpl_id, cache_flags, did_protect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_delete() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5HF_man_iblock_size
+ *
+ * Purpose: Gather storage used for the indirect block in fractal heap
+ *
+ * Return: non-negative on success, negative on error
+ *
+ * Programmer: Vailin Choi
+ * July 12 2007
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_size(H5F_t *f, hid_t dxpl_id, H5HF_hdr_t *hdr, haddr_t iblock_addr,
+ unsigned nrows, H5HF_indirect_t *par_iblock, unsigned par_entry, hsize_t *heap_size)
+{
+ H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(hdr);
+ HDassert(H5F_addr_defined(iblock_addr));
+ HDassert(heap_size);
+
+ /* Protect the indirect block */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, par_iblock, par_entry, FALSE, H5AC__READ_ONLY_FLAG, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap indirect block")
+
+ /* Accumulate size of this indirect block */
+ *heap_size += iblock->size;
+
+ /* Indirect entries in this indirect block */
+ if(iblock->nrows > hdr->man_dtable.max_direct_rows) {
+ unsigned first_row_bits; /* Number of bits used bit addresses in first row */
+ unsigned num_indirect_rows; /* Number of rows of blocks in each indirect block */
+ unsigned entry; /* Current entry in row */
+ size_t u; /* Local index variable */
+
+ entry = hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width;
+ first_row_bits = H5VM_log2_of2((uint32_t)hdr->man_dtable.cparam.start_block_size) +
+ H5VM_log2_of2(hdr->man_dtable.cparam.width);
+ num_indirect_rows =
+ (H5VM_log2_gen(hdr->man_dtable.row_block_size[hdr->man_dtable.max_direct_rows]) - first_row_bits) + 1;
+ for(u = hdr->man_dtable.max_direct_rows; u < iblock->nrows; u++, num_indirect_rows++) {
+ size_t v; /* Local index variable */
+
+ for(v = 0; v < hdr->man_dtable.cparam.width; v++, entry++)
+ if(H5F_addr_defined(iblock->ents[entry].addr))
+ if(H5HF_man_iblock_size(f, dxpl_id, hdr, iblock->ents[entry].addr, num_indirect_rows, iblock, entry, heap_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to get fractal heap storage info for indirect block")
+ } /* end for */
+ } /* end if */
+
+done:
+ /* Release the indirect block */
+ if(iblock && H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ iblock = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iblock_dest
+ *
+ * Purpose: Destroys a fractal heap indirect block in memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iblock_dest(H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(iblock);
+ HDassert(iblock->rc == 0);
+
+ /* Decrement reference count on shared info */
+ HDassert(iblock->hdr);
+ if(H5HF_hdr_decr(iblock->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
+ if(iblock->parent)
+ if(H5HF_iblock_decr(iblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Release entry tables */
+ if(iblock->ents)
+ iblock->ents = H5FL_SEQ_FREE(H5HF_indirect_ent_t, iblock->ents);
+ if(iblock->filt_ents)
+ iblock->filt_ents = H5FL_SEQ_FREE(H5HF_indirect_filt_ent_t, iblock->filt_ents);
+ if(iblock->child_iblocks)
+ iblock->child_iblocks = H5FL_SEQ_FREE(H5HF_indirect_ptr_t, iblock->child_iblocks);
+
+ /* Free fractal heap indirect block info */
+ iblock = H5FL_FREE(H5HF_indirect_t, iblock);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iblock_dest() */
+
diff --git a/src/H5HFiter.c b/src/H5HFiter.c
new file mode 100644
index 0000000..54246d2
--- /dev/null
+++ b/src/H5HFiter.c
@@ -0,0 +1,663 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFiter.c
+ * Apr 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Block iteration routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HF_block_loc_t struct */
+H5FL_DEFINE(H5HF_block_loc_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_init
+ *
+ * Purpose: Initialize a block iterator for walking over all the blocks
+ * in a fractal heap. (initialization finishes when iterator is
+ * actually used)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_init(H5HF_block_iter_t *biter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+
+ /* Reset block iterator information */
+ HDmemset(biter, 0, sizeof(H5HF_block_iter_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iter_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_start_offset
+ *
+ * Purpose: Initialize a block iterator to a particular location, given
+ * an offset in the heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_start_offset(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_block_iter_t *biter, hsize_t offset)
+{
+ H5HF_indirect_t *iblock; /* Indirect block for location context */
+ haddr_t iblock_addr; /* Address of indirect block */
+ unsigned iblock_nrows; /* # of rows in indirect block */
+ H5HF_indirect_t *iblock_parent; /* Parent indirect block of location context */
+ unsigned iblock_par_entry; /* Entry within parent indirect block */
+ hsize_t curr_offset; /* Current offset, as adjusted */
+ unsigned row; /* Current row we are on */
+ unsigned col; /* Column in row */
+ hbool_t root_block = TRUE; /* Flag to indicate the current block is the root indirect block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(!biter->ready);
+
+ /* Check for empty heap */
+ HDassert(offset >= hdr->man_dtable.cparam.start_block_size);
+
+ /* Allocate level structure */
+ if(NULL == (biter->curr = H5FL_MALLOC(H5HF_block_loc_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+/*
+1: <Scan down block offsets for dtable rows until find a row >= offset>
+ <Set current location's row, col, entry & size>
+ <If row < max_direct_rows>
+ <Done>
+ <Else - row > max_direct_rows>
+ <Create new block level>
+ <Link new block level into iterator>
+ <Adjust offset for block offset for row>
+ <Make new block level the current context>
+ <Goto 1>
+
+*/
+ do {
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+
+ /* Walk down the rows in the doubling table until we've found the correct row for the next block */
+ for(row = 0; row < hdr->man_dtable.max_root_rows; row++)
+ if((offset >= hdr->man_dtable.row_block_off[row]) &&
+ (offset < hdr->man_dtable.row_block_off[row] +
+ (hdr->man_dtable.cparam.width * hdr->man_dtable.row_block_size[row])))
+ break;
+
+ /* Adjust offset by row offset */
+ curr_offset = offset - hdr->man_dtable.row_block_off[row];
+
+ /* Compute column */
+ H5_CHECK_OVERFLOW((curr_offset / hdr->man_dtable.row_block_size[row]), hsize_t, unsigned);
+ col = (unsigned)(curr_offset / hdr->man_dtable.row_block_size[row]);
+
+ /* Set the current level's context */
+ biter->curr->row = row;
+ biter->curr->col = col;
+ biter->curr->entry = (row * hdr->man_dtable.cparam.width) + col;
+
+ /* Get the context indirect block's information */
+ if(root_block) {
+ iblock_addr = hdr->man_dtable.table_addr;
+ iblock_nrows = hdr->man_dtable.curr_root_rows;
+ iblock_parent = NULL;
+ iblock_par_entry = 0;
+
+ /* The root block can't go up further... */
+ biter->curr->up = NULL;
+
+ /* Next time through the loop will not be with the root indirect block */
+ root_block = FALSE;
+ } /* end if */
+ else {
+ hsize_t child_size; /* Size of new indirect block to create */
+
+ /* Retrieve the parent information from the previous context location */
+ iblock_parent = biter->curr->up->context;
+ iblock_par_entry = biter->curr->up->entry;
+
+ /* Look up the address of context indirect block */
+ iblock_addr = iblock_parent->ents[iblock_par_entry].addr;
+
+ /* Compute # of rows in context indirect block */
+ child_size = hdr->man_dtable.row_block_size[biter->curr->up->row];
+ iblock_nrows = (H5VM_log2_gen(child_size) - hdr->man_dtable.first_row_bits) + 1;
+ } /* end else */
+
+ /* Load indirect block for this context location */
+ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, iblock_parent, iblock_par_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+
+ /* Make indirect block the context for the current location */
+ biter->curr->context = iblock;
+
+ /* Hold the indirect block with the location */
+ if(H5HF_iblock_incr(biter->curr->context) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+
+ /* Release the current indirect block */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ iblock = NULL;
+
+ /* See if the location falls in a direct block row */
+ /* Or, if the offset has just filled up a direct or indirect block */
+ if(curr_offset == (col * hdr->man_dtable.row_block_size[row]) || row < hdr->man_dtable.max_direct_rows) {
+ HDassert(curr_offset - (col * hdr->man_dtable.row_block_size[row]) == 0);
+ break; /* Done now */
+ } /* end if */
+ /* Indirect block row */
+ else {
+ H5HF_block_loc_t *new_loc; /* Pointer to new block location */
+
+ /* Allocate level structure */
+ if(NULL == (new_loc = H5FL_MALLOC(H5HF_block_loc_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Link new level into iterator */
+ new_loc->up = biter->curr;
+
+ /* Adjust offset for new level */
+ offset = curr_offset - (col * hdr->man_dtable.row_block_size[row]);
+
+ /* Make new block the current context */
+ biter->curr = new_loc;
+ } /* end else */
+ } while(1); /* Breaks out in middle */
+
+ /* Set flag to indicate block iterator finished initializing */
+ biter->ready = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iter_start_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_set_entry
+ *
+ * Purpose: Set the current entry for the iterator
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_set_entry(const H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned entry)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+
+ /* Set location context */
+ biter->curr->entry = entry;
+ biter->curr->row = entry / hdr->man_dtable.cparam.width;
+ biter->curr->col = entry % hdr->man_dtable.cparam.width;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iter_set_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_start_entry
+ *
+ * Purpose: Initialize a block iterator to a particular location within
+ * an indirect block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_start_entry(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter,
+ H5HF_indirect_t *iblock, unsigned start_entry)
+{
+ H5HF_block_loc_t *new_loc = NULL; /* Pointer to new block location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(biter);
+ HDassert(!biter->ready);
+ HDassert(iblock);
+
+ /* Create new location for iterator */
+ if(NULL == (new_loc = H5FL_MALLOC(H5HF_block_loc_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Set up location context */
+ new_loc->entry = start_entry;
+ new_loc->row = start_entry / hdr->man_dtable.cparam.width;
+ new_loc->col = start_entry % hdr->man_dtable.cparam.width;
+ new_loc->context = iblock;
+ new_loc->up = NULL;
+
+ /* Increment reference count on indirect block */
+ if(H5HF_iblock_incr(new_loc->context) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+
+ /* Make new location the current location */
+ biter->curr = new_loc;
+
+ /* Set flag to indicate block iterator finished initializing */
+ biter->ready = TRUE;
+
+done:
+ if(ret_value < 0 && new_loc)
+ new_loc = H5FL_FREE(H5HF_block_loc_t, new_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iter_start_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_reset
+ *
+ * Purpose: Reset a block iterator to it's initial state, freeing any
+ * location context it currently has
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_reset(H5HF_block_iter_t *biter)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+
+ /* Free any location contexts that exist */
+ if(biter->curr) {
+ H5HF_block_loc_t *curr_loc; /* Pointer to current block location */
+ H5HF_block_loc_t *next_loc; /* Pointer to next block location */
+
+ /* Free location contexts */
+ curr_loc = biter->curr;
+ while(curr_loc) {
+ /* Get pointer to next node */
+ next_loc = curr_loc->up;
+
+ /* If this node is holding an indirect block, release the block */
+ if(curr_loc->context)
+ if(H5HF_iblock_decr(curr_loc->context) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Free the current location context */
+ curr_loc = H5FL_FREE(H5HF_block_loc_t, curr_loc);
+
+ /* Advance to next location */
+ curr_loc = next_loc;
+ } /* end while */
+
+ /* Reset top location context */
+ biter->curr = NULL;
+ } /* end if */
+
+ /* Reset block iterator flags */
+ biter->ready = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iter_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_next
+ *
+ * Purpose: Advance to the next block within the current block of the heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_next(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned nentries)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(biter->curr);
+ HDassert(biter->curr->context);
+ HDassert(biter->curr->row < biter->curr->context->nrows);
+
+ /* Advance entry in current block */
+ biter->curr->entry += nentries;
+ biter->curr->row = biter->curr->entry / hdr->man_dtable.cparam.width;
+ biter->curr->col = biter->curr->entry % hdr->man_dtable.cparam.width;
+/* HDassert(biter->curr->row <= biter->curr->context->nrows); */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iter_next() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_up
+ *
+ * Purpose: Move iterator up one level
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_up(H5HF_block_iter_t *biter)
+{
+ H5HF_block_loc_t *up_loc; /* Pointer to 'up' block location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(biter->ready);
+ HDassert(biter->curr);
+ HDassert(biter->curr->up);
+ HDassert(biter->curr->context);
+
+ /* Release hold on current location's indirect block */
+ if(H5HF_iblock_decr(biter->curr->context) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Get pointer to location context above this one */
+ up_loc = biter->curr->up;
+
+ /* Release this location */
+ biter->curr = H5FL_FREE(H5HF_block_loc_t, biter->curr);
+
+ /* Point location to next location up */
+ biter->curr = up_loc;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iter_up() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_down
+ *
+ * Purpose: Move iterator down one level
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_down(H5HF_block_iter_t *biter, H5HF_indirect_t *iblock)
+{
+ H5HF_block_loc_t *down_loc = NULL; /* Pointer to new 'down' block location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(biter->ready);
+ HDassert(biter->curr);
+ HDassert(biter->curr->context);
+
+ /* Create new location to move down to */
+ if(NULL == (down_loc = H5FL_MALLOC(H5HF_block_loc_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Initialize down location */
+ down_loc->row = 0;
+ down_loc->col = 0;
+ down_loc->entry = 0;
+ down_loc->context = iblock;
+ down_loc->up = biter->curr;
+
+ /* Increment reference count on indirect block */
+ if(H5HF_iblock_incr(down_loc->context) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+
+ /* Make down location the current location */
+ biter->curr = down_loc;
+
+done:
+ if(ret_value < 0 && down_loc)
+ down_loc = H5FL_FREE(H5HF_block_loc_t, down_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_iter_down() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_curr
+ *
+ * Purpose: Retrieve information about the current block iterator location
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_curr(H5HF_block_iter_t *biter, unsigned *row, unsigned *col,
+ unsigned *entry, H5HF_indirect_t **block)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(biter->ready);
+
+ /* Retrieve the information asked for */
+ if(row)
+ *row = biter->curr->row;
+ if(col)
+ *col = biter->curr->col;
+ if(entry)
+ *entry = biter->curr->entry;
+ if(block)
+ *block = biter->curr->context;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iter_curr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_offset
+ *
+ * Purpose: Retrieve offset of iterator in heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_iter_offset(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, hsize_t *offset)
+{
+ hsize_t curr_offset; /* For computing offset in heap */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+ HDassert(biter->ready);
+ HDassert(biter->curr->context);
+ HDassert(offset);
+
+ /* Compute the offset in the heap */
+ curr_offset = biter->curr->context->block_off;
+ curr_offset += hdr->man_dtable.row_block_off[biter->curr->row];
+ curr_offset += biter->curr->col * hdr->man_dtable.row_block_size[biter->curr->row];
+
+ /* Assign the return value */
+ *offset = curr_offset;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_iter_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_iter_ready
+ *
+ * Purpose: Query if iterator is ready to use
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Apr 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5HF_man_iter_ready(H5HF_block_iter_t *biter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(biter);
+
+ FUNC_LEAVE_NOAPI(biter->ready)
+} /* end H5HF_man_iter_ready() */
+
diff --git a/src/H5HFman.c b/src/H5HFman.c
new file mode 100644
index 0000000..2b88b50
--- /dev/null
+++ b/src/H5HFman.c
@@ -0,0 +1,685 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFman.c
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: "Managed" object routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Macro to check if we can apply all filters in the pipeline. Use whenever
+ * performing a modification operation */
+ #define H5HF_MAN_WRITE_CHECK_PLINE(HDR) \
+{ \
+ if(!((HDR)->checked_filters)) { \
+ if((HDR)->pline.nused) \
+ if(H5Z_can_apply_direct(&((HDR)->pline)) < 0) \
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "I/O filters can't operate on this heap") \
+ \
+ (HDR)->checked_filters = TRUE; \
+ } /* end if */ \
+}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ const uint8_t *id, H5HF_operator_t op, void *op_data, unsigned op_flags);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_insert
+ *
+ * Purpose: Insert an object in a managed direct block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t obj_size, const void *obj,
+ void *_id)
+{
+ H5HF_free_section_t *sec_node = NULL; /* Pointer to free space section */
+ H5HF_direct_t *dblock = NULL; /* Pointer to direct block to modify */
+ haddr_t dblock_addr = HADDR_UNDEF; /* Direct block address */
+ size_t dblock_size; /* Direct block size */
+ uint8_t *id = (uint8_t *)_id; /* Pointer to ID buffer */
+ size_t blk_off; /* Offset of object within block */
+ htri_t node_found; /* Whether an existing free list node was found */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(obj_size > 0);
+ HDassert(obj);
+ HDassert(id);
+
+ /* Check pipeline */
+ H5HF_MAN_WRITE_CHECK_PLINE(hdr)
+
+ /* Look for free space */
+ if((node_found = H5HF_space_find(hdr, dxpl_id, (hsize_t)obj_size, &sec_node)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap")
+
+ /* If we didn't find a node, go create a direct block big enough to hold the requested block */
+ if(!node_found)
+ /* Allocate direct block big enough to hold requested size */
+ if(H5HF_man_dblock_new(hdr, dxpl_id, obj_size, &sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create fractal heap direct block")
+
+ /* Check for row section */
+ if(sec_node->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
+ sec_node->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW) {
+
+ /* Allocate 'single' selection out of 'row' selection */
+ if(H5HF_man_iblock_alloc_row(hdr, dxpl_id, &sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't break up row section")
+ } /* end if */
+ HDassert(sec_node->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+
+ /* Check for 'single' section being serialized */
+ if(sec_node->sect_info.state == H5FS_SECT_SERIALIZED) {
+ if(H5HF_sect_single_revive(hdr, dxpl_id, sec_node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
+ } /* end if */
+ HDassert(sec_node->sect_info.state == H5FS_SECT_LIVE);
+
+ /* Retrieve direct block address from section */
+ if(H5HF_sect_single_dblock_info(hdr, sec_node, &dblock_addr, &dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information")
+
+ /* Lock direct block */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sec_node->u.single.parent, sec_node->u.single.par_entry, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block")
+
+ /* Insert object into block */
+
+ /* Get the offset of the object within the block */
+ H5_CHECK_OVERFLOW((sec_node->sect_info.addr - dblock->block_off), hsize_t, size_t);
+ blk_off = (size_t)(sec_node->sect_info.addr - dblock->block_off);
+
+ /* Sanity checks */
+ HDassert(sec_node->sect_info.size >= obj_size);
+
+ /* Reduce (& possibly re-add) single section */
+ if(H5HF_sect_single_reduce(hdr, dxpl_id, sec_node, obj_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce single section node")
+ sec_node = NULL;
+
+ /* Encode the object in the block */
+ {
+ uint8_t *p; /* Temporary pointer to obj info in block */
+
+ /* Point to location for object */
+ p = dblock->blk + blk_off;
+
+ /* Copy the object's data into the heap */
+ HDmemcpy(p, obj, obj_size);
+ p += obj_size;
+
+ /* Sanity check */
+ HDassert((size_t)(p - (dblock->blk + blk_off)) == obj_size);
+ } /* end block */
+
+ /* Set the heap ID for the new object (heap offset & obj length) */
+ H5HF_MAN_ID_ENCODE(id, hdr, (dblock->block_off + blk_off), obj_size);
+
+ /* Update statistics about heap */
+ hdr->man_nobjs++;
+
+ /* Reduce space available in heap (marks header dirty) */
+ if(H5HF_hdr_adj_free(hdr, -(ssize_t)obj_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't adjust free space for heap")
+
+done:
+ /* Release section node on error */
+ if(ret_value < 0)
+ if(sec_node && H5HF_sect_single_free((H5FS_section_info_t *)sec_node) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release section node")
+
+ /* Release the direct block (marked as dirty) */
+ if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_get_obj_len
+ *
+ * Purpose: Get the size of a managed heap object
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Dana Robinson (derobins@hdfgroup.org)
+ * August 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id, size_t *obj_len_p)
+{
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj_len_p);
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Skip over object offset */
+ id += hdr->heap_off_size;
+
+ /* Retrieve the entry length */
+ UINT64DECODE_VAR(id, *obj_len_p, hdr->heap_len_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_man_get_obj_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF__man_get_obj_off
+ *
+ * Purpose: Get the offset of a managed heap object
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 20 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5HF__man_get_obj_off(const H5HF_hdr_t *hdr, const uint8_t *id, hsize_t *obj_off_p)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj_off_p);
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Skip over object offset */
+ UINT64DECODE_VAR(id, *obj_off_p, hdr->heap_off_size);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5HF__man_get_obj_off() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_op_real
+ *
+ * Purpose: Internal routine to perform an operation on a managed heap
+ * object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ H5HF_operator_t op, void *op_data, unsigned op_flags)
+{
+ H5HF_direct_t *dblock = NULL; /* Pointer to direct block to query */
+ unsigned dblock_access_flags; /* Access method for direct block */
+ /* must equal either
+ * H5AC__NO_FLAGS_SET or
+ * H5AC__READ_ONLY_FLAG
+ */
+ haddr_t dblock_addr; /* Direct block address */
+ size_t dblock_size; /* Direct block size */
+ unsigned dblock_cache_flags; /* Flags for unprotecting direct block */
+ hsize_t obj_off; /* Object's offset in heap */
+ size_t obj_len; /* Object's length in heap */
+ size_t blk_off; /* Offset of object in block */
+ uint8_t *p; /* Temporary pointer to obj info in block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(op);
+
+ /* Set the access mode for the direct block */
+ if(op_flags & H5HF_OP_MODIFY) {
+ /* Check pipeline */
+ H5HF_MAN_WRITE_CHECK_PLINE(hdr)
+
+ dblock_access_flags = H5AC__NO_FLAGS_SET;
+ dblock_cache_flags = H5AC__DIRTIED_FLAG;
+ } /* end if */
+ else {
+ dblock_access_flags = H5AC__READ_ONLY_FLAG;
+ dblock_cache_flags = H5AC__NO_FLAGS_SET;
+ } /* end else */
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Decode the object offset within the heap & its length */
+ UINT64DECODE_VAR(id, obj_off, hdr->heap_off_size);
+ UINT64DECODE_VAR(id, obj_len, hdr->heap_len_size);
+
+ /* Check for bad offset or length */
+ if(obj_off == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap offset")
+ if(obj_off > hdr->man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large")
+ if(obj_len == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap object size")
+ if(obj_len > hdr->man_dtable.cparam.max_direct_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object size too large for direct block")
+ if(obj_len > hdr->max_man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object should be standalone")
+
+ /* Check for root direct block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ /* Set direct block info */
+ dblock_addr = hdr->man_dtable.table_addr;
+ dblock_size = hdr->man_dtable.cparam.start_block_size;
+
+ /* Lock direct block */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, NULL, 0, dblock_access_flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
+ } /* end if */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ unsigned entry; /* Entry of block */
+
+ /* Look up indirect block containing direct block */
+ if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
+
+ /* Set direct block info */
+ dblock_addr = iblock->ents[entry].addr;
+ H5_CHECK_OVERFLOW((hdr->man_dtable.row_block_size[entry / hdr->man_dtable.cparam.width]), hsize_t, size_t);
+ dblock_size = (size_t)hdr->man_dtable.row_block_size[entry / hdr->man_dtable.cparam.width];
+
+ /* Check for offset of invalid direct block */
+ if(!H5F_addr_defined(dblock_addr)) {
+ /* Unlock indirect block */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap ID not in allocated direct block")
+ } /* end if */
+
+ /* Lock direct block */
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, iblock, entry, dblock_access_flags))) {
+ /* Unlock indirect block */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block")
+ } /* end if */
+
+ /* Unlock indirect block */
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ iblock = NULL;
+ } /* end else */
+
+ /* Compute offset of object within block */
+ HDassert((obj_off - dblock->block_off) < (hsize_t)dblock_size);
+ blk_off = (size_t)(obj_off - dblock->block_off);
+
+ /* Check for object's offset in the direct block prefix information */
+ if(blk_off < (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object located in prefix of direct block")
+
+ /* Check for object's length overrunning the end of the direct block */
+ if((blk_off + obj_len) > dblock_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object overruns end of direct block")
+
+ /* Point to location for object */
+ p = dblock->blk + blk_off;
+
+ /* Call the user's 'op' callback */
+ if(op(p, obj_len, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "application's callback failed")
+
+done:
+ /* Unlock direct block */
+ if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, dblock_cache_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_op_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_read
+ *
+ * Purpose: Read an object from a managed heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_read(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, void *obj)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Call the internal 'op' routine routine */
+ if(H5HF_man_op_real(hdr, dxpl_id, id, H5HF_op_read, obj, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_write
+ *
+ * Purpose: Write an object to a managed heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ const void *obj)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Call the internal 'op' routine routine */
+ /* (Casting away const OK - QAK) */
+ if(H5HF_man_op_real(hdr, dxpl_id, id, H5HF_op_write, (void *)obj, H5HF_OP_MODIFY) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_op
+ *
+ * Purpose: Operate directly on an object from a managed heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sept 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_op(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ H5HF_operator_t op, void *op_data)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(op);
+
+ /* Call the internal 'op' routine routine */
+ if(H5HF_man_op_real(hdr, dxpl_id, id, op, op_data, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_remove
+ *
+ * Purpose: Remove an object from a managed heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id)
+{
+ H5HF_free_section_t *sec_node = NULL; /* Pointer to free space section for block */
+ H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ hsize_t obj_off; /* Object's offset in heap */
+ size_t obj_len; /* Object's length in heap */
+ size_t dblock_size; /* Direct block size */
+ hsize_t dblock_block_off; /* Offset of the direct block within the heap's address space */
+ unsigned dblock_entry; /* Entry of direct block in parent indirect block */
+ size_t blk_off; /* Offset of object in block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+
+ /* Check pipeline */
+ H5HF_MAN_WRITE_CHECK_PLINE(hdr)
+
+ /* Skip over the flag byte */
+ id++;
+
+ /* Decode the object offset within the heap & it's length */
+ UINT64DECODE_VAR(id, obj_off, hdr->heap_off_size);
+ UINT64DECODE_VAR(id, obj_len, hdr->heap_len_size);
+
+ /* Check for bad offset or length */
+ if(obj_off == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap offset")
+ if(obj_off > hdr->man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large")
+ if(obj_len == 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "invalid fractal heap object size")
+ if(obj_len > hdr->man_dtable.cparam.max_direct_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object size too large for direct block")
+ if(obj_len > hdr->max_man_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object should be standalone")
+
+ /* Check for root direct block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ /* Set direct block info */
+ dblock_size = hdr->man_dtable.cparam.start_block_size;
+ dblock_block_off = 0;
+ dblock_entry = 0;
+ } /* end if */
+ else {
+ /* Look up indirect block containing direct block */
+ if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &dblock_entry, &did_protect, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
+
+ /* Check for offset of invalid direct block */
+ if(!H5F_addr_defined(iblock->ents[dblock_entry].addr))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap ID not in allocated direct block")
+
+ /* Set direct block info */
+ H5_CHECK_OVERFLOW((hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width]), hsize_t, size_t);
+ dblock_size = (size_t)(hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width]);
+
+ /* Compute the direct block's offset in the heap's address space */
+ /* (based on parent indirect block's block offset) */
+ dblock_block_off = iblock->block_off;
+ dblock_block_off += hdr->man_dtable.row_block_off[dblock_entry / hdr->man_dtable.cparam.width];
+ dblock_block_off += hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width] * (dblock_entry % hdr->man_dtable.cparam.width);
+ } /* end else */
+
+ /* Compute offset of object within block */
+ HDassert((obj_off - dblock_block_off) < (hsize_t)dblock_size);
+ blk_off = (size_t)(obj_off - dblock_block_off);
+
+ /* Check for object's offset in the direct block prefix information */
+ if(blk_off < (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object located in prefix of direct block")
+
+ /* Check for object's length overrunning the end of the direct block */
+ if((blk_off + obj_len) > dblock_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "object overruns end of direct block")
+
+ /* Create free space section node */
+ if(NULL == (sec_node = H5HF_sect_single_new(obj_off, obj_len, iblock, dblock_entry)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for direct block's free space")
+
+ /* Unlock indirect block */
+ if(iblock) {
+ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ iblock = NULL;
+ } /* end if */
+
+ /* Increase space available in heap (marks header dirty) */
+ if(H5HF_hdr_adj_free(hdr, (ssize_t)obj_len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't adjust free space for heap")
+
+ /* Update statistics about heap */
+ hdr->man_nobjs--;
+
+ /* Return free space to the heap's list of space */
+ if(H5HF_space_add(hdr, dxpl_id, sec_node, H5FS_ADD_RETURNED_SPACE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
+ sec_node = NULL;
+
+done:
+ if(ret_value < 0) {
+ /* Release section node */
+ if(sec_node && H5HF_sect_single_free((H5FS_section_info_t *)sec_node) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release section node")
+ } /* end if */
+
+ /* Unlock indirect block */
+ if(iblock && H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_remove() */
+
diff --git a/src/H5HFmodule.h b/src/H5HFmodule.h
new file mode 100644
index 0000000..dd6576a
--- /dev/null
+++ b/src/H5HFmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5HF package. Including this header means that the source file
+ * is part of the H5HF package.
+ */
+#ifndef _H5HFmodule_H
+#define _H5HFmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5HF_MODULE
+#define H5_MY_PKG H5HF
+#define H5_MY_PKG_ERR H5E_HEAP
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5HFmodule_H */
+
diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h
new file mode 100644
index 0000000..d03c122
--- /dev/null
+++ b/src/H5HFpkg.h
@@ -0,0 +1,839 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Friday, February 24, 2006
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5HF package. Source files outside the H5HF package should
+ * include H5HFprivate.h instead.
+ */
+#if !(defined H5HF_FRIEND || defined H5HF_MODULE)
+#error "Do not include this file outside the H5HF package!"
+#endif
+
+#ifndef _H5HFpkg_H
+#define _H5HFpkg_H
+
+/* Get package's private header */
+#include "H5HFprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5B2private.h" /* v2 B-trees */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5FSprivate.h" /* Free space manager */
+#include "H5SLprivate.h" /* Skip lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Size of checksum information (on disk) */
+#define H5HF_SIZEOF_CHKSUM 4
+
+/* "Standard" size of prefix information for fractal heap metadata */
+#define H5HF_METADATA_PREFIX_SIZE(c) ( \
+ H5_SIZEOF_MAGIC /* Signature */ \
+ + (unsigned)1 /* Version */ \
+ + ((c) ? (unsigned)H5HF_SIZEOF_CHKSUM : (unsigned)0) /* Metadata checksum */ \
+ )
+
+/* Size of doubling-table information */
+#define H5HF_DTABLE_INFO_SIZE(h) ( \
+ (unsigned)2 /* Width of table (i.e. # of columns) */ \
+ + (unsigned)(h)->sizeof_size /* Starting block size */ \
+ + (unsigned)(h)->sizeof_size /* Maximum direct block size */ \
+ + (unsigned)2 /* Max. size of heap (log2 of actual value - i.e. the # of bits) */ \
+ + (unsigned)2 /* Starting # of rows in root indirect block */ \
+ + (unsigned)(h)->sizeof_addr /* File address of table managed */ \
+ + (unsigned)2 /* Current # of rows in root indirect block */ \
+ )
+
+/* Flags for status byte */
+#define H5HF_HDR_FLAGS_HUGE_ID_WRAPPED 0x01 /* "huge" object IDs have wrapped */
+#define H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS 0x02 /* checksum direct blocks */
+
+/* Size of the fractal heap header on disk */
+/* (this is the fixed-len portion, the variable-len I/O filter information
+ * follows this information, if there are I/O filters for the heap)
+ */
+#define H5HF_HEADER_SIZE(h) ( \
+ /* General metadata fields */ \
+ H5HF_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Fractal Heap Header specific fields */ \
+ \
+ /* General heap information */ \
+ + (unsigned)2 /* Heap ID len */ \
+ + (unsigned)2 /* I/O filters' encoded len */ \
+ + (unsigned)1 /* Status flags */ \
+ \
+ /* "Huge" object fields */ \
+ + (unsigned)4 /* Max. size of "managed" object */ \
+ + (unsigned)(h)->sizeof_size /* Next ID for "huge" object */ \
+ + (unsigned)(h)->sizeof_addr /* File address of "huge" object tracker B-tree */ \
+ \
+ /* "Managed" object free space fields */ \
+ + (unsigned)(h)->sizeof_size /* Total man. free space */ \
+ + (unsigned)(h)->sizeof_addr /* File address of free section header */ \
+ \
+ /* Statistics fields */ \
+ + (unsigned)(h)->sizeof_size /* Size of man. space in heap */ \
+ + (unsigned)(h)->sizeof_size /* Size of man. space iterator offset in heap */ \
+ + (unsigned)(h)->sizeof_size /* Size of alloacted man. space in heap */ \
+ + (unsigned)(h)->sizeof_size /* Number of man. objects in heap */ \
+ + (unsigned)(h)->sizeof_size /* Size of huge space in heap */ \
+ + (unsigned)(h)->sizeof_size /* Number of huge objects in heap */ \
+ + (unsigned)(h)->sizeof_size /* Size of tiny space in heap */ \
+ + (unsigned)(h)->sizeof_size /* Number of tiny objects in heap */ \
+ \
+ /* "Managed" object doubling table info */ \
+ + H5HF_DTABLE_INFO_SIZE(h) /* Size of managed obj. doubling-table info */ \
+ )
+
+/* Size of overhead for a direct block */
+#define H5HF_MAN_ABS_DIRECT_OVERHEAD(h) ( \
+ /* General metadata fields */ \
+ H5HF_METADATA_PREFIX_SIZE(h->checksum_dblocks) \
+ \
+ /* Fractal heap managed, absolutely mapped direct block specific fields */ \
+ + (unsigned)(h)->sizeof_addr /* File address of heap owning the block */ \
+ + (unsigned)(h)->heap_off_size /* Offset of the block in the heap */ \
+ )
+
+/* Size of managed indirect block entry for a child direct block */
+#define H5HF_MAN_INDIRECT_CHILD_DIR_ENTRY_SIZE(h) ( \
+ ((h)->filter_len > 0 ? \
+ ((unsigned)(h)->sizeof_addr + (unsigned)(h)->sizeof_size + (unsigned)4) : /* Size of entries for filtered direct blocks */ \
+ (unsigned)(h)->sizeof_addr) /* Size of entries for un-filtered direct blocks */ \
+ )
+
+/* Size of managed indirect block */
+#define H5HF_MAN_INDIRECT_SIZE(h, r) ( \
+ /* General metadata fields */ \
+ H5HF_METADATA_PREFIX_SIZE(TRUE) \
+ \
+ /* Fractal heap managed, absolutely mapped indirect block specific fields */ \
+ + (unsigned)(h)->sizeof_addr /* File address of heap owning the block */ \
+ + (unsigned)(h)->heap_off_size /* Offset of the block in the heap */ \
+ + (MIN(r, (h)->man_dtable.max_direct_rows) * (h)->man_dtable.cparam.width * H5HF_MAN_INDIRECT_CHILD_DIR_ENTRY_SIZE(h)) /* Size of entries for direct blocks */ \
+ + (((r > (h)->man_dtable.max_direct_rows) ? (r - (h)->man_dtable.max_direct_rows) : 0) * (h)->man_dtable.cparam.width * (h)->sizeof_addr) /* Size of entries for indirect blocks */ \
+ )
+
+/* Compute the # of bytes required to store an offset into a given buffer size */
+#define H5HF_SIZEOF_OFFSET_BITS(b) (((b) + 7) / 8)
+#define H5HF_SIZEOF_OFFSET_LEN(l) H5HF_SIZEOF_OFFSET_BITS(H5VM_log2_of2((unsigned)(l)))
+
+/* Heap ID bit flags */
+/* Heap ID version (2 bits: 6-7) */
+#define H5HF_ID_VERS_CURR 0x00 /* Current version of ID format */
+#define H5HF_ID_VERS_MASK 0xC0 /* Mask for getting the ID version from flags */
+/* Heap ID type (2 bits: 4-5) */
+#define H5HF_ID_TYPE_MAN 0x00 /* "Managed" object - stored in fractal heap blocks */
+#define H5HF_ID_TYPE_HUGE 0x10 /* "Huge" object - stored in file directly */
+#define H5HF_ID_TYPE_TINY 0x20 /* "Tiny" object - stored in heap ID directly */
+#define H5HF_ID_TYPE_RESERVED 0x30 /* "?" object - reserved for future use */
+#define H5HF_ID_TYPE_MASK 0x30 /* Mask for getting the ID type from flags */
+/* Heap ID bits 0-3 reserved for future use */
+
+/* Encode a "managed" heap ID */
+#define H5HF_MAN_ID_ENCODE(i, h, o, l) \
+ *(i) = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_MAN; \
+ (i)++; \
+ UINT64ENCODE_VAR((i), (o), (h)->heap_off_size); \
+ UINT64ENCODE_VAR((i), (l), (h)->heap_len_size)
+
+/* Decode a "managed" heap ID */
+#define H5HF_MAN_ID_DECODE(i, h, f, o, l) \
+ f = *(uint8_t *)i++; \
+ UINT64DECODE_VAR((i), (o), (h)->heap_off_size); \
+ UINT64DECODE_VAR((i), (l), (h)->heap_len_size)
+
+/* Free space section types for fractal heap */
+/* (values stored in free space data structures in file) */
+#define H5HF_FSPACE_SECT_SINGLE 0 /* Section is a range of actual bytes in a direct block */
+#define H5HF_FSPACE_SECT_FIRST_ROW 1 /* Section is first range of blocks in an indirect block row */
+#define H5HF_FSPACE_SECT_NORMAL_ROW 2 /* Section is a range of blocks in an indirect block row */
+#define H5HF_FSPACE_SECT_INDIRECT 3 /* Section is a span of blocks in an indirect block */
+
+/* Flags for 'op' operations */
+#define H5HF_OP_MODIFY 0x0001 /* Operation will modify object */
+#define H5HF_OP_FLAGS (H5HF_OP_MODIFY) /* Bit-wise OR of all op flags */
+
+/* Flags for 'root_iblock_flags' field in header */
+#define H5HF_ROOT_IBLOCK_PINNED 0x01
+#define H5HF_ROOT_IBLOCK_PROTECTED 0x02
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Doubling-table info */
+typedef struct H5HF_dtable_t {
+ /* Immutable, pre-set information for table */
+ H5HF_dtable_cparam_t cparam; /* Creation parameters for table */
+
+ /* Derived information (stored, varies during lifetime of table) */
+ haddr_t table_addr; /* Address of first block for table */
+ /* Undefined if no space allocated for table */
+ unsigned curr_root_rows; /* Current number of rows in the root indirect block */
+ /* 0 indicates that the TABLE_ADDR field points
+ * to direct block (of START_BLOCK_SIZE) instead
+ * of indirect root block.
+ */
+
+ /* Computed information (not stored) */
+ unsigned max_root_rows; /* Maximum # of rows in root indirect block */
+ unsigned max_direct_rows; /* Maximum # of direct rows in any indirect block */
+ unsigned start_bits; /* # of bits for starting block size (i.e. log2(start_block_size)) */
+ unsigned max_direct_bits; /* # of bits for max. direct block size (i.e. log2(max_direct_size)) */
+ unsigned max_dir_blk_off_size; /* Max. size of offsets in direct blocks */
+ unsigned first_row_bits; /* # of bits in address of first row */
+ hsize_t num_id_first_row; /* Number of IDs in first row of table */
+ hsize_t *row_block_size; /* Block size per row of indirect block */
+ hsize_t *row_block_off; /* Cumulative offset per row of indirect block */
+ hsize_t *row_tot_dblock_free; /* Total free space in dblocks for this row */
+ /* (For indirect block rows, it's the total
+ * free space in all direct blocks referenced
+ * from the indirect block)
+ */
+ size_t *row_max_dblock_free; /* Max. free space in dblocks for this row */
+ /* (For indirect block rows, it's the maximum
+ * free space in a direct block referenced
+ * from the indirect block)
+ */
+} H5HF_dtable_t;
+
+/* Fractal heap free list info (forward decl - defined in H5HFflist.c) */
+typedef struct H5HF_freelist_t H5HF_freelist_t;
+
+/* Forward decl indirect block info */
+typedef struct H5HF_indirect_t H5HF_indirect_t;
+
+/* Fractal heap block location */
+typedef struct H5HF_block_loc_t {
+ /* Necessary table fields */
+ unsigned row; /* Row of block in doubling table */
+ unsigned col; /* Column of block in doubling table */
+
+ /* Derived/computed/cached table fields */
+ unsigned entry; /* Entry of block in doubling table */
+
+ /* Infrastructure */
+ H5HF_indirect_t *context; /* Pointer to the indirect block containing the block */
+ struct H5HF_block_loc_t *up; /* Pointer to next level up in the stack of levels */
+} H5HF_block_loc_t;
+
+/* Fractal heap block iterator info */
+typedef struct H5HF_block_iter_t {
+ hbool_t ready; /* Set if iterator is finished initializing */
+ H5HF_block_loc_t *curr; /* Pointer to the current level information for iterator */
+} H5HF_block_iter_t;
+
+/* Fractal heap free space section info */
+typedef struct H5HF_free_section_t {
+ H5FS_section_info_t sect_info; /* Free space section information (must be first in struct) */
+ union {
+ struct {
+ H5HF_indirect_t *parent; /* Indirect block parent for free section's direct block */
+ unsigned par_entry; /* Entry of free section's direct block in parent indirect block */
+ } single;
+ struct {
+ struct H5HF_free_section_t *under; /* Pointer to indirect block underlying row section */
+ unsigned row; /* Row for range of blocks */
+ unsigned col; /* Column for range of blocks */
+ unsigned num_entries; /* Number of entries covered */
+
+ /* Fields that aren't stored */
+ hbool_t checked_out; /* Flag to indicate that a row section is temporarily out of the free space manager */
+ } row;
+ struct {
+ /* Holds either a pointer to an indirect block (if its "live") or
+ * the block offset of it's indirect block (if its "serialized")
+ * (This allows the indirect block that the section is within to
+ * be compared with other sections, whether it's serialized
+ * or not)
+ */
+ union {
+ H5HF_indirect_t *iblock; /* Indirect block for free section */
+ hsize_t iblock_off; /* Indirect block offset in "heap space" */
+ } u;
+ unsigned row; /* Row for range of blocks */
+ unsigned col; /* Column for range of blocks */
+ unsigned num_entries; /* Number of entries covered */
+
+ /* Fields that aren't stored */
+ struct H5HF_free_section_t *parent; /* Pointer to "parent" indirect section */
+ unsigned par_entry; /* Entry within parent indirect section */
+ hsize_t span_size; /* Size of space tracked, in "heap space" */
+ unsigned iblock_entries; /* Number of entries in indirect block where section is located */
+ unsigned rc; /* Reference count of outstanding row & child indirect sections */
+ unsigned dir_nrows; /* Number of direct rows in section */
+ struct H5HF_free_section_t **dir_rows; /* Array of pointers to outstanding row sections */
+ unsigned indir_nents; /* Number of indirect entries in section */
+ struct H5HF_free_section_t **indir_ents; /* Array of pointers to outstanding child indirect sections */
+ } indirect;
+ } u;
+} H5HF_free_section_t;
+
+/* The fractal heap header information */
+/* (Each fractal heap header has certain information that is shared across all
+ * the instances of blocks in that fractal heap)
+ */
+typedef struct H5HF_hdr_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* General header information (stored in header) */
+ unsigned id_len; /* Size of heap IDs (in bytes) */
+ unsigned filter_len; /* Size of I/O filter information (in bytes) */
+
+ /* Flags for heap settings (stored in status byte in header) */
+ hbool_t debug_objs; /* Is the heap storing objects in 'debug' format */
+ hbool_t write_once; /* Is heap being written in "write once" mode? */
+ hbool_t huge_ids_wrapped; /* Have "huge" object IDs wrapped around? */
+ hbool_t checksum_dblocks; /* Should the direct blocks in the heap be checksummed? */
+
+ /* Doubling table information (partially stored in header) */
+ /* (Partially set by user, partially derived/updated internally) */
+ H5HF_dtable_t man_dtable; /* Doubling-table info for managed objects */
+
+ /* Free space information for managed objects (stored in header) */
+ hsize_t total_man_free; /* Total amount of free space in managed blocks */
+ haddr_t fs_addr; /* Address of free space header on disk */
+
+ /* "Huge" object support (stored in header) */
+ uint32_t max_man_size; /* Max. size of object to manage in doubling table */
+ hsize_t huge_next_id; /* Next ID to use for indirectly tracked 'huge' object */
+ haddr_t huge_bt2_addr; /* Address of v2 B-tree for tracking "huge" object info */
+
+ /* I/O filter support (stored in header, if any are used) */
+ H5O_pline_t pline; /* I/O filter pipeline for heap objects */
+ size_t pline_root_direct_size; /* Size of filtered root direct block */
+ unsigned pline_root_direct_filter_mask; /* I/O filter mask for filtered root direct block */
+
+ /* Statistics for heap (stored in header) */
+ hsize_t man_size; /* Total amount of 'managed' space in heap */
+ hsize_t man_alloc_size; /* Total amount of allocated 'managed' space in heap */
+ hsize_t man_iter_off; /* Offset of iterator in 'managed' heap space */
+ hsize_t man_nobjs; /* Number of 'managed' objects in heap */
+ hsize_t huge_size; /* Total size of 'huge' objects in heap */
+ hsize_t huge_nobjs; /* Number of 'huge' objects in heap */
+ hsize_t tiny_size; /* Total size of 'tiny' objects in heap */
+ hsize_t tiny_nobjs; /* Number of 'tiny' objects in heap */
+
+ /* Cached/computed values (not stored in header) */
+ size_t rc; /* Reference count of heap's components using heap header */
+ haddr_t heap_addr; /* Address of heap header in the file */
+ size_t heap_size; /* Size of heap header in the file */
+ unsigned mode; /* Access mode for heap */
+ H5F_t *f; /* Pointer to file for heap */
+ size_t file_rc; /* Reference count of files using heap header */
+ hbool_t pending_delete; /* Heap is pending deletion */
+ uint8_t sizeof_size; /* Size of file sizes */
+ uint8_t sizeof_addr; /* Size of file addresses */
+ struct H5HF_indirect_t *root_iblock; /* Pointer to root indirect block */
+ unsigned root_iblock_flags; /* Flags to indicate whether root indirect block is pinned/protected */
+ H5FS_t *fspace; /* Free space list for objects in heap */
+ H5HF_block_iter_t next_block; /* Block iterator for searching for next block with space */
+ H5B2_t *huge_bt2; /* v2 B-tree handle for huge objects */
+ hsize_t huge_max_id; /* Max. 'huge' heap ID before rolling 'huge' heap IDs over */
+ uint8_t huge_id_size; /* Size of 'huge' heap IDs (in bytes) */
+ hbool_t huge_ids_direct; /* Flag to indicate that 'huge' object's offset & length are stored directly in heap ID */
+ size_t tiny_max_len; /* Max. size of tiny objects for this heap */
+ hbool_t tiny_len_extended; /* Flag to indicate that 'tiny' object's length is stored in extended form (i.e. w/extra byte) */
+ uint8_t heap_off_size; /* Size of heap offsets (in bytes) */
+ uint8_t heap_len_size; /* Size of heap ID lengths (in bytes) */
+ hbool_t checked_filters; /* TRUE if pipeline passes can_apply checks */
+} H5HF_hdr_t;
+
+/* Common indirect block doubling table entry */
+/* (common between entries pointing to direct & indirect child blocks) */
+typedef struct H5HF_indirect_ent_t {
+ haddr_t addr; /* Direct block's address */
+} H5HF_indirect_ent_t;
+
+/* Extern indirect block doubling table entry for compressed direct blocks */
+/* (only exists for indirect blocks in heaps that have I/O filters) */
+typedef struct H5HF_indirect_filt_ent_t {
+ size_t size; /* Size of child direct block, after passing though I/O filters */
+ unsigned filter_mask; /* Excluded filters for child direct block */
+} H5HF_indirect_filt_ent_t;
+
+/* Fractal heap indirect block */
+struct H5HF_indirect_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Internal heap information (not stored) */
+ size_t rc; /* Reference count of objects using this block */
+ H5HF_hdr_t *hdr; /* Shared heap header info */
+ struct H5HF_indirect_t *parent; /* Shared parent indirect block info */
+ struct H5HF_indirect_t
+ *fd_parent; /* Saved copy of the parent pointer -- this */
+ /* necessary as the parent field is sometimes */
+ /* nulled out before the eviction notify call */
+ /* is made from the metadata cache. Since */
+ /* this call cancels flush dependencies, it */
+ /* needs this information. */
+ unsigned par_entry; /* Entry in parent's table */
+ haddr_t addr; /* Address of this indirect block on disk */
+ size_t size; /* Size of indirect block on disk */
+ unsigned nrows; /* Total # of rows in indirect block */
+ unsigned max_rows; /* Max. # of rows in indirect block */
+ unsigned nchildren; /* Number of child blocks */
+ unsigned max_child; /* Max. offset used in child entries */
+ struct H5HF_indirect_t **child_iblocks; /* Array of pointers to pinned child indirect blocks */
+
+ /* Stored values */
+ hsize_t block_off; /* Offset of the block within the heap's address space */
+ H5HF_indirect_ent_t *ents; /* Pointer to block entry table */
+ H5HF_indirect_filt_ent_t *filt_ents; /* Pointer to filtered information for direct blocks */
+};
+
+/* A fractal heap direct block */
+typedef struct H5HF_direct_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ /* Internal heap information */
+ H5HF_hdr_t *hdr; /* Shared heap header info */
+ H5HF_indirect_t *parent; /* Shared parent indirect block info */
+ H5HF_indirect_t *fd_parent; /* Saved copy of the parent pointer -- this */
+ /* necessary as the parent field is sometimes */
+ /* nulled out before the eviction notify call */
+ /* is made from the metadata cache. Since */
+ /* this call cancels flush dependencies, it */
+ /* needs this information. */
+ unsigned par_entry; /* Entry in parent's table */
+ size_t size; /* Size of direct block */
+ hsize_t file_size; /* Size of direct block in file (only valid when block's space is being freed) */
+ uint8_t *blk; /* Pointer to buffer containing block data */
+ uint8_t *write_buf; /* Pointer to buffer containing the block data */
+ /* in form ready to copy to the metadata */
+ /* cache's image buffer. */
+ /* */
+ /* This field is used by */
+ /* H5HF_cache_dblock_pre_serialize() to pass */
+ /* the serialized image of the direct block to */
+ /* H5HF_cache_dblock_serialize(). It should */
+ /* NULL at all other times. */
+ /* */
+ /* If I/O filters are enabled, the pre- */
+ /* the pre-serialize function will allocate */
+ /* a buffer, copy the filtered version of the */
+ /* direct block image into it, and place the */
+ /* base address of the buffer in this field. */
+ /* The serialize function must discard this */
+ /* buffer after it copies the contents into */
+ /* the image buffer provided by the metadata */
+ /* cache. */
+ /* */
+ /* If I/O filters are not enabled, the */
+ /* write_buf field is simply set equal to the */
+ /* blk field by the pre-serialize function, */
+ /* and back to NULL by the serialize function. */
+ size_t write_size; /* size of the buffer pointed to by write_buf. */
+
+ /* Stored values */
+ hsize_t block_off; /* Offset of the block within the heap's address space */
+} H5HF_direct_t;
+
+/* Fractal heap */
+struct H5HF_t {
+ H5HF_hdr_t *hdr; /* Pointer to internal fractal heap header info */
+ H5F_t *f; /* Pointer to file for heap */
+};
+
+/* Fractal heap "parent info" (for loading a block) */
+typedef struct H5HF_parent_t {
+ H5HF_hdr_t *hdr; /* Pointer to heap header info */
+ H5HF_indirect_t *iblock; /* Pointer to parent indirect block */
+ unsigned entry; /* Location of block in parent's entry table */
+} H5HF_parent_t;
+
+/* Typedef for indirectly accessed 'huge' object's records in the v2 B-tree */
+typedef struct H5HF_huge_bt2_indir_rec_t {
+ haddr_t addr; /* Address of the object in the file */
+ hsize_t len; /* Length of the object in the file */
+ hsize_t id; /* ID used for object (not used for 'huge' objects directly accessed) */
+} H5HF_huge_bt2_indir_rec_t;
+
+/* Typedef for indirectly accessed, filtered 'huge' object's records in the v2 B-tree */
+typedef struct H5HF_huge_bt2_filt_indir_rec_t {
+ haddr_t addr; /* Address of the filtered object in the file */
+ hsize_t len; /* Length of the filtered object in the file */
+ unsigned filter_mask; /* I/O pipeline filter mask for filtered object in the file */
+ hsize_t obj_size; /* Size of the de-filtered object in memory */
+ hsize_t id; /* ID used for object (not used for 'huge' objects directly accessed) */
+} H5HF_huge_bt2_filt_indir_rec_t;
+
+/* Typedef for directly accessed 'huge' object's records in the v2 B-tree */
+typedef struct H5HF_huge_bt2_dir_rec_t {
+ haddr_t addr; /* Address of the object in the file */
+ hsize_t len; /* Length of the object in the file */
+} H5HF_huge_bt2_dir_rec_t;
+
+/* Typedef for directly accessed, filtered 'huge' object's records in the v2 B-tree */
+typedef struct H5HF_huge_bt2_filt_dir_rec_t {
+ haddr_t addr; /* Address of the filtered object in the file */
+ hsize_t len; /* Length of the filtered object in the file */
+ unsigned filter_mask; /* I/O pipeline filter mask for filtered object in the file */
+ hsize_t obj_size; /* Size of the de-filtered object in memory */
+} H5HF_huge_bt2_filt_dir_rec_t;
+
+/* User data for free space section 'add' callback */
+typedef struct {
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ hid_t dxpl_id; /* DXPL ID for operation */
+} H5HF_sect_add_ud_t;
+
+/* User data for v2 B-tree 'remove' callback on 'huge' objects */
+typedef struct {
+ H5HF_hdr_t *hdr; /* Fractal heap header (in) */
+ hid_t dxpl_id; /* DXPL ID for operation (in) */
+ hsize_t obj_len; /* Length of object removed (out) */
+} H5HF_huge_remove_ud_t;
+
+/* User data for fractal heap header cache client callback */
+typedef struct H5HF_hdr_cache_ud_t {
+ H5F_t *f; /* File pointer */
+ hid_t dxpl_id; /* DXPL ID for operation (in) */
+} H5HF_hdr_cache_ud_t;
+
+/* User data for fractal heap indirect block cache client callbacks */
+typedef struct H5HF_iblock_cache_ud_t {
+ H5HF_parent_t * par_info; /* Parent info */
+ H5F_t * f; /* File pointer */
+ const unsigned *nrows; /* Number of rows */
+} H5HF_iblock_cache_ud_t;
+
+/* User data for fractal heap direct block cache client callbacks */
+typedef struct H5HF_dblock_cache_ud_t {
+ H5HF_parent_t par_info; /* Parent info */
+ H5F_t * f; /* File pointer */
+ size_t odi_size; /* On disk image size of the direct block.
+ * Note that there is no necessary relation
+ * between this value, and the actual
+ * direct block size, as conpression may
+ * reduce the size of the on disk image,
+ * and check sums may increase it.
+ */
+ size_t dblock_size; /* size of the direct block, which bears
+ * no necessary relation to the block
+ * odi_size -- the size of the on disk
+ * image of the block. Note that the
+ * metadata cache is only interested
+ * in the odi_size, and thus it is this
+ * value that is passed to the cache in
+ * calls to it.
+ */
+ unsigned filter_mask; /* Excluded filters for direct block */
+ uint8_t *dblk; /* Pointer to the buffer containing the decompressed
+ * direct block data obtained in verify_chksum callback.
+ * It will be used later in deserialize callback.
+ */
+ htri_t decompressed; /* Indicate that the direct block has been
+ * decompressed in verify_chksum callback.
+ * It will be used later in deserialize callback.
+ */
+} H5HF_dblock_cache_ud_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* The v2 B-tree class for tracking indirectly accessed 'huge' objects */
+H5_DLLVAR const H5B2_class_t H5HF_HUGE_BT2_INDIR[1];
+
+/* The v2 B-tree class for tracking indirectly accessed filtered 'huge' objects */
+H5_DLLVAR const H5B2_class_t H5HF_HUGE_BT2_FILT_INDIR[1];
+
+/* The v2 B-tree class for tracking directly accessed 'huge' objects */
+H5_DLLVAR const H5B2_class_t H5HF_HUGE_BT2_DIR[1];
+
+/* The v2 B-tree class for tracking directly accessed filtered 'huge' objects */
+H5_DLLVAR const H5B2_class_t H5HF_HUGE_BT2_FILT_DIR[1];
+
+/* H5HF single section inherits serializable properties from H5FS_section_class_t */
+H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_SINGLE[1];
+
+/* H5HF 'first' row section inherits serializable properties from H5FS_section_class_t */
+H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_FIRST_ROW[1];
+
+/* H5HF 'normal' row section inherits serializable properties from H5FS_section_class_t */
+H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_NORMAL_ROW[1];
+
+/* H5HF indirect section inherits serializable properties from H5FS_section_class_t */
+H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_INDIRECT[1];
+
+/* Declare a free list to manage the H5HF_indirect_t struct */
+H5FL_EXTERN(H5HF_indirect_t);
+
+/* Declare a free list to manage the H5HF_indirect_ent_t sequence information */
+H5FL_SEQ_EXTERN(H5HF_indirect_ent_t);
+
+/* Declare a free list to manage the H5HF_indirect_filt_ent_t sequence information */
+H5FL_SEQ_EXTERN(H5HF_indirect_filt_ent_t);
+
+/* Declare a free list to manage the H5HF_indirect_t * sequence information */
+typedef H5HF_indirect_t *H5HF_indirect_ptr_t;
+H5FL_SEQ_EXTERN(H5HF_indirect_ptr_t);
+
+/* Declare a free list to manage the H5HF_direct_t struct */
+H5FL_EXTERN(H5HF_direct_t);
+
+/* Declare a free list to manage heap direct block data to/from disk */
+H5FL_BLK_EXTERN(direct_block);
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Doubling table routines */
+H5_DLL herr_t H5HF_dtable_init(H5HF_dtable_t *dtable);
+H5_DLL herr_t H5HF_dtable_dest(H5HF_dtable_t *dtable);
+H5_DLL herr_t H5HF_dtable_lookup(const H5HF_dtable_t *dtable, hsize_t off,
+ unsigned *row, unsigned *col);
+H5_DLL unsigned H5HF_dtable_size_to_row(const H5HF_dtable_t *dtable, size_t block_size);
+H5_DLL unsigned H5HF_dtable_size_to_rows(const H5HF_dtable_t *dtable, hsize_t size);
+H5_DLL hsize_t H5HF_dtable_span_size(const H5HF_dtable_t *dtable, unsigned start_row,
+ unsigned start_col, unsigned num_entries);
+
+/* Heap header routines */
+H5_DLL H5HF_hdr_t * H5HF_hdr_alloc(H5F_t *f);
+H5_DLL haddr_t H5HF_hdr_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam);
+H5_DLL H5HF_hdr_t *H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ unsigned flags);
+H5_DLL herr_t H5HF_hdr_finish_init_phase1(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_finish_init_phase2(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_finish_init(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_incr(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_decr(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_fuse_incr(H5HF_hdr_t *hdr);
+H5_DLL size_t H5HF_hdr_fuse_decr(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_dirty(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_adj_free(H5HF_hdr_t *hdr, ssize_t amt);
+H5_DLL herr_t H5HF_hdr_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free);
+H5_DLL herr_t H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size);
+H5_DLL herr_t H5HF_hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry);
+H5_DLL herr_t H5HF_hdr_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries);
+H5_DLL herr_t H5HF_hdr_update_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size);
+H5_DLL herr_t H5HF_hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries);
+H5_DLL herr_t H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t dblock_addr);
+H5_DLL herr_t H5HF_hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off);
+H5_DLL herr_t H5HF_hdr_empty(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_free(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_hdr_delete(H5HF_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5HF_hdr_dest(H5HF_hdr_t *hdr);
+
+/* Indirect block routines */
+H5_DLL herr_t H5HF_iblock_incr(H5HF_indirect_t *iblock);
+H5_DLL herr_t H5HF_iblock_decr(H5HF_indirect_t *iblock);
+H5_DLL herr_t H5HF_iblock_dirty(H5HF_indirect_t *iblock);
+H5_DLL herr_t H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ size_t min_dblock_size);
+H5_DLL herr_t H5HF_man_iblock_root_double(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ size_t min_dblock_size);
+H5_DLL herr_t H5HF_man_iblock_alloc_row(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t **sec_node);
+H5_DLL herr_t H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_indirect_t *par_iblock, unsigned par_entry, unsigned nrows,
+ unsigned max_rows, haddr_t *addr_p);
+H5_DLL H5HF_indirect_t *H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t iblock_addr, unsigned iblock_nrows,
+ H5HF_indirect_t *par_iblock, unsigned par_entry, hbool_t must_protect,
+ unsigned flags, hbool_t *did_protect);
+H5_DLL herr_t H5HF_man_iblock_unprotect(H5HF_indirect_t *iblock, hid_t dxpl_id,
+ unsigned cache_flags, hbool_t did_protect);
+H5_DLL herr_t H5HF_man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry,
+ haddr_t dblock_addr);
+H5_DLL herr_t H5HF_man_iblock_detach(H5HF_indirect_t *iblock, hid_t dxpl_id, unsigned entry);
+H5_DLL herr_t H5HF_man_iblock_entry_addr(H5HF_indirect_t *iblock, unsigned entry,
+ haddr_t *child_addr);
+H5_DLL herr_t H5HF_man_iblock_delete(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t iblock_addr, unsigned iblock_nrows, H5HF_indirect_t *par_iblock,
+ unsigned par_entry);
+H5_DLL herr_t H5HF_man_iblock_size(H5F_t *f, hid_t dxpl_id, H5HF_hdr_t *hdr,
+ haddr_t iblock_addr, unsigned nrows, H5HF_indirect_t *par_iblock, unsigned par_entry, hsize_t *heap_size/*out*/);
+H5_DLL herr_t H5HF_man_iblock_dest(H5HF_indirect_t *iblock);
+
+/* Direct block routines */
+H5_DLL herr_t H5HF_man_dblock_new(H5HF_hdr_t *fh, hid_t dxpl_id, size_t request,
+ H5HF_free_section_t **ret_sec_node);
+H5_DLL herr_t H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr,
+ H5HF_indirect_t *par_iblock, unsigned par_entry, haddr_t *addr_p,
+ H5HF_free_section_t **ret_sec_node);
+H5_DLL herr_t H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_direct_t *dblock, haddr_t dblock_addr);
+H5_DLL H5HF_direct_t *H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ haddr_t dblock_addr, size_t dblock_size,
+ H5HF_indirect_t *par_iblock, unsigned par_entry,
+ unsigned flags);
+H5_DLL herr_t H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ hsize_t obj_off, H5HF_indirect_t **par_iblock,
+ unsigned *par_entry, hbool_t *par_did_protect, unsigned flags);
+H5_DLL herr_t H5HF_man_dblock_delete(H5F_t *f, hid_t dxpl_id, haddr_t dblock_addr,
+ hsize_t dblock_size);
+H5_DLL herr_t H5HF_man_dblock_dest(H5HF_direct_t *dblock);
+
+/* Managed object routines */
+H5_DLL herr_t H5HF_man_insert(H5HF_hdr_t *fh, hid_t dxpl_id, size_t obj_size,
+ const void *obj, void *id);
+H5_DLL herr_t H5HF_man_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id,
+ size_t *obj_len_p);
+H5_DLL void H5HF__man_get_obj_off(const H5HF_hdr_t *hdr, const uint8_t *id,
+ hsize_t *obj_off_p);
+H5_DLL herr_t H5HF_man_read(H5HF_hdr_t *fh, hid_t dxpl_id, const uint8_t *id,
+ void *obj);
+H5_DLL herr_t H5HF_man_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ const void *obj);
+H5_DLL herr_t H5HF_man_op(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ H5HF_operator_t op, void *op_data);
+H5_DLL herr_t H5HF_man_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id);
+
+/* 'Huge' object routines */
+H5_DLL herr_t H5HF_huge_init(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_huge_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t obj_size,
+ void *obj, void *id);
+H5_DLL herr_t H5HF_huge_get_obj_len(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ const uint8_t *id, size_t *obj_len_p);
+H5_DLL herr_t H5HF__huge_get_obj_off(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ const uint8_t *id, hsize_t *obj_off_p);
+H5_DLL herr_t H5HF_huge_read(H5HF_hdr_t *fh, hid_t dxpl_id, const uint8_t *id,
+ void *obj);
+H5_DLL herr_t H5HF_huge_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ const void *obj);
+H5_DLL herr_t H5HF_huge_op(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id,
+ H5HF_operator_t op, void *op_data);
+H5_DLL herr_t H5HF_huge_remove(H5HF_hdr_t *fh, hid_t dxpl_id, const uint8_t *id);
+H5_DLL herr_t H5HF_huge_term(H5HF_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5HF_huge_delete(H5HF_hdr_t *hdr, hid_t dxpl_id);
+
+/* 'Huge' object v2 B-tree function callbacks */
+H5_DLL herr_t H5HF__huge_bt2_indir_found(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_indir_remove(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_filt_indir_found(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_filt_indir_remove(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_dir_remove(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_filt_dir_found(const void *nrecord, void *op_data);
+H5_DLL herr_t H5HF__huge_bt2_filt_dir_remove(const void *nrecord, void *op_data);
+
+/* 'Tiny' object routines */
+H5_DLL herr_t H5HF_tiny_init(H5HF_hdr_t *hdr);
+H5_DLL herr_t H5HF_tiny_insert(H5HF_hdr_t *hdr, size_t obj_size, const void *obj,
+ void *id);
+H5_DLL herr_t H5HF_tiny_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id,
+ size_t *obj_len_p);
+H5_DLL herr_t H5HF_tiny_read(H5HF_hdr_t *fh, const uint8_t *id, void *obj);
+H5_DLL herr_t H5HF_tiny_op(H5HF_hdr_t *hdr, const uint8_t *id,
+ H5HF_operator_t op, void *op_data);
+H5_DLL herr_t H5HF_tiny_remove(H5HF_hdr_t *fh, const uint8_t *id);
+
+/* Debugging routines for dumping file structures */
+H5_DLL void H5HF_hdr_print(const H5HF_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t dump_internal, FILE *stream, int indent, int fwidth);
+H5_DLL herr_t H5HF_hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth);
+H5_DLL herr_t H5HF_dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, haddr_t hdr_addr, size_t nrec);
+H5_DLL void H5HF_iblock_print(const H5HF_indirect_t *iblock, hbool_t dump_internal,
+ FILE *stream, int indent, int fwidth);
+H5_DLL herr_t H5HF_iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth, haddr_t hdr_addr, unsigned nrows);
+
+/* Block iteration routines */
+H5_DLL herr_t H5HF_man_iter_init(H5HF_block_iter_t *biter);
+H5_DLL herr_t H5HF_man_iter_start_offset(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_block_iter_t *biter, hsize_t offset);
+H5_DLL herr_t H5HF_man_iter_start_entry(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter,
+ H5HF_indirect_t *iblock, unsigned start_entry);
+H5_DLL herr_t H5HF_man_iter_set_entry(const H5HF_hdr_t *hdr,
+ H5HF_block_iter_t *biter, unsigned entry);
+H5_DLL herr_t H5HF_man_iter_next(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter,
+ unsigned nentries);
+H5_DLL herr_t H5HF_man_iter_up(H5HF_block_iter_t *biter);
+H5_DLL herr_t H5HF_man_iter_down(H5HF_block_iter_t *biter, H5HF_indirect_t *iblock);
+H5_DLL herr_t H5HF_man_iter_reset(H5HF_block_iter_t *biter);
+H5_DLL herr_t H5HF_man_iter_curr(H5HF_block_iter_t *biter, unsigned *row, unsigned *col,
+ unsigned *entry, H5HF_indirect_t **block);
+H5_DLL herr_t H5HF_man_iter_offset(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter,
+ hsize_t *offset);
+H5_DLL hbool_t H5HF_man_iter_ready(H5HF_block_iter_t *biter);
+
+/* Free space manipulation routines */
+H5_DLL herr_t H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id, hbool_t may_create);
+H5_DLL herr_t H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *node, unsigned flags);
+H5_DLL htri_t H5HF_space_find(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t request,
+ H5HF_free_section_t **node);
+H5_DLL herr_t H5HF_space_revert_root(const H5HF_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5HF_space_create_root(const H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_indirect_t *root_iblock);
+H5_DLL herr_t H5HF_space_size(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t *fs_size);
+H5_DLL herr_t H5HF_space_remove(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *node);
+H5_DLL herr_t H5HF_space_close(H5HF_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5HF_space_delete(H5HF_hdr_t *hdr, hid_t dxpl_id);
+H5_DLL herr_t H5HF_space_sect_change_class(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, uint16_t new_class);
+
+/* Free space section routines */
+H5_DLL H5HF_free_section_t *H5HF_sect_single_new(hsize_t sect_off,
+ size_t sect_size, H5HF_indirect_t *parent, unsigned par_entry);
+H5_DLL herr_t H5HF_sect_single_revive(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+H5_DLL herr_t H5HF_sect_single_dblock_info(H5HF_hdr_t *hdr,
+ H5HF_free_section_t *sect, haddr_t *dblock_addr, size_t *dblock_size);
+H5_DLL herr_t H5HF_sect_single_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, size_t amt);
+H5_DLL herr_t H5HF_sect_row_revive(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+H5_DLL herr_t H5HF_sect_row_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, unsigned *entry_p);
+H5_DLL H5HF_indirect_t *H5HF_sect_row_get_iblock(H5HF_free_section_t *sect);
+H5_DLL herr_t H5HF_sect_indirect_add(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries);
+H5_DLL herr_t H5HF_sect_single_free(H5FS_section_info_t *sect);
+
+/* Internal operator callbacks */
+H5_DLL herr_t H5HF_op_read(const void *obj, size_t obj_len, void *op_data);
+H5_DLL herr_t H5HF_op_write(const void *obj, size_t obj_len, void *op_data);
+
+/* Testing routines */
+#ifdef H5HF_TESTING
+H5_DLL herr_t H5HF_get_cparam_test(const H5HF_t *fh, H5HF_create_t *cparam);
+H5_DLL int H5HF_cmp_cparam_test(const H5HF_create_t *cparam1, const H5HF_create_t *cparam2);
+H5_DLL unsigned H5HF_get_max_root_rows(const H5HF_t *fh);
+H5_DLL unsigned H5HF_get_dtable_width_test(const H5HF_t *fh);
+H5_DLL unsigned H5HF_get_dtable_max_drows_test(const H5HF_t *fh);
+H5_DLL unsigned H5HF_get_iblock_max_drows_test(const H5HF_t *fh, unsigned pos);
+H5_DLL hsize_t H5HF_get_dblock_size_test(const H5HF_t *fh, unsigned row);
+H5_DLL hsize_t H5HF_get_dblock_free_test(const H5HF_t *fh, unsigned row);
+H5_DLL herr_t H5HF_get_id_off_test(const H5HF_t *fh, const void *id, hsize_t *obj_off);
+H5_DLL herr_t H5HF_get_id_type_test(const void *id, unsigned char *obj_type);
+H5_DLL herr_t H5HF_get_tiny_info_test(const H5HF_t *fh, size_t *max_len,
+ hbool_t *len_extended);
+H5_DLL herr_t H5HF_get_huge_info_test(const H5HF_t *fh, hsize_t *next_id,
+ hbool_t *ids_direct);
+#endif /* H5HF_TESTING */
+
+#endif /* _H5HFpkg_H */
+
diff --git a/src/H5HFprivate.h b/src/H5HFprivate.h
new file mode 100644
index 0000000..8cf4b3c
--- /dev/null
+++ b/src/H5HFprivate.h
@@ -0,0 +1,142 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFprivate.h
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Private header for library accessible fractal heap routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5HFprivate_H
+#define _H5HFprivate_H
+
+/* Include package's public header */
+#include "H5HFpublic.h"
+
+/* Private headers needed by this file */
+#include "H5Fprivate.h" /* File access */
+#include "H5Oprivate.h" /* Object headers */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Limit heap ID length to 4096 + 1, due to # of bits required to store
+ * length of 'tiny' objects (12 bits)
+ */
+#define H5HF_MAX_ID_LEN (4096 + 1)
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Creation parameters for doubling-tables */
+typedef struct H5HF_dtable_cparam_t {
+ unsigned width; /* Number of columns in the table (must be power of 2) */
+ size_t start_block_size; /* Starting block size for table (must be power of 2) */
+ size_t max_direct_size; /* Maximum size of a direct block (must be power of 2) */
+ unsigned max_index; /* Maximum ID/offset for table (integer log2 of actual value, ie. the # of bits required) */
+ unsigned start_root_rows; /* Starting number of rows for root indirect block */
+ /* 0 indicates to create the full indirect block for the root,
+ * right from the start. Doesn't have to be power of 2
+ */
+} H5HF_dtable_cparam_t;
+
+/* Fractal heap creation parameters */
+typedef struct H5HF_create_t {
+ H5HF_dtable_cparam_t managed;/* Mapped object doubling-table creation parameters */
+ hbool_t checksum_dblocks; /* Whether the direct blocks should be checksummed */
+ uint32_t max_man_size; /* Max. size of object to manage in doubling table */
+ /* (i.e. min. size of object to store standalone) */
+ uint16_t id_len; /* Length of IDs to use for heap objects */
+ /* (0 - make ID just large enough to hold length & offset of object in the heap) */
+ /* (1 - make ID just large enough to allow 'huge' objects to be accessed directly) */
+ /* (n - make ID 'n' bytes in size) */
+ H5O_pline_t pline; /* I/O filter pipeline to apply to direct blocks & 'huge' objects */
+} H5HF_create_t;
+
+/* Fractal heap metadata statistics info */
+typedef struct H5HF_stat_t {
+ /* 'Managed' object info */
+ hsize_t man_size; /* Size of 'managed' space in heap */
+ hsize_t man_alloc_size; /* Size of 'managed' space allocated in heap */
+ hsize_t man_iter_off; /* Offset of "new block" iterator in 'managed' heap space */
+ hsize_t man_free_space; /* Free space within 'managed' heap blocks */
+ hsize_t man_nobjs; /* Number of 'managed' objects in heap */
+
+ /* 'Huge' object info */
+ hsize_t huge_size; /* Size of 'huge' objects in heap */
+ hsize_t huge_nobjs; /* Number of 'huge' objects in heap */
+
+ /* 'Tiny' object info */
+ hsize_t tiny_size; /* Size of 'tiny' objects in heap */
+ hsize_t tiny_nobjs; /* Number of 'tiny' objects in heap */
+} H5HF_stat_t;
+
+/* Fractal heap info (forward decl - defined in H5HFpkg.h) */
+typedef struct H5HF_t H5HF_t;
+
+/* Typedef for 'op' operations */
+typedef herr_t (*H5HF_operator_t)(const void *obj/*in*/, size_t obj_len,
+ void *op_data/*in,out*/);
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General routines for fractal heap operations */
+H5_DLL H5HF_t *H5HF_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam);
+H5_DLL H5HF_t *H5HF_open(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr);
+H5_DLL herr_t H5HF_get_id_len(H5HF_t *fh, size_t *id_len_p/*out*/);
+H5_DLL herr_t H5HF_get_heap_addr(const H5HF_t *fh, haddr_t *heap_addr/*out*/);
+H5_DLL herr_t H5HF_insert(H5HF_t *fh, hid_t dxpl_id, size_t size,
+ const void *obj, void *id/*out*/);
+H5_DLL herr_t H5HF_get_obj_len(H5HF_t *fh, hid_t dxpl_id, const void *id,
+ size_t *obj_len_p/*out*/);
+H5_DLL herr_t H5HF_get_obj_off(H5HF_t *fh, hid_t dxpl_id, const void *_id,
+ hsize_t *obj_off_p/*out*/);
+H5_DLL herr_t H5HF_read(H5HF_t *fh, hid_t dxpl_id, const void *id,
+ void *obj/*out*/);
+H5_DLL herr_t H5HF_write(H5HF_t *fh, hid_t dxpl_id, void *id, hbool_t *id_changed,
+ const void *obj);
+H5_DLL herr_t H5HF_op(H5HF_t *fh, hid_t dxpl_id, const void *id,
+ H5HF_operator_t op, void *op_data);
+H5_DLL herr_t H5HF_remove(H5HF_t *fh, hid_t dxpl_id, const void *id);
+H5_DLL herr_t H5HF_close(H5HF_t *fh, hid_t dxpl_id);
+H5_DLL herr_t H5HF_delete(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr);
+
+/* Statistics routines */
+H5_DLL herr_t H5HF_stat_info(const H5HF_t *fh, H5HF_stat_t *stats);
+H5_DLL herr_t H5HF_size(const H5HF_t *fh, hid_t dxpl_id, hsize_t *heap_size/*out*/);
+
+/* Debugging routines */
+H5_DLL herr_t H5HF_id_print(H5HF_t *fh, hid_t dxpl_id,
+ const void *id, FILE *stream, int indent, int fwidth);
+#ifdef H5HF_DEBUGGING
+H5_DLL herr_t H5HF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth);
+#endif /* H5HF_DEBUGGING */
+
+#endif /* _H5HFprivate_H */
+
diff --git a/src/H5HFpublic.h b/src/H5HFpublic.h
new file mode 100644
index 0000000..82cfc21
--- /dev/null
+++ b/src/H5HFpublic.h
@@ -0,0 +1,52 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFpublic.h
+ * Feb 24 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Public declarations for the fractal heap package.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5HFpublic_H
+#define _H5HFpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/**********************************/
+/* Public API Function Prototypes */
+/**********************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5HFpublic_H */
+
diff --git a/src/H5HFsection.c b/src/H5HFsection.c
new file mode 100644
index 0000000..42c12ec
--- /dev/null
+++ b/src/H5HFsection.c
@@ -0,0 +1,4185 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Monday, May 1, 2006
+ *
+ * Purpose: Free space section routines for fractal heaps
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Size of serialized indirect section information */
+#define H5HF_SECT_INDIRECT_SERIAL_SIZE(h) ( \
+ (unsigned)(h)->heap_off_size /* Indirect block's offset in "heap space" */ \
+ + (unsigned)2 /* Row */ \
+ + (unsigned)2 /* Column */ \
+ + (unsigned)2 /* # of entries */ \
+ )
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for "class private" information for sections */
+typedef struct {
+ H5HF_hdr_t *hdr; /* Pointer to fractal heap header */
+} H5HF_sect_private_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Shared routines */
+static herr_t H5HF_sect_init_cls(H5FS_section_class_t *cls,
+ H5HF_hdr_t *hdr);
+static herr_t H5HF_sect_term_cls(H5FS_section_class_t *cls);
+static H5HF_free_section_t *H5HF_sect_node_new(unsigned sect_type,
+ haddr_t sect_addr, hsize_t sect_size, H5FS_section_state_t state);
+static herr_t H5HF_sect_node_free(H5HF_free_section_t *sect,
+ H5HF_indirect_t *parent);
+
+/* 'single' section routines */
+static herr_t H5HF_sect_single_locate_parent(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ hbool_t refresh, H5HF_free_section_t *sect);
+static herr_t H5HF_sect_single_full_dblock(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+
+/* 'single' section callbacks */
+static herr_t H5HF_sect_single_add(H5FS_section_info_t **sect, unsigned *flags,
+ void *udata);
+static H5FS_section_info_t *H5HF_sect_single_deserialize(const H5FS_section_class_t *cls,
+ hid_t dxpl_id, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags);
+static htri_t H5HF_sect_single_can_merge(const H5FS_section_info_t *sect1,
+ const H5FS_section_info_t *sect2, void *udata);
+static herr_t H5HF_sect_single_merge(H5FS_section_info_t **sect1,
+ H5FS_section_info_t *sect2, void *udata);
+static htri_t H5HF_sect_single_can_shrink(const H5FS_section_info_t *sect,
+ void *udata);
+static herr_t H5HF_sect_single_shrink(H5FS_section_info_t **_sect,
+ void *udata);
+static herr_t H5HF_sect_single_valid(const H5FS_section_class_t *cls,
+ const H5FS_section_info_t *sect, hid_t dxpl_id);
+
+/* 'row' section routines */
+static H5HF_free_section_t *H5HF_sect_row_create(haddr_t sect_off,
+ hsize_t sect_size, hbool_t is_first, unsigned row, unsigned col,
+ unsigned nentries, H5HF_free_section_t *under_sect);
+static herr_t H5HF_sect_row_first(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+static herr_t H5HF_sect_row_from_single(H5HF_hdr_t *hdr,
+ H5HF_free_section_t *sect, H5HF_direct_t *dblock);
+static herr_t H5HF_sect_row_free_real(H5HF_free_section_t *sect);
+
+/* 'row' section callbacks */
+static herr_t H5HF_sect_row_init_cls(H5FS_section_class_t *cls, void *udata);
+static herr_t H5HF_sect_row_term_cls(H5FS_section_class_t *cls);
+static herr_t H5HF_sect_row_serialize(const H5FS_section_class_t *cls,
+ const H5FS_section_info_t *sect, uint8_t *buf);
+static H5FS_section_info_t *H5HF_sect_row_deserialize(const H5FS_section_class_t *cls,
+ hid_t dxpl_id, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags);
+static htri_t H5HF_sect_row_can_merge(const H5FS_section_info_t *sect1,
+ const H5FS_section_info_t *sect2, void *udata);
+static herr_t H5HF_sect_row_merge(H5FS_section_info_t **sect1,
+ H5FS_section_info_t *sect2, void *udata);
+static htri_t H5HF_sect_row_can_shrink(const H5FS_section_info_t *sect,
+ void *udata);
+static herr_t H5HF_sect_row_shrink(H5FS_section_info_t **sect,
+ void *udata);
+static herr_t H5HF_sect_row_free(H5FS_section_info_t *sect);
+static herr_t H5HF_sect_row_valid(const H5FS_section_class_t *cls,
+ const H5FS_section_info_t *sect, hid_t dxpl_id);
+static herr_t H5HF_sect_row_debug(const H5FS_section_info_t *sect,
+ FILE *stream, int indent, int fwidth);
+
+/* 'indirect' section routines */
+static H5HF_free_section_t *H5HF_sect_indirect_new(H5HF_hdr_t *hdr,
+ haddr_t sect_off, hsize_t sect_size,
+ H5HF_indirect_t *iblock, hsize_t iblock_off,
+ unsigned row, unsigned col, unsigned nentries);
+static herr_t H5HF_sect_indirect_init_rows(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, hbool_t first_child, H5HF_free_section_t **first_row_sect,
+ unsigned space_flags, unsigned start_row, unsigned start_col,
+ unsigned end_row, unsigned end_col);
+static H5HF_free_section_t *H5HF_sect_indirect_for_row(H5HF_hdr_t *hdr,
+ H5HF_indirect_t *iblock, H5HF_free_section_t *row_sect);
+static herr_t H5HF_sect_indirect_decr(H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_revive_row(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, H5HF_indirect_t *sect_iblock);
+static herr_t H5HF_sect_indirect_reduce_row(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *row_sect, hbool_t *alloc_from_start);
+static herr_t H5HF_sect_indirect_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, unsigned child_entry);
+static herr_t H5HF_sect_indirect_first(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+static hbool_t H5HF_sect_indirect_is_first(H5HF_free_section_t *sect);
+static H5HF_indirect_t * H5HF_sect_indirect_get_iblock(H5HF_free_section_t *sect);
+static hsize_t H5HF_sect_indirect_iblock_off(const H5HF_free_section_t *sect);
+static H5HF_free_section_t * H5HF_sect_indirect_top(H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_merge_row(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect1, H5HF_free_section_t *sect2);
+static herr_t H5HF_sect_indirect_build_parent(H5HF_hdr_t *hdr, H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_shrink(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_serialize(H5HF_hdr_t *hdr,
+ const H5HF_free_section_t *sect, uint8_t *buf);
+static H5FS_section_info_t *H5HF_sect_indirect_deserialize(H5HF_hdr_t *hdr,
+ hid_t dxpl_id, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags);
+static herr_t H5HF_sect_indirect_free(H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_valid(const H5HF_hdr_t *hdr,
+ const H5HF_free_section_t *sect);
+static herr_t H5HF_sect_indirect_debug(const H5HF_free_section_t *sect,
+ FILE *stream, int indent, int fwidth);
+
+/* 'indirect' section callbacks */
+static herr_t H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, void *udata);
+static herr_t H5HF_sect_indirect_term_cls(H5FS_section_class_t *cls);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Class info for "single" free space sections */
+H5FS_section_class_t H5HF_FSPACE_SECT_CLS_SINGLE[1] = {{
+ /* Class variables */
+ H5HF_FSPACE_SECT_SINGLE, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ NULL, /* Initialize section class */
+ NULL, /* Terminate section class */
+
+ /* Object methods */
+ H5HF_sect_single_add, /* Add section */
+ NULL, /* Serialize section */
+ H5HF_sect_single_deserialize, /* Deserialize section */
+ H5HF_sect_single_can_merge, /* Can sections merge? */
+ H5HF_sect_single_merge, /* Merge sections */
+ H5HF_sect_single_can_shrink, /* Can section shrink container?*/
+ H5HF_sect_single_shrink, /* Shrink container w/section */
+ H5HF_sect_single_free, /* Free section */
+ H5HF_sect_single_valid, /* Check validity of section */
+ NULL, /* Split section node for alignment */
+ NULL, /* Dump debugging for section */
+}};
+
+/* Class info for "first row" free space sections */
+/* (Same as "normal" row sections, except they also act as a proxy for the
+ * underlying indirect section
+ */
+H5FS_section_class_t H5HF_FSPACE_SECT_CLS_FIRST_ROW[1] = {{
+ /* Class variables */
+ H5HF_FSPACE_SECT_FIRST_ROW, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ H5HF_sect_row_init_cls, /* Initialize section class */
+ H5HF_sect_row_term_cls, /* Terminate section class */
+
+ /* Object methods */
+ NULL, /* Add section */
+ H5HF_sect_row_serialize, /* Serialize section */
+ H5HF_sect_row_deserialize, /* Deserialize section */
+ H5HF_sect_row_can_merge, /* Can sections merge? */
+ H5HF_sect_row_merge, /* Merge sections */
+ H5HF_sect_row_can_shrink, /* Can section shrink container?*/
+ H5HF_sect_row_shrink, /* Shrink container w/section */
+ H5HF_sect_row_free, /* Free section */
+ H5HF_sect_row_valid, /* Check validity of section */
+ NULL, /* Split section node for alignment */
+ H5HF_sect_row_debug, /* Dump debugging for section */
+}};
+
+/* Class info for "normal row" free space sections */
+H5FS_section_class_t H5HF_FSPACE_SECT_CLS_NORMAL_ROW[1] = {{
+ /* Class variables */
+ H5HF_FSPACE_SECT_NORMAL_ROW, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM|H5FS_CLS_SEPAR_OBJ|H5FS_CLS_GHOST_OBJ, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ H5HF_sect_row_init_cls, /* Initialize section class */
+ H5HF_sect_row_term_cls, /* Terminate section class */
+
+ /* Object methods */
+ NULL, /* Add section */
+ NULL, /* Serialize section */
+ NULL, /* Deserialize section */
+ NULL, /* Can sections merge? */
+ NULL, /* Merge sections */
+ NULL, /* Can section shrink container?*/
+ NULL, /* Shrink container w/section */
+ H5HF_sect_row_free, /* Free section */
+ H5HF_sect_row_valid, /* Check validity of section */
+ NULL, /* Split section node for alignment */
+ H5HF_sect_row_debug, /* Dump debugging for section */
+}};
+
+/* Class info for "indirect" free space sections */
+/* (No object callbacks necessary - objects of this class should never be in
+ * section manager)
+ */
+H5FS_section_class_t H5HF_FSPACE_SECT_CLS_INDIRECT[1] = {{
+ /* Class variables */
+ H5HF_FSPACE_SECT_INDIRECT, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM|H5FS_CLS_GHOST_OBJ, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ H5HF_sect_indirect_init_cls, /* Initialize section class */
+ H5HF_sect_indirect_term_cls, /* Terminate section class */
+
+ /* Object methods */
+ NULL, /* Add section */
+ NULL, /* Serialize section */
+ NULL, /* Deserialize section */
+ NULL, /* Can sections merge? */
+ NULL, /* Merge sections */
+ NULL, /* Can section shrink container?*/
+ NULL, /* Shrink container w/section */
+ NULL, /* Free section */
+ NULL, /* Check validity of section */
+ NULL, /* Split section node for alignment */
+ NULL, /* Dump debugging for section */
+}};
+
+/* Declare a free list to manage the H5HF_free_section_t struct */
+H5FL_DEFINE(H5HF_free_section_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_init_cls
+ *
+ * Purpose: Initialize the common class structure
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 25, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_init_cls(H5FS_section_class_t *cls, H5HF_hdr_t *hdr)
+{
+ H5HF_sect_private_t *cls_prvt; /* Pointer to class private info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(!cls->cls_private);
+
+ /* Allocate & initialize the class-private (i.e. private shared) information
+ * for this type of section
+ */
+ if(NULL == (cls_prvt = (H5HF_sect_private_t *)H5MM_malloc(sizeof(H5HF_sect_private_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ cls_prvt->hdr = hdr;
+ cls->cls_private = cls_prvt;
+
+ /* Increment reference count on heap header */
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_init_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_term_cls
+ *
+ * Purpose: Terminate the common class structure
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 25, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_term_cls(H5FS_section_class_t *cls)
+{
+ H5HF_sect_private_t *cls_prvt; /* Pointer to class private info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+
+ /* Get pointer to class private info */
+ cls_prvt = (H5HF_sect_private_t *)cls->cls_private;
+
+ /* Decrement reference count on heap header */
+ if(H5HF_hdr_decr(cls_prvt->hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
+
+ /* Free the class private information */
+ cls->cls_private = H5MM_xfree(cls_prvt);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_term_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_node_new
+ *
+ * Purpose: Allocate a free space section node of a particular type
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_free_section_t *
+H5HF_sect_node_new(unsigned sect_type, haddr_t sect_addr, hsize_t sect_size,
+ H5FS_section_state_t sect_state)
+{
+ H5HF_free_section_t *new_sect; /* New section */
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(H5F_addr_defined(sect_addr));
+
+ /* Create free list section node */
+ if(NULL == (new_sect = H5FL_MALLOC(H5HF_free_section_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section")
+
+ /* Set the information passed in */
+ new_sect->sect_info.addr = sect_addr;
+ new_sect->sect_info.size = sect_size;
+
+ /* Set the section's class & state */
+ new_sect->sect_info.type = sect_type;
+ new_sect->sect_info.state = sect_state;
+
+ /* Set return value */
+ ret_value = new_sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_node_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_node_free
+ *
+ * Purpose: Free a section node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_node_free(H5HF_free_section_t *sect, H5HF_indirect_t *iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(sect);
+
+ /* Release indirect block, if there was one */
+ if(iblock)
+ if(H5HF_iblock_decr(iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
+
+ /* Release the section */
+ sect = H5FL_FREE(H5HF_free_section_t, sect);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_node_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_new
+ *
+ * Purpose: Create a new 'single' section and return it to the caller
+ *
+ * Return: Pointer to new section on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 30 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_free_section_t *
+H5HF_sect_single_new(hsize_t sect_off, size_t sect_size,
+ H5HF_indirect_t *parent, unsigned par_entry)
+{
+ H5HF_free_section_t *sect = NULL; /* 'Single' free space section to add */
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect_size);
+
+ /* Create free space section node */
+ if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_off, (hsize_t)sect_size, H5FS_SECT_LIVE)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for single section")
+
+ /* Set the 'single' specific fields */
+ sect->u.single.parent = parent;
+ if(sect->u.single.parent) {
+ if(H5HF_iblock_incr(sect->u.single.parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
+ } /* end if */
+ sect->u.single.par_entry = par_entry;
+
+ /* Set return value */
+ ret_value = sect;
+
+done:
+ if(!ret_value && sect) {
+ /* Release the section */
+ sect = H5FL_FREE(H5HF_free_section_t, sect);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_single_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_locate_parent
+ *
+ * Purpose: Locate the parent indirect block for a single section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * October 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_locate_parent(H5HF_hdr_t *hdr, hid_t dxpl_id, hbool_t refresh,
+ H5HF_free_section_t *sect)
+{
+ H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */
+ unsigned sec_entry; /* Entry within section indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(hdr->man_dtable.curr_root_rows > 0);
+ HDassert(sect);
+
+ /* Look up indirect block containing direct blocks for range */
+ if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, &sec_entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
+
+ /* Increment reference count on indirect block that free section is in */
+ if(H5HF_iblock_incr(sec_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+
+ /* Check for refreshing existing parent information */
+ if(refresh) {
+ if(sect->u.single.parent) {
+ /* Release hold on previous parent indirect block */
+ if(H5HF_iblock_decr(sect->u.single.parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
+ } /* end if */
+ } /* end if */
+
+ /* Set the information for the section */
+ sect->u.single.parent = sec_iblock;
+ sect->u.single.par_entry = sec_entry;
+
+ /* Unlock indirect block */
+ if(H5HF_man_iblock_unprotect(sec_iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ sec_iblock = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_single_locate_parent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_revive
+ *
+ * Purpose: Update the memory information for a 'single' free section
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_single_revive(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
+
+ /* Check for root direct block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ /* Set the information for the section */
+ HDassert(H5F_addr_defined(hdr->man_dtable.table_addr));
+ sect->u.single.parent = NULL;
+ sect->u.single.par_entry = 0;
+ } /* end if */
+ else {
+ /* Look up indirect block information for section */
+ if(H5HF_sect_single_locate_parent(hdr, dxpl_id, FALSE, sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get section's parent info")
+ } /* end else */
+
+ /* Section is "live" now */
+ sect->sect_info.state = H5FS_SECT_LIVE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_single_revive() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_dblock_info
+ *
+ * Purpose: Retrieve the direct block information for a single section
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * October 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_single_dblock_info(H5HF_hdr_t *hdr,
+ H5HF_free_section_t *sect, haddr_t *dblock_addr, size_t *dblock_size)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(dblock_addr);
+ HDassert(dblock_size);
+
+ /* Check for root direct block */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ /* Retrieve direct block info from heap header */
+ HDassert(H5F_addr_defined(hdr->man_dtable.table_addr));
+ *dblock_addr = hdr->man_dtable.table_addr;
+ *dblock_size = hdr->man_dtable.cparam.start_block_size;
+ } /* end if */
+ else {
+ /* Retrieve direct block info from parent indirect block */
+ *dblock_addr = sect->u.single.parent->ents[sect->u.single.par_entry].addr;
+ *dblock_size = hdr->man_dtable.row_block_size[sect->u.single.par_entry / hdr->man_dtable.cparam.width];
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_sect_single_dblock_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_reduce
+ *
+ * Purpose: Reduce the size of a single section (possibly freeing it)
+ * and re-add it back to the free space manager for the heap
+ * (if it hasn't been freed)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 31 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_single_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, size_t amt)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+
+ /* Check for eliminating the section */
+ if(sect->sect_info.size == amt) {
+ /* Free single section */
+ if(H5HF_sect_single_free((H5FS_section_info_t *)sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free single section node")
+ } /* end if */
+ else {
+ /* Adjust information for section */
+ sect->sect_info.addr += amt;
+ sect->sect_info.size -= amt;
+
+ /* Re-insert section node into heap's free space */
+ if(H5HF_space_add(hdr, dxpl_id, sect, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add single section to free space manager")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_single_reduce() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_full_dblock
+ *
+ * Purpose: Checks if a single section covers the entire direct block
+ * that it resides in, and converts it to a row section if so
+ *
+ * Note: Does not convert a single section to a row section if the
+ * single section is for a root direct block
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_full_dblock(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect)
+{
+ haddr_t dblock_addr; /* Section's direct block's address */
+ size_t dblock_size; /* Section's direct block's size */
+ size_t dblock_overhead; /* Direct block's overhead */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(hdr);
+
+ /* Retrieve direct block address from section */
+ if(H5HF_sect_single_dblock_info(hdr, sect, &dblock_addr, &dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information")
+
+ /* Check for section occupying entire direct block */
+ /* (and not the root direct block) */
+ dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ if((dblock_size - dblock_overhead) == sect->sect_info.size &&
+ hdr->man_dtable.curr_root_rows > 0) {
+ H5HF_direct_t *dblock; /* Pointer to direct block for section */
+
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect->u.single.parent, sect->u.single.par_entry, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block")
+ HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect->sect_info.addr));
+
+ /* Convert 'single' section into 'row' section */
+ if(H5HF_sect_row_from_single(hdr, sect, dblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't convert single section into row section")
+
+ /* Destroy direct block */
+ if(H5HF_man_dblock_destroy(hdr, dxpl_id, dblock, dblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block")
+ dblock = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_full_dblock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_add
+ *
+ * Purpose: Perform any actions on section as it is added to free space
+ * manager
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Don't need to check section if we are deserializing, because it should
+ * have already been checked when it was first added
+ */
+ if(!(*flags & H5FS_ADD_DESERIALIZING)) {
+ H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */
+
+ /* Sanity check */
+ HDassert(sect);
+ HDassert(hdr);
+
+ /* Check if single section covers entire direct block it's in */
+ /* (converts to row section possibly) */
+ if(H5HF_sect_single_full_dblock(hdr, dxpl_id, (*sect)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't check/convert single section")
+
+ /* Set the "returned space" flag if the single section was changed
+ * into a row section, so the "merging & shrinking" algorithm
+ * gets executed in the free space manager
+ */
+ if((*sect)->sect_info.type != H5HF_FSPACE_SECT_SINGLE)
+ *flags |= H5FS_ADD_RETURNED_SPACE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_deserialize
+ *
+ * Purpose: Deserialize a buffer into a "live" single section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 1, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FS_section_info_t *
+H5HF_sect_single_deserialize(const H5FS_section_class_t H5_ATTR_UNUSED *cls,
+ hid_t H5_ATTR_UNUSED dxpl_id, const uint8_t H5_ATTR_UNUSED *buf, haddr_t sect_addr,
+ hsize_t sect_size, unsigned H5_ATTR_UNUSED *des_flags)
+{
+ H5HF_free_section_t *new_sect; /* New section */
+ H5FS_section_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(H5F_addr_defined(sect_addr));
+ HDassert(sect_size);
+
+ /* Create free list section node */
+ if(NULL == (new_sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_addr, sect_size, H5FS_SECT_SERIALIZED)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "allocation failed for direct block free list section")
+
+ /* Set return value */
+ ret_value = (H5FS_section_info_t *)new_sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_can_merge
+ *
+ * Purpose: Can two sections of this type merge?
+ *
+ * Note: Second section must be "after" first section
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF_sect_single_can_merge(const H5FS_section_info_t *_sect1,
+ const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_free_section_t *sect1 = (const H5HF_free_section_t *)_sect1; /* Fractal heap free section */
+ const H5HF_free_section_t *sect2 = (const H5HF_free_section_t *)_sect2; /* Fractal heap free section */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert(sect2);
+ HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
+ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
+
+ /* Check if second section adjoins first section */
+ /* (This can only occur within a direct block, due to the direct block
+ * overhead at the beginning of a block, so no need to check if sections
+ * are actually within the same direct block)
+ */
+ if(H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr))
+ HGOTO_DONE(TRUE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_can_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_merge
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
+ void *_udata)
+{
+ H5HF_free_section_t **sect1 = (H5HF_free_section_t **)_sect1; /* Fractal heap free section */
+ H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert((*sect1)->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+ HDassert(sect2);
+ HDassert(sect2->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+ HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
+
+ /* Add second section's size to first section */
+ (*sect1)->sect_info.size += sect2->sect_info.size;
+
+ /* Get rid of second section */
+ if(H5HF_sect_single_free((H5FS_section_info_t *)sect2) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+ /* Check to see if we should revive first section */
+ if((*sect1)->sect_info.state != H5FS_SECT_LIVE)
+ if(H5HF_sect_single_revive(hdr, dxpl_id, (*sect1)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
+
+ /* Check if single section covers entire direct block it's in */
+ /* (converts to row section possibly) */
+ if(H5HF_sect_single_full_dblock(hdr, dxpl_id, (*sect1)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't check/convert single section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_can_shrink
+ *
+ * Purpose: Can this section shrink the container?
+ *
+ * Note: This isn't actually shrinking the heap (since that's already
+ * been done) as much as it's cleaning up _after_ the heap
+ * shrink.
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF_sect_single_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
+{
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ /* Check for section occupying entire root direct block */
+ /* (We shouldn't ever have a single section that occupies an entire
+ * direct block, unless it's in the root direct block (because it
+ * would have been converted into a row section, if there was an
+ * indirect block that covered it)
+ */
+ if(hdr->man_dtable.curr_root_rows == 0) {
+ size_t dblock_size; /* Section's direct block's size */
+ size_t dblock_overhead; /* Direct block's overhead */
+
+ dblock_size = hdr->man_dtable.cparam.start_block_size;
+ dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ if((dblock_size - dblock_overhead) == sect->sect_info.size)
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ else {
+ /* We shouldn't have a situation where the 'next block' iterator
+ * is moved before a direct block that still has objects within it.
+ */
+ HDassert(hdr->man_iter_off > sect->sect_info.addr);
+ HGOTO_DONE(FALSE)
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_can_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_shrink
+ *
+ * Purpose: Shrink container with section
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_shrink(H5FS_section_info_t **_sect, void H5_ATTR_UNUSED *_udata)
+{
+ H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */
+ H5HF_direct_t *dblock; /* Pointer to direct block for section */
+ haddr_t dblock_addr; /* Section's direct block's address */
+ size_t dblock_size; /* Section's direct block's size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(*sect);
+ HDassert((*sect)->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+
+ /* Check to see if we should revive section */
+ if((*sect)->sect_info.state != H5FS_SECT_LIVE)
+ if(H5HF_sect_single_revive(hdr, dxpl_id, (*sect)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
+
+ /* Retrieve direct block address from section */
+ if(H5HF_sect_single_dblock_info(hdr, (*sect), &dblock_addr, &dblock_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information")
+
+ /* Protect the direct block for the section */
+ /* (should be a root direct block) */
+ HDassert(dblock_addr == hdr->man_dtable.table_addr);
+ if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr,
+ dblock_size, (*sect)->u.single.parent, (*sect)->u.single.par_entry, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block")
+ HDassert(H5F_addr_eq(dblock->block_off + dblock_size, (*sect)->sect_info.addr + (*sect)->sect_info.size));
+
+ /* Destroy direct block */
+ if(H5HF_man_dblock_destroy(hdr, dxpl_id, dblock, dblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block")
+ dblock = NULL;
+
+ /* Get rid of section */
+ if(H5HF_sect_single_free((H5FS_section_info_t *)*sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+ /* Indicate that the section has been released */
+ *sect = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_free
+ *
+ * Purpose: Free a 'single' section node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_single_free(H5FS_section_info_t *_sect)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Pointer to section to free */
+ H5HF_indirect_t *parent = NULL; /* Parent indirect block for section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ /* Check for live reference to an indirect block */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ /* Get parent indirect block, if there was one */
+ if(sect->u.single.parent)
+ parent = sect->u.single.parent;
+ } /* end if */
+
+ /* Release the section */
+ if(H5HF_sect_node_free(sect, parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_single_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_single_valid
+ *
+ * Purpose: Check the validity of a section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, July 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_single_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls, const H5FS_section_info_t *_sect, hid_t dxpl_id)
+{
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Pointer to section to check */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ /* Check if this section is not in a direct block that is the root direct block */
+ /* (not enough information to check on a single section in a root direct block) */
+ if(sect->u.single.parent != NULL) {
+ H5HF_indirect_t *iblock; /* Indirect block that section's direct block resides in */
+ haddr_t dblock_addr; /* Direct block address */
+ size_t dblock_size; /* Direct block size */
+ size_t dblock_overhead; /* Direct block's overhead */
+ unsigned dblock_status = 0; /* Direct block's status in the metadata cache */
+ herr_t status; /* Generic status value */
+
+ /* Sanity check settings for section's direct block's parent */
+ iblock = sect->u.single.parent;
+ HDassert(H5F_addr_defined(iblock->ents[sect->u.single.par_entry].addr));
+
+ /* Retrieve direct block address from section */
+ /* (Casting away const OK - QAK) */
+ status = H5HF_sect_single_dblock_info(iblock->hdr, (H5HF_free_section_t *)sect, &dblock_addr, &dblock_size);
+ HDassert(status >= 0);
+ HDassert(H5F_addr_eq(iblock->ents[sect->u.single.par_entry].addr, dblock_addr));
+ HDassert(dblock_size > 0);
+
+ /* Check if the section is actually within the heap */
+ HDassert(sect->sect_info.addr < iblock->hdr->man_iter_off);
+
+ /* Check that the direct block has been merged correctly */
+ dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(iblock->hdr);
+ HDassert((sect->sect_info.size + dblock_overhead) < dblock_size);
+
+ /* Check the direct block's status in the metadata cache */
+ status = H5AC_get_entry_status(iblock->hdr->f, dblock_addr, &dblock_status);
+ HDassert(status >= 0);
+
+ /* If the direct block for the section isn't already protected,
+ * protect it here in order to check single section's sanity
+ * against it.
+ */
+ if(!(dblock_status & H5AC_ES__IS_PROTECTED)) {
+ H5HF_direct_t *dblock; /* Direct block for section */
+
+ /* Protect the direct block for the section */
+ dblock = H5HF_man_dblock_protect(iblock->hdr, dxpl_id, dblock_addr, dblock_size, iblock, sect->u.single.par_entry, H5AC__READ_ONLY_FLAG);
+ HDassert(dblock);
+
+ /* Sanity check settings for section */
+ HDassert(dblock_size == dblock->size);
+ HDassert(dblock->size > sect->sect_info.size);
+ HDassert(H5F_addr_lt(dblock->block_off, sect->sect_info.addr));
+ HDassert(H5F_addr_ge((dblock->block_off + dblock->size),
+ (sect->sect_info.addr + sect->sect_info.size)));
+
+ /* Release direct block */
+ status = H5AC_unprotect(iblock->hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET);
+ HDassert(status >= 0);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_sect_single_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_create
+ *
+ * Purpose: Create a new 'row' section
+ *
+ * Return: Success: pointer to new section
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_free_section_t *
+H5HF_sect_row_create(haddr_t sect_off, hsize_t sect_size, hbool_t is_first,
+ unsigned row, unsigned col, unsigned nentries, H5HF_free_section_t *under_sect)
+{
+ H5HF_free_section_t *sect = NULL; /* 'Row' section created */
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect_size);
+ HDassert(nentries);
+ HDassert(under_sect);
+
+ /* Create 'row' free space section node */
+ /* ("inherits" underlying indirect section's state) */
+ if(NULL == (sect = H5HF_sect_node_new((unsigned)(is_first ? H5HF_FSPACE_SECT_FIRST_ROW : H5HF_FSPACE_SECT_NORMAL_ROW), sect_off, sect_size, under_sect->sect_info.state)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for row section")
+
+ /* Set the 'row' specific fields */
+ sect->u.row.under = under_sect;
+ sect->u.row.row = row;
+ sect->u.row.col = col;
+ sect->u.row.num_entries = nentries;
+ sect->u.row.checked_out = FALSE;
+
+ /* Set return value */
+ ret_value = sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_from_single
+ *
+ * Purpose: Convert a 'single' section into a 'row' section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_from_single(H5HF_hdr_t *hdr, H5HF_free_section_t *sect,
+ H5HF_direct_t *dblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(dblock);
+
+ /* Convert 'single' section information to 'row' section info */
+ sect->sect_info.addr = dblock->block_off;
+ sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
+ sect->u.row.row = dblock->par_entry / hdr->man_dtable.cparam.width;
+ sect->u.row.col = dblock->par_entry % hdr->man_dtable.cparam.width;
+ sect->u.row.num_entries = 1;
+ sect->u.row.checked_out = FALSE;
+
+ /* Create indirect section that underlies the row section */
+ if(NULL == (sect->u.row.under = H5HF_sect_indirect_for_row(hdr, dblock->parent, sect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "serializing row section not supported yet")
+
+ /* Release single section's hold on underlying indirect block */
+ if(H5HF_iblock_decr(dblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_row_from_single() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_revive
+ *
+ * Purpose: Update the memory information for a 'row' free section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_row_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->u.row.under);
+ HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
+
+ /* Pass along "revive" request to underlying indirect section */
+ /* (which will mark this section as "live") */
+ if(H5HF_sect_indirect_revive_row(hdr, dxpl_id, sect->u.row.under) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_row_revive() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_reduce
+ *
+ * Purpose: Reduce the size of a row section (possibly freeing it)
+ * and re-add it back to the free space manager for the heap
+ * (if it hasn't been freed)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_row_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect,
+ unsigned *entry_p)
+{
+ hbool_t alloc_from_start; /* Whether to allocate from the end of the row */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
+ sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(entry_p);
+
+ /* Mark the row as checked out from the free space manager */
+ HDassert(sect->u.row.checked_out == FALSE);
+ sect->u.row.checked_out = TRUE;
+
+ /* Forward row section to indirect routines, to handle reducing underlying indirect section */
+ alloc_from_start = FALSE;
+ if(H5HF_sect_indirect_reduce_row(hdr, dxpl_id, sect, &alloc_from_start) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce underlying section")
+
+ /* Determine entry allocated */
+ *entry_p = (sect->u.row.row * hdr->man_dtable.cparam.width) + sect->u.row.col;
+ if(!alloc_from_start)
+ *entry_p += (sect->u.row.num_entries - 1);
+
+ /* Check for eliminating the section */
+ if(sect->u.row.num_entries == 1) {
+ /* Free row section */
+ if(H5HF_sect_row_free((H5FS_section_info_t *)sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free row section node")
+ } /* end if */
+ else {
+ /* Check whether to allocate from the beginning or end of the row */
+ if(alloc_from_start) {
+ /* Adjust section start */
+ sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.row.row];
+ sect->u.row.col++;
+ } /* end else */
+
+ /* Adjust span of blocks covered */
+ sect->u.row.num_entries--;
+
+ /* Check the row back in */
+ sect->u.row.checked_out = FALSE;
+
+ /* Add 'row' section back to free space list */
+ if(H5HF_space_add(hdr, dxpl_id, sect, 0) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add indirect section to free space manager")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_row_reduce() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_first
+ *
+ * Purpose: Make row a "first row"
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_first(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+
+ /* If the row is already checked out from the free space manager, just
+ * change it's class directly and the free space manager will adjust when
+ * it is checked back in.
+ */
+ if(sect->u.row.checked_out)
+ sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
+ else {
+ /* Change row section to be the "first row" */
+ if(H5HF_space_sect_change_class(hdr, dxpl_id, sect, H5HF_FSPACE_SECT_FIRST_ROW) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set row section to be first row")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_row_first() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_get_iblock
+ *
+ * Purpose: Retrieve the indirect block for a row section
+ *
+ * Return: Pointer to indirect block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HF_indirect_t *
+H5HF_sect_row_get_iblock(H5HF_free_section_t *sect)
+{
+ H5HF_indirect_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW ||
+ sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+
+ ret_value = H5HF_sect_indirect_get_iblock(sect->u.row.under);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_row_get_iblock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_init_cls
+ *
+ * Purpose: Initialize the "row" section class structure
+ *
+ * Note: Since 'row' sections are proxies for 'indirect' sections, this
+ * routine forwards call to 'indirect' class initialization
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_init_cls(H5FS_section_class_t *cls, void *_udata)
+{
+ H5HF_hdr_t *hdr = (H5HF_hdr_t *)_udata; /* Fractal heap header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(hdr);
+
+ /* Call common class initialization */
+ if(H5HF_sect_init_cls(cls, hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize common section class")
+
+ /* First row sections actually are proxies for indirection sections on disk */
+ if(cls->type == H5HF_FSPACE_SECT_FIRST_ROW)
+ cls->serial_size = H5HF_SECT_INDIRECT_SERIAL_SIZE(hdr);
+ else
+ cls->serial_size = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_init_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_term_cls
+ *
+ * Purpose: Terminate the "row" section class structure
+ *
+ * Note: Since 'row' sections are proxies for 'indirect' sections, this
+ * routine forwards call to 'indirect' class termination
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_term_cls(H5FS_section_class_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+
+ /* Call common class termination */
+ if(H5HF_sect_term_cls(cls) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't terminate common section class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_term_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_serialize
+ *
+ * Purpose: Serialize a "live" row section into a buffer
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_serialize(const H5FS_section_class_t *cls,
+ const H5FS_section_info_t *_sect, uint8_t *buf)
+{
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(buf);
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+ HDassert(sect->sect_info.addr == sect->u.row.under->sect_info.addr);
+
+ /* Forward to indirect routine to serialize underlying section */
+ hdr = ((H5HF_sect_private_t *)(cls->cls_private))->hdr;
+ if(H5HF_sect_indirect_serialize(hdr, sect->u.row.under, buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "can't serialize row section's underlying indirect section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_deserialize
+ *
+ * Purpose: Deserialize a buffer into a "live" row section
+ *
+ * Note: Actually this routine just forwards to the 'indirect'
+ * deserialize routine, which creates the row section.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FS_section_info_t *
+H5HF_sect_row_deserialize(const H5FS_section_class_t *cls, hid_t dxpl_id,
+ const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags)
+{
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ H5FS_section_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(buf);
+ HDassert(H5F_addr_defined(sect_addr));
+ HDassert(sect_size);
+
+ /* Forward to indirect routine to deserialize underlying section */
+ hdr = ((H5HF_sect_private_t *)(cls->cls_private))->hdr;
+ if(NULL == (ret_value = H5HF_sect_indirect_deserialize(hdr, dxpl_id, buf,
+ sect_addr, sect_size, des_flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't deserialize row section's underlying indirect section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_can_merge
+ *
+ * Purpose: Can two sections of this type merge?
+ *
+ * Note: Second section must be "after" first section
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF_sect_row_can_merge(const H5FS_section_info_t *_sect1,
+ const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_free_section_t *sect1 = (const H5HF_free_section_t *)_sect1; /* Fractal heap free section */
+ const H5HF_free_section_t *sect2 = (const H5HF_free_section_t *)_sect2; /* Fractal heap free section */
+ H5HF_free_section_t *top_indir_sect1, *top_indir_sect2; /* Top indirect section for each row */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert(sect1->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+ HDassert(sect2);
+ HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
+ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
+
+ /* Get the top indirect section underlying each row */
+ top_indir_sect1 = H5HF_sect_indirect_top(sect1->u.row.under);
+ HDassert(top_indir_sect1);
+ top_indir_sect2 = H5HF_sect_indirect_top(sect2->u.row.under);
+ HDassert(top_indir_sect2);
+
+ /* Check if second section shares the same underlying indirect block as
+ * the first section, but doesn't already have same underlying indirect
+ * section.
+ */
+ if(top_indir_sect1 != top_indir_sect2) {
+ if(H5HF_sect_indirect_iblock_off(top_indir_sect1) == H5HF_sect_indirect_iblock_off(top_indir_sect2)) {
+ /* Check if second section adjoins first section */
+ if(H5F_addr_eq((top_indir_sect1->sect_info.addr + top_indir_sect1->u.indirect.span_size), top_indir_sect2->sect_info.addr))
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_can_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_merge
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
+ void *_udata)
+{
+ H5HF_free_section_t **sect1 = (H5HF_free_section_t **)_sect1; /* Fractal heap free section */
+ H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert((*sect1)->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+ HDassert(sect2);
+ HDassert(sect2->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+
+ /* Check if second section is past end of "next block" iterator */
+ if(sect2->sect_info.addr >= hdr->man_iter_off) {
+ H5HF_free_section_t *top_indir_sect; /* Top indirect section for row */
+
+ /* Get the top indirect section underlying second row section */
+ top_indir_sect = H5HF_sect_indirect_top(sect2->u.row.under);
+
+ /* Shrink away underlying indirect section */
+ if(H5HF_sect_indirect_shrink(hdr, dxpl_id, top_indir_sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't shrink underlying indirect section")
+ } /* end if */
+ else {
+ /* Check to see if we should revive first section */
+ if((*sect1)->sect_info.state != H5FS_SECT_LIVE)
+ if(H5HF_sect_row_revive(hdr, dxpl_id, (*sect1)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
+
+ /* Check to see if we should revive second section */
+ if(sect2->sect_info.state != H5FS_SECT_LIVE)
+ if(H5HF_sect_row_revive(hdr, dxpl_id, sect2) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section")
+
+ /* Merge rows' underlying indirect sections together */
+ if(H5HF_sect_indirect_merge_row(hdr, dxpl_id, (*sect1), sect2) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMERGE, FAIL, "can't merge underlying indirect sections")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_can_shrink
+ *
+ * Purpose: Can this section shrink the container?
+ *
+ * Note: This isn't actually shrinking the heap (since that's already
+ * been done) as much as it's cleaning up _after_ the heap
+ * shrink.
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5HF_sect_row_can_shrink(const H5FS_section_info_t *_sect, void H5_ATTR_UNUSED *_udata)
+{
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Fractal heap free section */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+
+ /* Check if section is past end of "next block" iterator */
+ if(sect->sect_info.addr >= hdr->man_iter_off)
+ HGOTO_DONE(TRUE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_can_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_shrink
+ *
+ * Purpose: Shrink container with section
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_shrink(H5FS_section_info_t **_sect, void *_udata)
+{
+ H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect; /* Fractal heap free section */
+ H5HF_free_section_t *top_indir_sect; /* Top indirect section for row */
+ H5HF_sect_add_ud_t *udata = (H5HF_sect_add_ud_t *)_udata; /* User callback data */
+ H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */
+ hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(*sect);
+ HDassert((*sect)->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+
+ /* Get the top indirect section underlying each row */
+ top_indir_sect = H5HF_sect_indirect_top((*sect)->u.row.under);
+
+ /* Shrink away underlying indirect section */
+ if(H5HF_sect_indirect_shrink(hdr, dxpl_id, top_indir_sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't shrink underlying indirect section")
+
+ /* Indicate that the section has been released */
+ *sect = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_free_real
+ *
+ * Purpose: Free a 'row' section node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_free_real(H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(sect);
+
+ /* Release the section */
+ if(H5HF_sect_node_free(sect, NULL) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_free_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_free
+ *
+ * Purpose: Free a 'row' section node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_free(H5FS_section_info_t *_sect)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Pointer to section to free */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(sect);
+ HDassert(sect->u.row.under);
+
+ /* Decrement the ref. count on the row section's underlying indirect section */
+ if(H5HF_sect_indirect_decr(sect->u.row.under) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't detach section node")
+
+ /* Release the section */
+ if(H5HF_sect_row_free_real(sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_row_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_valid
+ *
+ * Purpose: Check the validity of a section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, July 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_valid(const H5FS_section_class_t *cls, const H5FS_section_info_t *_sect,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5HF_sect_private_t *cls_prvt; /* Pointer to class private info */
+ const H5HF_hdr_t *hdr; /* Fractal heap header */
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Pointer to section to check */
+ const H5HF_free_section_t *indir_sect; /* Pointer to underlying indirect section */
+ unsigned indir_idx; /* Index of row in underlying indirect section's row array */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Basic sanity check */
+ HDassert(cls);
+ HDassert(sect);
+
+ /* Retrieve class private information */
+ cls_prvt = (H5HF_sect_private_t *)cls->cls_private;
+ hdr = cls_prvt->hdr;
+
+ /* Sanity checking on the row */
+ HDassert(sect->u.row.under);
+ HDassert(sect->u.row.num_entries);
+ HDassert(sect->u.row.checked_out == FALSE);
+ indir_sect = sect->u.row.under;
+ indir_idx = sect->u.row.row - indir_sect->u.indirect.row;
+ HDassert(indir_sect->u.indirect.dir_rows[indir_idx] == sect);
+
+ /* Check if the section is actually within the heap */
+ HDassert(sect->sect_info.addr < hdr->man_iter_off);
+
+ /* Different checking for different kinds of rows */
+ if(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW) {
+ H5HF_free_section_t *top_indir_sect; /* Top indirect section for row */
+
+ /* Some extra sanity checks on the row */
+ HDassert(sect->u.row.row == indir_sect->u.indirect.row);
+
+ /* Get the top indirect section underlying row */
+ top_indir_sect = H5HF_sect_indirect_top(sect->u.row.under);
+
+ /* Check that the row's underlying indirect section is valid */
+ H5HF_sect_indirect_valid(hdr, top_indir_sect);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_sect_row_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_row_debug
+ *
+ * Purpose: Dump debugging information about an row free space section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 25, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_row_debug(const H5FS_section_info_t *_sect,
+ FILE *stream, int indent, int fwidth)
+{
+ const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Section to dump info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ /* Print indirect section information */
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Row:",
+ sect->u.row.row);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Column:",
+ sect->u.row.col);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of entries:",
+ sect->u.row.num_entries);
+
+ /* If this is a first row section display information about underlying indirect section */
+ if(sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW) {
+ /* Print indirect section header */
+ HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth,
+ "Underlying indirect section:");
+
+ H5HF_sect_indirect_debug(sect->u.row.under, stream, indent + 3, MAX(0, fwidth - 3));
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_sect_row_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_iblock_off
+ *
+ * Purpose: Get the offset of the indirect block for the section
+ *
+ * Return: Offset of indirect block in "heap space" (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5HF_sect_indirect_iblock_off(const H5HF_free_section_t *sect)
+{
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+
+ ret_value = sect->sect_info.state == H5FS_SECT_LIVE ? sect->u.indirect.u.iblock->block_off : sect->u.indirect.u.iblock_off;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_iblock_off() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_top
+ *
+ * Purpose: Get the "top" indirect section
+ *
+ * Return: Pointer to the top indirect section (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_free_section_t *
+H5HF_sect_indirect_top(H5HF_free_section_t *sect)
+{
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+
+ if(sect->u.indirect.parent)
+ ret_value = H5HF_sect_indirect_top(sect->u.indirect.parent);
+ else
+ ret_value = sect;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_top() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_init_cls
+ *
+ * Purpose: Initialize the "indirect" class structure
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, void *_udata)
+{
+ H5HF_hdr_t *hdr = (H5HF_hdr_t *)_udata; /* Fractal heap header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(hdr);
+
+ /* Call to common class initialization */
+ if(H5HF_sect_init_cls(cls, hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize common section class")
+
+ /* Set the size of all serialized objects of this class of sections */
+ cls->serial_size = H5HF_SECT_INDIRECT_SERIAL_SIZE(hdr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_indirect_init_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_term_cls
+ *
+ * Purpose: Terminate the "indirect" class structure
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_term_cls(H5FS_section_class_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+
+ /* Call common class termination */
+ if(H5HF_sect_term_cls(cls) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't terminate common section class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_indirect_term_cls() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_new
+ *
+ * Purpose: Create a new 'indirect' section for other routines to finish
+ * initializing.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_free_section_t *
+H5HF_sect_indirect_new(H5HF_hdr_t *hdr, haddr_t sect_off, hsize_t sect_size,
+ H5HF_indirect_t *iblock, hsize_t iblock_off, unsigned row, unsigned col,
+ unsigned nentries)
+{
+ H5HF_free_section_t *sect = NULL; /* 'Indirect' free space section to add */
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(nentries);
+
+ /* Create free space section node */
+ if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_INDIRECT, sect_off,
+ sect_size, (iblock ? H5FS_SECT_LIVE : H5FS_SECT_SERIALIZED))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for indirect section")
+
+ /* Set the 'indirect' specific fields */
+ if(iblock) {
+ sect->u.indirect.u.iblock = iblock;
+ sect->u.indirect.iblock_entries = hdr->man_dtable.cparam.width *
+ sect->u.indirect.u.iblock->max_rows;
+ if(H5HF_iblock_incr(sect->u.indirect.u.iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block")
+ } /* end if */
+ else {
+ sect->u.indirect.u.iblock_off = iblock_off;
+ sect->u.indirect.iblock_entries = 0;
+ } /* end else */
+ sect->u.indirect.row = row;
+ sect->u.indirect.col = col;
+ sect->u.indirect.num_entries = nentries;
+
+ /* Compute span size of indirect section */
+ sect->u.indirect.span_size = H5HF_dtable_span_size(&hdr->man_dtable,
+ row, col, nentries);
+ HDassert(sect->u.indirect.span_size > 0);
+
+ /* This indirect section doesn't (currently) have a parent */
+ sect->u.indirect.parent = NULL;
+ sect->u.indirect.par_entry = 0;
+
+ /* Set return value */
+ ret_value = sect;
+
+done:
+ if(!ret_value && sect) {
+ /* Release the section */
+ sect = H5FL_FREE(H5HF_free_section_t, sect);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_for_row
+ *
+ * Purpose: Create the underlying indirect section for a new row section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_free_section_t *
+H5HF_sect_indirect_for_row(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock,
+ H5HF_free_section_t *row_sect)
+{
+ H5HF_free_section_t *sect = NULL; /* 'Indirect' free space section to add */
+ H5HF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(iblock);
+ HDassert(row_sect);
+ HDassert(row_sect->u.row.row < hdr->man_dtable.max_direct_rows);
+
+ /* Create free space section node */
+ if(NULL == (sect = H5HF_sect_indirect_new(hdr, row_sect->sect_info.addr,
+ row_sect->sect_info.size, iblock, iblock->block_off,
+ row_sect->u.row.row, row_sect->u.row.col, row_sect->u.row.num_entries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create indirect section")
+
+ /* Set # of direct rows covered */
+ sect->u.indirect.dir_nrows = 1;
+
+ /* Allocate space for the derived row sections */
+ if(NULL == (sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "allocation failed for row section pointer array")
+
+ /* Atatch the new row section to indirect section */
+ sect->u.indirect.dir_rows[0] = row_sect;
+ sect->u.indirect.rc = 1;
+
+ /* No indirect rows in current section */
+ sect->u.indirect.indir_nents = 0;
+ sect->u.indirect.indir_ents = NULL;
+
+ /* Set return value */
+ ret_value = sect;
+
+done:
+ if(!ret_value && sect)
+ if(H5HF_sect_indirect_free(sect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "can't free indirect section node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_for_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_init_rows
+ *
+ * Purpose: Initialize the derived row sections for a newly created
+ * indirect section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_init_rows(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, hbool_t first_child, H5HF_free_section_t **first_row_sect,
+ unsigned space_flags, unsigned start_row, unsigned start_col,
+ unsigned end_row, unsigned end_col)
+{
+ hsize_t curr_off; /* Offset of new section in "heap space" */
+ size_t dblock_overhead; /* Direct block's overhead */
+ unsigned row_entries; /* # of entries in row */
+ unsigned row_col; /* Column within current row */
+ unsigned curr_entry; /* Current entry within indirect section */
+ unsigned curr_indir_entry; /* Current indirect entry within indirect section */
+ unsigned curr_row; /* Current row within indirect section */
+ unsigned dir_nrows; /* # of direct rows in indirect section */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(sect->u.indirect.span_size > 0);
+
+ /* Reset reference count for indirect section */
+ /* (Also reset the direct & indirect row pointers */
+ sect->u.indirect.rc = 0;
+ sect->u.indirect.dir_rows = NULL;
+ sect->u.indirect.indir_ents = NULL;
+
+ /* Set up direct block information, if necessary */
+ if(start_row < hdr->man_dtable.max_direct_rows) {
+ unsigned max_direct_row; /* Max. direct row covered */
+
+ /* Compute max. direct row covered by indirect section */
+ max_direct_row = MIN(end_row, (hdr->man_dtable.max_direct_rows - 1));
+
+ /* Compute # of direct rows covered */
+ dir_nrows = (max_direct_row - start_row) + 1;
+
+ /* Don't set the of direct rows in section yet, so sanity
+ * checking works (enabled in free section manager, with H5FS_DEBUG
+ * macro) correctly.
+ */
+ sect->u.indirect.dir_nrows = 0;
+
+ /* Allocate space for the derived row sections */
+ if(NULL == (sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * dir_nrows)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
+ } /* end if */
+ else {
+ /* No rows of direct blocks covered, reset direct row information */
+ dir_nrows = 0;
+ sect->u.indirect.dir_nrows = 0;
+ } /* end else */
+
+ /* Set up indirect block information, if necessary */
+ if(end_row >= hdr->man_dtable.max_direct_rows) {
+ unsigned indirect_start_row; /* Row to start indirect entries on */
+ unsigned indirect_start_col; /* Column to start indirect entries on */
+ unsigned indirect_start_entry; /* Index of starting indirect entry */
+ unsigned indirect_end_entry; /* Index of ending indirect entry */
+
+ /* Compute starting indirect entry */
+ if(start_row < hdr->man_dtable.max_direct_rows) {
+ indirect_start_row = hdr->man_dtable.max_direct_rows;
+ indirect_start_col = 0;
+ } /* end if */
+ else {
+ indirect_start_row = start_row;
+ indirect_start_col = start_col;
+ } /* end else */
+ indirect_start_entry = (indirect_start_row * hdr->man_dtable.cparam.width)
+ + indirect_start_col;
+
+ /* Compute ending indirect entry */
+ indirect_end_entry = (end_row * hdr->man_dtable.cparam.width) + end_col;
+
+ /* Compute # of indirect entries covered */
+ sect->u.indirect.indir_nents = (indirect_end_entry - indirect_start_entry) + 1;
+
+ /* Allocate space for the child indirect sections */
+ if(NULL == (sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * sect->u.indirect.indir_nents)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for indirect section pointer array")
+ } /* end if */
+ else {
+ /* No indirect block entries covered, reset indirect row information */
+ sect->u.indirect.indir_nents = 0;
+ } /* end else */
+
+ /* Set up initial row information */
+ if(start_row == end_row)
+ row_entries = (end_col - start_col) + 1;
+ else
+ row_entries = hdr->man_dtable.cparam.width - start_col;
+ row_col = start_col;
+
+ /* Loop over creating the sections covered by this indirect section */
+ curr_off = sect->sect_info.addr;
+ curr_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
+ curr_row = 0;
+ curr_indir_entry = 0;
+ dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
+ for(u = start_row; u <= end_row; u++, curr_row++) {
+ if(u < hdr->man_dtable.max_direct_rows) {
+ H5HF_free_section_t *row_sect = NULL; /* 'Row' free space section to add */
+
+ /* Create 'row' free space section node */
+ if(NULL == (row_sect = H5HF_sect_row_create(curr_off,
+ (hdr->man_dtable.row_block_size[u] - dblock_overhead), first_child, u, row_col,
+ row_entries, sect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "creation failed for child row section")
+
+ /* Add new row section to array for indirect section */
+ sect->u.indirect.dir_rows[curr_row] = row_sect;
+
+ /* Check to see if we should grab the first row section instead of adding it immediately */
+ if(first_row_sect)
+ *first_row_sect = row_sect;
+ else {
+ /* Add new row section to free space manager for the heap */
+ if(H5HF_space_add(hdr, dxpl_id, row_sect, space_flags) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add row section to free space")
+ } /* end else */
+
+ /* Increment reference count for underlying indirect section */
+ sect->u.indirect.rc++;
+
+ /* Advance the offset to the next section */
+ curr_off += row_entries * hdr->man_dtable.row_block_size[u];
+
+ /* Advance the current entry to the next row*/
+ curr_entry += row_entries;
+
+ /* Reset the 'first child' parameters */
+ first_child = FALSE;
+ first_row_sect = NULL;
+ } /* end if */
+ else {
+ H5HF_indirect_t *child_iblock; /* Child indirect block */
+ H5HF_free_section_t *child_sect; /* Child 'indirect' section to add */
+ unsigned child_nrows; /* Number of child rows in indirect blocks for this row */
+ unsigned child_nentries; /* Number of child entries in indirect blocks for this row */
+ unsigned v; /* Local index variable */
+
+ /* Compute info about row's indirect blocks for child section */
+ child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[u]);
+ child_nentries = child_nrows * hdr->man_dtable.cparam.width;
+
+ /* Add an indirect section for each indirect block in the row */
+ for(v = 0; v < row_entries; v++) {
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+
+ /* Try to get the child section's indirect block, if it's available */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ haddr_t child_iblock_addr; /* Child indirect block's address on disk */
+
+ /* Get the address of the child indirect block */
+ if(H5HF_man_iblock_entry_addr(sect->u.indirect.u.iblock, curr_entry, &child_iblock_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve child indirect block's address")
+
+ /* If the child indirect block's address is defined, protect it */
+ if(H5F_addr_defined(child_iblock_addr)) {
+ if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, child_iblock_addr, child_nrows, sect->u.indirect.u.iblock, curr_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
+ } /* end if */
+ else
+ child_iblock = NULL;
+ } /* end if */
+ else
+ child_iblock = NULL;
+
+ /* Create free space section node */
+ if(NULL == (child_sect = H5HF_sect_indirect_new(hdr, curr_off, (hsize_t)0,
+ child_iblock, curr_off, 0, 0, child_nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
+
+ /* Initialize rows for new indirect section */
+ if(H5HF_sect_indirect_init_rows(hdr, dxpl_id, child_sect,
+ first_child, first_row_sect, space_flags, 0, 0,
+ (child_nrows - 1), (hdr->man_dtable.cparam.width - 1)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize indirect section")
+
+ /* If we have a valid child indirect block, release it now */
+ /* (will be pinned, if rows reference it) */
+ if(child_iblock)
+ if(H5HF_man_iblock_unprotect(child_iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+
+ /* Attach child section to this section */
+ child_sect->u.indirect.parent = sect;
+ child_sect->u.indirect.par_entry = curr_entry;
+ sect->u.indirect.indir_ents[curr_indir_entry] = child_sect;
+ sect->u.indirect.rc++;
+
+ /* Advance the offset for the next section */
+ curr_off += hdr->man_dtable.row_block_size[u];
+
+ /* Advance to the next entry */
+ curr_entry++;
+ curr_indir_entry++;
+
+ /* Reset the 'first child' parameters */
+ first_child = FALSE;
+ first_row_sect = NULL;
+ } /* end for */
+ } /* end else */
+
+ /* Compute the # of entries for the next row */
+ if(u < (end_row - 1))
+ row_entries = hdr->man_dtable.cparam.width;
+ else
+ row_entries = end_col + 1;
+
+ /* Reset column for all other rows */
+ row_col = 0;
+ } /* end for */
+
+ /* Set the final # of direct rows in section */
+ sect->u.indirect.dir_nrows = dir_nrows;
+
+ /* Make certain we've tracked the section's dependents correctly */
+ HDassert(sect->u.indirect.rc ==
+ (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
+
+done:
+ if(ret_value < 0) {
+ if(sect->u.indirect.indir_ents)
+ H5MM_xfree(sect->u.indirect.indir_ents);
+ if(sect->u.indirect.dir_rows)
+ H5MM_xfree(sect->u.indirect.dir_rows);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_init_rows() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_add
+ *
+ * Purpose: Add a new 'indirect' section to the free space manager for this
+ * heap
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 3 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_sect_indirect_add(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries)
+{
+ H5HF_free_section_t *sect = NULL; /* 'Indirect' free space section to add */
+ H5HF_free_section_t *first_row_sect = NULL; /* First row section in new indirect section */
+ hsize_t sect_off; /* Offset of section in heap space */
+ unsigned start_row; /* Start row in indirect block */
+ unsigned start_col; /* Start column in indirect block */
+ unsigned end_entry; /* End entry in indirect block */
+ unsigned end_row; /* End row in indirect block */
+ unsigned end_col; /* End column in indirect block */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(iblock);
+ HDassert(nentries);
+
+ /* Compute starting column & row */
+ start_row = start_entry / hdr->man_dtable.cparam.width;
+ start_col = start_entry % hdr->man_dtable.cparam.width;
+
+ /* Compute end column & row */
+ end_entry = (start_entry + nentries) - 1;
+ end_row = end_entry / hdr->man_dtable.cparam.width;
+ end_col = end_entry % hdr->man_dtable.cparam.width;
+
+ /* Initialize information for rows skipped over */
+ sect_off = iblock->block_off;
+ for(u = 0; u < start_row; u++)
+ sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width;
+ sect_off += hdr->man_dtable.row_block_size[start_row] * start_col;
+
+ /* Create free space section node */
+ if(NULL == (sect = H5HF_sect_indirect_new(hdr, sect_off, (hsize_t)0, iblock,
+ iblock->block_off, start_row, start_col, nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
+
+ /* Initialize rows for new indirect section */
+ if(H5HF_sect_indirect_init_rows(hdr, dxpl_id, sect, TRUE, &first_row_sect,
+ H5FS_ADD_SKIP_VALID, start_row, start_col, end_row, end_col) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize indirect section")
+ HDassert(first_row_sect);
+
+ /* Now that underlying indirect section is consistent, add first row
+ * section to free space manager for the heap
+ */
+ if(H5HF_space_add(hdr, dxpl_id, first_row_sect, H5FS_ADD_RETURNED_SPACE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add row section to free space")
+
+done:
+ if(ret_value < 0 && sect)
+ if(H5HF_sect_indirect_free(sect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_decr
+ *
+ * Purpose: Decrement ref. count on indirect section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_decr(H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(sect->u.indirect.rc);
+
+ /* Decrement ref. count for indirect section */
+ sect->u.indirect.rc--;
+
+ /* If the indirect section's ref. count drops to zero, free the section */
+ if(sect->u.indirect.rc == 0) {
+ H5HF_free_section_t *par_sect; /* Parent indirect section */
+
+ /* Preserve pointer to parent indirect section when freeing this section */
+ par_sect = sect->u.indirect.parent;
+
+ /* Free indirect section */
+ if(H5HF_sect_indirect_free(sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+
+ /* Decrement ref. count on indirect section's parent */
+ if(par_sect)
+ if(H5HF_sect_indirect_decr(par_sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement ref. count on parent indirect section")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_decr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_revive_row
+ *
+ * Purpose: Update the memory information for a 'indirect' free section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 3 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_revive_row(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect)
+{
+ H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */
+ hbool_t did_protect; /* Whether we protected the indirect block or not */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
+
+ /* Look up indirect block containing indirect blocks for section */
+ if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, NULL, &did_protect, H5AC__READ_ONLY_FLAG) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section")
+
+ /* Increment reference count on indirect block that free section is in */
+ if(H5HF_iblock_incr(sec_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Set the pointer to the section's indirect block */
+ sect->u.indirect.u.iblock = sec_iblock;
+
+ /* Set the number of entries in the indirect block */
+ sect->u.indirect.iblock_entries = hdr->man_dtable.cparam.width *
+ sect->u.indirect.u.iblock->max_rows;
+
+ /* Unlock indirect block */
+ if(H5HF_man_iblock_unprotect(sec_iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ sec_iblock = NULL;
+
+ /* Section is "live" now */
+ sect->sect_info.state = H5FS_SECT_LIVE;
+
+ /* Loop over derived row sections and mark them all as 'live' now */
+ for(u = 0; u < sect->u.indirect.dir_nrows; u++)
+ sect->u.indirect.dir_rows[u]->sect_info.state = H5FS_SECT_LIVE;
+
+ /* Revive parent indirect section, if there is one */
+ if(sect->u.indirect.parent && sect->u.indirect.parent->sect_info.state == H5FS_SECT_SERIALIZED)
+ if(H5HF_sect_indirect_revive(hdr, dxpl_id, sect->u.indirect.parent, sect->u.indirect.u.iblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_revive_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_revive
+ *
+ * Purpose: Update the memory information for a 'indirect' free section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *sect, H5HF_indirect_t *sect_iblock)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED);
+ HDassert(sect_iblock);
+
+ /* Increment reference count on indirect block that free section is in */
+ if(H5HF_iblock_incr(sect_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block")
+
+ /* Set the pointer to the section's indirect block */
+ sect->u.indirect.u.iblock = sect_iblock;
+
+ /* Set the number of entries in the indirect block */
+ sect->u.indirect.iblock_entries = hdr->man_dtable.cparam.width *
+ sect->u.indirect.u.iblock->max_rows;
+
+ /* Section is "live" now */
+ sect->sect_info.state = H5FS_SECT_LIVE;
+
+ /* Loop over derived row sections and mark them all as 'live' now */
+ for(u = 0; u < sect->u.indirect.dir_nrows; u++)
+ sect->u.indirect.dir_rows[u]->sect_info.state = H5FS_SECT_LIVE;
+
+ /* Revive parent indirect section, if there is one */
+ if(sect->u.indirect.parent && sect->u.indirect.parent->sect_info.state == H5FS_SECT_SERIALIZED)
+ if(H5HF_sect_indirect_revive(hdr, dxpl_id, sect->u.indirect.parent, sect->u.indirect.u.iblock->parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_revive() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_reduce_row
+ *
+ * Purpose: Remove a block from an indirect section (possibly freeing it)
+ * and re-add it back to the free space manager for the heap
+ * (if it hasn't been freed)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_reduce_row(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *row_sect,
+ hbool_t *alloc_from_start)
+{
+ H5HF_free_section_t *sect; /* Indirect section underlying row section */
+ unsigned row_start_entry; /* Entry for first block covered in row section */
+ unsigned row_end_entry; /* Entry for last block covered in row section */
+ unsigned row_entry; /* Entry to allocate in row section */
+ unsigned start_entry; /* Entry for first block covered */
+ unsigned start_row; /* Start row in indirect block */
+ unsigned start_col; /* Start column in indirect block */
+ unsigned end_entry; /* Entry for last block covered */
+ unsigned end_row; /* End row in indirect block */
+ H5HF_free_section_t *peer_sect = NULL; /* Peer indirect section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(row_sect);
+
+ /* Compute starting & ending information for row section */
+ row_start_entry = (row_sect->u.row.row * hdr->man_dtable.cparam.width) + row_sect->u.row.col;
+ row_end_entry = (row_start_entry + row_sect->u.row.num_entries) - 1;
+
+ /* Compute starting & ending information for indirect section */
+ sect = row_sect->u.row.under;
+ start_row = sect->u.indirect.row;
+ start_col = sect->u.indirect.col;
+ start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
+ end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
+ end_row = end_entry / hdr->man_dtable.cparam.width;
+
+ /* Additional sanity check */
+ HDassert(sect->u.indirect.span_size > 0);
+ HDassert(sect->u.indirect.iblock_entries > 0);
+ HDassert(sect->u.indirect.dir_nrows > 0);
+ HDassert(sect->u.indirect.dir_rows);
+ HDassert(sect->u.indirect.dir_rows[(row_sect->u.row.row - start_row)] == row_sect);
+
+ /* Check if we should allocate from end of indirect section */
+ if(row_end_entry == end_entry && start_row != end_row) {
+ *alloc_from_start = FALSE;
+ row_entry = row_end_entry;
+ } /* end if */
+ else {
+ *alloc_from_start = TRUE;
+ row_entry = row_start_entry;
+ } /* end else */
+
+ /* Check if we have a parent section to be detached from */
+ if(sect->u.indirect.parent) {
+ hbool_t is_first; /* Flag to indicate that this section is the first section in hierarchy */
+
+ /* Check if this section is the first section */
+ is_first = H5HF_sect_indirect_is_first(sect);
+
+ /* Remove this indirect section from parent indirect section */
+ if(H5HF_sect_indirect_reduce(hdr, dxpl_id, sect->u.indirect.parent, sect->u.indirect.par_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce parent indirect section")
+ sect->u.indirect.parent = NULL;
+ sect->u.indirect.par_entry = 0;
+
+ /* If we weren't the first section, set "first row" for this indirect section */
+ if(!is_first)
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
+ } /* end if */
+
+ /* Adjust indirect section's span size */
+ sect->u.indirect.span_size -= row_sect->sect_info.size;
+
+ /* Check how to adjust section for allocated entry */
+ if(sect->u.indirect.num_entries > 1) {
+ if(row_entry == start_entry) {
+ /* Adjust section start */
+ sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.indirect.row];
+
+ /* Adjust block coordinates of span */
+ sect->u.indirect.col++;
+ if(sect->u.indirect.col == hdr->man_dtable.cparam.width) {
+ HDassert(row_sect->u.row.num_entries == 1);
+
+ /* Adjust section's span information */
+ sect->u.indirect.row++;
+ sect->u.indirect.col = 0;
+
+ /* Adjust direct row information */
+ sect->u.indirect.dir_nrows--;
+
+ /* Adjust direct row sections for indirect section */
+ if(sect->u.indirect.dir_nrows > 0) {
+ HDassert(sect->u.indirect.dir_rows);
+ HDmemmove(&sect->u.indirect.dir_rows[0],
+ &sect->u.indirect.dir_rows[1],
+ sect->u.indirect.dir_nrows * sizeof(H5HF_free_section_t *));
+ HDassert(sect->u.indirect.dir_rows[0]);
+
+ /* Make new "first row" in indirect section */
+ if(row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW)
+ if(H5HF_sect_row_first(hdr, dxpl_id, sect->u.indirect.dir_rows[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(sect->u.indirect.indir_nents > 0);
+ HDassert(sect->u.indirect.indir_ents);
+
+ /* Eliminate direct rows for this section */
+ sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
+
+ /* Make new "first row" in indirect section */
+ if(row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW)
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, sect->u.indirect.indir_ents[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for child indirect section")
+ } /* end else */
+ } /* end if */
+
+ /* Adjust number of entries covered */
+ sect->u.indirect.num_entries--;
+ } /* end if */
+ else if(row_entry == end_entry) {
+ unsigned new_end_row; /* New end row for entries */
+
+ /* Sanity check */
+ HDassert(sect->u.indirect.indir_nents == 0);
+ HDassert(sect->u.indirect.indir_ents == NULL);
+
+ /* Adjust number of entries covered */
+ sect->u.indirect.num_entries--;
+
+ /* Check for eliminating a direct row */
+ new_end_row = ((start_entry + sect->u.indirect.num_entries) - 1) / hdr->man_dtable.cparam.width;
+ HDassert(new_end_row <= end_row);
+ if(new_end_row < end_row) {
+ HDassert(new_end_row == (end_row - 1));
+ sect->u.indirect.dir_nrows--;
+ } /* end if */
+ } /* end if */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block for this section */
+ hsize_t iblock_off; /* Section's indirect block's offset in "heap space" */
+ unsigned peer_nentries; /* Number of entries in new peer indirect section */
+ unsigned peer_dir_nrows; /* Number of direct rows in new peer indirect section */
+ unsigned new_start_row; /* New starting row for current indirect section */
+ unsigned u; /* Local index variable */
+
+ /* Sanity checks */
+ HDassert(row_sect->u.row.col == 0);
+ HDassert(row_sect->u.row.row > 0);
+ HDassert(row_sect->u.row.row < hdr->man_dtable.max_direct_rows);
+ HDassert(row_sect->u.row.num_entries == hdr->man_dtable.cparam.width);
+ HDassert(row_sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+
+ /* Compute basic information about peer & current indirect sections */
+ new_start_row = row_sect->u.row.row;
+ peer_nentries = row_entry - start_entry;
+ peer_dir_nrows = new_start_row - start_row;
+
+ /* Get indirect block information for peer */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ iblock = sect->u.indirect.u.iblock;
+ iblock_off = sect->u.indirect.u.iblock->block_off;
+ } /* end if */
+ else {
+ iblock = NULL;
+ iblock_off = sect->u.indirect.u.iblock_off;
+ } /* end else */
+
+ /* Create peer indirect section */
+ if(NULL == (peer_sect = H5HF_sect_indirect_new(hdr, sect->sect_info.addr,
+ sect->sect_info.size, iblock, iblock_off, start_row, start_col,
+ peer_nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
+
+ /* Set up direct row & indirect entry information for peer section */
+ peer_sect->u.indirect.indir_nents = 0;
+ peer_sect->u.indirect.indir_ents = NULL;
+ peer_sect->u.indirect.dir_nrows = peer_dir_nrows;
+ if(NULL == (peer_sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * peer_dir_nrows)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "allocation failed for row section pointer array")
+
+ /* Transfer row sections between current & peer sections */
+ HDmemcpy(&peer_sect->u.indirect.dir_rows[0],
+ &sect->u.indirect.dir_rows[0],
+ (sizeof(H5HF_free_section_t *) * peer_dir_nrows));
+ HDmemmove(&sect->u.indirect.dir_rows[0],
+ &sect->u.indirect.dir_rows[peer_dir_nrows],
+ (sizeof(H5HF_free_section_t *) * (sect->u.indirect.dir_nrows - peer_dir_nrows)));
+ sect->u.indirect.dir_nrows -= peer_dir_nrows;
+ HDassert(row_sect == sect->u.indirect.dir_rows[0]);
+
+ /* Re-target transferred row sections to point to new underlying indirect section */
+ for(u = 0; u < peer_dir_nrows; u++)
+ peer_sect->u.indirect.dir_rows[u]->u.row.under = peer_sect;
+
+ /* Change first row section in indirect section to be the "first row" */
+ /* (But we don't have to tell the free space manager about it,
+ * because the row section is "checked out" from the free space
+ * manager currently.
+ */
+ row_sect->sect_info.type = H5HF_FSPACE_SECT_FIRST_ROW;
+
+ /* Adjust reference counts for current & peer sections */
+ peer_sect->u.indirect.rc = peer_dir_nrows;
+ sect->u.indirect.rc -= peer_dir_nrows;
+
+ /* Transfer/update cached information about indirect block */
+ peer_sect->u.indirect.iblock_entries = sect->u.indirect.iblock_entries;
+ peer_sect->u.indirect.span_size = row_sect->sect_info.addr - peer_sect->sect_info.addr;
+
+ /* Update information for current section */
+ sect->sect_info.addr = row_sect->sect_info.addr + hdr->man_dtable.row_block_size[new_start_row];
+ sect->u.indirect.span_size -= peer_sect->u.indirect.span_size; /* (span for row section has already been removed) */
+ sect->u.indirect.row = new_start_row;
+ sect->u.indirect.col = row_sect->u.row.col + 1;
+ sect->u.indirect.num_entries -= (peer_nentries + 1); /* Transferred entries, plus the entry allocated out of the row */
+
+ /* Make certain we've tracked the sections' dependents correctly */
+ HDassert(sect->u.indirect.rc ==
+ (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
+ HDassert(peer_sect->u.indirect.rc ==
+ (peer_sect->u.indirect.indir_nents + peer_sect->u.indirect.dir_nrows));
+
+ /* Reset the peer_sect variable, to indicate that it has been hooked into the data structures correctly and shouldn't be freed */
+ peer_sect = NULL;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Decrement count of entries & rows */
+ sect->u.indirect.num_entries--;
+ sect->u.indirect.dir_nrows--;
+ HDassert(sect->u.indirect.dir_nrows == 0);
+
+ /* Eliminate direct rows for this section */
+ sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
+ } /* end else */
+
+done:
+ /* Free allocated peer_sect. Note that this is necessary for all failures until peer_sect is linked
+ * into the main free space structures (via the direct blocks), and the reference count is updated. */
+ if(peer_sect) {
+ /* Sanity check - we should only be here if an error occurred */
+ HDassert(ret_value < 0);
+
+ if(H5HF_sect_indirect_free(peer_sect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_reduce_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_reduce
+ *
+ * Purpose: Reduce the size of a indirect section (possibly freeing it)
+ * and re-add it back to the free space manager for the heap
+ * (if it hasn't been freed)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect,
+ unsigned child_entry)
+{
+ unsigned start_entry; /* Entry for first block covered */
+ unsigned start_row; /* Start row in indirect block */
+ unsigned start_col; /* Start column in indirect block */
+ unsigned end_entry; /* Entry for last block covered */
+ unsigned end_row; /* End row in indirect block */
+ H5HF_free_section_t *peer_sect = NULL; /* Peer indirect section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->u.indirect.span_size > 0);
+ HDassert(sect->u.indirect.iblock_entries > 0);
+
+ /* Compute starting & ending information for indirect section */
+ start_row = sect->u.indirect.row;
+ start_col = sect->u.indirect.col;
+ start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
+ end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
+ end_row = end_entry / hdr->man_dtable.cparam.width;
+
+ /* Check how to adjust section for allocated entry */
+ if(sect->u.indirect.num_entries > 1) {
+ /* Check if we have a parent section to be detached from */
+ if(sect->u.indirect.parent) {
+ hbool_t is_first; /* Flag to indicate that this section is the first section in hierarchy */
+
+ /* Check if this section is the first section */
+ is_first = H5HF_sect_indirect_is_first(sect);
+
+ /* Reduce parent indirect section */
+ if(H5HF_sect_indirect_reduce(hdr, dxpl_id, sect->u.indirect.parent, sect->u.indirect.par_entry) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce parent indirect section")
+ sect->u.indirect.parent = NULL;
+ sect->u.indirect.par_entry = 0;
+
+ /* If we weren't the first section, set "first row" for this indirect section */
+ if(!is_first)
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for indirect section")
+ } /* end if */
+
+ /* Check if we can allocate from start of indirect section */
+ if(child_entry == start_entry) {
+ /* Sanity check */
+ HDassert(sect->u.indirect.dir_nrows == 0);
+ HDassert(sect->u.indirect.dir_rows == NULL);
+ HDassert(sect->u.indirect.indir_nents > 0);
+ HDassert(sect->u.indirect.indir_ents);
+
+ /* Adjust section start */
+ sect->sect_info.addr += hdr->man_dtable.row_block_size[start_row];
+
+ /* Adjust span of blocks covered */
+ sect->u.indirect.col++;
+ if(sect->u.indirect.col == hdr->man_dtable.cparam.width) {
+ sect->u.indirect.row++;
+ sect->u.indirect.col = 0;
+ } /* end if */
+ sect->u.indirect.num_entries--;
+ sect->u.indirect.span_size -= hdr->man_dtable.row_block_size[start_row];
+
+ /* Adjust indirect entry information */
+ sect->u.indirect.indir_nents--;
+ HDmemmove(&sect->u.indirect.indir_ents[0],
+ &sect->u.indirect.indir_ents[1],
+ sect->u.indirect.indir_nents * sizeof(H5HF_free_section_t *));
+ HDassert(sect->u.indirect.indir_ents[0]);
+
+ /* Make new "first row" in new first indirect child section */
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, sect->u.indirect.indir_ents[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for child indirect section")
+ } /* end if */
+ else if(child_entry == end_entry) {
+ /* Sanity check */
+ HDassert(sect->u.indirect.indir_nents > 0);
+ HDassert(sect->u.indirect.indir_ents);
+
+ /* Adjust span of blocks covered */
+ sect->u.indirect.num_entries--;
+ sect->u.indirect.span_size -= hdr->man_dtable.row_block_size[end_row];
+
+ /* Adjust indirect entry information */
+ sect->u.indirect.indir_nents--;
+ if(sect->u.indirect.indir_nents == 0)
+ sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
+ } /* end if */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block for this section */
+ hsize_t iblock_off; /* Section's indirect block's offset in "heap space" */
+ haddr_t peer_sect_addr; /* Address of new peer section in "heap space" */
+ unsigned peer_nentries; /* Number of entries in new peer indirect section */
+ unsigned peer_start_row; /* Starting row for new peer indirect section */
+ unsigned peer_start_col; /* Starting column for new peer indirect section */
+ unsigned child_row; /* Row where child entry is located */
+ unsigned new_nentries; /* New number of entries for current indirect section */
+ unsigned u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(sect->u.indirect.indir_nents > 0);
+ HDassert(sect->u.indirect.indir_ents);
+
+ /* Compute basic information about peer & current indirect sections */
+ peer_nentries = end_entry - child_entry;
+ peer_start_row = (child_entry + 1) / hdr->man_dtable.cparam.width;
+ peer_start_col = (child_entry + 1) % hdr->man_dtable.cparam.width;
+ child_row = child_entry / hdr->man_dtable.cparam.width;
+ new_nentries = sect->u.indirect.num_entries - (peer_nentries + 1);
+ HDassert(child_row >= hdr->man_dtable.max_direct_rows);
+
+ /* Get indirect block information for peer */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ iblock = sect->u.indirect.u.iblock;
+ iblock_off = sect->u.indirect.u.iblock->block_off;
+ } /* end if */
+ else {
+ iblock = NULL;
+ iblock_off = sect->u.indirect.u.iblock_off;
+ } /* end else */
+
+ /* Update the number of entries in current section & calculate it's span size */
+ /* (Will use this to compute the section address for the peer section */
+ sect->u.indirect.num_entries = new_nentries;
+ sect->u.indirect.span_size = H5HF_dtable_span_size(&hdr->man_dtable,
+ sect->u.indirect.row, sect->u.indirect.col, new_nentries);
+ HDassert(sect->u.indirect.span_size > 0);
+
+ /* Compute address of peer indirect section */
+ peer_sect_addr = sect->sect_info.addr;
+ peer_sect_addr += sect->u.indirect.span_size;
+ peer_sect_addr += hdr->man_dtable.row_block_size[child_row];
+
+ /* Create peer indirect section */
+ if(NULL == (peer_sect = H5HF_sect_indirect_new(hdr, peer_sect_addr,
+ sect->sect_info.size, iblock, iblock_off, peer_start_row,
+ peer_start_col, peer_nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
+
+ /* Set up direct row & indirect entry information for peer section */
+ peer_sect->u.indirect.dir_nrows = 0;
+ peer_sect->u.indirect.dir_rows = NULL;
+ peer_sect->u.indirect.indir_nents = peer_nentries;
+ if(NULL == (peer_sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *) * peer_nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "allocation failed for indirect section pointer array")
+
+ /* Transfer child indirect sections between current & peer sections */
+ HDmemcpy(&peer_sect->u.indirect.indir_ents[0],
+ &sect->u.indirect.indir_ents[sect->u.indirect.indir_nents - peer_nentries],
+ (sizeof(H5HF_free_section_t *) * peer_nentries));
+ sect->u.indirect.indir_nents -= (peer_nentries + 1); /* Transferred blocks, plus child entry */
+
+ /* Eliminate indirect entries for this section, if appropriate */
+ if(sect->u.indirect.indir_nents == 0)
+ sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
+
+ /* Re-target transferred row sections to point to new underlying indirect section */
+ for(u = 0; u < peer_nentries; u++)
+ peer_sect->u.indirect.indir_ents[u]->u.indirect.parent = peer_sect;
+
+ /* Adjust reference counts for current & peer sections */
+ peer_sect->u.indirect.rc = peer_nentries;
+ sect->u.indirect.rc -= peer_nentries;
+
+ /* Transfer cached information about indirect block */
+ peer_sect->u.indirect.iblock_entries = sect->u.indirect.iblock_entries;
+
+ /* Make certain we've tracked the sections' dependents correctly */
+ /* (Note modified on current section's ref. count, since we haven't
+ * detached the child section yet)
+ */
+ HDassert((sect->u.indirect.rc - 1) ==
+ (sect->u.indirect.indir_nents + sect->u.indirect.dir_nrows));
+ HDassert(peer_sect->u.indirect.rc ==
+ (peer_sect->u.indirect.indir_nents + peer_sect->u.indirect.dir_nrows));
+
+ /* Make new "first row" in peer section */
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, peer_sect->u.indirect.indir_ents[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't make new 'first row' for peer indirect section")
+
+ /* Reset the peer_sect variable, to indicate that it has been hooked into the data structures correctly and shouldn't be freed */
+ peer_sect = NULL;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Decrement count of entries & indirect entries */
+ sect->u.indirect.num_entries--;
+ sect->u.indirect.indir_nents--;
+ HDassert(sect->u.indirect.indir_nents == 0);
+
+ /* Eliminate indirect entries for this section */
+ sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
+ } /* end else */
+
+ /* Decrement # of sections which depend on this row */
+ /* (Must be last as section can be freed) */
+ if(H5HF_sect_indirect_decr(sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement section's ref. count ")
+
+done:
+ /* Free allocated peer_sect. Note that this is necessary for all failures until peer_sect is linked
+ * into the main free space structures (via the direct blocks), and the reference count is updated. */
+ if(peer_sect) {
+ /* Sanity check - we should only be here if an error occurred */
+ HDassert(ret_value < 0);
+
+ if(H5HF_sect_indirect_free(peer_sect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_reduce() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_is_first
+ *
+ * Purpose: Check if indirect section is first in all parents
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/<can't fail>
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5HF_sect_indirect_is_first(H5HF_free_section_t *sect)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(sect);
+
+ /* Recurse to parent */
+ if(sect->u.indirect.parent) {
+ if(sect->sect_info.addr == sect->u.indirect.parent->sect_info.addr)
+ ret_value = H5HF_sect_indirect_is_first(sect->u.indirect.parent);
+ } /* end if */
+ else
+ ret_value = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_is_first() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_first
+ *
+ * Purpose: Make new 'first row' for indirect section
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_first(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(hdr);
+ HDassert(sect);
+
+ /* Check if this indirect section has direct block rows */
+ if(sect->u.indirect.dir_nrows > 0) {
+ /* Sanity checks */
+ HDassert(sect->u.indirect.row == 0);
+ HDassert(sect->u.indirect.col == 0);
+ HDassert(sect->u.indirect.dir_rows);
+ HDassert(sect->u.indirect.dir_rows[0]);
+
+ /* Change first row section in indirect section to be the "first row" */
+ if(H5HF_sect_row_first(hdr, dxpl_id, sect->u.indirect.dir_rows[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set row section to be first row")
+ } /* end if */
+ else {
+ /* Sanity checks */
+ HDassert(sect->u.indirect.indir_nents > 0);
+ HDassert(sect->u.indirect.indir_ents);
+ HDassert(sect->u.indirect.indir_ents[0]);
+
+ /* Forward to first child indirect section */
+ if(H5HF_sect_indirect_first(hdr, dxpl_id, sect->u.indirect.indir_ents[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "can't set child indirect section to be first row")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_first() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_get_iblock
+ *
+ * Purpose: Retrieve the indirect block for a indirect section
+ *
+ * Return: Pointer to indirect block on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 9 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5HF_indirect_t *
+H5HF_sect_indirect_get_iblock(H5HF_free_section_t *sect)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT);
+ HDassert(sect->sect_info.state == H5FS_SECT_LIVE);
+
+ FUNC_LEAVE_NOAPI(sect->u.indirect.u.iblock)
+} /* end H5HF_sect_indirect_get_iblock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_merge_row
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_merge_row(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ H5HF_free_section_t *row_sect1, H5HF_free_section_t *row_sect2)
+{
+ H5HF_free_section_t *sect1, *sect2; /* Indirect sections underlying row sections */
+ unsigned start_entry1; /* Start entry for section #1 */
+ unsigned start_row1, start_col1; /* Starting row & column for section #1 */
+ unsigned end_entry1; /* End entry for section #1 */
+ unsigned end_row1; /* Ending row for section #1 */
+ unsigned start_row2; /* Starting row for section #2 */
+ hbool_t merged_rows; /* Flag to indicate that rows was merged together */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check parameters */
+ HDassert(hdr);
+ HDassert(row_sect1);
+ HDassert(row_sect1->u.row.under);
+ HDassert(row_sect1->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(row_sect2);
+ HDassert(row_sect2->u.row.under);
+ HDassert(row_sect2->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(row_sect2->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW);
+
+ /* Set up indirect section information */
+ sect1 = H5HF_sect_indirect_top(row_sect1->u.row.under);
+ HDassert(sect1);
+ sect2 = H5HF_sect_indirect_top(row_sect2->u.row.under);
+ HDassert(sect2);
+
+ /* Sanity check some assumptions about the indirect sections */
+ HDassert(sect1->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(sect1->u.indirect.span_size > 0);
+ HDassert(sect1->u.indirect.iblock_entries > 0);
+ HDassert(sect2->sect_info.state == H5FS_SECT_LIVE);
+ HDassert(sect2->u.indirect.span_size > 0);
+ HDassert(sect2->u.indirect.iblock_entries > 0);
+ HDassert(sect1->u.indirect.iblock_entries == sect2->u.indirect.iblock_entries);
+
+ /* Set up span information */
+ start_row1 = sect1->u.indirect.row;
+ start_col1 = sect1->u.indirect.col;
+ start_entry1 = (start_row1 * hdr->man_dtable.cparam.width) + start_col1;
+ end_entry1 = (start_entry1 + sect1->u.indirect.num_entries) - 1;
+ end_row1 = end_entry1 / hdr->man_dtable.cparam.width;
+ start_row2 = sect2->u.indirect.row;
+
+ /* Check for direct sections in second section */
+ /* (second indirect section can be parent of indirect section for second
+ * row, and thus have no row sections of it's own)
+ */
+ if(sect2->u.indirect.dir_nrows > 0) {
+ unsigned new_dir_nrows1; /* New value for number of direct rows in first section */
+ unsigned src_row2; /* Source row for copying from second section */
+ unsigned nrows_moved2; /* Number of rows to move from second section to first */
+
+ /* Sanity check child row assumptions */
+ /* (second indirect section should be at top of equal or deeper
+ * hier. of row/indirect sections, so if second indirect section
+ * has child row sections, first indirect section _must_ have
+ * them also)
+ */
+ HDassert(sect1->u.indirect.dir_nrows > 0);
+ HDassert(sect1->u.indirect.dir_rows);
+
+ /* Check for sections sharing a row in the same underlying indirect block */
+ if(row_sect1->u.row.under->u.indirect.u.iblock->block_off == row_sect2->u.row.under->u.indirect.u.iblock->block_off
+ && end_row1 == start_row2) {
+ H5HF_free_section_t *last_row_sect1; /* Last row in first indirect section */
+
+ /* Locate the last row section in first indirect section, if we don't already have it */
+ if(row_sect1->u.row.row != end_row1)
+ last_row_sect1 = sect1->u.indirect.dir_rows[sect1->u.indirect.dir_nrows - 1];
+ else
+ last_row_sect1 = row_sect1;
+ HDassert(last_row_sect1);
+ HDassert(last_row_sect1->u.row.row == end_row1);
+
+ /* Adjust info for first row section, to absorb second row section */
+ HDassert((last_row_sect1->u.row.col + last_row_sect1->u.row.num_entries) == row_sect2->u.row.col);
+ last_row_sect1->u.row.num_entries += row_sect2->u.row.num_entries;
+
+ /* Set up parameters for transfer of rows */
+ src_row2 = 1;
+ nrows_moved2 = sect2->u.indirect.dir_nrows - 1;
+ new_dir_nrows1 = (sect1->u.indirect.dir_nrows + sect2->u.indirect.dir_nrows) - 1;
+
+ /* Indicate that the rows were merged */
+ merged_rows = TRUE;
+ } /* end if */
+ else {
+
+ /* Set up parameters for transfer of rows */
+ src_row2 = 0;
+ nrows_moved2 = sect2->u.indirect.dir_nrows;
+ new_dir_nrows1 = sect1->u.indirect.dir_nrows + sect2->u.indirect.dir_nrows;
+
+ /* Indicate that the rows were _not_ merged */
+ merged_rows = FALSE;
+ } /* end else */
+
+ /* Check if we need to move additional rows */
+ if(nrows_moved2 > 0) {
+ H5HF_free_section_t **new_dir_rows; /* Pointer to new array of direct row pointers */
+
+ /* Extend the first section's row array */
+ if(NULL == (new_dir_rows = (H5HF_free_section_t **)H5MM_realloc(sect1->u.indirect.dir_rows, sizeof(H5HF_free_section_t *) * new_dir_nrows1)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
+ sect1->u.indirect.dir_rows = new_dir_rows;
+
+ /* Transfer the second section's rows to first section */
+ HDmemcpy(&sect1->u.indirect.dir_rows[sect1->u.indirect.dir_nrows],
+ &sect2->u.indirect.dir_rows[src_row2],
+ (sizeof(H5HF_free_section_t *) * nrows_moved2));
+
+ /* Re-target the row sections moved from second section */
+ for(u = sect1->u.indirect.dir_nrows; u < new_dir_nrows1; u++)
+ sect1->u.indirect.dir_rows[u]->u.row.under = sect1;
+
+ /* Adjust reference counts to account for transferred rows */
+ sect1->u.indirect.rc += nrows_moved2;
+ sect2->u.indirect.rc -= nrows_moved2;
+
+ /* Update information for first section */
+ sect1->u.indirect.dir_nrows = new_dir_nrows1;
+ } /* end if */
+ } /* end if */
+ else
+ /* Indicate that the rows were _not_ merged */
+ merged_rows = FALSE;
+
+ /* Check for indirect sections in second section */
+ if(sect2->u.indirect.indir_nents > 0) {
+ unsigned new_indir_nents1; /* New value for number of indirect entries in first section */
+
+ /* Some sanity checks on second indirect section */
+ HDassert(sect2->u.indirect.rc > 0);
+ HDassert(sect2->u.indirect.indir_nents > 0);
+ HDassert(sect2->u.indirect.indir_ents);
+
+ /* Set up parameters for transfer of entries */
+ new_indir_nents1 = sect1->u.indirect.indir_nents + sect2->u.indirect.indir_nents;
+
+ /* Check if first section can just take over second section's memory buffer */
+ if(sect1->u.indirect.indir_ents == NULL) {
+ sect1->u.indirect.indir_ents = sect2->u.indirect.indir_ents;
+ sect2->u.indirect.indir_ents = NULL;
+ } /* end if */
+ else {
+ H5HF_free_section_t **new_indir_ents; /* Pointer to new array of indirect entries */
+
+ /* Extend the first section's entry array */
+ if(NULL == (new_indir_ents = (H5HF_free_section_t **)H5MM_realloc(sect1->u.indirect.indir_ents, sizeof(H5HF_free_section_t *) * new_indir_nents1)))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for row section pointer array")
+ sect1->u.indirect.indir_ents = new_indir_ents;
+
+ /* Transfer the second section's entries to first section */
+ HDmemcpy(&sect1->u.indirect.indir_ents[sect1->u.indirect.indir_nents],
+ &sect2->u.indirect.indir_ents[0],
+ (sizeof(H5HF_free_section_t *) * sect2->u.indirect.indir_nents));
+ } /* end else */
+
+ /* Re-target the child indirect sections moved from second section */
+ for(u = sect1->u.indirect.indir_nents; u < new_indir_nents1; u++)
+ sect1->u.indirect.indir_ents[u]->u.indirect.parent = sect1;
+
+ /* Adjust reference counts for transferred child indirect sections */
+ sect1->u.indirect.rc += sect2->u.indirect.indir_nents;
+ sect2->u.indirect.rc -= sect2->u.indirect.indir_nents;
+
+ /* Update information for first section */
+ sect1->u.indirect.indir_nents = new_indir_nents1;
+ } /* end if */
+
+ /* Update information for first section */
+ sect1->u.indirect.num_entries += sect2->u.indirect.num_entries;
+ sect1->u.indirect.span_size += sect2->u.indirect.span_size;
+
+ /* Make certain we've tracked the first section's dependents correctly */
+ HDassert(sect1->u.indirect.rc ==
+ (sect1->u.indirect.indir_nents + sect1->u.indirect.dir_nrows));
+
+ /* Wrap up, freeing or re-inserting second row section */
+ /* (want this to be after the first indirection section is consistent again) */
+ if(merged_rows) {
+ /* Release second row section */
+ /* (indirectly releases second indirect section, since all of it's
+ * other dependents are gone)
+ */
+ HDassert(sect2->u.indirect.rc == 1);
+ if(H5HF_sect_row_free((H5FS_section_info_t *)row_sect2) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free row section")
+ } /* end if */
+ else {
+ /* Decrement ref. count on second indirect section's parent */
+ HDassert(sect2->u.indirect.rc == 0);
+ if(sect2->u.indirect.parent)
+ if(H5HF_sect_indirect_decr(sect2->u.indirect.parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't decrement ref. count on parent indirect section")
+
+ /* Free second indirect section */
+ if(H5HF_sect_indirect_free(sect2) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+
+ /* Re-add the second section's first row */
+ /* (it's already been added to first indirect section, but it's been removed
+ * from the free space manager and needs to be re-added)
+ */
+ row_sect2->sect_info.type = H5HF_FSPACE_SECT_NORMAL_ROW;
+ if(H5HF_space_add(hdr, dxpl_id, row_sect2, H5FS_ADD_SKIP_VALID) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add second row section to free space")
+ } /* end else */
+
+ /* Check if we can create parent indirect section for first section */
+ /* (i.e. merged indirect sections cover an entire indirect block) */
+ if(sect1->u.indirect.iblock_entries == sect1->u.indirect.num_entries) {
+ /* Build parent section for fully populated indirect section */
+ HDassert(sect1->u.indirect.parent == NULL);
+ if(H5HF_sect_indirect_build_parent(hdr, sect1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create parent for full indirect section")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_merge_row() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_build_parent
+ *
+ * Purpose: Build a parent indirect section for a full indirect section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, July 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_build_parent(H5HF_hdr_t *hdr, H5HF_free_section_t *sect)
+{
+ H5HF_indirect_t *par_iblock; /* Indirect block for parent section */
+ H5HF_free_section_t *par_sect = NULL; /* Parent indirect section */
+ unsigned par_row, par_col; /* Row & column in parent indirect section */
+ unsigned par_entry; /* Entry within parent indirect section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check parameters */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(sect->u.indirect.span_size > 0);
+ HDassert(sect->u.indirect.iblock_entries > 0);
+ HDassert(sect->u.indirect.iblock_entries == sect->u.indirect.num_entries);
+ HDassert(sect->u.indirect.u.iblock);
+ HDassert(sect->u.indirect.parent == NULL);
+
+ /* Get information for creating parent indirect section */
+ par_entry = sect->u.indirect.u.iblock->par_entry;
+ par_row = par_entry / hdr->man_dtable.cparam.width;
+ par_col = par_entry % hdr->man_dtable.cparam.width;
+ HDassert(par_row >= hdr->man_dtable.max_direct_rows);
+ par_iblock = sect->u.indirect.u.iblock->parent;
+ HDassert(par_iblock);
+
+ /* Create parent indirect section */
+ if(NULL == (par_sect = H5HF_sect_indirect_new(hdr, sect->sect_info.addr,
+ sect->sect_info.size, par_iblock, par_iblock->block_off,
+ par_row, par_col, 1)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section")
+
+ /* No rows of direct blocks covered in parent, reset direct row information */
+ par_sect->u.indirect.dir_nrows = 0;
+ par_sect->u.indirect.dir_rows = NULL;
+
+ /* Allocate space for the child indirect sections */
+ par_sect->u.indirect.indir_nents = 1;
+ if(NULL == (par_sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_malloc(sizeof(H5HF_free_section_t *))))
+ HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "allocation failed for indirect section pointer array")
+
+ /* Attach sections together */
+ sect->u.indirect.parent = par_sect;
+ sect->u.indirect.par_entry = par_entry;
+ par_sect->u.indirect.indir_ents[0] = sect;
+ par_sect->u.indirect.rc = 1;
+
+done:
+ if(ret_value < 0)
+ if(par_sect && H5HF_sect_indirect_free(par_sect) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_build_parent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_shrink
+ *
+ * Purpose: "Shrink" container w/section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_shrink(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check parameters */
+ HDassert(hdr);
+ HDassert(sect);
+
+ /* Sanity check some assumptions about the indirect section */
+ HDassert(sect->u.indirect.dir_nrows > 0 || sect->u.indirect.indir_nents > 0);
+
+ /* Walk through direct rows, freeing them */
+ for(u = 0; u < sect->u.indirect.dir_nrows; u++) {
+ /* Remove the normal rows from free space manager */
+ if(sect->u.indirect.dir_rows[u]->sect_info.type != H5HF_FSPACE_SECT_FIRST_ROW) {
+ HDassert(sect->u.indirect.dir_rows[u]->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+ if(H5HF_space_remove(hdr, dxpl_id, sect->u.indirect.dir_rows[u]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove section from heap free space")
+ } /* end if */
+
+ /* Release the row section */
+ if(H5HF_sect_row_free_real(sect->u.indirect.dir_rows[u]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free child section node")
+ } /* end for */
+
+ /* Walk through indirect entries, freeing them (recursively) */
+ for(u = 0; u < sect->u.indirect.indir_nents; u++)
+ if(H5HF_sect_indirect_shrink(hdr, dxpl_id, sect->u.indirect.indir_ents[u]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free child section node")
+
+ /* Free the indirect section itself */
+ if(H5HF_sect_indirect_free(sect) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_sect_indirect_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_serialize
+ *
+ * Purpose: Serialize a "live" indirect section into a buffer
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_serialize(H5HF_hdr_t *hdr, const H5HF_free_section_t *sect,
+ uint8_t *buf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(sect);
+ HDassert(buf);
+
+ /* Check if this indirect section has a parent & forward if this section is first */
+ if(sect->u.indirect.parent) {
+ if(sect->sect_info.addr == sect->u.indirect.parent->sect_info.addr)
+ if(H5HF_sect_indirect_serialize(hdr, sect->u.indirect.parent, buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "can't serialize indirect section's parent indirect section")
+ } /* end if */
+ else {
+ /* Indirect range's indirect block's block offset */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ HDassert(sect->u.indirect.u.iblock);
+ UINT64ENCODE_VAR(buf, sect->u.indirect.u.iblock->block_off, hdr->heap_off_size);
+ } /* end if */
+ else
+ UINT64ENCODE_VAR(buf, sect->u.indirect.u.iblock_off, hdr->heap_off_size);
+
+ /* Indirect range's row */
+ UINT16ENCODE(buf, sect->u.indirect.row);
+
+ /* Indirect range's column */
+ UINT16ENCODE(buf, sect->u.indirect.col);
+
+ /* Indirect range's # of entries */
+ UINT16ENCODE(buf, sect->u.indirect.num_entries);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_indirect_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_deserialize
+ *
+ * Purpose: Deserialize a buffer into a "live" indirect section
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FS_section_info_t *
+H5HF_sect_indirect_deserialize(H5HF_hdr_t *hdr, hid_t dxpl_id,
+ const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags)
+{
+ H5HF_free_section_t *new_sect; /* New indirect section */
+ hsize_t iblock_off; /* Indirect block's offset */
+ unsigned start_row; /* Indirect section's start row */
+ unsigned start_col; /* Indirect section's start column */
+ unsigned nentries; /* Indirect section's number of entries */
+ unsigned start_entry; /* Start entry in indirect block */
+ unsigned end_entry; /* End entry in indirect block */
+ unsigned end_row; /* End row in indirect block */
+ unsigned end_col; /* End column in indirect block */
+ H5FS_section_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(hdr);
+ HDassert(buf);
+ HDassert(H5F_addr_defined(sect_addr));
+ HDassert(sect_size);
+
+ /* Indirect range's indirect block's block offset */
+ UINT64DECODE_VAR(buf, iblock_off, hdr->heap_off_size);
+
+ /* Indirect section's row */
+ UINT16DECODE(buf, start_row);
+
+ /* Indirect section's column */
+ UINT16DECODE(buf, start_col);
+
+ /* Indirect section's # of entries */
+ UINT16DECODE(buf, nentries);
+
+ /* Create free space section node */
+ if(NULL == (new_sect = H5HF_sect_indirect_new(hdr, sect_addr, sect_size,
+ NULL, iblock_off, start_row, start_col, nentries)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create indirect section")
+
+ /* Compute start entry */
+ start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
+
+ /* Compute end column & row */
+ end_entry = (start_entry + nentries) - 1;
+ end_row = end_entry / hdr->man_dtable.cparam.width;
+ end_col = end_entry % hdr->man_dtable.cparam.width;
+
+ /* Initialize rows for new indirect section */
+ if(H5HF_sect_indirect_init_rows(hdr, dxpl_id, new_sect, TRUE, NULL,
+ H5FS_ADD_DESERIALIZING, new_sect->u.indirect.row, new_sect->u.indirect.col,
+ end_row, end_col) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize indirect section")
+
+ /* Indicate that this section shouldn't be added to free space manager's list */
+ *des_flags |= H5FS_DESERIALIZE_NO_ADD;
+
+ /* Set return value */
+ ret_value = (H5FS_section_info_t *)new_sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_indirect_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_free
+ *
+ * Purpose: Free a 'indirect' section node
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_free(H5HF_free_section_t *sect)
+{
+ H5HF_indirect_t *iblock = NULL; /* Indirect block for section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(sect);
+
+ /* Release the memory for tracking direct rows */
+ sect->u.indirect.dir_rows = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.dir_rows);
+
+ /* Release the memory for tracking indirect entries */
+ sect->u.indirect.indir_ents = (H5HF_free_section_t **)H5MM_xfree(sect->u.indirect.indir_ents);
+
+ /* Check for live reference to an indirect block */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ /* Get indirect block, if there was one */
+ if(sect->u.indirect.u.iblock)
+ iblock = sect->u.indirect.u.iblock;
+ } /* end if */
+
+ /* Release the sections */
+ if(H5HF_sect_node_free(sect, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_sect_indirect_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_valid
+ *
+ * Purpose: Check the validity of a section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, July 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_valid(const H5HF_hdr_t *hdr, const H5HF_free_section_t *sect)
+{
+ unsigned start_row; /* Row for first block covered */
+ unsigned start_col; /* Column for first block covered */
+ unsigned start_entry; /* Entry for first block covered */
+ unsigned end_row; /* Row for last block covered */
+ unsigned end_entry; /* Entry for last block covered */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check arguments */
+ HDassert(hdr);
+ HDassert(sect);
+
+ /* Compute starting entry, column & row */
+ start_row = sect->u.indirect.row;
+ start_col = sect->u.indirect.col;
+ start_entry = (start_row * hdr->man_dtable.cparam.width) + start_col;
+
+ /* Compute ending entry, column & row */
+ end_entry = (start_entry + sect->u.indirect.num_entries) - 1;
+ end_row = end_entry / hdr->man_dtable.cparam.width;
+
+ /* Sanity check any direct rows */
+ if(sect->u.indirect.dir_nrows > 0) {
+ unsigned dir_nrows; /* Number of direct rows in section */
+ unsigned max_dir_row; /* Maximum direct row in section */
+
+ /* Check for indirect rows in section */
+ if(end_row >= hdr->man_dtable.max_direct_rows)
+ max_dir_row = hdr->man_dtable.max_direct_rows - 1;
+ else
+ max_dir_row = end_row;
+
+ /* Iterate over direct rows, checking pointer references */
+ dir_nrows = (max_dir_row - start_row) + 1;
+ HDassert(dir_nrows == sect->u.indirect.dir_nrows);
+ for(u = 0; u < dir_nrows; u++) {
+ const H5HF_free_section_t *tmp_row_sect; /* Pointer to row section */
+
+ tmp_row_sect = sect->u.indirect.dir_rows[u];
+ HDassert(tmp_row_sect->sect_info.type == H5HF_FSPACE_SECT_FIRST_ROW
+ || tmp_row_sect->sect_info.type == H5HF_FSPACE_SECT_NORMAL_ROW);
+ HDassert(tmp_row_sect->u.row.under == sect);
+ HDassert(tmp_row_sect->u.row.row == (start_row + u));
+ if(u > 0) {
+ const H5HF_free_section_t *tmp_row_sect2; /* Pointer to row section */
+
+ tmp_row_sect2 = sect->u.indirect.dir_rows[u - 1];
+ HDassert(tmp_row_sect2->u.row.row < tmp_row_sect->u.row.row);
+ HDassert(H5F_addr_lt(tmp_row_sect2->sect_info.addr, tmp_row_sect->sect_info.addr));
+ HDassert(tmp_row_sect2->sect_info.size <= tmp_row_sect->sect_info.size);
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Sanity check any indirect entries */
+ if(sect->u.indirect.indir_nents > 0) {
+ /* Basic sanity checks */
+ if(sect->sect_info.state == H5FS_SECT_LIVE) {
+ HDassert(sect->u.indirect.iblock_entries);
+ HDassert(sect->u.indirect.indir_nents <= sect->u.indirect.iblock_entries);
+ } /* end if */
+ HDassert(sect->u.indirect.indir_ents);
+
+ /* Sanity check each child indirect section */
+ for(u = 0; u < sect->u.indirect.indir_nents; u++) {
+ const H5HF_free_section_t *tmp_child_sect; /* Pointer to child indirect section */
+
+ tmp_child_sect = sect->u.indirect.indir_ents[u];
+ HDassert(tmp_child_sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT);
+ HDassert(tmp_child_sect->u.indirect.parent == sect);
+ if(u > 0) {
+ const H5HF_free_section_t *tmp_child_sect2; /* Pointer to child indirect section */
+
+ tmp_child_sect2 = sect->u.indirect.indir_ents[u - 1];
+ HDassert(H5F_addr_lt(tmp_child_sect2->sect_info.addr, tmp_child_sect->sect_info.addr));
+ } /* end if */
+
+ /* Recursively check child indirect section */
+ H5HF_sect_indirect_valid(hdr, tmp_child_sect);
+ } /* end for */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_sect_indirect_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_sect_indirect_debug
+ *
+ * Purpose: Dump debugging information about an indirect free space section
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_sect_indirect_debug(const H5HF_free_section_t *sect,
+ FILE *stream, int indent, int fwidth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ /* Print indirect section information */
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Row:",
+ sect->u.indirect.row);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Column:",
+ sect->u.indirect.col);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of entries:",
+ sect->u.indirect.num_entries);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_sect_indirect_debug() */
+
diff --git a/src/H5HFspace.c b/src/H5HFspace.c
new file mode 100644
index 0000000..41954fc
--- /dev/null
+++ b/src/H5HFspace.c
@@ -0,0 +1,638 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFspace.c
+ * May 2 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Space allocation routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5HF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */
+#define H5HF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */
+#define H5HF_FSPACE_THRHD_DEF 1 /* Default: no alignment threshold */
+#define H5HF_FSPACE_ALIGN_DEF 1 /* Default: no alignment */
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_start
+ *
+ * Purpose: "Start up" free space for heap - open existing free space
+ * structure if one exists, otherwise create a new free space
+ * structure
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2006
+ *
+ * Modifications:
+ * Vailin Choi, July 29th, 2008
+ * Pass values of alignment and threshold to FS_create() and FS_open()
+ * for handling alignment.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id, hbool_t may_create)
+{
+ const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for fractal heap */
+ H5HF_FSPACE_SECT_CLS_SINGLE,
+ H5HF_FSPACE_SECT_CLS_FIRST_ROW,
+ H5HF_FSPACE_SECT_CLS_NORMAL_ROW,
+ H5HF_FSPACE_SECT_CLS_INDIRECT};
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check for creating free space info for the heap */
+ if(H5F_addr_defined(hdr->fs_addr)) {
+ /* Open an existing free space structure for the heap */
+ if(NULL == (hdr->fspace = H5FS_open(hdr->f, dxpl_id, hdr->fs_addr,
+ NELMTS(classes), classes, hdr, (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info")
+ } /* end if */
+ else {
+ /* Check if we are allowed to create the free space manager */
+ if(may_create) {
+ H5FS_create_t fs_create; /* Free space creation parameters */
+
+ /* Set the free space creation parameters */
+ fs_create.client = H5FS_CLIENT_FHEAP_ID;
+ fs_create.shrink_percent = H5HF_FSPACE_SHRINK;
+ fs_create.expand_percent = H5HF_FSPACE_EXPAND;
+ fs_create.max_sect_size = hdr->man_dtable.cparam.max_direct_size;
+ fs_create.max_sect_addr = hdr->man_dtable.cparam.max_index;
+
+ /* Create the free space structure for the heap */
+ if(NULL == (hdr->fspace = H5FS_create(hdr->f, dxpl_id, &hdr->fs_addr,
+ &fs_create, NELMTS(classes), classes, hdr, (hsize_t)H5HF_FSPACE_THRHD_DEF, (hsize_t)H5HF_FSPACE_ALIGN_DEF)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info")
+ HDassert(H5F_addr_defined(hdr->fs_addr));
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_start() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_add
+ *
+ * Purpose: Add a section to the free space for the heap
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 15 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node,
+ unsigned flags)
+{
+ H5HF_sect_add_ud_t udata; /* User data for free space manager 'add' */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(node);
+
+ /* Check if the free space for the heap has been initialized */
+ if(!hdr->fspace)
+ if(H5HF_space_start(hdr, dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
+
+ /* Construct user data */
+ udata.hdr = hdr;
+ udata.dxpl_id = dxpl_id;
+
+ /* Add to the free space for the heap */
+ if(H5FS_sect_add(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)node, flags, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't add section to heap free space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_find
+ *
+ * Purpose: Attempt to find space in a fractal heap
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5HF_space_find(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t request, H5HF_free_section_t **node)
+{
+ htri_t node_found = FALSE; /* Whether an existing free list node was found */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(request);
+ HDassert(node);
+
+ /* Check if the free space for the heap has been initialized */
+ if(!hdr->fspace)
+ if(H5HF_space_start(hdr, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
+
+ /* Search for free space in the heap */
+ if(hdr->fspace)
+ if((node_found = H5FS_sect_find(hdr->f, dxpl_id, hdr->fspace, request, (H5FS_section_info_t **)node)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap")
+
+ /* Set return value */
+ ret_value = node_found;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_revert_root_cb
+ *
+ * Purpose: Callback routine from iterator, to reset 'parent' pointers in
+ * sections, when the heap is changing from having a root indirect
+ * block to a direct block.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 24 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_space_revert_root_cb(H5FS_section_info_t *_sect, void H5_ATTR_UNUSED *_udata)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+
+ /* Only modify "live" single blocks... */
+ if(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE && sect->sect_info.state == H5FS_SECT_LIVE) {
+ /* Release hold on previous indirect block (we must have one) */
+ HDassert(sect->u.single.parent);
+ if(H5HF_iblock_decr(sect->u.single.parent) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on section's indirect block")
+
+ /* Reset parent information */
+ sect->u.single.parent = NULL;
+ sect->u.single.par_entry = 0;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_revert_root_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_revert_root
+ *
+ * Purpose: Reset 'parent' pointers in sections, when the heap is
+ * changing from having a root indirect block to a direct block.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 23 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_revert_root(const H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Only need to scan the sections if the free space has been initialized */
+ if(hdr->fspace) {
+ /* Iterate over all sections, reseting the parent pointers in 'single' sections */
+ if(H5FS_sect_iterate(hdr->f, dxpl_id, hdr->fspace, H5HF_space_revert_root_cb, NULL) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over sections to reset parent pointers")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_revert_root() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_create_root_cb
+ *
+ * Purpose: Callback routine from iterator, to set 'parent' pointers in
+ * sections to newly created root indirect block, when the heap
+ * is changing from having a root direct block to an indirect block.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 24 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_space_create_root_cb(H5FS_section_info_t *_sect, void *_udata)
+{
+ H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Section to dump info */
+ H5HF_indirect_t *root_iblock = (H5HF_indirect_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(root_iblock);
+
+ /* Sanity check sections */
+ /* (If we are switching from a direct block for the root block of the heap, */
+ /* there should only be 'single' type sections. -QAK) */
+ HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE);
+
+ /* Increment ref. count on new root indirect block */
+ if(H5HF_iblock_incr(root_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on section's indirect block")
+
+ /* Set parent info ("live" section must _NOT_ have a parent right now) */
+ if(sect->sect_info.state == H5FS_SECT_SERIALIZED)
+ sect->sect_info.state = H5FS_SECT_LIVE; /* Mark "live" now */
+ else
+ HDassert(!sect->u.single.parent);
+ sect->u.single.parent = root_iblock;
+ sect->u.single.par_entry = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_create_root_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_create_root
+ *
+ * Purpose: Set 'parent' pointers in sections to new indirect block, when
+ * the heap is changing from having a root direct block to a
+ * indirect block.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 24 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_create_root(const H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *root_iblock)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(root_iblock);
+
+ /* Only need to scan the sections if the free space has been initialized */
+ if(hdr->fspace) {
+ /* Iterate over all sections, seting the parent pointers in 'single' sections to the new indirect block */
+ if(H5FS_sect_iterate(hdr->f, dxpl_id, hdr->fspace, H5HF_space_create_root_cb, root_iblock) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over sections to set parent pointers")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_create_root() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_size
+ *
+ * Purpose: Query the size of the heap's free space info on disk
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * August 14 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_size(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t *fs_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(fs_size);
+
+ /* Check if the free space for the heap has been initialized */
+ if(!hdr->fspace)
+ if(H5HF_space_start(hdr, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space")
+
+ /* Get free space metadata size */
+ if(hdr->fspace) {
+ if(H5FS_size(hdr->f, hdr->fspace, fs_size) < 0)
+ HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't retrieve FS meta storage info")
+ } /* end if */
+ else
+ *fs_size = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_remove
+ *
+ * Purpose: Remove a section from the free space for the heap
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 24 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(hdr->fspace);
+ HDassert(node);
+
+ /* Remove from the free space for the heap */
+ if(H5FS_sect_remove(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)node) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove section from heap free space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_close
+ *
+ * Purpose: Close the free space for the heap
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_close(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check if the free space was ever opened */
+ if(hdr->fspace) {
+ hsize_t nsects; /* Number of sections for this heap */
+
+ /* Retrieve the number of sections for this heap */
+ if(H5FS_sect_stats(hdr->fspace, NULL, &nsects) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOUNT, FAIL, "can't query free space section count")
+#ifdef QAK
+HDfprintf(stderr, "%s: nsects = %Hu\n", FUNC, nsects);
+#endif /* QAK */
+
+ /* Close the free space for the heap */
+ if(H5FS_close(hdr->f, dxpl_id, hdr->fspace) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
+ hdr->fspace = NULL;
+
+ /* Check if we can delete the free space manager for this heap */
+ if(!nsects) {
+ if(H5FS_delete(hdr->f, dxpl_id, hdr->fs_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete free space info")
+ hdr->fs_addr = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_delete
+ *
+ * Purpose: Delete the free space manager for the heap
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_delete(H5HF_hdr_t *hdr, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Delete the free space manager */
+ if(H5FS_delete(hdr->f, dxpl_id, hdr->fs_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "can't delete to free space manager")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_space_change_sect_class
+ *
+ * Purpose: Change a section's class
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * July 10 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_space_sect_change_class(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect, uint16_t new_class)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef QAK
+HDfprintf(stderr, "%s: Called\n", FUNC);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(hdr->fspace);
+ HDassert(sect);
+
+ /* Notify the free space manager that a section has changed class */
+ if(H5FS_sect_change_class(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)sect, new_class) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "can't modify class of free space section")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_space_sect_change_class() */
+
diff --git a/src/H5HFstat.c b/src/H5HFstat.c
new file mode 100644
index 0000000..e38a9b1
--- /dev/null
+++ b/src/H5HFstat.c
@@ -0,0 +1,179 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, March 6, 2006
+ *
+ * Purpose: Fractal heap metadata statistics functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_stat_info
+ *
+ * Purpose: Retrieve metadata statistics for the fractal heap
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, March 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_stat_info(const H5HF_t *fh, H5HF_stat_t *stats)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(stats);
+
+ /* Report statistics for fractal heap */
+ stats->man_size = fh->hdr->man_size;
+ stats->man_alloc_size = fh->hdr->man_alloc_size;
+ stats->man_iter_off = fh->hdr->man_iter_off;
+ stats->man_nobjs = fh->hdr->man_nobjs;
+ stats->man_free_space = fh->hdr->total_man_free;
+ stats->huge_size = fh->hdr->huge_size;
+ stats->huge_nobjs = fh->hdr->huge_nobjs;
+ stats->tiny_size = fh->hdr->tiny_size;
+ stats->tiny_nobjs = fh->hdr->tiny_nobjs;
+/* XXX: Add more metadata statistics for the heap */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_stat_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_size
+ *
+ * Purpose: Retrieve storage info for:
+ * 1. fractal heap
+ * 2. btree storage used by huge objects in fractal heap
+ * 3. free space storage info
+ *
+ * Return: non-negative on success, negative on error
+ *
+ * Programmer: Vailin Choi
+ * July 12 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_size(const H5HF_t *fh, hid_t dxpl_id, hsize_t *heap_size)
+{
+ H5HF_hdr_t *hdr; /* Fractal heap header */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ hsize_t meta_size = 0; /* free space storage size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(fh);
+ HDassert(heap_size);
+
+ /* Get "convenience" pointer to fractal heap header */
+ hdr = fh->hdr;
+
+ /* Add in values already known */
+ *heap_size += hdr->heap_size; /* Heap header */
+ *heap_size += hdr->man_alloc_size; /* Direct block storage for "managed" objects */
+ *heap_size += hdr->huge_size; /* "huge" object storage */
+
+ /* Check for indirect blocks for managed objects */
+ if(H5F_addr_defined(hdr->man_dtable.table_addr) && hdr->man_dtable.curr_root_rows != 0)
+ if(H5HF_man_iblock_size(hdr->f, dxpl_id, hdr, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL, 0, heap_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to get fractal heap storage info for indirect block")
+
+ /* Check for B-tree storage of huge objects in fractal heap */
+ if(H5F_addr_defined(hdr->huge_bt2_addr)) {
+ /* Open the huge object index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(hdr->f, dxpl_id, hdr->huge_bt2_addr, hdr->f)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for tracking 'huge' objects")
+
+ /* Get the B-tree storage */
+ if(H5B2_size(bt2, dxpl_id, heap_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
+ } /* end if */
+
+ /* Get storage for free-space tracking info */
+ if(H5F_addr_defined(hdr->fs_addr)) {
+ if(H5HF_space_size(hdr, dxpl_id, &meta_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve FS meta storage info")
+ *heap_size += meta_size;
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for tracking 'huge' objects")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_size() */
+
diff --git a/src/H5HFtest.c b/src/H5HFtest.c
new file mode 100644
index 0000000..1b1f688
--- /dev/null
+++ b/src/H5HFtest.c
@@ -0,0 +1,551 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, February 3, 2006
+ *
+ * Purpose: Fractal heap testing functions.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+#define H5HF_TESTING /*suppress warning about H5HF testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_cparam_test
+ *
+ * Purpose: Retrieve the parameters used to create the fractal heap
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_cparam_test(const H5HF_t *fh, H5HF_create_t *cparam)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(cparam);
+
+ /* Get fractal heap creation parameters */
+ if(fh->hdr->id_len == (unsigned)(1 + fh->hdr->heap_off_size + fh->hdr->heap_len_size))
+ cparam->id_len = 0;
+ else if(fh->hdr->id_len == (unsigned)(1 + fh->hdr->sizeof_size + fh->hdr->sizeof_addr))
+ cparam->id_len = 1;
+ else
+ H5_CHECKED_ASSIGN(cparam->id_len, uint16_t, fh->hdr->id_len, unsigned);
+ cparam->max_man_size = fh->hdr->max_man_size;
+ HDmemcpy(&(cparam->managed), &(fh->hdr->man_dtable.cparam), sizeof(H5HF_dtable_cparam_t));
+ H5O_msg_copy(H5O_PLINE_ID, &(fh->hdr->pline), &(cparam->pline));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_get_cparam_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_cmp_cparam_test
+ *
+ * Purpose: Compare the parameters used to create the fractal heap
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5HF_cmp_cparam_test(const H5HF_create_t *cparam1, const H5HF_create_t *cparam2)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(cparam1);
+ HDassert(cparam2);
+
+ /* Compare doubling table parameters */
+ if(cparam1->managed.width < cparam2->managed.width)
+ HGOTO_DONE(-1)
+ else if(cparam1->managed.width > cparam2->managed.width)
+ HGOTO_DONE(1)
+ if(cparam1->managed.start_block_size < cparam2->managed.start_block_size)
+ HGOTO_DONE(-1)
+ else if(cparam1->managed.start_block_size > cparam2->managed.start_block_size)
+ HGOTO_DONE(1)
+ if(cparam1->managed.max_direct_size < cparam2->managed.max_direct_size)
+ HGOTO_DONE(-1)
+ else if(cparam1->managed.max_direct_size > cparam2->managed.max_direct_size)
+ HGOTO_DONE(1)
+ if(cparam1->managed.max_index < cparam2->managed.max_index)
+ HGOTO_DONE(-1)
+ else if(cparam1->managed.max_index > cparam2->managed.max_index)
+ HGOTO_DONE(1)
+ if(cparam1->managed.start_root_rows < cparam2->managed.start_root_rows)
+ HGOTO_DONE(-1)
+ else if(cparam1->managed.start_root_rows > cparam2->managed.start_root_rows)
+ HGOTO_DONE(1)
+
+ /* Compare other general parameters for heap */
+ if(cparam1->max_man_size < cparam2->max_man_size)
+ HGOTO_DONE(-1)
+ else if(cparam1->max_man_size > cparam2->max_man_size)
+ HGOTO_DONE(1)
+ if(cparam1->id_len < cparam2->id_len)
+ HGOTO_DONE(-1)
+ else if(cparam1->id_len > cparam2->id_len)
+ HGOTO_DONE(1)
+
+ /* Compare "important" parameters for any I/O pipeline filters */
+ if(cparam1->pline.nused < cparam2->pline.nused)
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.nused > cparam2->pline.nused)
+ HGOTO_DONE(1)
+ else {
+ size_t u, v; /* Local index variables */
+
+ /* Compare each filter */
+ for(u = 0; u < cparam1->pline.nused; u++) {
+ /* Check filter ID */
+ if(cparam1->pline.filter[u].id < cparam2->pline.filter[u].id)
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.filter[u].id > cparam2->pline.filter[u].id)
+ HGOTO_DONE(1)
+
+ /* Check filter flags */
+ if(cparam1->pline.filter[u].flags < cparam2->pline.filter[u].flags)
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.filter[u].flags > cparam2->pline.filter[u].flags)
+ HGOTO_DONE(1)
+
+/* Don't worry about comparing the filter names right now... */
+/* (they are expanded during the encode/decode process, but aren't copied
+ * during the H5Z_append operation, generating false positive failures)
+ */
+#ifdef QAK
+ /* Check filter name */
+HDfprintf(stderr, "%s: Check 1.0\n", "H5HF_cmp_cparam_test");
+HDfprintf(stderr, "%s: cparam1->pline.filter[%Zu].name = %s\n", "H5HF_cmp_cparam_test", u, (cparam1->pline.filter[u].name ? cparam1->pline.filter[u].name : "<nil>"));
+HDfprintf(stderr, "%s: cparam2->pline.filter[%Zu].name = %s\n", "H5HF_cmp_cparam_test", u, (cparam2->pline.filter[u].name ? cparam2->pline.filter[u].name : "<nil>"));
+ if(!cparam1->pline.filter[u].name && cparam2->pline.filter[u].name)
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.filter[u].name && !cparam2->pline.filter[u].name)
+ HGOTO_DONE(1)
+ else if(cparam1->pline.filter[u].name && cparam2->pline.filter[u].name) {
+ if((ret_value = HDstrcmp(cparam1->pline.filter[u].name, cparam2->pline.filter[u].name)))
+ HGOTO_DONE(ret_value)
+ } /* end if */
+#endif /* QAK */
+
+ /* Check # of filter parameters */
+ if(cparam1->pline.filter[u].cd_nelmts < cparam2->pline.filter[u].cd_nelmts)
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.filter[u].cd_nelmts > cparam2->pline.filter[u].cd_nelmts)
+ HGOTO_DONE(1)
+
+ /* Check filter parameters */
+ for(v = 0; v < cparam1->pline.filter[u].cd_nelmts; v++) {
+ if(cparam1->pline.filter[u].cd_values[v] < cparam2->pline.filter[u].cd_values[v])
+ HGOTO_DONE(-1)
+ else if(cparam1->pline.filter[u].cd_values[v] > cparam2->pline.filter[u].cd_values[v])
+ HGOTO_DONE(1)
+ } /* end for */
+
+ } /* end for */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_cmp_cparam_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_max_root_rows
+ *
+ * Purpose: Retrieve the max. # of rows in the root indirect block
+ *
+ * Return: Success: Max. # of rows in root indirect block
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 22, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_get_max_root_rows(const H5HF_t *fh)
+{
+ unsigned ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+
+ /* Return max. # of rows in root indirect block */
+ ret_value = fh->hdr->man_dtable.max_root_rows;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_max_root_rows() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_dtable_width_test
+ *
+ * Purpose: Retrieve the width of the doubling table for a heap
+ *
+ * Return: Success: Width of the doubling table
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 22, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_get_dtable_width_test(const H5HF_t *fh)
+{
+ unsigned ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+
+ /* Return width of doubling table */
+ ret_value = fh->hdr->man_dtable.cparam.width;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_dtable_width_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_dtable_max_drows_test
+ *
+ * Purpose: Retrieve the max. # of direct block rows in any indirect block
+ *
+ * Return: Success: Max. # of direct block rows
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 22, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_get_dtable_max_drows_test(const H5HF_t *fh)
+{
+ unsigned ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+
+ /* Return max. # of direct blocks in any indirect block */
+ ret_value = fh->hdr->man_dtable.max_direct_rows;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_dtable_max_drows_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_iblock_max_drows_test
+ *
+ * Purpose: Retrieve the max. # of direct block rows in an indirect block
+ *
+ * Note: POS is indexed from 1 and is only really working for the
+ * 2nd-level indirect blocks (i.e. indirect blocks with
+ * only direct block children)
+ *
+ * Return: Success: Max. # of direct block rows
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 22, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5HF_get_iblock_max_drows_test(const H5HF_t *fh, unsigned pos)
+{
+ unsigned ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(pos);
+
+ /* Return max. # of direct blocks in this indirect block row */
+ ret_value = pos + (fh->hdr->man_dtable.max_direct_bits -
+ fh->hdr->man_dtable.first_row_bits) + 1;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_iblock_max_drows_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_dblock_size_test
+ *
+ * Purpose: Retrieve the size of a direct block for a given row
+ *
+ * Return: Success: Size of direct block
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5HF_get_dblock_size_test(const H5HF_t *fh, unsigned row)
+{
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+
+ /* Return direct block free space */
+ ret_value = fh->hdr->man_dtable.row_block_size[row];
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_dblock_size_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_dblock_free_test
+ *
+ * Purpose: Retrieve the size of direct block free space for a given
+ * direct or indirect block size
+ *
+ * Return: Success: Size of direct block free space
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5HF_get_dblock_free_test(const H5HF_t *fh, unsigned row)
+{
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+
+ /* Return direct block free space */
+ ret_value = fh->hdr->man_dtable.row_tot_dblock_free[row];
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HF_get_dblock_free_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_id_off_test
+ *
+ * Purpose: Retrieve the offset for a [managed] heap ID
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, May 15, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_id_off_test(const H5HF_t *fh, const void *_id, hsize_t *obj_off)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(fh->hdr);
+ HDassert(id);
+ HDassert(obj_off);
+
+ /* Get the offset for a 'normal' heap ID */
+ id++;
+ UINT64DECODE_VAR(id, *obj_off, fh->hdr->heap_off_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_get_id_off_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_id_type_test
+ *
+ * Purpose: Retrieve the type of a heap ID
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_id_type_test(const void *_id, unsigned char *obj_type)
+{
+ const uint8_t *id = (const uint8_t *)_id; /* Object ID */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(id);
+ HDassert(obj_type);
+
+ /* Get the type for a heap ID */
+ *obj_type = *id & H5HF_ID_TYPE_MASK;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_get_id_type_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_tiny_info_test
+ *
+ * Purpose: Retrieve information about tiny object's ID length
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_tiny_info_test(const H5HF_t *fh, size_t *max_len,
+ hbool_t *len_extended)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(fh->hdr);
+ HDassert(max_len);
+ HDassert(len_extended);
+
+ /* Retrieve information about tiny object's ID encoding in a heap */
+ *max_len = fh->hdr->tiny_max_len;
+ *len_extended = fh->hdr->tiny_len_extended;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_get_tiny_info_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_get_huge_info_test
+ *
+ * Purpose: Retrieve information about huge object's ID length
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_get_huge_info_test(const H5HF_t *fh, hsize_t *next_id, hbool_t *ids_direct)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(fh);
+ HDassert(fh->hdr);
+ HDassert(ids_direct);
+
+ /* Retrieve information about tiny object's ID encoding in a heap */
+ if(next_id)
+ *next_id = fh->hdr->huge_next_id;
+ *ids_direct = fh->hdr->huge_ids_direct;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5HF_get_huge_info_test() */
+
diff --git a/src/H5HFtiny.c b/src/H5HFtiny.c
new file mode 100644
index 0000000..79462e9
--- /dev/null
+++ b/src/H5HFtiny.c
@@ -0,0 +1,404 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFtiny.c
+ * Aug 14 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Routines for "tiny" objects in fractal heap
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HFmodule.h" /* This source code file is part of the H5HF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Tiny object length information */
+#define H5HF_TINY_LEN_SHORT 16 /* Max. length able to be encoded in first heap ID byte */
+#define H5HF_TINY_MASK_SHORT 0x0F /* Mask for length in first heap ID byte */
+#define H5HF_TINY_MASK_EXT 0x0FFF /* Mask for length in two heap ID bytes */
+#define H5HF_TINY_MASK_EXT_1 0x0F00 /* Mask for length in first byte of two heap ID bytes */
+#define H5HF_TINY_MASK_EXT_2 0x00FF /* Mask for length in second byte of two heap ID bytes */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5HF_tiny_op_real(H5HF_hdr_t *hdr, const uint8_t *id,
+ H5HF_operator_t op, void *op_data);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_init
+ *
+ * Purpose: Initialize information for tracking 'tiny' objects
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_init(H5HF_hdr_t *hdr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Compute information about 'tiny' objects for the heap */
+
+ /* Check if tiny objects need an extra byte for their length */
+ /* (account for boundary condition when length of an object would need an
+ * extra byte, but using that byte means that the extra length byte is
+ * unneccessary)
+ */
+ if((hdr->id_len - 1) <= H5HF_TINY_LEN_SHORT) {
+ hdr->tiny_max_len = hdr->id_len - 1;
+ hdr->tiny_len_extended = FALSE;
+ } /* end if */
+ else if((hdr->id_len - 1) == (H5HF_TINY_LEN_SHORT + 1)) {
+ hdr->tiny_max_len = H5HF_TINY_LEN_SHORT;
+ hdr->tiny_len_extended = FALSE;
+ } /* end if */
+ else {
+ hdr->tiny_max_len = hdr->id_len - 2;
+ hdr->tiny_len_extended = TRUE;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_tiny_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_insert
+ *
+ * Purpose: Pack a 'tiny' object in a heap ID
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_insert(H5HF_hdr_t *hdr, size_t obj_size, const void *obj, void *_id)
+{
+ uint8_t *id = (uint8_t *)_id; /* Pointer to ID buffer */
+ size_t enc_obj_size; /* Encoded object size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+#ifdef QAK
+HDfprintf(stderr, "%s: obj_size = %Zu\n", FUNC, obj_size);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(obj_size <= hdr->tiny_max_len);
+ HDassert(obj_size <= (H5HF_TINY_MASK_EXT + 1));
+ HDassert(obj);
+ HDassert(id);
+
+ /* Adjust object's size for encoding it */
+ enc_obj_size = obj_size - 1;
+
+ /* Encode object into ID */
+ if(!hdr->tiny_len_extended) {
+ *id++ = (uint8_t)(H5HF_ID_VERS_CURR | H5HF_ID_TYPE_TINY |
+ (enc_obj_size & H5HF_TINY_MASK_SHORT));
+ } /* end if */
+ else {
+ *id++ = (uint8_t)(H5HF_ID_VERS_CURR | H5HF_ID_TYPE_TINY |
+ ((enc_obj_size & H5HF_TINY_MASK_EXT_1) >> 8));
+ *id++ = enc_obj_size & H5HF_TINY_MASK_EXT_2;
+ } /* end else */
+
+ HDmemcpy(id, obj, obj_size);
+ HDmemset(id + obj_size, 0, (hdr->id_len - ((size_t)1 + (size_t)hdr->tiny_len_extended + obj_size)));
+
+ /* Update statistics about heap */
+ hdr->tiny_size += obj_size;
+ hdr->tiny_nobjs++;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_tiny_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_get_obj_len
+ *
+ * Purpose: Get the size of a 'tiny' object in a fractal heap
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id, size_t *obj_len_p)
+{
+ size_t enc_obj_size; /* Encoded object size */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj_len_p);
+
+ /* Check if 'tiny' object ID is in extended form, and retrieve encoded size */
+ if(!hdr->tiny_len_extended)
+ enc_obj_size = *id & H5HF_TINY_MASK_SHORT;
+ else
+ /* (performed in this odd way to avoid compiler bug on tg-login3 with
+ * gcc 3.2.2 - QAK)
+ */
+ enc_obj_size = (size_t)*(id + 1) | ((size_t)(*id & H5HF_TINY_MASK_EXT_1) << 8);
+
+ /* Set the object's length */
+ *obj_len_p = enc_obj_size + 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HF_tiny_get_obj_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_op_real
+ *
+ * Purpose: Internal routine to perform operation on 'tiny' object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HF_tiny_op_real(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op,
+ void *op_data)
+{
+ size_t enc_obj_size; /* Encoded object size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(op);
+
+ /* Get the object's encoded length */
+ /* H5HF_tiny_obj_len can't fail */
+ ret_value = H5HF_tiny_get_obj_len(hdr, id, &enc_obj_size);
+
+ /* Advance past flag byte(s) */
+ if(!hdr->tiny_len_extended)
+ id++;
+ else {
+ /* (performed in two steps to avoid compiler bug on tg-login3 with
+ * gcc 3.2.2 - QAK)
+ */
+ id++; id++;
+ }
+
+ /* Call the user's 'op' callback */
+ if(op(id, enc_obj_size, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "application's callback failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_tiny_op_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_read
+ *
+ * Purpose: Read a 'tiny' object from the heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_read(H5HF_hdr_t *hdr, const uint8_t *id, void *obj)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(obj);
+
+ /* Call the internal 'op' routine */
+ if(H5HF_tiny_op_real(hdr, id, H5HF_op_read, obj) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_tiny_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_op
+ *
+ * Purpose: Operate directly on a 'tiny' object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sept 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_op(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op,
+ void *op_data)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+ HDassert(op);
+
+ /* Call the internal 'op' routine routine */
+ if(H5HF_tiny_op_real(hdr, id, op, op_data) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_tiny_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_tiny_remove
+ *
+ * Purpose: Remove a 'tiny' object from the heap statistics
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Aug 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_tiny_remove(H5HF_hdr_t *hdr, const uint8_t *id)
+{
+ size_t enc_obj_size; /* Encoded object size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(id);
+
+ /* Get the object's encoded length */
+ /* H5HF_tiny_obj_len can't fail */
+ ret_value = H5HF_tiny_get_obj_len(hdr, id, &enc_obj_size);
+
+ /* Update statistics about heap */
+ hdr->tiny_size -= enc_obj_size;
+ hdr->tiny_nobjs--;
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_tiny_remove() */
diff --git a/src/H5HG.c b/src/H5HG.c
new file mode 100644
index 0000000..893be80
--- /dev/null
+++ b/src/H5HG.c
@@ -0,0 +1,894 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, March 27, 1998
+ *
+ * Purpose: Operations on the global heap. The global heap is the set of
+ * all collections and each collection contains one or more
+ * global heap objects. An object belongs to exactly one
+ * collection. A collection is treated as an atomic entity for
+ * the purposes of I/O and caching.
+ *
+ * Each file has a small cache of global heap collections called
+ * the CWFS list and recently accessed collections with free
+ * space appear on this list. As collections are accessed the
+ * collection is moved toward the front of the list. New
+ * collections are added to the front of the list while old
+ * collections are added to the end of the list.
+ *
+ * The collection model reduces the overhead which would be
+ * incurred if the global heap were a single object, and the
+ * CWFS list allows the library to cheaply choose a collection
+ * for a new object based on object size, amount of free space
+ * in the collection, and temporal locality.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HGmodule.h" /* This source code file is part of the H5HG module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HGpkg.h" /* Global heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/*
+ * The maximum number of links allowed to a global heap object.
+ */
+#define H5HG_MAXLINK 65535
+
+/*
+ * The maximum number of indices allowed in a global heap object.
+ */
+#define H5HG_MAXIDX 65535
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static haddr_t H5HG_create(H5F_t *f, hid_t dxpl_id, size_t size);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the H5HG_heap_t struct */
+H5FL_DEFINE(H5HG_heap_t);
+
+/* Declare a free list to manage sequences of H5HG_obj_t's */
+H5FL_SEQ_DEFINE(H5HG_obj_t);
+
+/* Declare a PQ free list to manage heap chunks */
+H5FL_BLK_DEFINE(gheap_chunk);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_create
+ *
+ * Purpose: Creates a global heap collection of the specified size. If
+ * SIZE is less than some minimum it will be readjusted. The
+ * new collection is allocated in the file and added to the
+ * beginning of the CWFS list.
+ *
+ * Return: Success: Ptr to a cached heap. The pointer is valid
+ * only until some other hdf5 library function
+ * is called.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, March 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5HG_create(H5F_t *f, hid_t dxpl_id, size_t size)
+{
+ H5HG_heap_t *heap = NULL;
+ uint8_t *p = NULL;
+ haddr_t addr = HADDR_UNDEF;
+ size_t n;
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, HADDR_UNDEF)
+
+ /* Check args */
+ HDassert(f);
+ if(size < H5HG_MINSIZE)
+ size = H5HG_MINSIZE;
+ size = H5HG_ALIGN(size);
+
+ /* Create it */
+ H5_CHECK_OVERFLOW(size, size_t, hsize_t);
+ if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_GHEAP, dxpl_id, (hsize_t)size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to allocate file space for global heap")
+ if(NULL == (heap = H5FL_CALLOC(H5HG_heap_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
+ heap->addr = addr;
+ heap->size = size;
+ heap->shared = H5F_SHARED(f);
+
+ if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
+ HDmemset(heap->chunk, 0, size);
+ heap->nalloc = H5HG_NOBJS(f, size);
+ heap->nused = 1; /* account for index 0, which is used for the free object */
+ if(NULL == (heap->obj = H5FL_SEQ_MALLOC(H5HG_obj_t, heap->nalloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
+
+ /* Initialize the header */
+ HDmemcpy(heap->chunk, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ p = heap->chunk + H5_SIZEOF_MAGIC;
+ *p++ = H5HG_VERSION;
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ H5F_ENCODE_LENGTH(f, p, size);
+
+ /*
+ * Padding so free space object is aligned. If malloc returned memory
+ * which was always at least H5HG_ALIGNMENT aligned then we could just
+ * align the pointer, but this might not be the case.
+ */
+ n = (size_t)H5HG_ALIGN(p - heap->chunk) - (size_t)(p - heap->chunk);
+#ifdef OLD_WAY
+/* Don't bother zeroing out the rest of the info in the heap -QAK */
+ HDmemset(p, 0, n);
+#endif /* OLD_WAY */
+ p += n;
+
+ /* The freespace object */
+ heap->obj[0].size = size - H5HG_SIZEOF_HDR(f);
+ HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+ heap->obj[0].nrefs = 0;
+ heap->obj[0].begin = p;
+ UINT16ENCODE(p, 0); /*object ID*/
+ UINT16ENCODE(p, 0); /*reference count*/
+ UINT32ENCODE(p, 0); /*reserved*/
+ H5F_ENCODE_LENGTH(f, p, heap->obj[0].size);
+#ifdef OLD_WAY
+/* Don't bother zeroing out the rest of the info in the heap -QAK */
+ HDmemset (p, 0, (size_t)((heap->chunk+heap->size) - p));
+#endif /* OLD_WAY */
+
+ /* Add this heap to the beginning of the CWFS list */
+ if(H5F_cwfs_add(f, heap) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to add global heap collection to file's CWFS")
+
+ /* Add the heap to the cache */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_GHEAP, addr, heap, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to cache global heap collection")
+
+ ret_value = addr;
+
+done:
+ /* Cleanup on error */
+ if(!H5F_addr_defined(ret_value)) {
+ if(H5F_addr_defined(addr)) {
+ /* Release the space on disk */
+ if(H5MF_xfree(f, H5FD_MEM_GHEAP, dxpl_id, addr, (hsize_t)size) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, HADDR_UNDEF, "unable to free global heap")
+
+ /* Check if the heap object was allocated */
+ if(heap)
+ /* Destroy the heap object */
+ if(H5HG_free(heap) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, HADDR_UNDEF, "unable to destroy global heap collection")
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF);
+} /* H5HG_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_protect
+ *
+ * Purpose: Convenience wrapper around H5AC_protect on an indirect block
+ *
+ * Return: Pointer to indirect block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 5, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+H5HG_heap_t *
+H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)
+{
+ H5HG_heap_t *heap; /* Global heap */
+ H5HG_heap_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* only H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Lock the heap into memory */
+ if(NULL == (heap = (H5HG_heap_t *)H5AC_protect(f, dxpl_id, H5AC_GHEAP, addr, f, flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap")
+
+ /* Set the heap's address */
+ heap->addr = addr;
+
+ /* Set the return value */
+ ret_value = heap;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HG_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_alloc
+ *
+ * Purpose: Given a heap with enough free space, this function will split
+ * the free space to make a new empty heap object and initialize
+ * the header. SIZE is the exact size of the object data to be
+ * stored. It will be increased to make room for the object
+ * header and then rounded up for alignment.
+ *
+ * Return: Success: The heap object ID of the new object.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Friday, March 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5HG_alloc(H5F_t *f, H5HG_heap_t *heap, size_t size, unsigned *heap_flags_ptr)
+{
+ size_t idx;
+ uint8_t *p;
+ size_t need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(size);
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(heap->obj[0].size>=need);
+ HDassert(heap_flags_ptr);
+
+ /*
+ * Find an ID for the new object. ID zero is reserved for the free space
+ * object.
+ */
+ if(heap->nused <= H5HG_MAXIDX)
+ idx = heap->nused++;
+ else {
+ for(idx = 1; idx < heap->nused; idx++)
+ if(NULL == heap->obj[idx].begin)
+ break;
+ } /* end else */
+
+ HDassert(idx < heap->nused);
+
+ /* Check if we need more room to store heap objects */
+ if(idx >= heap->nalloc) {
+ size_t new_alloc; /* New allocation number */
+ H5HG_obj_t *new_obj; /* New array of object descriptions */
+
+ /* Determine the new number of objects to index */
+ /* nalloc is *not* guaranteed to be a power of 2! - NAF 10/26/09 */
+ new_alloc = MIN(MAX(heap->nalloc * 2, (idx + 1)), (H5HG_MAXIDX + 1));
+ HDassert(idx < new_alloc);
+
+ /* Reallocate array of objects */
+ if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, 0, "memory allocation failed")
+
+ /* Clear newly allocated space */
+ HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0]));
+
+ /* Update heap information */
+ heap->nalloc = new_alloc;
+ heap->obj = new_obj;
+ HDassert(heap->nalloc > heap->nused);
+ } /* end if */
+
+ /* Initialize the new object */
+ heap->obj[idx].nrefs = 0;
+ heap->obj[idx].size = size;
+ heap->obj[idx].begin = heap->obj[0].begin;
+ p = heap->obj[idx].begin;
+ UINT16ENCODE(p, idx);
+ UINT16ENCODE(p, 0); /*nrefs*/
+ UINT32ENCODE(p, 0); /*reserved*/
+ H5F_ENCODE_LENGTH (f, p, size);
+
+ /* Fix the free space object */
+ if(need == heap->obj[0].size) {
+ /*
+ * All free space has been exhausted from this collection.
+ */
+ heap->obj[0].size = 0;
+ heap->obj[0].begin = NULL;
+ } /* end if */
+ else if(heap->obj[0].size-need >= H5HG_SIZEOF_OBJHDR (f)) {
+ /*
+ * Some free space remains and it's larger than a heap object header,
+ * so write the new free heap object header to the heap.
+ */
+ heap->obj[0].size -= need;
+ heap->obj[0].begin += need;
+ p = heap->obj[0].begin;
+ UINT16ENCODE(p, 0); /*id*/
+ UINT16ENCODE(p, 0); /*nrefs*/
+ UINT32ENCODE(p, 0); /*reserved*/
+ H5F_ENCODE_LENGTH (f, p, heap->obj[0].size);
+ HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+ } /* end else-if */
+ else {
+ /*
+ * Some free space remains but it's smaller than a heap object header,
+ * so we don't write the header.
+ */
+ heap->obj[0].size -= need;
+ heap->obj[0].begin += need;
+ HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+ }
+
+ /* Mark the heap as dirty */
+ *heap_flags_ptr |= H5AC__DIRTIED_FLAG;
+
+ /* Set the return value */
+ ret_value = idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HG_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_extend
+ *
+ * Purpose: Extend a heap to hold an object of SIZE bytes.
+ * SIZE is the exact size of the object data to be
+ * stored. It will be increased to make room for the object
+ * header and then rounded up for alignment.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, June 12, 2004
+ *
+ * Modifications:
+ *
+ * John Mainzer, 6/8/05
+ * Modified the function to use the new dirtied parameter of
+ * of H5AC_unprotect() instead of modifying the is_dirty
+ * field of the cache info.
+ *
+ * In this case, that required adding the new heap_dirtied_ptr
+ * parameter to the function's argument list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_extend(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t need)
+{
+ H5HG_heap_t *heap = NULL; /* Pointer to heap to extend */
+ unsigned heap_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting heap */
+ size_t old_size; /* Previous size of the heap's chunk */
+ uint8_t *new_chunk; /* Pointer to new chunk information */
+ uint8_t *p; /* Pointer to raw heap info */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Protect the heap */
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
+
+ /* Re-allocate the heap information in memory */
+ if(NULL == (new_chunk = H5FL_BLK_REALLOC(gheap_chunk, heap->chunk, (heap->size + need))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "new heap allocation failed")
+ HDmemset(new_chunk + heap->size, 0, need);
+
+ /* Adjust the size of the heap */
+ old_size = heap->size;
+ heap->size += need;
+
+ /* Encode the new size of the heap */
+ p = new_chunk + H5_SIZEOF_MAGIC + 1 /* version */ + 3 /* reserved */;
+ H5F_ENCODE_LENGTH(f, p, heap->size);
+
+ /* Move the pointers to the existing objects to their new locations */
+ for(u = 0; u < heap->nused; u++)
+ if(heap->obj[u].begin)
+ heap->obj[u].begin = new_chunk + (heap->obj[u].begin - heap->chunk);
+
+ /* Update the heap chunk pointer now */
+ heap->chunk = new_chunk;
+
+ /* Update the free space information for the heap */
+ heap->obj[0].size += need;
+ if(heap->obj[0].begin == NULL)
+ heap->obj[0].begin = heap->chunk+old_size;
+ p = heap->obj[0].begin;
+ UINT16ENCODE(p, 0); /*id*/
+ UINT16ENCODE(p, 0); /*nrefs*/
+ UINT32ENCODE(p, 0); /*reserved*/
+ H5F_ENCODE_LENGTH(f, p, heap->obj[0].size);
+ HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+
+ /* Resize the heap in the cache */
+ if(H5AC_resize_entry(heap, heap->size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize global heap in cache")
+
+ /* Mark the heap as dirty */
+ heap_flags |= H5AC__DIRTIED_FLAG;
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, heap->addr, heap, heap_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to unprotect heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HG_extend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_insert
+ *
+ * Purpose: A new object is inserted into the global heap. It will be
+ * placed in the first collection on the CWFS list which has
+ * enough free space and that collection will be advanced one
+ * position in the list. If no collection on the CWFS list has
+ * enough space then a new collection will be created.
+ *
+ * It is legal to push a zero-byte object onto the heap to get
+ * the reference count features of heap objects.
+ *
+ * Return: Success: Non-negative, and a heap object handle returned
+ * through the HOBJ pointer.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, March 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_insert(H5F_t *f, hid_t dxpl_id, size_t size, void *obj, H5HG_t *hobj/*out*/)
+{
+ size_t need; /*total space needed for object */
+ size_t idx;
+ haddr_t addr; /* Address of heap to add object within */
+ H5HG_heap_t *heap = NULL;
+ unsigned heap_flags = H5AC__NO_FLAGS_SET;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(0 == size || obj);
+ HDassert(hobj);
+
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Find a large enough collection on the CWFS list */
+ need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(size);
+
+ /* Look for a heap in the file's CWFS that has enough space for the object */
+ addr = HADDR_UNDEF;
+ if(H5F_cwfs_find_free_heap(f, dxpl_id, need, &addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "error trying to locate heap")
+
+ /*
+ * If we didn't find any collection with enough free space then allocate a
+ * new collection large enough for the message plus the collection header.
+ */
+ if(!H5F_addr_defined(addr)) {
+ addr = H5HG_create(f, dxpl_id, need + H5HG_SIZEOF_HDR(f));
+
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to allocate a global heap collection")
+ } /* end if */
+ HDassert(H5F_addr_defined(addr));
+
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
+
+ /* Split the free space to make room for the new object */
+ if(0 == (idx = H5HG_alloc(f, heap, size, &heap_flags)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "unable to allocate global heap object")
+
+ /* Copy data into the heap */
+ if(size > 0) {
+ HDmemcpy(heap->obj[idx].begin + H5HG_SIZEOF_OBJHDR(f), obj, size);
+#ifdef OLD_WAY
+/* Don't bother zeroing out the rest of the info in the heap -QAK */
+ HDmemset(heap->obj[idx].begin + H5HG_SIZEOF_OBJHDR(f) + size, 0,
+ need - (H5HG_SIZEOF_OBJHDR(f) + size));
+#endif /* OLD_WAY */
+ } /* end if */
+ heap_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Return value */
+ hobj->addr = heap->addr;
+ hobj->idx = idx;
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, heap->addr, heap, heap_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to unprotect heap.")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5HG_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_read
+ *
+ * Purpose: Reads the specified global heap object into the buffer OBJECT
+ * supplied by the caller. If the caller doesn't supply a
+ * buffer then one will be allocated. The buffer should be
+ * large enough to hold the result.
+ *
+ * Return: Success: The buffer containing the result.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5HG_read(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj, void *object/*out*/,
+ size_t *buf_size)
+{
+ H5HG_heap_t *heap = NULL; /* Pointer to global heap object */
+ size_t size; /* Size of the heap object */
+ uint8_t *p; /* Pointer to object in heap buffer */
+ void *orig_object = object; /* Keep a copy of the original object pointer */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, NULL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(hobj);
+
+ /* Load the heap */
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap")
+
+ HDassert(hobj->idx < heap->nused);
+ HDassert(heap->obj[hobj->idx].begin);
+ size = heap->obj[hobj->idx].size;
+ p = heap->obj[hobj->idx].begin + H5HG_SIZEOF_OBJHDR(f);
+
+ /* Allocate a buffer for the object read in, if the user didn't give one */
+ if(!object && NULL == (object = H5MM_malloc(size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(object, p, size);
+
+ /*
+ * Advance the heap in the CWFS list. We might have done this already
+ * with the H5AC_protect(), but it won't hurt to do it twice.
+ */
+ if(heap->obj[0].begin) {
+ if(H5F_cwfs_advance_heap(f, heap, FALSE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, NULL, "can't adjust file's CWFS")
+ } /* end if */
+
+ /* If the caller would like to know the heap object's size, set that */
+ if(buf_size)
+ *buf_size = size;
+
+ /* Set return value */
+ ret_value = object;
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, hobj->addr, heap, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ if(NULL == ret_value && NULL == orig_object && object)
+ H5MM_free(object);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5HG_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_link
+ *
+ * Purpose: Adjusts the link count for a global heap object by adding
+ * ADJUST to the current value. This function will fail if the
+ * new link count would overflow. Nothing special happens when
+ * the link count reaches zero; in order for a heap object to be
+ * removed one must call H5HG_remove().
+ *
+ * Return: Success: Number of links present after the adjustment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5HG_link(H5F_t *f, hid_t dxpl_id, const H5HG_t *hobj, int adjust)
+{
+ H5HG_heap_t *heap = NULL;
+ unsigned heap_flags = H5AC__NO_FLAGS_SET;
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(hobj);
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Load the heap */
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
+
+ if(adjust != 0) {
+ HDassert(hobj->idx < heap->nused);
+ HDassert(heap->obj[hobj->idx].begin);
+ if((heap->obj[hobj->idx].nrefs + adjust) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "new link count would be out of range")
+ if((heap->obj[hobj->idx].nrefs + adjust) > H5HG_MAXLINK)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "new link count would be out of range")
+ heap->obj[hobj->idx].nrefs += adjust;
+ heap_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = heap->obj[hobj->idx].nrefs;
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, hobj->addr, heap, heap_flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5HG_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_get_obj_size
+ *
+ * Purpose: Returns the size of a global heap object.
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, February 12, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_get_obj_size(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj, size_t *obj_size)
+{
+ H5HG_heap_t *heap = NULL; /* Pointer to global heap object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(hobj);
+ HDassert(obj_size);
+
+ /* Load the heap */
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
+
+ HDassert(hobj->idx < heap->nused);
+ HDassert(heap->obj[hobj->idx].begin);
+
+ /* Set object size */
+ *obj_size = heap->obj[hobj->idx].size;
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, hobj->addr, heap, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5HG_get_obj_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_remove
+ *
+ * Purpose: Removes the specified object from the global heap.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 30, 1998
+ *
+ * Modifications:
+ *
+ * John Mainzer - 6/8/05
+ * Modified function to use the dirtied parameter of
+ * H5AC_unprotect() instead of modifying the is_dirty
+ * field of the cache info.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_remove (H5F_t *f, hid_t dxpl_id, H5HG_t *hobj)
+{
+ H5HG_heap_t *heap = NULL;
+ uint8_t *p = NULL, *obj_start = NULL;
+ size_t need;
+ unsigned u;
+ unsigned flags = H5AC__NO_FLAGS_SET;/* Whether the heap gets deleted */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__GLOBALHEAP_TAG, FAIL);
+
+ /* Check args */
+ HDassert(f);
+ HDassert(hobj);
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Load the heap */
+ if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
+
+ HDassert(hobj->idx < heap->nused);
+ HDassert(heap->obj[hobj->idx].begin);
+ obj_start = heap->obj[hobj->idx].begin;
+ /* Include object header size */
+ need = H5HG_ALIGN(heap->obj[hobj->idx].size) + H5HG_SIZEOF_OBJHDR(f);
+
+ /* Move the new free space to the end of the heap */
+ for(u = 0; u < heap->nused; u++)
+ if(heap->obj[u].begin > heap->obj[hobj->idx].begin)
+ heap->obj[u].begin -= need;
+ if(NULL == heap->obj[0].begin) {
+ heap->obj[0].begin = heap->chunk + (heap->size - need);
+ heap->obj[0].size = need;
+ heap->obj[0].nrefs = 0;
+ } /* end if */
+ else
+ heap->obj[0].size += need;
+ HDmemmove(obj_start, obj_start + need,
+ heap->size - (size_t)((obj_start + need) - heap->chunk));
+ if(heap->obj[0].size >= H5HG_SIZEOF_OBJHDR(f)) {
+ p = heap->obj[0].begin;
+ UINT16ENCODE(p, 0); /*id*/
+ UINT16ENCODE(p, 0); /*nrefs*/
+ UINT32ENCODE(p, 0); /*reserved*/
+ H5F_ENCODE_LENGTH (f, p, heap->obj[0].size);
+ } /* end if */
+ HDmemset(heap->obj + hobj->idx, 0, sizeof(H5HG_obj_t));
+ flags |= H5AC__DIRTIED_FLAG;
+
+ if((heap->obj[0].size + H5HG_SIZEOF_HDR(f)) == heap->size) {
+ /*
+ * The collection is empty. Remove it from the CWFS list and return it
+ * to the file free list.
+ */
+ flags |= H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; /* Indicate that the object was deleted, for the unprotect call */
+ } /* end if */
+ else {
+ /*
+ * If the heap is in the CWFS list then advance it one position. The
+ * H5AC_protect() might have done that too, but that's okay. If the
+ * heap isn't on the CWFS list then add it to the end.
+ */
+ if(H5F_cwfs_advance_heap(f, heap, TRUE) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "can't adjust file's CWFS")
+ } /* end else */
+
+done:
+ if(heap && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, hobj->addr, heap, flags) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL);
+} /* end H5HG_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_free
+ *
+ * Purpose: Destroys a global heap collection in memory
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 15, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_free(H5HG_heap_t *heap)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ HDassert(heap);
+
+ /* Remove the heap from the CWFS list */
+ if(H5F_cwfs_remove_heap(heap->shared, heap) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove heap from file's CWFS")
+
+ if(heap->chunk)
+ heap->chunk = H5FL_BLK_FREE(gheap_chunk, heap->chunk);
+ if(heap->obj)
+ heap->obj = H5FL_SEQ_FREE(H5HG_obj_t, heap->obj);
+ heap = H5FL_FREE(H5HG_heap_t, heap);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5HG_free() */
+
diff --git a/src/H5HGcache.c b/src/H5HGcache.c
new file mode 100644
index 0000000..50b2669
--- /dev/null
+++ b/src/H5HGcache.c
@@ -0,0 +1,494 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HGcache.c
+ * Feb 5 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement global heap metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HGmodule.h" /* This source code file is part of the H5HG module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HGpkg.h" /* Global heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+static herr_t H5HG__cache_heap_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5HG__cache_heap_get_final_load_size(const void *_image,
+ size_t image_len, void *udata, size_t *actual_len);
+static void *H5HG__cache_heap_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HG__cache_heap_image_len(const void *thing, size_t *image_len);
+static herr_t H5HG__cache_heap_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HG__cache_heap_free_icr(void *thing);
+
+/* Prefix deserialization */
+static herr_t H5HG__hdr_deserialize(H5HG_heap_t *heap, const uint8_t *image,
+ const H5F_t *f);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5HG inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_GHEAP[1] = {{
+ H5AC_GHEAP_ID, /* Metadata client ID */
+ "global heap", /* Metadata client name (for debugging) */
+ H5FD_MEM_GHEAP, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5HG__cache_heap_get_initial_load_size, /* 'get_initial_load_size' callback */
+ H5HG__cache_heap_get_final_load_size, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5HG__cache_heap_deserialize, /* 'deserialize' callback */
+ H5HG__cache_heap_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5HG__cache_heap_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5HG__cache_heap_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__hdr_deserialize()
+ *
+ * Purpose: Decode a global heap's header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * December 15, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__hdr_deserialize(H5HG_heap_t *heap, const uint8_t *image, const H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(heap);
+ HDassert(image);
+ HDassert(f);
+
+ /* Magic number */
+ if(HDmemcmp(image, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad global heap collection signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(H5HG_VERSION != *image++)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong version number in global heap")
+
+ /* Reserved */
+ image += 3;
+
+ /* Size */
+ H5F_DECODE_LENGTH(f, image, heap->size);
+ HDassert(heap->size >= H5HG_MINSIZE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HG__hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_get_initial_load_size()
+ *
+ * Purpose: Return the initial speculative read size to the metadata
+ * cache. This size will be used in the initial attempt to read
+ * the global heap. If this read is too small, the cache will
+ * try again with the correct value obtained from
+ * H5HG__cache_get_final_load_size().
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__cache_heap_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = (size_t)H5HG_MINSIZE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HG__cache_heap_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_get_initial_load_size()
+ *
+ * Purpose: Return the final read size for a speculatively ready heap to
+ * the metadata cache.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__cache_heap_get_final_load_size(const void *image, size_t image_len,
+ void *udata, size_t *actual_len)
+{
+ H5HG_heap_t heap; /* Global heap */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+ HDassert(image_len == H5HG_MINSIZE);
+
+ /* Deserialize the heap's header */
+ if(H5HG__hdr_deserialize(&heap, (const uint8_t *)image, (const H5F_t *)udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, FAIL, "can't decode global heap prefix")
+
+ /* Set the final size for the cache image */
+ *actual_len = heap.size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HG__cache_heap_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of the global
+ * heap, deserialize it, load its contents into a newly allocated
+ * instance of H5HG_heap_t, and return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */
+ H5HG_heap_t *heap = NULL; /* New global heap */
+ uint8_t *image; /* Pointer to image to decode */
+ size_t max_idx = 0; /* Maximum heap object index seen */
+ size_t nalloc; /* Number of objects allocated */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(_image);
+ HDassert(len >= (size_t)H5HG_MINSIZE);
+ HDassert(f);
+ HDassert(dirty);
+
+ /* Allocate a new global heap */
+ if(NULL == (heap = H5FL_CALLOC(H5HG_heap_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ heap->shared = H5F_SHARED(f);
+ if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the image buffer into the newly allocate chunk */
+ HDmemcpy(heap->chunk, _image, len);
+
+ /* Deserialize the heap's header */
+ if(H5HG__hdr_deserialize(heap, (const uint8_t *)heap->chunk, f) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode global heap header")
+
+ /* Decode each object */
+ image = heap->chunk + H5HG_SIZEOF_HDR(f);
+ nalloc = H5HG_NOBJS(f, heap->size);
+
+ /* Calloc the obj array because the file format spec makes no guarantee
+ * about the order of the objects, and unused slots must be set to zero.
+ */
+ if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ heap->nalloc = nalloc;
+
+ while(image < (heap->chunk + heap->size)) {
+ if((image + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) {
+ /*
+ * The last bit of space is too tiny for an object header, so
+ * we assume that it's free space.
+ */
+ HDassert(NULL == heap->obj[0].begin);
+ heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image);
+ heap->obj[0].begin = image;
+ image += heap->obj[0].size;
+ } /* end if */
+ else {
+ size_t need;
+ unsigned idx;
+ uint8_t *begin = image;
+
+ UINT16DECODE(image, idx);
+
+ /* Check if we need more room to store heap objects */
+ if(idx >= heap->nalloc) {
+ size_t new_alloc; /* New allocation number */
+ H5HG_obj_t *new_obj; /* New array of object descriptions */
+
+ /* Determine the new number of objects to index */
+ new_alloc = MAX(heap->nalloc * 2, (idx + 1));
+ HDassert(idx < new_alloc);
+
+ /* Reallocate array of objects */
+ if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear newly allocated space */
+ HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0]));
+
+ /* Update heap information */
+ heap->nalloc = new_alloc;
+ heap->obj = new_obj;
+ HDassert(heap->nalloc > heap->nused);
+ } /* end if */
+
+ UINT16DECODE(image, heap->obj[idx].nrefs);
+ image += 4; /*reserved*/
+ H5F_DECODE_LENGTH(f, image, heap->obj[idx].size);
+ heap->obj[idx].begin = begin;
+
+ /*
+ * The total storage size includes the size of the object
+ * header and is zero padded so the next object header is
+ * properly aligned. The entire obj array was calloc'ed,
+ * so no need to zero the space here. The last bit of space
+ * is the free space object whose size is never padded and
+ * already includes the object header.
+ */
+ if(idx > 0) {
+ need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size);
+ if(idx > max_idx)
+ max_idx = idx;
+ } /* end if */
+ else
+ need = heap->obj[idx].size;
+
+ image = begin + need;
+ } /* end else */
+ } /* end while */
+
+ /* Sanity checks */
+ HDassert(image == heap->chunk + heap->size);
+ HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+
+ /* Set the next index value to use */
+ if(max_idx > 0)
+ heap->nused = max_idx + 1;
+ else
+ heap->nused = 1;
+
+ /* Sanity check */
+ HDassert(max_idx < heap->nused);
+
+ /* Add the new heap to the CWFS list for the file */
+ if(H5F_cwfs_add(f, heap) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS")
+
+ ret_value = heap;
+
+done:
+ if(!ret_value && heap)
+ if(H5HG_free(heap) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy global heap collection")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HG__cache_heap_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_image_len
+ *
+ * Purpose: Return the on disk image size of the global heap to the
+ * metadata cache via the image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__cache_heap_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HG_heap_t *heap = (const H5HG_heap_t *)_thing;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(heap);
+ HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(heap->cache_info.type == H5AC_GHEAP);
+ HDassert(heap->size >= H5HG_MINSIZE);
+ HDassert(image_len);
+
+ *image_len = heap->size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HG__cache_heap_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_serialize
+ *
+ * Purpose: Given an appropriately sized buffer and an instance of
+ * H5HG_heap_t, serialize the global heap for writing to file,
+ * and copy the serialized verion into the buffer.
+ *
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__cache_heap_serialize(const H5F_t *f, void *image, size_t len,
+ void *_thing)
+{
+ H5HG_heap_t *heap = (H5HG_heap_t *)_thing;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(f);
+ HDassert(image);
+ HDassert(heap);
+ HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(heap->cache_info.type == H5AC_GHEAP);
+ HDassert(heap->size == len);
+ HDassert(heap->chunk);
+
+ /* copy the image into the buffer */
+ HDmemcpy(image, heap->chunk, len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HG__cache_heap_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG__cache_heap_free_icr
+ *
+ * Purpose: Free the in memory representation of the supplied global heap.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/27/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HG__cache_heap_free_icr(void *_thing)
+{
+ H5HG_heap_t *heap = (H5HG_heap_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(heap);
+ HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(heap->cache_info.type == H5AC_GHEAP);
+
+ /* Destroy global heap collection */
+ if(H5HG_free(heap) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HG__cache_heap_free_icr() */
+
diff --git a/src/H5HGdbg.c b/src/H5HGdbg.c
new file mode 100644
index 0000000..6dd94f5
--- /dev/null
+++ b/src/H5HGdbg.c
@@ -0,0 +1,177 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Wednesday, July 9, 2003
+ *
+ * Purpose: Global Heap object debugging functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HGmodule.h" /* This source code file is part of the H5HG module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HGpkg.h" /* Global heaps */
+#include "H5Iprivate.h" /* ID Functions */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_debug
+ *
+ * Purpose: Prints debugging information about a global heap collection.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Mar 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HG_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth)
+{
+ unsigned u, nused, maxobj;
+ unsigned j, k;
+ H5HG_heap_t *h = NULL;
+ uint8_t *p = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined (addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ if(NULL == (h = H5HG_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap collection");
+
+ HDfprintf(stream, "%*sGlobal Heap Collection...\n", indent, "");
+ HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Dirty:",
+ (int)(h->cache_info.is_dirty));
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Total collection size in file:",
+ (unsigned long)(h->size));
+
+ for(u = 1, nused = 0, maxobj = 0; u < h->nused; u++)
+ if(h->obj[u].begin) {
+ nused++;
+ if (u>maxobj)
+ maxobj = u;
+ }
+ HDfprintf(stream, "%*s%-*s %u/%lu/", indent, "", fwidth,
+ "Objects defined/allocated/max:",
+ nused,
+ (unsigned long)h->nalloc);
+ if(nused)
+ HDfprintf(stream, "%u\n", maxobj);
+ else
+ HDfprintf(stream, "NA\n");
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Free space:",
+ (unsigned long)(h->obj[0].size));
+
+ for(u = 1; u < h->nused; u++)
+ if(h->obj[u].begin) {
+ char buf[64];
+
+ HDsnprintf(buf, sizeof(buf), "Object %u", u);
+ HDfprintf(stream, "%*s%s\n", indent, "", buf);
+ HDfprintf(stream, "%*s%-*s %lu\n", indent + 3, "", MIN(fwidth - 3, 0),
+ "Obffset in block:",
+ (unsigned long)(h->obj[u].begin - h->chunk));
+ HDfprintf(stream, "%*s%-*s %d\n", indent + 3, "", MIN(fwidth - 3, 0),
+ "Reference count:",
+ h->obj[u].nrefs);
+ HDfprintf(stream, "%*s%-*s %lu/%lu\n", indent + 3, "",
+ MIN(fwidth - 3, 0),
+ "Size of object body:",
+ (unsigned long)(h->obj[u].size),
+ (unsigned long)H5HG_ALIGN(h->obj[u].size));
+ p = h->obj[u].begin + H5HG_SIZEOF_OBJHDR(f);
+ for(j = 0; j < h->obj[u].size; j += 16) {
+ HDfprintf(stream, "%*s%04u: ", indent + 6, "", j);
+ for(k = 0; k < 16; k++) {
+ if(8 == k)
+ HDfprintf(stream, " ");
+ if(j + k < h->obj[u].size)
+ HDfprintf(stream, "%02x ", p[j + k]);
+ else
+ HDfputs(" ", stream);
+ }
+ for(k = 0; k < 16 && j + k < h->obj[u].size; k++) {
+ if(8 == k)
+ HDfprintf(stream, " ");
+ HDfputc(p[j + k]>' ' && p[j + k] <= '~' ? p[j + k] : '.', stream);
+ }
+ HDfprintf(stream, "\n");
+ }
+ }
+
+done:
+ if (h && H5AC_unprotect(f, dxpl_id, H5AC_GHEAP, addr, h, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release object header");
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HG_debug() */
+
diff --git a/src/H5HGmodule.h b/src/H5HGmodule.h
new file mode 100644
index 0000000..1c68206
--- /dev/null
+++ b/src/H5HGmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5HG package. Including this header means that the source file
+ * is part of the H5HG package.
+ */
+#ifndef _H5HGmodule_H
+#define _H5HGmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5HG_MODULE
+#define H5_MY_PKG H5HG
+#define H5_MY_PKG_ERR H5E_HEAP
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5HGmodule_H */
+
diff --git a/src/H5HGpkg.h b/src/H5HGpkg.h
new file mode 100644
index 0000000..47760bf
--- /dev/null
+++ b/src/H5HGpkg.h
@@ -0,0 +1,144 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Wednesday, July 9, 2003
+ *
+ * Purpose: This file contains declarations which are visible
+ * only within the H5HG package. Source files outside the
+ * H5HG package should include H5HGprivate.h instead.
+ */
+#if !(defined H5HG_FRIEND || defined H5HG_MODULE)
+#error "Do not include this file outside the H5HG package!"
+#endif
+
+#ifndef _H5HGpkg_H
+#define _H5HGpkg_H
+
+/* Get package's private header */
+#include "H5HGprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free lists */
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage the H5HG_t struct */
+H5FL_EXTERN(H5HG_heap_t);
+
+/* Declare extern the free list to manage sequences of H5HG_obj_t's */
+H5FL_SEQ_EXTERN(H5HG_obj_t);
+
+/* Declare extern the PQ free list to manage heap chunks */
+H5FL_BLK_EXTERN(gheap_chunk);
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/*
+ * Global heap collection version.
+ */
+#define H5HG_VERSION 1
+
+/*
+ * All global heap collections are at least this big. This allows us to read
+ * most collections with a single read() since we don't have to read a few
+ * bytes of header to figure out the size. If the heap is larger than this
+ * then a second read gets the rest after we've decoded the header.
+ */
+#define H5HG_MINSIZE 4096
+
+/*
+ * Pad all global heap messages to a multiple of eight bytes so we can load
+ * the entire collection into memory and operate on it there. Eight should
+ * be sufficient for machines that have alignment constraints because our
+ * largest data type is eight bytes.
+ */
+#define H5HG_ALIGNMENT 8
+#define H5HG_ALIGN(X) (H5HG_ALIGNMENT*(((X)+H5HG_ALIGNMENT-1)/H5HG_ALIGNMENT))
+#define H5HG_ISALIGNED(X) ((X)==H5HG_ALIGN(X))
+
+/*
+ * The size of the collection header, always a multiple of the alignment so
+ * that the stuff that follows the header is aligned.
+ */
+#define H5HG_SIZEOF_HDR(f) \
+ (size_t)H5HG_ALIGN(4 + /*magic number */ \
+ 1 + /*version number */ \
+ 3 + /*reserved */ \
+ H5F_SIZEOF_SIZE(f)) /*collection size */
+
+/*
+ * The overhead associated with each object in the heap, always a multiple of
+ * the alignment so that the stuff that follows the header is aligned.
+ */
+#define H5HG_SIZEOF_OBJHDR(f) \
+ (size_t)H5HG_ALIGN(2 + /*object id number */ \
+ 2 + /*reference count */ \
+ 4 + /*reserved */ \
+ H5F_SIZEOF_SIZE(f)) /*object data size */
+
+/*
+ * The initial guess for the number of messages in a collection. We assume
+ * that all objects in that collection are zero length, giving the maximum
+ * possible number of objects in the collection. The collection itself has
+ * some overhead and each message has some overhead. The `+2' accounts for
+ * rounding and for the free space object.
+ */
+#define H5HG_NOBJS(f,z) ((((z)-H5HG_SIZEOF_HDR(f))/ \
+ H5HG_SIZEOF_OBJHDR(f)+2))
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+typedef struct H5HG_obj_t {
+ int nrefs; /* reference count */
+ size_t size; /* total size of object */
+ uint8_t *begin; /* ptr to object into heap->chunk */
+} H5HG_obj_t;
+
+/* Forward declarations for fields */
+struct H5F_file_t;
+
+struct H5HG_heap_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions, _must_ be */
+ /* first field in structure */
+ haddr_t addr; /*collection address */
+ size_t size; /*total size of collection */
+ uint8_t *chunk; /*the collection, incl. header */
+ size_t nalloc; /*numb object slots allocated */
+ size_t nused; /*number of slots used */
+ /* If this value is >65535 then all indices */
+ /* have been used at some time and the */
+ /* correct new index should be searched for */
+ struct H5F_file_t *shared; /* shared file */
+ H5HG_obj_t *obj; /*array of object descriptions */
+};
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+H5_DLL herr_t H5HG_free(H5HG_heap_t *heap);
+H5_DLL H5HG_heap_t *H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags);
+
+#endif /* _H5HGpkg_H */
+
diff --git a/src/H5HGprivate.h b/src/H5HGprivate.h
new file mode 100644
index 0000000..19dcaa4
--- /dev/null
+++ b/src/H5HGprivate.h
@@ -0,0 +1,77 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, March 27, 1998
+ */
+#ifndef _H5HGprivate_H
+#define _H5HGprivate_H
+
+/* Include package's public header */
+#include "H5HGpublic.h"
+
+/* Private headers needed by this file. */
+#include "H5Fprivate.h" /* File access */
+
+/* Information to locate object in global heap */
+typedef struct H5HG_t {
+ haddr_t addr; /*address of collection */
+ size_t idx; /*object ID within collection */
+} H5HG_t;
+
+/* Typedef for heap in memory (defined in H5HGpkg.h) */
+typedef struct H5HG_heap_t H5HG_heap_t;
+
+
+/*
+ * Limit global heap collections to the some reasonable size. This is
+ * fairly arbitrary, but needs to be small enough that no more than H5HG_MAXIDX
+ * objects will be allocated from a single heap.
+ */
+#define H5HG_MAXSIZE 65536
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5HG_MODULE
+#define H5HG_ADDR(H) ((H)->addr)
+#define H5HG_SIZE(H) ((H)->size)
+#define H5HG_FREE_SIZE(H) ((H)->obj[0].size)
+#else /* H5HG_MODULE */
+#define H5HG_ADDR(H) (H5HG_get_addr(H))
+#define H5HG_SIZE(H) (H5HG_get_size(H))
+#define H5HG_FREE_SIZE(H) (H5HG_get_free_size(H))
+#endif /* H5HG_MODULE */
+
+
+/* Main global heap routines */
+H5_DLL herr_t H5HG_insert(H5F_t *f, hid_t dxpl_id, size_t size, void *obj,
+ H5HG_t *hobj/*out*/);
+H5_DLL void *H5HG_read(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj, void *object, size_t *buf_size/*out*/);
+H5_DLL int H5HG_link(H5F_t *f, hid_t dxpl_id, const H5HG_t *hobj, int adjust);
+H5_DLL herr_t H5HG_get_obj_size(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj, size_t *obj_size);
+H5_DLL herr_t H5HG_remove(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj);
+
+/* Support routines */
+H5_DLL herr_t H5HG_extend(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t need);
+
+/* Query routines */
+H5_DLL haddr_t H5HG_get_addr(const H5HG_heap_t *h);
+H5_DLL size_t H5HG_get_size(const H5HG_heap_t *h);
+H5_DLL size_t H5HG_get_free_size(const H5HG_heap_t *h);
+
+/* Debugging functions */
+H5_DLL herr_t H5HG_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent,
+ int fwidth);
+
+#endif /* _H5HGprivate_H */
+
diff --git a/src/H5HGpublic.h b/src/H5HGpublic.h
new file mode 100644
index 0000000..fcec593
--- /dev/null
+++ b/src/H5HGpublic.h
@@ -0,0 +1,31 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, March 27, 1998
+ */
+#ifndef _H5HGpublic_H
+#define _H5HGpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/H5HGquery.c b/src/H5HGquery.c
new file mode 100644
index 0000000..35abc2e
--- /dev/null
+++ b/src/H5HGquery.c
@@ -0,0 +1,143 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Wednesday, July 20, 2011
+ *
+ * Purpose: Query routines for global heaps.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HGmodule.h" /* This source code file is part of the H5HG module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HGpkg.h" /* Global heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_get_addr
+ *
+ * Purpose: Query the address of a global heap object.
+ *
+ * Return: Address of heap on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5HG_get_addr(const H5HG_heap_t *heap)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(heap);
+
+ FUNC_LEAVE_NOAPI(heap->addr)
+} /* H5HG_get_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_get_size
+ *
+ * Purpose: Query the size of a global heap object.
+ *
+ * Return: Size of heap on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5HG_get_size(const H5HG_heap_t *heap)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(heap);
+
+ FUNC_LEAVE_NOAPI(heap->size)
+} /* H5HG_get_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HG_get_free_size
+ *
+ * Purpose: Query the free size of a global heap object.
+ *
+ * Return: Free size of heap on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 20, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5HG_get_free_size(const H5HG_heap_t *heap)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(heap);
+
+ FUNC_LEAVE_NOAPI(heap->obj[0].size)
+} /* H5HG_get_free_size() */
+
diff --git a/src/H5HL.c b/src/H5HL.c
new file mode 100644
index 0000000..fa577c3
--- /dev/null
+++ b/src/H5HL.c
@@ -0,0 +1,1047 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HL.c
+ * Jul 16 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Heap functions for the local heaps used by symbol
+ * tables to store names (among other things).
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HLpkg.h" /* Local Heaps */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5HL_MIN_HEAP 128 /* Minimum size to reduce heap buffer to */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static H5HL_free_t *H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl);
+static herr_t H5HL__minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap);
+static herr_t H5HL__dirty(H5HL_t *heap);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the H5HL_free_t struct */
+H5FL_DEFINE(H5HL_free_t);
+
+/* Declare a PQ free list to manage the heap chunk information */
+H5FL_BLK_DEFINE(lheap_chunk);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_create
+ *
+ * Purpose: Creates a new heap data structure on disk and caches it
+ * in memory. SIZE_HINT is a hint for the initial size of the
+ * data area of the heap. If size hint is invalid then a
+ * reasonable (but probably not optimal) size will be chosen.
+ *
+ * Return: Success: SUCCEED. The file address of new heap is
+ * returned through the ADDR argument.
+ * Failure: FAIL. addr_p will be HADDR_UNDEF.
+ *
+ * Programmer: Robb Matzke
+ * Jul 16 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, haddr_t *addr_p/*out*/))
+
+ H5HL_t *heap = NULL; /* Heap created */
+ H5HL_prfx_t *prfx = NULL; /* Heap prefix */
+ hsize_t total_size = 0; /* Total heap size on disk */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(addr_p);
+
+ /* Adjust size hint as necessary */
+ if(size_hint && size_hint < H5HL_SIZEOF_FREE(f))
+ size_hint = H5HL_SIZEOF_FREE(f);
+ size_hint = H5HL_ALIGN(size_hint);
+
+ /* Allocate new heap structure */
+ if(NULL == (heap = H5HL__new(H5F_SIZEOF_SIZE(f), H5F_SIZEOF_ADDR(f), H5HL_SIZEOF_HDR(f))))
+ H5E_THROW(H5E_CANTALLOC, "can't allocate new heap struct");
+
+ /* Allocate file space */
+ total_size = heap->prfx_size + size_hint;
+ if(HADDR_UNDEF == (heap->prfx_addr = H5MF_alloc(f, H5FD_MEM_LHEAP, dxpl_id, total_size)))
+ H5E_THROW(H5E_CANTALLOC, "unable to allocate file memory");
+
+ /* Initialize info */
+ heap->single_cache_obj = TRUE;
+ heap->dblk_addr = heap->prfx_addr + (hsize_t)heap->prfx_size;
+ heap->dblk_size = size_hint;
+ if(size_hint)
+ if(NULL == (heap->dblk_image = H5FL_BLK_CALLOC(lheap_chunk, size_hint)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ /* free list */
+ if(size_hint) {
+ if(NULL == (heap->freelist = H5FL_MALLOC(H5HL_free_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+ heap->freelist->offset = 0;
+ heap->freelist->size = size_hint;
+ heap->freelist->prev = heap->freelist->next = NULL;
+ heap->free_block = 0;
+ } /* end if */
+ else {
+ heap->freelist = NULL;
+ heap->free_block = H5HL_FREE_NULL;
+ } /* end else */
+
+ /* Allocate the heap prefix */
+ if(NULL == (prfx = H5HL__prfx_new(heap)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ /* Add to cache */
+ if(FAIL == H5AC_insert_entry(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET))
+ H5E_THROW(H5E_CANTINIT, "unable to cache local heap prefix");
+
+ /* Set address to return */
+ *addr_p = heap->prfx_addr;
+
+CATCH
+ if(ret_value < 0) {
+ *addr_p = HADDR_UNDEF;
+ if(prfx) {
+ if(FAIL == H5HL__prfx_dest(prfx))
+ H5E_THROW(H5E_CANTFREE, "unable to destroy local heap prefix");
+ } /* end if */
+ else {
+ if(heap) {
+ if(H5F_addr_defined(heap->prfx_addr))
+ if(FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, dxpl_id, heap->prfx_addr, total_size))
+ H5E_THROW(H5E_CANTFREE, "can't release heap data?");
+ if(FAIL == H5HL__dest(heap))
+ H5E_THROW(H5E_CANTFREE, "unable to destroy local heap");
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+END_FUNC(PRIV) /* end H5HL_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__minimize_heap_space
+ *
+ * Purpose: Go through the heap's freelist and determine if we can
+ * eliminate the free blocks at the tail of the buffer.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Bill Wendling
+ * Sept. 16, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap))
+
+ size_t new_heap_size = heap->dblk_size; /* New size of heap */
+
+ /* check args */
+ HDassert(f);
+ HDassert(heap);
+
+ /*
+ * Check to see if we can reduce the size of the heap in memory by
+ * eliminating free blocks at the tail of the buffer before flushing the
+ * buffer out.
+ */
+ if(heap->freelist) {
+ H5HL_free_t *tmp_fl;
+ H5HL_free_t *last_fl = NULL;
+
+ /* Search for a free block at the end of the buffer */
+ for(tmp_fl = heap->freelist; tmp_fl; tmp_fl = tmp_fl->next)
+ /* Check if the end of this free block is at the end of the buffer */
+ if(tmp_fl->offset + tmp_fl->size == heap->dblk_size) {
+ last_fl = tmp_fl;
+ break;
+ } /* end if */
+
+ /*
+ * Found free block at the end of the buffer, decide what to do
+ * about it
+ */
+ if(last_fl) {
+ /*
+ * If the last free block's size is more than half the memory
+ * buffer size (and the memory buffer is larger than the
+ * minimum size), reduce or eliminate it.
+ */
+ if(last_fl->size >= (heap->dblk_size / 2) && heap->dblk_size > H5HL_MIN_HEAP) {
+ /*
+ * Reduce size of buffer until it's too small or would
+ * eliminate the free block
+ */
+ while(new_heap_size > H5HL_MIN_HEAP &&
+ new_heap_size >= (last_fl->offset + H5HL_SIZEOF_FREE(f)))
+ new_heap_size /= 2;
+
+ /*
+ * Check if reducing the memory buffer size would
+ * eliminate the free block
+ */
+ if(new_heap_size < (last_fl->offset + H5HL_SIZEOF_FREE(f))) {
+ /* Check if this is the only block on the free list */
+ if(last_fl->prev == NULL && last_fl->next == NULL) {
+ /* Double the new memory size */
+ new_heap_size *= 2;
+
+ /* Truncate the free block */
+ last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset);
+ new_heap_size = last_fl->offset + last_fl->size;
+ HDassert(last_fl->size >= H5HL_SIZEOF_FREE(f));
+ } /* end if */
+ else {
+ /*
+ * Set the size of the memory buffer to the start
+ * of the free list
+ */
+ new_heap_size = last_fl->offset;
+
+ /* Eliminate the free block from the list */
+ last_fl = H5HL__remove_free(heap, last_fl);
+ } /* end else */
+ } /* end if */
+ else {
+ /* Truncate the free block */
+ last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset);
+ new_heap_size = last_fl->offset + last_fl->size;
+ HDassert(last_fl->size >= H5HL_SIZEOF_FREE(f));
+ HDassert(last_fl->size == H5HL_ALIGN(last_fl->size));
+ } /* end else */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+ /*
+ * If the heap grew smaller than disk storage then move the
+ * data segment of the heap to another contiguous block of disk
+ * storage.
+ */
+ if(new_heap_size != heap->dblk_size) {
+ HDassert(new_heap_size < heap->dblk_size);
+
+ /* Resize the memory buffer */
+ if(NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, new_heap_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ /* Reallocate data block in file */
+ if(FAIL == H5HL__dblk_realloc(f, dxpl_id, heap, new_heap_size))
+ H5E_THROW(H5E_CANTRESIZE, "reallocating data block failed");
+ } /* end if */
+
+CATCH
+ /* No special processing on errors */
+
+END_FUNC(STATIC) /* H5HL__minimize_heap_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_protect
+ *
+ * Purpose: This function is a wrapper for the H5AC_protect call.
+ *
+ * Return: Success: Non-NULL pointer to the local heap prefix.
+ * Failure: NULL
+ *
+ * Programmer: Bill Wendling
+ * Sept. 17, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+H5HL_t *, NULL, NULL,
+H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags))
+
+ H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */
+ H5HL_prfx_t *prfx = NULL; /* Local heap prefix */
+ H5HL_dblk_t *dblk = NULL; /* Local heap data block */
+ H5HL_t *heap = NULL; /* Heap data structure */
+ unsigned prfx_cache_flags = H5AC__NO_FLAGS_SET; /* Cache flags for unprotecting prefix entry */
+ unsigned dblk_cache_flags = H5AC__NO_FLAGS_SET; /* Cache flags for unprotecting data block entry */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* only the H5AC__READ_ONLY_FLAG may appear in flags */
+ HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Construct the user data for protect callback */
+ prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f);
+ prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f);
+ prfx_udata.prfx_addr = addr;
+ prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f);
+
+ /* Protect the local heap prefix */
+ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix");
+
+ /* Get the pointer to the heap */
+ heap = prfx->heap;
+
+ /* Check if the heap is already pinned in memory */
+ /* (for re-entrant situation) */
+ if(heap->prots == 0) {
+ /* Check if heap has separate data block */
+ if(heap->single_cache_obj)
+ /* Set the flag for pinning the prefix when unprotecting it */
+ prfx_cache_flags |= H5AC__PIN_ENTRY_FLAG;
+ else {
+ /* Protect the local heap data block */
+ if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, flags)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block");
+
+ /* Set the flag for pinning the data block when unprotecting it */
+ dblk_cache_flags |= H5AC__PIN_ENTRY_FLAG;
+ } /* end if */
+ } /* end if */
+
+ /* Increment # of times heap is protected */
+ heap->prots++;
+
+ /* Set return value */
+ ret_value = heap;
+
+CATCH
+ /* Release the prefix from the cache, now pinned */
+ if(prfx && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, prfx_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix");
+
+ /* Release the data block from the cache, now pinned */
+ if(dblk && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, dblk_cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap data block");
+
+END_FUNC(PRIV) /* end H5HL_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_offset_into
+ *
+ * Purpose: Called directly after the call to H5HL_protect so that
+ * a pointer to the object in the heap can be obtained.
+ *
+ * Return: Success: Valid pointer.
+ * Failure: Can't fail
+ *
+ * Programmer: Bill Wendling
+ * Sept. 17, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, NOERR,
+void *, NULL, -,
+H5HL_offset_into(const H5HL_t *heap, size_t offset))
+
+ /* Sanity check */
+ HDassert(heap);
+ HDassert(offset < heap->dblk_size);
+
+ ret_value = heap->dblk_image + offset;
+
+END_FUNC(PRIV) /* end H5HL_offset_into() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_unprotect
+ *
+ * Purpose: Unprotect the data retrieved by the H5HL_protect call.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Bill Wendling
+ * Sept. 17, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_unprotect(H5HL_t *heap))
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Decrement # of times heap is protected */
+ heap->prots--;
+
+ /* Check for last unprotection of heap */
+ if(heap->prots == 0) {
+ /* Check for separate heap data block */
+ if(heap->single_cache_obj) {
+ /* Mark local heap prefix as evictable again */
+ if(FAIL == H5AC_unpin_entry(heap->prfx))
+ H5E_THROW(H5E_CANTUNPIN, "unable to unpin local heap data block");
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(heap->dblk);
+
+ /* Mark local heap data block as evictable again */
+ /* (data block still pins prefix) */
+ if(FAIL == H5AC_unpin_entry(heap->dblk))
+ H5E_THROW(H5E_CANTUNPIN, "unable to unpin local heap data block");
+ } /* end else */
+ } /* end if */
+
+CATCH
+ /* No special processing on errors */
+
+END_FUNC(PRIV) /* end H5HL_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__remove_free
+ *
+ * Purpose: Removes free list element FL from the specified heap and
+ * frees it.
+ *
+ * Return: NULL
+ *
+ * Programmer: Robb Matzke
+ * Jul 17 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, NOERR,
+H5HL_free_t *, NULL, -,
+H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl))
+
+ if(fl->prev)
+ fl->prev->next = fl->next;
+ if(fl->next)
+ fl->next->prev = fl->prev;
+
+ if(!fl->prev)
+ heap->freelist = fl->next;
+
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ ret_value = (H5HL_free_t *)H5FL_FREE(H5HL_free_t, fl);
+
+END_FUNC(STATIC) /* end H5HL__remove_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dirty
+ *
+ * Purpose: Mark heap as dirty
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(STATIC, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__dirty(H5HL_t *heap))
+
+ /* check arguments */
+ HDassert(heap);
+ HDassert(heap->prfx);
+
+ /* Mark heap data block as dirty, if there is one */
+ if(!heap->single_cache_obj) {
+ /* Sanity check */
+ HDassert(heap->dblk);
+
+ if(FAIL == H5AC_mark_entry_dirty(heap->dblk))
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap data block as dirty");
+ } /* end if */
+
+ /* Mark heap prefix as dirty */
+ if(FAIL == H5AC_mark_entry_dirty(heap->prfx))
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap prefix as dirty");
+
+CATCH
+ /* No special processing on errors */
+
+END_FUNC(STATIC) /* end H5HL__dirty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_insert
+ *
+ * Purpose: Inserts a new item into the heap.
+ *
+ * Return: Success: Offset of new item within heap.
+ * Failure: UFAIL
+ *
+ * Programmer: Robb Matzke
+ * Jul 17 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+size_t, UFAIL, UFAIL,
+H5HL_insert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t buf_size, const void *buf))
+
+ H5HL_free_t *fl = NULL, *last_fl = NULL;
+ size_t offset = 0;
+ size_t need_size;
+ hbool_t found;
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(heap);
+ HDassert(buf_size > 0);
+ HDassert(buf);
+
+ /* Mark heap as dirty in cache */
+ /* (A bit early in the process, but it's difficult to determine in the
+ * code below where to mark the heap as dirty, especially in error cases,
+ * so we just accept that an extra flush of the heap info could occur
+ * if an error occurs -QAK)
+ */
+ if(FAIL == H5HL__dirty(heap))
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap as dirty");
+
+ /*
+ * In order to keep the free list descriptors aligned on word boundaries,
+ * whatever that might mean, we round the size up to the next multiple of
+ * a word.
+ */
+ need_size = H5HL_ALIGN(buf_size);
+
+ /*
+ * Look for a free slot large enough for this object and which would
+ * leave zero or at least H5G_SIZEOF_FREE bytes left over.
+ */
+ for(fl = heap->freelist, found = FALSE; fl; fl = fl->next) {
+ if(fl->size > need_size && fl->size - need_size >= H5HL_SIZEOF_FREE(f)) {
+ /* a big enough free block was found */
+ offset = fl->offset;
+ fl->offset += need_size;
+ fl->size -= need_size;
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ found = TRUE;
+ break;
+ } else if(fl->size == need_size) {
+ /* free block of exact size found */
+ offset = fl->offset;
+ fl = H5HL__remove_free(heap, fl);
+ found = TRUE;
+ break;
+ } else if(!last_fl || last_fl->offset < fl->offset) {
+ /* track free space that's closest to end of heap */
+ last_fl = fl;
+ }
+ } /* end for */
+
+ /*
+ * If no free chunk was large enough, then allocate more space and
+ * add it to the free list. If the heap ends with a free chunk, we
+ * can extend that free chunk. Otherwise we'll have to make another
+ * free chunk. If the heap must expand, we double its size.
+ */
+ if(found == FALSE) {
+ size_t need_more; /* How much more space we need */
+ size_t new_dblk_size; /* Final size of space allocated for heap data block */
+ size_t old_dblk_size; /* Previous size of space allocated for heap data block */
+ htri_t was_extended; /* Whether the local heap's data segment on disk was extended */
+
+ /* At least double the heap's size, making certain there's enough room
+ * for the new object */
+ need_more = MAX(need_size, heap->dblk_size);
+
+ /* If there is no last free block or it's not at the end of the heap,
+ * and the amount of space to allocate is not big enough to include at
+ * least the new object and a free-list info, trim down the amount of
+ * space requested to just the amount of space needed. (Generally
+ * speaking, this only occurs when the heap is small -QAK)
+ */
+ if(!(last_fl && last_fl->offset + last_fl->size == heap->dblk_size)
+ && (need_more < (need_size + H5HL_SIZEOF_FREE(f))))
+ need_more = need_size;
+
+ new_dblk_size = heap->dblk_size + need_more;
+ HDassert(heap->dblk_size < new_dblk_size);
+ old_dblk_size = heap->dblk_size;
+ H5_CHECK_OVERFLOW(heap->dblk_size, size_t, hsize_t);
+ H5_CHECK_OVERFLOW(new_dblk_size, size_t, hsize_t);
+
+ /* Extend current heap if possible */
+ was_extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_LHEAP, heap->dblk_addr, (hsize_t)(heap->dblk_size), (hsize_t)need_more);
+ if(FAIL == was_extended)
+ H5E_THROW(H5E_CANTEXTEND, "error trying to extend heap");
+
+ /* Check if we extended the heap data block in file */
+ if(was_extended == TRUE) {
+ /* Check for prefix & data block contiguous */
+ if(heap->single_cache_obj) {
+ /* Resize prefix+data block */
+ if(FAIL == H5AC_resize_entry(heap->prfx, (size_t)(heap->prfx_size + new_dblk_size)))
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap prefix in cache");
+ } /* end if */
+ else {
+ /* Resize 'standalone' data block */
+ if(FAIL == H5AC_resize_entry(heap->dblk, (size_t)new_dblk_size))
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap data block in cache");
+ } /* end else */
+
+ /* Note new size */
+ heap->dblk_size = new_dblk_size;
+ } /* end if */
+ else { /* ...if we can't, allocate a new chunk & release the old */
+ /* Reallocate data block in file */
+ if(FAIL == H5HL__dblk_realloc(f, dxpl_id, heap, new_dblk_size))
+ H5E_THROW(H5E_CANTRESIZE, "reallocating data block failed");
+ } /* end if */
+
+ /* If the last free list in the heap is at the end of the heap, extend it */
+ if(last_fl && last_fl->offset + last_fl->size == old_dblk_size) {
+ /*
+ * Increase the size of the last free block.
+ */
+ offset = last_fl->offset;
+ last_fl->offset += need_size;
+ last_fl->size += need_more - need_size;
+ HDassert(last_fl->offset == H5HL_ALIGN(last_fl->offset));
+ HDassert(last_fl->size == H5HL_ALIGN(last_fl->size));
+
+ if (last_fl->size < H5HL_SIZEOF_FREE(f)) {
+#ifdef H5HL_DEBUG
+ if (H5DEBUG(HL) && last_fl->size) {
+ HDfprintf(H5DEBUG(HL), "H5HL: lost %lu bytes at line %d\n",
+ (unsigned long)(last_fl->size), __LINE__);
+ }
+#endif
+ last_fl = H5HL__remove_free(heap, last_fl);
+ }
+ } /* end if */
+ else {
+ /*
+ * Create a new free list element large enough that we can
+ * take some space out of it right away.
+ */
+ offset = old_dblk_size;
+ if(need_more - need_size >= H5HL_SIZEOF_FREE(f)) {
+ if(NULL == (fl = H5FL_MALLOC(H5HL_free_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+ fl->offset = old_dblk_size + need_size;
+ fl->size = need_more - need_size;
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ fl->prev = NULL;
+ fl->next = heap->freelist;
+ if(heap->freelist)
+ heap->freelist->prev = fl;
+ heap->freelist = fl;
+#ifdef H5HL_DEBUG
+ } else if (H5DEBUG(HL) && need_more > need_size) {
+ HDfprintf(H5DEBUG(HL), "H5HL_insert: lost %lu bytes at line %d\n",
+ (unsigned long)(need_more - need_size), __LINE__);
+#endif
+ }
+ } /* end else */
+
+#ifdef H5HL_DEBUG
+ if (H5DEBUG(HL)) {
+ HDfprintf(H5DEBUG(HL), "H5HL: resize mem buf from %lu to %lu bytes\n",
+ (unsigned long)(old_dblk_size),
+ (unsigned long)(old_dblk_size + need_more));
+ }
+#endif
+ if(NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, heap->dblk_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ /* Clear new section so junk doesn't appear in the file */
+ /* (Avoid clearing section which will be overwritten with newly inserted data) */
+ HDmemset(heap->dblk_image + offset + buf_size, 0, (new_dblk_size - (offset + buf_size)));
+ } /* end if */
+
+ /* Copy the data into the heap */
+ HDmemcpy(heap->dblk_image + offset, buf, buf_size);
+
+ /* Set return value */
+ ret_value = offset;
+
+CATCH
+ /* No special processing on errors */
+
+END_FUNC(PRIV) /* H5HL_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_remove
+ *
+ * Purpose: Removes an object or part of an object from the heap at
+ * address ADDR of file F. The object (or part) to remove
+ * begins at byte OFFSET from the beginning of the heap and
+ * continues for SIZE bytes.
+ *
+ * Once part of an object is removed, one must not attempt
+ * to access that part. Removing the beginning of an object
+ * results in the object OFFSET increasing by the amount
+ * truncated. Removing the end of an object results in
+ * object truncation. Removing the middle of an object results
+ * in two separate objects, one at the original offset and
+ * one at the first offset past the removed portion.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Jul 16 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_remove(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t offset, size_t size))
+
+ H5HL_free_t *fl = NULL;
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(heap);
+ HDassert(size > 0);
+ HDassert(offset == H5HL_ALIGN(offset));
+
+ size = H5HL_ALIGN(size);
+
+ HDassert(offset < heap->dblk_size);
+ HDassert(offset + size <= heap->dblk_size);
+
+ /* Mark heap as dirty in cache */
+ /* (A bit early in the process, but it's difficult to determine in the
+ * code below where to mark the heap as dirty, especially in error cases,
+ * so we just accept that an extra flush of the heap info could occur
+ * if an error occurs -QAK)
+ */
+ if(FAIL == H5HL__dirty(heap))
+ H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap as dirty");
+
+ /*
+ * Check if this chunk can be prepended or appended to an already
+ * free chunk. It might also fall between two chunks in such a way
+ * that all three chunks can be combined into one.
+ */
+ fl = heap->freelist;
+ while(fl) {
+ H5HL_free_t *fl2 = NULL;
+
+ if((offset + size) == fl->offset) {
+ fl->offset = offset;
+ fl->size += size;
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ fl2 = fl->next;
+ while(fl2) {
+ if((fl2->offset + fl2->size) == fl->offset) {
+ fl->offset = fl2->offset;
+ fl->size += fl2->size;
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ fl2 = H5HL__remove_free(heap, fl2);
+ if(((fl->offset + fl->size) == heap->dblk_size) &&
+ ((2 * fl->size) > heap->dblk_size)) {
+ if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap))
+ H5E_THROW(H5E_CANTFREE, "heap size minimization failed");
+ }
+ H5_LEAVE(SUCCEED);
+ }
+ fl2 = fl2->next;
+ }
+ if(((fl->offset + fl->size) == heap->dblk_size) &&
+ ((2 * fl->size) > heap->dblk_size)) {
+ if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap))
+ H5E_THROW(H5E_CANTFREE, "heap size minimization failed");
+ }
+ H5_LEAVE(SUCCEED);
+ } else if(fl->offset + fl->size == offset) {
+ fl->size += size;
+ fl2 = fl->next;
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ while(fl2) {
+ if(fl->offset + fl->size == fl2->offset) {
+ fl->size += fl2->size;
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ fl2 = H5HL__remove_free(heap, fl2);
+ if(((fl->offset + fl->size) == heap->dblk_size) &&
+ ((2 * fl->size) > heap->dblk_size)) {
+ if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap))
+ H5E_THROW(H5E_CANTFREE, "heap size minimization failed");
+ } /* end if */
+ H5_LEAVE(SUCCEED);
+ } /* end if */
+ fl2 = fl2->next;
+ } /* end while */
+ if(((fl->offset + fl->size) == heap->dblk_size) &&
+ ((2 * fl->size) > heap->dblk_size)) {
+ if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap))
+ H5E_THROW(H5E_CANTFREE, "heap size minimization failed");
+ } /* end if */
+ H5_LEAVE(SUCCEED);
+ } /* end if */
+ fl = fl->next;
+ } /* end while */
+
+ /*
+ * The amount which is being removed must be large enough to
+ * hold the free list data. If not, the freed chunk is forever
+ * lost.
+ */
+ if(size < H5HL_SIZEOF_FREE(f)) {
+#ifdef H5HL_DEBUG
+ if(H5DEBUG(HL)) {
+ HDfprintf(H5DEBUG(HL), "H5HL: lost %lu bytes\n", (unsigned long) size);
+ }
+#endif
+ H5_LEAVE(SUCCEED);
+ } /* end if */
+
+ /*
+ * Add an entry to the free list.
+ */
+ if(NULL == (fl = H5FL_MALLOC(H5HL_free_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+ fl->offset = offset;
+ fl->size = size;
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ HDassert(fl->size == H5HL_ALIGN(fl->size));
+ fl->prev = NULL;
+ fl->next = heap->freelist;
+ if(heap->freelist)
+ heap->freelist->prev = fl;
+ heap->freelist = fl;
+
+ if(((fl->offset + fl->size) == heap->dblk_size) &&
+ ((2 * fl->size) > heap->dblk_size)) {
+ if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap))
+ H5E_THROW(H5E_CANTFREE, "heap size minimization failed");
+ } /* end if */
+
+CATCH
+ /* No special processing on exit */
+
+END_FUNC(PRIV) /* end H5HL_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_delete
+ *
+ * Purpose: Deletes a local heap from disk, freeing disk space used.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Mar 22 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr))
+
+ H5HL_t *heap = NULL; /* Local heap to delete */
+ H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */
+ H5HL_prfx_t *prfx = NULL; /* Local heap prefix */
+ H5HL_dblk_t *dblk = NULL; /* Local heap data block */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Construct the user data for protect callback */
+ prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f);
+ prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f);
+ prfx_udata.prfx_addr = addr;
+ prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f);
+
+ /* Protect the local heap prefix */
+ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix");
+
+ /* Get the pointer to the heap */
+ heap = prfx->heap;
+
+ /* Check if heap has separate data block */
+ if(!heap->single_cache_obj)
+ /* Protect the local heap data block */
+ if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, H5AC__NO_FLAGS_SET)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block");
+
+ /* Set the flags for releasing the prefix and data block */
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+CATCH
+ /* Release the data block from the cache, now deleted */
+ if(dblk && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap data block");
+
+ /* Release the prefix from the cache, now deleted */
+ if(prfx && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, cache_flags) < 0)
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix");
+
+END_FUNC(PRIV) /* end H5HL_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_get_size
+ *
+ * Purpose: Retrieves the current size of a heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Nov 7 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_get_size(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t *size))
+
+ H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */
+ H5HL_prfx_t *prfx = NULL; /* Local heap prefix */
+ H5HL_t *heap; /* Heap data structure */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(size);
+
+ /* Construct the user data for protect callback */
+ prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f);
+ prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f);
+ prfx_udata.prfx_addr = addr;
+ prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f);
+
+ /* Protect the local heap prefix */
+ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix");
+
+ /* Get the pointer to the heap */
+ heap = prfx->heap;
+
+ /* Set the size to return */
+ *size = heap->dblk_size;
+
+CATCH
+ if(prfx && FAIL == H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET))
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix");
+
+END_FUNC(PRIV) /* end H5HL_get_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_heapsize
+ *
+ * Purpose: Compute the size in bytes of the specified instance of
+ * H5HL_t via H5HL_size()
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * June 19 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap_size))
+
+ H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */
+ H5HL_prfx_t *prfx = NULL; /* Local heap prefix */
+ H5HL_t *heap; /* Heap data structure */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(heap_size);
+
+ /* Construct the user data for protect callback */
+ prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f);
+ prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f);
+ prfx_udata.prfx_addr = addr;
+ prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f);
+
+ /* Protect the local heap prefix */
+ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix");
+
+ /* Get the pointer to the heap */
+ heap = prfx->heap;
+
+ /* Accumulate the size of the local heap */
+ *heap_size += (hsize_t)(heap->prfx_size + heap->dblk_size);
+
+CATCH
+ if(prfx && FAIL == H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET))
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix");
+
+END_FUNC(PRIV) /* end H5HL_heapsize() */
+
diff --git a/src/H5HLcache.c b/src/H5HLcache.c
new file mode 100644
index 0000000..926f787
--- /dev/null
+++ b/src/H5HLcache.c
@@ -0,0 +1,967 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLcache.c
+ * Feb 5 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement local heap metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HLpkg.h" /* Local Heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5HL_VERSION 0 /* Local heap collection version */
+
+/* Set the local heap size to speculatively read in
+ * (needs to be more than the local heap prefix size to work at all and
+ * should be larger than the default local heap size to save the
+ * extra I/O operations)
+ */
+#define H5HL_SPEC_READ_SIZE 512
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+/* Local heap prefix */
+static herr_t H5HL__cache_prefix_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5HL__cache_prefix_get_final_load_size(const void *_image,
+ size_t image_len, void *udata, size_t *actual_len);
+static void *H5HL__cache_prefix_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HL__cache_prefix_image_len(const void *thing, size_t *image_len);
+static herr_t H5HL__cache_prefix_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HL__cache_prefix_free_icr(void *thing);
+
+/* Local heap data block */
+static herr_t H5HL__cache_datablock_get_initial_load_size(void *udata, size_t *image_len);
+static void *H5HL__cache_datablock_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5HL__cache_datablock_image_len(const void *thing, size_t *image_len);
+static herr_t H5HL__cache_datablock_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5HL__cache_datablock_notify(H5C_notify_action_t action, void *_thing);
+static herr_t H5HL__cache_datablock_free_icr(void *thing);
+
+/* Header deserialization */
+static herr_t H5HL__hdr_deserialize(H5HL_t *heap, const uint8_t *image,
+ H5HL_cache_prfx_ud_t *udata);
+
+/* Free list de/serialization */
+static herr_t H5HL__fl_deserialize(H5HL_t *heap);
+static void H5HL__fl_serialize(const H5HL_t *heap);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5HL inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_LHEAP_PRFX[1] = {{
+ H5AC_LHEAP_PRFX_ID, /* Metadata client ID */
+ "local heap prefix", /* Metadata client name (for debugging) */
+ H5FD_MEM_LHEAP, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5HL__cache_prefix_get_initial_load_size, /* 'get_initial_load_size' callback */
+ H5HL__cache_prefix_get_final_load_size, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5HL__cache_prefix_deserialize, /* 'deserialize' callback */
+ H5HL__cache_prefix_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5HL__cache_prefix_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5HL__cache_prefix_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+const H5AC_class_t H5AC_LHEAP_DBLK[1] = {{
+ H5AC_LHEAP_DBLK_ID, /* Metadata client ID */
+ "local heap datablock", /* Metadata client name (for debugging) */
+ H5FD_MEM_LHEAP, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5HL__cache_datablock_get_initial_load_size,/* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ NULL, /* 'verify_chksum' callback */
+ H5HL__cache_datablock_deserialize, /* 'deserialize' callback */
+ H5HL__cache_datablock_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5HL__cache_datablock_serialize, /* 'serialize' callback */
+ H5HL__cache_datablock_notify, /* 'notify' callback */
+ H5HL__cache_datablock_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__hdr_deserialize()
+ *
+ * Purpose: Decode a local heap's header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * December 15, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__hdr_deserialize( H5HL_t *heap, const uint8_t *image,
+ H5HL_cache_prfx_ud_t *udata)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(heap);
+ HDassert(image);
+ HDassert(udata);
+
+ /* Check magic number */
+ if(HDmemcmp(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad local heap signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(H5HL_VERSION != *image++)
+ HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong version number in local heap")
+
+ /* Reserved */
+ image += 3;
+
+ /* Store the prefix's address & length */
+ heap->prfx_addr = udata->prfx_addr;
+ heap->prfx_size = udata->sizeof_prfx;
+
+ /* Heap data size */
+ H5F_DECODE_LENGTH_LEN(image, heap->dblk_size, udata->sizeof_size);
+
+ /* Free list head */
+ H5F_DECODE_LENGTH_LEN(image, heap->free_block, udata->sizeof_size);
+ if(heap->free_block != H5HL_FREE_NULL && heap->free_block >= heap->dblk_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad heap free list")
+
+ /* Heap data address */
+ H5F_addr_decode_len(udata->sizeof_addr, &image, &(heap->dblk_addr));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__fl_deserialize
+ *
+ * Purpose: Deserialize the free list for a heap data block
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__fl_deserialize(H5HL_t *heap)
+{
+ H5HL_free_t *fl = NULL, *tail = NULL; /* Heap free block nodes */
+ hsize_t free_block; /* Offset of free block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(heap);
+ HDassert(!heap->freelist);
+
+ /* Build free list */
+ free_block = heap->free_block;
+ while(H5HL_FREE_NULL != free_block) {
+ const uint8_t *image; /* Pointer into image buffer */
+
+ /* Sanity check */
+ if(free_block >= heap->dblk_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "bad heap free list")
+
+ /* Allocate & initialize free list node */
+ if(NULL == (fl = H5FL_MALLOC(H5HL_free_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ fl->offset = (size_t)free_block;
+ fl->prev = tail;
+ fl->next = NULL;
+
+ /* Decode offset of next free block */
+ image = heap->dblk_image + free_block;
+ H5F_DECODE_LENGTH_LEN(image, free_block, heap->sizeof_size);
+ if(0 == free_block)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "free block size is zero?")
+
+ /* Decode length of this free block */
+ H5F_DECODE_LENGTH_LEN(image, fl->size, heap->sizeof_size);
+ if((fl->offset + fl->size) > heap->dblk_size)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "bad heap free list")
+
+ /* Append node onto list */
+ if(tail)
+ tail->next = fl;
+ else
+ heap->freelist = fl;
+ tail = fl;
+ fl = NULL;
+ } /* end while */
+
+done:
+ if(ret_value < 0)
+ if(fl)
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ fl = H5FL_FREE(H5HL_free_t, fl);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__fl_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__fl_serialize
+ *
+ * Purpose: Serialize the free list for a heap data block
+ *
+ * Return: Nothing (void)
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5HL__fl_serialize(const H5HL_t *heap)
+{
+ H5HL_free_t *fl; /* Pointer to heap free list node */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Serialize the free list into the heap data's image */
+ for(fl = heap->freelist; fl; fl = fl->next) {
+ uint8_t *image; /* Pointer into raw data buffer */
+
+ HDassert(fl->offset == H5HL_ALIGN(fl->offset));
+ image = heap->dblk_image + fl->offset;
+
+ if(fl->next)
+ H5F_ENCODE_LENGTH_LEN(image, fl->next->offset, heap->sizeof_size)
+ else
+ H5F_ENCODE_LENGTH_LEN(image, H5HL_FREE_NULL, heap->sizeof_size)
+
+ H5F_ENCODE_LENGTH_LEN(image, fl->size, heap->sizeof_size)
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI_VOID
+
+} /* end H5HL__fl_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_get_initial_load_size()
+ *
+ * Purpose: Return the initial size of the buffer the metadata cache should
+ * load from file and pass to the deserialize routine.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_prefix_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = H5HL_SPEC_READ_SIZE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_prefix_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_get_final_load_size()
+ *
+ * Purpose: Return the final size of the buffer the metadata cache should
+ * load from file and pass to the deserialize routine.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_prefix_get_final_load_size(const void *_image, size_t image_len,
+ void *_udata, size_t *actual_len)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */
+ H5HL_t heap; /* Local heap */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+
+ /* Deserialize the heap's header */
+ if(H5HL__hdr_deserialize(&heap, (const uint8_t *)image, udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, FAIL, "can't decode local heap header")
+
+ /* Set the final size for the cache image */
+ *actual_len = heap.prfx_size;
+
+ /* Check if heap block exists */
+ if(heap.dblk_size)
+ /* Check if heap data block is contiguous with header */
+ if(H5F_addr_eq((heap.prfx_addr + heap.prfx_size), heap.dblk_addr))
+ /* Note that the heap should be a single object in the cache */
+ *actual_len += heap.dblk_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_prefix_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of the local
+ * heap prefix, deserialize it, load its contents into a newly allocated
+ * instance of H5HL_prfx_t, and return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HL__cache_prefix_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5HL_t *heap = NULL; /* Local heap */
+ H5HL_prfx_t *prfx = NULL; /* Heap prefix deserialized */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into decoding buffer */
+ H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(udata->sizeof_size > 0);
+ HDassert(udata->sizeof_addr > 0);
+ HDassert(udata->sizeof_prfx > 0);
+ HDassert(H5F_addr_defined(udata->prfx_addr));
+ HDassert(dirty);
+
+ /* Allocate space in memory for the heap */
+ if(NULL == (heap = H5HL__new(udata->sizeof_size, udata->sizeof_addr, udata->sizeof_prfx)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate local heap structure");
+
+ /* Deserialize the heap's header */
+ if(H5HL__hdr_deserialize(heap, (const uint8_t *)image, udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode local heap header")
+
+ /* Allocate the heap prefix */
+ if(NULL == (prfx = H5HL__prfx_new(heap)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate local heap prefix");
+
+ /* Check if heap block exists */
+ if(heap->dblk_size) {
+ /* Check if heap data block is contiguous with header */
+ if(H5F_addr_eq((heap->prfx_addr + heap->prfx_size), heap->dblk_addr)) {
+ /* Note that the heap should be a single object in the cache */
+ heap->single_cache_obj = TRUE;
+
+ /* Allocate space for the heap data image */
+ if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Set image to the start of the data block. This is necessary
+ * because there may be a gap between the used portion of the
+ * prefix and the data block due to alignment constraints. */
+ image = ((const uint8_t *)_image) + heap->prfx_size;
+
+ /* Copy the heap data from the speculative read buffer */
+ HDmemcpy(heap->dblk_image, image, heap->dblk_size);
+
+ /* Build free list */
+ if(H5HL__fl_deserialize(heap) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list")
+ } /* end if */
+ else
+ /* Note that the heap should _NOT_ be a single
+ * object in the cache
+ */
+ heap->single_cache_obj = FALSE;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = prfx;
+
+done:
+ /* Release the [possibly partially initialized] local heap on errors */
+ if(!ret_value) {
+ if(prfx) {
+ if(FAIL == H5HL__prfx_dest(prfx))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap prefix");
+ } /* end if */
+ else {
+ if(heap && FAIL == H5HL__dest(heap))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap");
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_prefix_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_image_len
+ *
+ * Purpose: Return the on disk image size of a local heap prefix to the
+ * metadata cache via the image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_prefix_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HL_prfx_t *prfx = (const H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(prfx);
+ HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX);
+ HDassert(image_len);
+
+ /* Set the prefix's size */
+ *image_len = prfx->heap->prfx_size;
+
+ /* If the heap is stored as a single object, add in the
+ * data block size also
+ */
+ if(prfx->heap->single_cache_obj)
+ *image_len += prfx->heap->dblk_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_prefix_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_serialize
+ *
+ * Purpose: Given a pointer to an instance of H5HL_prfx_t and an
+ * appropriately sized buffer, serialize the contents of the
+ * instance for writing to disk, and copy the serialized data
+ * into the buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_prefix_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5HL_prfx_t *prfx = (H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */
+ H5HL_t *heap; /* Pointer to the local heap */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into image buffer */
+ size_t buf_size; /* expected size of the image buffer */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(prfx);
+ HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX);
+ HDassert(H5F_addr_eq(prfx->cache_info.addr, prfx->heap->prfx_addr));
+ HDassert(prfx->heap);
+
+ /* Get the pointer to the heap */
+ heap = prfx->heap;
+ HDassert(heap);
+
+ /* Compute the buffer size */
+ buf_size = heap->prfx_size;
+ if(heap->single_cache_obj)
+ buf_size += heap->dblk_size;
+ HDassert(len == buf_size);
+
+ /* Update the free block value from the free list */
+ heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL;
+
+ /* Serialize the heap prefix */
+ HDmemcpy(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+ *image++ = H5HL_VERSION;
+ *image++ = 0; /*reserved*/
+ *image++ = 0; /*reserved*/
+ *image++ = 0; /*reserved*/
+ H5F_ENCODE_LENGTH_LEN(image, heap->dblk_size, heap->sizeof_size);
+ H5F_ENCODE_LENGTH_LEN(image, heap->free_block, heap->sizeof_size);
+ H5F_addr_encode_len(heap->sizeof_addr, &image, heap->dblk_addr);
+
+ /* Check if the local heap is a single object in cache */
+ if(heap->single_cache_obj) {
+ if((size_t)(image - (uint8_t *)_image) < heap->prfx_size) {
+ size_t gap; /* Size of gap between prefix and data block */
+
+ /* Set image to the start of the data block. This is necessary
+ * because there may be a gap between the used portion of
+ * the prefix and the data block due to alignment constraints.
+ */
+ gap = heap->prfx_size - (size_t)(image - (uint8_t *)_image);
+ HDmemset(image, 0, gap);
+ image += gap;
+ } /* end if */
+
+ /* Serialize the free list into the heap data's image */
+ H5HL__fl_serialize(heap);
+
+ /* Copy the heap data block into the cache image */
+ HDmemcpy(image, heap->dblk_image, heap->dblk_size);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) + heap->dblk_size == len);
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of local heap */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_prefix_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_prefix_free_icr
+ *
+ * Purpose: Free the supplied in core representation of a local heap
+ * prefix.
+ *
+ * Note that this function handles the partially initialize prefix
+ * from a failed speculative load attempt. See comments below for
+ * details.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_prefix_free_icr(void *_thing)
+{
+ H5HL_prfx_t *prfx = (H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(prfx);
+ HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX);
+ HDassert(H5F_addr_eq(prfx->cache_info.addr, prfx->heap->prfx_addr));
+
+ /* Destroy local heap prefix */
+ if(H5HL__prfx_dest(prfx) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't destroy local heap prefix")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_prefix_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_get_initial_load_size()
+ *
+ * Purpose: Tell the metadata cache how large a buffer to read from
+ * file when loading a datablock. In this case, we simply lookup
+ * the correct value in the user data, and return it in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_datablock_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5HL_t *heap = (H5HL_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(heap);
+ HDassert(heap->dblk_size > 0);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = heap->dblk_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_datablock_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of a local
+ * heap data block, deserialize it, load its contents into a newly allocated
+ * instance of H5HL_dblk_t, and return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5HL__cache_datablock_deserialize(const void *image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5HL_dblk_t *dblk = NULL; /* Local heap data block deserialized */
+ H5HL_t *heap = (H5HL_t *)_udata; /* User data for callback */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(heap);
+ HDassert(heap->dblk_size == len);
+ HDassert(!heap->single_cache_obj);
+ HDassert(NULL == heap->dblk);
+ HDassert(dirty);
+
+ /* Allocate space in memory for the heap data block */
+ if(NULL == (dblk = H5HL__dblk_new(heap)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed");
+
+ /* Check for heap still retaining image */
+ if(NULL == heap->dblk_image) {
+ /* Allocate space for the heap data image */
+ if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate data block image buffer");
+
+ /* copy the datablock from the read buffer */
+ HDmemcpy(heap->dblk_image, image, len);
+
+ /* Build free list */
+ if(FAIL == H5HL__fl_deserialize(heap))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list");
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dblk;
+
+done:
+ /* Release the [possibly partially initialized] local heap on errors */
+ if(!ret_value && dblk)
+ if(FAIL == H5HL__dblk_dest(dblk))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap data block");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_datablock_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_image_len
+ *
+ * Purpose: Return the size of the on disk image of the datablock.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_datablock_image_len(const void *_thing, size_t *image_len)
+{
+ const H5HL_dblk_t *dblk = (const H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(dblk);
+ HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK);
+ HDassert(dblk->heap);
+ HDassert(dblk->heap->dblk_size > 0);
+ HDassert(image_len);
+
+ *image_len = dblk->heap->dblk_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_datablock_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_serialize
+ *
+ * Purpose: Serialize the supplied datablock, and copy the serialized
+ * image into the supplied image buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_datablock_serialize(const H5F_t *f, void *image, size_t len,
+ void *_thing)
+{
+ H5HL_t *heap; /* Pointer to the local heap */
+ H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(dblk);
+ HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK);
+ HDassert(dblk->heap);
+ heap = dblk->heap;
+ HDassert(heap->dblk_size == len);
+ HDassert(!heap->single_cache_obj);
+
+ /* Update the free block value from the free list */
+ heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL;
+
+ /* Serialize the free list into the heap data's image */
+ H5HL__fl_serialize(heap);
+
+ /* Copy the heap's data block into the cache's image */
+ HDmemcpy(image, heap->dblk_image, heap->dblk_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HL__cache_datablock_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_notify
+ *
+ * Purpose: This function is used to create and destroy pinned
+ * relationships between datablocks and their prefix parent.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 19, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_datablock_notify(H5C_notify_action_t action, void *_thing)
+{
+ H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dblk);
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Sanity checks */
+ HDassert(dblk->heap);
+ HDassert(dblk->heap->prfx);
+
+ /* Pin the heap's prefix */
+ if(FAIL == H5AC_pin_protected_entry(dblk->heap->prfx))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin local heap prefix")
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Sanity checks */
+ HDassert(dblk->heap);
+ HDassert(dblk->heap->prfx);
+
+ /* Unpin the local heap prefix */
+ if(FAIL == H5AC_unpin_entry(dblk->heap->prfx))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin local heap prefix")
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_datablock_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__cache_datablock_free_icr
+ *
+ * Purpose: Free the in memory representation of the supplied local heap data block.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 6/21/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5HL__cache_datablock_free_icr(void *_thing)
+{
+ H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(dblk);
+ HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK);
+
+ /* Destroy the data block */
+ if(H5HL__dblk_dest(dblk) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap data block")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HL__cache_datablock_free_icr() */
+
diff --git a/src/H5HLdbg.c b/src/H5HLdbg.c
new file mode 100644
index 0000000..3533a39
--- /dev/null
+++ b/src/H5HLdbg.c
@@ -0,0 +1,129 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Wednesday, July 9, 2003
+ *
+ * Purpose: Local Heap object debugging functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+/***********/
+/* Headers */
+/***********/
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HLpkg.h" /* Local heaps */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL_debug
+ *
+ * Purpose: Prints debugging information about a heap.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Aug 1 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PRIV, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, int fwidth))
+
+ H5HL_t *h = NULL;
+ int free_block;
+ H5HL_free_t *freelist;
+ uint8_t *marker = NULL;
+ size_t amount_free = 0;
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ if(NULL == (h = (H5HL_t *)H5HL_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG)))
+ H5E_THROW(H5E_CANTPROTECT, "unable to load/protect local heap");
+
+ HDfprintf(stream, "%*sLocal Heap...\n", indent, "");
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Header size (in bytes):",
+ (unsigned long)h->prfx_size);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Address of heap data:",
+ h->dblk_addr);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Data bytes allocated for heap:",
+ h->dblk_size);
+
+ /*
+ * Traverse the free list and check that all free blocks fall within
+ * the heap and that no two free blocks point to the same region of
+ * the heap. */
+ if(NULL == (marker = (uint8_t *)H5MM_calloc(h->dblk_size)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ HDfprintf(stream, "%*sFree Blocks (offset, size):\n", indent, "");
+ for(free_block = 0, freelist = h->freelist; freelist; freelist = freelist->next, free_block++) {
+ char temp_str[32];
+
+ HDsnprintf(temp_str, sizeof(temp_str), "Block #%d:", free_block);
+ HDfprintf(stream, "%*s%-*s %8Zu, %8Zu\n", indent+3, "", MAX(0,fwidth-9),
+ temp_str,
+ freelist->offset, freelist->size);
+ if((freelist->offset + freelist->size) > h->dblk_size)
+ HDfprintf(stream, "***THAT FREE BLOCK IS OUT OF BOUNDS!\n");
+ else {
+ int overlap = 0;
+ size_t i;
+
+ for(i = 0; i < freelist->size; i++) {
+ if(marker[freelist->offset + i])
+ overlap++;
+ marker[freelist->offset + i] = 1;
+ } /* end for */
+ if(overlap)
+ HDfprintf(stream, "***THAT FREE BLOCK OVERLAPPED A PREVIOUS ONE!\n");
+ else
+ amount_free += freelist->size;
+ } /* end for */
+ } /* end for */
+
+ if(h->dblk_size)
+ HDfprintf(stream, "%*s%-*s %.2f%%\n", indent, "", fwidth,
+ "Percent of heap used:",
+ ((double)100.0f * (double)(h->dblk_size - amount_free) / (double)h->dblk_size));
+
+ /*
+ * Print the data in a VMS-style octal dump.
+ */
+ H5_buffer_dump(stream, indent, h->dblk_image, marker, (size_t)0, h->dblk_size);
+
+CATCH
+ if(h && FAIL == H5HL_unprotect(h))
+ H5E_THROW(H5E_CANTUNPROTECT, "unable to release/unprotect local heap");
+
+ if(marker && NULL != (marker = (uint8_t *)H5MM_xfree(marker)))
+ H5E_THROW(H5E_CANTFREE, "can't free marker buffer");
+
+END_FUNC(PRIV) /* end H5HL_debug() */
diff --git a/src/H5HLdblk.c b/src/H5HLdblk.c
new file mode 100644
index 0000000..684d7f9
--- /dev/null
+++ b/src/H5HLdblk.c
@@ -0,0 +1,274 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLdblk.c
+ * Summer 2012
+ * Dana Robinson <derobins@hdfgroup.org>
+ *
+ * Purpose: Data block routines for local heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5HLpkg.h" /* Local Heaps */
+#include "H5MFprivate.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HL_dblk_t struct */
+H5FL_DEFINE_STATIC(H5HL_dblk_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dblk_new
+ *
+ * Purpose: Create a new local heap data block object
+ *
+ * Return: Success: non-NULL pointer to new local heap data block
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5HL_dblk_t *, NULL, NULL,
+H5HL__dblk_new(H5HL_t *heap))
+
+ H5HL_dblk_t *dblk = NULL; /* New local heap data block */
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Allocate new local heap data block */
+ if(NULL == (dblk = H5FL_CALLOC(H5HL_dblk_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for local heap data block")
+
+ /* Increment ref. count on heap data structure */
+ if(FAIL == H5HL__inc_rc(heap))
+ H5E_THROW(H5E_CANTINC, "can't increment heap ref. count")
+
+ /* Link the heap & the data block */
+ dblk->heap = heap;
+ heap->dblk = dblk;
+
+ /* Set the return value */
+ ret_value = dblk;
+
+CATCH
+ /* Ensure that the data block memory is deallocated on errors */
+ if(!ret_value && dblk != NULL)
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ dblk = H5FL_FREE(H5HL_dblk_t, dblk);
+
+END_FUNC(PKG) /* end H5HL__dblk_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dblk_dest
+ *
+ * Purpose: Destroy a local heap data block object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__dblk_dest(H5HL_dblk_t *dblk))
+
+ /* check arguments */
+ HDassert(dblk);
+
+ /* Check if data block was initialized */
+ if(dblk->heap) {
+ /* Unlink data block from heap */
+ dblk->heap->dblk = NULL;
+
+ /* Decrement ref. count on heap data structure */
+ if(FAIL == H5HL__dec_rc(dblk->heap))
+ H5E_THROW(H5E_CANTDEC, "can't decrement heap ref. count")
+
+ /* Unlink heap from data block */
+ dblk->heap = NULL;
+ } /* end if */
+
+CATCH
+ /* Free local heap data block */
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ dblk = H5FL_FREE(H5HL_dblk_t, dblk);
+
+END_FUNC(PKG) /* end H5HL__dblk_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dblk_realloc
+ *
+ * Purpose: Reallocate data block for heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__dblk_realloc(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t new_heap_size))
+
+ H5HL_dblk_t *dblk; /* Local heap data block */
+ haddr_t old_addr; /* Old location of heap data block */
+ haddr_t new_addr; /* New location of heap data block */
+ size_t old_heap_size; /* Old size of heap data block */
+
+ /* check arguments */
+ HDassert(heap);
+ HDassert(new_heap_size > 0);
+
+ /* Release old space on disk */
+ old_addr = heap->dblk_addr;
+ old_heap_size = heap->dblk_size;
+ H5_CHECK_OVERFLOW(old_heap_size, size_t, hsize_t);
+ if(FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, dxpl_id, old_addr, (hsize_t)old_heap_size))
+ H5E_THROW(H5E_CANTFREE, "can't free old local heap data");
+
+ /* Allocate new space on disk */
+ H5_CHECK_OVERFLOW(new_heap_size, size_t, hsize_t);
+ if(HADDR_UNDEF == (new_addr = H5MF_alloc(f, H5FD_MEM_LHEAP, dxpl_id, (hsize_t)new_heap_size)))
+ H5E_THROW(H5E_CANTALLOC, "unable to allocate file space for local heap");
+
+ /* Update heap info*/
+ heap->dblk_addr = new_addr;
+ heap->dblk_size = new_heap_size;
+
+ /* Check if heap data block actually moved in the file */
+ if(H5F_addr_eq(old_addr, new_addr)) {
+ /* Check if heap data block is contiguous w/prefix */
+ if(heap->single_cache_obj) {
+ /* Sanity check */
+ HDassert(H5F_addr_eq(heap->prfx_addr + heap->prfx_size, old_addr));
+ HDassert(heap->prfx);
+
+ /* Resize the heap prefix in the cache */
+ if(FAIL == H5AC_resize_entry(heap->prfx, (size_t)(heap->prfx_size + new_heap_size)))
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap in cache");
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_ne(heap->prfx_addr + heap->prfx_size, old_addr));
+ HDassert(heap->dblk);
+
+ /* Resize the heap data block in the cache */
+ if(H5AC_resize_entry(heap->dblk, (size_t)new_heap_size) < 0)
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap (data block) in cache");
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check if heap data block was contiguous w/prefix previously */
+ if(heap->single_cache_obj) {
+ /* Create new heap data block */
+ if(NULL == (dblk = H5HL__dblk_new(heap)))
+ H5E_THROW(H5E_CANTALLOC, "unable to allocate local heap data block");
+
+ /* Resize current heap prefix */
+ heap->prfx_size = H5HL_SIZEOF_HDR(f);
+ if(FAIL == H5AC_resize_entry(heap->prfx, (size_t)heap->prfx_size))
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap prefix in cache");
+
+ /* Insert data block into cache (pinned) */
+ if(FAIL == H5AC_insert_entry(f, dxpl_id, H5AC_LHEAP_DBLK, new_addr, dblk, H5AC__PIN_ENTRY_FLAG))
+ H5E_THROW(H5E_CANTINIT, "unable to cache local heap data block");
+
+ dblk = NULL;
+
+ /* Reset 'single cache object' flag */
+ heap->single_cache_obj = FALSE;
+ } /* end if */
+ else {
+ /* Resize the heap data block in the cache */
+ /* (ignore [unlikely] case where heap data block ends up
+ * contiguous w/heap prefix again.
+ */
+ if(FAIL == H5AC_resize_entry(heap->dblk, (size_t)new_heap_size))
+ H5E_THROW(H5E_CANTRESIZE, "unable to resize heap data block in cache");
+
+ /* Relocate the heap data block in the cache */
+ if(FAIL == H5AC_move_entry(f, H5AC_LHEAP_DBLK, old_addr, new_addr, dxpl_id))
+ H5E_THROW(H5E_CANTMOVE, "unable to move heap data block in cache");
+
+ } /* end else */
+ } /* end else */
+
+CATCH
+ /* Restore old heap address & size on errors */
+ if(FAIL == ret_value) {
+ heap->dblk_addr = old_addr;
+ heap->dblk_size = old_heap_size;
+ } /* end if */
+
+END_FUNC(PKG) /* end H5HL__dblk_realloc() */
+
diff --git a/src/H5HLint.c b/src/H5HLint.c
new file mode 100644
index 0000000..e625f3d
--- /dev/null
+++ b/src/H5HLint.c
@@ -0,0 +1,220 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLint.c
+ * Oct 12 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Local heap internal routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5HLpkg.h" /* Local Heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HL_t struct */
+H5FL_DEFINE_STATIC(H5HL_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__new
+ *
+ * Purpose: Create a new local heap object
+ *
+ * Return: Success: non-NULL pointer to new local heap
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Jan 5 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5HL_t *, NULL, NULL,
+H5HL__new(size_t sizeof_size, size_t sizeof_addr, size_t prfx_size))
+
+ H5HL_t *heap = NULL; /* New local heap */
+
+ /* check arguments */
+ HDassert(sizeof_size > 0);
+ HDassert(sizeof_addr > 0);
+ HDassert(prfx_size > 0);
+
+ /* Allocate new local heap structure */
+ if(NULL == (heap = H5FL_CALLOC(H5HL_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed");
+
+ /* Initialize non-zero fields */
+ heap->sizeof_size = sizeof_size;
+ heap->sizeof_addr = sizeof_addr;
+ heap->prfx_size = prfx_size;
+
+ /* Set the return value */
+ ret_value = heap;
+
+CATCH
+ if(!ret_value && heap != NULL)
+ if (NULL == (heap = H5FL_FREE(H5HL_t, heap)))
+ H5E_THROW(H5E_CANTFREE, "can't free heap memory");
+
+END_FUNC(PKG) /* end H5HL__new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__inc_rc
+ *
+ * Purpose: Increment ref. count on heap
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, NOERR,
+herr_t, SUCCEED, -,
+H5HL__inc_rc(H5HL_t *heap))
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Increment heap's ref. count */
+ heap->rc++;
+
+END_FUNC(PKG) /* end H5HL__inc_rc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dec_rc
+ *
+ * Purpose: Decrement ref. count on heap
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__dec_rc(H5HL_t *heap))
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Decrement heap's ref. count */
+ heap->rc--;
+
+CATCH
+ /* Check if we should destroy the heap */
+ if(heap->rc == 0 && FAIL == H5HL__dest(heap))
+ H5E_THROW(H5E_CANTFREE, "unable to destroy local heap");
+
+END_FUNC(PKG) /* end H5HL__dec_rc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__dest
+ *
+ * Purpose: Destroys a heap in memory.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Jan 15 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__dest(H5HL_t *heap))
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Verify that node is unused */
+ HDassert(heap->prots == 0);
+ HDassert(heap->rc == 0);
+ HDassert(heap->prfx == NULL);
+ HDassert(heap->dblk == NULL);
+
+CATCH
+ if(heap->dblk_image)
+ if(NULL != (heap->dblk_image = H5FL_BLK_FREE(lheap_chunk, heap->dblk_image)))
+ H5E_THROW(H5E_CANTFREE, "unable to free local heap data block image");
+ while(heap->freelist) {
+ H5HL_free_t *fl;
+
+ fl = heap->freelist;
+ heap->freelist = fl->next;
+ if(NULL != (fl = H5FL_FREE(H5HL_free_t, fl)))
+ H5E_THROW(H5E_CANTFREE, "unable to free local heap free list");
+ } /* end while */
+
+ if(NULL != (heap = H5FL_FREE(H5HL_t, heap)))
+ H5E_THROW(H5E_CANTFREE, "unable to free local heap");
+
+END_FUNC(PKG) /* end H5HL__dest() */
diff --git a/src/H5HLmodule.h b/src/H5HLmodule.h
new file mode 100644
index 0000000..b0fd750
--- /dev/null
+++ b/src/H5HLmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5HL package. Including this header means that the source file
+ * is part of the H5HL package.
+ */
+#ifndef _H5HLmodule_H
+#define _H5HLmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5HL_MODULE
+#define H5_MY_PKG H5HL
+#define H5_MY_PKG_ERR H5E_HEAP
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5HLmodule_H */
+
diff --git a/src/H5HLpkg.h b/src/H5HLpkg.h
new file mode 100644
index 0000000..770b7c0
--- /dev/null
+++ b/src/H5HLpkg.h
@@ -0,0 +1,152 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Wednesday, July 9, 2003
+ *
+ * Purpose: This file contains declarations which are visible
+ * only within the H5HL package. Source files outside the
+ * H5HL package should include H5HLprivate.h instead.
+ */
+#if !(defined H5HL_FRIEND || defined H5HL_MODULE)
+#error "Do not include this file outside the H5HL package!"
+#endif
+
+#ifndef _H5HLpkg_H
+#define _H5HLpkg_H
+
+/* Get package's private header */
+#include "H5HLprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5FLprivate.h" /* Free lists */
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage the H5HL_free_t struct */
+H5FL_EXTERN(H5HL_free_t);
+
+/* Declare extern the PQ free list to manage the heap chunk information */
+H5FL_BLK_EXTERN(lheap_chunk);
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* If this package header is being included in one of the H5HL source files,
+ * define the proper control macros for the generic FUNC_ENTER/LEAVE and
+ * error reporting macros.
+ */
+#ifdef H5HL_PACKAGE
+#define H5_MY_PKG H5HL
+#define H5_MY_PKG_ERR H5E_HEAP
+#define H5_MY_PKG_INIT NO
+#endif /* H5HL_PACKAGE */
+
+#define H5HL_SIZEOF_HDR(F) \
+ H5HL_ALIGN(H5_SIZEOF_MAGIC + /* heap signature */ \
+ 1 + /* version */ \
+ 3 + /* reserved */ \
+ H5F_SIZEOF_SIZE(F) + /* data size */ \
+ H5F_SIZEOF_SIZE(F) + /* free list head */ \
+ H5F_SIZEOF_ADDR(F)) /* data address */
+
+/* Value indicating end of free list on disk */
+#define H5HL_FREE_NULL 1
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+typedef struct H5HL_free_t {
+ size_t offset; /* offset of free block */
+ size_t size; /* size of free block */
+ struct H5HL_free_t *prev; /* previous entry in free list */
+ struct H5HL_free_t *next; /* next entry in free list */
+} H5HL_free_t;
+
+/* Forward declarations */
+typedef struct H5HL_dblk_t H5HL_dblk_t;
+typedef struct H5HL_prfx_t H5HL_prfx_t;
+
+struct H5HL_t {
+ /* General heap-management fields */
+ size_t rc; /* Ref. count for prefix & data block using this struct */
+ size_t prots; /* # of times the heap has been protected */
+ size_t sizeof_size; /* Size of file sizes */
+ size_t sizeof_addr; /* Size of file addresses */
+ hbool_t single_cache_obj; /* Indicate if the heap is a single object in the cache */
+ H5HL_free_t *freelist; /* the free list */
+
+ /* Prefix-specific fields */
+ H5HL_prfx_t *prfx; /* The prefix object for the heap */
+ haddr_t prfx_addr; /* address of heap prefix */
+ size_t prfx_size; /* size of heap prefix */
+ hsize_t free_block; /* Address of first free block */
+
+ /* Data block-specific fields */
+ H5HL_dblk_t *dblk; /* The data block object for the heap */
+ haddr_t dblk_addr; /* address of data block */
+ size_t dblk_size; /* size of heap data block on disk and in mem */
+ uint8_t *dblk_image; /* The data block image */
+};
+
+/* Struct for heap data block */
+struct H5HL_dblk_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions, _must_ be */
+ /* first field in structure */
+ H5HL_t *heap; /* Pointer to heap for data block */
+};
+
+/* Struct for heap prefix */
+struct H5HL_prfx_t {
+ H5AC_info_t cache_info; /* Information for H5AC cache functions, _must_ be */
+ /* first field in structure */
+ H5HL_t *heap; /* Pointer to heap for prefix */
+};
+
+/* Callback information for loading local heap prefix from disk */
+typedef struct H5HL_cache_prfx_ud_t {
+ size_t sizeof_size; /* Size of file sizes */
+ size_t sizeof_addr; /* Size of file addresses */
+ haddr_t prfx_addr; /* Address of prefix */
+ size_t sizeof_prfx; /* Size of heap prefix */
+} H5HL_cache_prfx_ud_t;
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Heap routines */
+H5_DLL H5HL_t *H5HL__new(size_t sizeof_size, size_t sizeof_addr, size_t prfx_size);
+H5_DLL herr_t H5HL__dest(H5HL_t *heap);
+H5_DLL herr_t H5HL__inc_rc(H5HL_t *heap);
+H5_DLL herr_t H5HL__dec_rc(H5HL_t *heap);
+
+/* Heap prefix routines */
+H5_DLL H5HL_prfx_t *H5HL__prfx_new(H5HL_t *heap);
+H5_DLL herr_t H5HL__prfx_dest(H5HL_prfx_t *prfx);
+
+/* Heap data block routines */
+H5_DLL H5HL_dblk_t *H5HL__dblk_new(H5HL_t *heap);
+H5_DLL herr_t H5HL__dblk_dest(H5HL_dblk_t *dblk);
+H5_DLL herr_t H5HL__dblk_realloc(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t new_heap_size);
+
+#endif /* _H5HLpkg_H */
diff --git a/src/H5HLprfx.c b/src/H5HLprfx.c
new file mode 100644
index 0000000..41c254a
--- /dev/null
+++ b/src/H5HLprfx.c
@@ -0,0 +1,164 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLprfx.c
+ * Summer 2012
+ * Dana Robinson <derobins@hdfgroup.org>
+ *
+ * Purpose: Prefix routines for local heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5HLmodule.h" /* This source code file is part of the H5HL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5HLpkg.h" /* Local Heaps */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5HL_prfx_t struct */
+H5FL_DEFINE_STATIC(H5HL_prfx_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__prfx_new
+ *
+ * Purpose: Create a new local heap prefix object
+ *
+ * Return: Success: non-NULL pointer to new local heap prefix
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+H5HL_prfx_t *, NULL, NULL,
+H5HL__prfx_new(H5HL_t *heap))
+
+ H5HL_prfx_t *prfx = NULL; /* New local heap prefix */
+
+ /* check arguments */
+ HDassert(heap);
+
+ /* Allocate new local heap prefix */
+ if(NULL == (prfx = H5FL_CALLOC(H5HL_prfx_t)))
+ H5E_THROW(H5E_CANTALLOC, "memory allocation failed for local heap prefix")
+
+ /* Increment ref. count on heap data structure */
+ if(FAIL == H5HL__inc_rc(heap))
+ H5E_THROW(H5E_CANTINC, "can't increment heap ref. count")
+
+ /* Link the heap & the prefix */
+ prfx->heap = heap;
+ heap->prfx = prfx;
+
+ /* Set the return value */
+ ret_value = prfx;
+
+CATCH
+ /* Ensure that the prefix memory is deallocated on errors */
+ if(!ret_value && prfx != NULL)
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ prfx = H5FL_FREE(H5HL_prfx_t, prfx);
+
+END_FUNC(PKG) /* end H5HL__prfx_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HL__prfx_dest
+ *
+ * Purpose: Destroy a local heap prefix object
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Oct 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+BEGIN_FUNC(PKG, ERR,
+herr_t, SUCCEED, FAIL,
+H5HL__prfx_dest(H5HL_prfx_t *prfx))
+
+ /* check arguments */
+ HDassert(prfx);
+
+ /* Check if prefix was initialized */
+ if(prfx->heap) {
+ /* Unlink prefix from heap */
+ prfx->heap->prfx = NULL;
+
+ /* Decrement ref. count on heap data structure */
+ if(FAIL == H5HL__dec_rc(prfx->heap))
+ H5E_THROW(H5E_CANTDEC, "can't decrement heap ref. count")
+
+ /* Unlink heap from prefix */
+ prfx->heap = NULL;
+ } /* end if */
+
+CATCH
+ /* Free prefix memory */
+ /* H5FL_FREE always returns NULL so we can't check for errors */
+ prfx = H5FL_FREE(H5HL_prfx_t, prfx);
+
+END_FUNC(PKG) /* end H5HL__prfx_dest() */
+
diff --git a/src/H5HLprivate.h b/src/H5HLprivate.h
new file mode 100644
index 0000000..054d396
--- /dev/null
+++ b/src/H5HLprivate.h
@@ -0,0 +1,76 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLprivate.h
+ * Jul 16 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Private declarations for the H5HL (local heap) package.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5HLprivate_H
+#define _H5HLprivate_H
+
+/* Include package's public header */
+#include "H5HLpublic.h"
+
+/* Private headers needed by this file. */
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Fprivate.h" /* File access */
+
+/*
+ * Feature: Define H5HL_DEBUG on the compiler command line if you want to
+ * enable diagnostic messages from this layer.
+ */
+#ifdef NDEBUG
+# undef H5HL_DEBUG
+#endif
+
+#define H5HL_ALIGN(X) ((((unsigned)X)+7)&(unsigned)(~0x07)) /* align on 8-byte boundary */
+
+#define H5HL_SIZEOF_FREE(F) \
+ H5HL_ALIGN(H5F_SIZEOF_SIZE (F) + /* ptr to next free block */ \
+ H5F_SIZEOF_SIZE (F)) /* size of this free block */
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Typedef for local heap in memory (defined in H5HLpkg.h) */
+typedef struct H5HL_t H5HL_t;
+
+/*
+ * Library prototypes
+ */
+H5_DLL herr_t H5HL_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, haddr_t *addr/*out*/);
+H5_DLL herr_t H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr);
+H5_DLL herr_t H5HL_get_size(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t *size);
+H5_DLL herr_t H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap_size);
+H5_DLL size_t H5HL_insert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t size,
+ const void *buf);
+H5_DLL void *H5HL_offset_into(const H5HL_t *heap, size_t offset);
+H5_DLL H5HL_t *H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags);
+H5_DLL herr_t H5HL_remove(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t offset,
+ size_t size);
+H5_DLL herr_t H5HL_unprotect(H5HL_t *heap);
+
+/* Debugging routines for dumping file structures */
+H5_DLL herr_t H5HL_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent,
+ int fwidth);
+
+#endif
+
diff --git a/src/H5HLpublic.h b/src/H5HLpublic.h
new file mode 100644
index 0000000..143bb78
--- /dev/null
+++ b/src/H5HLpublic.h
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HLpublic.h
+ * Jul 16 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public declarations for the H5HL (local heap) package.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5HLpublic_H
+#define _H5HLpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/H5HP.c b/src/H5HP.c
new file mode 100644
index 0000000..4ef5662
--- /dev/null
+++ b/src/H5HP.c
@@ -0,0 +1,919 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Provides a heap abstract data type.
+ *
+ * (See chapter 11 - "Priority Queues" of _Algorithms_, by
+ * Sedgewick for additional information)
+ *
+ */
+
+
+/* Private headers needed */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HPprivate.h" /* Heap routines */
+#include "H5FLprivate.h" /* Memory management functions */
+
+/* Local Macros */
+#define H5HP_START_SIZE 16 /* Initial number of entries for heaps */
+
+/* Private typedefs & structs */
+
+/* Data structure for entries in the internal heap array */
+typedef struct {
+ int val; /* Value to be used for heap condition */
+ H5HP_info_t *obj; /* Pointer to object stored in heap */
+}H5HP_ent_t;
+
+/* Main heap data structure */
+struct H5HP_t {
+ H5HP_type_t type; /* Type of heap (minimum or maximum value at "top") */
+ size_t nobjs; /* Number of active objects in heap array */
+ size_t nalloc; /* Number of allocated locations in heap array */
+ H5HP_ent_t *heap; /* Pointer to array containing heap entries */
+};
+
+/* Static functions */
+static herr_t H5HP_swim_max(H5HP_t *heap, size_t loc);
+static herr_t H5HP_swim_min(H5HP_t *heap, size_t loc);
+static herr_t H5HP_sink_max(H5HP_t *heap, size_t loc);
+static herr_t H5HP_sink_min(H5HP_t *heap, size_t loc);
+
+/* Declare a free list to manage the H5HP_t struct */
+H5FL_DEFINE_STATIC(H5HP_t);
+
+/* Declare a free list to manage sequences of H5HP_ent_t */
+H5FL_SEQ_DEFINE_STATIC(H5HP_ent_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_swim_max
+ PURPOSE
+ Restore heap condition by moving an object upward
+ USAGE
+ herr_t H5HP_swim_max(heap, loc)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ size_t loc; IN: Location to start from
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Restore the heap condition for the heap's array by "swimming" the object
+ at a location upward.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine is for "maximum" value heaps.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5HP_swim_max(H5HP_t *heap, size_t loc)
+{
+ int val; /* Temporary copy value of object to move in heap */
+ H5HP_info_t *obj; /* Temporary pointer to object to move in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get copies of the information about the object to move in the heap */
+ val=heap->heap[loc].val;
+ obj=heap->heap[loc].obj;
+
+ /* Move object up in heap until it's reached the maximum location possible */
+ while(heap->heap[loc/2].val < val) {
+ /* Move object "above" current location in heap down */
+ heap->heap[loc].val=heap->heap[loc/2].val;
+ heap->heap[loc].obj=heap->heap[loc/2].obj;
+
+ /* Update heap location for object which moved */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ /* Move to location "above" current location */
+ loc=loc/2;
+ } /* end while */
+
+ /* Put object into heap at correct location */
+ heap->heap[loc].val=val;
+ heap->heap[loc].obj=obj;
+
+ /* Update heap location for object */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_swim_max() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_swim_min
+ PURPOSE
+ Restore heap condition by moving an object upward
+ USAGE
+ herr_t H5HP_swim_min(heap, loc)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ size_t loc; IN: Location to start from
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Restore the heap condition for the heap's array by "swimming" the object
+ at a location upward.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine is for "minimum" value heaps.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5HP_swim_min(H5HP_t *heap, size_t loc)
+{
+ int val; /* Temporary copy value of object to move in heap */
+ H5HP_info_t *obj; /* Temporary pointer to object to move in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get copies of the information about the object to move in the heap */
+ val=heap->heap[loc].val;
+ obj=heap->heap[loc].obj;
+
+ /* Move object up in heap until it's reached the minimum location possible */
+ while(heap->heap[loc/2].val > val) {
+ /* Move object "above" current location in heap down */
+ heap->heap[loc].val=heap->heap[loc/2].val;
+ heap->heap[loc].obj=heap->heap[loc/2].obj;
+
+ /* Update heap location for object which moved */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ /* Move to location "above" current location */
+ loc=loc/2;
+ } /* end while */
+
+ /* Put object into heap at correct location */
+ heap->heap[loc].val=val;
+ heap->heap[loc].obj=obj;
+
+ /* Update heap location for object */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_swim_min() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_sink_max
+ PURPOSE
+ Restore heap condition by moving an object downward
+ USAGE
+ herr_t H5HP_sink_max(heap, loc)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ size_t loc; IN: Location to start from
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Restore the heap condition for the heap's array by "sinking" the object
+ at a location downward.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine is for "maximum" value heaps.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5HP_sink_max(H5HP_t *heap, size_t loc)
+{
+ int val; /* Temporary copy value of object to move in heap */
+ void *obj; /* Temporary pointer to object to move in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get copies of the information about the object to move in the heap */
+ val=heap->heap[loc].val;
+ obj=heap->heap[loc].obj;
+
+ /* Move object up in heap until it's reached the maximum location possible */
+ while((2*loc)<=heap->nobjs) {
+ size_t new_loc=loc*2; /* New object's potential location area */
+
+ /* Get the greater of the two objects below the location in heap */
+ if(new_loc<heap->nobjs && (heap->heap[new_loc].val < heap->heap[new_loc+1].val))
+ new_loc++;
+
+ /* Check if the object is smaller than the larger of the objects below it */
+ /* If so, its in the correct location now, and we can get out */
+ if(val >= heap->heap[new_loc].val)
+ break;
+
+ /* Move the greater of the two objects below the current location up */
+ heap->heap[loc].val=heap->heap[new_loc].val;
+ heap->heap[loc].obj=heap->heap[new_loc].obj;
+
+ /* Update heap location for object which moved */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ /* Move to location "below" current location */
+ loc=new_loc;
+ } /* end while */
+
+ /* Put object into heap at correct location */
+ heap->heap[loc].val = val;
+ heap->heap[loc].obj = (H5HP_info_t *)obj;
+
+ /* Update heap location for object */
+ heap->heap[loc].obj->heap_loc = loc;
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_sink_max() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_sink_min
+ PURPOSE
+ Restore heap condition by moving an object downward
+ USAGE
+ herr_t H5HP_sink_min(heap, loc)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ size_t loc; IN: Location to start from
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Restore the heap condition for the heap's array by "sinking" the object
+ at a location downward.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine is for "minimum" value heaps.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5HP_sink_min(H5HP_t *heap, size_t loc)
+{
+ int val; /* Temporary copy value of object to move in heap */
+ void *obj; /* Temporary pointer to object to move in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Get copies of the information about the object to move in the heap */
+ val=heap->heap[loc].val;
+ obj=heap->heap[loc].obj;
+
+ /* Move object up in heap until it's reached the maximum location possible */
+ while((2*loc)<=heap->nobjs) {
+ size_t new_loc=loc*2; /* New object's potential location area */
+
+ /* Get the lesser of the two objects below the location in heap */
+ if(new_loc<heap->nobjs && (heap->heap[new_loc].val > heap->heap[new_loc+1].val))
+ new_loc++;
+
+ /* Check if the object is greater than the larger of the objects below it */
+ /* If so, its in the correct location now, and we can get out */
+ if(val <= heap->heap[new_loc].val)
+ break;
+
+ /* Move the greater of the two objects below the current location up */
+ heap->heap[loc].val=heap->heap[new_loc].val;
+ heap->heap[loc].obj=heap->heap[new_loc].obj;
+
+ /* Update heap location for object which moved */
+ heap->heap[loc].obj->heap_loc=loc;
+
+ /* Move to location "below" current location */
+ loc=new_loc;
+ } /* end while */
+
+ /* Put object into heap at correct location */
+ heap->heap[loc].val = val;
+ heap->heap[loc].obj = (H5HP_info_t *)obj;
+
+ /* Update heap location for object */
+ heap->heap[loc].obj->heap_loc = loc;
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_sink_min() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_create
+ PURPOSE
+ Create a heap
+ USAGE
+ H5HP_t *H5HP_create(heap_type)
+ H5HP_type_t heap_type; IN: Type of heap to create
+
+ RETURNS
+ Returns a pointer to a heap on success, NULL on failure.
+ DESCRIPTION
+ Create a priority queue. The SIZE is used to set the initial number of
+ entries allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5HP_t *
+H5HP_create(H5HP_type_t heap_type)
+{
+ H5HP_t *new_heap=NULL; /* Pointer to new heap object created */
+ H5HP_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check args */
+ HDassert(heap_type==H5HP_MIN_HEAP || heap_type==H5HP_MAX_HEAP);
+
+ /* Allocate ref-counted string structure */
+ if((new_heap=H5FL_MALLOC(H5HP_t))==NULL)
+ HGOTO_ERROR(H5E_HEAP,H5E_NOSPACE,NULL,"memory allocation failed");
+
+ /* Allocate the array to store the heap entries */
+ if((new_heap->heap = H5FL_SEQ_MALLOC(H5HP_ent_t, (size_t)(H5HP_START_SIZE + 1)))==NULL)
+ HGOTO_ERROR(H5E_HEAP,H5E_NOSPACE,NULL,"memory allocation failed");
+
+ /* Set the internal fields */
+ new_heap->type=heap_type;
+ new_heap->nobjs=0;
+ new_heap->nalloc=H5HP_START_SIZE+1;
+
+ /* Set the information in the 0'th location based on the type of heap */
+ if(heap_type==H5HP_MIN_HEAP) {
+ /* Set the value in the '0' location to be the minimum value, to
+ * simplify the algorithms
+ */
+ new_heap->heap[0].val=INT_MIN;
+ new_heap->heap[0].obj=NULL;
+ } /* end if */
+ else {
+ /* Set the value in the '0' location to be the maximum value, to
+ * simplify the algorithms
+ */
+ new_heap->heap[0].val=INT_MAX;
+ new_heap->heap[0].obj=NULL;
+ } /* end else */
+
+ /* Set the return value */
+ ret_value=new_heap;
+
+done:
+ /* Error cleanup */
+ if(NULL ==ret_value) {
+ if(NULL != new_heap) {
+ if(NULL != new_heap->heap)
+ new_heap->heap = H5FL_SEQ_FREE(H5HP_ent_t, new_heap->heap);
+ new_heap = H5FL_FREE(H5HP_t, new_heap);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_count
+ PURPOSE
+ Check the number of elements in a heap
+ USAGE
+ ssize_t H5HP_count(heap)
+ const H5HP_t *heap; IN: Pointer to heap to query
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Checks the number of elements in heap
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+ssize_t
+H5HP_count(const H5HP_t *heap)
+{
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(heap);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Return the number of objects in the heap */
+ H5_CHECK_OVERFLOW(heap->nobjs,size_t,ssize_t);
+ ret_value=(ssize_t)heap->nobjs;
+
+ /* No post-condition check necessary, since heap is constant */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_count() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_insert
+ PURPOSE
+ Insert an object into a heap, with an initial value
+ USAGE
+ herr_t H5HP_insert(heap, val, obj)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ int val; IN: Initial value for object in heap
+ void *obj; IN: Pointer to object to insert into heap
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Inserts a OBJ into a HEAP, with an initial VALue.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_insert(H5HP_t *heap, int val, void *obj)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(obj);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Increment number of objects in heap */
+ heap->nobjs++;
+
+ /* Check if we need to allocate more room for heap array */
+ if(heap->nobjs>=heap->nalloc) {
+ size_t n = MAX(H5HP_START_SIZE, 2*(heap->nalloc-1)) + 1;
+ H5HP_ent_t *new_heap = H5FL_SEQ_REALLOC(H5HP_ent_t,heap->heap, n);
+
+ if (!new_heap)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend heap array");
+ heap->heap = new_heap;
+ heap->nalloc = n;
+ } /* end if */
+
+ /* Insert new object at end of heap */
+ heap->heap[heap->nobjs].val = val;
+ heap->heap[heap->nobjs].obj = (H5HP_info_t *)obj;
+ heap->heap[heap->nobjs].obj->heap_loc = heap->nobjs;
+
+ /* Restore heap condition */
+ if(heap->type==H5HP_MAX_HEAP) {
+ if(H5HP_swim_max(heap,heap->nobjs)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "unable to restore heap condition");
+ } /* end if */
+ else {
+ if(H5HP_swim_min(heap,heap->nobjs)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "unable to restore heap condition");
+ } /* end else */
+
+done:
+
+ /* Check internal consistency */
+ /* (Post-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_insert() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_top
+ PURPOSE
+ Check the value of the top object in the heap
+ USAGE
+ herr_t H5HP_top(heap, val)
+ const H5HP_t *heap; IN: Pointer to heap to modify
+ int val; IN/OUT: Initial value for object in heap
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Checks the value of the top object in a heap
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_top(const H5HP_t *heap, int *val)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(val);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Get value of the top object in the heap */
+ *val=heap->heap[1].val;
+
+ /* No post-condition check necessary, since heap is constant */
+ FUNC_LEAVE_NOAPI(SUCCEED);
+} /* end H5HP_top() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_remove
+ PURPOSE
+ Remove an object into a heap
+ USAGE
+ herr_t H5HP_remove(heap, val, obj)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ int *val; OUT: Pointer to value of object removed from heap
+ void **obj; OUT: Pointer to object removed from heap
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Removes the top object on a heap, returning its value and object pointer
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_remove(H5HP_t *heap, int *val, void **obj)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(val);
+ HDassert(obj);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Check if there are any objects on the heap to remove */
+ if(heap->nobjs==0)
+ HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "heap is empty");
+
+ /* Get the information for the top object on the heap */
+ HDassert(heap->heap[1].obj->heap_loc==1);
+ *val=heap->heap[1].val;
+ *obj=heap->heap[1].obj;
+
+ /* Move the last element in the heap to the top */
+ heap->heap[1].val=heap->heap[heap->nobjs].val;
+ heap->heap[1].obj=heap->heap[heap->nobjs].obj;
+ heap->heap[1].obj->heap_loc=1;
+
+ /* Decrement number of objects in heap */
+ heap->nobjs--;
+
+ /* Restore heap condition, if there are objects on the heap */
+ if(heap->nobjs>0) {
+ if(heap->type==H5HP_MAX_HEAP) {
+ if(H5HP_sink_max(heap, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to restore heap condition");
+ } /* end if */
+ else {
+ if(H5HP_sink_min(heap, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to restore heap condition");
+ } /* end else */
+ } /* end if */
+
+done:
+
+ /* Check internal consistency */
+ /* (Post-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_remove() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_change
+ PURPOSE
+ Change the priority of an object on a heap
+ USAGE
+ herr_t H5HP_change(heap, val, obj)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ int val; IN: New priority value for object
+ void *obj; IN: Pointer to object to modify
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Changes the priority of an object on a heap.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_change(H5HP_t *heap, int val, void *_obj)
+{
+ H5HP_info_t *obj=(H5HP_info_t *)_obj; /* Alias for object */
+ size_t obj_loc; /* Location of object in heap */
+ int old_val; /* Object's old priority value */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(obj);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Get the location of the object in the heap */
+ obj_loc=obj->heap_loc;
+ HDassert(obj_loc>0 && obj_loc<=heap->nobjs);
+
+ /* Change the heap object's priority */
+ old_val=heap->heap[obj_loc].val;
+ heap->heap[obj_loc].val=val;
+
+ /* Restore heap condition */
+ if(val<old_val) {
+ if(heap->type==H5HP_MAX_HEAP) {
+ if(H5HP_sink_max(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end if */
+ else {
+ if(H5HP_swim_min(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end else */
+ } /* end if */
+ else {
+ if(heap->type==H5HP_MAX_HEAP) {
+ if(H5HP_swim_max(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end if */
+ else {
+ if(H5HP_sink_min(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end else */
+ } /* end else */
+
+done:
+
+ /* Check internal consistency */
+ /* (Post-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_change() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_incr
+ PURPOSE
+ Increment the priority of an object on a heap
+ USAGE
+ herr_t H5HP_incr(heap, amt, obj)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ unsigned amt; IN: Amount to increase priority by
+ void *obj; IN: Pointer to object to modify
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Increments the priority of an object on a heap by one.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_incr(H5HP_t *heap, unsigned amt, void *_obj)
+{
+ H5HP_info_t *obj=(H5HP_info_t *)_obj; /* Alias for object */
+ size_t obj_loc; /* Location of object in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(obj);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Get the location of the object in the heap */
+ obj_loc = obj->heap_loc;
+ HDassert(obj_loc > 0 && obj_loc <= heap->nobjs);
+
+ /* Change the heap object's priority */
+ heap->heap[obj_loc].val += (int)amt;
+
+ /* Restore heap condition */
+ if(H5HP_MAX_HEAP == heap->type) {
+ if(H5HP_swim_max(heap, obj_loc) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition")
+ } /* end if */
+ else {
+ if(H5HP_sink_min(heap, obj_loc) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition")
+ } /* end else */
+
+done:
+
+ /* Check internal consistency */
+ /* (Post-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_incr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_decr
+ PURPOSE
+ Decrement the priority of an object on a heap
+ USAGE
+ herr_t H5HP_dec(heap, amt, obj)
+ H5HP_t *heap; IN/OUT: Pointer to heap to modify
+ unsigned amt; IN: Amount to decrease priority by
+ void *obj; IN: Pointer to object to modify
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Decrements the priority of an object on a heap by one.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_decr(H5HP_t *heap, unsigned amt, void *_obj)
+{
+ H5HP_info_t *obj=(H5HP_info_t *)_obj; /* Alias for object */
+ size_t obj_loc; /* Location of object in heap */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(heap);
+ HDassert(obj);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ /* Get the location of the object in the heap */
+ obj_loc=obj->heap_loc;
+ HDassert(obj_loc>0 && obj_loc<=heap->nobjs);
+
+ /* Change the heap object's priority */
+ H5_CHECK_OVERFLOW(amt, unsigned, int);
+ heap->heap[obj_loc].val-=(int)amt;
+
+ /* Restore heap condition */
+ if(heap->type==H5HP_MAX_HEAP) {
+ if(H5HP_sink_max(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end if */
+ else {
+ if(H5HP_swim_min(heap,obj_loc)<0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRESTORE, FAIL, "unable to restore heap condition");
+ } /* end else */
+
+done:
+
+ /* Check internal consistency */
+ /* (Post-condition) */
+ HDassert(heap->nobjs<heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type==H5HP_MAX_HEAP && heap->heap[0].val==INT_MAX) ||
+ (heap->type==H5HP_MIN_HEAP && heap->heap[0].val==INT_MIN));
+ HDassert(heap->heap[0].obj==NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5HP_decr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5HP_close
+ PURPOSE
+ Close a heap, deallocating it.
+ USAGE
+ herr_t H5HP_close(heap)
+ H5HP_t *heap; IN/OUT: Pointer to heap to close
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a heap, freeing all internal information. Any objects left in
+ the heap are not deallocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5HP_close(H5HP_t *heap)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(heap);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+ HDassert(heap->nobjs < heap->nalloc);
+ HDassert(heap->heap);
+ HDassert((heap->type == H5HP_MAX_HEAP && heap->heap[0].val == INT_MAX) ||
+ (heap->type == H5HP_MIN_HEAP && heap->heap[0].val == INT_MIN));
+ HDassert(NULL == heap->heap[0].obj);
+
+ /* Free internal structures for heap */
+ heap->heap = H5FL_SEQ_FREE(H5HP_ent_t, heap->heap);
+
+ /* Free actual heap object */
+ heap = H5FL_FREE(H5HP_t, heap);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5HP_close() */
+
diff --git a/src/H5HPprivate.h b/src/H5HPprivate.h
new file mode 100644
index 0000000..041c2b9
--- /dev/null
+++ b/src/H5HPprivate.h
@@ -0,0 +1,69 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5HP module
+ */
+#ifndef _H5HPprivate_H
+#define _H5HPprivate_H
+
+/**************************************/
+/* Public headers needed by this file */
+/**************************************/
+#ifdef LATER
+#include "H5HPpublic.h"
+#endif /* LATER */
+
+/***************************************/
+/* Private headers needed by this file */
+/***************************************/
+#include "H5private.h"
+
+/************/
+/* Typedefs */
+/************/
+
+/* Typedef for heap struct (defined in H5HP.c) */
+typedef struct H5HP_t H5HP_t;
+
+/* Typedef for objects which can be inserted into heaps */
+/* This _must_ be the first field in objects which can be inserted into heaps */
+typedef struct H5HP_info_t {
+ size_t heap_loc; /* Location of object in heap */
+}H5HP_info_t;
+
+/* Typedef for type of heap to create */
+typedef enum {
+ H5HP_MIN_HEAP, /* Minimum values in heap are at the "top" */
+ H5HP_MAX_HEAP /* Maximum values in heap are at the "top" */
+} H5HP_type_t;
+
+/**********/
+/* Macros */
+/**********/
+
+/********************/
+/* Private routines */
+/********************/
+H5_DLL H5HP_t *H5HP_create(H5HP_type_t heap_type);
+H5_DLL herr_t H5HP_insert(H5HP_t *heap, int val, void *obj);
+H5_DLL ssize_t H5HP_count(const H5HP_t *heap);
+H5_DLL herr_t H5HP_top(const H5HP_t *heap, int *val);
+H5_DLL herr_t H5HP_remove(H5HP_t *heap, int *val, void **ptr);
+H5_DLL herr_t H5HP_change(H5HP_t *heap, int val, void *obj);
+H5_DLL herr_t H5HP_incr(H5HP_t *heap, unsigned amt, void *obj);
+H5_DLL herr_t H5HP_decr(H5HP_t *heap, unsigned amt, void *obj);
+H5_DLL herr_t H5HP_close(H5HP_t *heap);
+
+#endif /* _H5HPprivate_H */
+
diff --git a/src/H5I.c b/src/H5I.c
new file mode 100644
index 0000000..ce4ecdc
--- /dev/null
+++ b/src/H5I.c
@@ -0,0 +1,2300 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * FILE: H5I.c - Internal storage routines for handling "IDs"
+ *
+ * REMARKS: ID's which allow objects (void *'s currently) to be bundled
+ * into "types" for more general storage.
+ *
+ * DESIGN: The types are stored in an array of pointers to store each
+ * type in an element. Each "type" node contains a link to a
+ * hash table to manage the IDs in each type. Allowed types are
+ * values within the range 1 to H5I_MAX_NUM_TYPES and are given out
+ * at run-time. Types used by the library are stored in global
+ * variables defined in H5Ipublic.h.
+ *
+ * AUTHOR: Quincey Koziol
+ *
+ * MODIFICATIONS:
+ * 1/3/96 - Starting writing specs & coding prototype
+ * 1/7/96 - Finished coding prototype
+ * 6/10/97 - Moved into HDF5 library
+ * 5/18/04 - Expanded to allow registration of new types at run-time
+ */
+
+#include "H5Imodule.h" /* This source code file is part of the H5I module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Ipkg.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5SLprivate.h" /* Skip Lists */
+
+/* Define this to compile in support for dumping ID information */
+/* #define H5I_DEBUG_OUTPUT */
+#ifndef H5I_DEBUG_OUTPUT
+#include "H5Gprivate.h" /* Groups */
+#else /* H5I_DEBUG_OUTPUT */
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Tprivate.h" /* Datatypes */
+#endif /* H5I_DEBUG_OUTPUT */
+
+/* Local Macros */
+
+/* Combine a Type number and an atom index into an atom */
+#define H5I_MAKE(g,i) ((((hid_t)(g) & TYPE_MASK) << ID_BITS) | \
+ ((hid_t)(i) & ID_MASK))
+
+/* Local typedefs */
+
+/* Atom information structure used */
+typedef struct H5I_id_info_t {
+ hid_t id; /* ID for this info */
+ unsigned count; /* ref. count for this atom */
+ unsigned app_count; /* ref. count of application visible atoms */
+ const void *obj_ptr; /* pointer associated with the atom */
+} H5I_id_info_t;
+
+/* ID type structure used */
+typedef struct {
+ const H5I_class_t *cls; /* Pointer to ID class */
+ unsigned init_count; /* # of times this type has been initialized*/
+ uint64_t id_count; /* Current number of IDs held */
+ uint64_t nextid; /* ID to use for the next atom */
+ H5SL_t *ids; /* Pointer to skip list that stores IDs */
+} H5I_id_type_t;
+
+typedef struct {
+ H5I_search_func_t app_cb; /* Application's callback routine */
+ void *app_key; /* Application's "key" (user data) */
+ void *ret_obj; /* Object to return */
+} H5I_search_ud_t;
+
+/* User data for iterator callback for ID iteration */
+typedef struct {
+ H5I_search_func_t user_func; /* 'User' function to invoke */
+ void *user_udata; /* User data to pass to 'user' function */
+ hbool_t app_ref; /* Whether this is an appl. ref. call */
+} H5I_iterate_ud_t;
+
+/* User data for H5I__clear_type_cb */
+typedef struct {
+ H5I_id_type_t *type_ptr; /* Pointer to the type being cleard */
+ hbool_t force; /* Whether to always remove the id */
+ hbool_t app_ref; /* Whether this is an appl. ref. call */
+} H5I_clear_type_ud_t;
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/*-------------------- Locally scoped variables -----------------------------*/
+
+/* Array of pointers to atomic types */
+static H5I_id_type_t *H5I_id_type_list_g[H5I_MAX_NUM_TYPES];
+
+/* Variable to keep track of the number of types allocated. Its value is the */
+/* next type ID to be handed out, so it is always one greater than the number */
+/* of types. */
+/* Starts at 1 instead of 0 because it makes trace output look nicer. If more */
+/* types (or IDs within a type) are needed, adjust TYPE_BITS in H5Ipkg.h */
+/* and/or increase size of hid_t */
+static H5I_type_t H5I_next_type = (H5I_type_t) H5I_NTYPES;
+
+/* Declare a free list to manage the H5I_id_info_t struct */
+H5FL_DEFINE_STATIC(H5I_id_info_t);
+
+/* Declare a free list to manage the H5I_id_type_t struct */
+H5FL_DEFINE_STATIC(H5I_id_type_t);
+
+/* Declare a free list to manage the H5I_class_t struct */
+H5FL_DEFINE_STATIC(H5I_class_t);
+
+/*--------------------- Local function prototypes ---------------------------*/
+static htri_t H5I__clear_type_cb(void *_id, void *key, void *udata);
+static int H5I__destroy_type(H5I_type_t type);
+static void *H5I__remove_verify(hid_t id, H5I_type_t id_type);
+static void *H5I__remove_common(H5I_id_type_t *type_ptr, hid_t id);
+static int H5I__inc_type_ref(H5I_type_t type);
+static int H5I__get_type_ref(H5I_type_t type);
+static H5I_id_info_t *H5I__find_id(hid_t id);
+#ifdef H5I_DEBUG_OUTPUT
+static herr_t H5I__debug(H5I_type_t type);
+#endif /* H5I_DEBUG_OUTPUT */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_term_package
+ *
+ * Purpose: Terminate the H5I interface: release all memory, reset all
+ * global variables to initial values. This only happens if all
+ * types have been destroyed from other interfaces.
+ *
+ * Return: Success: Positive if any action was taken that might
+ * affect some other interface; zero otherwise.
+ *
+ * Failure: Negative.
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ H5I_id_type_t *type_ptr; /* Pointer to ID type */
+ H5I_type_t type; /* Type of ID */
+
+ /* How many types are still being used? */
+ for(type = (H5I_type_t)0; type < H5I_next_type; H5_INC_ENUM(H5I_type_t, type))
+ if((type_ptr = H5I_id_type_list_g[type]) && type_ptr->ids)
+ n++;
+
+ /* If no types are used then clean up */
+ if(0 == n) {
+ for(type = (H5I_type_t)0; type < H5I_next_type; H5_INC_ENUM(H5I_type_t,type)) {
+ type_ptr = H5I_id_type_list_g[type];
+ if(type_ptr) {
+ HDassert(NULL == type_ptr->ids);
+ type_ptr = H5FL_FREE(H5I_id_type_t, type_ptr);
+ H5I_id_type_list_g[type] = NULL;
+ n++;
+ } /* end if */
+ } /* end for */
+
+ /* Mark interface closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5I_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iregister_type
+ *
+ * Purpose: Public interface to H5I_register_type. Creates a new type
+ * of ID's to give out. A specific number (RESERVED) of type
+ * entries may be reserved to enable "constant" values to be handed
+ * out which are valid IDs in the type, but which do not map to any
+ * data structures and are not allocated dynamically later. HASH_SIZE is
+ * the minimum hash table size to use for the type. FREE_FUNC is
+ * called with an object pointer when the object is removed from
+ * the type.
+ *
+ * Return: Success: Type ID of the new type
+ * Failure: H5I_BADID
+ *
+ * Programmers: Nathaniel Furrer
+ * James Laird
+ * Friday, April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+H5I_type_t
+H5Iregister_type(size_t hash_size, unsigned reserved, H5I_free_t free_func)
+{
+ H5I_class_t *cls = NULL; /* New ID class */
+ H5I_type_t new_type; /* New ID type value */
+ H5I_type_t ret_value = H5I_BADID; /* Return value */
+
+ FUNC_ENTER_API(H5I_BADID)
+ H5TRACE3("It", "zIux", hash_size, reserved, free_func);
+
+ /* Generate a new H5I_type_t value */
+
+ /* Increment the number of types*/
+ if(H5I_next_type < H5I_MAX_NUM_TYPES) {
+ new_type = H5I_next_type;
+ H5_INC_ENUM(H5I_type_t, H5I_next_type);
+ } /* end if */
+ else {
+ hbool_t done; /* Indicate that search was successful */
+ int i; /* Local index variable */
+
+ /* Look for a free type to give out */
+ done = FALSE;
+ for(i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES && done == FALSE; i++) {
+ if(NULL == H5I_id_type_list_g[i]) {
+ /* Found a free type ID */
+ new_type = (H5I_type_t)i;
+ done = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* Verify that we found a type to give out */
+ if(done == FALSE)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5I_BADID, "Maximum number of ID types exceeded.")
+ } /* end else */
+
+ /* Allocate new ID class */
+ if(NULL == (cls = H5FL_MALLOC(H5I_class_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTALLOC, H5I_BADID, "ID class allocation failed")
+
+ /* Initialize class fields */
+ cls->type_id = new_type;
+ cls->flags = H5I_CLASS_IS_APPLICATION;
+ cls->reserved = reserved;
+ cls->free_func = free_func;
+
+ /* Register the new ID class */
+ if(H5I_register_type(cls) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, H5I_BADID, "can't initialize ID class")
+
+ /* Set return value */
+ ret_value = new_type;
+
+done:
+ /* Clean up on error */
+ if(ret_value < 0)
+ if(cls)
+ cls = H5FL_FREE(H5I_class_t, cls);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iregister_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register_type
+ *
+ * Purpose: Creates a new type of ID's to give out.
+ * The class is initialized or its reference count is incremented
+ * (if it is already initialized).
+ *
+ * Return: Success: Type ID of the new type
+ * Failure: H5I_BADID
+ *
+ * Programmers: Nathaniel Furrer
+ * James Laird
+ * Friday, April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_register_type(const H5I_class_t *cls)
+{
+ H5I_id_type_t *type_ptr = NULL; /* Ptr to the atomic type*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cls);
+ HDassert(cls->type_id > 0 && cls->type_id < H5I_MAX_NUM_TYPES);
+
+ /* Initialize the type */
+ if(NULL == H5I_id_type_list_g[cls->type_id]) {
+ /* Allocate the type information for new type */
+ if(NULL == (type_ptr = (H5I_id_type_t *)H5FL_CALLOC(H5I_id_type_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTALLOC, FAIL, "ID type allocation failed")
+ H5I_id_type_list_g[cls->type_id] = type_ptr;
+ } /* end if */
+ else {
+ /* Get the pointer to the existing type */
+ type_ptr = H5I_id_type_list_g[cls->type_id];
+ } /* end else */
+
+ /* Initialize the ID type structure for new types */
+ if(type_ptr->init_count == 0) {
+ type_ptr->cls = cls;
+ type_ptr->id_count = 0;
+ type_ptr->nextid = cls->reserved;
+ if(NULL == (type_ptr->ids = H5SL_create(H5SL_TYPE_HID, NULL)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCREATE, FAIL, "skip list creation failed")
+ } /* end if */
+
+ /* Increment the count of the times this type has been initialized */
+ type_ptr->init_count++;
+
+done:
+ if(ret_value < 0) { /* Clean up on error */
+ if(type_ptr) {
+ if(type_ptr->ids)
+ H5SL_close(type_ptr->ids);
+ (void)H5FL_FREE(H5I_id_type_t, type_ptr);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Itype_exists
+ *
+ * Purpose: Query function to inform the user if a given type is
+ * currently registered with the library.
+ *
+ * Return: Success: 1 if the type is registered, 0 if it is not
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Nathaniel Furrer
+ * Tuesday, June 29, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Itype_exists(H5I_type_t type)
+{
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "It", type);
+
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ if(NULL == H5I_id_type_list_g[type])
+ ret_value = FALSE;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Itype_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Inmembers
+ *
+ * Purpose: Returns the number of members in a type. Public interface to
+ * H5I_nmembers. The public interface throws an error if the
+ * supplied type does not exist. This is different than the
+ * private interface, which will just return 0.
+ *
+ * Return: Success: Zero
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Nathaniel Furrer
+ * Friday, April 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Inmembers(H5I_type_t type, hsize_t *num_members)
+{
+ int ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "It*h", type, num_members);
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ /* Validate parameters. This needs to be done here, instead of letting
+ * the private interface handle it, because the public interface throws
+ * an error when the supplied type does not exist.
+ */
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ if(NULL == H5I_id_type_list_g[type])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "supplied type does not exist")
+
+ if(num_members) {
+ int64_t members;
+
+ if((members = H5I_nmembers(type)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCOUNT, FAIL, "can't compute number of members")
+
+ H5_CHECKED_ASSIGN(*num_members, hsize_t, members, int64_t);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Inmembers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_nmembers
+ *
+ * Purpose: Returns the number of members in a type.
+ *
+ * Return: Success: Number of members; zero if the type is empty
+ * or has been deleted.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 24, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+int64_t
+H5I_nmembers(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr; /* Pointer to the ID type */
+ int64_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ if(NULL == (type_ptr = H5I_id_type_list_g[type]) || type_ptr->init_count <= 0)
+ HGOTO_DONE(0);
+
+ /* Set return value */
+ H5_CHECKED_ASSIGN(ret_value, int64_t, type_ptr->id_count, uint64_t);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_nmembers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iclear_type
+ *
+ * Purpose: Removes all objects from the type, calling the free
+ * function for each object regardless of the reference count.
+ * Public interface to H5I_clear_type.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: James Laird
+ * Nathaniel Furrer
+ * Friday, April 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Iclear_type(H5I_type_t type, hbool_t force)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "Itb", type, force);
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ ret_value = H5I_clear_type(type, force, TRUE);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iclear_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_clear_type
+ *
+ * Purpose: Removes all objects from the type, calling the free
+ * function for each object regardless of the reference count.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 24, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_clear_type(H5I_type_t type, hbool_t force, hbool_t app_ref)
+{
+ H5I_clear_type_ud_t udata; /* udata struct for callback */
+ int ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ udata.type_ptr = H5I_id_type_list_g[type];
+ if(udata.type_ptr == NULL || udata.type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Finish constructing udata */
+ udata.force = force;
+ udata.app_ref = app_ref;
+
+ /* Attempt to free all ids in the type */
+ if(H5SL_try_free_safe(udata.type_ptr->ids, H5I__clear_type_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, FAIL, "can't free ids in type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_clear_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__clear_type_cb
+ *
+ * Purpose: Attempts to free the specified ID , calling the free
+ * function for the object.
+ *
+ * Return: Success: Non-negative
+ * Failure: negative
+ *
+ * Programmer: Neil Fortner
+ * Friday, July 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5I__clear_type_cb(void *_id, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5I_id_info_t *id = (H5I_id_info_t *)_id; /* Current ID being worked with */
+ H5I_clear_type_ud_t *udata = (H5I_clear_type_ud_t *)_udata; /* udata struct */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(id);
+ HDassert(udata);
+ HDassert(udata->type_ptr);
+
+ /*
+ * Do nothing to the object if the reference count is larger than
+ * one and forcing is off.
+ */
+ if(udata->force || (id->count - (!udata->app_ref * id->app_count)) <= 1) {
+ /* Check for a 'free' function and call it, if it exists */
+ /* (Casting away const OK -QAK) */
+ if(udata->type_ptr->cls->free_func && (udata->type_ptr->cls->free_func)((void *)id->obj_ptr) < 0) {
+ if(udata->force) {
+#ifdef H5I_DEBUG
+ if(H5DEBUG(I)) {
+ fprintf(H5DEBUG(I), "H5I: free type=%d obj=0x%08lx "
+ "failure ignored\n",
+ (int)udata->type_ptr->cls->type_id,
+ (unsigned long)(id->obj_ptr));
+ } /* end if */
+#endif /*H5I_DEBUG*/
+
+ /* Indicate node should be removed from list */
+ ret_value = TRUE;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Indicate node should be removed from list */
+ ret_value = TRUE;
+ } /* end else */
+
+ /* Remove ID if requested */
+ if(ret_value) {
+ /* Free ID info */
+ id = H5FL_FREE(H5I_id_info_t, id);
+
+ /* Decrement the number of IDs in the type */
+ udata->type_ptr->id_count--;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__clear_type_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Idestroy_type
+ *
+ * Purpose: Destroys a type along with all atoms in that type
+ * regardless of their reference counts. Destroying IDs
+ * involves calling the free-func for each ID's object and
+ * then adding the ID struct to the ID free list. Public
+ * interface to H5I__destroy_type.
+ *
+ * Return: Zero on success/Negative on failure
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Idestroy_type(H5I_type_t type)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "It", type);
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ ret_value = H5I__destroy_type(type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Idestroy_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__destroy_type
+ *
+ * Purpose: Destroys a type along with all atoms in that type
+ * regardless of their reference counts. Destroying IDs
+ * involves calling the free-func for each ID's object and
+ * then adding the ID struct to the ID free list.
+ *
+ * Return: Zero on success/Negative on failure
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5I__destroy_type(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr; /* ptr to the atomic type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ type_ptr = H5I_id_type_list_g[type];
+ if(type_ptr == NULL || type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Close/clear/destroy all IDs for this type */
+ H5E_BEGIN_TRY {
+ H5I_clear_type(type, TRUE, FALSE);
+ } H5E_END_TRY /*don't care about errors*/
+
+ /* Check if we should release the ID class */
+ if(type_ptr->cls->flags & H5I_CLASS_IS_APPLICATION)
+ type_ptr->cls = H5FL_FREE(H5I_class_t, (void *)type_ptr->cls);
+
+ if(H5SL_close(type_ptr->ids) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEOBJ, FAIL, "can't close skip list")
+ type_ptr->ids = NULL;
+
+ type_ptr = H5FL_FREE(H5I_id_type_t, type_ptr);
+ H5I_id_type_list_g[type] = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__destroy_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iregister
+ *
+ * Purpose: Public interface to H5I_register.
+ *
+ * Return: Success: New object id.
+ * Failure: Negative
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Iregister(H5I_type_t type, const void *object)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_API(H5I_INVALID_HID)
+ H5TRACE2("i", "It*x", type, object);
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ ret_value = H5I_register(type, object, TRUE);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register
+ *
+ * Purpose: Registers an OBJECT in a TYPE and returns an ID for it.
+ * This routine does _not_ check for unique-ness of the objects,
+ * if you register an object twice, you will get two different
+ * IDs for it. This routine does make certain that each ID in a
+ * type is unique. IDs are created by getting a unique number
+ * for the type the ID is in and incorporating the type into
+ * the ID which is returned to the user.
+ *
+ * Return: Success: New object id.
+ * Failure: Negative
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5I_register(H5I_type_t type, const void *object, hbool_t app_ref)
+{
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ H5I_id_info_t *id_ptr; /*ptr to the new ID information */
+ hid_t new_id; /*new ID */
+ hid_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ type_ptr = H5I_id_type_list_g[type];
+ if(NULL == type_ptr || type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+ if(NULL == (id_ptr = H5FL_MALLOC(H5I_id_info_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the struct & it's ID */
+ new_id = H5I_MAKE(type, type_ptr->nextid);
+ id_ptr->id = new_id;
+ id_ptr->count = 1; /*initial reference count*/
+ id_ptr->app_count = !!app_ref;
+ id_ptr->obj_ptr = object;
+
+ /* Insert into the type */
+ if(H5SL_insert(type_ptr->ids, id_ptr, &id_ptr->id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, FAIL, "can't insert ID node into skip list")
+ type_ptr->id_count++;
+ type_ptr->nextid++;
+
+ /*
+ * Sanity check for the 'nextid' getting too large and wrapping around.
+ */
+ HDassert(type_ptr->nextid <= ID_MASK);
+
+ /* Set return value */
+ ret_value = new_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register_with_id
+ *
+ * Purpose: Registers an OBJECT in a TYPE with the supplied ID for it.
+ * This routine will check to ensure the supplied ID is not already
+ * in use, and ensure that it is a valid ID for the given type,
+ * but will NOT check to ensure the OBJECT is not already
+ * registered (thus, it is possible to register one object under
+ * multiple IDs).
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Mike McGreevy
+ * Wednesday, July 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_register_with_id(H5I_type_t type, const void *object, hbool_t app_ref, hid_t id)
+{
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ H5I_id_info_t *id_ptr; /*ptr to the new ID information */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+
+ /* Make sure ID is not already in use */
+ if(NULL != (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "ID already in use?!")
+
+ /* Make sure type number is valid */
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ /* Get type pointer from list of types */
+ type_ptr = H5I_id_type_list_g[type];
+
+ if(NULL == type_ptr || type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Make sure requested ID belongs to object's type */
+ if(H5I_TYPE(id) != type)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "invalid type for provided ID")
+
+ /* Allocate new structure to house this ID */
+ if(NULL == (id_ptr = H5FL_MALLOC(H5I_id_info_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the struct & insert requested ID */
+ id_ptr->id = id;
+ id_ptr->count = 1; /*initial reference count*/
+ id_ptr->app_count = !!app_ref;
+ id_ptr->obj_ptr = object;
+
+ /* Insert into the type */
+ if(H5SL_insert(type_ptr->ids, id_ptr, &id_ptr->id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, FAIL, "can't insert ID node into skip list")
+ type_ptr->id_count++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register_with_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_subst
+ *
+ * Purpose: Substitute a new object pointer for the specified ID.
+ *
+ * Return: Success: Non-null previous object pointer associated
+ * with the specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 27, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_subst(hid_t id, const void *new_object)
+{
+ H5I_id_info_t *id_ptr; /* Pointer to the atom */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* General lookup of the ID */
+ if(NULL == (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOTFOUND, NULL, "can't get ID ref count")
+
+ /* Get the old object pointer to return */
+ /* (Casting away const OK -QAK) */
+ ret_value = (void *)id_ptr->obj_ptr;
+
+ /* Set the new object pointer for the ID */
+ id_ptr->obj_ptr = new_object;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end if */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_object
+ *
+ * Purpose: Find an object pointer for the specified ID.
+ *
+ * Return: Success: Non-null object pointer associated with the
+ * specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_object(hid_t id)
+{
+ H5I_id_info_t *id_ptr; /*ptr to the new atom */
+ void *ret_value = NULL; /*return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* General lookup of the ID */
+ if(NULL != (id_ptr = H5I__find_id(id))) {
+ /* Get the object pointer to return */
+ /* (Casting away const OK -QAK) */
+ ret_value = (void *)id_ptr->obj_ptr;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end if */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iobject_verify
+ *
+ * Purpose: Find an object pointer for the specified ID, verifying that
+ * its in a particular type. Public interface to
+ * H5I_object_verify.
+ *
+ * Return: Success: Non-null object pointer associated with the
+ * specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ * Friday, April 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5Iobject_verify(hid_t id, H5I_type_t id_type)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE2("*x", "iIt", id, id_type);
+
+ if(H5I_IS_LIB_TYPE(id_type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type")
+
+ if(id_type < 1 || id_type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "identifier has invalid type")
+
+ ret_value = H5I_object_verify(id, id_type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iobject_verify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_object_verify
+ *
+ * Purpose: Find an object pointer for the specified ID, verifying that
+ * its in a particular type.
+ *
+ * Return: Success: Non-null object pointer associated with the
+ * specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 31, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_object_verify(hid_t id, H5I_type_t id_type)
+{
+ H5I_id_info_t *id_ptr = NULL; /*ptr to the new atom */
+ void *ret_value = NULL; /*return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ HDassert(id_type >= 1 && id_type < H5I_next_type);
+
+ /* Verify that the type of the ID is correct & lookup the ID */
+ if(id_type == H5I_TYPE(id) && NULL != (id_ptr = H5I__find_id(id))) {
+ /* Get the object pointer to return */
+ /* (Casting away const OK -QAK) */
+ ret_value = (void *)id_ptr->obj_ptr;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5I_object_verify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_type
+ *
+ * Purpose: Given an object ID return the type to which it
+ * belongs. The ID need not be the ID of an object which
+ * currently exists because the type number is encoded
+ * in the object ID.
+ *
+ * Return: Success: A valid type number
+ * Failure: H5I_BADID, a negative value.
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+H5I_type_t
+H5I_get_type(hid_t id)
+{
+ H5I_type_t ret_value = H5I_BADID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ if(id > 0)
+ ret_value = H5I_TYPE(id);
+
+ HDassert(ret_value >= H5I_BADID && ret_value < H5I_next_type);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iget_type
+ *
+ * Purpose: The public version of H5I_get_type(), obtains a type number
+ * when given an ID. The ID need not be the ID of an
+ * object which currently exists because the type number is
+ * encoded as part of the ID.
+ *
+ * Return: Success: Type number
+ * Failure: H5I_BADID, a negative value
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+H5I_type_t
+H5Iget_type(hid_t id)
+{
+ H5I_type_t ret_value = H5I_BADID; /* Return value */
+
+ FUNC_ENTER_API(H5I_BADID)
+ H5TRACE1("It", "i", id);
+
+ ret_value = H5I_get_type(id);
+
+ if(ret_value <= H5I_BADID || ret_value >= H5I_next_type || NULL == H5I_object(id))
+ HGOTO_DONE(H5I_BADID);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iget_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iremove_verify
+ *
+ * Purpose: Removes the specified ID from its type, first checking that the
+ * type of the ID and the type type are the same. Public interface to
+ * H5I__remove_verify.
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Nathaniel Furrer
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5Iremove_verify(hid_t id, H5I_type_t id_type)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE2("*x", "iIt", id, id_type);
+
+ if(H5I_IS_LIB_TYPE(id_type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type")
+
+ /* Remove the id */
+ ret_value = H5I__remove_verify(id, id_type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iremove_verify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__remove_verify
+ *
+ * Purpose: Removes the specified ID from its type, first checking that
+ * the ID's type is the same as the ID type supplied as an argument
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Nat Furrer
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I__remove_verify(hid_t id, H5I_type_t id_type)
+{
+ void * ret_value = NULL; /*return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Argument checking will be performed by H5I_remove() */
+
+ /* Verify that the type of the ID is correct */
+ if(id_type == H5I_TYPE(id))
+ ret_value = H5I_remove(id);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__remove_verify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__remove_common
+ *
+ * Purpose: Common code to remove a specified ID from its type.
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * October 3, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5I__remove_common(H5I_id_type_t *type_ptr, hid_t id)
+{
+ H5I_id_info_t *curr_id; /* Pointer to the current atom */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type_ptr);
+
+ /* Get the ID node for the ID */
+ if(NULL == (curr_id = (H5I_id_info_t *)H5SL_remove(type_ptr->ids, &id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, NULL, "can't remove ID node from skip list")
+
+ /* (Casting away const OK -QAK) */
+ ret_value = (void *)curr_id->obj_ptr;
+ curr_id = H5FL_FREE(H5I_id_info_t, curr_id);
+
+ /* Decrement the number of IDs in the type */
+ (type_ptr->id_count)--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__remove_common() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_remove
+ *
+ * Purpose: Removes the specified ID from its type.
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_remove(hid_t id)
+{
+ H5I_id_type_t *type_ptr; /* Pointer to the atomic type */
+ H5I_type_t type; /* Atom's atomic type */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check arguments */
+ type = H5I_TYPE(id);
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number")
+ type_ptr = H5I_id_type_list_g[type];
+ if(type_ptr == NULL || type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid type")
+
+ /* Remove the node from the type */
+ if(NULL == (ret_value = H5I__remove_common(type_ptr, id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, NULL, "can't remove ID node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Idec_ref
+ *
+ * Purpose: Decrements the number of references outstanding for an ID.
+ * If the reference count for an ID reaches zero, the object
+ * will be closed.
+ *
+ * Return: Success: New reference count
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 7, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Idec_ref(hid_t id)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", id);
+
+ /* Check arguments */
+ if(id < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID")
+
+ /* Do actual decrement operation */
+ if((ret_value = H5I_dec_app_ref(id)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDEC, FAIL, "can't decrement ID ref count")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Idec_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_ref
+ *
+ * Purpose: Decrements the number of references outstanding for an ID.
+ * This will fail if the type is not a reference counted type.
+ * The ID type's 'free' function will be called for the ID
+ * if the reference count for the ID reaches 0 and a free
+ * function has been defined at type creation time.
+ *
+ * Return: Success: New reference count.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_ref(hid_t id)
+{
+ H5I_id_info_t *id_ptr; /* Pointer to the new ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if(NULL == (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't locate ID")
+
+ /*
+ * If this is the last reference to the object then invoke the type's
+ * free method on the object. If the free method is undefined or
+ * successful then remove the object from the type; otherwise leave
+ * the object in the type without decrementing the reference
+ * count. If the reference count is more than one then decrement the
+ * reference count without calling the free method.
+ *
+ * Beware: the free method may call other H5I functions.
+ *
+ * If an object is closing, we can remove the ID even though the free
+ * method might fail. This can happen when a mandatory filter fails to
+ * write when a dataset is closed and the chunk cache is flushed to the
+ * file. We have to close the dataset anyway. (SLU - 2010/9/7)
+ */
+ if(1 == id_ptr->count) {
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+
+ /* Get the ID's type */
+ type_ptr = H5I_id_type_list_g[H5I_TYPE(id)];
+
+ /* (Casting away const OK -QAK) */
+ if(!type_ptr->cls->free_func || (type_ptr->cls->free_func)((void *)id_ptr->obj_ptr) >= 0) {
+ /* Remove the node from the type */
+ if(NULL == H5I__remove_common(type_ptr, id))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, FAIL, "can't remove ID node")
+ ret_value = 0;
+ } /* end if */
+ else
+ ret_value = FAIL;
+ } /* end if */
+ else {
+ --(id_ptr->count);
+ ret_value = (int)id_ptr->count;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_app_ref
+ *
+ * Purpose: H5I_dec_ref wrapper for case of modifying the application ref.
+ * count for an ID as well as normal reference count.
+ *
+ * Return: Success: New app. reference count.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sept 16, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_app_ref(hid_t id)
+{
+ H5I_id_info_t *id_ptr; /* Pointer to the new ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* Call regular decrement reference count routine */
+ if((ret_value = H5I_dec_ref(id)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDEC, FAIL, "can't decrement ID ref count")
+
+ /* Check if the ID still exists */
+ if(ret_value > 0) {
+ /* General lookup of the ID */
+ if(NULL == (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't locate ID")
+
+ /* Adjust app_ref */
+ --(id_ptr->app_count);
+ HDassert(id_ptr->count >= id_ptr->app_count);
+
+ /* Set return value */
+ ret_value = (int)id_ptr->app_count;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_app_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_app_ref_always_close
+ *
+ * Purpose: H5I_dec_app_ref wrapper for case of always closing the ID,
+ * even when the free routine fails
+ *
+ * Return: Success: New app. reference count.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sept 16, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_app_ref_always_close(hid_t id)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* Call application decrement reference count routine */
+ ret_value = H5I_dec_app_ref(id);
+
+ /* Check for failure */
+ if(ret_value < 0) {
+ /*
+ * If an object is closing, we can remove the ID even though the free
+ * method might fail. This can happen when a mandatory filter fails to
+ * write when a dataset is closed and the chunk cache is flushed to the
+ * file. We have to close the dataset anyway. (SLU - 2010/9/7)
+ */
+ H5I_remove(id);
+
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDEC, FAIL, "can't decrement ID ref count")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_app_ref_always_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iinc_ref
+ *
+ * Purpose: Increments the number of references outstanding for an ID.
+ *
+ * Return: Success: New reference count
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 7, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Iinc_ref(hid_t id)
+{
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", id);
+
+ /* Check arguments */
+ if(id < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID")
+
+ /* Do actual increment operation */
+ if((ret_value = H5I_inc_ref(id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINC, FAIL, "can't increment ID ref count")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iinc_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_inc_ref
+ *
+ * Purpose: Increment the reference count for an object.
+ *
+ * Return: Success: The new reference count.
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_inc_ref(hid_t id, hbool_t app_ref)
+{
+ H5I_id_info_t *id_ptr; /* Pointer to the ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if(NULL == (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't locate ID")
+
+ /* Adjust reference counts */
+ ++(id_ptr->count);
+ if (app_ref)
+ ++(id_ptr->app_count);
+
+ /* Set return value */
+ ret_value = (int)(app_ref ? id_ptr->app_count : id_ptr->count);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_inc_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iget_ref
+ *
+ * Purpose: Retrieves the number of references outstanding for an ID.
+ *
+ * Return: Success: Reference count
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Dec 7, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Iget_ref(hid_t id)
+{
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", id);
+
+ /* Check arguments */
+ if(id < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID")
+
+ /* Do actual retrieve operation */
+ if((ret_value = H5I_get_ref(id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iget_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_ref
+ *
+ * Purpose: Retrieve the reference count for an object.
+ *
+ * Return: Success: The reference count.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, Decemeber 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_get_ref(hid_t id, hbool_t app_ref)
+{
+ H5I_id_info_t *id_ptr; /* Pointer to the ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if(NULL == (id_ptr = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't locate ID")
+
+ /* Set return value */
+ ret_value = (int)(app_ref ? id_ptr->app_count : id_ptr->count);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iinc_type_ref
+ *
+ * Purpose: Increments the number of references outstanding for an ID type.
+ *
+ * Return: Success: New reference count
+ * Failure: Negative
+ *
+ * Programmer: Nat Furrer
+ * James Laird
+ * April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Iinc_type_ref(H5I_type_t type)
+{
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "It", type);
+
+ /* Check arguments */
+ if(type <= 0 || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID type")
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ /* Do actual increment operation */
+ if((ret_value = H5I__inc_type_ref(type)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINC, FAIL, "can't increment ID type ref count")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iinc_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__inc_type_ref
+ *
+ * Purpose: Increment the reference count for an ID type.
+ *
+ * Return: Success: The new reference count.
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Nat Furrer
+ * Friday, April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__inc_type_ref(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr; /* Pointer to the type */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type > 0 && type < H5I_next_type);
+
+ /* Check arguments */
+ type_ptr = H5I_id_type_list_g[type];
+ if(!type_ptr)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Set return value */
+ ret_value = (int)(++(type_ptr->init_count));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__inc_type_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Idec_type_ref
+ *
+ * Purpose: Decrements the reference count on an entire type of IDs.
+ * If the type reference count becomes zero then the type is
+ * destroyed along with all atoms in that type regardless of
+ * their reference counts. Destroying IDs involves calling
+ * the free-func for each ID's object and then adding the ID
+ * struct to the ID free list. Public interface to
+ * H5I_dec_type_ref.
+ * Returns the number of references to the type on success; a
+ * return value of 0 means that the type will have to be
+ * re-initialized before it can be used again (and should probably
+ * be set to H5I_UNINIT).
+ *
+ * Return: Number of references to type on success/Negative on failure
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Idec_type_ref(H5I_type_t type)
+{
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "It", type);
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ ret_value = H5I_dec_type_ref(type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Idec_type_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_type_ref
+ *
+ * Purpose: Decrements the reference count on an entire type of IDs.
+ * If the type reference count becomes zero then the type is
+ * destroyed along with all atoms in that type regardless of
+ * their reference counts. Destroying IDs involves calling
+ * the free-func for each ID's object and then adding the ID
+ * struct to the ID free list.
+ * Returns the number of references to the type on success; a
+ * return value of 0 means that the type will have to be
+ * re-initialized before it can be used again (and should probably
+ * be set to H5I_UNINIT).
+ *
+ * Return: Number of references to type on success/Negative on failure
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_dec_type_ref(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr; /* Pointer to the ID type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ type_ptr = H5I_id_type_list_g[type];
+ if(type_ptr == NULL || type_ptr->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /*
+ * Decrement the number of users of the atomic type. If this is the
+ * last user of the type then release all atoms from the type and
+ * free all memory it used. The free function is invoked for each atom
+ * being freed.
+ */
+ if(1 == type_ptr->init_count) {
+ H5I__destroy_type(type);
+ ret_value = 0;
+ } /* end if */
+ else {
+ --(type_ptr->init_count);
+ ret_value = (herr_t)type_ptr->init_count;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_type_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iget_type_ref
+ *
+ * Purpose: Retrieves the number of references outstanding for a type.
+ *
+ * Return: Success: Reference count
+ * Failure: Negative
+ *
+ * Programmer: Nat Furrer
+ * James Laird
+ * April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Iget_type_ref(H5I_type_t type)
+{
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "It", type);
+
+ /* Check arguments */
+ if(type <= 0 || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID type")
+
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type")
+
+ /* Do actual retrieve operation */
+ if((ret_value = H5I__get_type_ref(type)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID type ref count")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iget_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__get_type_ref
+ *
+ * Purpose: Retrieve the reference count for an ID type.
+ *
+ * Return: Success: The reference count.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Nat Furrer
+ * James Laird
+ * April 30, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__get_type_ref(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type >= 0);
+
+ /* Check arguments */
+ type_ptr = H5I_id_type_list_g[type];
+ if(!type_ptr)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Set return value */
+ ret_value = (int)type_ptr->init_count;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__get_type_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iis_valid
+ *
+ * Purpose: Check if the given id is valid. An id is valid if it is in
+ * use and has an application reference count of at least 1.
+ *
+ * Return: Success: TRUE if the id is valid, FALSE otherwise.
+ *
+ * Failure: Negative (never fails currently)
+ *
+ * Programmer: Neil Fortner
+ * Friday, October 31, 2008 (boo)
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Iis_valid(hid_t id)
+{
+ H5I_id_info_t *id_ptr; /* ptr to the ID */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", id);
+
+ /* Find the ID */
+ if (NULL == (id_ptr = H5I__find_id(id)))
+ ret_value = FALSE;
+
+ /* Check if the found id is an internal id */
+ else if (!id_ptr->app_count)
+ ret_value = FALSE;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iis_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__search_cb
+ *
+ * Purpose: Callback routine for H5Isearch, when it calls H5I_iterate.
+ * Calls "user" callback search function, and then sets return
+ * value, based on the result of that callback.
+ *
+ * Return: Success: The first object in the type for which FUNC
+ * returns non-zero. NULL if FUNC returned zero
+ * for every object in the type.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 30, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__search_cb(void *obj, hid_t id, void *_udata)
+{
+ H5I_search_ud_t *udata = (H5I_search_ud_t *)_udata; /* User data for callback */
+ int ret_value = -1; /* Callback return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ ret_value = (*udata->app_cb)(obj, id, udata->app_key);
+ if(ret_value > 0)
+ udata->ret_obj = obj;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__search_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Isearch
+ *
+ * Purpose: Apply function FUNC to each member of type TYPE and return a
+ * pointer to the first object for which FUNC returns non-zero.
+ * The FUNC should take a pointer to the object and the KEY as
+ * arguments and return non-zero to terminate the search (zero
+ * to continue). Public interface to H5I_search.
+ *
+ * Limitation: Currently there is no way to start searching from where a
+ * previous search left off.
+ *
+ * Return: Success: The first object in the type for which FUNC
+ * returns non-zero. NULL if FUNC returned zero
+ * for every object in the type.
+ *
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Nathaniel Furrer
+ * Friday, April 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5Isearch(H5I_type_t type, H5I_search_func_t func, void *key)
+{
+ H5I_search_ud_t udata; /* Context for iteration */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE3("*x", "Itx*x", type, func, key);
+
+ /* Check arguments */
+ if(H5I_IS_LIB_TYPE(type))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type")
+
+ /* Set up udata struct */
+ udata.app_cb = func;
+ udata.app_key = key;
+ udata.ret_obj = NULL;
+
+ /* Note that H5I_iterate returns an error code. We ignore it
+ * here, as we can't do anything with it without revising the API.
+ */
+ (void)H5I_iterate(type, H5I__search_cb, &udata, TRUE);
+
+ /* Set return value */
+ ret_value = udata.ret_obj;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Isearch() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__iterate_cb
+ *
+ * Purpose: Callback routine for H5I_iterate, invokes "user" callback
+ * function, and then sets return value, based on the result of
+ * that callback.
+ *
+ * Return: Success: Non-negative on success
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, October 3, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5I_id_info_t *item = (H5I_id_info_t *)_item; /* Pointer to the ID node */
+ H5I_iterate_ud_t *udata = (H5I_iterate_ud_t *)_udata; /* User data for callback */
+ int ret_value = H5_ITER_CONT; /* Callback return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Don't make callback if app_ref is set and the appl. ref count is 0 */
+ if((!udata->app_ref) || (item->app_count > 0)) {
+ herr_t cb_ret_val;
+
+ /* (Casting away const OK) */
+ cb_ret_val = (*udata->user_func)((void *)item->obj_ptr, item->id, udata->user_udata);
+ if(cb_ret_val > 0)
+ ret_value = H5_ITER_STOP; /* terminate iteration early */
+ else if(cb_ret_val < 0)
+ ret_value = H5_ITER_ERROR; /* indicate failure (which terminates iteration) */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_iterate
+ *
+ * Purpose: Apply function FUNC to each member of type TYPE (with
+ * non-zero application reference count if app_ref is TRUE).
+ * Stop if FUNC returns a non zero value (i.e. anything
+ * other than H5_ITER_CONT).
+ *
+ * If FUNC returns a positive value (i.e. H5_ITER_STOP),
+ * return SUCCEED.
+ *
+ * If FUNC returns a negative value (i.e. H5_ITER_ERROR),
+ * return FAIL.
+ *
+ * The FUNC should take a pointer to the object and the
+ * udata as arguments and return non-zero to terminate
+ * siteration, and zero to continue.
+ *
+ * Limitation: Currently there is no way to start the iteration from
+ * where a previous iteration left off.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * Monday, December 6, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref)
+{
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ type_ptr = H5I_id_type_list_g[type];
+
+ /* Only iterate through ID list if it is initialized and there are IDs in type */
+ if(type_ptr && type_ptr->init_count > 0 && type_ptr->id_count > 0) {
+ H5I_iterate_ud_t iter_udata; /* User data for iteration callback */
+ herr_t iter_status; /* Iteration status */
+
+ /* Set up iterator user data */
+ iter_udata.user_func = func;
+ iter_udata.user_udata = udata;
+ iter_udata.app_ref = app_ref;
+
+ /* Iterate over IDs */
+ if((iter_status = H5SL_iterate(type_ptr->ids, H5I__iterate_cb, &iter_udata)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "iteration failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__find_id
+ *
+ * Purpose: Given an object ID find the info struct that describes the
+ * object.
+ *
+ * Return: Success: Ptr to the object's info struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Unknown
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5I_id_info_t *
+H5I__find_id(hid_t id)
+{
+ H5I_type_t type; /*ID's type */
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ H5I_id_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ type = H5I_TYPE(id);
+ if(type <= H5I_BADID || type >= H5I_next_type)
+ HGOTO_DONE(NULL)
+
+ type_ptr = H5I_id_type_list_g[type];
+ if(!type_ptr || type_ptr->init_count <= 0)
+ HGOTO_DONE(NULL)
+
+ /* Locate the ID node for the ID */
+ ret_value = (H5I_id_info_t *)H5SL_search(type_ptr->ids, &id);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__find_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iget_name
+ *
+ * Purpose: Gets a name of an object from its ID.
+ *
+ * Return: Success: The length of name.
+ *
+ * Failure: -1
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ *
+ * Date: July 26, 2002
+ *
+ * Comments: Public function
+ * If `name' is non-NULL then write up to `size' bytes into that
+ * buffer and always return the length of the entry name.
+ * Otherwise `size' is ignored and the function does not store the name,
+ * just returning the number of characters required to store the name.
+ * If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
+ * is unchanged and the function returns a negative value.
+ * If a zero is returned for the name's length, then there is no name
+ * associated with the ID.
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Iget_name(hid_t id, char *name/*out*/, size_t size)
+{
+ H5G_loc_t loc; /* Object location */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "ixz", id, name, size);
+
+ /* Get object location */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't retrieve object location")
+
+ /* Call internal group routine to retrieve object's name */
+ if((ret_value = H5G_get_name(&loc, name, size, NULL, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't retrieve object name")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iget_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Iget_file_id
+ *
+ * Purpose: The public version of H5I_get_file_id(), obtains the file
+ * ID given an object ID. User has to close this ID.
+ *
+ * Return: Success: file ID
+ *
+ * Failure: a negative value
+ *
+ * Programmer: Raymond Lu
+ * Oct 27, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Iget_file_id(hid_t obj_id)
+{
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", obj_id);
+
+ if((ret_value = H5I_get_file_id(obj_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't retrieve file ID")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Iget_file_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_file_id
+ *
+ * Purpose: The private version of H5Iget_file_id(), obtains the file
+ * ID given an object ID.
+ *
+ * Return: Success: file ID
+ * Failure: a negative value
+ *
+ * Programmer: Raymond Lu
+ * Oct 27, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5I_get_file_id(hid_t obj_id, hbool_t app_ref)
+{
+ H5I_type_t type; /* ID type */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get object type */
+ type = H5I_TYPE(obj_id);
+ if(type == H5I_FILE) {
+ /* Increment reference count on file ID */
+ if(H5I_inc_ref(obj_id, app_ref) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTSET, FAIL, "incrementing file ID failed")
+
+ /* Set return value */
+ ret_value = obj_id;
+ } /* end if */
+ else if(type == H5I_DATATYPE || type == H5I_GROUP || type == H5I_DATASET || type == H5I_ATTR) {
+ H5G_loc_t loc; /* Location of object */
+
+ /* Get the object location information */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get object location")
+
+ /* Get the file ID for the object */
+ if((ret_value = H5F_get_id(loc.oloc->file, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get file ID")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid object ID")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_file_id() */
+
+#ifdef H5I_DEBUG_OUTPUT
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__debug_cb
+ *
+ * Purpose: Dump the contents of an ID to stderr for debugging.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5I__debug_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5I_id_info_t *item = (H5I_id_info_t *)_item; /* Pointer to the ID node */
+ H5I_type_t type = *(H5I_type_t *)_udata; /* User data */
+ H5G_name_t *path = NULL;
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ fprintf(stderr, " id = %lu\n", (unsigned long)(item->id));
+ fprintf(stderr, " count = %u\n", item->count);
+ fprintf(stderr, " obj = 0x%08lx\n", (unsigned long)(item->obj_ptr));
+
+ /* Get the group location, so we get get the name */
+ switch(type) {
+ case H5I_GROUP:
+ path = H5G_nameof((H5G_t*)item->obj_ptr);
+ break;
+
+ case H5I_DATASET:
+ path = H5D_nameof((H5D_t*)item->obj_ptr);
+ break;
+
+ case H5I_DATATYPE:
+ path = H5T_nameof((H5T_t*)item->obj_ptr);
+ break;
+
+ default:
+ break; /* Other types of IDs are not stored in files */
+ } /* end switch*/
+
+ if(path) {
+ if(path->user_path_r)
+ fprintf(stderr, " user_path = %s\n", H5RS_get_str(path->user_path_r));
+ if(path->full_path_r)
+ fprintf(stderr, " full_path = %s\n", H5RS_get_str(path->full_path_r));
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5I__debug_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__debug
+ *
+ * Purpose: Dump the contents of a type to stderr for debugging.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5I__debug(H5I_type_t type)
+{
+ H5I_id_type_t *type_ptr;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ fprintf(stderr, "Dumping ID type %d\n", (int)type);
+ type_ptr = H5I_id_type_list_g[type];
+
+ /* Header */
+ fprintf(stderr, " init_count = %u\n", type_ptr->init_count);
+ fprintf(stderr, " reserved = %u\n", type_ptr->cls->reserved);
+ fprintf(stderr, " id_count = %llu\n", (unsigned long long)type_ptr->id_count);
+ fprintf(stderr, " nextid = %llu\n", (unsigned long long)type_ptr->nextid);
+
+ /* List */
+ fprintf(stderr, " List:\n");
+ H5SL_iterate(type_ptr->ids, H5I__debug_cb, &type);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5I__debug() */
+#endif /* H5I_DEBUG_OUTPUT */
+
diff --git a/src/H5Imodule.h b/src/H5Imodule.h
new file mode 100644
index 0000000..60bda5a
--- /dev/null
+++ b/src/H5Imodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5I package. Including this header means that the source file
+ * is part of the H5I package.
+ */
+#ifndef _H5Imodule_H
+#define _H5Imodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5I_MODULE
+#define H5_MY_PKG H5I
+#define H5_MY_PKG_ERR H5E_ATOM
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5Imodule_H */
+
diff --git a/src/H5Ipkg.h b/src/H5Ipkg.h
new file mode 100644
index 0000000..16d7d67
--- /dev/null
+++ b/src/H5Ipkg.h
@@ -0,0 +1,74 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, May 15, 2003
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5I package. Source files outside the H5I package should
+ * include H5Iprivate.h instead.
+ */
+#if !(defined H5I_FRIEND || defined H5I_MODULE)
+#error "Do not include this file outside the H5I package!"
+#endif
+
+#ifndef _H5Ipkg_H
+#define _H5Ipkg_H
+
+/* Get package's private header */
+#include "H5Iprivate.h"
+
+/* Other private headers needed by this file */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/*
+ * Number of bits to use for ID Type in each atom. Increase if more types
+ * are needed (though this will decrease the number of available IDs per
+ * type). This is the only number that must be changed since all other bit
+ * field sizes and masks are calculated from TYPE_BITS.
+ */
+#define TYPE_BITS 7
+#define TYPE_MASK (((hid_t)1 << TYPE_BITS) - 1)
+
+#define H5I_MAX_NUM_TYPES TYPE_MASK
+
+/*
+ * Number of bits to use for the Atom index in each atom (assumes 8-bit
+ * bytes). We don't use the sign bit.
+ */
+#define ID_BITS ((sizeof(hid_t) * 8) - (TYPE_BITS + 1))
+#define ID_MASK (((hid_t)1 << ID_BITS) - 1)
+
+/* Map an atom to an ID type number */
+#define H5I_TYPE(a) ((H5I_type_t)(((hid_t)(a) >> ID_BITS) & TYPE_MASK))
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Testing functions */
+#ifdef H5I_TESTING
+H5_DLL ssize_t H5I_get_name_test(hid_t id, char *name/*out*/, size_t size,
+ hbool_t *cached);
+#endif /* H5I_TESTING */
+
+#endif /*_H5Ipkg_H*/
diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h
new file mode 100644
index 0000000..25cea4f
--- /dev/null
+++ b/src/H5Iprivate.h
@@ -0,0 +1,86 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-----------------------------------------------------------------------------
+ * File: H5Iprivate.h
+ * Purpose: header file for ID API
+ *---------------------------------------------------------------------------*/
+
+/* avoid re-inclusion */
+#ifndef _H5Iprivate_H
+#define _H5Iprivate_H
+
+/* Include package's public header */
+#include "H5Ipublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h"
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Macro to determine if a H5I_type_t is a "library type" */
+#define H5I_IS_LIB_TYPE( type ) (type > 0 && type < H5I_NTYPES)
+
+/* Flags for ID class */
+#define H5I_CLASS_IS_APPLICATION 0x01
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+typedef struct H5I_class_t {
+ H5I_type_t type_id; /* Class ID for the type */
+ unsigned flags; /* Class behavior flags */
+ unsigned reserved; /* Number of reserved IDs for this type */
+ /* [A specific number of type entries may be
+ * reserved to enable "constant" values to be
+ * handed out which are valid IDs in the type,
+ * but which do not map to any data structures
+ * and are not allocated dynamically later.]
+ */
+ H5I_free_t free_func; /* Free function for object's of this type */
+} H5I_class_t;
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+H5_DLL herr_t H5I_register_type(const H5I_class_t *cls);
+H5_DLL int64_t H5I_nmembers(H5I_type_t type);
+H5_DLL herr_t H5I_clear_type(H5I_type_t type, hbool_t force, hbool_t app_ref);
+H5_DLL hid_t H5I_register(H5I_type_t type, const void *object, hbool_t app_ref);
+H5_DLL herr_t H5I_register_with_id(H5I_type_t type, const void *object, hbool_t app_ref, hid_t id);
+H5_DLL void *H5I_subst(hid_t id, const void *new_object);
+H5_DLL void *H5I_object(hid_t id);
+H5_DLL void *H5I_object_verify(hid_t id, H5I_type_t id_type);
+H5_DLL H5I_type_t H5I_get_type(hid_t id);
+H5_DLL hid_t H5I_get_file_id(hid_t obj_id, hbool_t app_ref);
+H5_DLL void *H5I_remove(hid_t id);
+H5_DLL herr_t H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref);
+H5_DLL int H5I_get_ref(hid_t id, hbool_t app_ref);
+H5_DLL int H5I_inc_ref(hid_t id, hbool_t app_ref);
+H5_DLL int H5I_dec_ref(hid_t id);
+H5_DLL int H5I_dec_app_ref(hid_t id);
+H5_DLL int H5I_dec_app_ref_always_close(hid_t id);
+H5_DLL herr_t H5I_dec_type_ref(H5I_type_t type);
+
+#endif /* _H5Iprivate_H */
+
diff --git a/src/H5Ipublic.h b/src/H5Ipublic.h
new file mode 100644
index 0000000..896f82f
--- /dev/null
+++ b/src/H5Ipublic.h
@@ -0,0 +1,102 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains function prototypes for each exported function in
+ * the H5I module.
+ */
+#ifndef _H5Ipublic_H
+#define _H5Ipublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/*
+ * Library type values. Start with `1' instead of `0' because it makes the
+ * tracing output look better when hid_t values are large numbers. Change the
+ * TYPE_BITS in H5I.c if the MAXID gets larger than 32 (an assertion will
+ * fail otherwise).
+ *
+ * When adding types here, add a section to the 'misc19' test in test/tmisc.c
+ * to verify that the H5I{inc|dec|get}_ref() routines work correctly with in.
+ *
+ */
+typedef enum H5I_type_t {
+ H5I_UNINIT = (-2), /*uninitialized type */
+ H5I_BADID = (-1), /*invalid Type */
+ H5I_FILE = 1, /*type ID for File objects */
+ H5I_GROUP, /*type ID for Group objects */
+ H5I_DATATYPE, /*type ID for Datatype objects */
+ H5I_DATASPACE, /*type ID for Dataspace objects */
+ H5I_DATASET, /*type ID for Dataset objects */
+ H5I_ATTR, /*type ID for Attribute objects */
+ H5I_REFERENCE, /*type ID for Reference objects */
+ H5I_VFL, /*type ID for virtual file layer */
+ H5I_GENPROP_CLS, /*type ID for generic property list classes */
+ H5I_GENPROP_LST, /*type ID for generic property lists */
+ H5I_ERROR_CLASS, /*type ID for error classes */
+ H5I_ERROR_MSG, /*type ID for error messages */
+ H5I_ERROR_STACK, /*type ID for error stacks */
+ H5I_NTYPES /*number of library types, MUST BE LAST! */
+} H5I_type_t;
+
+/* Type of atoms to return to users */
+typedef int64_t hid_t;
+#define H5_SIZEOF_HID_T H5_SIZEOF_INT64_T
+
+/* An invalid object ID. This is also negative for error return. */
+#define H5I_INVALID_HID (-1)
+
+/*
+ * Function for freeing objects. This function will be called with an object
+ * ID type number and a pointer to the object. The function should free the
+ * object and return non-negative to indicate that the object
+ * can be removed from the ID type. If the function returns negative
+ * (failure) then the object will remain in the ID type.
+ */
+typedef herr_t (*H5I_free_t)(void*);
+
+/* Type of the function to compare objects & keys */
+typedef int (*H5I_search_func_t)(void *obj, hid_t id, void *key);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public API functions */
+
+H5_DLL hid_t H5Iregister(H5I_type_t type, const void *object);
+H5_DLL void *H5Iobject_verify(hid_t id, H5I_type_t id_type);
+H5_DLL void *H5Iremove_verify(hid_t id, H5I_type_t id_type);
+H5_DLL H5I_type_t H5Iget_type(hid_t id);
+H5_DLL hid_t H5Iget_file_id(hid_t id);
+H5_DLL ssize_t H5Iget_name(hid_t id, char *name/*out*/, size_t size);
+H5_DLL int H5Iinc_ref(hid_t id);
+H5_DLL int H5Idec_ref(hid_t id);
+H5_DLL int H5Iget_ref(hid_t id);
+H5_DLL H5I_type_t H5Iregister_type(size_t hash_size, unsigned reserved, H5I_free_t free_func);
+H5_DLL herr_t H5Iclear_type(H5I_type_t type, hbool_t force);
+H5_DLL herr_t H5Idestroy_type(H5I_type_t type);
+H5_DLL int H5Iinc_type_ref(H5I_type_t type);
+H5_DLL int H5Idec_type_ref(H5I_type_t type);
+H5_DLL int H5Iget_type_ref(H5I_type_t type);
+H5_DLL void *H5Isearch(H5I_type_t type, H5I_search_func_t func, void *key);
+H5_DLL herr_t H5Inmembers(H5I_type_t type, hsize_t *num_members);
+H5_DLL htri_t H5Itype_exists(H5I_type_t type);
+H5_DLL htri_t H5Iis_valid(hid_t id);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Ipublic_H */
+
diff --git a/src/H5Itest.c b/src/H5Itest.c
new file mode 100644
index 0000000..e7bd2a7
--- /dev/null
+++ b/src/H5Itest.c
@@ -0,0 +1,96 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgoup.org>
+ * Tuesday, July 27, 2010
+ *
+ * Purpose: ID testing functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Imodule.h" /* This source code file is part of the H5I module */
+#define H5I_TESTING /*suppress warning about H5I testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Ipkg.h" /* IDs */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_name_test
+ *
+ * Purpose: Testing version of H5Iget_name()
+ *
+ * Return: Success: The length of name.
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 27, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5I_get_name_test(hid_t id, char *name/*out*/, size_t size, hbool_t *cached)
+{
+ H5G_loc_t loc; /* Object location */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't retrieve object location")
+
+ /* Call internal group routine to retrieve object's name */
+ if((ret_value = H5G_get_name(&loc, name, size, cached, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't retrieve object name")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_name_test() */
+
diff --git a/src/H5L.c b/src/H5L.c
new file mode 100644
index 0000000..469a86c
--- /dev/null
+++ b/src/H5L.c
@@ -0,0 +1,3297 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Lmodule.h" /* This source code file is part of the H5L module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lpkg.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* File objects */
+#include "H5Pprivate.h" /* Property lists */
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5L_MIN_TABLE_SIZE 32 /* Minimum size of the user-defined link type table if it is allocated */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for path traversal routine for getting link info by name */
+typedef struct {
+ H5L_info_t *linfo; /* Buffer to return to user */
+ hid_t dxpl_id; /* DXPL to use in callback */
+} H5L_trav_gi_t;
+
+/* User data for path traversal routine for getting link info by index */
+typedef struct {
+ /* In */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Order to iterate in index */
+ hsize_t n; /* Offset of link within index */
+ hid_t dxpl_id; /* DXPL to use in callback */
+
+ /* Out */
+ H5L_info_t *linfo; /* Buffer to return to user */
+} H5L_trav_gibi_t;
+
+/* User data for path traversal callback to creating a link */
+typedef struct {
+ H5F_t *file; /* Pointer to the file */
+ H5P_genplist_t *lc_plist; /* Link creation property list */
+ hid_t dxpl_id; /* Dataset transfer property list */
+ H5G_name_t *path; /* Path to object being linked */
+ H5O_obj_create_t *ocrt_info; /* Pointer to object creation info */
+ H5O_link_t *lnk; /* Pointer to link information to insert */
+} H5L_trav_cr_t;
+
+/* User data for path traversal routine for moving and renaming a link */
+typedef struct {
+ const char *dst_name; /* Destination name for moving object */
+ H5T_cset_t cset; /* Char set for new name */
+ H5G_loc_t *dst_loc; /* Destination location for moving object */
+ unsigned dst_target_flags; /* Target flags for destination object */
+ hbool_t copy; /* TRUE if this is a copy operation */
+ hid_t lapl_id; /* LAPL to use in callback */
+ hid_t dxpl_id; /* DXPL to use in callback */
+} H5L_trav_mv_t;
+
+/* User data for path traversal routine for moving and renaming an object */
+typedef struct {
+ H5F_t *file; /* Pointer to the file */
+ H5O_link_t *lnk; /* Pointer to link information to insert */
+ hbool_t copy; /* TRUE if this is a copy operation */
+ hid_t dxpl_id; /* Dataset transfer property list */
+} H5L_trav_mv2_t;
+
+/* User data for path traversal routine for checking if a link exists */
+typedef struct {
+ /* Down */
+ char *sep; /* Pointer to next separator in the string */
+ hid_t lapl_id; /* Link access property list */
+ hid_t dxpl_id; /* Dataset transfer property list */
+
+ /* Up */
+ hbool_t exists; /* Whether the link exists or not */
+} H5L_trav_le_t;
+
+/* User data for path traversal routine for getting link value */
+typedef struct {
+ size_t size; /* Size of user buffer */
+ void *buf; /* User buffer */
+} H5L_trav_gv_t;
+
+/* User data for path traversal routine for getting link value by index */
+typedef struct {
+ /* In */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Order to iterate in index */
+ hsize_t n; /* Offset of link within index */
+ hid_t dxpl_id; /* DXPL to use in callback */
+ size_t size; /* Size of user buffer */
+
+ /* Out */
+ void *buf; /* User buffer */
+} H5L_trav_gvbi_t;
+
+/* User data for path traversal routine for removing link */
+typedef struct {
+ hid_t dxpl_id; /* DXPL to use in callback */
+} H5L_trav_rm_t;
+
+/* User data for path traversal routine for removing link by index */
+typedef struct {
+ /* In */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Order to iterate in index */
+ hsize_t n; /* Offset of link within index */
+ hid_t dxpl_id; /* DXPL to use in callback */
+} H5L_trav_rmbi_t;
+
+/* User data for path traversal routine for getting name by index */
+typedef struct {
+ /* In */
+ H5_index_t idx_type; /* Index to use */
+ H5_iter_order_t order; /* Order to iterate in index */
+ hsize_t n; /* Offset of link within index */
+ size_t size; /* Size of name buffer */
+ hid_t dxpl_id; /* DXPL to use in callback */
+
+ /* Out */
+ char *name; /* Buffer to return name to user */
+ ssize_t name_len; /* Length of full name */
+} H5L_trav_gnbi_t;
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static int H5L_find_class_idx(H5L_type_t id);
+static herr_t H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_create_real(const H5G_loc_t *link_loc, const char *link_name,
+ H5G_name_t *obj_path, H5F_t *obj_file, H5O_link_t *lnk, H5O_obj_create_t *ocrt_info,
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5L_get_val_real(const H5O_link_t *lnk, void *buf, size_t size);
+static herr_t H5L_get_val_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_get_val_by_idx_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_delete_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_delete_by_idx_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_move_dest_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L__exists_final_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L__exists_inter_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static htri_t H5L__exists(const H5G_loc_t *loc, const char *name, hid_t lapl_id,
+ hid_t dxpl_id);
+static herr_t H5L_get_info_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_get_info_by_idx_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5L_get_name_by_idx_cb(H5G_loc_t *grp_loc/*in*/,
+ const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Information about user-defined links */
+static size_t H5L_table_alloc_g = 0;
+static size_t H5L_table_used_g = 0;
+static H5L_class_t *H5L_table_g = NULL;
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_init
+ *
+ * Purpose: Initialize the interface from some other package.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: James Laird
+ * Thursday, July 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L__init_package
+ *
+ * Purpose: Initialize information specific to H5L interface.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, January 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Initialize user-defined link classes */
+ if(H5L_register_external() < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register external link class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_term_package
+ *
+ * Purpose: Terminate any resources allocated in H5L__init_package.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, January 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5L_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Free the table of link types */
+ if(H5L_table_g) {
+ H5L_table_g = (H5L_class_t *)H5MM_xfree(H5L_table_g);
+ H5L_table_used_g = H5L_table_alloc_g = 0;
+ n++;
+ } /* end if */
+
+ /* Mark the interface as uninitialized */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* H5L_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lmove
+ *
+ * Purpose: Renames an object within an HDF5 file and moves it to a new
+ * group. The original name SRC is unlinked from the group graph
+ * and then inserted with the new name DST (which can specify a
+ * new path for the object) as an atomic operation. The names
+ * are interpreted relative to SRC_LOC_ID and
+ * DST_LOC_ID, which are either file IDs or group ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, March 29, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t src_loc, *src_loc_p;
+ H5G_loc_t dst_loc, *dst_loc_p;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name, lcpl_id,
+ lapl_id);
+
+ /* Check arguments */
+ if(src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not both be H5L_SAME_LOC")
+ if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(dst_loc_id != H5L_SAME_LOC && H5G_loc(dst_loc_id, &dst_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!src_name || !*src_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!dst_name || !*dst_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified")
+ if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id,
+ ((src_loc_id != H5L_SAME_LOC) ? src_loc_id : dst_loc_id),
+ TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up src & dst location pointers */
+ src_loc_p = &src_loc;
+ dst_loc_p = &dst_loc;
+ if(src_loc_id == H5L_SAME_LOC)
+ src_loc_p = dst_loc_p;
+ else if(dst_loc_id == H5L_SAME_LOC)
+ dst_loc_p = src_loc_p;
+
+ /* Move the link */
+ if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, FALSE, lcpl_id,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTMOVE, FAIL, "unable to move link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lmove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcopy
+ *
+ * Purpose: Creates an identical copy of a link with the same creation
+ * time and target. The new link can have a different name
+ * and be in a different location than the original.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, March 29, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t src_loc, *src_loc_p;
+ H5G_loc_t dst_loc, *dst_loc_p;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name, lcpl_id,
+ lapl_id);
+
+ /* Check arguments */
+ if(src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not both be H5L_SAME_LOC")
+ if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(dst_loc_id != H5L_SAME_LOC && H5G_loc(dst_loc_id, &dst_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!src_name || !*src_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!dst_name || !*dst_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified")
+ if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id,
+ ((src_loc_id != H5L_SAME_LOC) ? src_loc_id : dst_loc_id),
+ TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up src & dst location pointers */
+ src_loc_p = &src_loc;
+ dst_loc_p = &dst_loc;
+ if(src_loc_id == H5L_SAME_LOC)
+ src_loc_p = dst_loc_p;
+ else if(dst_loc_id == H5L_SAME_LOC)
+ dst_loc_p = src_loc_p;
+
+ /* Copy the link */
+ if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, TRUE, lcpl_id,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTMOVE, FAIL, "unable to move link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lcopy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcreate_soft
+ *
+ * Purpose: Creates a soft link from LINK_NAME to LINK_TARGET.
+ *
+ * LINK_TARGET can be anything and is interpreted at lookup
+ * time relative to the group which contains the final component
+ * of LINK_NAME. For instance, if LINK_TARGET is `./foo' and
+ * LINK_NAME is `./x/y/bar' and a request is made for `./x/y/bar'
+ * then the actual object looked up is `./x/y/./foo'.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcreate_soft(const char *link_target,
+ hid_t link_loc_id, const char *link_name, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t link_loc; /* Group location for new link */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*si*sii", link_target, link_loc_id, link_name, lcpl_id, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(link_loc_id, &link_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!link_target || !*link_target)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no target specified")
+ if(!link_name || !*link_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified")
+ if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, link_loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Create the link */
+ if(H5L_create_soft(link_target, &link_loc, link_name, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lcreate_soft() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcreate_hard
+ *
+ * Purpose: Creates a hard link from NEW_NAME to CUR_NAME.
+ *
+ * CUR_NAME must name an existing object. CUR_NAME and
+ * NEW_NAME are interpreted relative to CUR_LOC_ID and
+ * NEW_LOC_ID, which are either file IDs or group IDs.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcreate_hard(hid_t cur_loc_id, const char *cur_name,
+ hid_t new_loc_id, const char *new_name, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t cur_loc, *cur_loc_p;
+ H5G_loc_t new_loc, *new_loc_p;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*si*sii", cur_loc_id, cur_name, new_loc_id, new_name, lcpl_id,
+ lapl_id);
+
+ /* Check arguments */
+ if(cur_loc_id == H5L_SAME_LOC && new_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not be both H5L_SAME_LOC")
+ if(cur_loc_id != H5L_SAME_LOC && H5G_loc(cur_loc_id, &cur_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(new_loc_id != H5L_SAME_LOC && H5G_loc(new_loc_id, &new_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!cur_name || !*cur_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified")
+ if(!new_name || !*new_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified")
+ if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, cur_loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up current & new location pointers */
+ cur_loc_p = &cur_loc;
+ new_loc_p = &new_loc;
+ if(cur_loc_id == H5L_SAME_LOC)
+ cur_loc_p = new_loc_p;
+ else if(new_loc_id == H5L_SAME_LOC)
+ new_loc_p = cur_loc_p;
+ else if(cur_loc_p->oloc->file != new_loc_p->oloc->file)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should be in the same file.")
+
+ /* Create the link */
+ if(H5L_create_hard(cur_loc_p, cur_name, new_loc_p, new_name,
+ lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lcreate_hard() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcreate_ud
+ *
+ * Purpose: Creates a user-defined link of type LINK_TYPE named LINK_NAME
+ * with user-specified data UDATA.
+ *
+ * The format of the information pointed to by UDATA is
+ * defined by the user. UDATA_SIZE holds the size of this buffer.
+ *
+ * LINK_NAME is interpreted relative to LINK_LOC_ID.
+ *
+ * The property list specified by LCPL_ID holds properties used
+ * to create the link.
+ *
+ * The link class of the new link must already be registered
+ * with the library.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, December 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcreate_ud(hid_t link_loc_id, const char *link_name, H5L_type_t link_type,
+ const void *udata, size_t udata_size, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t link_loc;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sLl*xzii", link_loc_id, link_name, link_type, udata,
+ udata_size, lcpl_id, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(link_loc_id, &link_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!link_name || !*link_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no link name specified")
+ if(link_type < H5L_TYPE_UD_MIN || link_type > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link class")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, link_loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Create external link */
+ if(H5L_create_ud(&link_loc, link_name, udata, udata_size, link_type, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lcreate_ud() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ldelete
+ *
+ * Purpose: Removes the specified NAME from the group graph and
+ * decrements the link count for the object to which NAME
+ * points. If the link count reaches zero then all file-space
+ * associated with the object will be reclaimed (but if the
+ * object is open, then the reclamation of the file space is
+ * delayed until all handles to the object are closed).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ldelete(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Group's location */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*si", loc_id, name, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Unlink */
+ if(H5L_delete(&loc, name, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL, "unable to delete link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ldelete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ldelete_by_idx
+ *
+ * Purpose: Removes the specified link from the group graph and
+ * decrements the link count for the object to which it
+ * points, according to the order within an index.
+ *
+ * If the link count reaches zero then all file-space
+ * associated with the object will be reclaimed (but if the
+ * object is open, then the reclamation of the file space is
+ * delayed until all handles to the object are closed).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ldelete_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Group's location */
+ H5L_trav_rmbi_t udata; /* User data for callback */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*sIiIohi", loc_id, group_name, idx_type, order, n, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up user data for unlink operation */
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.n = n;
+ udata.dxpl_id = dxpl_id;
+
+ /* Traverse the group hierarchy to remove the link */
+ if(H5G_traverse(&loc, group_name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK|H5G_TARGET_MOUNT,
+ H5L_delete_by_idx_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ldelete_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lget_val
+ *
+ * Purpose: Returns the link value of a link whose name is NAME. For
+ * symbolic links, this is the path to which the link points,
+ * including the null terminator. For user-defined links, it
+ * is the link buffer.
+ *
+ * At most SIZE bytes are copied to the BUF result buffer.
+ *
+ * Return: Success: Non-negative with the link value in BUF.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lget_val(hid_t loc_id, const char *name, void *buf/*out*/, size_t size,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Group location for location to query */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*sxzi", loc_id, name, buf, size, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Get the link value */
+ if(H5L_get_val(&loc, name, buf, size, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link value for '%s'", name)
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lget_val() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lget_val_by_idx
+ *
+ * Purpose: Returns the link value of a link, according to the order of
+ * an index. For symbolic links, this is the path to which the
+ * link points, including the null terminator. For user-defined
+ * links, it is the link buffer.
+ *
+ * At most SIZE bytes are copied to the BUF result buffer.
+ *
+ * Return: Success: Non-negative with the link value in BUF.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 13, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lget_val_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, void *buf/*out*/, size_t size,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Group location for location to query */
+ H5L_trav_gvbi_t udata; /* User data for callback */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("e", "i*sIiIohxzi", loc_id, group_name, idx_type, order, n, buf, size,
+ lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up user data for retrieving information */
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.n = n;
+ udata.dxpl_id = dxpl_id;
+ udata.buf = buf;
+ udata.size = size;
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ if(H5G_traverse(&loc, group_name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L_get_val_by_idx_cb,
+ &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lget_val_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lexists
+ *
+ * Purpose: Checks if a link of a given name exists in a group
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 16, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Lexists(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+ H5G_loc_t loc;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ htri_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("t", "i*si", loc_id, name, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Check for the existence of the link */
+ if((ret_value = H5L__exists(&loc, name, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lexists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lget_info
+ *
+ * Purpose: Gets metadata for a link.
+ *
+ * Return: Success: Non-negative with information in LINFO
+ *
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Wednesday, June 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lget_info(hid_t loc_id, const char *name, H5L_info_t *linfo /*out*/,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*sxi", loc_id, name, linfo, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Get the link information */
+ if(H5L_get_info(&loc, name, linfo, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "unable to get link info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lget_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lget_info_by_idx
+ *
+ * Purpose: Gets metadata for a link, according to the order within an
+ * index.
+ *
+ * Return: Success: Non-negative with information in LINFO
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lget_info_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ H5L_info_t *linfo /*out*/, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Group location for group to query */
+ H5L_trav_gibi_t udata; /* User data for callback */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIohxi", loc_id, group_name, idx_type, order, n, linfo,
+ lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up user data for callback */
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.n = n;
+ udata.dxpl_id = dxpl_id;
+ udata.linfo = linfo;
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ if(H5G_traverse(&loc, group_name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK,
+ H5L_get_info_by_idx_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "unable to get link info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lget_info_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lregister
+ *
+ * Purpose: Registers a class of user-defined links, or changes the
+ * behavior of an existing class.
+ *
+ * The link class passed in will override any existing link
+ * class for the specified link class ID. It must at least
+ * include a H5L_class_t version (which should be
+ * H5L_LINK_CLASS_T_VERS), a link class ID, and a traversal
+ * function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lregister(const H5L_class_t *cls)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*x", cls);
+
+ /* Check args */
+ if(cls == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link class")
+
+ /* Check H5L_class_t version number; this is where a function to convert
+ * from an outdated version should be called.
+ */
+ if(cls->version != H5L_LINK_CLASS_T_VERS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5L_class_t version number")
+
+ if(cls->id < H5L_TYPE_UD_MIN || cls->id > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link identification number")
+ if(cls->trav_func == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no traversal function specified")
+
+ /* Do it */
+ if(H5L_register(cls) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lunregister
+ *
+ * Purpose: Unregisters a class of user-defined links, preventing them
+ * from being traversed, queried, moved, etc.
+ *
+ * A link class can be re-registered using H5Lregister().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lunregister(H5L_type_t id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "Ll", id);
+
+ /* Check args */
+ if(id < 0 || id > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link type")
+
+ /* Do it */
+ if(H5L_unregister(id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to unregister link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lunregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lis_registered
+ *
+ * Purpose: Tests whether a user-defined link class has been registered
+ * or not.
+ *
+ * Return: Positive if the link class has been registered
+ * Zero if it is unregistered
+ * Negative on error (if the class is not a valid UD class ID)
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Lis_registered(H5L_type_t id)
+{
+ size_t i; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "Ll", id);
+
+ /* Check args */
+ if(id < 0 || id > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link type id number")
+
+ /* Is the link class already registered? */
+ for(i = 0; i < H5L_table_used_g; i++)
+ if(H5L_table_g[i].id == id) {
+ ret_value = TRUE;
+ break;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lis_registered() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lget_name_by_idx
+ *
+ * Purpose: Gets name for a link, according to the order within an
+ * index.
+ *
+ * Same pattern of behavior as H5Iget_name.
+ *
+ * Return: Success: Non-negative length of name, with information
+ * in NAME buffer
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Lget_name_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ char *name /*out*/, size_t size, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ H5L_trav_gnbi_t udata; /* User data for callback */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("Zs", "i*sIiIohxzi", loc_id, group_name, idx_type, order, n, name, size,
+ lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up user data for callback */
+ udata.idx_type = idx_type;
+ udata.order = order;
+ udata.n = n;
+ udata.dxpl_id = dxpl_id;
+ udata.name = name;
+ udata.size = size;
+ udata.name_len = -1;
+
+ /* Traverse the group hierarchy to locate the link to get name of */
+ if(H5G_traverse(&loc, group_name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK,
+ H5L_get_name_by_idx_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_EXISTS, FAIL, "name doesn't exist")
+
+ /* Set the return value */
+ ret_value = udata.name_len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lget_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Literate
+ *
+ * Purpose: Iterates over links in a group, with user callback routine,
+ * according to the order within an index.
+ *
+ * Same pattern of behavior as H5Giterate.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Literate(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order,
+ hsize_t *idx_p, H5L_iterate_t op, void *op_data)
+{
+ H5I_type_t id_type; /* Type of ID */
+ H5G_link_iterate_t lnk_op; /* Link operator */
+ hsize_t last_lnk; /* Index of last object looked at */
+ hsize_t idx; /* Internal location to hold index */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iIiIo*hx*x", grp_id, idx_type, order, idx_p, op, op_data);
+
+ /* Check arguments */
+ id_type = H5I_get_type(grp_id);
+ if(!(H5I_GROUP == id_type || H5I_FILE == id_type))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified")
+
+ /* Set up iteration beginning/end info */
+ idx = (idx_p == NULL ? 0 : *idx_p);
+ last_lnk = 0;
+
+ /* Build link operator info */
+ lnk_op.op_type = H5G_LINK_OP_NEW;
+ lnk_op.op_func.op_new = op;
+
+ /* Iterate over the links */
+ if((ret_value = H5G_iterate(grp_id, ".", idx_type, order, idx, &last_lnk, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "link iteration failed")
+
+ /* Set the index we stopped at */
+ if(idx_p)
+ *idx_p = last_lnk;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Literate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Literate_by_name
+ *
+ * Purpose: Iterates over links in a group, with user callback routine,
+ * according to the order within an index.
+ *
+ * Same pattern of behavior as H5Giterate.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Literate_by_name(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t *idx_p,
+ H5L_iterate_t op, void *op_data, hid_t lapl_id)
+{
+ H5G_link_iterate_t lnk_op; /* Link operator */
+ hsize_t last_lnk; /* Index of last object looked at */
+ hsize_t idx; /* Internal location to hold index */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("e", "i*sIiIo*hx*xi", loc_id, group_name, idx_type, order, idx_p, op,
+ op_data, lapl_id);
+
+ /* Check arguments */
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up iteration beginning/end info */
+ idx = (idx_p == NULL ? 0 : *idx_p);
+ last_lnk = 0;
+
+ /* Build link operator info */
+ lnk_op.op_type = H5G_LINK_OP_NEW;
+ lnk_op.op_func.op_new = op;
+
+ /* Iterate over the links */
+ if((ret_value = H5G_iterate(loc_id, group_name, idx_type, order, idx, &last_lnk, &lnk_op,
+ op_data, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_BADITER, FAIL, "link iteration failed")
+
+ /* Set the index we stopped at */
+ if(idx_p)
+ *idx_p = last_lnk;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Literate_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lvisit
+ *
+ * Purpose: Recursively visit all the links in a group and all
+ * the groups that are linked to from that group. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Each _link_ reachable from the initial group will only be
+ * visited once. However, because an object may be reached from
+ * more than one link, the visitation may call the application's
+ * callback with more than one link that points to a particular
+ * _object_.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Quincey Koziol
+ * November 24 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lvisit(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order,
+ H5L_iterate_t op, void *op_data)
+{
+ H5I_type_t id_type; /* Type of ID */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIiIox*x", grp_id, idx_type, order, op, op_data);
+
+ /* Check args */
+ id_type = H5I_get_type(grp_id);
+ if(!(H5I_GROUP == id_type || H5I_FILE == id_type))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified")
+
+ /* Call internal group visitation routine */
+ if((ret_value = H5G_visit(grp_id, ".", idx_type, order, op, op_data, H5P_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "link visitation failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lvisit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lvisit_by_name
+ *
+ * Purpose: Recursively visit all the links in a group and all
+ * the groups that are linked to from that group. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Each _link_ reachable from the initial group will only be
+ * visited once. However, because an object may be reached from
+ * more than one link, the visitation may call the application's
+ * callback with more than one link that points to a particular
+ * _object_.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Quincey Koziol
+ * November 3 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lvisit_by_name(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, H5L_iterate_t op, void *op_data, hid_t lapl_id)
+{
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIox*xi", loc_id, group_name, idx_type, order, op, op_data,
+ lapl_id);
+
+ /* Check args */
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Call internal group visitation routine */
+ if((ret_value = H5G_visit(loc_id, group_name, idx_type, order, op, op_data, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_BADITER, FAIL, "link visitation failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lvisit_by_name() */
+
+/*
+ *-------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
+ * N O A P I F U N C T I O N S B E Y O N D T H I S P O I N T
+ *-------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_find_class_idx
+ *
+ * Purpose: Given a link class ID, return the offset in the global array
+ * that holds all the registered link classes.
+ *
+ * Return: Success: Non-negative index of entry in global
+ * link class table.
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5L_find_class_idx(H5L_type_t id)
+{
+ size_t i; /* Local index variable */
+ int ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ for(i = 0; i < H5L_table_used_g; i++)
+ if(H5L_table_g[i].id == id)
+ HGOTO_DONE((int)i)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_find_class_idx */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_find_class
+ *
+ * Purpose: Given a link class ID return a pointer to a global struct that
+ * defines the link class.
+ *
+ * Return: Success: Ptr to entry in global link class table.
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+const H5L_class_t *
+H5L_find_class(H5L_type_t id)
+{
+ int idx; /* Filter index in global table */
+ H5L_class_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Get the index in the global table */
+ if((idx = H5L_find_class_idx(id)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, NULL, "unable to find link class")
+
+ /* Set return value */
+ ret_value = H5L_table_g+idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_find_class */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_register
+ *
+ * Purpose: Registers a class of user-defined links, or changes the
+ * behavior of an existing class.
+ *
+ * See H5Lregister for full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_register(const H5L_class_t *cls)
+{
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(cls);
+ HDassert(cls->id >= 0 && cls->id <= H5L_TYPE_MAX);
+
+ /* Is the link type already registered? */
+ for(i = 0; i < H5L_table_used_g; i++)
+ if(H5L_table_g[i].id == cls->id)
+ break;
+
+ /* Filter not already registered */
+ if(i >= H5L_table_used_g) {
+ if(H5L_table_used_g >= H5L_table_alloc_g) {
+ size_t n = MAX(H5L_MIN_TABLE_SIZE, (2 * H5L_table_alloc_g));
+ H5L_class_t *table = (H5L_class_t *)H5MM_realloc(H5L_table_g, (n * sizeof(H5L_class_t)));
+ if(!table)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend link type table")
+ H5L_table_g = table;
+ H5L_table_alloc_g = n;
+ } /* end if */
+
+ /* Initialize */
+ i = H5L_table_used_g++;
+ } /* end if */
+
+ /* Copy link class info into table */
+ HDmemcpy(H5L_table_g + i, cls, sizeof(H5L_class_t));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_register */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_unregister
+ *
+ * Purpose: Unregisters a class of user-defined links.
+ *
+ * See H5Lunregister for full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_unregister(H5L_type_t id)
+{
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(id >= 0 && id <= H5L_TYPE_MAX);
+
+ /* Is the filter already registered? */
+ for(i = 0; i < H5L_table_used_g; i++)
+ if(H5L_table_g[i].id == id)
+ break;
+
+ /* Fail if filter not found */
+ if(i >= H5L_table_used_g)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered")
+
+ /* Remove filter from table */
+ /* Don't worry about shrinking table size (for now) */
+ HDmemmove(&H5L_table_g[i], &H5L_table_g[i + 1], sizeof(H5L_class_t) * ((H5L_table_used_g - 1) - i));
+ H5L_table_used_g--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_unregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_link
+ *
+ * Purpose: Creates a link from OBJ_ID to CUR_NAME. See H5Olink() for
+ * full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, December 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_link(const H5G_loc_t *new_loc, const char *new_name, H5G_loc_t *obj_loc,
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5O_link_t lnk; /* Link to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(new_loc);
+ HDassert(obj_loc);
+ HDassert(new_name && *new_name);
+
+ /* The link callback will check that the object isn't being hard linked
+ * into a different file, so we don't need to do it here (there could be
+ * external links along the path).
+ */
+
+ /* Construct link information for eventual insertion */
+ lnk.type = H5L_TYPE_HARD;
+ lnk.u.hard.addr = obj_loc->oloc->addr;
+
+ /* Create the link */
+ if(H5L_create_real(new_loc, new_name, obj_loc->path, obj_loc->oloc->file, &lnk, NULL, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_link_object
+ *
+ * Purpose: Creates a new object and a link to it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 9, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_link_object(const H5G_loc_t *new_loc, const char *new_name,
+ H5O_obj_create_t *ocrt_info, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5O_link_t lnk; /* Link to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(new_loc);
+ HDassert(new_name && *new_name);
+ HDassert(ocrt_info);
+
+ /* The link callback will check that the object isn't being hard linked
+ * into a different file, so we don't need to do it here (there could be
+ * external links along the path).
+ */
+
+ /* Construct link information for eventual insertion */
+ lnk.type = H5L_TYPE_HARD;
+
+ /* Create the link */
+ if(H5L_create_real(new_loc, new_name, NULL, NULL, &lnk, ocrt_info, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_link_object() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_link_cb
+ *
+ * Purpose: Callback for creating a link to an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_cr_t *udata = (H5L_trav_cr_t *)_udata; /* User data passed in */
+ H5G_t *grp = NULL; /* H5G_t for this group, opened to pass to user callback */
+ hid_t grp_id = FAIL; /* Id for this group (passed to user callback */
+ H5G_loc_t temp_loc; /* For UD callback */
+ hbool_t temp_loc_init = FALSE; /* Temporary location for UD callback (temp_loc) has been initialized */
+ hbool_t obj_created = FALSE; /* Whether an object was created (through a hard link) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid location */
+ /* (which is not what we want) */
+ if(obj_loc != NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name already exists")
+
+ /* Check for crossing file boundaries with a new hard link */
+ if(udata->lnk->type == H5L_TYPE_HARD) {
+ /* Check for creating an object */
+ /* (only for hard links) */
+ if(udata->ocrt_info) {
+ H5G_loc_t new_loc; /* Group location for new object */
+
+ /* Create new object at this location */
+ if(NULL == (udata->ocrt_info->new_obj = H5O_obj_create(grp_loc->oloc->file, udata->ocrt_info->obj_type, udata->ocrt_info->crt_info, &new_loc, udata->dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create object")
+
+ /* Set address for hard link */
+ udata->lnk->u.hard.addr = new_loc.oloc->addr;
+
+ /* Set object path to use for setting object name (below) */
+ udata->path = new_loc.path;
+
+ /* Indicate that an object was created */
+ obj_created = TRUE;
+ } /* end if */
+ else {
+ /* Check that both objects are in same file */
+ if(!H5F_SAME_SHARED(grp_loc->oloc->file, udata->file))
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "interfile hard links are not allowed")
+ } /* end else */
+ } /* end if */
+
+ /* Set 'standard' aspects of link */
+ udata->lnk->corder = 0; /* Will be re-written during group insertion, if the group is tracking creation order */
+ udata->lnk->corder_valid = FALSE; /* Creation order not valid (yet) */
+
+ /* Check for non-default link creation properties */
+ if(udata->lc_plist) {
+ /* Get character encoding property */
+ if(H5P_get(udata->lc_plist, H5P_STRCRT_CHAR_ENCODING_NAME, &udata->lnk->cset) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding")
+ } /* end if */
+ else
+ udata->lnk->cset = H5F_DEFAULT_CSET; /* Default character encoding for link */
+
+ /* Set the link's name correctly */
+ /* Casting away const OK -QAK */
+ udata->lnk->name = (char *)name;
+
+ /* Insert link into group */
+ if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, TRUE,
+ udata->ocrt_info ? udata->ocrt_info->obj_type : H5O_TYPE_UNKNOWN,
+ udata->ocrt_info ? udata->ocrt_info->crt_info : NULL,
+ udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link for object")
+
+ /* Set object's path if it has been passed in and is not set */
+ if(udata->path != NULL && udata->path->user_path_r == NULL)
+ if(H5G_name_set(grp_loc->path, udata->path, name) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name")
+
+ /* If link is a user-defined link, trigger its creation callback if it has one */
+ if(udata->lnk->type >= H5L_TYPE_UD_MIN) {
+ const H5L_class_t *link_class; /* User-defined link class */
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(udata->lnk->type)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to get class of UD link")
+
+ if(link_class->create_func != NULL) {
+ H5O_loc_t temp_oloc;
+ H5G_name_t temp_path;
+
+ /* Create a temporary location (or else H5G_open will do a shallow
+ * copy and wipe out grp_loc)
+ */
+ H5G_name_reset(&temp_path);
+ if(H5O_loc_copy(&temp_oloc, grp_loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ temp_loc.oloc = &temp_oloc;
+ temp_loc.path = &temp_path;
+ temp_loc_init = TRUE;
+
+ /* Set up location for user-defined callback */
+ if((grp = H5G_open(&temp_loc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp_id = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register ID for group")
+
+ /* Make callback */
+ if((link_class->create_func)(name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size, H5P_DEFAULT) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "link creation callback failed")
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Check if an object was created */
+ if(obj_created) {
+ H5O_loc_t oloc; /* Object location for created object */
+
+ /* Set up object location */
+ HDmemset(&oloc, 0, sizeof(oloc));
+ oloc.file = grp_loc->oloc->file;
+ oloc.addr = udata->lnk->u.hard.addr;
+
+ /* Decrement refcount on new object's object header in memory */
+ if(H5O_dec_rc_by_loc(&oloc, udata->dxpl_id) < 0)
+ HDONE_ERROR(H5E_LINK, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+ } /* end if */
+
+ /* Close the location given to the user callback if it was created */
+ if(grp_id >= 0) {
+ if(H5I_dec_app_ref(grp_id) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ } /* end if */
+ else if(grp != NULL) {
+ if(H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback")
+ } /* end if */
+ else if(temp_loc_init)
+ H5G_loc_free(&temp_loc);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_link_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_create_real
+ *
+ * Purpose: Creates a link at a path location
+ *
+ * lnk should have linkclass-specific information already
+ * set, but this function will take care of setting name.
+ *
+ * obj_path can be NULL if the object's path doesn't need to
+ * be set, and obj_file can be NULL if the object is not a
+ * hard link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 5, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_create_real(const H5G_loc_t *link_loc, const char *link_name,
+ H5G_name_t *obj_path, H5F_t *obj_file, H5O_link_t *lnk,
+ H5O_obj_create_t *ocrt_info, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
+{
+ char *norm_link_name = NULL; /* Pointer to normalized link name */
+ unsigned target_flags = H5G_TARGET_NORMAL; /* Flags to pass to group traversal function */
+ H5P_genplist_t *lc_plist = NULL; /* Link creation property list */
+ H5L_trav_cr_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(link_loc);
+ HDassert(link_name && *link_name);
+ HDassert(lnk);
+ HDassert(lnk->type >= H5L_TYPE_HARD && lnk->type <= H5L_TYPE_MAX);
+
+ /* Get normalized link name */
+ if((norm_link_name = H5G_normalize(link_name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name")
+
+ /* Check for flags present in creation property list */
+ if(lcpl_id != H5P_DEFAULT) {
+ unsigned crt_intmd_group;
+
+ /* Get link creation property list */
+ if(NULL == (lc_plist = (H5P_genplist_t *)H5I_object(lcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get intermediate group creation property */
+ if(H5P_get(lc_plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups")
+
+ if(crt_intmd_group > 0)
+ target_flags |= H5G_CRT_INTMD_GROUP;
+ } /* end if */
+
+ /* Set up user data
+ * FILE is used to make sure that hard links don't cross files, and
+ * should be NULL for other link types.
+ * LC_PLIST is a pointer to the link creation property list.
+ * DXPL_ID is the dxpl ID that needs to be used during writes and reads.
+ * PATH is a pointer to the path of the object being inserted if this is
+ * a hard link; this is used to set the paths to objects when they are
+ * created. For other link types, this is NULL.
+ * OCRT_INFO is a pointer to the structure for object creation.
+ * LNK is the link struct passed into this function. At this point all
+ * of its fields should be populated except for name, which is set when
+ * inserting it in the callback.
+ */
+ udata.file = obj_file;
+ udata.lc_plist = lc_plist;
+ udata.dxpl_id = dxpl_id;
+ udata.path = obj_path;
+ udata.ocrt_info = ocrt_info;
+ udata.lnk = lnk;
+
+ /* Traverse the destination path & create new link */
+ if(H5G_traverse(link_loc, link_name, target_flags, H5L_link_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert link")
+
+done:
+ /* Free the normalized path name */
+ if(norm_link_name)
+ H5MM_xfree(norm_link_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_create_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_create_hard
+ *
+ * Purpose: Creates a hard link from NEW_NAME to CUR_NAME.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
+ const H5G_loc_t *link_loc, const char *link_name, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ char *norm_cur_name = NULL; /* Pointer to normalized current name */
+ H5F_t *link_file = NULL; /* Pointer to file to link to */
+ H5O_link_t lnk; /* Link to insert */
+ H5G_loc_t obj_loc; /* Location of object to link to */
+ H5G_name_t path; /* obj_loc's path*/
+ H5O_loc_t oloc; /* obj_loc's oloc */
+ hbool_t loc_valid = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(cur_loc);
+ HDassert(cur_name && *cur_name);
+ HDassert(link_loc);
+ HDassert(link_name && *link_name);
+
+ /* Get normalized copy of the current name */
+ if((norm_cur_name = H5G_normalize(cur_name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name")
+
+ /* Set up link data specific to hard links */
+ lnk.type = H5L_TYPE_HARD;
+
+ /* Get object location for object pointed to */
+ obj_loc.path = &path;
+ obj_loc.oloc = &oloc;
+ H5G_loc_reset(&obj_loc);
+ if(H5G_loc_find(cur_loc, norm_cur_name, &obj_loc, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found")
+ loc_valid = TRUE;
+
+ /* Construct link information for eventual insertion */
+ lnk.u.hard.addr = obj_loc.oloc->addr;
+
+ /* Set destination's file information */
+ link_file = obj_loc.oloc->file;
+
+ /* Create actual link to the object. Pass in NULL for the path, since this
+ * function shouldn't change an object's user path. */
+ if(H5L_create_real(link_loc, link_name, NULL, link_file, &lnk, NULL, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+
+done:
+ /* Free the object header location */
+ if(loc_valid)
+ if(H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to free location")
+
+ /* Free the normalized path name */
+ if(norm_cur_name)
+ H5MM_xfree(norm_cur_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_create_hard() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_create_soft
+ *
+ * Purpose: Creates a soft link from LINK_NAME to TARGET_PATH.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_create_soft(const char *target_path, const H5G_loc_t *link_loc,
+ const char *link_name, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
+{
+ char *norm_target = NULL; /* Pointer to normalized current name */
+ H5O_link_t lnk; /* Link to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(link_loc);
+ HDassert(target_path && *target_path);
+ HDassert(link_name && *link_name);
+
+ /* Get normalized copy of the link target */
+ if((norm_target = H5G_normalize(target_path)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name")
+
+ /* Set up link data specific to soft links */
+ lnk.type = H5L_TYPE_SOFT;
+ lnk.u.soft.name = norm_target;
+
+ /* Create actual link to the object */
+ if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, NULL, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+
+done:
+ /* Free the normalized target name */
+ if(norm_target)
+ H5MM_xfree(norm_target);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_create_soft() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_create_ud
+ *
+ * Purpose: Creates a user-defined link. See H5Lcreate_ud for
+ * full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Friday, May 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_create_ud(const H5G_loc_t *link_loc, const char *link_name,
+ const void *ud_data, size_t ud_data_size, H5L_type_t type, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5O_link_t lnk; /* Link to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(type >= H5L_TYPE_UD_MIN && type <= H5L_TYPE_MAX);
+ HDassert(link_loc);
+ HDassert(link_name && *link_name);
+ HDassert(ud_data_size == 0 || ud_data);
+
+ /* Initialize the link struct's pointer to its udata buffer */
+ lnk.u.ud.udata = NULL;
+
+ /* Make sure that this link class is registered */
+ if(H5L_find_class_idx(type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "link class has not been registered with library")
+
+ /* Fill in UD link-specific information in the link struct*/
+ if(ud_data_size > 0) {
+ lnk.u.ud.udata = H5MM_malloc((size_t)ud_data_size);
+ HDmemcpy(lnk.u.ud.udata, ud_data, (size_t) ud_data_size);
+ } /* end if */
+ else
+ lnk.u.ud.udata = NULL;
+
+ lnk.u.ud.size = ud_data_size;
+ lnk.type = type;
+
+ /* Create actual link to the object */
+ if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, NULL, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to register new name for object")
+
+done:
+ /* Free the link's udata buffer if it's been allocated */
+ H5MM_xfree(lnk.u.ud.udata);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_create_ud() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_val_real
+ *
+ * Purpose: Retrieve link value from a link object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_val_real(const H5O_link_t *lnk, void *buf, size_t size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(lnk);
+
+ /* Check for soft link */
+ if(H5L_TYPE_SOFT == lnk->type) {
+ /* Copy to output buffer */
+ if(size > 0 && buf) {
+ HDstrncpy((char *)buf, lnk->u.soft.name, size);
+ if(HDstrlen(lnk->u.soft.name) >= size)
+ ((char *)buf)[size - 1] = '\0';
+ } /* end if */
+ } /* end if */
+ /* Check for user-defined link */
+ else if(lnk->type >= H5L_TYPE_UD_MIN) {
+ const H5L_class_t *link_class; /* User-defined link class */
+
+ /* Get the link class for this type of link. It's okay if the class
+ * isn't registered, though--we just can't give any more information
+ * about it
+ */
+ link_class = H5L_find_class(lnk->type);
+
+ if(link_class != NULL && link_class->query_func != NULL) {
+ if((link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, buf, size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query callback returned failure")
+ } /* end if */
+ else if(buf && size > 0)
+ ((char *)buf)[0] = '\0';
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "object is not a symbolic or user-defined link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_val_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_val_cb
+ *
+ * Purpose: Callback for retrieving link value or udata.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_val_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
+ H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gv_t *udata = (H5L_trav_gv_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(lnk == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "'%s' doesn't exist", name)
+
+ /* Retrieve the value for the link */
+ if(H5L_get_val_real(lnk, udata->buf, udata->size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't retrieve link value")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_val_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_val
+ *
+ * Purpose: Returns the value of a symbolic link or the udata for a
+ * user-defined link.
+ *
+ * Return: Success: Non-negative, with at most SIZE bytes of the
+ * link value copied into the BUF buffer. If the
+ * link value is larger than SIZE characters
+ * counting the null terminator then the BUF
+ * result will not be null terminated.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_get_val(H5G_loc_t *loc, const char *name, void *buf/*out*/, size_t size,
+ hid_t lapl_id, hid_t dxpl_id)
+{
+ H5L_trav_gv_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up user data for retrieving information */
+ udata.size = size;
+ udata.buf = buf;
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ if(H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L_get_val_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L_get_val() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_val_by_idx_cb
+ *
+ * Purpose: Callback for retrieving a link's value according to an
+ * index's order.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_val_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gvbi_t *udata = (H5L_trav_gvbi_t *)_udata; /* User data passed in */
+ H5O_link_t fnd_lnk; /* Link within group */
+ hbool_t lnk_copied = FALSE; /* Whether the link was copied */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name of the group resolved to a valid object */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Query link */
+ if(H5G_obj_lookup_by_idx(obj_loc->oloc, udata->idx_type, udata->order,
+ udata->n, &fnd_lnk, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "link not found")
+ lnk_copied = TRUE;
+
+ /* Retrieve the value for the link */
+ if(H5L_get_val_real(&fnd_lnk, udata->buf, udata->size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't retrieve link value")
+
+done:
+ /* Reset the link information, if we have a copy */
+ if(lnk_copied)
+ H5O_msg_reset(H5O_LINK_ID, &fnd_lnk);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_val_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_delete_cb
+ *
+ * Purpose: Callback for deleting a link. This routine
+ * actually deletes the link
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_delete_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
+ H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_rm_t *udata = (H5L_trav_rm_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the group resolved to a valid link */
+ if(grp_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Check if the name in this group resolved to a valid link */
+ if(name == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Check for non-existent (NULL) link.
+ * Note that this can also occur when attempting to remove '.'
+ */
+ if(lnk == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "callback link pointer is NULL (specified link may be '.' or not exist)")
+
+ /* Remove the link from the group */
+ if(H5G_obj_remove(grp_loc->oloc, grp_loc->path->full_path_r, name, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to remove link from group")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_delete_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_delete
+ *
+ * Purpose: Delete a link from a group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 17, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_delete(H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5L_trav_rm_t udata; /* User data for callback */
+ char *norm_name = NULL; /* Pointer to normalized name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Get normalized copy of the name */
+ if((norm_name = H5G_normalize(name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name")
+
+ /* Set up user data for unlink operation */
+ udata.dxpl_id = dxpl_id;
+ if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK|H5G_TARGET_MOUNT, H5L_delete_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "can't unlink object")
+
+done:
+ /* Free the normalized path name */
+ if(norm_name)
+ H5MM_xfree(norm_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_delete_by_idx_cb
+ *
+ * Purpose: Callback for removing a link according to an index's order.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_delete_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gvbi_t *udata = (H5L_trav_gvbi_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(udata->dxpl_id, (obj_loc) ? (obj_loc->oloc->addr) : HADDR_UNDEF, FAIL)
+
+ /* Check if the name of the group resolved to a valid object */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Delete link */
+ if(H5G_obj_remove_by_idx(obj_loc->oloc, obj_loc->path->full_path_r,
+ udata->idx_type, udata->order, udata->n, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "link not found")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5L_delete_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_move_dest_cb
+ *
+ * Purpose: Second callback for moving and renaming an object. This routine
+ * inserts a new link into the group returned by the traversal.
+ * It is called by H5L_move_cb.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, April 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_move_dest_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_mv2_t *udata = (H5L_trav_mv2_t *)_udata; /* User data passed in */
+ H5G_t *grp = NULL; /* H5G_t for this group, opened to pass to user callback */
+ hid_t grp_id = FAIL; /* ID for this group (passed to user callback */
+ H5G_loc_t temp_loc; /* For UD callback */
+ hbool_t temp_loc_init = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Make sure an object with this name doesn't already exist */
+ if(obj_loc != NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "an object with that name already exists")
+
+ /* Check for crossing file boundaries with a new hard link */
+ if(udata->lnk->type == H5L_TYPE_HARD) {
+ /* Check that both objects are in same file */
+ if(!H5F_SAME_SHARED(grp_loc->oloc->file, udata->file))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "moving a link across files is not allowed")
+ } /* end if */
+
+ /* Give the object its new name */
+ /* Casting away const okay -JML */
+ HDassert(udata->lnk->name == NULL);
+ udata->lnk->name = (char *)name;
+
+ /* Insert the link into the group */
+ if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, TRUE, H5O_TYPE_UNKNOWN,
+ NULL, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+
+ /* If the link was a user-defined link, call its move callback if it has one */
+ if(udata->lnk->type >= H5L_TYPE_UD_MIN) {
+ const H5L_class_t *link_class; /* User-defined link class */
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(udata->lnk->type)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered")
+
+ if((!udata->copy && link_class->move_func) || (udata->copy && link_class->copy_func)) {
+ H5O_loc_t temp_oloc;
+ H5G_name_t temp_path;
+
+ /* Create a temporary location (or else H5G_open will do a shallow
+ * copy and wipe out grp_loc)
+ */
+ H5G_name_reset(&temp_path);
+ if(H5O_loc_copy(&temp_oloc, grp_loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ temp_loc.oloc = &temp_oloc;
+ temp_loc.path = &temp_path;
+ temp_loc_init = TRUE;
+
+ /* Set up location for user-defined callback */
+ if((grp = H5G_open(&temp_loc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp_id = H5I_register(H5I_GROUP, grp, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group ID")
+
+ if(udata->copy) {
+ if((link_class->copy_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD copy callback returned error")
+ } /* end if */
+ else {
+ if((link_class->move_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD move callback returned error")
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Close the location given to the user callback if it was created */
+ if(grp_id >= 0) {
+ if(H5I_dec_app_ref(grp_id) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ } /* end if */
+ else if(grp != NULL) {
+ if(H5G_close(grp) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback")
+ } /* end if */
+ else if(temp_loc_init)
+ H5G_loc_free(&temp_loc);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ /* Reset the "name" field in udata->lnk because it is owned by traverse()
+ * and must not be manipulated after traverse closes */
+ udata->lnk->name = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_move_dest_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_move_cb
+ *
+ * Purpose: Callback for moving and renaming an object. This routine
+ * replaces the names of open objects with the moved object
+ * in the path
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Friday, April 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_mv_t *udata = (H5L_trav_mv_t *)_udata; /* User data passed in */
+ H5L_trav_mv2_t udata_out; /* User data for H5L_move_dest_cb traversal */
+ char * orig_name = NULL; /* The name of the link in this group */
+ hbool_t link_copied = FALSE; /* Has udata_out.lnk been allocated? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Check for operations on '.' */
+ if(lnk == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "the name of a link must be supplied to move or copy")
+
+ /* Set up user data for move_dest_cb */
+ if(NULL == (udata_out.lnk = (H5O_link_t *)H5O_msg_copy(H5O_LINK_ID, lnk, NULL)))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy link to be moved")
+
+ /* In this special case, the link's name is going to be replaced at its
+ * destination, so we should free it here.
+ */
+ udata_out.lnk->name = (char *)H5MM_xfree(udata_out.lnk->name);
+ link_copied = TRUE;
+
+ udata_out.lnk->cset = udata->cset;
+ udata_out.file = grp_loc->oloc->file;
+ udata_out.copy = udata->copy;
+ udata_out.dxpl_id = udata->dxpl_id;
+
+ /* Keep a copy of link's name (it's "owned" by the H5G_traverse() routine) */
+ orig_name = H5MM_xstrdup(name);
+
+ /* Insert the link into its new location */
+ if(H5G_traverse(udata->dst_loc, udata->dst_name, udata->dst_target_flags,
+ H5L_move_dest_cb, &udata_out, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link")
+
+ /* If this is a move and not a copy operation, change the object's name and remove the old link */
+ if(!udata->copy) {
+ H5RS_str_t *dst_name_r; /* Ref-counted version of dest name */
+
+ /* Make certain that the destination name is a full (not relative) path */
+ if(*(udata->dst_name) != '/') {
+ HDassert(udata->dst_loc->path->full_path_r);
+
+ /* Create reference counted string for full dst path */
+ if((dst_name_r = H5G_build_fullpath_refstr_str(udata->dst_loc->path->full_path_r,
+ udata->dst_name)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build destination path name")
+ } /* end if */
+ else
+ dst_name_r = H5RS_wrap(udata->dst_name);
+ HDassert(dst_name_r);
+
+ /* Fix names up */
+ if(H5G_name_replace(lnk, H5G_NAME_MOVE, obj_loc->oloc->file, obj_loc->path->full_path_r,
+ udata->dst_loc->oloc->file, dst_name_r, udata->dxpl_id) < 0) {
+ H5RS_decr(dst_name_r);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to replace name")
+ } /* end if */
+
+ /* Remove the old link */
+ if(H5G_obj_remove(grp_loc->oloc, grp_loc->path->full_path_r, orig_name, udata->dxpl_id) < 0) {
+ H5RS_decr(dst_name_r);
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to remove old name")
+ } /* end if */
+
+ H5RS_decr(dst_name_r);
+ } /* end if */
+
+done:
+ /* Cleanup */
+ if(orig_name)
+ H5MM_xfree(orig_name);
+
+ /* If udata_out.lnk was copied, free any memory allocated
+ * In this special case, the H5L_move_dest_cb callback resets the name
+ * so H5O_msg_free shouldn't try to free it
+ */
+ if(link_copied)
+ H5O_msg_free(H5O_LINK_ID, udata_out.lnk);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_move_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_move
+ *
+ * Purpose: Atomically move or copy a link.
+ *
+ * Creates a copy of a link in a new destination with a new name.
+ * SRC_LOC and SRC_NAME together define the link's original
+ * location, while DST_LOC and DST_NAME together define its
+ * final location.
+ *
+ * If copy_flag is FALSE, the original link is removed
+ * (effectively moving the link).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, May 1, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc,
+ const char *dst_name, hbool_t copy_flag, hid_t lcpl_id, hid_t lapl_id,
+ hid_t dxpl_id)
+{
+ unsigned dst_target_flags = H5G_TARGET_NORMAL;
+ H5T_cset_t char_encoding = H5F_DEFAULT_CSET; /* Character encoding for link */
+ H5P_genplist_t* lc_plist; /* Link creation property list */
+ H5P_genplist_t* la_plist; /* Link access property list */
+ H5L_trav_mv_t udata; /* User data for traversal */
+ hid_t lapl_copy; /* Copy of lapl for this function */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(src_loc);
+ HDassert(dst_loc);
+ HDassert(src_name && *src_name);
+ HDassert(dst_name && *dst_name);
+
+ /* Check for flags present in creation property list */
+ if(lcpl_id != H5P_DEFAULT) {
+ unsigned crt_intmd_group;
+
+ if(NULL == (lc_plist = (H5P_genplist_t *)H5I_object(lcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get intermediate group creation property */
+ if(H5P_get(lc_plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups")
+
+ /* Set target flags for source and destination */
+ if(crt_intmd_group > 0)
+ dst_target_flags |= H5G_CRT_INTMD_GROUP;
+
+ /* Get character encoding property */
+ if(H5P_get(lc_plist, H5P_STRCRT_CHAR_ENCODING_NAME, &char_encoding) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding")
+ } /* end if */
+
+ /* Copy the link access property list because traversing UD links will
+ * decrease the NLINKS property. HDF5 should have NLINKS traversals to
+ * get to the source and NLINKS more to get to the destination. */
+ if(lapl_id == H5P_DEFAULT)
+ lapl_copy = lapl_id;
+ else {
+ if(NULL == (la_plist = (H5P_genplist_t *)H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a valid access PL")
+ if((lapl_copy = H5P_copy_plist(la_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy access properties")
+ } /* end else */
+
+ /* Set up user data */
+ udata.dst_loc = dst_loc;
+ udata.dst_name= dst_name;
+ udata.dst_target_flags = dst_target_flags;
+ udata.cset = char_encoding;
+ udata.copy = copy_flag;
+ udata.lapl_id = lapl_copy;
+ udata.dxpl_id = dxpl_id;
+
+ /* Do the move */
+ if(H5G_traverse(src_loc, src_name, H5G_TARGET_MOUNT | H5G_TARGET_SLINK | H5G_TARGET_UDLINK,
+ H5L_move_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to find link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_move() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L__exists_final_cb
+ *
+ * Purpose: Callback for checking whether a link exists, as the final
+ * component of a path
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 16 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L__exists_final_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t *lnk, H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_le_t *udata = (H5L_trav_le_t *)_udata; /* User data passed in */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check if the name in this group resolved to a valid link */
+ udata->exists = (hbool_t)(lnk != NULL);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5L__exists_final_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L__exists_inter_cb
+ *
+ * Purpose: Callback for checking whether a link exists, as an intermediate
+ * component of a path
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 31 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L__exists_inter_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_le_t *udata = (H5L_trav_le_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check if the name in this group resolved to a valid link */
+ if(lnk != NULL) {
+ /* Check for more components to the path */
+ if(udata->sep) {
+ H5G_traverse_t cb_func; /* Callback function for tranversal */
+ char *next; /* Pointer to next component name */
+
+ /* Look for another separator */
+ next = udata->sep;
+ if(NULL == (udata->sep = HDstrchr(udata->sep, '/')))
+ cb_func = H5L__exists_final_cb;
+ else {
+ /* Chew through adjacent separators, if present */
+ do {
+ *udata->sep = '\0';
+ udata->sep++;
+ } while('/' == *udata->sep);
+ cb_func = H5L__exists_inter_cb;
+ } /* end else */
+ if(H5G_traverse(obj_loc, next, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, cb_func, udata, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine if link exists")
+ } /* end if */
+ else
+ udata->exists = TRUE;
+ } /* end if */
+ else
+ udata->exists = FALSE;
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L__exists_inter_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_exists_tolerant
+ *
+ * Purpose: Returns whether a link exists in a group
+ *
+ * Note: Same as H5L_exists, except that missing links are reported
+ * as 'FALSE' instead of causing failures
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 31 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5L_exists_tolerant(const H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5L_trav_le_t udata; /* User data for traversal */
+ H5G_traverse_t cb_func; /* Callback function for tranversal */
+ char *name_copy = NULL; /* Duplicate of name */
+ char *name_trav; /* Name to traverse */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Copy the name and skip leading '/'s */
+ name_trav = name_copy = H5MM_strdup(name);
+ while('/' == *name_trav)
+ name_trav++;
+
+ /* A path of "/" will always exist in a file */
+ if('\0' == *name_trav)
+ HGOTO_DONE(TRUE)
+
+ /* Set up user data & correct callback */
+ udata.lapl_id = lapl_id;
+ udata.dxpl_id = dxpl_id;
+ udata.exists = FALSE;
+ if(NULL == (udata.sep = HDstrchr(name_trav, '/')))
+ cb_func = H5L__exists_final_cb;
+ else {
+ /* Chew through adjacent separators, if present */
+ do {
+ *udata.sep = '\0';
+ udata.sep++;
+ } while('/' == *udata.sep);
+ cb_func = H5L__exists_inter_cb;
+ } /* end else */
+
+ /* Traverse the group hierarchy to locate the link to check */
+ if(H5G_traverse(loc, name_trav, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, cb_func, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine if link exists")
+
+ /* Set return value */
+ ret_value = (htri_t)udata.exists;
+
+done:
+ /* Release duplicated string */
+ H5MM_xfree(name_copy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L_exists_tolerant() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L__exists
+ *
+ * Purpose: Returns whether a link exists in a group
+ *
+ * Note: Same as H5L_exists_tolerant, except that missing links are reported
+ * as failures
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 16 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5L__exists(const H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5L_trav_le_t udata; /* User data for traversal */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* A path of "/" will always exist in a file */
+ if(0 == HDstrcmp(name, "/"))
+ HGOTO_DONE(TRUE)
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ udata.exists = FALSE;
+ if(H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__exists_final_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "path doesn't exist")
+
+ /* Set return value */
+ ret_value = (htri_t)udata.exists;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L__exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_info_cb
+ *
+ * Purpose: Callback for retrieving a link's metadata
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, April 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_info_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t *lnk, H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gi_t *udata = (H5L_trav_gi_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name in this group resolved to a valid link */
+ if(lnk == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Get information from the link */
+ if(H5G_link_to_info(lnk, udata->linfo) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get link info")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_info_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_info
+ *
+ * Purpose: Returns metadata about a link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, April 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_get_info(const H5G_loc_t *loc, const char *name,
+ H5L_info_t *linfo/*out*/, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5L_trav_gi_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ udata.linfo = linfo;
+ udata.dxpl_id = dxpl_id;
+
+ /* Traverse the group hierarchy to locate the object to get info about */
+ if(H5G_traverse(loc, name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK, H5L_get_info_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L_get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_info_by_idx_cb
+ *
+ * Purpose: Callback for retrieving a link's metadata according to an
+ * index's order.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_info_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gibi_t *udata = (H5L_trav_gibi_t *)_udata; /* User data passed in */
+ H5O_link_t fnd_lnk; /* Link within group */
+ hbool_t lnk_copied = FALSE; /* Whether the link was copied */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name of the group resolved to a valid object */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Query link */
+ if(H5G_obj_lookup_by_idx(obj_loc->oloc, udata->idx_type, udata->order,
+ udata->n, &fnd_lnk, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "link not found")
+ lnk_copied = TRUE;
+
+ /* Get information from the link */
+ if(H5G_link_to_info(&fnd_lnk, udata->linfo) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get link info")
+
+done:
+ /* Reset the link information, if we have a copy */
+ if(lnk_copied)
+ H5O_msg_reset(H5O_LINK_ID, &fnd_lnk);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_info_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_default_lcpl
+ *
+ * Purpose: Accessor for the default Link Creation Property List
+ *
+ * Return: Success: ID of the deafult lcpl
+ *
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Tuesday, July 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5L_get_default_lcpl(void)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ ret_value = H5P_LINK_CREATE_DEFAULT;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L_get_default_lcpl */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_get_name_by_idx_cb
+ *
+ * Purpose: Callback for retrieving a link's name according to an
+ * index's order.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5L_get_name_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5L_trav_gnbi_t *udata = (H5L_trav_gnbi_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check if the name of the group resolved to a valid object */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group doesn't exist")
+
+ /* Query link */
+ if((udata->name_len = H5G_obj_get_name_by_idx(obj_loc->oloc, udata->idx_type, udata->order,
+ udata->n, udata->name, udata->size, udata->dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "link not found")
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_get_name_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_link_copy_file
+ *
+ * Purpose: Copy a link and the object it points to from one file to
+ * another.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sep 29 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_link_copy_file(H5F_t *dst_file, hid_t dxpl_id, const H5O_link_t *_src_lnk,
+ const H5O_loc_t *src_oloc, H5O_link_t *dst_lnk, H5O_copy_t *cpy_info)
+{
+ H5O_link_t tmp_src_lnk; /* Temporary copy of src link, when needed */
+ const H5O_link_t *src_lnk = _src_lnk; /* Source link */
+ hbool_t dst_lnk_init = FALSE; /* Whether the destination link is initialized */
+ hbool_t expanded_link_open = FALSE; /* Whether the target location has been opened */
+ H5G_loc_t tmp_src_loc; /* Group location holding target object */
+ H5G_name_t tmp_src_path; /* Path for target object */
+ H5O_loc_t tmp_src_oloc; /* Object location for target object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check arguments */
+ HDassert(dst_file);
+ HDassert(src_lnk);
+ HDassert(dst_lnk);
+ HDassert(cpy_info);
+
+ /* Expand soft or external link, if requested */
+ if((H5L_TYPE_SOFT == src_lnk->type && cpy_info->expand_soft_link)
+ || (H5L_TYPE_EXTERNAL == src_lnk->type
+ && cpy_info->expand_ext_link)) {
+ H5G_loc_t lnk_grp_loc; /* Group location holding link */
+ H5G_name_t lnk_grp_path; /* Path for link */
+ htri_t tar_exists; /* Whether the target object exists */
+
+ /* Set up group location for link */
+ H5G_name_reset(&lnk_grp_path);
+ lnk_grp_loc.path = &lnk_grp_path;
+ lnk_grp_loc.oloc = (H5O_loc_t *)src_oloc; /* Casting away const OK -QAK */
+
+ /* Check if the target object exists */
+ if((tar_exists = H5G_loc_exists(&lnk_grp_loc, src_lnk->name, H5P_DEFAULT,
+ dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to check if target object exists")
+
+ if(tar_exists) {
+ /* Make a temporary copy of the link, so that it will not change the
+ * info in the cache when we change it to a hard link */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, src_lnk, &tmp_src_lnk))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy message")
+
+ /* Set up group location for target object. Let H5G_traverse expand
+ * the link. */
+ tmp_src_loc.path = &tmp_src_path;
+ tmp_src_loc.oloc = &tmp_src_oloc;
+ if(H5G_loc_reset(&tmp_src_loc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to reset location")
+
+ /* Find the target object */
+ if(H5G_loc_find(&lnk_grp_loc, src_lnk->name, &tmp_src_loc,
+ H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to find target object")
+ expanded_link_open = TRUE;
+
+ /* Convert symbolic link to hard link */
+ if(tmp_src_lnk.type == H5L_TYPE_SOFT)
+ tmp_src_lnk.u.soft.name =
+ (char *)H5MM_xfree(tmp_src_lnk.u.soft.name);
+ else if(tmp_src_lnk.u.ud.size > 0)
+ tmp_src_lnk.u.ud.udata = H5MM_xfree(tmp_src_lnk.u.ud.udata);
+ tmp_src_lnk.type = H5L_TYPE_HARD;
+ tmp_src_lnk.u.hard.addr = tmp_src_oloc.addr;
+ src_lnk = &tmp_src_lnk;
+ } /* end if */
+ } /* end if */
+
+ /* Copy src link information to dst link information */
+ if(NULL == H5O_msg_copy(H5O_LINK_ID, src_lnk, dst_lnk))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy message")
+ dst_lnk_init = TRUE;
+
+ /* Check if object in source group is a hard link & copy it */
+ if(H5L_TYPE_HARD == src_lnk->type) {
+ H5O_loc_t new_dst_oloc; /* Copied object location in destination */
+
+ /* Set up copied object location to fill in */
+ H5O_loc_reset(&new_dst_oloc);
+ new_dst_oloc.file = dst_file;
+
+ if(!expanded_link_open) {
+ /* Build temporary object location for source */
+ H5O_loc_reset(&tmp_src_oloc);
+ tmp_src_oloc.file = src_oloc->file;
+ tmp_src_oloc.addr = src_lnk->u.hard.addr;
+ } /* end if */
+ HDassert(H5F_addr_defined(tmp_src_oloc.addr));
+
+ /* Copy the shared object from source to destination */
+ /* Don't care about obj_type or udata because those are only important
+ * for old style groups */
+ if(H5O_copy_header_map(&tmp_src_oloc, &new_dst_oloc, dxpl_id, cpy_info,
+ TRUE, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Copy new destination object's information for eventual insertion */
+ dst_lnk->u.hard.addr = new_dst_oloc.addr;
+ } /* end if */
+
+done:
+ /* Check if we used a temporary src link */
+ if(src_lnk != _src_lnk) {
+ HDassert(src_lnk == &tmp_src_lnk);
+ H5O_msg_reset(H5O_LINK_ID, &tmp_src_lnk);
+ } /* end if */
+ if(ret_value < 0)
+ if(dst_lnk_init)
+ H5O_msg_reset(H5O_LINK_ID, dst_lnk);
+ /* Check if we need to free the temp source oloc */
+ if(expanded_link_open)
+ if(H5G_loc_free(&tmp_src_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_link_copy_file() */
+
diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c
new file mode 100644
index 0000000..b4a173f
--- /dev/null
+++ b/src/H5Lexternal.c
@@ -0,0 +1,731 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#include "H5Lmodule.h" /* This source code file is part of the H5L module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lpkg.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opublic.h" /* File objects */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Version of external link format */
+#define H5L_EXT_VERSION 0
+
+/* Valid flags for external links */
+#define H5L_EXT_FLAGS_ALL 0
+
+/* Size of local link name buffer for traversing external links */
+#define H5L_EXT_TRAVERSE_BUF_SIZE 256
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static hid_t H5L_extern_traverse(const char H5_ATTR_UNUSED *link_name, hid_t cur_group,
+ const void *udata, size_t H5_ATTR_UNUSED udata_size, hid_t lapl_id);
+static ssize_t H5L_extern_query(const char H5_ATTR_UNUSED * link_name, const void *udata,
+ size_t udata_size, void * buf /*out*/, size_t buf_size);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Default External Link link class */
+static const H5L_class_t H5L_EXTERN_LINK_CLASS[1] = {{
+ H5L_LINK_CLASS_T_VERS, /* H5L_class_t version */
+ H5L_TYPE_EXTERNAL, /* Link type id number */
+ "external", /* Link name for debugging */
+ NULL, /* Creation callback */
+ NULL, /* Move callback */
+ NULL, /* Copy callback */
+ H5L_extern_traverse, /* The actual traversal function */
+ NULL, /* Deletion callback */
+ H5L_extern_query /* Query callback */
+}};
+
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5L_getenv_prefix_name --
+ *
+ * Purpose: Get the first pathname in the list of pathnames stored in ENV_PREFIX,
+ * which is separated by the environment delimiter.
+ * ENV_PREFIX is modified to point to the remaining pathnames
+ * in the list.
+ *
+ * Return: A pointer to a pathname
+ *
+ * Programmer: Vailin Choi, April 2, 2008
+ *
+--------------------------------------------------------------------------*/
+static char *
+H5L_getenv_prefix_name(char **env_prefix/*in,out*/)
+{
+ char *retptr=NULL;
+ char *strret=NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ strret = HDstrchr(*env_prefix, H5_COLON_SEPC);
+ if (strret == NULL) {
+ retptr = *env_prefix;
+ *env_prefix = strret;
+ } else {
+ retptr = *env_prefix;
+ *env_prefix = strret + 1;
+ *strret = '\0';
+ }
+
+ FUNC_LEAVE_NOAPI(retptr)
+} /* end H5L_getenv_prefix_name() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5L_build_name
+ *
+ * Purpose: Prepend PREFIX to FILE_NAME and store in FULL_NAME
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi, April 2, 2008
+ *
+--------------------------------------------------------------------------*/
+static herr_t
+H5L_build_name(char *prefix, char *file_name, char **full_name/*out*/)
+{
+ size_t prefix_len; /* length of prefix */
+ size_t fname_len; /* Length of external link file name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ prefix_len = HDstrlen(prefix);
+ fname_len = HDstrlen(file_name);
+
+ /* Allocate a buffer to hold the filename + prefix + possibly the delimiter + terminating null byte */
+ if(NULL == (*full_name = (char *)H5MM_malloc(prefix_len + fname_len + 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer")
+
+ /* Compose the full file name */
+ HDsnprintf(*full_name, (prefix_len + fname_len + 2), "%s%s%s", prefix,
+ (H5_CHECK_DELIMITER(prefix[prefix_len - 1]) ? "" : H5_DIR_SEPS), file_name);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5L_build_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_extern_traverse
+ *
+ * Purpose: Default traversal function for external links. This can
+ * be overridden using H5Lregister().
+ *
+ * Given a filename and path packed into the link udata,
+ * attempts to open an object within an external file.
+ * If the H5L_ELINK_PREFIX_NAME property is set in the
+ * link access property list, appends that prefix to the
+ * filename being opened.
+ *
+ * Return: ID of the opened object on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ * Modifications:
+ * Vailin Choi, April 2, 2008
+ * Add handling to search for the target file
+ * See description in RM: H5Lcreate_external
+ *
+ * Vailin Choi; Sept. 12th, 2008; bug #1247
+ * Retrieve the file access property list identifer that is set
+ * for link access property via H5Pget_elink_fapl().
+ * If the return value is H5P_DEFAULT, the parent's file access
+ * property is used to H5F_open() the target file;
+ * Otherwise, the file access property retrieved from H5Pget_elink_fapl()
+ * is used to H5F_open() the target file.
+ *
+ * Vailin Choi; Nov 2010
+ * Free memory pointed to by tmp_env_prefix for HDF5_EXT_PREFIX case.
+ *
+ *-------------------------------------------------------------------------
+ */
+static hid_t
+H5L_extern_traverse(const char H5_ATTR_UNUSED *link_name, hid_t cur_group,
+ const void *_udata, size_t H5_ATTR_UNUSED udata_size, hid_t lapl_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ char *my_prefix; /* Library's copy of the prefix */
+ H5G_loc_t root_loc; /* Location of root group in external file */
+ H5G_loc_t loc; /* Location of object */
+ H5F_t *ext_file = NULL; /* File struct for external file */
+ const uint8_t *p = (const uint8_t *)_udata; /* Pointer into external link buffer */
+ const char *file_name; /* Name of file containing external link's object */
+ char *full_name = NULL; /* File name with prefix */
+ const char *obj_name; /* Name external link's object */
+ size_t fname_len; /* Length of external link file name */
+ unsigned intent; /* File access permissions */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ hid_t fapl_id = -1; /* File access property list for external link's file */
+ hid_t ext_obj = -1; /* ID for external link's object */
+ char *parent_group_name = NULL;/* Temporary pointer to group name */
+ char local_group_name[H5L_EXT_TRAVERSE_BUF_SIZE]; /* Local buffer to hold group name */
+ char *temp_file_name = NULL; /* Temporary pointer to file name */
+ size_t temp_file_name_len; /* Length of temporary file name */
+ char *actual_file_name = NULL; /* Parent file's actual name */
+ H5P_genplist_t *fa_plist; /* File access property list pointer */
+ H5F_close_degree_t fc_degree = H5F_CLOSE_WEAK; /* File close degree for target file */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(p);
+
+ /* Check external link version & flags */
+ if(((*p >> 4) & 0x0F) > H5L_EXT_VERSION)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
+ if((*p & 0x0F) & ~H5L_EXT_FLAGS_ALL)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
+ p++;
+
+ /* Gather some information from the external link's user data */
+ file_name = (const char *)p;
+ fname_len = HDstrlen(file_name);
+ obj_name = (const char *)p + fname_len + 1;
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, cur_group, FALSE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Get the fapl_id set for lapl_id if any */
+ if(H5P_get(plist, H5L_ACS_ELINK_FAPL_NAME, &fapl_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fapl for links")
+
+ /* Get the location for the group holding the external link */
+ if(H5G_loc(cur_group, &loc) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get object location")
+
+ /* get the access flags set for lapl_id if any */
+ if(H5P_get(plist, H5L_ACS_ELINK_FLAGS_NAME, &intent) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get elink file access flags")
+
+ /* get the file access mode flags for the parent file, if they were not set
+ * on lapl_id */
+ if(intent == H5F_ACC_DEFAULT)
+ intent = H5F_INTENT(loc.oloc->file);
+
+ if((fapl_id == H5P_DEFAULT) && ((fapl_id = H5F_get_access_plist(loc.oloc->file, FALSE)) < 0))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get parent's file access property list")
+
+ /* Get callback_info */
+ if(H5P_get(plist, H5L_ACS_ELINK_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get elink callback info")
+
+ /* Get file access property list */
+ if(NULL == (fa_plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Make callback if it exists */
+ if(cb_info.func) {
+ const char *parent_file_name; /* Parent file name */
+ ssize_t group_name_len; /* Length of parent group name */
+
+ /* Get parent file name */
+ parent_file_name = H5F_OPEN_NAME(loc.oloc->file);
+
+ /* Query length of parent group name */
+ if((group_name_len = H5G_get_name(&loc, NULL, (size_t) 0, NULL, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve length of group name")
+
+ /* Account for null terminator */
+ group_name_len++;
+
+ /* Check if we need to allocate larger buffer */
+ if((size_t)group_name_len > sizeof(local_group_name)) {
+ if(NULL == (parent_group_name = (char *)H5MM_malloc((size_t)group_name_len)))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTALLOC, FAIL, "can't allocate buffer to hold group name, group_name_len = %zd", group_name_len)
+ } /* end if */
+ else
+ parent_group_name = local_group_name;
+
+ /* Get parent group name */
+ if(H5G_get_name(&loc, parent_group_name, (size_t) group_name_len, NULL, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve group name")
+
+ /* Make callback */
+ if((cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name, &intent, fapl_id, cb_info.user_data) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "traversal operator failed")
+
+ /* Check access flags */
+ if((intent & H5F_ACC_TRUNC) || (intent & H5F_ACC_EXCL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+ } /* end if */
+
+ /* Set file close degree for new file to "weak" */
+ if(H5P_set(fa_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree")
+
+ /*
+ * Start searching for the target file
+ */
+
+ /* Simplify intent flags for open calls */
+ intent &= (H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ);
+
+ /* Copy the file name to use */
+ if(NULL == (temp_file_name = H5MM_strdup(file_name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ temp_file_name_len = HDstrlen(temp_file_name);
+
+ /* target file_name is an absolute pathname: see RM for detailed description */
+ if(H5_CHECK_ABSOLUTE(file_name) || H5_CHECK_ABS_PATH(file_name)) {
+ /* Try opening file */
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id))) {
+ char *ptr;
+
+ H5E_clear_stack(NULL);
+
+ /* get last component of file_name */
+ H5_GET_LAST_DELIMITER(file_name, ptr)
+ HDassert(ptr);
+
+ /* Increment past delimiter */
+ ptr++;
+
+ /* Copy into the temp. file name */
+ HDstrncpy(temp_file_name, ptr, temp_file_name_len);
+ temp_file_name[temp_file_name_len - 1] = '\0';
+ } /* end if */
+ } /* end if */
+ else if(H5_CHECK_ABS_DRIVE(file_name)) {
+ /* Try opening file */
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id))) {
+
+ H5E_clear_stack(NULL);
+
+ /* strip "<drive-letter>:" */
+ HDstrncpy(temp_file_name, &file_name[2], temp_file_name_len);
+ temp_file_name[temp_file_name_len - 1] = '\0';
+ } /* end if */
+ } /* end if */
+
+ /* try searching from paths set in the environment variable */
+ if(ext_file == NULL) {
+ char *env_prefix;
+
+ if(NULL != (env_prefix = HDgetenv("HDF5_EXT_PREFIX"))) {
+ char *tmp_env_prefix, *saved_env;
+
+ if(NULL == (saved_env = tmp_env_prefix = H5MM_strdup(env_prefix)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ while((tmp_env_prefix) && (*tmp_env_prefix)) {
+ char *out_prefix_name;
+
+ out_prefix_name = H5L_getenv_prefix_name(&tmp_env_prefix/*in,out*/);
+ if(out_prefix_name && (*out_prefix_name)) {
+ if(H5L_build_name(out_prefix_name, temp_file_name, &full_name/*out*/) < 0) {
+ saved_env = (char *)H5MM_xfree(saved_env);
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+ } /* end if */
+
+ ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id);
+ full_name = (char *)H5MM_xfree(full_name);
+ if(ext_file != NULL)
+ break;
+ H5E_clear_stack(NULL);
+ } /* end if */
+ } /* end while */
+ saved_env = (char *)H5MM_xfree(saved_env);
+ } /* end if */
+ } /* end if */
+
+ /* try searching from property list */
+ if(ext_file == NULL) {
+ if(H5P_peek(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix")
+ if(my_prefix) {
+ if(H5L_build_name(my_prefix, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
+ H5E_clear_stack(NULL);
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
+ } /* end if */
+
+ /* try searching from main file's "extpath": see description in H5F_open() & H5_build_extpath() */
+ if(ext_file == NULL) {
+ char *extpath;
+
+ if(NULL != (extpath = H5F_EXTPATH(loc.oloc->file))) {
+ if(H5L_build_name(extpath, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
+ H5E_clear_stack(NULL);
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
+ } /* end if */
+
+ /* try the relative file_name stored in temp_file_name */
+ if(ext_file == NULL) {
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, temp_file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
+ H5E_clear_stack(NULL);
+ } /* end if */
+
+ /* try the 'resolved' name for the parent file (i.e. the name after symlinks
+ * were resolved)
+ */
+ if(ext_file == NULL) {
+ char *ptr = NULL;
+
+ /* Copy resolved file name */
+ if(NULL == (actual_file_name = H5MM_strdup(H5F_ACTUAL_NAME(loc.oloc->file))))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTALLOC, FAIL, "can't duplicate resolved file name string")
+
+ /* get last component of file_name */
+ H5_GET_LAST_DELIMITER(actual_file_name, ptr)
+ if(!ptr)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file, external link file name = '%s', temp_file_name = '%s'", file_name, temp_file_name)
+
+ /* Truncate filename portion from actual file name path */
+ *ptr = '\0';
+
+ /* Build new file name for the external file */
+ if(H5L_build_name(actual_file_name, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+
+ /* Try opening with the resolved name */
+ if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file, external link file name = '%s', temp_file_name = '%s'", file_name, temp_file_name)
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
+
+
+ /* Retrieve the "group location" for the file's root group */
+ if(H5G_root_loc(ext_file, &root_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file")
+
+ /* Open the object referenced in the external file */
+ if((ext_obj = H5O_open_name(&root_loc, obj_name, lapl_id, dxpl_id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+ /* Set return value */
+ ret_value = ext_obj;
+
+done:
+ /* Release resources */
+ if(fapl_id > 0 && H5I_dec_ref(fapl_id) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list")
+ if(ext_file && H5F_efc_close(loc.oloc->file, ext_file) < 0)
+ HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
+ if(parent_group_name && parent_group_name != local_group_name)
+ parent_group_name = (char *)H5MM_xfree(parent_group_name);
+ full_name = (char *)H5MM_xfree(full_name);
+ temp_file_name = (char *)H5MM_xfree(temp_file_name);
+ actual_file_name = (char *)H5MM_xfree(actual_file_name);
+
+ if(ret_value < 0) {
+ /* Close object if it's open and something failed */
+ if(ext_obj >= 0 && H5I_dec_ref(ext_obj) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for external object")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_extern_traverse() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_extern_query
+ *
+ * Purpose: Default query function for external links. This can
+ * be overridden using H5Lregister().
+ *
+ * Returns the size of the link's user data. If a buffer of
+ * is provided, copies at most buf_size bytes of the udata
+ * into it.
+ *
+ * Return: Size of buffer on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5L_extern_query(const char H5_ATTR_UNUSED * link_name, const void *_udata, size_t udata_size,
+ void *buf /*out*/, size_t buf_size)
+{
+ const uint8_t *udata = (const uint8_t *)_udata; /* Pointer to external link buffer */
+ ssize_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check external link version & flags */
+ if(((*udata >> 4) & 0x0F) != H5L_EXT_VERSION)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
+ if((*udata & 0x0F) & ~H5L_EXT_FLAGS_ALL)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
+
+ /* If the buffer is NULL, skip writing anything in it and just return
+ * the size needed */
+ if(buf) {
+ if(udata_size < buf_size)
+ buf_size = udata_size;
+
+ /* Copy the udata verbatim up to buf_size */
+ HDmemcpy(buf, udata, buf_size);
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (ssize_t)udata_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_extern_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcreate_external
+ *
+ * Purpose: Creates an external link from LINK_NAME to OBJ_NAME.
+ *
+ * External links are links to objects in other HDF5 files. They
+ * are allowed to "dangle" like soft links internal to a file.
+ * FILE_NAME is the name of the file that OBJ_NAME is is contained
+ * within. If OBJ_NAME is given as a relative path name, the
+ * path will be relative to the root group of FILE_NAME.
+ * LINK_NAME is interpreted relative to LINK_LOC_ID, which is
+ * either a file ID or a group ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 18, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcreate_external(const char *file_name, const char *obj_name,
+ hid_t link_loc_id, const char *link_name, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t link_loc; /* Group location to create link */
+ char *norm_obj_name = NULL; /* Pointer to normalized current name */
+ void *ext_link_buf = NULL; /* Buffer to contain external link */
+ size_t buf_size; /* Size of buffer to hold external link */
+ size_t file_name_len; /* Length of file name string */
+ size_t norm_obj_name_len; /* Length of normalized object name string */
+ uint8_t *p; /* Pointer into external link buffer */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "*s*si*sii", file_name, obj_name, link_loc_id, link_name,
+ lcpl_id, lapl_id);
+
+ /* Check arguments */
+ if(!file_name || !*file_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no file name specified")
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name specified")
+ if(H5G_loc(link_loc_id, &link_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!link_name || !*link_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no link name specified")
+
+ /* Get normalized copy of the link target */
+ if(NULL == (norm_obj_name = H5G_normalize(obj_name)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize object name")
+
+ /* Combine the filename and link name into a single buffer to give to the UD link */
+ file_name_len = HDstrlen(file_name) + 1;
+ norm_obj_name_len = HDstrlen(norm_obj_name) + 1;
+ buf_size = 1 + file_name_len + norm_obj_name_len;
+ if(NULL == (ext_link_buf = H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate udata buffer")
+
+ /* Encode the external link information */
+ p = (uint8_t *)ext_link_buf;
+ *p++ = (H5L_EXT_VERSION << 4) | H5L_EXT_FLAGS_ALL; /* External link version & flags */
+ HDstrncpy((char *)p, file_name, buf_size - 1); /* Name of file containing external link's object */
+ p += file_name_len;
+ HDstrncpy((char *)p, norm_obj_name, buf_size - (file_name_len + 1)); /* External link's object */
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, link_loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Create an external link */
+ if(H5L_create_ud(&link_loc, link_name, ext_link_buf, buf_size, H5L_TYPE_EXTERNAL, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ H5MM_xfree(ext_link_buf);
+ H5MM_xfree(norm_obj_name);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lcreate_external() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_register_external
+ *
+ * Purpose: Registers default "External Link" link class.
+ * Use during library initialization or to restore the default
+ * after users change it.
+ *
+ * Return: Non-negative on success/ negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_register_external(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5L_register(H5L_EXTERN_LINK_CLASS) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register external link class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_register_external() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lunpack_elink_val
+ *
+ * Purpose: Given a buffer holding the "link value" from an external link,
+ * gets pointers to the information within the link value buffer.
+ *
+ * External link link values contain some flags and
+ * two NULL-terminated strings, one after the other.
+ *
+ * The FLAGS value will be filled in and FILENAME and
+ * OBJ_PATH will be set to pointers within ext_linkval (unless
+ * any of these values is NULL).
+ *
+ * Using this function on strings that aren't external link
+ * udata buffers can result in segmentation faults.
+ *
+ * Return: Non-negative on success/ Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 17, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lunpack_elink_val(const void *_ext_linkval, size_t link_size,
+ unsigned *flags, const char **filename, const char **obj_path)
+{
+ const uint8_t *ext_linkval = (const uint8_t *)_ext_linkval; /* Pointer to the link value */
+ unsigned lnk_version; /* External link format version */
+ unsigned lnk_flags; /* External link flags */
+ size_t len; /* Length of the filename in the linkval*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*xz*Iu**s**s", _ext_linkval, link_size, flags, filename,
+ obj_path);
+
+ /* Sanity check external link buffer */
+ if(ext_linkval == NULL )
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an external link linkval buffer")
+ lnk_version = (*ext_linkval >> 4) & 0x0F;
+ lnk_flags = *ext_linkval & 0x0F;
+ if(lnk_version > H5L_EXT_VERSION)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
+ if(lnk_flags & (unsigned)~H5L_EXT_FLAGS_ALL)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
+ if(link_size <= 2)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid external link buffer")
+
+ /* Try to do some error checking. If the last character in the linkval
+ * (the last character of obj_path) isn't NULL, then something's wrong.
+ */
+ if(ext_linkval[link_size - 1] != '\0')
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "linkval buffer is not NULL-terminated")
+
+ /* We're now guaranteed that HDstrlen won't segfault, since the buffer has
+ * at least one NULL in it.
+ */
+ len = HDstrlen((const char *)ext_linkval + 1);
+
+ /* If the first NULL we found was at the very end of the buffer, then
+ * this external link value has no object name and is invalid.
+ */
+ if((len + 1) >= (link_size - 1))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "linkval buffer doesn't contain an object path")
+
+ /* If we got here then the buffer contains (at least) two strings packed
+ * in the correct way. Assume it's correct and return pointers to the
+ * filename and object path.
+ */
+ if(filename)
+ *filename = (const char *)ext_linkval + 1;
+ if(obj_path)
+ *obj_path = ((const char *)ext_linkval + 1) + len + 1; /* Add one for NULL terminator */
+
+ /* Set the flags to return */
+ if(flags)
+ *flags = lnk_flags;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lunpack_elink_val() */
+
diff --git a/src/H5Lmodule.h b/src/H5Lmodule.h
new file mode 100644
index 0000000..cba4de4
--- /dev/null
+++ b/src/H5Lmodule.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5L package. Including this header means that the source file
+ * is part of the H5L package.
+ */
+#ifndef _H5Lmodule_H
+#define _H5Lmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5L_MODULE
+#define H5_MY_PKG H5L
+#define H5_MY_PKG_ERR H5E_LINK
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Lmodule_H */
+
+
diff --git a/src/H5Lpkg.h b/src/H5Lpkg.h
new file mode 100644
index 0000000..39e3197
--- /dev/null
+++ b/src/H5Lpkg.h
@@ -0,0 +1,62 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: James Laird <matzke@llnl.gov>
+ * Friday, December 1, 2005
+ *
+ * Purpose: This file contains declarations which are visible
+ * only within the H5L package. Source files outside the
+ * H5L package should include H5Lprivate.h instead.
+ */
+#if !(defined H5L_FRIEND || defined H5L_MODULE)
+#error "Do not include this file outside the H5L package!"
+#endif
+
+#ifndef _H5Lpkg_H
+#define _H5Lpkg_H
+
+/* Get package's private header */
+#include "H5Lprivate.h"
+
+/* Other private headers needed by this file */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+H5_DLL herr_t H5L_create_ud(const H5G_loc_t *link_loc, const char *link_name,
+ const void * ud_data, size_t ud_data_size, H5L_type_t type,
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_link_copy_file(H5F_t *dst_file, hid_t dxpl_id,
+ const H5O_link_t *_src_lnk, const H5O_loc_t *src_oloc, H5O_link_t *dst_lnk,
+ H5O_copy_t *cpy_info);
+
+#endif /* _H5Lpkg_H */
+
diff --git a/src/H5Lprivate.h b/src/H5Lprivate.h
new file mode 100644
index 0000000..dd243a6
--- /dev/null
+++ b/src/H5Lprivate.h
@@ -0,0 +1,98 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5L module
+ * for dealing with links in an HDF5 file.
+ */
+#ifndef _H5Lprivate_H
+#define _H5Lprivate_H
+
+/* Include package's public header */
+#include "H5Lpublic.h"
+
+/* Private headers needed by this file */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Oprivate.h" /* Object headers */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Default number of soft links to traverse */
+#define H5L_NUM_LINKS 16
+
+/* ======== Link creation property names ======== */
+#define H5L_CRT_INTERMEDIATE_GROUP_NAME "intermediate_group" /* Create intermediate groups flag */
+
+/* ======== Link access property names ======== */
+#define H5L_ACS_NLINKS_NAME "max soft links" /* Number of soft links to traverse */
+#define H5L_ACS_ELINK_PREFIX_NAME "external link prefix" /* External link prefix */
+#define H5L_ACS_ELINK_FAPL_NAME "external link fapl" /* file access property list for external link access */
+#define H5L_ACS_ELINK_FLAGS_NAME "external link flags" /* file access flags for external link traversal */
+#define H5L_ACS_ELINK_CB_NAME "external link callback" /* callback function for external link traversal */
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Structure for external link traversal callback property */
+typedef struct H5L_elink_cb_t {
+ H5L_elink_traverse_t func;
+ void *user_data;
+} H5L_elink_cb_t;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Library Private Prototypes */
+/******************************/
+
+/* General operations on links */
+H5_DLL herr_t H5L_init(void);
+H5_DLL herr_t H5L_link(const H5G_loc_t *new_loc, const char *new_name,
+ H5G_loc_t *obj_loc, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_link_object(const H5G_loc_t *new_loc, const char *new_name,
+ H5O_obj_create_t *ocrt_info, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
+ const H5G_loc_t *link_loc, const char *link_name, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_create_soft(const char *target_path, const H5G_loc_t *cur_loc,
+ const char *cur_name, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL hid_t H5L_get_default_lcpl(void);
+H5_DLL herr_t H5L_move(H5G_loc_t *src_loc, const char *src_name,
+ H5G_loc_t *dst_loc, const char *dst_name, hbool_t copy_flag,
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL htri_t H5L_exists_tolerant(const H5G_loc_t *loc, const char *name, hid_t lapl_id,
+ hid_t dxpl_id);
+H5_DLL herr_t H5L_get_info(const H5G_loc_t *loc, const char *name,
+ H5L_info_t *linkbuf/*out*/, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_delete(H5G_loc_t *loc, const char *name, hid_t lapl_id,
+ hid_t dxpl_id);
+H5_DLL herr_t H5L_get_val(H5G_loc_t *loc, const char *name, void *buf/*out*/,
+ size_t size, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5L_register_external(void);
+
+/* User-defined link functions */
+H5_DLL herr_t H5L_register(const H5L_class_t *cls);
+H5_DLL herr_t H5L_unregister(H5L_type_t id);
+H5_DLL const H5L_class_t *H5L_find_class(H5L_type_t id);
+
+#endif /* _H5Lprivate_H */
+
diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h
new file mode 100644
index 0000000..9d1643e
--- /dev/null
+++ b/src/H5Lpublic.h
@@ -0,0 +1,200 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Lpublic.h
+ * Dec 1 2005
+ * James Laird
+ *
+ * Purpose: Public declarations for the H5L package (links)
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Lpublic_H
+#define _H5Lpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h" /* Generic Functions */
+#include "H5Ipublic.h" /* IDs */
+#include "H5Tpublic.h" /* Datatypes */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Maximum length of a link's name */
+/* (encoded in a 32-bit unsigned integer) */
+#define H5L_MAX_LINK_NAME_LEN ((uint32_t)(-1)) /* (4GB - 1) */
+
+/* Macro to indicate operation occurs on same location */
+#define H5L_SAME_LOC (hid_t)0
+
+/* Current version of the H5L_class_t struct */
+#define H5L_LINK_CLASS_T_VERS 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/* Link class types.
+ * Values less than 64 are reserved for the HDF5 library's internal use.
+ * Values 64 to 255 are for "user-defined" link class types; these types are
+ * defined by HDF5 but their behavior can be overridden by users.
+ * Users who want to create new classes of links should contact the HDF5
+ * development team at hdfhelp@ncsa.uiuc.edu .
+ * These values can never change because they appear in HDF5 files.
+ */
+typedef enum {
+ H5L_TYPE_ERROR = (-1), /* Invalid link type id */
+ H5L_TYPE_HARD = 0, /* Hard link id */
+ H5L_TYPE_SOFT = 1, /* Soft link id */
+ H5L_TYPE_EXTERNAL = 64, /* External link id */
+ H5L_TYPE_MAX = 255 /* Maximum link type id */
+} H5L_type_t;
+#define H5L_TYPE_BUILTIN_MAX H5L_TYPE_SOFT /* Maximum value link value for "built-in" link types */
+#define H5L_TYPE_UD_MIN H5L_TYPE_EXTERNAL /* Link ids at or above this value are "user-defined" link types. */
+
+/* Information struct for link (for H5Lget_info/H5Lget_info_by_idx) */
+typedef struct {
+ H5L_type_t type; /* Type of link */
+ hbool_t corder_valid; /* Indicate if creation order is valid */
+ int64_t corder; /* Creation order */
+ H5T_cset_t cset; /* Character set of link name */
+ union {
+ haddr_t address; /* Address hard link points to */
+ size_t val_size; /* Size of a soft link or UD link value */
+ } u;
+} H5L_info_t;
+
+/* The H5L_class_t struct can be used to override the behavior of a
+ * "user-defined" link class. Users should populate the struct with callback
+ * functions defined below.
+ */
+/* Callback prototypes for user-defined links */
+/* Link creation callback */
+typedef herr_t (*H5L_create_func_t)(const char *link_name, hid_t loc_group,
+ const void *lnkdata, size_t lnkdata_size, hid_t lcpl_id);
+
+/* Callback for when the link is moved */
+typedef herr_t (*H5L_move_func_t)(const char *new_name, hid_t new_loc,
+ const void *lnkdata, size_t lnkdata_size);
+
+/* Callback for when the link is copied */
+typedef herr_t (*H5L_copy_func_t)(const char *new_name, hid_t new_loc,
+ const void *lnkdata, size_t lnkdata_size);
+
+/* Callback during link traversal */
+typedef hid_t (*H5L_traverse_func_t)(const char *link_name, hid_t cur_group,
+ const void *lnkdata, size_t lnkdata_size, hid_t lapl_id);
+
+/* Callback for when the link is deleted */
+typedef herr_t (*H5L_delete_func_t)(const char *link_name, hid_t file,
+ const void *lnkdata, size_t lnkdata_size);
+
+/* Callback for querying the link */
+/* Returns the size of the buffer needed */
+typedef ssize_t (*H5L_query_func_t)(const char *link_name, const void *lnkdata,
+ size_t lnkdata_size, void *buf /*out*/, size_t buf_size);
+
+/* User-defined link types */
+typedef struct {
+ int version; /* Version number of this struct */
+ H5L_type_t id; /* Link type ID */
+ const char *comment; /* Comment for debugging */
+ H5L_create_func_t create_func; /* Callback during link creation */
+ H5L_move_func_t move_func; /* Callback after moving link */
+ H5L_copy_func_t copy_func; /* Callback after copying link */
+ H5L_traverse_func_t trav_func; /* Callback during link traversal */
+ H5L_delete_func_t del_func; /* Callback for link deletion */
+ H5L_query_func_t query_func; /* Callback for queries */
+} H5L_class_t;
+
+/* Prototype for H5Literate/H5Literate_by_name() operator */
+typedef herr_t (*H5L_iterate_t)(hid_t group, const char *name, const H5L_info_t *info,
+ void *op_data);
+
+/* Callback for external link traversal */
+typedef herr_t (*H5L_elink_traverse_t)(const char *parent_file_name,
+ const char *parent_group_name, const char *child_file_name,
+ const char *child_object_name, unsigned *acc_flags, hid_t fapl_id,
+ void *op_data);
+
+
+/********************/
+/* Public Variables */
+/********************/
+
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+H5_DLL herr_t H5Lmove(hid_t src_loc, const char *src_name, hid_t dst_loc,
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id);
+H5_DLL herr_t H5Lcopy(hid_t src_loc, const char *src_name, hid_t dst_loc,
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id);
+H5_DLL herr_t H5Lcreate_hard(hid_t cur_loc, const char *cur_name,
+ hid_t dst_loc, const char *dst_name, hid_t lcpl_id, hid_t lapl_id);
+H5_DLL herr_t H5Lcreate_soft(const char *link_target, hid_t link_loc_id,
+ const char *link_name, hid_t lcpl_id, hid_t lapl_id);
+H5_DLL herr_t H5Ldelete(hid_t loc_id, const char *name, hid_t lapl_id);
+H5_DLL herr_t H5Ldelete_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id);
+H5_DLL herr_t H5Lget_val(hid_t loc_id, const char *name, void *buf/*out*/,
+ size_t size, hid_t lapl_id);
+H5_DLL herr_t H5Lget_val_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ void *buf/*out*/, size_t size, hid_t lapl_id);
+H5_DLL htri_t H5Lexists(hid_t loc_id, const char *name, hid_t lapl_id);
+H5_DLL herr_t H5Lget_info(hid_t loc_id, const char *name,
+ H5L_info_t *linfo /*out*/, hid_t lapl_id);
+H5_DLL herr_t H5Lget_info_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ H5L_info_t *linfo /*out*/, hid_t lapl_id);
+H5_DLL ssize_t H5Lget_name_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
+ char *name /*out*/, size_t size, hid_t lapl_id);
+H5_DLL herr_t H5Literate(hid_t grp_id, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t *idx, H5L_iterate_t op, void *op_data);
+H5_DLL herr_t H5Literate_by_name(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t *idx,
+ H5L_iterate_t op, void *op_data, hid_t lapl_id);
+H5_DLL herr_t H5Lvisit(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order,
+ H5L_iterate_t op, void *op_data);
+H5_DLL herr_t H5Lvisit_by_name(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op,
+ void *op_data, hid_t lapl_id);
+
+/* UD link functions */
+H5_DLL herr_t H5Lcreate_ud(hid_t link_loc_id, const char *link_name,
+ H5L_type_t link_type, const void *udata, size_t udata_size, hid_t lcpl_id,
+ hid_t lapl_id);
+H5_DLL herr_t H5Lregister(const H5L_class_t *cls);
+H5_DLL herr_t H5Lunregister(H5L_type_t id);
+H5_DLL htri_t H5Lis_registered(H5L_type_t id);
+
+/* External link functions */
+H5_DLL herr_t H5Lunpack_elink_val(const void *ext_linkval/*in*/, size_t link_size,
+ unsigned *flags, const char **filename/*out*/, const char **obj_path /*out*/);
+H5_DLL herr_t H5Lcreate_external(const char *file_name, const char *obj_name,
+ hid_t link_loc_id, const char *link_name, hid_t lcpl_id, hid_t lapl_id);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Lpublic_H */
+
diff --git a/src/H5MF.c b/src/H5MF.c
new file mode 100644
index 0000000..e54d809
--- /dev/null
+++ b/src/H5MF.c
@@ -0,0 +1,3919 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MF.c
+ * Jul 11 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: File memory management functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#define H5FS_FRIEND /*suppress error about including H5Fpkg */
+#include "H5MFmodule.h" /* This source code file is part of the H5MF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FSpkg.h" /* File access */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MFpkg.h" /* File memory management */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5MF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */
+#define H5MF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Enum for kind of free space section+aggregator merging allowed for a file */
+typedef enum {
+ H5MF_AGGR_MERGE_SEPARATE, /* Everything in separate free list */
+ H5MF_AGGR_MERGE_DICHOTOMY, /* Metadata in one free list and raw data in another */
+ H5MF_AGGR_MERGE_TOGETHER /* Metadata & raw data in one free list */
+} H5MF_aggr_merge_t;
+
+/* User data for section info iterator callback for iterating over free space sections */
+typedef struct {
+ H5F_sect_info_t *sects; /* section info to be retrieved */
+ size_t sect_count; /* # of sections requested */
+ size_t sect_idx; /* the current count of sections */
+} H5MF_sect_iter_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Allocator routines */
+static haddr_t H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size);
+
+/* "File closing" routines */
+static herr_t H5MF__close_aggrfs(H5F_t *f, hid_t dxpl_id);
+static herr_t H5MF__close_pagefs(H5F_t *f, hid_t dxpl_id);
+static herr_t H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id);
+
+/* General routines */
+static herr_t H5MF__get_free_sects(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums);
+static hbool_t H5MF__fsm_type_is_self_referential(H5F_t *f, H5F_mem_page_t fsm_type);
+static hbool_t H5MF__fsm_is_self_referential(H5F_t *f, H5FS_t *fspace);
+
+/* Free-space type manager routines */
+static herr_t H5MF__create_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+static herr_t H5MF__close_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+static herr_t H5MF__delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+static herr_t H5MF__close_delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_init_merge_flags
+ *
+ * Purpose: Initialize the free space section+aggregator merge flags
+ * for the file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 1, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_init_merge_flags(H5F_t *f)
+{
+ H5MF_aggr_merge_t mapping_type; /* Type of free list mapping */
+ H5FD_mem_t type; /* Memory type for iteration */
+ hbool_t all_same; /* Whether all the types map to the same value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+
+ /* Iterate over all the free space types to determine if sections of that type
+ * can merge with the metadata or small 'raw' data aggregator
+ */
+ all_same = TRUE;
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ /* Check for any different type mappings */
+ if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_DEFAULT]) {
+ all_same = FALSE;
+ break;
+ } /* end if */
+
+ /* Check for all allocation types mapping to the same free list type */
+ if(all_same) {
+ if(f->shared->fs_type_map[H5FD_MEM_DEFAULT] == H5FD_MEM_DEFAULT)
+ mapping_type = H5MF_AGGR_MERGE_SEPARATE;
+ else
+ mapping_type = H5MF_AGGR_MERGE_TOGETHER;
+ } /* end if */
+ else {
+ /* Check for raw data mapping into same list as metadata */
+ if(f->shared->fs_type_map[H5FD_MEM_DRAW] == f->shared->fs_type_map[H5FD_MEM_SUPER])
+ mapping_type = H5MF_AGGR_MERGE_SEPARATE;
+ else {
+ hbool_t all_metadata_same; /* Whether all metadata go in same free list */
+
+ /* One or more allocation type don't map to the same free list type */
+ /* Check if all the metadata allocation types map to the same type */
+ all_metadata_same = TRUE;
+ for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ /* Skip checking raw data free list mapping */
+ /* (global heap is treated as raw data) */
+ if(type != H5FD_MEM_DRAW && type != H5FD_MEM_GHEAP) {
+ /* Check for any different type mappings */
+ if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_SUPER]) {
+ all_metadata_same = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Check for all metadata on same free list */
+ if(all_metadata_same)
+ mapping_type = H5MF_AGGR_MERGE_DICHOTOMY;
+ else
+ mapping_type = H5MF_AGGR_MERGE_SEPARATE;
+ } /* end else */
+ } /* end else */
+
+ /* Based on mapping type, initialize merging flags for each free list type */
+ switch(mapping_type) {
+ case H5MF_AGGR_MERGE_SEPARATE:
+ /* Don't merge any metadata together */
+ HDmemset(f->shared->fs_aggr_merge, 0, sizeof(f->shared->fs_aggr_merge));
+
+ /* Check if merging raw data should be allowed */
+ /* (treat global heaps as raw data) */
+ if(H5FD_MEM_DRAW == f->shared->fs_type_map[H5FD_MEM_DRAW] ||
+ H5FD_MEM_DEFAULT == f->shared->fs_type_map[H5FD_MEM_DRAW]) {
+ f->shared->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA;
+ f->shared->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
+ } /* end if */
+ break;
+
+ case H5MF_AGGR_MERGE_DICHOTOMY:
+ /* Merge all metadata together (but not raw data) */
+ HDmemset(f->shared->fs_aggr_merge, H5F_FS_MERGE_METADATA, sizeof(f->shared->fs_aggr_merge));
+
+ /* Allow merging raw data allocations together */
+ /* (treat global heaps as raw data) */
+ f->shared->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA;
+ f->shared->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA;
+ break;
+
+ case H5MF_AGGR_MERGE_TOGETHER:
+ /* Merge all allocation types together */
+ HDmemset(f->shared->fs_aggr_merge, (H5F_FS_MERGE_METADATA | H5F_FS_MERGE_RAWDATA), sizeof(f->shared->fs_aggr_merge));
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADVALUE, FAIL, "invalid mapping type")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_init_merge_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_alloc_to_fs_type
+ *
+ * Purpose: Map "alloc_type" to the free-space manager type
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Nov 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5MF_alloc_to_fs_type(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size, H5F_mem_page_t *fs_type)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(fs_type);
+
+ if(H5F_PAGED_AGGR(f)) { /* paged aggregation */
+ if(size >= f->shared->fs_page_size) {
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_PAGED_AGGR)) { /* multi or split driver */
+ /* For non-contiguous address space, map to large size free-space manager for each alloc_type */
+ if(H5FD_MEM_DEFAULT == f->shared->fs_type_map[alloc_type])
+ *fs_type = (H5F_mem_page_t) (alloc_type + (H5FD_MEM_NTYPES - 1));
+ else
+ *fs_type = (H5F_mem_page_t) (f->shared->fs_type_map[alloc_type] + (H5FD_MEM_NTYPES - 1));
+ } /* end if */
+ else
+ /* For contiguous address space, map to generic large size free-space manager */
+ *fs_type = H5F_MEM_PAGE_GENERIC; /* H5F_MEM_PAGE_SUPER */
+ } /* end if */
+ else
+ *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f, alloc_type);
+ } /* end if */
+ else /* non-paged aggregation */
+ *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f, alloc_type);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5MF_alloc_to_fs_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_open_fstype
+ *
+ * Purpose: Open an existing free space manager of TYPE for file by
+ * creating a free-space structure.
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 8 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_open_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */
+ H5MF_FSPACE_SECT_CLS_SIMPLE,
+ H5MF_FSPACE_SECT_CLS_SMALL,
+ H5MF_FSPACE_SECT_CLS_LARGE };
+ hsize_t alignment; /* Alignment to use */
+ hsize_t threshold; /* Threshold to use */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else {
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+ HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
+ } /* end else */
+ HDassert(f->shared);
+ HDassert(H5F_addr_defined(f->shared->fs_addr[type]));
+ HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
+
+ /* Set up the aligment and threshold to use depending on the manager type */
+ if(H5F_PAGED_AGGR(f)) {
+ alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF;
+ threshold = H5F_ALIGN_THRHD_DEF;
+ } /* end if */
+ else {
+ alignment = f->shared->alignment;
+ threshold = f->shared->threshold;
+ } /* end else */
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* Open an existing free space structure for the file */
+ if(NULL == (f->shared->fs_man[type] = H5FS_open(f, dxpl_id, f->shared->fs_addr[type],
+ NELMTS(classes), classes, f, alignment, threshold)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
+
+ /* Set the state for the free space manager to "open", if it is now */
+ if(f->shared->fs_man[type])
+ f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_open_fstype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__create_fstype
+ *
+ * Purpose: Create free space manager of TYPE for the file by creating
+ * a free-space structure
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 8 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__create_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */
+ H5MF_FSPACE_SECT_CLS_SIMPLE,
+ H5MF_FSPACE_SECT_CLS_SMALL,
+ H5MF_FSPACE_SECT_CLS_LARGE };
+ H5FS_create_t fs_create; /* Free space creation parameters */
+ hsize_t alignment; /* Alignment to use */
+ hsize_t threshold; /* Threshold to use */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else {
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+ HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
+ } /* end else */
+ HDassert(f->shared);
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
+ HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED);
+
+ /* Set the free space creation parameters */
+ fs_create.client = H5FS_CLIENT_FILE_ID;
+ fs_create.shrink_percent = H5MF_FSPACE_SHRINK;
+ fs_create.expand_percent = H5MF_FSPACE_EXPAND;
+ fs_create.max_sect_addr = 1 + H5VM_log2_gen((uint64_t)f->shared->maxaddr);
+ fs_create.max_sect_size = f->shared->maxaddr;
+
+ /* Set up alignment and threshold to use depending on TYPE */
+ if(H5F_PAGED_AGGR(f)) {
+ alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF;
+ threshold = H5F_ALIGN_THRHD_DEF;
+ } /* end if */
+ else {
+ alignment = f->shared->alignment;
+ threshold = f->shared->threshold;
+ } /* end else */
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ if(NULL == (f->shared->fs_man[type] = H5FS_create(f, dxpl_id, NULL,
+ &fs_create, NELMTS(classes), classes, f, alignment, threshold)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info")
+
+ /* Set the state for the free space manager to "open", if it is now */
+ if(f->shared->fs_man[type])
+ f->shared->fs_state[type] = H5F_FS_STATE_OPEN;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__create_fstype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_start_fstype
+ *
+ * Purpose: Open or create a free space manager of a given TYPE.
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 8 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_start_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(f->shared);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else {
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+ HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST);
+ } /* end else */
+
+ /* Check if the free space manager exists already */
+ if(H5F_addr_defined(f->shared->fs_addr[type])) {
+ /* Open existing free space manager */
+ if(H5MF_open_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space")
+ } /* end if */
+ else {
+ /* Create new free space manager */
+ if(H5MF__create_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCREATE, FAIL, "can't initialize file free space")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_start_fstype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__delete_fstype
+ *
+ * Purpose: Delete the free-space manager as specified by TYPE.
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; April 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ haddr_t tmp_fs_addr; /* Temporary holder for free space manager address */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* check args */
+ HDassert(f);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+ HDassert(H5F_addr_defined(f->shared->fs_addr[type]));
+
+ /* Put address into temporary variable and reset it */
+ /* (Avoids loopback in file space freeing routine) */
+ tmp_fs_addr = f->shared->fs_addr[type];
+ f->shared->fs_addr[type] = HADDR_UNDEF;
+
+ /* Shift to "deleting" state, to make certain we don't track any
+ * file space freed as a result of deleting the free space manager.
+ */
+ f->shared->fs_state[type] = H5F_FS_STATE_DELETING;
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Before deleting free space manager\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Delete free space manager for this type */
+ if(H5FS_delete(f, dxpl_id, tmp_fs_addr) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't delete free space manager")
+
+ /* Shift [back] to closed state */
+ HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING);
+ f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
+
+ /* Sanity check that the free space manager for this type wasn't started up again */
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[type]));
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__delete_fstype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__close_fstype
+ *
+ * Purpose: Close the free space manager of TYPE for file
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; July 1st, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__close_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+ HDassert(f->shared);
+ HDassert(f->shared->fs_man[type]);
+ HDassert(f->shared->fs_state[type] != H5F_FS_STATE_CLOSED);
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Before closing free space manager\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Close an existing free space structure for the file */
+ if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info")
+ f->shared->fs_man[type] = NULL;
+ f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__close_fstype() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_add_sect
+ *
+ * Purpose: To add a section to the specified free-space manager.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; April 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_add_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, H5FS_t *fspace, H5MF_free_section_t *node)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ H5MF_sect_ud_t udata; /* User data for callback */
+ H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */
+
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(fspace);
+ HDassert(node);
+
+ H5MF_alloc_to_fs_type(f, alloc_type, node->sect_info.size, &fs_type);
+
+ /* Construct user data for callbacks */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.alloc_type = alloc_type;
+ udata.allow_sect_absorb = TRUE;
+ udata.allow_eoa_shrink_only = FALSE;
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_is_self_referential(f, fspace))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: adding node, node->sect_info.addr = %a, node->sect_info.size = %Hu\n", FUNC, node->sect_info.addr, node->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ /* Add the section */
+ if(H5FS_sect_add(f, dxpl_id, fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_add_sect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_find_sect
+ *
+ * Purpose: To find a section from the specified free-space manager to fulfill the request.
+ * If found, re-add the left-over space back to the manager.
+ *
+ * Return: TRUE if a section is found to fulfill the request
+ * FALSE if not
+ *
+ * Programmer: Vailin Choi; April 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_find_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size, H5FS_t *fspace, haddr_t *addr)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ H5MF_free_section_t *node; /* Free space section pointer */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ htri_t ret_value = FAIL; /* Whether an existing free list node was found */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(fspace);
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_is_self_referential(f, fspace))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* Try to get a section from the free space manager */
+ if((ret_value = H5FS_sect_find(f, dxpl_id, fspace, size, (H5FS_section_info_t **)&node)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "error locating free space in file")
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section found = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Check for actually finding section */
+ if(ret_value) {
+ /* Sanity check */
+ HDassert(node);
+
+ /* Retrieve return value */
+ if(addr)
+ *addr = node->sect_info.addr;
+
+ /* Check for eliminating the section */
+ if(node->sect_info.size == size) {
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: freeing node\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Free section node */
+ if(H5MF_sect_free((H5FS_section_info_t *)node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+ } /* end if */
+ else {
+ /* Adjust information for section */
+ node->sect_info.addr += size;
+ node->sect_info.size -= size;
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: re-adding node, node->sect_info.size = %Hu\n", FUNC, node->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Re-add the section to the free-space manager */
+ if(H5MF_add_sect(f, alloc_type, dxpl_id, fspace, node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_find_sect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_alloc
+ *
+ * Purpose: Allocate SIZE bytes of file memory and return the relative
+ * address where that contiguous chunk of file memory exists.
+ * The TYPE argument describes the purpose for which the storage
+ * is being requested.
+ *
+ * Return: Success: The file address of new chunk.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* free space manager ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, HADDR_UNDEF)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(size > 0);
+
+ if(f->shared->first_alloc_dealloc) {
+ HDassert(! H5AC_cache_image_pending(f));
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "tidy of self referential fsm hack failed")
+ } /* end if */
+
+ H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type);
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Check 1.0\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, fs_type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, HADDR_UNDEF, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* Check if we are using the free space manager for this file */
+ if(H5F_HAVE_FREE_SPACE_MANAGER(f)) {
+ /* We are about to change the contents of the free space manager --
+ * notify metadata cache that the associated fsm ring is
+ * unsettled
+ */
+ if(H5AC_unsettle_ring(f, fsm_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, HADDR_UNDEF, "attempt to notify cache that ring is unsettled failed")
+
+ /* Check if the free space manager for the file has been initialized */
+ if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type])) {
+ /* Open the free-space manager */
+ if(H5MF_open_fstype(f, dxpl_id, fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, HADDR_UNDEF, "can't initialize file free space")
+ HDassert(f->shared->fs_man[fs_type]);
+ } /* end if */
+
+ /* Search for large enough space in the free space manager */
+ if(f->shared->fs_man[fs_type])
+ if(H5MF_find_sect(f, alloc_type, dxpl_id, size, f->shared->fs_man[fs_type], &ret_value) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating a node")
+ } /* end if */
+
+ /* If no space is found from the free-space manager, continue further action */
+ if(!H5F_addr_defined(ret_value)) {
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Check 2.0\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ if(f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE) {
+ HDassert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN);
+ if(HADDR_UNDEF == (ret_value = H5MF__alloc_pagefs(f, alloc_type, dxpl_id, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from paged aggregation")
+ } /* end if */
+ else { /* For non-paged aggregation, continue further action */
+ if(HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, dxpl_id, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd")
+ } /* end else */
+ } /* end if */
+ HDassert(H5F_addr_defined(ret_value));
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Check 3.0\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, HADDR_UNDEF, "unable to set property value")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size);
+#endif /* H5MF_ALLOC_DEBUG */
+#ifdef H5MF_ALLOC_DEBUG_DUMP
+H5MF_sects_dump(f, dxpl_id, stderr);
+#endif /* H5MF_ALLOC_DEBUG_DUMP */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF)
+} /* end H5MF_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__alloc_pagefs
+ *
+ * Purpose: Allocate space from either the large or small free-space manager.
+ * For "large" request:
+ * Allocate request from VFD
+ * Determine mis-aligned fragment and return the fragment to the
+ * appropriate manager
+ * For "small" request:
+ * Allocate a page from the large manager
+ * Determine whether space is available from a mis-aligned fragment
+ * being returned to the manager
+ * Return left-over space to the manager after fulfilling request
+ *
+ * Return: Success: The file address of new chunk.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size)
+{
+ H5F_mem_page_t ptype; /* Free-space mananger type */
+ H5MF_free_section_t *node = NULL; /* Free space section pointer */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, HADDR_UNDEF)
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ H5MF_alloc_to_fs_type(f, alloc_type, size, &ptype);
+
+ switch(ptype) {
+ case H5F_MEM_PAGE_GENERIC:
+ case H5F_MEM_PAGE_LARGE_BTREE:
+ case H5F_MEM_PAGE_LARGE_DRAW:
+ case H5F_MEM_PAGE_LARGE_GHEAP:
+ case H5F_MEM_PAGE_LARGE_LHEAP:
+ case H5F_MEM_PAGE_LARGE_OHDR:
+ {
+ haddr_t eoa; /* EOA for the file */
+ hsize_t frag_size = 0; /* Fragment size */
+
+ /* Get the EOA for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa")
+ HDassert(!(eoa % f->shared->fs_page_size));
+
+ H5MF_EOA_MISALIGN(f, (eoa+size), f->shared->fs_page_size, frag_size);
+
+ /* Allocate from VFD */
+ if(HADDR_UNDEF == (ret_value = H5F_alloc(f, dxpl_id, alloc_type, size + frag_size, NULL, NULL)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
+
+ /* If there is a mis-aligned fragment at EOA */
+ if(frag_size) {
+
+ /* Start up the free-space manager */
+ if(!(f->shared->fs_man[ptype]))
+ if(H5MF_start_fstype(f, dxpl_id, ptype) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space")
+
+ /* Create free space section for the fragment */
+ if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_LARGE, ret_value + size, frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section")
+
+ /* Add the fragment to the large free-space manager */
+ if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[ptype], node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space")
+
+ node = NULL;
+ } /* end if */
+ }
+ break;
+
+ case H5F_MEM_PAGE_META:
+ case H5F_MEM_PAGE_DRAW:
+ case H5F_MEM_PAGE_BTREE:
+ case H5F_MEM_PAGE_GHEAP:
+ case H5F_MEM_PAGE_LHEAP:
+ case H5F_MEM_PAGE_OHDR:
+ {
+ haddr_t new_page; /* The address for the new file size page */
+
+ /* Allocate one file space page */
+ if(HADDR_UNDEF == (new_page = H5MF_alloc(f, alloc_type, dxpl_id, f->shared->fs_page_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
+
+ /* Start up the free-space manager */
+ if(!(f->shared->fs_man[ptype]))
+ if(H5MF_start_fstype(f, dxpl_id, ptype) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space")
+ HDassert(f->shared->fs_man[ptype]);
+
+ if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_SMALL, (new_page + size), (f->shared->fs_page_size - size))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section")
+
+ /* Add the remaining space in the page to the manager */
+ if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[ptype], node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space")
+
+ node = NULL;
+
+ /* Insert the new page into the Page Buffer list of new pages so
+ we don't read an empty page from disk */
+ if(f->shared->page_buf != NULL && H5PB_add_new_page(f, alloc_type, new_page) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't add new page to Page Buffer new page list")
+
+ ret_value = new_page;
+ }
+ break;
+
+ case H5F_MEM_PAGE_NTYPES:
+ case H5F_MEM_PAGE_DEFAULT:
+ default:
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space: unrecognized type")
+ break;
+ } /* end switch */
+
+done:
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size);
+#endif /* H5MF_ALLOC_DEBUG */
+#ifdef H5MF_ALLOC_DEBUG_DUMP
+H5MF_sects_dump(f, dxpl_id, stderr);
+#endif /* H5MF_ALLOC_DEBUG_DUMP */
+
+ /* Release section node, if allocated and not added to section list or merged */
+ if(node)
+ if(H5MF_sect_free((H5FS_section_info_t *)node) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free section node")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF)
+} /* end H5MF__alloc_pagefs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_alloc_tmp
+ *
+ * Purpose: Allocate temporary space in the file
+ *
+ * Note: The address returned is non-overlapping with any other address
+ * in the file and suitable for insertion into the metadata
+ * cache.
+ *
+ * The address is _not_ suitable for actual file I/O and will
+ * cause an error if it is so used.
+ *
+ * The space allocated with this routine should _not_ be freed,
+ * it should just be abandoned. Calling H5MF_xfree() with space
+ * from this routine will cause an error.
+ *
+ * Return: Success: Temporary file address
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 4, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5MF_alloc_tmp(H5F_t *f, hsize_t size)
+{
+ haddr_t eoa; /* End of allocated space in the file */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: size = %Hu\n", FUNC, size);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(size > 0);
+
+ /* Retrieve the 'eoa' for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
+
+ /* Compute value to return */
+ ret_value = f->shared->tmp_addr - size;
+
+ /* Check for overlap into the actual allocated space in the file */
+ if(H5F_addr_le(ret_value, eoa))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed")
+
+ /* Adjust temporary address allocator in the file */
+ f->shared->tmp_addr = ret_value;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_alloc_tmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_xfree
+ *
+ * Purpose: Frees part of a file, making that part of the file
+ * available for reuse.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 17 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr,
+ hsize_t size)
+{
+ H5F_io_info2_t fio_info; /* I/O info for operation */
+ H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */
+ H5MF_free_section_t *node = NULL; /* Free space section pointer */
+ unsigned ctype; /* section class type */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of fsm */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check arguments */
+ HDassert(f);
+ if(!H5F_addr_defined(addr) || 0 == size)
+ HGOTO_DONE(SUCCEED)
+ HDassert(addr != 0); /* Can't deallocate the superblock :-) */
+
+ if(f->shared->first_alloc_dealloc) {
+ HDassert(!H5AC_cache_image_pending(f));
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed")
+ } /* end if */
+
+ H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type);
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, fs_type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* we are about to change the contents of the free space manager --
+ * notify metadata cache that the associated fsm ring is
+ * unsettled
+ */
+ /* Only do so for strategies that use free-space managers */
+ if(H5F_HAVE_FREE_SPACE_MANAGER(f))
+ if(H5AC_unsettle_ring(f, fsm_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "attempt to notify cache that ring is unsettled failed")
+
+ /* Check for attempting to free space that's a 'temporary' file address */
+ if(H5F_addr_le(f->shared->tmp_addr, addr))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space")
+
+ /* Set up I/O info for operation */
+ fio_info.f = f;
+ if(H5FD_MEM_DRAW == alloc_type) {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end if */
+ else {
+ if(NULL == (fio_info.meta_dxpl = (H5P_genplist_t *)H5I_object(dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ if(NULL == (fio_info.raw_dxpl = (H5P_genplist_t *)H5I_object(H5AC_rawdata_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+ } /* end else */
+
+ /* Check if the space to free intersects with the file's metadata accumulator */
+ if(H5F__accum_free(&fio_info, alloc_type, addr, size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't check free space intersection w/metadata accumulator")
+
+ /* Check if the free space manager for the file has been initialized */
+ if(!f->shared->fs_man[fs_type]) {
+ /* If there's no free space manager for objects of this type,
+ * see if we can avoid creating one by checking if the freed
+ * space is at the end of the file
+ */
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: fs_addr = %a\n", FUNC, f->shared->fs_addr[fs_type]);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ if(!H5F_addr_defined(f->shared->fs_addr[fs_type])) {
+ htri_t status; /* "can absorb" status for section into */
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Trying to avoid starting up free space manager\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ /* Try to shrink the file or absorb the block into a block aggregator */
+ if((status = H5MF_try_shrink(f, alloc_type, dxpl_id, addr, size)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check for absorbing block")
+ else if(status > 0)
+ /* Indicate success */
+ HGOTO_DONE(SUCCEED)
+ else if(size < f->shared->fs_threshold) {
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, addr, size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ HGOTO_DONE(SUCCEED)
+ } /* end else-if */
+ } /* end if */
+
+ /* If we are deleting the free space manager, leave now, to avoid
+ * [re-]starting it.
+ * or if file space strategy type is not using a free space manager
+ * (H5F_FSPACE_STRATEGY_AGGR or H5F_FSPACE_STRATEGY_NONE), drop free space
+ * section on the floor.
+ *
+ * Note: this drops the space to free on the floor...
+ *
+ */
+ if(f->shared->fs_state[fs_type] == H5F_FS_STATE_DELETING ||
+ !H5F_HAVE_FREE_SPACE_MANAGER(f)) {
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, addr, size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* There's either already a free space manager, or the freed
+ * space isn't at the end of the file, so start up (or create)
+ * the file space manager
+ */
+ if(H5MF_start_fstype(f, dxpl_id, fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+ } /* end if */
+
+ /* Create the free-space section for the freed section */
+ ctype = H5MF_SECT_CLASS_TYPE(f, size);
+ if(NULL == (node = H5MF_sect_new(ctype, addr, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
+
+ /* If size of the freed section is larger than threshold, add it to the free space manager */
+ if(size >= f->shared->fs_threshold) {
+ HDassert(f->shared->fs_man[fs_type]);
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Add to the free space for the file */
+ if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[fs_type], node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space")
+ node = NULL;
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: After H5FS_sect_add()\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+ else {
+ htri_t merged; /* Whether node was merged */
+ H5MF_sect_ud_t udata; /* User data for callback */
+
+ /* Construct user data for callbacks */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.alloc_type = alloc_type;
+ udata.allow_sect_absorb = TRUE;
+ udata.allow_eoa_shrink_only = FALSE;
+
+ /* Try to merge the section that is smaller than threshold */
+ if((merged = H5FS_sect_try_merge(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't merge section to file free space")
+ else if(merged == TRUE) /* successfully merged */
+ /* Indicate that the node was used */
+ node = NULL;
+ } /* end else */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Release section node, if allocated and not added to section list or merged */
+ if(node)
+ if(H5MF_sect_free((H5FS_section_info_t *)node) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG */
+#ifdef H5MF_ALLOC_DEBUG_DUMP
+H5MF_sects_dump(f, dxpl_id, stderr);
+#endif /* H5MF_ALLOC_DEBUG_DUMP */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_xfree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_try_extend
+ *
+ * Purpose: Extend a block in the file if possible.
+ * For non-paged aggregation:
+ * --try to extend at EOA
+ * --try to extend into the aggregators
+ * --try to extend into a free-space section if adjoined
+ * For paged aggregation:
+ * --try to extend at EOA
+ * --try to extend into a free-space section if adjoined
+ * --try to extend into the page end threshold if a metadata block
+ *
+ * Return: Success: TRUE(1) - Block was extended
+ * FALSE(0) - Block could not be extended
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, June 11, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t alloc_type, haddr_t addr,
+ hsize_t size, hsize_t extra_requested)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */
+ haddr_t end; /* End of block to extend */
+ H5FD_mem_t map_type; /* Mapped type */
+ H5F_mem_page_t fs_type; /* free space type */
+ htri_t allow_extend = TRUE; /* Possible to extend the block */
+ hsize_t frag_size = 0; /* Size of mis-aligned fragment */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_requested = %Hu\n", FUNC, (unsigned)alloc_type, addr, size, extra_requested);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
+
+ if(f->shared->first_alloc_dealloc) {
+ HDassert(! H5AC_cache_image_pending(f));
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed")
+ } /* end if */
+
+ /* Set mapped type, treating global heap as raw data */
+ map_type = (alloc_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : alloc_type;
+
+ /* Compute end of block to extend */
+ end = addr + size;
+
+ /* For paged aggregation:
+ * To extend a small block: can only extend if not crossing page boundary
+ * To extend a large block at EOA: calculate in advance mis-aligned fragment so EOA will still end at page boundary
+ */
+ if(H5F_PAGED_AGGR(f)) {
+ if(size < f->shared->fs_page_size) {
+ /* To extend a small block: cannot cross page boundary */
+ if((addr / f->shared->fs_page_size) != (((end + extra_requested) - 1) / f->shared->fs_page_size))
+ allow_extend = FALSE;
+ } /* end if */
+ else {
+ haddr_t eoa; /* EOA for the file */
+
+ /* To extend a large block: calculate in advance the mis-aligned fragment so EOA will end at page boundary if extended */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa")
+ HDassert(!(eoa % f->shared->fs_page_size));
+
+ H5MF_EOA_MISALIGN(f, (eoa+extra_requested), f->shared->fs_page_size, frag_size);
+ } /* end else */
+ } /* end if */
+
+ /* Get free space type from allocation type */
+ H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type);
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, fs_type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ if(allow_extend) {
+ /* Try extending the block at EOA */
+ if((ret_value = H5F_try_extend(f, dxpl_id, map_type, end, extra_requested + frag_size)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file")
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: extended = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* If extending at EOA succeeds: */
+ /* for paged aggregation, put the fragment into the large-sized free-space manager */
+ if(ret_value == TRUE && H5F_PAGED_AGGR(f) && frag_size) {
+ H5MF_free_section_t *node = NULL; /* Free space section pointer */
+
+ /* Should be large-sized block */
+ HDassert(size >= f->shared->fs_page_size);
+
+ /* Start up the free-space manager */
+ if(!(f->shared->fs_man[fs_type]))
+ if(H5MF_start_fstype(f, dxpl_id, fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+
+ /* Create free space section for the fragment */
+ if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_LARGE, end + extra_requested, frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
+
+ /* Add the fragment to the large-sized free-space manager */
+ if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[fs_type], node) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space")
+
+ node = NULL;
+ } /* end if */
+
+ /* For non-paged aggregation: try to extend into the aggregators */
+ if(ret_value == FALSE && (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR ||
+ f->shared->fs_strategy == H5F_FSPACE_STRATEGY_AGGR) ) {
+ H5F_blk_aggr_t *aggr; /* Aggregator to use */
+
+ /* Check if the block is able to extend into aggregation block */
+ aggr = (map_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr);
+ if((ret_value = H5MF_aggr_try_extend(f, dxpl_id, aggr, map_type, end, extra_requested)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block")
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: H5MF_aggr_try_extend = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+
+ /* If no extension so far, try to extend into a free-space section */
+ if(ret_value == FALSE && ((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) ||
+ (H5F_PAGED_AGGR(f))) ) {
+ H5MF_sect_ud_t udata; /* User data */
+
+ /* Construct user data for callbacks */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.alloc_type = alloc_type;
+
+ /* Check if the free space for the file has been initialized */
+ if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type]))
+ /* Open the free-space manager */
+ if(H5MF_open_fstype(f, dxpl_id, fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+
+ /* Try to extend the block into a free-space section */
+ if(f->shared->fs_man[fs_type]) {
+ if((ret_value = H5FS_sect_try_extend(f, dxpl_id, f->shared->fs_man[fs_type], addr, size, extra_requested, H5FS_ADD_RETURNED_SPACE, &udata)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending block in free space manager")
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Try to H5FS_sect_try_extend = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+
+ /* For paged aggregation and a metadata block: try to extend into page end threshold */
+ if(ret_value == FALSE && H5F_PAGED_AGGR(f) && map_type != H5FD_MEM_DRAW) {
+ H5MF_EOA_MISALIGN(f, end, f->shared->fs_page_size, frag_size);
+
+ if(frag_size <= H5F_PGEND_META_THRES(f) && extra_requested <= frag_size)
+ ret_value = TRUE;
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Try to extend into the page end threshold = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+ } /* end if */
+ } /* allow_extend */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG */
+#ifdef H5MF_ALLOC_DEBUG_DUMP
+H5MF_sects_dump(f, dxpl_id, stderr);
+#endif /* H5MF_ALLOC_DEBUG_DUMP */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_try_extend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_try_shrink
+ *
+ * Purpose: Try to shrink the size of a file with a block or absorb it
+ * into a block aggregator.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Feb 14 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr,
+ hsize_t size)
+{
+ H5MF_free_section_t *node = NULL; /* Free space section pointer */
+ H5MF_sect_ud_t udata; /* User data for callback */
+ H5FS_section_class_t *sect_cls; /* Section class */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of fsm */
+ H5F_mem_page_t fs_type; /* Free space type */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(size > 0);
+
+ /* Set up free-space section class information */
+ sect_cls = H5MF_SECT_CLS_TYPE(f, size);
+ HDassert(sect_cls);
+
+ /* Get free space type from allocation type */
+ H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type);
+
+ /* Set the ring type in the DXPL */
+ if(H5MF__fsm_type_is_self_referential(f, fs_type))
+ fsm_ring = H5AC_RING_MDFSM;
+ else
+ fsm_ring = H5AC_RING_RDFSM;
+ if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* Create free-space section for block */
+ if(NULL == (node = H5MF_sect_new(sect_cls->type, addr, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section")
+
+ /* Construct user data for callbacks */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.alloc_type = alloc_type;
+ udata.allow_sect_absorb = FALSE; /* Force section to be absorbed into aggregator */
+ udata.allow_eoa_shrink_only = FALSE;
+
+ /* Check if the block can shrink the container */
+ if(sect_cls->can_shrink) {
+ if((ret_value = (*sect_cls->can_shrink)((const H5FS_section_info_t *)node, &udata)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container")
+ if(ret_value > 0) {
+ HDassert(sect_cls->shrink);
+
+ if((*sect_cls->shrink)((H5FS_section_info_t **)&node, &udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container")
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Free section node allocated */
+ if(node && H5MF_sect_free((H5FS_section_info_t *)node) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_try_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_close
+ *
+ * Purpose: Close the free space tracker(s) for a file:
+ * paged or non-paged aggregation
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_close(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+
+ if(H5F_PAGED_AGGR(f)) {
+ if((ret_value = H5MF__close_pagefs(f, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'page' file space")
+ } /* end if */
+ else {
+ if((ret_value = H5MF__close_aggrfs(f, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'aggr' file space")
+ } /* end else */
+
+done:
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__close_delete_fstype
+ *
+ * Purpose: Common code for closing and deleting the freespace manager
+ * of TYPE for file.
+ * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Jan 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__close_delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ if(H5F_PAGED_AGGR(f))
+ HDassert(type < H5F_MEM_PAGE_NTYPES);
+ else
+ HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES);
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* If the free space manager for this type is open, close it */
+ if(f->shared->fs_man[type])
+ if(H5MF__close_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* If there is free space manager info for this type, delete it */
+ if(H5F_addr_defined(f->shared->fs_addr[type]))
+ if(H5MF__delete_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't delete the free space manager")
+
+done:
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF__close_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_try_close
+ *
+ * Purpose: This is called by H5Fformat_convert() to close and delete
+ * free-space managers when downgrading persistent free-space
+ * to non-persistent.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * Jan 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_try_close(H5F_t *f, hid_t dxpl_id)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+
+ /* If there have been no file space allocations / deallocation so
+ * far, must call H5MF_tidy_self_referential_fsm_hack() to float
+ * all self referential FSMs and release file space allocated to
+ * them. Otherwise, the function will be called after the format
+ * conversion, and will become very confused.
+ *
+ * The situation is further complicated if a cache image exists
+ * and had not yet been loaded into the metadata cache. In this
+ * case, call H5AC_force_cache_image_load() instead of
+ * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load()
+ * will load the cache image, and then call
+ * H5MF_tidy_self_referential_fsm_hack() to discard the cache image
+ * block.
+ */
+ if(f->shared->first_alloc_dealloc) {
+ if(H5AC_cache_image_pending(f)) {
+ if(H5AC_force_cache_image_load(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "forced cache image load failed")
+ } /* end if */
+ else {
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed")
+ } /* end else */
+ } /* end if */
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_RDFSM, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ if(H5F_PAGED_AGGR(f)) {
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+
+ /* Iterate over all the free space types that have managers and
+ * get each free list's space
+ */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) {
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, ptype))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring ) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ if(H5MF__close_delete_fstype(f, dxpl_id, ptype) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
+ } /* end for */
+ } /* end if */
+ else {
+ H5FD_mem_t type; /* Memory type for iteration */
+
+ /* Iterate over all the free space types that have managers and
+ * get each free list's space
+ */
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
+ /* test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ if(H5MF__close_delete_fstype(f, dxpl_id, (H5F_mem_page_t)type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
+ } /* end for */
+ } /* end else */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF_try_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__close_aggrfs
+ *
+ * Purpose: Close the free space tracker(s) for a file: non-paged aggregation
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 22, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__close_aggrfs(H5F_t *f, hid_t dxpl_id)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5FD_mem_t type; /* Memory type for iteration */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(f->shared->sblock);
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_RDFSM, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ /* Free the space in aggregators */
+ /* (for space not at EOA, it may be put into free space managers) */
+ if(H5MF_free_aggrs(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
+
+ /* Trying shrinking the EOA for the file */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+ /* Making free-space managers persistent for superblock version >= 2 */
+ if(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2
+ && f->shared->fs_persist) {
+ H5O_fsinfo_t fsinfo; /* File space info message */
+ haddr_t final_eoa; /* Final eoa -- for sanity check */
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+
+ /* superblock extension and free space manager message should
+ * exist at this point -- verify at least the former.
+ */
+ HDassert(H5F_addr_defined(f->shared->sblock->ext_addr));
+
+ /* file space for all non-empty free space managers should be
+ * allocated at this point, and these free space managers should
+ * be written to file and thus their headers and section info
+ * entries in the metadata cache should be clean.
+ */
+
+ /* gather data for the free space manager superblock extension message.
+ *
+ * In passing, verify that all the free space managers are closed.
+ */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF;
+ for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ fsinfo.fs_addr[type-1] = f->shared->fs_addr[type];
+ fsinfo.strategy = f->shared->fs_strategy;
+ fsinfo.persist = f->shared->fs_persist;
+ fsinfo.threshold = f->shared->fs_threshold;
+ fsinfo.page_size = f->shared->fs_page_size;
+ fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres;
+ fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_pre_fsm_fsalloc;
+
+ /* Write the free space manager message -- message must already exist */
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension")
+
+ /* Close the free space managers */
+ for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
+ if(f->shared->fs_man[type]) {
+ /* test to see if we need to switch rings -- do
+ * so if required
+ */
+ if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ HDassert(f->shared->fs_state[type] == H5F_FS_STATE_OPEN);
+
+ if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager")
+ f->shared->fs_man[type] = NULL;
+ f->shared->fs_state[type] = H5F_FS_STATE_CLOSED;
+ } /* end if */
+ f->shared->fs_addr[type] = HADDR_UNDEF;
+ } /* end for */
+
+ /* verify that we haven't dirtied any metadata cache entries
+ * from the metadata free space manager ring out.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* verify that the aggregators are still shutdown. */
+ HDassert(f->shared->sdata_aggr.tot_size == 0);
+ HDassert(f->shared->sdata_aggr.addr == 0);
+ HDassert(f->shared->sdata_aggr.size == 0);
+
+ HDassert(f->shared->meta_aggr.tot_size == 0);
+ HDassert(f->shared->meta_aggr.addr == 0);
+ HDassert(f->shared->meta_aggr.size == 0);
+
+ /* Trying shrinking the EOA for the file */
+ /* (in case any free space is now at the EOA) */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+ /* get the eoa, and verify that it has the expected value */
+ if(HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)) )
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* f->shared->eoa_post_fsm_fsalloc is undefined if there has
+ * been no file space allocation or deallocation since file
+ * open.
+ */
+ HDassert((f->shared->first_alloc_dealloc) || (final_eoa == f->shared->eoa_post_fsm_fsalloc));
+ } /* end if */
+ else { /* super_vers can be 0, 1, 2 */
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ if(H5MF__close_delete_fstype(f, dxpl_id, (H5F_mem_page_t)type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+ } /* end else */
+
+ /* Free the space in aggregators (again) */
+ /* (in case any free space information re-started them) */
+ if(H5MF_free_aggrs(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators")
+
+ /* Trying shrinking the EOA for the file */
+ /* (in case any free space is now at the EOA) */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__close_aggrfs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__close_pagefs
+ *
+ * Purpose: Close the free space tracker(s) for a file: paged aggregation
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__close_pagefs(H5F_t *f, hid_t dxpl_id)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* ring value needed for this
+ * iteration.
+ */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+ H5O_fsinfo_t fsinfo; /* File space info message */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Entering\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(f->shared->sblock);
+ HDassert(f->shared->fs_page_size);
+ HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2);
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_RDFSM, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ /* Trying shrinking the EOA for the file */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+ /* Set up file space info message */
+ fsinfo.strategy = f->shared->fs_strategy;
+ fsinfo.persist = f->shared->fs_persist;
+ fsinfo.threshold = f->shared->fs_threshold;
+ fsinfo.page_size = f->shared->fs_page_size;
+ fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres;
+ fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF;
+
+ if(f->shared->fs_persist) {
+ haddr_t final_eoa; /* final eoa -- for sanity check */
+
+ /* superblock extension and free space manager message should
+ * exist at this point -- verify at least the former.
+ */
+ HDassert(H5F_addr_defined(f->shared->sblock->ext_addr));
+
+ /* file space for all non-empty free space managers should be
+ * allocated at this point, and these free space managers should
+ * be written to file and thus their headers and section info
+ * entries in the metadata cache should be clean.
+ */
+
+ /* gather data for the free space manager superblock extension message.
+ * Only need addresses of FSMs and eoa prior to allocation of
+ * file space for the self referential free space managers. Other
+ * data was gathered above.
+ */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ fsinfo.fs_addr[ptype-1] = f->shared->fs_addr[ptype];
+ fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_pre_fsm_fsalloc;
+
+ /* Write the free space manager message -- message must already exist */
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension")
+
+ /* Close the free space managers */
+ /* use H5MF__close_fstype() for this? */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) {
+ if(f->shared->fs_man[ptype]) {
+ /* test to see if we need to switch rings -- do
+ * so if required
+ */
+ if(H5MF__fsm_type_is_self_referential(f, ptype))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ HDassert(f->shared->fs_state[ptype] == H5F_FS_STATE_OPEN);
+
+ if(H5FS_close(f, dxpl_id, f->shared->fs_man[ptype]) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager")
+ f->shared->fs_man[ptype] = NULL;
+ f->shared->fs_state[ptype] = H5F_FS_STATE_CLOSED;
+ } /* end if */
+ f->shared->fs_addr[ptype] = HADDR_UNDEF;
+ } /* end for */
+
+ /* verify that we haven't dirtied any metadata cache entries
+ * from the metadata free space manager ring out.
+ */
+ HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM));
+
+ /* Trying shrinking the EOA for the file */
+ /* (in case any free space is now at the EOA) */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+ /* get the eoa, and verify that it has the expected value */
+ if(HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)) )
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* f->shared->eoa_post_fsm_fsalloc is undefined if there has
+ * been no file space allocation or deallocation since file
+ * open.
+ *
+ * If there is a cache image in the file at file open,
+ * f->shared->first_alloc_dealloc will always be FALSE unless
+ * the file is opened R/O, as otherwise, the image will have been
+ * read and discarded by this point.
+ *
+ * If a cache image was created on file close, the actual EOA
+ * should be in f->shared->eoa_post_mdci_fsalloc. Note that in
+ * this case, it is conceivable that f->shared->first_alloc_dealloc
+ * will still be TRUE, as the cache image is allocated directly from
+ * the file driver layer. However, as this possibility seems remote,
+ * it is ignored in the following assert.
+ */
+ HDassert((f->shared->first_alloc_dealloc) ||
+ (final_eoa == f->shared->eoa_post_fsm_fsalloc) ||
+ ((H5F_addr_defined(f->shared->eoa_post_mdci_fsalloc)) &&
+ (final_eoa == f->shared->eoa_post_mdci_fsalloc)));
+ } /* end if */
+ else {
+ /* Iterate over all the free space types that have managers
+ * and get each free list's space
+ */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ if(H5MF__close_delete_fstype(f, dxpl_id, ptype) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager")
+
+ /* Write file space info message to superblock extension object header */
+ /* Create the superblock extension object header in advance if needed */
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension")
+ } /* end else */
+
+ /* Trying shrinking the EOA for the file */
+ /* (in case any free space is now at the EOA) */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Leaving\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__close_pagefs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__close_shrink_eoa
+ *
+ * Purpose: Shrink the EOA while closing
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, July 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5F_mem_t type;
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+ hbool_t eoa_shrank; /* Whether an EOA shrink occurs */
+ htri_t status; /* Status value */
+ H5MF_sect_ud_t udata; /* User data for callback */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Construct user data for callbacks */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.allow_sect_absorb = FALSE;
+ udata.allow_eoa_shrink_only = TRUE;
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value(1)")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ /* Iterate until no more EOA shrinking occurs */
+ do {
+ eoa_shrank = FALSE;
+
+ if(H5F_PAGED_AGGR(f)) {
+ /* Check the last section of each free-space manager */
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) {
+ if(f->shared->fs_man[ptype]) {
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, ptype))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ udata.alloc_type = (H5FD_mem_t)((H5FD_mem_t)ptype < H5FD_MEM_NTYPES ? ptype : ((ptype % H5FD_MEM_NTYPES) + 1));
+
+ if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[ptype], &udata)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
+ else if(status > 0)
+ eoa_shrank = TRUE;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else {
+ /* Check the last section of each free-space manager */
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) {
+ if(f->shared->fs_man[type]) {
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ udata.alloc_type = type;
+
+ if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[type], &udata)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
+ else if(status > 0)
+ eoa_shrank = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* check the two aggregators */
+ if((status = H5MF_aggrs_try_shrink_eoa(f, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
+ else if(status > 0)
+ eoa_shrank = TRUE;
+ } /* end else */
+ } while(eoa_shrank);
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF__close_shrink_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_get_freespace
+ *
+ * Purpose: Retrieve the amount of free space in the file
+ *
+ * Return: Success: Amount of free space in file
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_get_freespace(H5F_t *f, hid_t dxpl_id, hsize_t *tot_space, hsize_t *meta_size)
+{
+ haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */
+ hsize_t ma_size = 0; /* Size of "metadata aggregator" */
+ haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */
+ hsize_t sda_size = 0; /* Size of "small data aggregator" */
+ hsize_t tot_fs_size = 0; /* Amount of all free space managed */
+ hsize_t tot_meta_size = 0; /* Amount of metadata for free space managers */
+ H5FD_mem_t tt; /* Memory type for iteration */
+ H5F_mem_page_t type; /* Memory type for iteration */
+ H5F_mem_page_t start_type; /* Memory type for iteration */
+ H5F_mem_page_t end_type; /* Memory type for iteration */
+ htri_t fs_started[H5F_MEM_PAGE_NTYPES]; /* Indicate whether the free-space manager has been started */
+ haddr_t fs_eoa[H5FD_MEM_NTYPES]; /* EAO for each free-space manager */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_RDFSM, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ /* Determine start/end points for loop */
+ if(H5F_PAGED_AGGR(f)) {
+ start_type = H5F_MEM_PAGE_META;
+ end_type = H5F_MEM_PAGE_NTYPES;
+ } /* end if */
+ else {
+ start_type = (H5F_mem_page_t)H5FD_MEM_SUPER;
+ end_type = (H5F_mem_page_t)H5FD_MEM_NTYPES;
+ } /* end else */
+
+ for(tt = H5FD_MEM_SUPER; tt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, tt))
+ if(HADDR_UNDEF == (fs_eoa[tt] = H5F_get_eoa(f, tt)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ if(!H5F_PAGED_AGGR(f)) {
+ /* Retrieve metadata aggregator info, if available */
+ if(H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats")
+
+ /* Retrieve 'small data' aggregator info, if available */
+ if(H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats")
+ } /* end if */
+
+ /* Iterate over all the free space types that have managers and get each free list's space */
+ for(type = start_type; type < end_type; H5_INC_ENUM(H5F_mem_page_t, type)) {
+ fs_started[type] = FALSE;
+
+ /* Check if the free space for the file has been initialized */
+ if(!f->shared->fs_man[type] && H5F_addr_defined(f->shared->fs_addr[type])) {
+ if(H5MF_open_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+ HDassert(f->shared->fs_man[type]);
+ fs_started[type] = TRUE;
+ } /* end if */
+
+ /* test to see if we need to switch rings -- do
+ * so if required
+ */
+ if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ /* Check if there's free space of this type */
+ if(f->shared->fs_man[type]) {
+ hsize_t type_fs_size = 0; /* Amount of free space managed for each type */
+ hsize_t type_meta_size = 0; /* Amount of free space metadata for each type */
+
+ /* Retrieve free space size from free space manager */
+ if(H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats")
+ if(H5FS_size(f, f->shared->fs_man[type], &type_meta_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats")
+
+ /* Increment total free space for types */
+ tot_fs_size += type_fs_size;
+ tot_meta_size += type_meta_size;
+ } /* end if */
+ } /* end for */
+
+ /* Close the free-space managers if they were opened earlier in this routine */
+ for(type = start_type; type < end_type; H5_INC_ENUM(H5F_mem_page_t, type)) {
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ if(fs_started[type])
+ if(H5MF__close_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space")
+ } /* end for */
+
+ /* Set the value(s) to return */
+ /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */
+ if(tot_space)
+ *tot_space = tot_fs_size + ma_size + sda_size;
+ if(meta_size)
+ *meta_size = tot_meta_size;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_get_freespace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_get_free_sections()
+ *
+ * Purpose: To retrieve free-space section information for
+ * paged or non-paged aggregation
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5MF_get_free_sections(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, size_t nsects, H5F_sect_info_t *sect_info)
+{
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ size_t total_sects = 0; /* Total number of sections */
+ H5MF_sect_iter_ud_t sect_udata; /* User data for callback */
+ H5F_mem_page_t start_type, end_type; /* Memory types to iterate over */
+ H5F_mem_page_t ty; /* Memory type for iteration */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, -1)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+
+ /* H5MF_tidy_self_referential_fsm_hack() will fail if any self
+ * referential FSM is opened prior to the call to it. Thus call
+ * it here if necessary and if it hasn't been called already.
+ *
+ * The situation is further complicated if a cache image exists
+ * and had not yet been loaded into the metadata cache. In this
+ * case, call H5AC_force_cache_image_load() instead of
+ * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load()
+ * will load the cache image, and then call
+ * H5MF_tidy_self_referential_fsm_hack() to discard the cache image
+ * block.
+ */
+ if(f->shared->first_alloc_dealloc) {
+ if(H5AC_cache_image_pending(f)) {
+ if(H5AC_force_cache_image_load(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "forced cache image load failed")
+ } /* end if */
+ else {
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed")
+ } /* end else */
+ } /* end if */
+
+ if(type == H5FD_MEM_DEFAULT) {
+ start_type = H5F_MEM_PAGE_SUPER;
+ end_type = H5F_MEM_PAGE_NTYPES;
+ } /* end if */
+ else {
+ start_type = end_type = (H5F_mem_page_t)type;
+ if(H5F_PAGED_AGGR(f)) /* set to the corresponding LARGE free-space manager */
+ end_type = (H5F_mem_page_t)(end_type + H5FD_MEM_NTYPES);
+ else
+ H5_INC_ENUM(H5F_mem_page_t, end_type);
+ } /* end else */
+
+ /* Set up user data for section iteration */
+ sect_udata.sects = sect_info;
+ sect_udata.sect_count = nsects;
+ sect_udata.sect_idx = 0;
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_RDFSM, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value(0)")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_RDFSM;
+
+ /* Iterate over memory types, retrieving the number of sections of each type */
+ for(ty = start_type; ty < end_type; H5_INC_ENUM(H5F_mem_page_t, ty)) {
+ hbool_t fs_started = FALSE; /* The free-space manager is opened or not */
+ size_t nums = 0; /* The number of free-space sections */
+
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, ty))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ if(!f->shared->fs_man[ty] && H5F_addr_defined(f->shared->fs_addr[ty])) {
+ if(H5MF_open_fstype(f, dxpl_id, ty) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't open the free space manager")
+ HDassert(f->shared->fs_man[ty]);
+ fs_started = TRUE;
+ } /* end if */
+
+ /* Check if there's free space sections of this type */
+ if(f->shared->fs_man[ty])
+ if(H5MF__get_free_sects(f, dxpl_id, f->shared->fs_man[ty], &sect_udata, &nums) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get section info for the free space manager")
+
+ /* Increment total # of sections */
+ total_sects += nums;
+
+ /* Close the free space manager of this type, if we started it here */
+ if(fs_started)
+ if(H5MF__close_fstype(f, dxpl_id, ty) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCLOSEOBJ, FAIL, "can't close file free space")
+ if((H5F_PAGED_AGGR(f)) && (type != H5FD_MEM_DEFAULT))
+ ty = (H5F_mem_page_t)(ty + H5FD_MEM_NTYPES - 2);
+ } /* end for */
+
+ /* Set return value */
+ ret_value = (ssize_t)total_sects;
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, -1)
+} /* H5MF_get_free_sections() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sects_cb()
+ *
+ * Purpose: Iterator callback for each free-space section
+ * Retrieve address and size into user data
+ *
+ * Return: Always succeed
+ *
+ * Programmer: Vailin Choi
+ * July 1st, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sects_cb(H5FS_section_info_t *_sect, void *_udata)
+{
+ H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect;
+ H5MF_sect_iter_ud_t *udata = (H5MF_sect_iter_ud_t *)_udata;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(udata->sect_idx < udata->sect_count) {
+ udata->sects[udata->sect_idx].addr = sect->sect_info.addr;
+ udata->sects[udata->sect_idx].size = sect->sect_info.size;
+ udata->sect_idx++;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MF_sects_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__get_free_sects
+ *
+ * Purpose: Retrieve section information for the specified free-space manager.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__get_free_sects(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums)
+{
+ hsize_t hnums = 0; /* # of sections */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(sect_udata);
+ HDassert(nums);
+ HDassert(fspace);
+
+ /* Query how many sections of this type */
+ if(H5FS_sect_stats(fspace, NULL, &hnums) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats")
+ H5_CHECKED_ASSIGN(*nums, size_t, hnums, hsize_t);
+
+ /* Check if we should retrieve the section info */
+ if(sect_udata->sects && *nums > 0)
+ /* Iterate over all the free space sections of this type, adding them to the user's section info */
+ if(H5FS_sect_iterate(f, dxpl_id, fspace, H5MF_sects_cb, sect_udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't iterate over sections")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF__get_free_sects() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_settle_raw_data_fsm()
+ *
+ * Purpose: Handle any tasks required before the metadata cache
+ * can serialize or flush the raw data free space manager
+ * and any metadata free space managers that reside in the
+ * raw data free space manager ring.
+ *
+ * Specifically, this means any metadata managers that DON'T
+ * handle space allocation for free space manager header or
+ * section info will reside in the raw data free space manager
+ * ring.
+ *
+ * In the absence of page allocation, there is at most one
+ * free space manager per memory type defined in H5F_mem_t.
+ * Of these, the one that allocates H5FD_MEM_DRAW will
+ * always reside in the raw data free space manager ring.
+ * If there is more than one metadata free space manager,
+ * all that don't handle H5FD_MEM_FSPACE_HDR or
+ * H5FD_MEM_FSPACE_SINFO (which map to H5FD_MEM_OHDR and
+ * H5FD_MEM_LHEAP respectively) will reside in the raw
+ * data free space manager ring as well
+ *
+ * With page allocation, the situation is conceptually
+ * identical, but more complex in practice.
+ *
+ * In the worst case (multi file driver) page allocation
+ * can result in two free space managers for each memory
+ * type -- one for small (less than on equal to one page)
+ * allocations, and one for large (greater than one page)
+ * allocations.
+ *
+ * In the more common one file case, page allocation will
+ * result in a total of three free space managers -- one for
+ * small (<= one page) raw data allocations, one for small
+ * metadata allocations (i.e, all memory types other than
+ * H5FD_MEM_DRAW), and one for all large (> one page)
+ * allocations.
+ *
+ * Despite these complications, the solution is the same in
+ * the page allocation case -- free space managers (be they
+ * small data or large) are assigned to the raw data free
+ * space manager ring if they don't allocate file space for
+ * free space managers. Note that in the one file case, the
+ * large free space manager must be assigned to the metadata
+ * free space manager ring, as it both allocates pages for
+ * the metadata free space manager, and allocates space for
+ * large (> 1 page) metadata cache entries.
+ *
+ * At present, the task list for this routine is:
+ *
+ * 1) Reduce the EOA to the extent possible. To do this:
+ *
+ * a) Free both aggregators. Space not at EOA will be
+ * added to the appropriate free space manager.
+ *
+ * The raw data aggregator should not be restarted
+ * after this point. It is possible that the metadata
+ * aggregator will be.
+ *
+ * b) Free all file space currently allocated to free
+ * space managers.
+ *
+ * c) Delete the free space manager superblock
+ * extension message if allocated.
+ *
+ * This done, reduce the EOA by moving it to just before
+ * the last piece of free memory in the file.
+ *
+ * 2) Ensure that space is allocated for the free space
+ * manager superblock extension message. Must do this
+ * now, before reallocating file space for free space
+ * managers, as it is possible that this allocation may
+ * grab the last section in a FSM -- making it unnecessary
+ * to re-allocate file space for it.
+ *
+ * 3) Scan all free space managers not involved in allocating
+ * space for free space managers. For each such free space
+ * manager, test to see if it contains free space. If
+ * it does, allocate file space for its header and section
+ * data. If it contains no free space, leave it without
+ * allocated file space as there is no need to save it to
+ * file.
+ *
+ * Note that all free space managers in this class should
+ * see no further space allocations / deallocations as
+ * at this point, all raw data allocations should be
+ * finalized, as should all metadata allocations not
+ * involving free space managers.
+ *
+ * We will allocate space for free space managers involved
+ * in the allocation of file space for free space managers
+ * in H5MF_settle_meta_data_fsm()
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: John Mainzer
+ * 5/25/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled)
+{
+ int pass_count;
+ hsize_t alloc_size;
+ H5F_mem_t mem_type; /* Memory type for iteration */
+ H5F_mem_page_t fsm_type; /* FSM type for iteration */
+ H5O_fsinfo_t fsinfo; /* Free space manager info message */
+ H5FS_stat_t fs_stat; /* Information for free-space manager */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */
+ H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(fsm_settled);
+
+ /* Only need to settle things if we are persisting the free space info
+ * and allocation/deallocation has occurred.
+ */
+ if(f->shared->fs_persist && !f->shared->first_alloc_dealloc) {
+ hbool_t fsm_opened[H5F_MEM_PAGE_NTYPES]; /* State of FSM */
+ hbool_t fsm_visited[H5F_MEM_PAGE_NTYPES]; /* State of FSM */
+
+ /* Sanity check */
+ HDassert(f->shared->sblock);
+
+ /* should only be called if file is opened R/W */
+ HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
+
+ /* shouldn't be called unless we have a superblock supporting the
+ * superblock extension.
+ */
+ HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2);
+
+ /* Initialize fsm_opened and fsm_visited */
+ HDmemset(fsm_opened, 0, sizeof(fsm_opened));
+ HDmemset(fsm_visited, 0, sizeof(fsm_visited));
+
+ /* 1) Reduce the EOA to the extent possible. */
+
+ /* a) Free the space in aggregators:
+ *
+ * (for space not at EOF, it may be put into free space managers)
+ *
+ * Do this now so that the raw data FSM (and any other FSM that isn't
+ * involved in space allocation for FSMs) will have no further activity.
+ *
+ * Note that while the raw data aggregator should not be restarted during
+ * the close process, this need not be the case for the metadata aggregator.
+ *
+ * Note also that the aggregators will not exist if page aggregation
+ * is enabled -- skip this if so.
+ */
+ /* Vailin -- is this correct? */
+ if(!H5F_PAGED_AGGR(f) && (H5MF_free_aggrs(f, dxpl_id) < 0))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators")
+
+ /* Set the ring type in the DXPL. In most cases, we will
+ * need H5AC_RING_MDFSM first, so initialy set the ring in
+ * the DXPL to that value. We will alter this later if
+ * needed.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_MDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value(0)")
+ reset_ring = TRUE;
+ curr_ring = H5AC_RING_MDFSM;
+
+ /* b) Free the file space (if any) allocated to each free space manager.
+ *
+ * Do this to facilitate reduction of the size of the file to the
+ * extent possible. We will re-allocate space to free space managers
+ * that have free space to save after this reduction.
+ *
+ * In the case of the raw data free space manager, and any other free
+ * space manager that does not allocate space for free space managers,
+ * allocations should be complete at this point, as all raw data should
+ * have space allocated and be flushed to file by now. Thus we
+ * can examine such free space managers and only re-allocate space for
+ * them if they contain free space. Do this later in this function after
+ * the EOA has been reduced to the extent possible.
+ *
+ * For free space managers that allocate file space for free space
+ * managers (usually just a single metadata free space manager, but for
+ * now at least, free space managers for different types of metadata
+ * are possible), the matter is more ticklish due to the self-
+ * referential nature of the problem. These FSMs are dealt with in
+ * H5MF_settle_meta_data_fsm().
+ *
+ * Since paged allocation may be enabled, there may be up to two
+ * free space managers per memory type -- one for small and one for
+ * large allocation. Hence we must loop over the memory types twice
+ * setting the allocation size accordingly if paged allocation is
+ * enabled.
+ */
+ for(pass_count = 0; pass_count <= 1; pass_count++) {
+ if(pass_count == 0)
+ alloc_size = 1;
+ else if ( H5F_PAGED_AGGR(f) )
+ alloc_size = f->shared->fs_page_size + 1;
+ else /* no need for a second pass */
+ break;
+
+ for(mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5F_mem_t, mem_type)) {
+ H5MF_alloc_to_fs_type(f, mem_type, alloc_size, &fsm_type);
+
+ if(pass_count == 0) { /* this is the first pass */
+ HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER);
+ } /* end if */
+ else if(H5F_PAGED_AGGR(f)) { /* page alloc active */
+ HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
+ } /* end else-if */
+ else /* paged allocation disabled -- should be unreachable */
+ HDassert(FALSE);
+
+ if(!fsm_visited[fsm_type]) {
+ fsm_visited[fsm_type] = TRUE;
+
+ /* If there is no active FSM for this type, but such a FSM has
+ * space allocated in file, open it so that we can free its file
+ * space.
+ */
+ if(NULL == f->shared->fs_man[fsm_type]) {
+ if(H5F_addr_defined(f->shared->fs_addr[fsm_type])) {
+ /* Sanity check */
+ HDassert(fsm_opened[fsm_type] == FALSE);
+
+ if(H5MF_open_fstype(f, dxpl_id, fsm_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager")
+ fsm_opened[fsm_type] = TRUE;
+ } /* end if */
+ } /* end if */
+
+ if(f->shared->fs_man[fsm_type]) {
+ /* Test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, fsm_type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info")
+
+ /* Check if the free space manager has space in the file */
+ if(H5F_addr_defined(fs_stat.addr) || H5F_addr_defined(fs_stat.sect_addr)) {
+ /* Delete the free space manager in the file. Will
+ * reallocate later if the free space manager contains
+ * any free space.
+ */
+ if(H5FS_free(f, f->shared->fs_man[fsm_type], dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers")
+ f->shared->fs_addr[fsm_type] = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+
+ /* note that we are tracking opened FSM -- we will close them
+ * at the end of the function.
+ */
+ } /* end if */
+ } /* end for */
+ } /* end for */
+
+
+ /* c) Delete the free space manager superblock extension message
+ * if allocated.
+ *
+ * Must do this since the routine that writes / creates superblock
+ * extension messages will choke if the target message is
+ * unexpectedly either absent or present.
+ *
+ * Update: This is probably unecessary, as I gather that the
+ * file space manager info message is guaranteed to exist.
+ * Leave it in for now, but consider removing it.
+ */
+ if(H5F_addr_defined(f->shared->sblock->ext_addr))
+ if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_FSINFO_ID) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "error in removing message from superblock extension")
+
+ /* As the final element in 1), shrink the EOA for the file */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+
+ /* 2) Ensure that space is allocated for the free space manager superblock
+ * extension message. Must do this now, before reallocating file space
+ * for free space managers, as it is possible that this allocation may
+ * grab the last section in a FSM -- making it unnecessary to
+ * re-allocate file space for it.
+ *
+ * Do this by writing a free space manager superblock extension message.
+ *
+ * Since no free space manager has file space allocated for it, this
+ * message must be invalid since we can't save addresses of FSMs when
+ * those addresses are unknown. This is OK -- we will write the correct
+ * values to the message at free space manager shutdown.
+ */
+ for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type))
+ fsinfo.fs_addr[fsm_type - 1] = HADDR_UNDEF;
+ fsinfo.strategy = f->shared->fs_strategy;
+ fsinfo.persist = f->shared->fs_persist;
+ fsinfo.threshold = f->shared->fs_threshold;
+ fsinfo.page_size = f->shared->fs_page_size;
+ fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres;
+ fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+
+ if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, TRUE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing fsinfo message to superblock extension")
+
+
+ /* 3) Scan all free space managers not involved in allocating
+ * space for free space managers. For each such free space
+ * manager, test to see if it contains free space. If
+ * it does, allocate file space for its header and section
+ * data. If it contains no free space, leave it without
+ * allocated file space as there is no need to save it to
+ * file.
+ *
+ * Note that all free space managers in this class should
+ * see no further space allocations / deallocations as
+ * at this point, all raw data allocations should be
+ * finalized, as should all metadata allocations not involving
+ * free space managers.
+ *
+ * We will allocate space for free space managers involved
+ * in the allocation of file space for free space managers
+ * in H5MF_settle_meta_data_fsm()
+ */
+
+ /* Reinitialize fsm_visited */
+ for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type))
+ fsm_visited[fsm_type] = FALSE;
+
+ for(pass_count = 0; pass_count <= 1; pass_count++) {
+ if(pass_count == 0)
+ alloc_size = 1;
+ else if(H5F_PAGED_AGGR(f))
+ alloc_size = f->shared->fs_page_size + 1;
+ else /* no need for a second pass */
+ break;
+
+ for(mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5F_mem_t, mem_type)) {
+ H5MF_alloc_to_fs_type(f, mem_type, alloc_size, &fsm_type);
+
+ if(pass_count == 0) { /* this is the first pass */
+ HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER);
+ } /* end if */
+ else if(H5F_PAGED_AGGR(f)) { /* page alloc active */
+ HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
+ } /* end else-if */
+ else /* paged allocation disabled -- should be unreachable */
+ HDassert(FALSE);
+
+ /* test to see if we need to switch rings -- do so if required */
+ if(H5MF__fsm_type_is_self_referential(f, fsm_type))
+ needed_ring = H5AC_RING_MDFSM;
+ else
+ needed_ring = H5AC_RING_RDFSM;
+
+ if(needed_ring != curr_ring) {
+ if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring)< 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ curr_ring = needed_ring;
+ } /* end if */
+
+ /* Since there can be a many-to-one mapping from memory types
+ * to free space managers, ensure that we don't visit any FSM
+ * more than once.
+ */
+ if(!fsm_visited[fsm_type]) {
+ fsm_visited[fsm_type] = TRUE;
+
+ if(f->shared->fs_man[fsm_type]) {
+ /* Only allocate file space if the target free space manager
+ * doesn't allocate file space for free space managers. Note
+ * that this is also the deciding factor as to whether a FSM
+ * in in the raw data FSM ring.
+ */
+ if(!H5MF__fsm_type_is_self_referential(f, fsm_type)) {
+ /* The current ring should be H5AC_RING_RDFSM */
+ HDassert(curr_ring == H5AC_RING_RDFSM);
+
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0 )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
+
+ /* If the free space manager contains section info,
+ * allocate space for the header and sinfo (note that
+ * space must not be allocated at present -- verify
+ * verify this with assertions).
+ */
+ if(fs_stat.serial_sect_count > 0) {
+ /* Sanity check */
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+
+ /* Allocate FSM header */
+ if(H5FS_alloc_hdr(f, f->shared->fs_man[fsm_type], &f->shared->fs_addr[fsm_type], dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocated free-space header")
+
+ /* Allocate FSM section info */
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.alloc_sect_size == 0);
+ if(H5FS_alloc_sect(f, f->shared->fs_man[fsm_type], dxpl_id) < 0 )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate free-space section info")
+
+#ifndef NDEBUG
+ /* Re-Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info")
+
+ HDassert(H5F_addr_defined(fs_stat.addr));
+ HDassert(H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.serial_sect_count > 0);
+ HDassert(fs_stat.alloc_sect_size > 0);
+ HDassert(fs_stat.alloc_sect_size == fs_stat.sect_size);
+#endif /* NDEBUG */
+ } /* end if */
+ else {
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.serial_sect_count == 0);
+ HDassert(fs_stat.alloc_sect_size == 0);
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ /* Close any opened FSMs */
+ if(fsm_opened[fsm_type]) {
+ if(H5MF__close_fstype(f, dxpl_id, fsm_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space manager")
+ fsm_opened[fsm_type] = FALSE;
+ } /* end if */
+ } /* end if */
+ } /* end for */
+ } /* end for */
+
+ /* verify that all opened FSMs were closed */
+ for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type))
+ HDassert(!fsm_opened[fsm_type]);
+
+ /* Indicate that the FSM was settled successfully */
+ *fsm_settled = TRUE;
+ } /* end if */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF_settle_raw_data_fsm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_settle_meta_data_fsm()
+ *
+ * Purpose: If the free space manager is persistent, handle any tasks
+ * required before the metadata cache can serialize or flush
+ * the metadata free space manager(s) that handle file space
+ * allocation for free space managers.
+ *
+ * In most cases, there will be only one manager assigned
+ * to this role. However, since for reasons unknown,
+ * free space manager headers and section info blocks are
+ * different classes of memory, it is possible that two free
+ * space managers will be involved.
+ *
+ * On entry to this function, the raw data settle routine
+ * (H5MF_settle_raw_data_fsm()) should have:
+ *
+ * 1) Freed the aggregators.
+ *
+ * 2) Freed all file space allocated to the free space managers.
+ *
+ * 3) Deleted the free space manager superblock extension message
+ *
+ * 4) Reduced the EOA to the extent possible.
+ *
+ * 5) Re-created the free space manager superblock extension
+ * message.
+ *
+ * 6) Reallocated file space for all non-empty free space
+ * managers NOT involved in allocation of space for free
+ * space managers.
+ *
+ * Note that these free space managers (if not empty) should
+ * have been written to file by this point, and that no
+ * further space allocations involving them should take
+ * place during file close.
+ *
+ * On entry to this routine. the free space manager(s) involved
+ * in allocation of file space for free space managers should
+ * still be floating. (i.e. should not have any file space
+ * allocated to them.)
+ *
+ * Similarly, the raw data aggregator should not have been
+ * restarted. Note that it is probable that reallocation of
+ * space in 5) and 6) above will have re-started the metadata
+ * aggregator.
+ *
+ *
+ * In this routine, we proceed as follows:
+ *
+ * 1) Verify that the free space manager(s) involved in file
+ * space allocation for free space managers are still floating.
+ *
+ * 2) Free the aggregators.
+ *
+ * 3) Reduce the EOA to the extent possible, and make note
+ * of the resulting value. This value will be stored
+ * in the fsinfo superblock extension message and be used
+ * in the subsequent file open.
+ *
+ * 4) Re-allocate space for any free space manager(s) that:
+ *
+ * a) are involved in allocation of space for free space
+ * managers, and
+ *
+ * b) contain free space.
+ *
+ * It is possible that we could allocate space for one
+ * of these free space manager(s) only to have the allocation
+ * result in the free space manager being empty and thus
+ * obliging us to free the space again. Thus there is the
+ * potential for an infinte loop if we want to avoid saving
+ * empty free space managers.
+ *
+ * Similarly, it is possible that we could allocate space
+ * for a section info block, only to discover that this
+ * allocation has changed the size of the section info --
+ * forcing us to deallocate and start the loop over again.
+ *
+ * To avoid this, simply allocate file space for these
+ * FSM(s) directly from the VFD layer if allocation is
+ * indicated. This avoids the issue by bypassing the FSMs
+ * in this case.
+ *
+ * Note that this may increase the size of the file needlessly.
+ * A better solution would be to modify the FSM code to
+ * save empty FSMs to file, and to allow section info blocks
+ * to be oversized. However, given that the FSM code is
+ * also used by the fractal heaps, and that we are under
+ * severe time pressure at the moment, the above brute
+ * force solution is attractive.
+ *
+ * 5) Make note of the EOA -- used for sanity checking on
+ * FSM shutdown.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: John Mainzer
+ * 5/25/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled)
+{
+ H5F_mem_page_t sm_fshdr_fs_type; /* small fs hdr fsm */
+ H5F_mem_page_t sm_fssinfo_fs_type; /* small fs sinfo fsm */
+ H5F_mem_page_t lg_fshdr_fs_type; /* large fs hdr fsm */
+ H5F_mem_page_t lg_fssinfo_fs_type; /* large fs sinfo fsm */
+ H5FS_t *sm_hdr_fspace = NULL; /* ptr to sm FSM hdr alloc FSM */
+ H5FS_t *sm_sinfo_fspace = NULL; /* ptr to sm FSM sinfo alloc FSM */
+ H5FS_t *lg_hdr_fspace = NULL; /* ptr to lg FSM hdr alloc FSM */
+ H5FS_t *lg_sinfo_fspace = NULL; /* ptr to lg FSM sinfo alloc FSM */
+ haddr_t eoa_pre_fsm_fsalloc; /* eoa pre file space allocation */
+ /* for self referential FSMs */
+ haddr_t eoa_post_fsm_fsalloc; /* eoa post file space allocation */
+ /* for self referential FSMs */
+ H5FS_stat_t fs_stat; /* Information for hdr FSM */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ hbool_t reset_ring = FALSE; /* Whether we set the ring */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(fsm_settled);
+
+ /* Only need to settle things if we are persisting the free space info
+ * and allocation/deallocation has occurred.
+ */
+ if(f->shared->fs_persist && !f->shared->first_alloc_dealloc) {
+ /* Sanity check */
+ HDassert(f->shared->lf);
+
+ /* should only be called if file is opened R/W */
+ HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
+
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type);
+
+ HDassert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
+
+ HDassert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
+
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type]));
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type]));
+
+ /* Note that in most cases, sm_hdr_fspace will equal sm_sinfo_fspace. */
+ sm_hdr_fspace = f->shared->fs_man[sm_fshdr_fs_type];
+ sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type];
+
+ if(H5F_PAGED_AGGR(f)) {
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fs_type);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fs_type);
+
+ HDassert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES);
+
+ HDassert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES);
+
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type]));
+ HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type]));
+
+ /* Note that in most cases, lg_hdr_fspace will equal lg_sinfo_fspace. */
+ lg_hdr_fspace = f->shared->fs_man[lg_fshdr_fs_type];
+ lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type];
+ } /* end if */
+
+ /* Set the ring in the dxpl appropriately for subsequent calls */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_MDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+#ifndef NDEBUG
+ /* Verify that sm_hdr_fspace is floating if it exists */
+ if(sm_hdr_fspace) {
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, sm_hdr_fspace, &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
+
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.alloc_sect_size == 0);
+ } /* end if */
+
+ /* Verify that sm_sinfo_fspace is floating if it exists and is distinct */
+ if((sm_sinfo_fspace) && (sm_hdr_fspace != sm_sinfo_fspace)) {
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, sm_sinfo_fspace, &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
+
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.alloc_sect_size == 0);
+ } /* end if */
+
+ if(H5F_PAGED_AGGR(f)) {
+ /* Verify that lg_hdr_fspace is floating if it exists */
+ if(lg_hdr_fspace) {
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, lg_hdr_fspace, &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (3)")
+
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.alloc_sect_size == 0);
+ } /* end if */
+
+ /* Verify that lg_sinfo_fspace is floating if it
+ * exists and is distinct
+ */
+ if((lg_sinfo_fspace) && (lg_hdr_fspace != lg_sinfo_fspace)) {
+ /* Query free space manager info for this type */
+ if(H5FS_stat_info(f, lg_sinfo_fspace, &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (4)")
+
+ HDassert(!H5F_addr_defined(fs_stat.addr));
+ HDassert(!H5F_addr_defined(fs_stat.sect_addr));
+ HDassert(fs_stat.alloc_sect_size == 0);
+ } /* end if */
+ } /* end if */
+#endif /* NDEBUG */
+
+ /* Free the space in the metadata aggregator. Do this via the
+ * H5MF_free_aggrs() call. Note that the raw data aggregator must
+ * have already been freed. Sanity checks for this?
+ *
+ * Note that the aggregators will not exist if paged aggregation
+ * is enabled -- don't attempt to free if this is the case.
+ */
+ /* Vailin -- is this correct? */
+ /* (for space not at EOF, it may be put into free space managers) */
+ if((!H5F_PAGED_AGGR(f)) && (H5MF_free_aggrs(f, dxpl_id) < 0))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators")
+
+ /* Trying shrinking the EOA for the file */
+ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa")
+
+ /* At this point, the EOA should be set to a value that contains
+ * the allocation for all user data, all non self referential FSMs,
+ * the superblock and all superblock extension messages.
+ *
+ * Make note of the current EOA. We will store this value in the
+ * free space manager superblock extension message. Since space for
+ * everything other than the self referential FSMs (and possibly the
+ * cache image) has been allocated at this point, this allows us to
+ * to float the self referential FSMs on the first file space allocation /
+ * deallocaiton and then set the EOA to this value before we handle
+ * the allocation / deallocation. (If a cache image exists, the
+ * first allocation / deallocation will be the deallocation of space
+ * for the cache image).
+ *
+ * WARNING: This approach settling the self referential free space
+ * managers and allocating space for them in the file will
+ * not work as currently implemented with the split and
+ * multi file drivers, as the self referential free space
+ * manager header and section info can be stored in up to
+ * two different files -- requiring that up to two EOA's
+ * be stored in the the free space managers super block
+ * extension message.
+ *
+ * As of this writing, we are solving this problem by
+ * simply not supporting persistant FSMs with the split
+ * and multi file drivers.
+ *
+ * Current plans are to do away with the multi file
+ * driver, so this should be a non-issue in this case.
+ *
+ * We should be able to support the split file driver
+ * without a file format change. However, the code to
+ * do so does not exist at present.
+ */
+ if(HADDR_UNDEF == (eoa_pre_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA")
+
+
+ /* ******************* PROBLEM: ********************
+ *
+ * If the file has an alignement other than 1, and if
+ * the EOA is not a multiple of this alignment, allocating sapce
+ * for the section via the VFD info has the potential of generating
+ * a fragment that will be added to the free space manager. This
+ * of course undoes everything we have been doing here.
+ *
+ * Need a way around this. Obvious solution is to force the EOA to
+ * be a multiple of the alignment.
+ *
+ * Fortunately, alignment is typically 1, so this is a non-issue in
+ * most cases. In cases where the alignment is not 1, for now we
+ * have decided to drop the fragment on the floor.
+ *
+ * Eventually, we should fix this by modifying the on disk representations
+ * of free space managers to allow for empty space, so as to bypass the
+ * issues created by self-referential free space managers, and make
+ * this issue moot.
+ */
+ /* HDassert(f->shared->alignment == 1); */
+
+
+ /* The free space manager(s) that handle space allocations for free
+ * space managers should be settled now, albeit without file space
+ * allocated to them. To avoid the possibility of changing the sizes
+ * of their section info blocks, allocate space for them now at the
+ * end of file via H5FD_alloc().
+ *
+ * In the past, this issue of allocating space without touching the
+ * free space managers has been deal with by calling
+ * H5MF_aggr_vfd_alloc(), which in turn calls H5MF_aggr_alloc().
+ * This is problematic since (if I read the code correctly) it will
+ * re-constitute the metadata aggregator, which will add any leftover
+ * space to one of the free space managers when freed.
+ *
+ * This is a non-starter, since the entire objective is to settle the
+ * free space managers.
+ *
+ * Hence the decision to call H5FD_alloc() directly.
+ *
+ * As discussed in PROBLEM above, if f->shared->alignment is not 1,
+ * this has the possibility of generating a fragment of file space
+ * that would typically be inserted into one of the free space managers.
+ *
+ * This is isn't good, but due to schedule pressure, we will just drop
+ * the fragment on the floor for now.
+ */
+ if(sm_hdr_fspace)
+ if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, sm_hdr_fspace, &(f->shared->fs_addr[sm_fshdr_fs_type])) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sm hdr FSM file space")
+
+ if(sm_sinfo_fspace && (sm_sinfo_fspace != sm_hdr_fspace))
+ if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, sm_sinfo_fspace, &(f->shared->fs_addr[sm_fssinfo_fs_type])) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sm sinfo FSM file space")
+
+ if(H5F_PAGED_AGGR(f)) {
+ if(lg_hdr_fspace)
+ if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, lg_hdr_fspace, &(f->shared->fs_addr[lg_fshdr_fs_type])) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg hdr FSM file space")
+
+ if(lg_sinfo_fspace && (lg_sinfo_fspace != lg_hdr_fspace))
+ if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, lg_sinfo_fspace, &(f->shared->fs_addr[lg_fssinfo_fs_type])) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg sinfo FSM file space")
+ } /* end if */
+
+ /* Get the eoa after allocation of file space for the self referential
+ * free space managers. Assuming no cache image, this should be the
+ * final EOA of the file.
+ */
+ if(HADDR_UNDEF == (eoa_post_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* All free space managers should have file space allocated for them
+ * now, and should see no further allocations / deallocations. Store
+ * the pre and post file space allocaton for self referential FSMs EOA
+ * for use when we actually write the free space manager superblock
+ * extension message.
+ */
+ f->shared->eoa_pre_fsm_fsalloc = eoa_pre_fsm_fsalloc;
+ f->shared->eoa_post_fsm_fsalloc = eoa_post_fsm_fsalloc;
+
+ /* Indicate that the FSM was settled successfully */
+ *fsm_settled = TRUE;
+ } /* end if */
+
+done:
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF_settle_meta_data_fsm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__fsm_type_is_self_referential()
+ *
+ * Purpose: Return TRUE if the indicated free space manager allocates
+ * file space for free space managers. Return FALSE otherwise.
+ *
+ * Return: TRUE/FALSE
+ *
+ * Programmer: John Mainzer
+ * 12/6/16
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5MF__fsm_type_is_self_referential(H5F_t *f, H5F_mem_page_t fsm_type)
+{
+ H5F_mem_page_t sm_fshdr_fsm;
+ H5F_mem_page_t sm_fssinfo_fsm;
+ H5F_mem_page_t lg_fshdr_fsm;
+ H5F_mem_page_t lg_fssinfo_fsm;
+ hbool_t result = FALSE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(fsm_type >= H5F_MEM_PAGE_DEFAULT);
+ HDassert(fsm_type < H5F_MEM_PAGE_NTYPES);
+
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm);
+
+ if(H5F_PAGED_AGGR(f)) {
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fsm);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fsm);
+
+ result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm)
+ || (fsm_type == lg_fshdr_fsm) || (fsm_type == lg_fssinfo_fsm);
+ } /* end if */
+ else {
+ /* In principle, fsm_type should always be less than
+ * H5F_MEM_PAGE_LARGE_SUPER whenever paged aggregation
+ * is not enabled. However, since there is code that does
+ * not observe this prinicple, force the result to FALSE if
+ * fsm_type is greater than or equal to H5F_MEM_PAGE_LARGE_SUPER.
+ */
+ if(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER)
+ result = FALSE;
+ else
+ result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(result)
+} /* H5MF__fsm_type_is_self_referential() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__fsm_is_self_referential()
+ *
+ * Purpose: Return TRUE if the indicated free space manager allocates
+ * file space for free space managers. Return FALSE otherwise.
+ *
+ * Return: TRUE/FALSE
+ *
+ * Programmer: John Mainzer
+ * 12/6/16
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5MF__fsm_is_self_referential(H5F_t *f, H5FS_t *fspace)
+{
+ H5F_mem_page_t sm_fshdr_fsm;
+ H5F_mem_page_t sm_fssinfo_fsm;
+ hbool_t result = FALSE;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(fspace);
+
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm);
+
+ if(H5F_PAGED_AGGR(f)) {
+ H5F_mem_page_t lg_fshdr_fsm;
+ H5F_mem_page_t lg_fssinfo_fsm;
+
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fsm);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fsm);
+
+ result = (fspace == f->shared->fs_man[sm_fshdr_fsm]) ||
+ (fspace == f->shared->fs_man[sm_fssinfo_fsm]) ||
+ (fspace == f->shared->fs_man[lg_fshdr_fsm]) ||
+ (fspace == f->shared->fs_man[lg_fssinfo_fsm]);
+ } /* end if */
+ else
+ result = (fspace == f->shared->fs_man[sm_fshdr_fsm]) ||
+ (fspace == f->shared->fs_man[sm_fssinfo_fsm]);
+
+ FUNC_LEAVE_NOAPI(result)
+} /* H5MF__fsm_is_self_referential() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_tidy_self_referential_fsm_hack
+ *
+ * Purpose: As discussed in the comments of the settle routines above,
+ * the existence of self referential free space managers
+ * as currently implemented creates the possibility of
+ * infinite loops at file close.
+ *
+ * As a hack to avoid this, we have added code to settle
+ * self referential free space managers, and then allocate
+ * space for them directly from the file driver.
+ *
+ * To avoid dropping ever increasing amounts of file space
+ * on the floor with each subsequent file close/open cycle,
+ * we need to clean this up on file open. To avoid this,
+ * this function is called on the first file space allocation
+ * or deallocation after file open to float the self referential
+ * free space managers and reduce the EOA to the value it
+ * had before the direct allocation of space for the self
+ * referential free space managers.
+ *
+ * The function proceeds as follows:
+ *
+ * 1) Verify that f->shared->first_alloc_dealloc is TRUE,
+ * and then set it to FALSE.
+ *
+ * 2) Get the current EOA. Verify that it is greater than
+ * or equal to f->shared->eoa_pre_fsm_fsalloc. If the
+ * current eoa is equal to f->shared->eoa_pre_fsm_fsalloc,
+ * no self referential FSMs were stored, and we are done.
+ *
+ * NOTE: This will have to be reworked somewhat for
+ * cache image.
+ *
+ * 3) Load the self referential FSMs. In passing verify that
+ * the lowest address of a FSM header is equal to
+ * f->shared->eoa_pre_fsm_fsalloc.'
+ *
+ * Note that we don't have to use any special I/O for
+ * this -- we can use the regular I/O methods even if
+ * paged aggregation and page buffering is enabled.
+ *
+ * 4) Float the FSMs. Ensure that the file space is NOT
+ * released.
+ *
+ * 5) Set EOA equal to f->shared->eoa_pre_fsm_fsalloc,
+ * and then set f->shared->eoa_pre_fsm_fsalloc to
+ * HADDR_UNDEF.
+ *
+ * If page buffering, verify that the new EOA is
+ * on a page boundary, and expunge any pages in the
+ * page buffer after the new EOA.
+ *
+ * Note that this function is also called from test code
+ * when it is necessary to startup a self referential
+ * free space manager prior to the first file space
+ * allocation / deallocation. Failure to do so will
+ * result in assertion failures in this function on
+ * the first file space allocation / deallocation.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: John Mainzer
+ * 12/11/16
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_tidy_self_referential_fsm_hack(H5F_t *f, hid_t dxpl_id)
+{
+ haddr_t eoa; /* EOA of file */
+ hsize_t tail_size = 0; /* Size of chunk to free */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ haddr_t first_srfsm_hdr = HADDR_UNDEF; /* Addr of first self referential */
+ /* fsm header in file */
+ H5FS_stat_t fs_stat; /* Information for hdr FSM */
+ H5F_mem_page_t sm_fshdr_fs_type; /* Small fs hdr fsm */
+ H5F_mem_page_t sm_fssinfo_fs_type; /* Small fs sinfo fsm */
+ H5F_mem_page_t lg_fshdr_fs_type; /* Large fs hdr fsm */
+ H5F_mem_page_t lg_fssinfo_fs_type; /* Large fs sinfo fsm */
+ hbool_t reset_ring = FALSE; /* Whether the ring was set */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->fs_persist);
+ HDassert(f->shared->first_alloc_dealloc);
+
+ /* Set the ring type in the DXPL. Since we are only dealing with
+ * self referential FSMs, we will only need H5AC_RING_MDFSM.
+ */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_MDFSM, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value")
+ reset_ring = TRUE;
+
+ /* 1) Verify that f->shared->first_alloc_dealloc is TRUE,
+ * and then set it to FALSE.
+ */
+ HDassert(f->shared->first_alloc_dealloc);
+ f->shared->first_alloc_dealloc = FALSE;
+
+
+ /* 2) Get the current EOA. Verify that it is greater than
+ * or equal to f->shared->eoa_pre_fsm_fsalloc. If the
+ * current eoa is equal to f->shared->eoa_pre_fsm_fsalloc,
+ * no self referential FSMs were stored, and we are done.
+ *
+ * NOTE: This will have to be reworked somewhat for
+ * cache image.
+ */
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA")
+ HDassert(H5F_addr_le(f->shared->eoa_pre_fsm_fsalloc, eoa));
+
+ if(H5F_addr_eq(f->shared->eoa_pre_fsm_fsalloc, eoa))
+ HGOTO_DONE(SUCCEED)
+
+
+ /* 3) Load the self referential FSMs. In passing verify that
+ * the lowest address of a FSM header is equal to
+ * f->shared->eoa_pre_fsm_fsalloc.'
+ *
+ * Note that we don't have to use any special I/O for
+ * this -- we can use the regular I/O methods even if
+ * paged aggregation and page buffering is enabled.
+ */
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type);
+ HDassert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
+
+ HDassert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT);
+ HDassert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER);
+
+ HDassert(NULL == f->shared->fs_man[sm_fshdr_fs_type]);
+ HDassert(NULL == f->shared->fs_man[sm_fssinfo_fs_type]);
+
+ if(H5F_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type])) {
+ first_srfsm_hdr = f->shared->fs_addr[sm_fshdr_fs_type];
+
+ /* open the FSM */
+ if(H5MF_open_fstype(f, dxpl_id, sm_fshdr_fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager")
+
+ HDassert(f->shared->fs_man[sm_fshdr_fs_type]);
+ } /* end if */
+
+ if((sm_fshdr_fs_type != sm_fssinfo_fs_type) &&
+ (H5F_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type]))) {
+
+ if(!H5F_addr_defined(first_srfsm_hdr) ||
+ (H5F_addr_defined(first_srfsm_hdr) &&
+ H5F_addr_lt(f->shared->fs_addr[sm_fssinfo_fs_type], first_srfsm_hdr)))
+ first_srfsm_hdr = f->shared->fs_addr[sm_fssinfo_fs_type];
+
+ HDassert(NULL == f->shared->fs_man[sm_fssinfo_fs_type]);
+
+ /* open the FSM */
+ if(H5MF_open_fstype(f, dxpl_id, sm_fssinfo_fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager")
+
+ HDassert(f->shared->fs_man[sm_fssinfo_fs_type]);
+ } /* end if */
+
+ if(H5F_PAGED_AGGR(f)) {
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fs_type);
+ H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fs_type);
+
+ HDassert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES);
+
+ HDassert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER);
+ HDassert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES);
+
+ HDassert(NULL == f->shared->fs_man[lg_fshdr_fs_type]);
+ HDassert(NULL == f->shared->fs_man[lg_fssinfo_fs_type]);
+
+ if(H5F_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type])) {
+ if(!H5F_addr_defined(first_srfsm_hdr) ||
+ (H5F_addr_defined(first_srfsm_hdr) &&
+ H5F_addr_lt(f->shared->fs_addr[lg_fshdr_fs_type], first_srfsm_hdr)))
+ first_srfsm_hdr = f->shared->fs_addr[lg_fshdr_fs_type];
+
+ HDassert(NULL == f->shared->fs_man[lg_fshdr_fs_type]);
+
+ /* open the FSM */
+ if(H5MF_open_fstype(f, dxpl_id, lg_fshdr_fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager")
+ HDassert(f->shared->fs_man[lg_fshdr_fs_type]);
+ } /* end if */
+
+ if(lg_fshdr_fs_type != lg_fssinfo_fs_type && H5F_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type])) {
+ if(!H5F_addr_defined(first_srfsm_hdr) ||
+ (H5F_addr_defined(first_srfsm_hdr) &&
+ H5F_addr_lt(f->shared->fs_addr[lg_fssinfo_fs_type], first_srfsm_hdr)))
+ first_srfsm_hdr = f->shared->fs_addr[lg_fssinfo_fs_type];
+
+ HDassert(NULL == f->shared->fs_man[lg_fssinfo_fs_type]);
+
+ /* open the FSM */
+ if(H5MF_open_fstype(f, dxpl_id, lg_fssinfo_fs_type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager")
+ HDassert(f->shared->fs_man[lg_fssinfo_fs_type]);
+ } /* end if */
+ } /* end if */
+ HDassert(H5F_addr_eq(first_srfsm_hdr, f->shared->eoa_pre_fsm_fsalloc));
+
+ /* 4) Float the FSMs. Ensure that the file space is NOT released. */
+ if(f->shared->fs_man[sm_fshdr_fs_type]) {
+ /* Sanity check: Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[sm_fshdr_fs_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info")
+
+ HDassert(H5F_addr_defined(fs_stat.addr));
+ HDassert(H5F_addr_defined(fs_stat.sect_addr));
+ if(H5FS_free(f, f->shared->fs_man[sm_fshdr_fs_type], dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers")
+ f->shared->fs_addr[sm_fshdr_fs_type] = HADDR_UNDEF;
+ } /* end if */
+
+ if(sm_fshdr_fs_type != sm_fssinfo_fs_type && f->shared->fs_man[sm_fssinfo_fs_type]) {
+ /* Sanity check: Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[sm_fssinfo_fs_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info")
+
+ HDassert(H5F_addr_defined(fs_stat.addr));
+ HDassert(H5F_addr_defined(fs_stat.sect_addr));
+ if(H5FS_free(f, f->shared->fs_man[sm_fssinfo_fs_type], dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers")
+ f->shared->fs_addr[sm_fssinfo_fs_type] = HADDR_UNDEF;
+ } /* end if */
+
+ if(H5F_PAGED_AGGR(f)) {
+ if(f->shared->fs_man[lg_fshdr_fs_type]) {
+ /* Sanity check: Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[lg_fshdr_fs_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
+
+ HDassert(H5F_addr_defined(fs_stat.addr));
+ HDassert(H5F_addr_defined(fs_stat.sect_addr));
+ if(H5FS_free(f, f->shared->fs_man[lg_fshdr_fs_type], dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't float free-space headers")
+ f->shared->fs_addr[lg_fshdr_fs_type] = HADDR_UNDEF;
+ } /* end if */
+
+ if(lg_fshdr_fs_type != lg_fssinfo_fs_type && f->shared->fs_man[lg_fssinfo_fs_type]) {
+ /* Sanity check: Query free space manager info for this type */
+ if(H5FS_stat_info(f, f->shared->fs_man[lg_fssinfo_fs_type], &fs_stat) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info")
+
+ HDassert(H5F_addr_defined(fs_stat.addr));
+ HDassert(H5F_addr_defined(fs_stat.sect_addr));
+ if(H5FS_free(f, f->shared->fs_man[lg_fssinfo_fs_type], dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't float free-space headers")
+ f->shared->fs_addr[lg_fssinfo_fs_type] = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+
+ /* 5) Set EOA equal to f->shared->eoa_pre_fsm_fsalloc,
+ * and then set f->shared->eoa_pre_fsm_fsalloc to
+ * HADDR_UNDEF.
+ *
+ * If page buffering, verify that the new EOA is
+ * on a page boundary, and expunge any pages in the
+ * page buffer after the new EOA.
+ */
+ if(!H5F_PAGED_AGGR(f)) {
+ /* Verify that the aggregators are still shutdown. */
+ HDassert(f->shared->sdata_aggr.tot_size == 0);
+ HDassert(f->shared->sdata_aggr.addr == 0);
+ HDassert(f->shared->sdata_aggr.size == 0);
+
+ HDassert(f->shared->meta_aggr.tot_size == 0);
+ HDassert(f->shared->meta_aggr.addr == 0);
+ HDassert(f->shared->meta_aggr.size == 0);
+ } /* end if */
+
+ tail_size = (hsize_t)(eoa - f->shared->eoa_pre_fsm_fsalloc);
+
+ /* Release file space allocated to self referential FSMs */
+ if(H5F_free(f, dxpl_id, H5FD_MEM_DEFAULT, f->shared->eoa_pre_fsm_fsalloc, tail_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA")
+ HDassert(H5F_addr_eq(f->shared->eoa_pre_fsm_fsalloc, eoa));
+
+ f->shared->eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+
+ HDassert((!H5F_PAGED_AGGR(f)) || (0 == (eoa % f->shared->fs_page_size)));
+
+done:
+ /* Reset the ring in the DXPL */
+ if(reset_ring)
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF_tidy_self_referential_fsm_hack() */
+
diff --git a/src/H5MFaggr.c b/src/H5MFaggr.c
new file mode 100644
index 0000000..7c05e0d
--- /dev/null
+++ b/src/H5MFaggr.c
@@ -0,0 +1,902 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, January 8, 2008
+ *
+ * Purpose: Routines for aggregating free space allocations
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5MFmodule.h" /* This source code file is part of the H5MF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5MFpkg.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+#define EXTEND_THRESHOLD 0.10F
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5MF__aggr_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type,
+ H5F_blk_aggr_t *aggr);
+static haddr_t H5MF__aggr_alloc(H5F_t *f, hid_t dxpl_id, H5F_blk_aggr_t *aggr,
+ H5F_blk_aggr_t *other_aggr, H5FD_mem_t type, hsize_t size);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_vfd_alloc
+ *
+ * Purpose: Allocate SIZE bytes of file memory via H5MF__aggr_alloc()
+ * and return the relative address where that contiguous chunk
+ * of file memory exists.
+ * The TYPE argument describes the purpose for which the storage
+ * is being requested.
+ *
+ * Return: Success: The file address of new chunk.
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Vailin Choi; July 1st, 2009
+ * (The coding is from H5MF_alloc().)
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5MF_aggr_vfd_alloc(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size)
+{
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI(HADDR_UNDEF)
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size);
+#endif /* H5MF_AGGR_DEBUG */
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+ HDassert(size > 0);
+
+ /* Couldn't find anything from the free space manager, go allocate some */
+ if(alloc_type != H5FD_MEM_DRAW && alloc_type != H5FD_MEM_GHEAP) {
+ /* Handle metadata differently from "raw" data */
+ if(HADDR_UNDEF == (ret_value = H5MF__aggr_alloc(f, dxpl_id, &(f->shared->meta_aggr), &(f->shared->sdata_aggr), alloc_type, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate metadata")
+ } /* end if */
+ else {
+ /* Allocate "raw" data: H5FD_MEM_DRAW and H5FD_MEM_GHEAP */
+ if(HADDR_UNDEF == (ret_value = H5MF__aggr_alloc(f, dxpl_id, &(f->shared->sdata_aggr), &(f->shared->meta_aggr), H5FD_MEM_DRAW, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate raw data")
+ } /* end else */
+
+ /* Sanity check for overlapping into file's temporary allocation space */
+ HDassert(H5F_addr_le((ret_value + size), f->shared->tmp_addr));
+
+done:
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size);
+#endif /* H5MF_AGGR_DEBUG */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_aggr_vfd_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__aggr_alloc
+ *
+ * Purpose: Try to allocate SIZE bytes of memory from an aggregator
+ * block if possible.
+ *
+ * Return: Success: The format address of the new file memory.
+ * Failure: The undefined address HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 13, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5MF__aggr_alloc(H5F_t *f, hid_t dxpl_id, H5F_blk_aggr_t *aggr,
+ H5F_blk_aggr_t *other_aggr, H5FD_mem_t type, hsize_t size)
+{
+ haddr_t eoa_frag_addr = HADDR_UNDEF; /* Address of fragment at EOA */
+ hsize_t eoa_frag_size = 0; /* Size of fragment at EOA */
+ haddr_t eoa = HADDR_UNDEF; /* Initial EOA for the file */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_STATIC
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size);
+#endif /* H5MF_AGGR_DEBUG */
+
+ /* check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+ HDassert(other_aggr);
+ HDassert(other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+ HDassert(other_aggr->feature_flag != aggr->feature_flag);
+ HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
+ HDassert(size > 0);
+
+ /* Get the EOA for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa")
+
+ /*
+ * If the aggregation feature is enabled for this file and strategy is not H5F_FILE_SPACE_NONE,
+ * allocate "generic" space and sub-allocate out of that, if possible.
+ * Otherwise just allocate through H5F_alloc().
+ */
+ if((f->shared->feature_flags & aggr->feature_flag) && f->shared->fs_strategy != H5F_FSPACE_STRATEGY_NONE) {
+ haddr_t aggr_frag_addr = HADDR_UNDEF; /* Address of aggregrator fragment */
+ hsize_t aggr_frag_size = 0; /* Size of aggregator fragment */
+ hsize_t alignment; /* Alignment of this section */
+ hsize_t aggr_mis_align = 0; /* Mis-alignment of aggregator */
+ H5FD_mem_t alloc_type, other_alloc_type;/* Current aggregator & 'other' aggregator types */
+
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: aggr = {%a, %Hu, %Hu}\n", FUNC, aggr->addr, aggr->tot_size, aggr->size);
+#endif /* H5MF_AGGR_DEBUG */
+
+ /* Turn off alignment if allocation < threshold */
+ alignment = H5F_ALIGNMENT(f);
+ if(!((alignment > 1) && (size >= H5F_THRESHOLD(f))))
+ alignment = 0; /* no alignment */
+
+ /* Generate fragment if aggregator is mis-aligned */
+ if(alignment && H5F_addr_gt(aggr->addr, 0) && (aggr_mis_align = (aggr->addr + H5F_BASE_ADDR(f)) % alignment)) {
+ aggr_frag_addr = aggr->addr;
+ aggr_frag_size = alignment - aggr_mis_align;
+ } /* end if */
+
+ alloc_type = aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW;
+ other_alloc_type = other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW;
+
+ /* Check if the space requested is larger than the space left in the block */
+ if((size + aggr_frag_size) > aggr->size) {
+ htri_t extended = FALSE; /* Whether the file was extended */
+
+ /* Check if the block asked for is too large for 'normal' aggregator block */
+ if(size >= aggr->alloc_size) {
+ hsize_t ext_size = size + aggr_frag_size;
+
+ /* Check for overlapping into file's temporary allocation space */
+ if(H5F_addr_gt((aggr->addr + aggr->size + ext_size), f->shared->tmp_addr))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, HADDR_UNDEF, "'normal' file space allocation request will overlap into 'temporary' file space")
+
+ if((aggr->addr > 0) && (extended = H5F_try_extend(f, dxpl_id, alloc_type, (aggr->addr + aggr->size), ext_size)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't extending space")
+ else if (extended) {
+ /* aggr->size is unchanged */
+ ret_value = aggr->addr + aggr_frag_size;
+ aggr->addr += ext_size;
+ aggr->tot_size += ext_size;
+ } else {
+ /* Release "other" aggregator, if it exists, is at the end of the allocated space,
+ * has allocated more than one block and the unallocated space is greater than its
+ * allocation block size.
+ */
+ if((other_aggr->size > 0) && (H5F_addr_eq((other_aggr->addr + other_aggr->size), eoa)) &&
+ (other_aggr->tot_size > other_aggr->size) && ((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size)) {
+ if(H5MF__aggr_free(f, dxpl_id, other_alloc_type, other_aggr) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block")
+ } /* end if */
+
+ /* Allocate space from the VFD (i.e. at the end of the file) */
+ if(HADDR_UNDEF == (ret_value = H5F_alloc(f, dxpl_id, alloc_type, size, &eoa_frag_addr, &eoa_frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
+ } /* end else */
+ } /* end if */
+ else {
+ hsize_t ext_size = aggr->alloc_size;
+
+ /* Allocate another block */
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: Allocating block\n", FUNC);
+#endif /* H5MF_AGGR_DEBUG */
+
+ if(aggr_frag_size > (ext_size - size))
+ ext_size += (aggr_frag_size - (ext_size - size));
+
+ /* Check for overlapping into file's temporary allocation space */
+ if(H5F_addr_gt((aggr->addr + aggr->size + ext_size), f->shared->tmp_addr))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, HADDR_UNDEF, "'normal' file space allocation request will overlap into 'temporary' file space")
+
+ if((aggr->addr > 0) && (extended = H5F_try_extend(f, dxpl_id, alloc_type, (aggr->addr + aggr->size), ext_size)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't extending space")
+ else if(extended) {
+ aggr->addr += aggr_frag_size;
+ aggr->size += (ext_size - aggr_frag_size);
+ aggr->tot_size += ext_size;
+ } /* end else-if */
+ else {
+ haddr_t new_space; /* Address of new space allocated */
+
+ /* Release "other" aggregator, if it exists, is at the end of the allocated space,
+ * has allocated more than one block and the unallocated space is greater than its
+ * allocation block size.
+ */
+ if((other_aggr->size > 0) && (H5F_addr_eq((other_aggr->addr + other_aggr->size), eoa)) &&
+ (other_aggr->tot_size > other_aggr->size) && ((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size)) {
+ if(H5MF__aggr_free(f, dxpl_id, other_alloc_type, other_aggr) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block")
+ } /* end if */
+
+ /* Allocate space from the VFD (i.e. at the end of the file) */
+ if(HADDR_UNDEF == (new_space = H5F_alloc(f, dxpl_id, alloc_type, aggr->alloc_size, &eoa_frag_addr, &eoa_frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
+
+ /* Return the unused portion of the block to a free list */
+ if(aggr->size > 0)
+ if(H5MF_xfree(f, alloc_type, dxpl_id, aggr->addr, aggr->size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block")
+
+ /* If the block is not to be aligned, fold the eoa fragment
+ * into the newly allocated aggregator, as it could have
+ * been allocated in an aligned manner if the aggregator
+ * block is larger than the threshold */
+ if(eoa_frag_size && !alignment) {
+ HDassert(eoa_frag_addr + eoa_frag_size == new_space);
+ aggr->addr = eoa_frag_addr;
+ aggr->size = aggr->alloc_size + eoa_frag_size;
+ aggr->tot_size = aggr->size;
+
+ /* Reset EOA fragment */
+ eoa_frag_addr = HADDR_UNDEF;
+ eoa_frag_size = 0;
+ } /* end if */
+ else {
+ /* Point the aggregator at the newly allocated block */
+ aggr->addr = new_space;
+ aggr->size = aggr->alloc_size;
+ aggr->tot_size = aggr->alloc_size;
+ } /* end else */
+ } /* end else */
+
+ /* Allocate space out of the metadata block */
+ ret_value = aggr->addr;
+ aggr->size -= size;
+ aggr->addr += size;
+ } /* end else */
+
+ /* Freeing any possible fragment due to file allocation */
+ if(eoa_frag_size)
+ if(H5MF_xfree(f, alloc_type, dxpl_id, eoa_frag_addr, eoa_frag_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free eoa fragment")
+
+ /* Freeing any possible fragment due to alignment in the block after extension */
+ if(extended && aggr_frag_size)
+ if(H5MF_xfree(f, alloc_type, dxpl_id, aggr_frag_addr, aggr_frag_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation fragment")
+ } /* end if */
+ else {
+ /* Allocate space out of the block */
+ ret_value = aggr->addr + aggr_frag_size;
+ aggr->size -= (size + aggr_frag_size);
+ aggr->addr += (size + aggr_frag_size);
+
+ /* free any possible fragment */
+ if(aggr_frag_size)
+ if(H5MF_xfree(f, alloc_type, dxpl_id, aggr_frag_addr, aggr_frag_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation fragment")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Allocate data from the file */
+ if(HADDR_UNDEF == (ret_value = H5F_alloc(f, dxpl_id, type, size, &eoa_frag_addr, &eoa_frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space")
+
+ /* Check if fragment was generated */
+ if(eoa_frag_size)
+ /* Put fragment on the free list */
+ if(H5MF_xfree(f, type, dxpl_id, eoa_frag_addr, eoa_frag_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "can't free eoa fragment")
+ } /* end else */
+
+ /* Sanity check for overlapping into file's temporary allocation space */
+ HDassert(H5F_addr_le((ret_value + size), f->shared->tmp_addr));
+
+ /* Post-condition sanity check */
+ if(H5F_ALIGNMENT(f) && size >= H5F_THRESHOLD(f))
+ HDassert(!((ret_value + H5FD_get_base_addr(f->shared->lf)) % H5F_ALIGNMENT(f)));
+
+done:
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value);
+#endif /* H5MF_AGGR_DEBUG */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF__aggr_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_try_extend
+ *
+ * Purpose: Check if a block is inside an aggregator block and extend it
+ * if possible.
+ *
+ * Note:
+ * When the block to be extended adjoins the aggregator--
+ * 1) When the aggregator is at end of file:
+ * A) If the request is below the threshold, extend the block into the aggregator
+ * B) If the request is above the threshold,
+ * a) extend the aggregator by aggr->alloc_size or the extended amount
+ * b) extend the block into the aggregator
+ * 2) When the aggregator is not at end of file:
+ * Extended the block into the aggregator if it has enough space to satisfy the request
+ *
+ * Return: Success: TRUE(1) - Block was extended
+ * FALSE(0) - Block could not be extended
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 13, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_aggr_try_extend(H5F_t *f, hid_t dxpl_id, H5F_blk_aggr_t *aggr,
+ H5FD_mem_t type, haddr_t blk_end, hsize_t extra_requested)
+{
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+
+ /* Check if this aggregator is active */
+ if(f->shared->feature_flags & aggr->feature_flag) {
+ /*
+ * If the block being tested adjoins the beginning of the aggregator
+ * block, check if the aggregator can accomodate the extension.
+ */
+ if(H5F_addr_eq(blk_end, aggr->addr)) {
+ haddr_t eoa; /* EOA for the file */
+
+ /* Get the EOA for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa")
+
+ /* If the aggregator is at the end of file: */
+ if(H5F_addr_eq(eoa, aggr->addr + aggr->size)) {
+ /* If extra_requested is below percentage threshold, extend block into the aggregator. */
+ if(extra_requested <= (hsize_t)(EXTEND_THRESHOLD * (float)aggr->size)) {
+ aggr->size -= extra_requested;
+ aggr->addr += extra_requested;
+
+ /* Indicate success */
+ HGOTO_DONE(TRUE);
+ } /* end if */
+ /*
+ * If extra_requested is above percentage threshold:
+ * 1) "bubble" up the aggregator by aggr->alloc_size or extra_requested
+ * 2) extend the block into the aggregator
+ */
+ else {
+ hsize_t extra = (extra_requested < aggr->alloc_size) ? aggr->alloc_size : extra_requested;
+
+ if((ret_value = H5F_try_extend(f, dxpl_id, type, (aggr->addr + aggr->size), extra)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file")
+ else if(ret_value == TRUE) {
+ /* Shift the aggregator block by the extra requested */
+ /* (allocates the space for the extra_requested) */
+ aggr->addr += extra_requested;
+
+ /* Add extra to the aggregator's total allocated amount */
+ aggr->tot_size += extra;
+
+ /* Account for any space added to the aggregator */
+ /* (either 0 (if extra_requested > aggr->alloc_size) or
+ * (aggr->alloc_size - extra_requested) -QAK
+ */
+ aggr->size += extra;
+ aggr->size -= extra_requested;
+ } /* end else-if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* The aggreator is not at end of file */
+ /* Check if aggregator has enough internal space to satisfy the extension. */
+ if(aggr->size >= extra_requested) {
+ /* Extend block into aggregator */
+ aggr->size -= extra_requested;
+ aggr->addr += extra_requested;
+
+ /* Indicate success */
+ HGOTO_DONE(TRUE);
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_aggr_try_extend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_can_absorb
+ *
+ * Purpose: Check if a section adjoins an aggregator block and one can
+ * absorb the other.
+ *
+ * Return: Success: TRUE(1) - Section or aggregator can be absorbed
+ * FALSE(0) - Section and aggregator can not be absorbed
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 1, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_aggr_can_absorb(const H5F_t *f, const H5F_blk_aggr_t *aggr,
+ const H5MF_free_section_t *sect, H5MF_shrink_type_t *shrink)
+{
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+ HDassert(sect);
+ HDassert(shrink);
+
+ /* Check if this aggregator is active */
+ if(f->shared->feature_flags & aggr->feature_flag) {
+ /* Check if the block adjoins the beginning or end of the aggregator */
+ if(H5F_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr)
+ || H5F_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr)) {
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: section {%a, %Hu} adjoins aggr = {%a, %Hu}\n", "H5MF_aggr_can_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr, aggr->size);
+#endif /* H5MF_AGGR_DEBUG */
+ /* Check if aggregator would get too large and should be absorbed into section */
+ if((aggr->size + sect->sect_info.size) >= aggr->alloc_size)
+ *shrink = H5MF_SHRINK_SECT_ABSORB_AGGR;
+ else
+ *shrink = H5MF_SHRINK_AGGR_ABSORB_SECT;
+
+ /* Indicate success */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_aggr_can_absorb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_absorb
+ *
+ * Purpose: Absorb a free space section into an aggregator block or
+ * vice versa.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, February 1, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_aggr_absorb(const H5F_t H5_ATTR_UNUSED *f, H5F_blk_aggr_t *aggr, H5MF_free_section_t *sect,
+ hbool_t allow_sect_absorb)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+ HDassert(f->shared->feature_flags & aggr->feature_flag);
+ HDassert(sect);
+
+ /* Check if aggregator would get too large and should be absorbed into section */
+ if((aggr->size + sect->sect_info.size) >= aggr->alloc_size && allow_sect_absorb) {
+ /* Check if the section adjoins the beginning or end of the aggregator */
+ if(H5F_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr)) {
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: aggr {%a, %Hu} adjoins front of section = {%a, %Hu}\n", "H5MF_aggr_absorb", aggr->addr, aggr->size, sect->sect_info.addr, sect->sect_info.size);
+#endif /* H5MF_AGGR_DEBUG */
+ /* Absorb aggregator onto end of section */
+ sect->sect_info.size += aggr->size;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr));
+
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: aggr {%a, %Hu} adjoins end of section = {%a, %Hu}\n", "H5MF_aggr_absorb", aggr->addr, aggr->size, sect->sect_info.addr, sect->sect_info.size);
+#endif /* H5MF_AGGR_DEBUG */
+ /* Absorb aggregator onto beginning of section */
+ sect->sect_info.addr -= aggr->size;
+ sect->sect_info.size += aggr->size;
+ } /* end if */
+
+ /* Reset aggregator */
+ aggr->tot_size = 0;
+ aggr->addr = 0;
+ aggr->size = 0;
+ } /* end if */
+ else {
+ /* Check if the section adjoins the beginning or end of the aggregator */
+ if(H5F_addr_eq((sect->sect_info.addr + sect->sect_info.size), aggr->addr)) {
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: section {%a, %Hu} adjoins front of aggr = {%a, %Hu}\n", "H5MF_aggr_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr, aggr->size);
+#endif /* H5MF_AGGR_DEBUG */
+ /* Absorb section onto front of aggregator */
+ aggr->addr -= sect->sect_info.size;
+ aggr->size += sect->sect_info.size;
+
+ /* Sections absorbed onto front of aggregator count against the total
+ * amount of space aggregated together.
+ */
+ aggr->tot_size -= MIN(aggr->tot_size, sect->sect_info.size);
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5F_addr_eq((aggr->addr + aggr->size), sect->sect_info.addr));
+
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: section {%a, %Hu} adjoins end of aggr = {%a, %Hu}\n", "H5MF_aggr_absorb", sect->sect_info.addr, sect->sect_info.size, aggr->addr, aggr->size);
+#endif /* H5MF_AGGR_DEBUG */
+ /* Absorb section onto end of aggregator */
+ aggr->size += sect->sect_info.size;
+ } /* end if */
+ /* Sanity check */
+ HDassert(!allow_sect_absorb || (aggr->size < aggr->alloc_size));
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5MF_aggr_absorb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_query
+ *
+ * Purpose: Query a block aggregator's current address & size info
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 13, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_aggr_query(const H5F_t *f, const H5F_blk_aggr_t *aggr, haddr_t *addr,
+ hsize_t *size)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+
+ /* Check if this aggregator is active */
+ if(f->shared->feature_flags & aggr->feature_flag) {
+ if(addr)
+ *addr = aggr->addr;
+ if(size)
+ *size = aggr->size;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5MF_aggr_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_reset
+ *
+ * Purpose: Reset a block aggregator, returning any space back to file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 13, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_aggr_reset(H5F_t *f, hid_t dxpl_id, H5F_blk_aggr_t *aggr)
+{
+ H5FD_mem_t alloc_type; /* Type of file memory to work with */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+
+ /* Set the type of memory in the file */
+ alloc_type = (aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW); /* Type of file memory to work with */
+
+ /* Check if this aggregator is active */
+ if(f->shared->feature_flags & aggr->feature_flag) {
+ haddr_t tmp_addr; /* Temporary holder for aggregator address */
+ hsize_t tmp_size; /* Temporary holder for aggregator size */
+
+ /* Retain aggregator info */
+ tmp_addr = aggr->addr;
+ tmp_size = aggr->size;
+#ifdef H5MF_AGGR_DEBUG
+HDfprintf(stderr, "%s: tmp_addr = %a, tmp_size = %Hu\n", FUNC, tmp_addr, tmp_size);
+#endif /* H5MF_AGGR_DEBUG */
+
+ /* Reset aggregator block information */
+ aggr->tot_size = 0;
+ aggr->addr = 0;
+ aggr->size = 0;
+
+ /* Return the unused portion of the metadata block to the file */
+ if(tmp_size > 0 && (H5F_INTENT(f) & H5F_ACC_RDWR))
+ if(H5MF_xfree(f, alloc_type, dxpl_id, tmp_addr, tmp_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't release aggregator's free space")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_aggr_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_free_aggrs
+ *
+ * Purpose: Reset a metadata & small block aggregators, returning any space
+ * back to file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * July 1st, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_free_aggrs(H5F_t *f, hid_t dxpl_id)
+{
+ H5F_blk_aggr_t *first_aggr; /* First aggregator to reset */
+ H5F_blk_aggr_t *second_aggr; /* Second aggregator to reset */
+ haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */
+ hsize_t ma_size = 0; /* Size of "metadata aggregator" */
+ haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */
+ hsize_t sda_size = 0; /* Size of "small data aggregator" */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->lf);
+
+ /* Retrieve metadata aggregator info, if available */
+ if(H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats")
+
+ /* Retrieve 'small data' aggregator info, if available */
+ if(H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats")
+
+ /* Make certain we release the aggregator that's later in the file first */
+ /* (so the file shrinks properly) */
+ if(H5F_addr_defined(ma_addr) && H5F_addr_defined(sda_addr)) {
+ if(H5F_addr_lt(ma_addr, sda_addr)) {
+ first_aggr = &(f->shared->sdata_aggr);
+ second_aggr = &(f->shared->meta_aggr);
+ } /* end if */
+ else {
+ first_aggr = &(f->shared->meta_aggr);
+ second_aggr = &(f->shared->sdata_aggr);
+ } /* end else */
+ } /* end if */
+ else {
+ first_aggr = &(f->shared->meta_aggr);
+ second_aggr = &(f->shared->sdata_aggr);
+ } /* end else */
+
+ /* Release the unused portion of the metadata and "small data" blocks back
+ * to the free lists in the file.
+ */
+ if(H5MF_aggr_reset(f, dxpl_id, first_aggr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset metadata block")
+ if(H5MF_aggr_reset(f, dxpl_id, second_aggr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset 'small data' block")
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_free_aggrs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggr_can_shrink_eoa
+ *
+ * Purpose: Check if the remaining space in the aggregator is at EOA
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_aggr_can_shrink_eoa(H5F_t *f, H5FD_mem_t type, H5F_blk_aggr_t *aggr)
+{
+ haddr_t eoa = HADDR_UNDEF; /* EOA for the file */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(aggr);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+
+ /* Get the EOA for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa")
+
+ /* Check if the aggregator is at EOA */
+ if(aggr->size > 0 && H5F_addr_defined(aggr->addr))
+ ret_value = H5F_addr_eq(eoa, aggr->addr + aggr->size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_aggr_can_shrink_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF__aggr_free
+ *
+ * Purpose: Free the aggregator's space in the file.
+ *
+ * Note: Does _not_ put the space on a free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF__aggr_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, H5F_blk_aggr_t *aggr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared->lf);
+ HDassert(aggr);
+ HDassert(H5F_addr_defined(aggr->addr));
+ HDassert(aggr->size > 0);
+ HDassert(H5F_INTENT(f) & H5F_ACC_RDWR);
+ HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA);
+ HDassert(f->shared->feature_flags & aggr->feature_flag);
+
+ /* Free the remaining space at EOA in the aggregator */
+ if(H5F_free(f, dxpl_id, type, aggr->addr, aggr->size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregation block")
+
+ /* Reset the aggregator */
+ aggr->tot_size = 0;
+ aggr->addr = HADDR_UNDEF;
+ aggr->size = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF__aggr_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_aggrs_try_shrink_eoa
+ *
+ * Purpose: Check the metadata & small block aggregators to see if
+ * EOA shrink is possible; if so, shrink each aggregator
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MF_aggrs_try_shrink_eoa(H5F_t *f, hid_t dxpl_id)
+{
+ htri_t ma_status; /* Whether the metadata aggregator can shrink the EOA */
+ htri_t sda_status; /* Whether the small data aggregator can shrink the EOA */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(f->shared);
+
+ if((ma_status = H5MF_aggr_can_shrink_eoa(f, H5FD_MEM_DEFAULT, &(f->shared->meta_aggr))) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats")
+ if(ma_status > 0)
+ if(H5MF__aggr_free(f, dxpl_id, H5FD_MEM_DEFAULT, &(f->shared->meta_aggr)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
+
+ if((sda_status = H5MF_aggr_can_shrink_eoa(f, H5FD_MEM_DRAW, &(f->shared->sdata_aggr))) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats")
+ if(sda_status > 0)
+ if(H5MF__aggr_free(f, dxpl_id, H5FD_MEM_DRAW, &(f->shared->sdata_aggr)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa")
+
+ ret_value = (ma_status || sda_status);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_aggrs_try_shrink_eoa() */
+
diff --git a/src/H5MFdbg.c b/src/H5MFdbg.c
new file mode 100644
index 0000000..49cfbfc
--- /dev/null
+++ b/src/H5MFdbg.c
@@ -0,0 +1,332 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MFdbg.c
+ * Jan 31 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File memory management debugging functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5MFmodule.h" /* This source code file is part of the H5MF module */
+#define H5MF_DEBUGGING /* Need access to file space debugging routines */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5MFpkg.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for free space section iterator callback */
+typedef struct {
+ H5FS_t *fspace; /* Free space manager */
+ FILE *stream; /* Stream for output */
+ int indent; /* Indention amount */
+ int fwidth; /* Field width amount */
+} H5MF_debug_iter_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sects_debug_cb
+ *
+ * Purpose: Prints debugging info about a free space section for a file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * January 31 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sects_debug_cb(H5FS_section_info_t *_sect, void *_udata)
+{
+ H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; /* Section to dump info */
+ H5MF_debug_iter_ud_t *udata = (H5MF_debug_iter_ud_t *)_udata; /* User data for callbacks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(sect);
+ HDassert(udata);
+
+ /* Print generic section information */
+ HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth,
+ "Section type:",
+ (sect->sect_info.type == H5MF_FSPACE_SECT_SIMPLE ? "simple" :
+ (sect->sect_info.type == H5MF_FSPACE_SECT_SMALL ? "small" :
+ (sect->sect_info.type == H5MF_FSPACE_SECT_LARGE ? "large" : "unknown"))));
+ HDfprintf(udata->stream, "%*s%-*s %a\n", udata->indent, "", udata->fwidth,
+ "Section address:",
+ sect->sect_info.addr);
+ HDfprintf(udata->stream, "%*s%-*s %Hu\n", udata->indent, "", udata->fwidth,
+ "Section size:",
+ sect->sect_info.size);
+ HDfprintf(udata->stream, "%*s%-*s %Hu\n", udata->indent, "", udata->fwidth,
+ "End of section:",
+ (haddr_t)((sect->sect_info.addr + sect->sect_info.size) - 1));
+ HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth,
+ "Section state:",
+ (sect->sect_info.state == H5FS_SECT_LIVE ? "live" : "serialized"));
+
+ /* Dump section-specific debugging information */
+ if(H5FS_sect_debug(udata->fspace, _sect, udata->stream, udata->indent + 3, MAX(0, udata->fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't dump section's debugging info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_sects_debug_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sects_debug
+ *
+ * Purpose: Iterate over free space sections for a file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * January 31 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, FILE *stream, int indent, int fwidth)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ H5FD_mem_t type; /* Memory type for iteration */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ if(H5F_addr_eq(f->shared->fs_addr[type], fs_addr)) {
+ if(!f->shared->fs_man[type])
+ if(H5MF_open_fstype(f, dxpl_id, type) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space")
+
+ if(f->shared->fs_man[type]) {
+ H5MF_debug_iter_ud_t udata; /* User data for callbacks */
+
+ /* Prepare user data for section iteration callback */
+ udata.fspace = f->shared->fs_man[type];
+ udata.stream = stream;
+ udata.indent = indent;
+ udata.fwidth = fwidth;
+
+ /* Iterate over all the free space sections */
+ if(H5FS_sect_iterate(f, dxpl_id, f->shared->fs_man[type], H5MF_sects_debug_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't iterate over heap's free space")
+
+ /* Close the free space information */
+ if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
+ } /* end if */
+ break;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* H5MF_sects_debug() */
+
+#ifdef H5MF_ALLOC_DEBUG_DUMP
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sects_dump
+ *
+ * Purpose: Prints debugging info about free space sections for a file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 31 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_sects_dump(H5F_t *f, hid_t dxpl_id, FILE *stream)
+{
+ haddr_t eoa; /* End of allocated space in the file */
+ int indent = 0; /* Amount to indent */
+ int fwidth = 50; /* Field width */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL)
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: Dumping file free space sections\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(stream);
+
+ /* Retrieve the 'eoa' for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: for type = H5FD_MEM_DEFAULT, eoa = %a\n", FUNC, eoa);
+#endif /* H5MF_ALLOC_DEBUG */
+
+ if(H5F_PAGED_AGGR(f)) { /* File space paging */
+ H5F_mem_page_t ptype; /* Memory type for iteration -- page fs */
+
+ for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) {
+ /* Print header for type */
+ HDfprintf(stream, "%*sFile Free Space Info for type = %u:\n", indent, "", (unsigned)ptype);
+
+ /* Print header for sections */
+ HDfprintf(stream, "%*sSections:\n", indent + 3, "");
+
+ /* If there is a free space manager for this type, iterate over them */
+ if(f->shared->fs_man[ptype]) {
+ H5MF_debug_iter_ud_t udata; /* User data for callbacks */
+
+ /* Prepare user data for section iteration callback */
+ udata.fspace = f->shared->fs_man[ptype];
+ udata.stream = stream;
+ udata.indent = indent + 6;
+ udata.fwidth = MAX(0, fwidth - 6);
+
+ /* Iterate over all the free space sections */
+ if(H5FS_sect_iterate(f, dxpl_id, f->shared->fs_man[ptype], H5MF_sects_debug_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't iterate over heap's free space")
+ } /* end if */
+ else
+ /* No sections of this type */
+ HDfprintf(stream, "%*s<none>\n", indent + 6, "");
+ } /* end for */
+ } /* end if */
+ else { /* not file space paging */
+ H5FD_mem_t atype; /* Memory type for iteration -- aggr fs */
+ haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */
+ hsize_t ma_size = 0; /* Size of "metadata aggregator" */
+ haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */
+ hsize_t sda_size = 0; /* Size of "small data aggregator" */
+
+ /* Retrieve metadata aggregator info, if available */
+ H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size);
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: ma_addr = %a, ma_size = %Hu, end of ma = %a\n", FUNC, ma_addr, ma_size, (haddr_t)((ma_addr + ma_size) - 1));
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* Retrieve 'small data' aggregator info, if available */
+ H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size);
+#ifdef H5MF_ALLOC_DEBUG
+HDfprintf(stderr, "%s: sda_addr = %a, sda_size = %Hu, end of sda = %a\n", FUNC, sda_addr, sda_size, (haddr_t)((sda_addr + sda_size) - 1));
+#endif /* H5MF_ALLOC_DEBUG */
+
+ /* Iterate over all the free space types that have managers and dump each free list's space */
+ for(atype = H5FD_MEM_DEFAULT; atype < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, atype)) {
+ /* Print header for type */
+ HDfprintf(stream, "%*sFile Free Space Info for type = %u:\n", indent, "", (unsigned)atype);
+
+ /* Check for this type being mapped to another type */
+ if(H5FD_MEM_DEFAULT == f->shared->fs_type_map[atype] || atype == f->shared->fs_type_map[atype]) {
+ /* Retrieve the 'eoa' for this file memory type */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, atype)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3), "eoa:", eoa);
+
+ /* Print header for sections */
+ HDfprintf(stream, "%*sSections:\n", indent + 3, "");
+
+ /* If there is a free space manager for this type, iterate over them */
+ if(f->shared->fs.aggr.fs_man[atype]) {
+ H5MF_debug_iter_ud_t udata; /* User data for callbacks */
+
+ /* Prepare user data for section iteration callback */
+ udata.fspace = f->shared->fs_man[atype];
+ udata.stream = stream;
+ udata.indent = indent + 6;
+ udata.fwidth = MAX(0, fwidth - 6);
+
+ /* Iterate over all the free space sections */
+ if(H5FS_sect_iterate(f, dxpl_id, f->shared->fs_man[atype], H5MF_sects_debug_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't iterate over heap's free space")
+ } /* end if */
+ else /* No sections of this type */
+ HDfprintf(stream, "%*s<none>\n", indent + 6, "");
+ } /* end if */
+ else
+ HDfprintf(stream, "%*sMapped to type = %u\n", indent, "", (unsigned)f->shared->fs_type_map[atype]);
+ } /* end for */
+ } /* end else */
+
+done:
+HDfprintf(stderr, "%s: Done dumping file free space sections\n", FUNC);
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5MF_sects_dump() */
+#endif /* H5MF_ALLOC_DEBUG_DUMP */
+
diff --git a/src/H5MFmodule.h b/src/H5MFmodule.h
new file mode 100644
index 0000000..53daabf
--- /dev/null
+++ b/src/H5MFmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5MF package. Including this header means that the source file
+ * is part of the H5MF package.
+ */
+#ifndef _H5MFmodule_H
+#define _H5MFmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5MF_MODULE
+#define H5_MY_PKG H5MF
+#define H5_MY_PKG_ERR H5E_RESOURCE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5MFmodule_H */
+
diff --git a/src/H5MFpkg.h b/src/H5MFpkg.h
new file mode 100644
index 0000000..b95a6db
--- /dev/null
+++ b/src/H5MFpkg.h
@@ -0,0 +1,215 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, January 8, 2008
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5MF package. Source files outside the H5MF package should
+ * include H5MFprivate.h instead.
+ */
+#if !(defined H5MF_FRIEND || defined H5MF_MODULE)
+#error "Do not include this file outside the H5MF package!"
+#endif
+
+#ifndef _H5MFpkg_H
+#define _H5MFpkg_H
+
+/* Get package's private header */
+#include "H5MFprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5FSprivate.h" /* File free space */
+
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Define this to display information about file allocations */
+/* #define H5MF_ALLOC_DEBUG */
+
+/* Define this to display more information about file allocations */
+/* #define H5MF_ALLOC_DEBUG_MORE */
+
+/* Define this to display more information about block aggregator actions */
+/* #define H5MF_AGGR_DEBUG */
+
+/* Define this to dump free space tracker contents after they've been modified */
+/* #define H5MF_ALLOC_DEBUG_DUMP */
+
+/* Free-space section types for file */
+/* (values stored in free space data structures in file) */
+#define H5MF_FSPACE_SECT_SIMPLE 0 /* For non-paged aggregation: section is a range of actual bytes in file */
+#define H5MF_FSPACE_SECT_SMALL 1 /* For paged aggregation: "small" meta/raw data section which is < fsp_size) */
+#define H5MF_FSPACE_SECT_LARGE 2 /* For paged aggregation: "large" Section which is >= fsp_size) */
+
+/* For non-paged aggregation: map allocation request type to tracked free-space type */
+/* F -- pointer to H5F_t; T -- H5FD_mem_t */
+#define H5MF_ALLOC_TO_FS_AGGR_TYPE(F, T) \
+ ((H5FD_MEM_DEFAULT == (F)->shared->fs_type_map[T]) ? (T) : (F)->shared->fs_type_map[T])
+
+/* Get section class type based on size */
+#define H5MF_SECT_CLASS_TYPE(F, S) \
+ ((H5F_PAGED_AGGR(F)) ? \
+ ((S >= (F)->shared->fs_page_size) ? H5MF_FSPACE_SECT_LARGE : H5MF_FSPACE_SECT_SMALL) : H5MF_FSPACE_SECT_SIMPLE)
+
+/* Get section class cls */
+#define H5MF_SECT_CLS_TYPE(F, S) \
+ ((H5F_PAGED_AGGR(F)) ? \
+ ((S >= (F)->shared->fs_page_size) ? \
+ H5MF_FSPACE_SECT_CLS_LARGE : H5MF_FSPACE_SECT_CLS_SMALL) : H5MF_FSPACE_SECT_CLS_SIMPLE)
+
+/* Calculate the mis-aligned fragment */
+#define H5MF_EOA_MISALIGN(F, E, A, FR) \
+{ \
+ hsize_t m; \
+ \
+ if(H5F_addr_gt((E), 0) && ((m) = ((E) + H5F_BASE_ADDR(F)) % (A))) \
+ (FR) = (A) - m; \
+ else \
+ (FR) = 0; \
+}
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* File free space section info */
+typedef struct H5MF_free_section_t {
+ H5FS_section_info_t sect_info; /* Free space section information (must be first in struct) */
+#ifdef NOT_YET
+ union {
+ struct {
+ H5HF_indirect_t *parent; /* Indirect block parent for free section's direct block */
+ unsigned par_entry; /* Entry of free section's direct block in parent indirect block */
+ } single;
+ struct {
+ struct H5HF_free_section_t *under; /* Pointer to indirect block underlying row section */
+ unsigned row; /* Row for range of blocks */
+ unsigned col; /* Column for range of blocks */
+ unsigned num_entries; /* Number of entries covered */
+
+ /* Fields that aren't stored */
+ hbool_t checked_out; /* Flag to indicate that a row section is temporarily out of the free space manager */
+ } row;
+ struct {
+ /* Holds either a pointer to an indirect block (if its "live") or
+ * the block offset of it's indirect block (if its "serialized")
+ * (This allows the indirect block that the section is within to
+ * be compared with other sections, whether it's serialized
+ * or not)
+ */
+ union {
+ H5HF_indirect_t *iblock; /* Indirect block for free section */
+ hsize_t iblock_off; /* Indirect block offset in "heap space" */
+ } u;
+ unsigned row; /* Row for range of blocks */
+ unsigned col; /* Column for range of blocks */
+ unsigned num_entries; /* Number of entries covered */
+
+ /* Fields that aren't stored */
+ struct H5HF_free_section_t *parent; /* Pointer to "parent" indirect section */
+ unsigned par_entry; /* Entry within parent indirect section */
+ hsize_t span_size; /* Size of space tracked, in "heap space" */
+ unsigned iblock_entries; /* Number of entries in indirect block where section is located */
+ unsigned rc; /* Reference count of outstanding row & child indirect sections */
+ unsigned dir_nrows; /* Number of direct rows in section */
+ struct H5HF_free_section_t **dir_rows; /* Array of pointers to outstanding row sections */
+ unsigned indir_nents; /* Number of indirect entries in section */
+ struct H5HF_free_section_t **indir_ents; /* Array of pointers to outstanding child indirect sections */
+ } indirect;
+ } u;
+#endif /* NOT_YET */
+} H5MF_free_section_t;
+
+/* Type of "container shrink" operation to perform */
+typedef enum {
+ H5MF_SHRINK_EOA, /* Section should shrink the EOA value */
+ H5MF_SHRINK_AGGR_ABSORB_SECT, /* Section should merge into the aggregator block */
+ H5MF_SHRINK_SECT_ABSORB_AGGR /* Aggregator block should merge into the section */
+} H5MF_shrink_type_t;
+
+/* User data for free space manager section callbacks */
+typedef struct H5MF_sect_ud_t {
+ /* Down */
+ H5F_t *f; /* Pointer to file to operate on */
+ hid_t dxpl_id; /* DXPL for VFD operations */
+ H5FD_mem_t alloc_type; /* Type of memory being allocated */
+ hbool_t allow_sect_absorb; /* Whether sections are allowed to absorb a block aggregator */
+ hbool_t allow_eoa_shrink_only; /* Whether shrinking eoa is allowed only for the section */
+
+ /* Up */
+ H5MF_shrink_type_t shrink; /* Type of shrink operation to perform */
+ H5F_blk_aggr_t *aggr; /* Aggregator block to operate on */
+} H5MF_sect_ud_t;
+
+/* Information about the current free-space manager to use */
+typedef struct H5MF_fs_t {
+ H5F_fs_state_t *fs_state;
+ haddr_t *fs_addr;
+ H5FS_t **fs_man;
+ hsize_t align_thres; /* Threshold for alignment */
+ hsize_t alignment; /* Alignment */
+} H5MF_fs_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+/* H5MF single section inherits serializable properties from H5FS_section_class_t */
+H5_DLLVAR H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SIMPLE[1];
+H5_DLLVAR H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SMALL[1];
+H5_DLLVAR H5FS_section_class_t H5MF_FSPACE_SECT_CLS_LARGE[1];
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Allocator routines */
+H5_DLL herr_t H5MF_open_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+H5_DLL herr_t H5MF_start_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type);
+
+H5_DLL htri_t H5MF_find_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size, H5FS_t *fspace, haddr_t *addr);
+H5_DLL herr_t H5MF_add_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, H5FS_t *fspace, H5MF_free_section_t *node);
+
+H5_DLL herr_t H5MF_sects_dump(H5F_t *f, hid_t dxpl_id, FILE *stream);
+
+H5_DLL void H5MF_alloc_to_fs_type(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size, H5F_mem_page_t *fs_type);
+
+/* 'simple/small/large' section routines */
+H5_DLL H5MF_free_section_t *H5MF_sect_new(unsigned ctype, haddr_t sect_off,
+ hsize_t sect_size);
+H5_DLL herr_t H5MF_sect_free(H5FS_section_info_t *sect);
+
+
+/* Block aggregator routines */
+H5_DLL htri_t H5MF_aggr_try_extend(H5F_t *f, hid_t dxpl_id, H5F_blk_aggr_t *aggr,
+ H5FD_mem_t type, haddr_t abs_blk_end, hsize_t extra_requested);
+H5_DLL htri_t H5MF_aggr_can_absorb(const H5F_t *f, const H5F_blk_aggr_t *aggr,
+ const H5MF_free_section_t *sect, H5MF_shrink_type_t *shrink);
+H5_DLL herr_t H5MF_aggr_absorb(const H5F_t *f, H5F_blk_aggr_t *aggr,
+ H5MF_free_section_t *sect, hbool_t allow_sect_absorb);
+H5_DLL herr_t H5MF_aggr_query(const H5F_t *f, const H5F_blk_aggr_t *aggr,
+ haddr_t *addr, hsize_t *size);
+
+/* Testing routines */
+#ifdef H5MF_TESTING
+#endif /* H5MF_TESTING */
+
+#endif /* _H5MFpkg_H */
+
diff --git a/src/H5MFprivate.h b/src/H5MFprivate.h
new file mode 100644
index 0000000..bfeaa33
--- /dev/null
+++ b/src/H5MFprivate.h
@@ -0,0 +1,94 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MFprivate.h
+ * Jul 11 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Private header file for file memory management.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5MFprivate_H
+#define _H5MFprivate_H
+
+/* Private headers needed by this file */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File Drivers */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* File space manager routines */
+H5_DLL herr_t H5MF_init_merge_flags(H5F_t *f);
+H5_DLL herr_t H5MF_get_freespace(H5F_t *f, hid_t dxpl_id, hsize_t *tot_space, hsize_t *meta_size);
+H5_DLL herr_t H5MF_close(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5MF_try_close(H5F_t *f, hid_t dxpl_id);
+
+/* File space allocation routines */
+H5_DLL haddr_t H5MF_alloc(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+H5_DLL haddr_t H5MF_aggr_vfd_alloc(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+H5_DLL herr_t H5MF_xfree(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
+ hsize_t size);
+H5_DLL herr_t H5MF_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type,
+ haddr_t addr, hsize_t size, hsize_t extra_requested);
+H5_DLL htri_t H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id,
+ haddr_t addr, hsize_t size);
+H5_DLL ssize_t H5MF_get_free_sections(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type,
+ size_t nsects, H5F_sect_info_t *sect_info);
+
+/* File 'temporary' space allocation routines */
+H5_DLL haddr_t H5MF_alloc_tmp(H5F_t *f, hsize_t size);
+
+/* 'block aggregator' routines */
+H5_DLL herr_t H5MF_free_aggrs(H5F_t *f, hid_t dxpl_id);
+H5_DLL htri_t H5MF_aggrs_try_shrink_eoa(H5F_t *f, hid_t dxpl_id);
+
+/* Free space manager settling routines */
+H5_DLL herr_t H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled);
+H5_DLL herr_t H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled);
+
+/* This function has to be declared in H5MFprivate.h as it is needed
+ * in our test code to allow us to manually start a self referential
+ * free space manager prior to the first file space allocations /
+ * deallocation without causing assertion failures on the first
+ * file space allocation / deallocation.
+ */
+H5_DLL herr_t H5MF_tidy_self_referential_fsm_hack(H5F_t *f, hid_t dxpl_id);
+
+/* Debugging routines */
+#ifdef H5MF_DEBUGGING
+H5_DLL herr_t H5MF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ FILE *stream, int indent, int fwidth);
+#endif /* H5MF_DEBUGGING */
+
+#endif /* end _H5MFprivate_H */
+
diff --git a/src/H5MFsection.c b/src/H5MFsection.c
new file mode 100644
index 0000000..0dd26b3
--- /dev/null
+++ b/src/H5MFsection.c
@@ -0,0 +1,1093 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Tuesday, January 8, 2008
+ *
+ * Purpose: Free space section callbacks for file.
+ *
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5MFmodule.h" /* This source code file is part of the H5MF module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5MFpkg.h" /* File memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* 'simple/small/large' section callbacks */
+static H5FS_section_info_t *H5MF_sect_deserialize(const H5FS_section_class_t *cls,
+ hid_t dxpl_id, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size,
+ unsigned *des_flags);
+static herr_t H5MF_sect_valid(const H5FS_section_class_t *cls,
+ const H5FS_section_info_t *sect, hid_t dxpl_id);
+static H5FS_section_info_t *H5MF_sect_split(H5FS_section_info_t *sect,
+ hsize_t frag_size);
+
+
+/* 'simple' section callbacks */
+static htri_t H5MF_sect_simple_can_merge(const H5FS_section_info_t *sect1,
+ const H5FS_section_info_t *sect2, void *udata);
+static herr_t H5MF_sect_simple_merge(H5FS_section_info_t **sect1,
+ H5FS_section_info_t *sect2, void *udata);
+static htri_t H5MF_sect_simple_can_shrink(const H5FS_section_info_t *_sect,
+ void *udata);
+static herr_t H5MF_sect_simple_shrink(H5FS_section_info_t **_sect,
+ void *udata);
+
+
+/* 'small' section callbacks */
+static herr_t H5MF_sect_small_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata);
+static htri_t H5MF_sect_small_can_merge(const H5FS_section_info_t *sect1,
+ const H5FS_section_info_t *sect2, void *udata);
+static herr_t H5MF_sect_small_merge(H5FS_section_info_t **sect1,
+ H5FS_section_info_t *sect2, void *udata);
+static htri_t H5MF_sect_small_can_shrink(const H5FS_section_info_t *_sect,
+ void *udata);
+static herr_t H5MF_sect_small_shrink(H5FS_section_info_t **_sect,
+ void *udata);
+
+/* 'large' section callbacks */
+static htri_t H5MF_sect_large_can_merge(const H5FS_section_info_t *sect1,
+ const H5FS_section_info_t *sect2, void *udata);
+static herr_t H5MF_sect_large_merge(H5FS_section_info_t **sect1,
+ H5FS_section_info_t *sect2, void *udata);
+static htri_t H5MF_sect_large_can_shrink(const H5FS_section_info_t *_sect,
+ void *udata);
+static herr_t H5MF_sect_large_shrink(H5FS_section_info_t **_sect,
+ void *udata);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Class info for "simple" free space sections */
+H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SIMPLE[1] = {{
+ /* Class variables */
+ H5MF_FSPACE_SECT_SIMPLE, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ NULL, /* Initialize section class */
+ NULL, /* Terminate section class */
+
+ /* Object methods */
+ NULL, /* Add section */
+ NULL, /* Serialize section */
+ H5MF_sect_deserialize, /* Deserialize section */
+ H5MF_sect_simple_can_merge, /* Can sections merge? */
+ H5MF_sect_simple_merge, /* Merge sections */
+ H5MF_sect_simple_can_shrink, /* Can section shrink container?*/
+ H5MF_sect_simple_shrink, /* Shrink container w/section */
+ H5MF_sect_free, /* Free section */
+ H5MF_sect_valid, /* Check validity of section */
+ H5MF_sect_split, /* Split section node for alignment */
+ NULL, /* Dump debugging for section */
+}};
+
+/* Class info for "small" free space sections */
+H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SMALL[1] = {{
+ /* Class variables */
+ H5MF_FSPACE_SECT_SMALL, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ NULL, /* Initialize section class */
+ NULL, /* Terminate section class */
+
+ /* Object methods */
+ H5MF_sect_small_add, /* Add section */
+ NULL, /* Serialize section */
+ H5MF_sect_deserialize, /* Deserialize section */
+ H5MF_sect_small_can_merge, /* Can sections merge? */
+ H5MF_sect_small_merge, /* Merge sections */
+ H5MF_sect_small_can_shrink, /* Can section shrink container?*/
+ H5MF_sect_small_shrink, /* Shrink container w/section */
+ H5MF_sect_free, /* Free section */
+ H5MF_sect_valid, /* Check validity of section */
+ H5MF_sect_split, /* Split section node for alignment */
+ NULL, /* Dump debugging for section */
+}};
+
+/* Class info for "large" free space sections */
+H5FS_section_class_t H5MF_FSPACE_SECT_CLS_LARGE[1] = {{
+ /* Class variables */
+ H5MF_FSPACE_SECT_LARGE, /* Section type */
+ 0, /* Extra serialized size */
+ H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags */
+ NULL, /* Class private info */
+
+ /* Class methods */
+ NULL, /* Initialize section class */
+ NULL, /* Terminate section class */
+
+ /* Object methods */
+ NULL, /* Add section */
+ NULL, /* Serialize section */
+ H5MF_sect_deserialize, /* Deserialize section */
+ H5MF_sect_large_can_merge, /* Can sections merge? */
+ H5MF_sect_large_merge, /* Merge sections */
+ H5MF_sect_large_can_shrink, /* Can section shrink container?*/
+ H5MF_sect_large_shrink, /* Shrink container w/section */
+ H5MF_sect_free, /* Free section */
+ H5MF_sect_valid, /* Check validity of section */
+ H5MF_sect_split, /* Split section node for alignment */
+ NULL, /* Dump debugging for section */
+}};
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5MF_free_section_t struct */
+H5FL_DEFINE(H5MF_free_section_t);
+
+/*
+ * "simple/small/large" section callbacks
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_new
+ *
+ * Purpose: Create a new section of "ctype" and return it to the caller
+ *
+ * Return: Pointer to new section on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * January 8 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+H5MF_free_section_t *
+H5MF_sect_new(unsigned ctype, haddr_t sect_off, hsize_t sect_size)
+{
+ H5MF_free_section_t *sect; /* 'Simple' free space section to add */
+ H5MF_free_section_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect_size);
+
+ /* Create free space section node */
+ if(NULL == (sect = H5FL_MALLOC(H5MF_free_section_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section")
+
+ /* Set the information passed in */
+ sect->sect_info.addr = sect_off;
+ sect->sect_info.size = sect_size;
+
+ /* Set the section's class & state */
+ sect->sect_info.type = ctype;
+ sect->sect_info.state = H5FS_SECT_LIVE;
+
+ /* Set return value */
+ ret_value = sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MF_sect_new() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_free
+ *
+ * Purpose: Free a 'simple/small/large' section node
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MF_sect_free(H5FS_section_info_t *_sect)
+{
+ H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; /* File free section */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ /* Release the section */
+ sect = H5FL_FREE(H5MF_free_section_t, sect);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MF_sect_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_deserialize
+ *
+ * Purpose: Deserialize a buffer into a "live" section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FS_section_info_t *
+H5MF_sect_deserialize(const H5FS_section_class_t *cls,
+ hid_t H5_ATTR_UNUSED dxpl_id, const uint8_t H5_ATTR_UNUSED *buf, haddr_t sect_addr,
+ hsize_t sect_size, unsigned H5_ATTR_UNUSED *des_flags)
+{
+ H5MF_free_section_t *sect; /* New section */
+ H5FS_section_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(cls);
+ HDassert(H5F_addr_defined(sect_addr));
+ HDassert(sect_size);
+
+ /* Create free space section for block */
+ if(NULL == (sect = H5MF_sect_new(cls->type, sect_addr, sect_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section")
+
+ /* Set return value */
+ ret_value = (H5FS_section_info_t *)sect;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_valid
+ *
+ * Purpose: Check the validity of a section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls,
+ const H5FS_section_info_t
+#ifdef NDEBUG
+ H5_ATTR_UNUSED
+#endif /* NDEBUG */
+ *_sect, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+#ifndef NDEBUG
+ const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */
+#endif /* NDEBUG */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MF_sect_valid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_split
+ *
+ * Purpose: Split SECT into 2 sections: fragment for alignment & the aligned section
+ * SECT's addr and size are updated to point to the aligned section
+ *
+ * Return: Success: the fragment for aligning sect
+ * Failure: null
+ *
+ * Programmer: Vailin Choi, July 29, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FS_section_info_t *
+H5MF_sect_split(H5FS_section_info_t *sect, hsize_t frag_size)
+{
+ H5MF_free_section_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate space for new section */
+ if(NULL == (ret_value = H5MF_sect_new(sect->type, sect->addr, frag_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section")
+
+ /* Set new section's info */
+ sect->addr += frag_size;
+ sect->size -= frag_size;
+
+done:
+ FUNC_LEAVE_NOAPI((H5FS_section_info_t *)ret_value)
+} /* end H5MF_sect_split() */
+
+/*
+ * "simple" section callbacks
+ */
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_simple_can_merge
+ *
+ * Purpose: Can two sections of this type merge?
+ *
+ * Note: Second section must be "after" first section
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_simple_can_merge(const H5FS_section_info_t *_sect1,
+ const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
+{
+ const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1; /* File free section */
+ const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2; /* File free section */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert(sect2);
+ HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
+ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
+
+ /* Check if second section adjoins first section */
+ ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_simple_can_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_simple_merge
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_simple_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
+ void H5_ATTR_UNUSED *_udata)
+{
+ H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1; /* File free section */
+ H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2; /* File free section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
+ HDassert(sect2);
+ HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_SIMPLE);
+ HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
+
+ /* Add second section's size to first section */
+ (*sect1)->sect_info.size += sect2->sect_info.size;
+
+ /* Get rid of second section */
+ if(H5MF_sect_free((H5FS_section_info_t *)sect2) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_simple_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_simple_can_shrink
+ *
+ * Purpose: Can this section shrink the container?
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_simple_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
+{
+ const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ haddr_t eoa; /* End of address space in the file */
+ haddr_t end; /* End of section to extend */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Retrieve the end of the file's address space */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(udata->f, udata->alloc_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* Compute address of end of section to check */
+ end = sect->sect_info.addr + sect->sect_info.size;
+
+ /* Check if the section is exactly at the end of the allocated space in the file */
+ if(H5F_addr_eq(end, eoa)) {
+ /* Set the shrinking type */
+ udata->shrink = H5MF_SHRINK_EOA;
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Indicate shrinking can occur */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ else {
+ /* Shrinking can't occur if the 'eoa_shrink_only' flag is set and we're not shrinking the EOA */
+ if(udata->allow_eoa_shrink_only)
+ HGOTO_DONE(FALSE)
+
+ /* Check if this section is allowed to merge with metadata aggregation block */
+ if(udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_METADATA) {
+ htri_t status; /* Status from aggregator adjoin */
+
+ /* See if section can absorb the aggregator & vice versa */
+ if((status = H5MF_aggr_can_absorb(udata->f, &(udata->f->shared->meta_aggr), sect, &(udata->shrink))) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block")
+ else if(status > 0) {
+ /* Set the aggregator to operate on */
+ udata->aggr = &(udata->f->shared->meta_aggr);
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins metadata aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Indicate shrinking can occur */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+
+ /* Check if this section is allowed to merge with small 'raw' aggregation block */
+ if(udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_RAWDATA) {
+ htri_t status; /* Status from aggregator adjoin */
+
+ /* See if section can absorb the aggregator & vice versa */
+ if((status = H5MF_aggr_can_absorb(udata->f, &(udata->f->shared->sdata_aggr), sect, &(udata->shrink))) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block")
+ else if(status > 0) {
+ /* Set the aggregator to operate on */
+ udata->aggr = &(udata->f->shared->sdata_aggr);
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins small data aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Indicate shrinking can occur */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Set return value */
+ ret_value = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_simple_can_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_simple_shrink
+ *
+ * Purpose: Shrink container with section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 8, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_simple_shrink(H5FS_section_info_t **_sect, void *_udata)
+{
+ H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Check for shrinking file */
+ if(H5MF_SHRINK_EOA == udata->shrink) {
+ /* Sanity check */
+ HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
+
+ /* Release section's space at EOA */
+ if(H5F_free(udata->f, udata->dxpl_id, udata->alloc_type, (*sect)->sect_info.addr, (*sect)->sect_info.size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(udata->aggr);
+
+ /* Absorb the section into the aggregator or vice versa */
+ if(H5MF_aggr_absorb(udata->f, udata->aggr, *sect, udata->allow_sect_absorb) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't absorb section into aggregator or vice versa")
+ } /* end else */
+
+ /* Check for freeing section */
+ if(udata->shrink != H5MF_SHRINK_SECT_ABSORB_AGGR) {
+ /* Free section */
+ if(H5MF_sect_free((H5FS_section_info_t *)*sect) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+
+ /* Mark section as freed, for free space manager */
+ *sect = NULL;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_simple_shrink() */
+
+/*
+ * "small" section callbacks
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_small_add
+ *
+ * Purpose: Perform actions on a small "meta" action before adding it to the free space manager:
+ * 1) Drop the section if it is at page end and its size <= page end threshold
+ * 2) Adjust section size to include page end threshold if
+ * (section size + threshold) is at page end
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_small_add(H5FS_section_info_t **_sect, unsigned *flags, void *_udata)
+{
+ H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* Fractal heap free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ haddr_t sect_end;
+ hsize_t rem, prem;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Entering, section {%a, %Hu}\n", FUNC, (*sect)->sect_info.addr, (*sect)->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Do not adjust the section raw data or global heap data */
+ if(udata->alloc_type == H5FD_MEM_DRAW || udata->alloc_type == H5FD_MEM_GHEAP)
+ HGOTO_DONE(ret_value);
+
+ sect_end = (*sect)->sect_info.addr + (*sect)->sect_info.size;
+ rem = sect_end % udata->f->shared->fs_page_size;
+ prem = udata->f->shared->fs_page_size - rem;
+
+ /* Drop the section if it is at page end and its size is <= pgend threshold */
+ if(!rem && (*sect)->sect_info.size <= H5F_PGEND_META_THRES(udata->f) && (*flags & H5FS_ADD_RETURNED_SPACE)) {
+ if(H5MF_sect_free((H5FS_section_info_t *)(*sect)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
+ *sect = NULL;
+ *flags &= (unsigned)~H5FS_ADD_RETURNED_SPACE;
+ *flags |= H5FS_PAGE_END_NO_ADD;
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section is dropped\n", FUNC);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+ /* Adjust the section if it is not at page end but its size + pgend threshold is at page end */
+ else
+ if(prem <= H5F_PGEND_META_THRES(udata->f)) {
+ (*sect)->sect_info.size += prem;
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section is adjusted {%a, %Hu}\n", FUNC, (*sect)->sect_info.addr, (*sect)->sect_info.size);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_small_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_small_can_shrink
+ *
+ * Purpose: Can this section shrink the container?
+ *
+ * Note: A small section is allowed to shrink only at closing.
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_small_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
+{
+ const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ haddr_t eoa; /* End of address space in the file */
+ haddr_t end; /* End of section to extend */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Retrieve the end of the file's address space */
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(udata->f->shared->lf, udata->alloc_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* Compute address of end of section to check */
+ end = sect->sect_info.addr + sect->sect_info.size;
+
+ /* Check if the section is exactly at the end of the allocated space in the file */
+ if(H5F_addr_eq(end, eoa) && sect->sect_info.size == udata->f->shared->fs_page_size) {
+ udata->shrink = H5MF_SHRINK_EOA;
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Indicate shrinking can occur */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_small_can_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_small_shrink
+ *
+ * Purpose: Shrink container with section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_small_shrink(H5FS_section_info_t **_sect, void *_udata)
+{
+ H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert((*sect)->sect_info.type == H5MF_FSPACE_SECT_SMALL);
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->shrink == H5MF_SHRINK_EOA);
+ HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
+
+ /* Release section's space at EOA */
+ if(H5F_free(udata->f, udata->dxpl_id, udata->alloc_type, (*sect)->sect_info.addr, (*sect)->sect_info.size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
+
+ /* Free section */
+ if(H5MF_sect_free((H5FS_section_info_t *)*sect) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+
+ /* Mark section as freed, for free space manager */
+ *sect = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_small_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_small_can_merge
+ *
+ * Purpose: Can two sections of this type merge?
+ *
+ * Note: Second section must be "after" first section
+ * The "merged" section cannot cross page boundary.
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_small_can_merge(const H5FS_section_info_t *_sect1,
+ const H5FS_section_info_t *_sect2, void *_udata)
+{
+ const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1; /* File free section */
+ const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert(sect2);
+ HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
+ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
+
+ /* Check if second section adjoins first section */
+ ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
+ if(ret_value > 0)
+ /* If they are on different pages, couldn't merge */
+ if((sect1->sect_info.addr / udata->f->shared->fs_page_size) != (((sect2->sect_info.addr + sect2->sect_info.size - 1) / udata->f->shared->fs_page_size)))
+ ret_value = FALSE;
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_small_can_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_small_merge
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node.
+ * If the size of the "merged" section is equal to file space page size,
+ * free the section.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_small_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
+ void *_udata)
+{
+ H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1; /* File free section */
+ H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_SMALL);
+ HDassert(sect2);
+ HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_SMALL);
+ HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
+
+ /* Add second section's size to first section */
+ (*sect1)->sect_info.size += sect2->sect_info.size;
+
+ if((*sect1)->sect_info.size == udata->f->shared->fs_page_size) {
+ if(H5MF_xfree(udata->f, udata->alloc_type, udata->dxpl_id, (*sect1)->sect_info.addr, (*sect1)->sect_info.size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section")
+
+ /* Need to free possible metadata page in the PB cache */
+ /* This is in response to the data corruption bug from fheap.c with page buffering + page strategy */
+ /* Note: Large metadata page bypasses the PB cache */
+ /* Note: Update of raw data page (large or small sized) is handled by the PB cache */
+ if(udata->f->shared->page_buf != NULL && udata->alloc_type != H5FD_MEM_DRAW)
+ if(H5PB_remove_entry(udata->f, (*sect1)->sect_info.addr) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free merged section")
+
+ if(H5MF_sect_free((H5FS_section_info_t *)(*sect1)) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
+ *sect1 = NULL;
+ } /* end if */
+
+ /* Get rid of second section */
+ if(H5MF_sect_free((H5FS_section_info_t *)sect2) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_small_merge() */
+
+/*
+ * "Large" section callbacks
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_large_can_merge (same as H5MF_sect_simple_can_merge)
+ *
+ * Purpose: Can two sections of this type merge?
+ *
+ * Note: Second section must be "after" first section
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_large_can_merge(const H5FS_section_info_t *_sect1,
+ const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata)
+{
+ const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1; /* File free section */
+ const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2; /* File free section */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert(sect2);
+ HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */
+ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr));
+
+ ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr);
+
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_large_can_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_large_merge (same as H5MF_sect_simple_merge)
+ *
+ * Purpose: Merge two sections of this type
+ *
+ * Note: Second section always merges into first node
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_large_merge(H5FS_section_info_t **_sect1, H5FS_section_info_t *_sect2,
+ void H5_ATTR_UNUSED *_udata)
+{
+ H5MF_free_section_t **sect1 = (H5MF_free_section_t **)_sect1; /* File free section */
+ H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2; /* File free section */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect1);
+ HDassert((*sect1)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
+ HDassert(sect2);
+ HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_LARGE);
+ HDassert(H5F_addr_eq((*sect1)->sect_info.addr + (*sect1)->sect_info.size, sect2->sect_info.addr));
+
+ /* Add second section's size to first section */
+ (*sect1)->sect_info.size += sect2->sect_info.size;
+
+ /* Get rid of second section */
+ if(H5MF_sect_free((H5FS_section_info_t *)sect2) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_large_merge() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_large_can_shrink
+ *
+ * Purpose: Can this section shrink the container?
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5MF_sect_large_can_shrink(const H5FS_section_info_t *_sect, void *_udata)
+{
+ const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ haddr_t eoa; /* End of address space in the file */
+ haddr_t end; /* End of section to extend */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert(sect->sect_info.type == H5MF_FSPACE_SECT_LARGE);
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Retrieve the end of the file's address space */
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(udata->f->shared->lf, udata->alloc_type)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* Compute address of end of section to check */
+ end = sect->sect_info.addr + sect->sect_info.size;
+
+ /* Check if the section is exactly at the end of the allocated space in the file */
+ if(H5F_addr_eq(end, eoa) && sect->sect_info.size >= udata->f->shared->fs_page_size) {
+ /* Set the shrinking type */
+ udata->shrink = H5MF_SHRINK_EOA;
+#ifdef H5MF_ALLOC_DEBUG_MORE
+HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa);
+#endif /* H5MF_ALLOC_DEBUG_MORE */
+
+ /* Indicate shrinking can occur */
+ HGOTO_DONE(TRUE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_large_can_shrink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MF_sect_large_shrink
+ *
+ * Purpose: Shrink a large-sized section
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; Dec 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5MF_sect_large_shrink(H5FS_section_info_t **_sect, void *_udata)
+{
+ H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* File free section */
+ H5MF_sect_ud_t *udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */
+ hsize_t frag_size = 0; /* Fragment size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(sect);
+ HDassert((*sect)->sect_info.type == H5MF_FSPACE_SECT_LARGE);
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->shrink == H5MF_SHRINK_EOA);
+ HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR);
+ HDassert(H5F_PAGED_AGGR(udata->f));
+
+ /* Calculate possible mis-aligned fragment */
+ H5MF_EOA_MISALIGN(udata->f, (*sect)->sect_info.addr, udata->f->shared->fs_page_size, frag_size);
+
+ /* Free full pages from EOA */
+ /* Retain partial page in the free-space manager so as to keep EOA at page boundary */
+ if(H5F_free(udata->f, udata->dxpl_id, udata->alloc_type, (*sect)->sect_info.addr+frag_size, (*sect)->sect_info.size-frag_size) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed")
+
+ if(frag_size) /* Adjust section size for the partial page */
+ (*sect)->sect_info.size = frag_size;
+ else {
+ /* Free section */
+ if(H5MF_sect_free((H5FS_section_info_t *)*sect) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node")
+
+ /* Mark section as freed, for free space manager */
+ *sect = NULL;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MF_sect_large_shrink() */
+
diff --git a/src/H5MM.c b/src/H5MM.c
new file mode 100644
index 0000000..ee3b28f
--- /dev/null
+++ b/src/H5MM.c
@@ -0,0 +1,572 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MM.c
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Memory management functions
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+#define H5MM_SIG_SIZE 4
+#define H5MM_HEAD_GUARD_SIZE 8
+#define H5MM_TAIL_GUARD_SIZE 8
+#define H5MM_BLOCK_FROM_BUF(mem) ((H5MM_block_t *)((unsigned char *)mem - (offsetof(H5MM_block_t, b) + H5MM_HEAD_GUARD_SIZE)))
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+/* Memory allocation "block", wrapped around each allocation */
+struct H5MM_block_t; /* Forward declaration for typedef */
+typedef struct H5MM_block_t {
+ unsigned char sig[H5MM_SIG_SIZE]; /* Signature for the block, to indicate it was allocated with H5MM* interface */
+ struct H5MM_block_t *next; /* Pointer to next block in the list of allocated blocks */
+ struct H5MM_block_t *prev; /* Pointer to previous block in the list of allocated blocks */
+ union {
+ struct {
+ size_t size; /* Size of allocated block */
+ hbool_t in_use; /* Whether the block is in use or is free */
+ } info;
+ double _align; /* Align following buffer (b) to double boundary (unused) */
+ } u;
+ unsigned char b[]; /* Buffer for caller (includes header and footer) */
+} H5MM_block_t;
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+static hbool_t H5MM__is_our_block(void *mem);
+static void H5MM__sanity_check_block(const H5MM_block_t *block);
+static void H5MM__sanity_check(void *mem);
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+/* Constant strings for block signature, head & tail guards */
+static const char H5MM_block_signature_s[H5MM_SIG_SIZE] = {'H', '5', 'M', 'M'};
+static const char H5MM_block_head_guard_s[H5MM_HEAD_GUARD_SIZE] = {'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'};
+static const char H5MM_block_tail_guard_s[H5MM_TAIL_GUARD_SIZE] = {'B', 'E', 'E', 'F', 'D', 'E', 'A', 'D'};
+
+/* Flag to indicate the the interface has been initialized */
+static hbool_t H5MM_init_s = FALSE;
+
+/* Head of the list of allocated blocks */
+static H5MM_block_t H5MM_block_head_s;
+
+/* Statistics about block allocations */
+static unsigned long long H5MM_total_alloc_bytes_s = 0;
+static unsigned long long H5MM_curr_alloc_bytes_s = 0;
+static unsigned long long H5MM_peak_alloc_bytes_s = 0;
+static size_t H5MM_max_block_size_s = 0;
+static size_t H5MM_total_alloc_blocks_count_s = 0;
+static size_t H5MM_curr_alloc_blocks_count_s = 0;
+static size_t H5MM_peak_alloc_blocks_count_s = 0;
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM__is_our_block
+ *
+ * Purpose: Try to determine if a memory buffer has been allocated through
+ * the H5MM* interface, instead of the system's malloc() routines.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Dec 30 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5MM__is_our_block(void *mem)
+{
+ H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem);
+
+ return(0 == HDmemcmp(block->sig, H5MM_block_signature_s, H5MM_SIG_SIZE));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM__sanity_check_block
+ *
+ * Purpose: Check a block wrapper around a buffer to validate it.
+ *
+ * Return: N/A (void)
+ *
+ * Programmer: Quincey Koziol
+ * Dec 30 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE static void
+H5MM__sanity_check_block(const H5MM_block_t *block)
+{
+ HDassert(block->u.info.size > 0);
+ HDassert(block->u.info.in_use);
+ /* Check for head & tail guards, if not head of linked list */
+ if(block->u.info.size != SIZET_MAX) {
+ HDassert(0 == HDmemcmp(block->b, H5MM_block_head_guard_s, H5MM_HEAD_GUARD_SIZE));
+ HDassert(0 == HDmemcmp(block->b + H5MM_HEAD_GUARD_SIZE + block->u.info.size, H5MM_block_tail_guard_s, H5MM_TAIL_GUARD_SIZE));
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM__sanity_check
+ *
+ * Purpose: Check a buffer to validate it (just calls
+ * H5MM__sanity_check_block after finding block for buffer)
+ *
+ * Return: N/A (void)
+ *
+ * Programmer: Quincey Koziol
+ * Dec 30 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE static void
+H5MM__sanity_check(void *mem)
+{
+ H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem);
+
+ H5MM__sanity_check_block(block);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_sanity_check_all
+ *
+ * Purpose: Sanity check all current memory allocations.
+ *
+ * Return: N/A (void)
+ *
+ * Programmer: Quincey Koziol
+ * Jan 5 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE void
+H5MM_sanity_check_all(void)
+{
+ H5MM_block_t *curr = NULL;
+
+ curr = H5MM_block_head_s.next;
+ while(curr != &H5MM_block_head_s) {
+ H5MM__sanity_check_block(curr);
+ curr = curr->next;
+ } /* end while */
+} /* end H5MM_sanity_check_all() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_final_sanity_check
+ *
+ * Purpose: Final sanity checks on memory allocation.
+ *
+ * Return: N/A (void)
+ *
+ * Programmer: Quincey Koziol
+ * Jan 1 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE void
+H5MM_final_sanity_check(void)
+{
+ HDassert(0 == H5MM_curr_alloc_bytes_s);
+ HDassert(0 == H5MM_curr_alloc_blocks_count_s);
+ HDassert(H5MM_block_head_s.next == &H5MM_block_head_s);
+ HDassert(H5MM_block_head_s.prev == &H5MM_block_head_s);
+#ifdef H5MM_PRINT_MEMORY_STATS
+ HDfprintf(stderr, "%s: H5MM_total_alloc_bytes_s = %llu\n", __func__, H5MM_total_alloc_bytes_s);
+ HDfprintf(stderr, "%s: H5MM_peak_alloc_bytes_s = %llu\n", __func__, H5MM_peak_alloc_bytes_s);
+ HDfprintf(stderr, "%s: H5MM_max_block_size_s = %zu\n", __func__, H5MM_max_block_size_s);
+ HDfprintf(stderr, "%s: H5MM_total_alloc_blocks_count_s = %zu\n", __func__, H5MM_total_alloc_blocks_count_s);
+ HDfprintf(stderr, "%s: H5MM_peak_alloc_blocks_count_s = %zu\n", __func__, H5MM_peak_alloc_blocks_count_s);
+#endif /* H5MM_PRINT_MEMORY_STATS */
+}
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_malloc
+ *
+ * Purpose: Similar to the C89 version of malloc().
+ *
+ * On size of 0, we return a NULL pointer instead of the
+ * standard-allowed 'special' pointer since that's more
+ * difficult to check as a return value. This is still
+ * considered an error condition since allocations of zero
+ * bytes usually indicate problems.
+ *
+ * Return: Success: Pointer to new memory
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Nov 8 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MM_malloc(size_t size)
+{
+ void *ret_value = NULL;
+
+ HDassert(size);
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ /* Initialize block list head singleton */
+ if(!H5MM_init_s) {
+ HDmemcpy(H5MM_block_head_s.sig, H5MM_block_signature_s, H5MM_SIG_SIZE);
+ H5MM_block_head_s.next = &H5MM_block_head_s;
+ H5MM_block_head_s.prev = &H5MM_block_head_s;
+ H5MM_block_head_s.u.info.size = SIZET_MAX;
+ H5MM_block_head_s.u.info.in_use = TRUE;
+
+ H5MM_init_s = TRUE;
+ } /* end if */
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+ if(size) {
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ H5MM_block_t *block;
+ size_t alloc_size = sizeof(H5MM_block_t) + size + H5MM_HEAD_GUARD_SIZE + H5MM_TAIL_GUARD_SIZE;
+
+ if(NULL != (block = (H5MM_block_t *)HDmalloc(alloc_size))) {
+ /* Set up block */
+ HDmemcpy(block->sig, H5MM_block_signature_s, H5MM_SIG_SIZE);
+ block->next = H5MM_block_head_s.next;
+ H5MM_block_head_s.next = block;
+ block->next->prev = block;
+ block->prev = &H5MM_block_head_s;
+ block->u.info.size = size;
+ block->u.info.in_use = TRUE;
+ HDmemcpy(block->b, H5MM_block_head_guard_s, H5MM_HEAD_GUARD_SIZE);
+ HDmemcpy(block->b + H5MM_HEAD_GUARD_SIZE + size, H5MM_block_tail_guard_s, H5MM_TAIL_GUARD_SIZE);
+
+ /* Update statistics */
+ H5MM_total_alloc_bytes_s += size;
+ H5MM_curr_alloc_bytes_s += size;
+ if(H5MM_curr_alloc_bytes_s > H5MM_peak_alloc_bytes_s)
+ H5MM_peak_alloc_bytes_s = H5MM_curr_alloc_bytes_s;
+ if(size > H5MM_max_block_size_s)
+ H5MM_max_block_size_s = size;
+ H5MM_total_alloc_blocks_count_s++;
+ H5MM_curr_alloc_blocks_count_s++;
+ if(H5MM_curr_alloc_blocks_count_s > H5MM_peak_alloc_blocks_count_s)
+ H5MM_peak_alloc_blocks_count_s = H5MM_curr_alloc_blocks_count_s;
+
+ /* Set buffer to return */
+ ret_value = block->b + H5MM_HEAD_GUARD_SIZE;
+ } /* end if */
+ else
+ ret_value = NULL;
+#else /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ ret_value = HDmalloc(size);
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ } /* end if */
+ else
+ ret_value = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_calloc
+ *
+ * Purpose: Similar to the C89 version of calloc(), except this
+ * routine just takes a 'size' parameter.
+ *
+ * On size of 0, we return a NULL pointer instead of the
+ * standard-allowed 'special' pointer since that's more
+ * difficult to check as a return value. This is still
+ * considered an error condition since allocations of zero
+ * bytes usually indicate problems.
+ *
+ *
+ * Return: Success: Pointer to new memory
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Nov 8 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MM_calloc(size_t size)
+{
+ void *ret_value = NULL;
+
+ HDassert(size);
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(size) {
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ if(NULL != (ret_value = H5MM_malloc(size)))
+ HDmemset(ret_value, 0, size);
+#else /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ ret_value = HDcalloc((size_t)1, size);
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ } /* end if */
+ else
+ ret_value = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_calloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_realloc
+ *
+ * Purpose: Similar semantics as C89's realloc(). Specifically, the
+ * following calls are equivalent:
+ *
+ * H5MM_realloc(NULL, size) <==> H5MM_malloc(size)
+ * H5MM_realloc(ptr, 0) <==> H5MM_xfree(ptr)
+ * H5MM_realloc(NULL, 0) <==> NULL
+ *
+ * Note that the (NULL, 0) combination is undefined behavior
+ * in the C standard.
+ *
+ * Return: Success: Ptr to new memory if size > 0
+ * NULL if size is zero
+ * Failure: NULL (input buffer is unchanged on failure)
+ *
+ * Programmer: Robb Matzke
+ * Jul 10 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MM_realloc(void *mem, size_t size)
+{
+ void *ret_value = NULL;
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mem || size);
+
+ if(NULL == mem && 0 == size)
+ /* Not defined in the standard, return NULL */
+ ret_value = NULL;
+ else {
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ if(size > 0) {
+ if(mem) {
+ if(H5MM__is_our_block(mem)) {
+ H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem);
+ size_t old_size = block->u.info.size;
+
+ H5MM__sanity_check(mem);
+
+ ret_value = H5MM_malloc(size);
+ HDmemcpy(ret_value, mem, MIN(size, old_size));
+ H5MM_xfree(mem);
+ } /* end if */
+ else
+ ret_value = HDrealloc(mem, size);
+ }
+ else
+ ret_value = H5MM_malloc(size);
+ }
+ else
+ ret_value = H5MM_xfree(mem);
+#else /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ ret_value = HDrealloc(mem, size);
+
+ /* Some platforms do not return NULL if size is zero. */
+ if(0 == size)
+ ret_value = NULL;
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_realloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_xstrdup
+ *
+ * Purpose: Duplicates a string, including memory allocation.
+ * NULL is an acceptable value for the input string.
+ *
+ * Return: Success: Pointer to a new string (NULL if s is NULL).
+ * Failure: abort()
+ *
+ * Programmer: Robb Matzke
+ * Jul 10 1997
+ *-------------------------------------------------------------------------
+ */
+char *
+H5MM_xstrdup(const char *s)
+{
+ char *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(s) {
+ if(NULL == (ret_value = (char *)H5MM_malloc(HDstrlen(s) + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDstrcpy(ret_value, s);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_xstrdup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_strdup
+ *
+ * Purpose: Duplicates a string, including memory allocation.
+ * NULL is NOT an acceptable value for the input string.
+ *
+ * If the string to be duplicated is the NULL pointer, then
+ * an error will be raised.
+ *
+ * Return: Success: Pointer to a new string
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Jul 10 1997
+ *-------------------------------------------------------------------------
+ */
+char *
+H5MM_strdup(const char *s)
+{
+ char *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(!s)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "null string")
+ if(NULL == (ret_value = (char *)H5MM_malloc(HDstrlen(s) + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDstrcpy(ret_value, s);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_strdup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MM_xfree
+ *
+ * Purpose: Just like free(3) except null pointers are allowed as
+ * arguments, and the return value (always NULL) can be
+ * assigned to the pointer whose memory was just freed:
+ *
+ * thing = H5MM_xfree (thing);
+ *
+ * Return: Success: NULL
+ * Failure: never fails
+ *
+ * Programmer: Robb Matzke
+ * Jul 10 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MM_xfree(void *mem)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(mem) {
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ if(H5MM__is_our_block(mem)) {
+ H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem);
+
+ /* Run sanity checks on this block and its neighbors */
+ H5MM__sanity_check(mem);
+ H5MM__sanity_check_block(block->next);
+ H5MM__sanity_check_block(block->prev);
+
+ /* Update statistics */
+ H5MM_curr_alloc_bytes_s -= block->u.info.size;
+ H5MM_curr_alloc_blocks_count_s--;
+
+ /* Reset block info */
+ HDmemset(block->sig, 0, H5MM_SIG_SIZE);
+ block->next->prev = block->prev;
+ block->prev->next = block->next;
+ block->next = NULL;
+ block->prev = NULL;
+ block->u.info.in_use = FALSE;
+
+ /* Free the block (finally!) */
+ HDfree(block);
+ }
+ else
+ HDfree(mem);
+#else /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ HDfree(mem);
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5MM_xfree() */
+
diff --git a/src/H5MMprivate.h b/src/H5MMprivate.h
new file mode 100644
index 0000000..0524601
--- /dev/null
+++ b/src/H5MMprivate.h
@@ -0,0 +1,54 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MMprivate.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Private header for memory management.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5MMprivate_H
+#define _H5MMprivate_H
+
+#include "H5MMpublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h"
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+/*#define H5MM_PRINT_MEMORY_STATS */
+#define H5MM_free(Z) H5MM_xfree(Z)
+#else /* H5_MEMORY_ALLOC_SANITY_CHECK */
+#define H5MM_free(Z) HDfree(Z)
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+/*
+ * Library prototypes...
+ */
+H5_DLL void *H5MM_malloc(size_t size);
+H5_DLL void *H5MM_calloc(size_t size);
+H5_DLL void *H5MM_realloc(void *mem, size_t size);
+H5_DLL char *H5MM_xstrdup(const char *s);
+H5_DLL char *H5MM_strdup(const char *s);
+H5_DLL void *H5MM_xfree(void *mem);
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+H5_DLL void H5MM_sanity_check_all(void);
+H5_DLL void H5MM_final_sanity_check(void);
+#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */
+
+#endif /* _H5MMprivate_H */
+
diff --git a/src/H5MMpublic.h b/src/H5MMpublic.h
new file mode 100644
index 0000000..4e54c33
--- /dev/null
+++ b/src/H5MMpublic.h
@@ -0,0 +1,45 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MMproto.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public declarations for the H5MM (memory management)
+ * package.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5MMpublic_H
+#define _H5MMpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/* These typedefs are currently used for VL datatype allocation/freeing */
+typedef void *(*H5MM_allocate_t)(size_t size, void *alloc_info);
+typedef void (*H5MM_free_t)(void *mem, void *free_info);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5MMpublic_H */
+
diff --git a/src/H5MP.c b/src/H5MP.c
new file mode 100644
index 0000000..8c9b411
--- /dev/null
+++ b/src/H5MP.c
@@ -0,0 +1,474 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MP.c
+ * May 2 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Implements memory pools. (Similar to Apache's APR
+ * memory pools)
+ *
+ * Please see the documentation in:
+ * doc/html/TechNotes/MemoryPools.html for a full description
+ * of how they work, etc.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5MPmodule.h" /* This source code file is part of the H5MP module */
+
+/* Private headers */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5MPpkg.h" /* Memory Pools */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Minimum sized block */
+#define H5MP_MIN_BLOCK (H5MP_BLOCK_ALIGN(sizeof(H5MP_page_blk_t)) + H5MP_BLOCK_ALIGNMENT)
+
+/* First block in page */
+#define H5MP_PAGE_FIRST_BLOCK(p) \
+ (H5MP_page_blk_t *)((unsigned char *)(p) + H5MP_BLOCK_ALIGN(sizeof(H5MP_page_t)))
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/********************************/
+/* Package Variable Definitions */
+/********************************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/********************/
+/* Static Variables */
+/********************/
+
+/* Declare a free list to manage the H5MP_pool_t struct */
+H5FL_DEFINE(H5MP_pool_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_create
+ *
+ * Purpose: Create a new memory pool
+ *
+ * Return: Pointer to the memory pool "header" on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5MP_pool_t *
+H5MP_create(size_t page_size, unsigned flags)
+{
+ H5MP_pool_t *mp = NULL; /* New memory pool header */
+ H5MP_pool_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate space for the pool header */
+ if(NULL == (mp = H5FL_MALLOC(H5MP_pool_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for memory pool header")
+
+ /* Assign information */
+ mp->page_size = H5MP_BLOCK_ALIGN(page_size);
+ mp->flags = flags;
+
+ /* Initialize information */
+ mp->free_size = 0;
+ mp->first = NULL;
+ mp->max_size = mp->page_size - H5MP_BLOCK_ALIGN(sizeof(H5MP_page_t));
+
+ /* Create factory for pool pages */
+ if(NULL == (mp->page_fac = H5FL_fac_init(page_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't create page factory")
+
+ /* Set return value */
+ ret_value = mp;
+
+done:
+ if(NULL == ret_value && mp)
+ if(H5MP_close(mp) < 0)
+ HDONE_ERROR(H5E_RESOURCE, H5E_CANTFREE, NULL, "unable to free memory pool header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MP_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_new_page
+ *
+ * Purpose: Allocate new page for a memory pool
+ *
+ * Return: Pointer to the page allocated on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 4 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5MP_page_t *
+H5MP_new_page(H5MP_pool_t *mp, size_t page_size)
+{
+ H5MP_page_t *new_page; /* New page created */
+ H5MP_page_blk_t *first_blk; /* Pointer to first block in page */
+ H5MP_page_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(mp);
+ HDassert(page_size >= mp->page_size);
+
+ /* Allocate page */
+ if(page_size > mp->page_size) {
+ if(NULL == (new_page = (H5MP_page_t *)H5MM_malloc(page_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for page")
+ new_page->free_size = page_size - H5MP_BLOCK_ALIGN(sizeof(H5MP_page_t));
+ new_page->fac_alloc = FALSE;
+ } /* end if */
+ else {
+ if(NULL == (new_page = (H5MP_page_t *)H5FL_FAC_MALLOC(mp->page_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for page")
+ new_page->free_size = mp->max_size;
+ new_page->fac_alloc = TRUE;
+ } /* end else */
+#ifdef QAK
+HDfprintf(stderr,"%s: Allocating new page = %p\n", FUNC, new_page);
+#endif /* QAK */
+
+ /* Initialize page information */
+ first_blk = H5MP_PAGE_FIRST_BLOCK(new_page);
+ first_blk->size = new_page->free_size;
+ first_blk->page = new_page;
+ first_blk->is_free = TRUE;
+ first_blk->prev = NULL;
+ first_blk->next = NULL;
+
+ /* Insert into page list */
+ new_page->prev = NULL;
+ new_page->next = mp->first;
+ if(mp->first)
+ mp->first->prev = new_page;
+ mp->first = new_page;
+
+ /* Account for new free space */
+ new_page->free_blk = first_blk;
+ mp->free_size += new_page->free_size;
+
+ /* Assign return value */
+ ret_value = new_page;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MP_new_page() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_malloc
+ *
+ * Purpose: Allocate space in a memory pool
+ *
+ * Return: Pointer to the space allocated on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MP_malloc (H5MP_pool_t *mp, size_t request)
+{
+ H5MP_page_t *alloc_page = NULL; /* Page to allocate space from */
+ H5MP_page_blk_t *alloc_free; /* Pointer to free space in page */
+ size_t needed; /* Size requested, plus block header and alignment */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(mp);
+ HDassert(request > 0);
+
+ /* Compute actual size needed */
+ needed = H5MP_BLOCK_ALIGN(request) + H5MP_BLOCK_ALIGN(sizeof(H5MP_page_blk_t));
+#ifdef QAK
+HDfprintf(stderr,"%s: sizeof(H5MP_page_blk_t) = %Zu\n", FUNC, sizeof(H5MP_page_blk_t));
+HDfprintf(stderr,"%s: request = %Zu, needed = %Zu\n", FUNC, request, needed);
+#endif /* QAK */
+
+ /* See if the request can be handled by existing free space */
+ if(needed <= mp->free_size) {
+ size_t pool_free_avail; /* Amount of free space possibly available in pool */
+
+ /* Locate page with enough free space */
+ alloc_page = mp->first;
+ pool_free_avail = mp->free_size;
+ while(alloc_page && pool_free_avail >= needed) {
+ /* If we found a page with enough free space, search for large
+ * enough free block on that page */
+ if(alloc_page->free_size >= needed) {
+ size_t page_free_avail; /* Amount of free space possibly available */
+
+ /* Locate large enough block */
+ alloc_free = alloc_page->free_blk;
+ page_free_avail = alloc_page->free_size;
+ while(alloc_free && page_free_avail >= needed) {
+ if(alloc_free->is_free) {
+ /* If we found a large enough block, leave now */
+ if(alloc_free->size >= needed)
+ goto found; /* Needed to escape double "while" loop */
+
+ /* Decrement amount of potential space left */
+ page_free_avail -= alloc_free->size;
+ } /* end if */
+
+ /* Go to next block */
+ alloc_free = alloc_free->next;
+ } /* end while */
+ } /* end if */
+
+ /* Decrement amount of potential space left */
+ pool_free_avail -= alloc_page->free_size;
+
+ /* Go to next page */
+ alloc_page = alloc_page->next;
+ } /* end while */
+ } /* end if */
+
+ {
+ size_t page_size; /* Size of page needed */
+
+ /* Check if the request is too large for a standard page */
+ page_size = (needed > mp->max_size) ?
+ (needed + H5MP_BLOCK_ALIGN(sizeof(H5MP_page_t))) : mp->page_size;
+
+ /* Allocate new page */
+ if(NULL == (alloc_page = H5MP_new_page(mp, page_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for page")
+
+ /* Set the block to allocate from */
+ alloc_free = alloc_page->free_blk;
+ } /* end block */
+
+ /* Allocate space in page */
+found:
+
+ /* Sanity check */
+ HDassert(alloc_page);
+ HDassert(alloc_free);
+
+ /* Check if we can subdivide the free space */
+ if(alloc_free->size > (needed + H5MP_MIN_BLOCK)) {
+ H5MP_page_blk_t *new_free; /* New free block created */
+
+ /* Carve out new free block after block to allocate */
+ new_free = (H5MP_page_blk_t *)(((unsigned char *)alloc_free) + needed);
+
+ /* Link into existing lists */
+ new_free->next = alloc_free->next;
+ if(alloc_free->next)
+ alloc_free->next->prev = new_free;
+ new_free->prev = alloc_free;
+ alloc_free->next = new_free;
+
+ /* Set blocks' information */
+ new_free->size = alloc_free->size - needed;
+ new_free->is_free = TRUE;
+ new_free->page = alloc_free->page;
+ alloc_free->size = needed;
+ alloc_free->is_free = FALSE;
+ } /* end if */
+ else {
+ /* Use whole free space block for new block */
+ alloc_free->is_free = FALSE;
+ } /* end else */
+
+ /* Update page & pool's free size information */
+ alloc_page->free_size -= alloc_free->size;
+ if(alloc_page->free_blk == alloc_free)
+ alloc_page->free_blk = alloc_free->next;
+ mp->free_size -= alloc_free->size;
+
+ /* Set new space pointer for the return value */
+ ret_value = ((unsigned char *)alloc_free) + H5MP_BLOCK_ALIGN(sizeof(H5MP_page_blk_t));
+#ifdef QAK
+HDfprintf(stderr,"%s: Allocating space from page, ret_value = %p\n", FUNC, ret_value);
+#endif /* QAK */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MP_malloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_free
+ *
+ * Purpose: Release space in a memory pool
+ *
+ * Return: NULL on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 3 2005
+ *
+ * Note: Should we release pages that have no used blocks?
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5MP_free(H5MP_pool_t *mp, void *spc)
+{
+ H5MP_page_blk_t *spc_blk; /* Block for space to free */
+ H5MP_page_t *spc_page; /* Page containing block to free */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(mp);
+ HDassert(spc);
+
+ /* Get block header for space to free */
+ spc_blk = (H5MP_page_blk_t *)(((unsigned char *)spc) - H5MP_BLOCK_ALIGN(sizeof(H5MP_page_blk_t)));
+
+ /* Mark block as free */
+ HDassert(spc_blk->is_free == FALSE);
+ spc_blk->is_free = TRUE;
+
+ /* Add it's space to the amount of free space in the page & pool */
+ spc_page = spc_blk->page;
+#ifdef QAK
+HDfprintf(stderr,"%s: Freeing from page = %p\n", "H5MP_free", spc_page);
+#endif /* QAK */
+ spc_page->free_size += spc_blk->size;
+ mp->free_size += spc_blk->size;
+
+ /* Move page with newly freed space to front of list of pages in pool */
+ if(spc_page != mp->first) {
+ /* Remove page from list */
+ spc_page->prev->next = spc_page->next;
+ if(spc_page->next)
+ spc_page->next->prev = spc_page->prev;
+
+ /* Insert page at beginning of list */
+ spc_page->prev = NULL;
+ spc_page->next = mp->first;
+ mp->first->prev = spc_page;
+ mp->first = spc_page;
+ } /* end if */
+
+ /* Check if block can be merged with free space after it on page */
+ if(spc_blk->next != NULL) {
+ H5MP_page_blk_t *next_blk; /* Block following space to free */
+
+ next_blk = spc_blk->next;
+ HDassert(next_blk->prev == spc_blk);
+ if(next_blk->is_free) {
+ spc_blk->size += next_blk->size;
+ spc_blk->next = next_blk->next;
+ } /* end if */
+ } /* end if */
+
+ /* Check if block can be merged with free space before it on page */
+ if(spc_blk->prev != NULL) {
+ H5MP_page_blk_t *prev_blk; /* Block before space to free */
+
+ prev_blk = spc_blk->prev;
+ HDassert(prev_blk->next == spc_blk);
+ if(prev_blk->is_free) {
+ prev_blk->size += spc_blk->size;
+ prev_blk->next = spc_blk->next;
+ } /* end if */
+ } /* end if */
+
+ /* Check if the block freed becomes the first free block on the page */
+ if(spc_page->free_blk == NULL || spc_blk < spc_page->free_blk)
+ spc_page->free_blk = spc_blk;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MP_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_close
+ *
+ * Purpose: Release all memory for a pool and destroy pool
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * May 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MP_close(H5MP_pool_t *mp)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Release memory for pool pages */
+ if(mp->first != NULL) {
+ H5MP_page_t *page, *next_page; /* Pointer to pages in pool */
+
+ /* Iterate through pages, releasing them */
+ page = mp->first;
+ while(page) {
+ next_page = page->next;
+
+ /* Free the page appropriately */
+ if(page->fac_alloc)
+ page = (H5MP_page_t *)H5FL_FAC_FREE(mp->page_fac, page);
+ else
+ page = (H5MP_page_t *)H5MM_xfree(page);
+
+ page = next_page;
+ } /* end while */
+ } /* end if */
+
+ /* Release page factory */
+ if(mp->page_fac)
+ if(H5FL_fac_term(mp->page_fac) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't destroy page factory")
+
+done:
+ /* Free the memory pool itself */
+ mp = H5FL_FREE(H5MP_pool_t, mp);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MP_close() */
+
diff --git a/src/H5MPmodule.h b/src/H5MPmodule.h
new file mode 100644
index 0000000..27f7706
--- /dev/null
+++ b/src/H5MPmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5MP package. Including this header means that the source file
+ * is part of the H5MP package.
+ */
+#ifndef _H5MPmodule_H
+#define _H5MPmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5MP_MODULE
+#define H5_MY_PKG H5MP
+#define H5_MY_PKG_ERR H5E_RESOURCE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5MPmodule_H */
+
diff --git a/src/H5MPpkg.h b/src/H5MPpkg.h
new file mode 100644
index 0000000..29a25fa
--- /dev/null
+++ b/src/H5MPpkg.h
@@ -0,0 +1,104 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Monday, May 2, 2005
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5MP package. Source files outside the H5MP package should
+ * include H5MPprivate.h instead.
+ */
+#if !(defined H5MP_FRIEND || defined H5MP_MODULE)
+#error "Do not include this file outside the H5MP package!"
+#endif
+
+#ifndef _H5MPpkg_H
+#define _H5MPpkg_H
+
+/* Get package's private header */
+#include "H5MPprivate.h" /* Memory Pools */
+
+/* Other private headers needed by this file */
+#include "H5FLprivate.h" /* Free Lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+/* Alignment macros */
+/* (Ideas from Apache APR :-) */
+
+/* Default alignment necessary */
+#define H5MP_BLOCK_ALIGNMENT 8
+
+/* General alignment macro */
+/* (this only works for aligning to power of 2 boundary) */
+#define H5MP_ALIGN(x, a) \
+ (((x) + ((size_t)(a)) - 1) & ~(((size_t)(a)) - 1))
+
+/* Default alignment */
+#define H5MP_BLOCK_ALIGN(x) H5MP_ALIGN(x, H5MP_BLOCK_ALIGNMENT)
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Free block in pool */
+typedef struct H5MP_page_blk_t {
+ size_t size; /* Size of block (includes this H5MP_page_blk_t info) */
+ unsigned is_free:1; /* Flag to indicate the block is free */
+ struct H5MP_page_t *page; /* Pointer to page block is located in */
+ struct H5MP_page_blk_t *prev; /* Pointer to previous block in page */
+ struct H5MP_page_blk_t *next; /* Pointer to next block in page */
+} H5MP_page_blk_t;
+
+/* Memory pool page */
+typedef struct H5MP_page_t {
+ size_t free_size; /* Total amount of free space in page */
+ unsigned fac_alloc:1; /* Flag to indicate the page was allocated by the pool's factory */
+ H5MP_page_blk_t *free_blk; /* Pointer to first free block in page */
+ struct H5MP_page_t *next; /* Pointer to next page in pool */
+ struct H5MP_page_t *prev; /* Pointer to previous page in pool */
+} H5MP_page_t;
+
+/* Memory pool header */
+struct H5MP_pool_t {
+ H5FL_fac_head_t *page_fac; /* Free-list factory for pages */
+ size_t page_size; /* Page size for pool */
+ size_t free_size; /* Total amount of free space in pool */
+ size_t max_size; /* Maximum block that will fit in a standard page */
+ H5MP_page_t *first; /* Pointer to first page in pool */
+ unsigned flags; /* Bit flags for pool settings */
+};
+
+
+/*****************************************/
+/* Package Private Variable Declarations */
+/*****************************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+#ifdef H5MP_TESTING
+H5_DLL herr_t H5MP_get_pool_free_size (const H5MP_pool_t *mp, size_t *free_size);
+H5_DLL htri_t H5MP_pool_is_free_size_correct(const H5MP_pool_t *mp);
+H5_DLL herr_t H5MP_get_pool_first_page(const H5MP_pool_t *mp, H5MP_page_t **page);
+H5_DLL herr_t H5MP_get_page_free_size(const H5MP_page_t *mp, size_t *page);
+H5_DLL herr_t H5MP_get_page_next_page(const H5MP_page_t *page, H5MP_page_t **next_page);
+#endif /* H5MP_TESTING */
+
+#endif /* _H5MPpkg_H */
+
diff --git a/src/H5MPprivate.h b/src/H5MPprivate.h
new file mode 100644
index 0000000..009cb50
--- /dev/null
+++ b/src/H5MPprivate.h
@@ -0,0 +1,60 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5MPprivate.h
+ * May 2 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Private header for memory pool routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5MPprivate_H
+#define _H5MPprivate_H
+
+/* Include package's public header (not yet) */
+/* #include "H5MPpublic.h" */
+
+/* Private headers needed by this file */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Pool creation flags */
+/* Default settings */
+#define H5MP_FLG_DEFAULT 0
+#define H5MP_PAGE_SIZE_DEFAULT 4096 /* (bytes) */
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Memory pool header (defined in H5MPpkg.c) */
+typedef struct H5MP_pool_t H5MP_pool_t;
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+H5_DLL H5MP_pool_t *H5MP_create (size_t page_size, unsigned flags);
+H5_DLL void * H5MP_malloc (H5MP_pool_t *mp, size_t request);
+H5_DLL void * H5MP_free (H5MP_pool_t *mp, void *spc);
+H5_DLL herr_t H5MP_close (H5MP_pool_t *mp);
+
+#endif /* _H5MPprivate_H */
diff --git a/src/H5MPtest.c b/src/H5MPtest.c
new file mode 100644
index 0000000..b3f2e24
--- /dev/null
+++ b/src/H5MPtest.c
@@ -0,0 +1,235 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Tuesday, May 3, 2005
+ *
+ * Purpose: Memory pool testing functions.
+ */
+
+#include "H5MPmodule.h" /* This source code file is part of the H5MP module */
+#define H5MP_TESTING /*include H5MP testing funcs*/
+
+/* Private headers */
+#include "H5private.h" /* Generic Functions */
+#include "H5MPpkg.h" /* Memory Pools */
+#include "H5Eprivate.h" /* Error handling */
+
+/* Static Prototypes */
+
+/* Package variables */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_get_pool_free_size
+ *
+ * Purpose: Retrieve the total amount of free space in entire pool
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MP_get_pool_free_size(const H5MP_pool_t *mp, size_t *free_size)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(mp);
+ HDassert(free_size);
+
+ /* Get memory pool's free space */
+ *free_size = mp->free_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MP_get_pool_free_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_get_pool_first_page
+ *
+ * Purpose: Retrieve the first page in a memory pool
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MP_get_pool_first_page(const H5MP_pool_t *mp, H5MP_page_t **page)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(mp);
+ HDassert(page);
+
+ /* Get memory pool's first page */
+ *page = mp->first;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MP_get_pool_first_page() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_pool_is_free_size_correct
+ *
+ * Purpose: Check that the free space reported in each page corresponds
+ * to the free size in each page and that the free space in the
+ * free blocks for a page corresponds with the free space for
+ * the page.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5MP_pool_is_free_size_correct(const H5MP_pool_t *mp)
+{
+ H5MP_page_t *page; /* Pointer to current page */
+ size_t pool_free; /* Size of pages' free space */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(mp);
+
+ /* Iterate through pages, checking the free size & accumulating the
+ * free space for all the pages */
+ page = mp->first;
+ pool_free = 0;
+ while(page != NULL) {
+ H5MP_page_blk_t *blk; /* Pointer to current free block */
+ size_t page_free; /* Size of blocks on free list */
+
+ /* Iterate through the blocks in page, accumulating free space */
+ blk = (H5MP_page_blk_t *)((unsigned char *)page + H5MP_BLOCK_ALIGN(sizeof(H5MP_page_t)));
+ page_free = 0;
+ while(blk != NULL) {
+ if(blk->is_free)
+ page_free += blk->size;
+ blk = blk->next;
+ } /* end while */
+
+ /* Check that the free space from the blocks on the free list
+ * corresponds to space in page */
+#ifdef QAK
+HDfprintf(stderr,"%s: page_free = %Zu, page->free_size = %Zu\n", "H5MP_pool_is_free_size_correct", page_free, page->free_size);
+#endif /* QAK */
+ if(page_free != page->free_size)
+ HGOTO_DONE (FALSE)
+
+ /* Increment the amount of free space in pool */
+ pool_free += page->free_size;
+
+ /* Advance to next page */
+ page = page->next;
+ } /* end while */
+
+ /* Check that the free space from the pages
+ * corresponds to free space in pool */
+#ifdef QAK
+HDfprintf(stderr,"%s: pool_free = %Zu, mp->free_size = %Zu\n", "H5MP_pool_is_free_size_correct", pool_free, mp->free_size);
+#endif /* QAK */
+ if(pool_free != mp->free_size)
+ HGOTO_DONE (FALSE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5MP_pool_is_free_size_correct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_get_page_free_size
+ *
+ * Purpose: Retrieve the amount of free space in given page
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MP_get_page_free_size(const H5MP_page_t *page, size_t *free_size)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(page);
+ HDassert(free_size);
+
+ /* Get memory page's free space */
+ *free_size = page->free_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MP_get_page_free_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5MP_get_page_next_page
+ *
+ * Purpose: Retrieve the next page in the pool
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5MP_get_page_next_page(const H5MP_page_t *page, H5MP_page_t **next_page)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments. */
+ HDassert(page);
+ HDassert(next_page);
+
+ /* Get next memory page */
+ *next_page = page->next;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5MP_get_page_next_page() */
+
diff --git a/src/H5O.c b/src/H5O.c
new file mode 100644
index 0000000..152e6cc
--- /dev/null
+++ b/src/H5O.c
@@ -0,0 +1,3725 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5O.c
+ * Aug 5 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Object header routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MFprivate.h" /* File memory management */
+#ifdef H5O_ENABLE_BOGUS
+#include "H5MMprivate.h" /* Memory management */
+#endif /* H5O_ENABLE_BOGUS */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for recursive traversal over objects from a group */
+typedef struct {
+ hid_t obj_id; /* The ID for the starting group */
+ H5G_loc_t *start_loc; /* Location of starting group */
+ hid_t lapl_id; /* LAPL for walking across links */
+ hid_t dxpl_id; /* DXPL for operations */
+ H5SL_t *visited; /* Skip list for tracking visited nodes */
+ H5O_iterate_t op; /* Application callback */
+ void *op_data; /* Application's op data */
+} H5O_iter_visit_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
+static herr_t H5O_obj_type_real(H5O_t *oh, H5O_type_t *obj_type);
+static herr_t H5O_visit(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id,
+ hid_t dxpl_id);
+static herr_t H5O_get_hdr_info_real(const H5O_t *oh, H5O_hdr_info_t *hdr);
+static const H5O_obj_class_t *H5O_obj_class_real(H5O_t *oh);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Header message ID to class mapping */
+
+/* Remember to increment H5O_MSG_TYPES in H5Opkg.h when adding a new
+ * message.
+ */
+
+const H5O_msg_class_t *const H5O_msg_class_g[] = {
+ H5O_MSG_NULL, /*0x0000 Null */
+ H5O_MSG_SDSPACE, /*0x0001 Dataspace */
+ H5O_MSG_LINFO, /*0x0002 Link information */
+ H5O_MSG_DTYPE, /*0x0003 Datatype */
+ H5O_MSG_FILL, /*0x0004 Old data storage -- fill value */
+ H5O_MSG_FILL_NEW, /*0x0005 New data storage -- fill value */
+ H5O_MSG_LINK, /*0x0006 Link */
+ H5O_MSG_EFL, /*0x0007 Data storage -- external data files */
+ H5O_MSG_LAYOUT, /*0x0008 Data Layout */
+#ifdef H5O_ENABLE_BOGUS
+ H5O_MSG_BOGUS_VALID, /*0x0009 "Bogus valid" (for testing) */
+#else /* H5O_ENABLE_BOGUS */
+ NULL, /*0x0009 "Bogus valid" (for testing) */
+#endif /* H5O_ENABLE_BOGUS */
+ H5O_MSG_GINFO, /*0x000A Group information */
+ H5O_MSG_PLINE, /*0x000B Data storage -- filter pipeline */
+ H5O_MSG_ATTR, /*0x000C Attribute */
+ H5O_MSG_NAME, /*0x000D Object name */
+ H5O_MSG_MTIME, /*0x000E Object modification date and time */
+ H5O_MSG_SHMESG, /*0x000F File-wide shared message table */
+ H5O_MSG_CONT, /*0x0010 Object header continuation */
+ H5O_MSG_STAB, /*0x0011 Symbol table */
+ H5O_MSG_MTIME_NEW, /*0x0012 New Object modification date and time */
+ H5O_MSG_BTREEK, /*0x0013 Non-default v1 B-tree 'K' values */
+ H5O_MSG_DRVINFO, /*0x0014 Driver info settings */
+ H5O_MSG_AINFO, /*0x0015 Attribute information */
+ H5O_MSG_REFCOUNT, /*0x0016 Object's ref. count */
+ H5O_MSG_FSINFO, /*0x0017 Free-space manager info */
+ H5O_MSG_MDCI, /*0x0018 Metadata cache image */
+ H5O_MSG_UNKNOWN, /*0x0019 Placeholder for unknown message */
+#ifdef H5O_ENABLE_BOGUS
+ H5O_MSG_BOGUS_INVALID, /*0x001A "Bogus invalid" (for testing) */
+#else /* H5O_ENABLE_BOGUS */
+ NULL, /*0x001A "Bogus invalid" (for testing) */
+#endif /* H5O_ENABLE_BOGUS */
+};
+
+/* Declare a free list to manage the H5O_t struct */
+H5FL_DEFINE(H5O_t);
+
+/* Declare a free list to manage the H5O_mesg_t sequence information */
+H5FL_SEQ_DEFINE(H5O_mesg_t);
+
+/* Declare a free list to manage the H5O_chunk_t sequence information */
+H5FL_SEQ_DEFINE(H5O_chunk_t);
+
+/* Declare a free list to manage the chunk image information */
+H5FL_BLK_DEFINE(chunk_image);
+
+/* Declare external the free list for H5O_cont_t sequences */
+H5FL_SEQ_EXTERN(H5O_cont_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Declare external the free list for time_t's */
+H5FL_EXTERN(time_t);
+
+/* Declare external the free list for H5_obj_t's */
+H5FL_EXTERN(H5_obj_t);
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Header object ID to class mapping */
+/*
+ * Initialize the object class info table. Begin with the most general types
+ * and end with the most specific. For instance, any object that has a
+ * datatype message is a datatype but only some of them are datasets.
+ */
+static const H5O_obj_class_t *const H5O_obj_class_g[] = {
+ H5O_OBJ_DATATYPE, /* Datatype object (H5O_TYPE_NAMED_DATATYPE - 2) */
+ H5O_OBJ_DATASET, /* Dataset object (H5O_TYPE_DATASET - 1) */
+ H5O_OBJ_GROUP, /* Group object (H5O_TYPE_GROUP - 0) */
+};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__init_package
+ *
+ * Purpose: Initialize information specific to H5O interface.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O__init_package(void)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* H5O interface sanity checks */
+ HDcompile_assert(H5O_MSG_TYPES == NELMTS(H5O_msg_class_g));
+ HDcompile_assert(sizeof(H5O_fheap_id_t) == H5O_FHEAP_ID_LEN);
+
+ HDcompile_assert(H5O_UNKNOWN_ID < H5O_MSG_TYPES);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oopen
+ *
+ * Purpose: Opens an object within an HDF5 file.
+ *
+ * This function opens an object in the same way that H5Gopen2,
+ * H5Topen2, and H5Dopen2 do. However, H5Oopen doesn't require
+ * the type of object to be known beforehand. This can be
+ * useful in user-defined links, for instance, when only a
+ * path is known.
+ *
+ * The opened object should be closed again with H5Oclose
+ * or H5Gclose, H5Tclose, or H5Dclose.
+ *
+ * Return: Success: An open object identifier
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+ H5G_loc_t loc;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*si", loc_id, name, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Open the object */
+ if((ret_value = H5O_open_name(&loc, name, lapl_id, dxpl_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oopen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oopen_by_idx
+ *
+ * Purpose: Opens an object within an HDF5 file, according to the offset
+ * within an index.
+ *
+ * This function opens an object in the same way that H5Gopen,
+ * H5Topen, and H5Dopen do. However, H5Oopen doesn't require
+ * the type of object to be known beforehand. This can be
+ * useful in user-defined links, for instance, when only a
+ * path is known.
+ *
+ * The opened object should be closed again with H5Oclose
+ * or H5Gclose, H5Tclose, or H5Dclose.
+ *
+ * Return: Success: An open object identifier
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 20 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Oopen_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t lapl_id)
+{
+ H5G_loc_t loc;
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hbool_t loc_found = FALSE; /* Entry at 'name' found */
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("i", "i*sIiIohi", loc_id, group_name, idx_type, order, n, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location, according to the order in the index */
+ if(H5G_loc_find_by_idx(&loc, group_name, idx_type, order, n, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "group not found")
+ loc_found = TRUE;
+
+ /* Open the object */
+ if((ret_value = H5O_open_by_loc(&obj_loc, lapl_id, dxpl_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+done:
+ /* Release the object location if we failed after copying it */
+ if(ret_value < 0 && loc_found)
+ if(H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oopen_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oopen_by_addr
+ *
+ * Purpose: Warning! This function is EXTREMELY DANGEROUS!
+ * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA,
+ * and other VERY BAD THINGS!
+ *
+ * This function opens an object using its address within the
+ * HDF5 file, similar to an HDF5 hard link. The open object
+ * is identical to an object opened with H5Oopen() and should
+ * be closed with H5Oclose() or a type-specific closing
+ * function (such as H5Gclose() ).
+ *
+ * This function is very dangerous if called on an invalid
+ * address. For this reason, H5Oincr_refcount() should be
+ * used to prevent HDF5 from deleting any object that is
+ * referenced by address (e.g. by a user-defined link).
+ * H5Odecr_refcount() should be used when the object is
+ * no longer being referenced by address (e.g. when the UD link
+ * is deleted).
+ *
+ * The address of the HDF5 file on disk has no effect on
+ * H5Oopen_by_addr(), nor does the use of any unusual file
+ * drivers. The "address" is really the offset within the
+ * HDF5 file, and HDF5's file drivers will transparently
+ * map this to an address on disk for the filesystem.
+ *
+ * Return: Success: An open object identifier
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Oopen_by_addr(hid_t loc_id, haddr_t addr)
+{
+ H5G_loc_t loc;
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hid_t lapl_id = H5P_LINK_ACCESS_DEFAULT; /* lapl to use to open this object */
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "ia", loc_id, addr);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no address supplied")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+ obj_loc.oloc->addr = addr;
+ obj_loc.oloc->file = loc.oloc->file;
+ H5G_name_reset(obj_loc.path); /* objects opened through this routine don't have a path name */
+
+ /* Open the object */
+ if((ret_value = H5O_open_by_loc(&obj_loc, lapl_id, H5AC_ind_read_dxpl_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+done:
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oopen_by_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Olink
+ *
+ * Purpose: Creates a hard link from NEW_NAME to the object specified
+ * by OBJ_ID using properties defined in the Link Creation
+ * Property List LCPL.
+ *
+ * This function should be used to link objects that have just
+ * been created.
+ *
+ * NEW_NAME is interpreted relative to
+ * NEW_LOC_ID, which is either a file ID or a
+ * group ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, December 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name, hid_t lcpl_id,
+ hid_t lapl_id)
+{
+ H5G_loc_t new_loc;
+ H5G_loc_t obj_loc;
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "ii*sii", obj_id, new_loc_id, new_name, lcpl_id, lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(obj_id, &obj_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(new_loc_id == H5L_SAME_LOC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "cannot use H5L_SAME_LOC when only one location is specified")
+ if(H5G_loc(new_loc_id, &new_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!new_name || !*new_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+/* Avoid compiler warning on 32-bit machines */
+#if H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T
+ if(HDstrlen(new_name) > H5L_MAX_LINK_NAME_LEN)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "name too long")
+#endif /* H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T */
+ if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, obj_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Link to the object */
+ if(H5L_link(&new_loc, new_name, &obj_loc, lcpl_id, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Olink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oincr_refcount
+ *
+ * Purpose: Warning! This function is EXTREMELY DANGEROUS!
+ * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA,
+ * and other VERY BAD THINGS!
+ *
+ * This function increments the "hard link" reference count
+ * for an object. It should be used when a user-defined link
+ * that references an object by address is created. When the
+ * link is deleted, H5Odecr_refcount should be used.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oincr_refcount(hid_t object_id)
+{
+ H5O_loc_t *oloc;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", object_id);
+
+ /* Get the object's oloc so we can adjust its link count */
+ if((oloc = H5O_get_loc(object_id)) == NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ if(H5O_link(oloc, 1, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5O_incr_refcount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Odecr_refcount
+ *
+ * Purpose: Warning! This function is EXTREMELY DANGEROUS!
+ * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA,
+ * and other VERY BAD THINGS!
+ *
+ * This function decrements the "hard link" reference count
+ * for an object. It should be used when user-defined links
+ * that reference an object by address are deleted, and only
+ * after H5Oincr_refcount has already been used.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Odecr_refcount(hid_t object_id)
+{
+ H5O_loc_t *oloc;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", object_id);
+
+ /* Get the object's oloc so we can adjust its link count */
+ if((oloc = H5O_get_loc(object_id)) == NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ if(H5O_link(oloc, -1, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Odecr_refcount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oexists_by_name
+ *
+ * Purpose: Determine if a linked-to object exists
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * February 2 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Oexists_by_name(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location info */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("t", "i*si", loc_id, name, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Check if the object exists */
+ if((ret_value = H5G_loc_exists(&loc, name, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine if '%s' exists", name)
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oexists_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oget_info
+ *
+ * Purpose: Retrieve information about an object.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oget_info(hid_t loc_id, H5O_info_t *oinfo)
+{
+ H5G_loc_t loc; /* Location of group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", loc_id, oinfo);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!oinfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Retrieve the object's information */
+ if(H5G_loc_info(&loc, ".", TRUE, oinfo/*out*/, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oget_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oget_info_by_name
+ *
+ * Purpose: Retrieve information about an object.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oget_info_by_name(hid_t loc_id, const char *name, H5O_info_t *oinfo, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*s*xi", loc_id, name, oinfo, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(!oinfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Retrieve the object's information */
+ if(H5G_loc_info(&loc, name, TRUE, oinfo/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oget_info_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oget_info_by_idx
+ *
+ * Purpose: Retrieve information about an object, according to the order
+ * of an index.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 26 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oget_info_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, H5O_info_t *oinfo, hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIoh*xi", loc_id, group_name, idx_type, order, n, oinfo,
+ lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!group_name || !*group_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!oinfo)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location, according to the order in the index */
+ if(H5G_loc_find_by_idx(&loc, group_name, idx_type, order, n, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "group not found")
+ loc_found = TRUE;
+
+ /* Retrieve the object's information */
+ if(H5O_get_info(obj_loc.oloc, dxpl_id, TRUE, oinfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object info")
+
+done:
+ /* Release the object location */
+ if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oget_info_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oset_comment
+ *
+ * Purpose: Gives the specified object a comment. The COMMENT string
+ * should be a null terminated string. An object can have only
+ * one comment at a time. Passing NULL for the COMMENT argument
+ * will remove the comment property from the object.
+ *
+ * Note: Deprecated in favor of using attributes on objects
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 30 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oset_comment(hid_t obj_id, const char *comment)
+{
+ H5G_loc_t loc; /* Location of group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", obj_id, comment);
+
+ /* Check args */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* (Re)set the object's comment */
+ if(H5G_loc_set_comment(&loc, ".", comment, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oset_comment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oset_comment_by_name
+ *
+ * Purpose: Gives the specified object a comment. The COMMENT string
+ * should be a null terminated string. An object can have only
+ * one comment at a time. Passing NULL for the COMMENT argument
+ * will remove the comment property from the object.
+ *
+ * Note: Deprecated in favor of using attributes on objects
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 30 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oset_comment_by_name(hid_t loc_id, const char *name, const char *comment,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*s*si", loc_id, name, comment, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* (Re)set the object's comment */
+ if(H5G_loc_set_comment(&loc, name, comment, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oset_comment_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oget_comment
+ *
+ * Purpose: Retrieve comment for an object.
+ *
+ * Return: Success: Number of bytes in the comment excluding the
+ * null terminator. Zero if the object has no
+ * comment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * August 30 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Oget_comment(hid_t obj_id, char *comment, size_t bufsize)
+{
+ H5G_loc_t loc; /* Location of group */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*sz", obj_id, comment, bufsize);
+
+ /* Check args */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Retrieve the object's comment */
+ if((ret_value = H5G_loc_get_comment(&loc, ".", comment/*out*/, bufsize, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oget_comment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oget_comment_by_name
+ *
+ * Purpose: Retrieve comment for an object.
+ *
+ * Return: Success: Number of bytes in the comment excluding the
+ * null terminator. Zero if the object has no
+ * comment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * August 30 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Oget_comment_by_name(hid_t loc_id, const char *name, char *comment, size_t bufsize,
+ hid_t lapl_id)
+{
+ H5G_loc_t loc; /* Location of group */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("Zs", "i*s*szi", loc_id, name, comment, bufsize, lapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Retrieve the object's comment */
+ if((ret_value = H5G_loc_get_comment(&loc, name, comment/*out*/, bufsize, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oget_comment_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ovisit
+ *
+ * Purpose: Recursively visit an object and all the objects reachable
+ * from it. If the starting object is a group, all the objects
+ * linked to from that group will be visited. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Soft links and user-defined links are ignored during
+ * this operation.
+ *
+ * NOTE: Each _object_ reachable from the initial group will only
+ * be visited once. If multiple hard links point to the same
+ * object, the first link to the object's path (according to the
+ * iteration index and iteration order given) will be used to in
+ * the callback about the object.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Quincey Koziol
+ * November 25 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ovisit(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order,
+ H5O_iterate_t op, void *op_data)
+{
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIiIox*x", obj_id, idx_type, order, op, op_data);
+
+ /* Check args */
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified")
+
+ /* Call internal object visitation routine */
+ if((ret_value = H5O_visit(obj_id, ".", idx_type, order, op, op_data, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ovisit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ovisit_by_name
+ *
+ * Purpose: Recursively visit an object and all the objects reachable
+ * from it. If the starting object is a group, all the objects
+ * linked to from that group will be visited. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Soft links and user-defined links are ignored during
+ * this operation.
+ *
+ * NOTE: Each _object_ reachable from the initial group will only
+ * be visited once. If multiple hard links point to the same
+ * object, the first link to the object's path (according to the
+ * iteration index and iteration order given) will be used to in
+ * the callback about the object.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Quincey Koziol
+ * November 24 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ovisit_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id)
+{
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "i*sIiIox*xi", loc_id, obj_name, idx_type, order, op, op_data,
+ lapl_id);
+
+ /* Check args */
+ if(!obj_name || !*obj_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+ if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+ if(!op)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Call internal object visitation routine */
+ if((ret_value = H5O_visit(loc_id, obj_name, idx_type, order, op, op_data, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ovisit_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oclose
+ *
+ * Purpose: Close an open file object.
+ *
+ * This is the companion to H5Oopen. It is used to close any
+ * open object in an HDF5 file (but not IDs are that not file
+ * objects, such as property lists and dataspaces). It has
+ * the same effect as calling H5Gclose, H5Dclose, or H5Tclose.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oclose(hid_t object_id)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", object_id);
+
+ /* Get the type of the object and close it in the correct way */
+ switch(H5I_get_type(object_id)) {
+ case H5I_GROUP:
+ case H5I_DATATYPE:
+ case H5I_DATASET:
+ if(H5I_object(object_id) == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object")
+ if(H5I_dec_app_ref(object_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close object")
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Odisable_mdc_flushes
+ *
+ * Purpose: To "cork" an object:
+ * --keep dirty entries assoicated with the object in the metadata cache
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * January 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Odisable_mdc_flushes(hid_t object_id)
+{
+ H5O_loc_t *oloc; /* Object location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", object_id);
+
+ /* Get the object's oloc */
+ if(NULL == (oloc = H5O_get_loc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ if(H5AC_cork(oloc->file, oloc->addr, H5AC__SET_CORK, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCORK, FAIL, "unable to cork an object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Odisable_mdc_flushes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oenable_mdc_flushes
+ *
+ * Purpose: To "uncork" an object
+ * --release keeping dirty entries associated with the object
+ * in the metadata cache
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * January 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oenable_mdc_flushes(hid_t object_id)
+{
+ H5O_loc_t *oloc; /* Object location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", object_id);
+
+ /* Get the object's oloc */
+ if(NULL == (oloc = H5O_get_loc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ /* Set the value */
+ if(H5AC_cork(oloc->file, oloc->addr, H5AC__UNCORK, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNCORK, FAIL, "unable to uncork an object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Oenable_mdc_flushes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oare_mdc_flushes_disabled
+ *
+ * Purpose: Retrieve the object's "cork" status in the parameter "are_disabled":
+ * TRUE if mdc flushes for the object is disabled
+ * FALSE if mdc flushes for the object is not disabled
+ * Return error if the parameter "are_disabled" is not supplied
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * January 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oare_mdc_flushes_disabled(hid_t object_id, hbool_t *are_disabled)
+{
+ H5O_loc_t *oloc; /* Object location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", object_id, are_disabled);
+
+ /* Check args */
+
+ /* Get the object's oloc */
+ if(NULL == (oloc = H5O_get_loc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+ if(!are_disabled)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ /* Get the cork status */
+ if(H5AC_cork(oloc->file, oloc->addr, H5AC__GET_CORKED, are_disabled) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Oare_mdc_flushes_disabled() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_create
+ *
+ * Purpose: Creates a new object header. Allocates space for it and
+ * then calls an initialization function. The object header
+ * is opened for write access and should eventually be
+ * closed by calling H5O_close().
+ *
+ * Return: Success: Non-negative, the ENT argument contains
+ * information about the object header,
+ * including its address.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, size_t initial_rc,
+ hid_t ocpl_id, H5O_loc_t *loc/*out*/)
+{
+ H5P_genplist_t *oc_plist; /* Object creation property list */
+ H5O_t *oh = NULL; /* Object header created */
+ haddr_t oh_addr; /* Address of initial object header */
+ size_t oh_size; /* Size of initial object header */
+ uint8_t oh_flags; /* Object header's initial status flags */
+ unsigned insert_flags = H5AC__NO_FLAGS_SET; /* Flags for inserting object header into cache */
+ hbool_t store_msg_crt_idx; /* Whether to always store message creation indices for this file */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(loc);
+ HDassert(TRUE == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE));
+
+ /* Check for invalid access request */
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "no write intent on file")
+
+ /* Make certain we allocate at least a reasonable size for the object header */
+ size_hint = H5O_ALIGN_F(f, MAX(H5O_MIN_SIZE, size_hint));
+
+ /* Get the property list */
+ if(NULL == (oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get any object header status flags set by properties */
+ if(H5P_get(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags")
+
+ /* Allocate the object header and zero out header fields */
+ if(NULL == (oh = H5FL_CALLOC(H5O_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize file-specific information for object header */
+ store_msg_crt_idx = H5F_STORE_MSG_CRT_IDX(f);
+ if(H5F_USE_LATEST_FLAGS(f, H5F_LATEST_OBJ_HEADER) || store_msg_crt_idx || (oh_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED))
+ oh->version = H5O_VERSION_LATEST;
+ else
+ oh->version = H5O_VERSION_1;
+ oh->sizeof_size = H5F_SIZEOF_SIZE(f);
+ oh->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ oh->swmr_write = !!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE);
+#ifdef H5O_ENABLE_BAD_MESG_COUNT
+ /* Check whether the "bad message count" property is set */
+ if(H5P_exist_plist(oc_plist, H5O_BAD_MESG_COUNT_NAME) > 0) {
+ /* Retrieve bad message count flag */
+ if(H5P_get(oc_plist, H5O_BAD_MESG_COUNT_NAME, &oh->store_bad_mesg_count) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get bad message count flag")
+ } /* end if */
+#endif /* H5O_ENABLE_BAD_MESG_COUNT */
+
+ /* Create object header proxy if doing SWMR writes */
+ if(oh->swmr_write) {
+ /* Create virtual entry, for use as proxy */
+ if(NULL == (oh->proxy = H5AC_proxy_entry_create()))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy")
+ } /* end if */
+ else
+ oh->proxy = NULL;
+
+ /* Set initial status flags */
+ oh->flags = oh_flags;
+
+ /* Initialize version-specific fields */
+ if(oh->version > H5O_VERSION_1) {
+ /* Initialize all time fields with current time, if we are storing them */
+ if(oh->flags & H5O_HDR_STORE_TIMES)
+ oh->atime = oh->mtime = oh->ctime = oh->btime = H5_now();
+ else
+ oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
+
+ /* Make certain attribute creation order tracking is enabled if
+ * attributes can be shared in this file.
+ */
+ if(store_msg_crt_idx)
+ oh->flags |= H5O_HDR_ATTR_CRT_ORDER_TRACKED;
+
+ /* Retrieve attribute storage phase change values from property list */
+ if(H5P_get(oc_plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &oh->max_compact) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get max. # of compact attributes")
+ if(H5P_get(oc_plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &oh->min_dense) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get min. # of dense attributes")
+
+ /* Check for non-default attribute storage phase change values */
+ if(oh->max_compact != H5O_CRT_ATTR_MAX_COMPACT_DEF || oh->min_dense != H5O_CRT_ATTR_MIN_DENSE_DEF)
+ oh->flags |= H5O_HDR_ATTR_STORE_PHASE_CHANGE;
+
+ /* Determine correct value for chunk #0 size bits */
+/* Avoid compiler warning on 32-bit machines */
+#if H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T
+ if(size_hint > 4294967295UL)
+ oh->flags |= H5O_HDR_CHUNK0_8;
+ else
+#endif /* H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T */
+ if(size_hint > 65535)
+ oh->flags |= H5O_HDR_CHUNK0_4;
+ else if(size_hint > 255)
+ oh->flags |= H5O_HDR_CHUNK0_2;
+ } /* end if */
+ else {
+ /* Reset unused time fields */
+ oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
+ } /* end else */
+
+ /* Compute total size of initial object header */
+ /* (i.e. object header prefix and first chunk) */
+ oh_size = (size_t)H5O_SIZEOF_HDR(oh) + size_hint;
+
+ /* Allocate disk space for header and first chunk */
+ if(HADDR_UNDEF == (oh_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)oh_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header")
+
+ /* Create the chunk list */
+ oh->nchunks = oh->alloc_nchunks = 1;
+ if(NULL == (oh->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the first chunk */
+ oh->chunk[0].addr = oh_addr;
+ oh->chunk[0].size = oh_size;
+ oh->chunk[0].gap = 0;
+
+ /* Allocate enough space for the first chunk */
+ /* (including space for serializing the object header prefix */
+ if(NULL == (oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, oh_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ oh->chunk[0].chunk_proxy = NULL;
+
+ /* Put magic # for object header in first chunk */
+ if(oh->version > H5O_VERSION_1)
+ HDmemcpy(oh->chunk[0].image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+
+ /* Create the message list */
+ oh->nmesgs = 1;
+ oh->alloc_nmesgs = H5O_NMESGS;
+ if(NULL == (oh->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh->alloc_nmesgs)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize the initial "null" message, covering the entire first chunk */
+ oh->mesg[0].type = H5O_MSG_NULL;
+ oh->mesg[0].dirty = TRUE;
+ oh->mesg[0].native = NULL;
+ oh->mesg[0].raw = oh->chunk[0].image + (H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)) + H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[0].raw_size = size_hint - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[0].chunkno = 0;
+
+ /* Check for non-zero initial refcount on the object header */
+ if(initial_rc > 0) {
+ /* Set the initial refcount & pin the header when its inserted */
+ oh->rc = initial_rc;
+ insert_flags |= H5AC__PIN_ENTRY_FLAG;
+ } /* end if */
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(dxpl_id, oh_addr, FAIL);
+
+ /* Cache object header */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_OHDR, oh_addr, oh, insert_flags) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header")
+
+ /* Reset object header pointer, now that it's been inserted into the cache */
+ oh = NULL;
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+ /* Set up object location */
+ loc->file = f;
+ loc->addr = oh_addr;
+
+ /* Open it */
+ if(H5O_open(loc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object header")
+
+done:
+ if(ret_value < 0 && oh)
+ if(H5O__free(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_open
+ *
+ * Purpose: Opens an object header which is described by the symbol table
+ * entry OBJ_ENT.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ * Modification:
+ * Raymond Lu
+ * 5 November 2007
+ * Turn off the holding file variable if it's on. When it's
+ * needed, the caller will turn it on again.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_open(H5O_loc_t *loc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(loc->file);
+
+#ifdef H5O_DEBUG
+ if(H5DEBUG(O))
+ HDfprintf(H5DEBUG(O), "> %a\n", loc->addr);
+#endif
+
+ /* Turn off the variable for holding file or increment open-lock counters */
+ if(loc->holding_file)
+ loc->holding_file = FALSE;
+ else
+ H5F_INCR_NOPEN_OBJS(loc->file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_open_name
+ *
+ * Purpose: Opens an object within an HDF5 file.
+ *
+ * Return: Success: An open object identifier
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * March 5 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref)
+{
+ H5G_loc_t obj_loc; /* Location used to open group */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'name' found */
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(name && *name);
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(loc, name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Open the object */
+ if((ret_value = H5O_open_by_loc(&obj_loc, lapl_id, dxpl_id, app_ref)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+done:
+ if(ret_value < 0 && loc_found)
+ if(H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_open_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_open_by_loc
+ *
+ * Purpose: Opens an object and returns an ID given its group loction.
+ *
+ * Return: Success: Open object identifier
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * July 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5O_open_by_loc(const H5G_loc_t *obj_loc, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref)
+{
+ const H5O_obj_class_t *obj_class; /* Class of object for location */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(obj_loc);
+
+ /* Get the object class for this location */
+ if(NULL == (obj_class = H5O_obj_class(obj_loc->oloc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object class")
+
+ /* Call the object class's 'open' routine */
+ HDassert(obj_class->open);
+ if((ret_value = obj_class->open(obj_loc, lapl_id, dxpl_id, app_ref)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_open_by_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_close
+ *
+ * Purpose: Closes an object header that was previously open.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_close(H5O_loc_t *loc, hbool_t *file_closed /*out*/)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_NOPEN_OBJS(loc->file) > 0);
+
+ /* Set the file_closed flag to the default value.
+ * This flag lets downstream code know if the file struct is
+ * still accessible and/or likely to contain useful data.
+ * It's needed by the evict-on-close code. Clients can ignore
+ * this value by passing in NULL.
+ */
+ if(file_closed)
+ *file_closed = FALSE;
+
+ /* Decrement open-lock counters */
+ H5F_DECR_NOPEN_OBJS(loc->file);
+
+#ifdef H5O_DEBUG
+ if(H5DEBUG(O)) {
+ if(H5F_FILE_ID(loc->file)< 0 && 1 == H5F_NREFS(loc->file))
+ HDfprintf(H5DEBUG(O), "< %a auto %lu remaining\n",
+ loc->addr,
+ (unsigned long)H5F_NOPEN_OBJS(loc->file));
+ else
+ HDfprintf(H5DEBUG(O), "< %a\n", loc->addr);
+ } /* end if */
+#endif
+
+ /*
+ * If the file open object count has reached the number of open mount points
+ * (each of which has a group open in the file) attempt to close the file.
+ */
+ if(H5F_NOPEN_OBJS(loc->file) == H5F_NMOUNTS(loc->file))
+ /* Attempt to close down the file hierarchy */
+ if(H5F_try_close(loc->file, file_closed) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
+
+ /* Release location information */
+ if(H5O_loc_free(loc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "problem attempting to free location")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_oh
+ *
+ * Purpose: Adjust the link count for an open object header by adding
+ * ADJUST to the link count.
+ *
+ * Return: Success: New link count
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, hbool_t *deleted)
+{
+ haddr_t addr = H5O_OH_GET_ADDR(oh); /* Object header address */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(deleted);
+
+ /* Check for adjusting link count */
+ if(adjust) {
+ if(adjust < 0) {
+ /* Check for too large of an adjustment */
+ if((unsigned)(-adjust) > oh->nlink)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "link count would be negative")
+
+ /* Adjust the link count for the object header */
+ oh->nlink = (unsigned)((int)oh->nlink + adjust);
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+
+ /* Check if the object should be deleted */
+ if(oh->nlink == 0) {
+ /* Check if the object is still open by the user */
+ if(H5FO_opened(f, addr) != NULL) {
+ /* Flag the object to be deleted when it's closed */
+ if(H5FO_mark(f, addr, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion")
+ } /* end if */
+ else {
+ /* Mark the object header for deletion */
+ *deleted = TRUE;
+ } /* end else */
+ } /* end if */
+ } /* end if */
+ else {
+ /* A new object, or one that will be deleted */
+ if(0 == oh->nlink) {
+ /* Check if the object is currently open, but marked for deletion */
+ if(H5FO_marked(f, addr)) {
+ /* Remove "delete me" flag on the object */
+ if(H5FO_mark(f, addr, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion")
+ } /* end if */
+ } /* end if */
+
+ /* Adjust the link count for the object header */
+ oh->nlink = (unsigned)((int)oh->nlink + adjust);
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+ } /* end if */
+
+ /* Check for operations on refcount message */
+ if(oh->version > H5O_VERSION_1) {
+ /* Check if the object has a refcount message already */
+ if(oh->has_refcount_msg) {
+ /* Check for removing refcount message */
+ if(oh->nlink <= 1) {
+ if(H5O_msg_remove_real(f, oh, H5O_MSG_REFCOUNT, H5O_ALL, NULL, NULL, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete refcount message")
+ oh->has_refcount_msg = FALSE;
+ } /* end if */
+ /* Update refcount message with new link count */
+ else {
+ H5O_refcount_t refcount = oh->nlink;
+
+ if(H5O_msg_write_real(f, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update refcount message")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check for adding refcount message to object */
+ if(oh->nlink > 1) {
+ H5O_refcount_t refcount = oh->nlink;
+
+ if(H5O_msg_append_real(f, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to create new refcount message")
+ oh->has_refcount_msg = TRUE;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (int)oh->nlink;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link
+ *
+ * Purpose: Adjust the link count for an object header by adding
+ * ADJUST to the link count.
+ *
+ * Return: Success: New link count
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL;
+ hbool_t deleted = FALSE; /* Whether the object was deleted */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Call the "real" link routine */
+ if((ret_value = H5O_link_oh(loc->file, adjust, dxpl_id, oh, &deleted)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust object link count")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+ if(ret_value >= 0 && deleted && H5O_delete(loc->file, dxpl_id, loc->addr) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_protect
+ *
+ * Purpose: Wrapper around H5AC_protect for use during a H5O_protect->
+ * H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls
+ * during an object's creation.
+ *
+ * Return: Success: Pointer to the object header structure for the
+ * object.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Dec 31 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_t *
+H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags,
+ hbool_t pin_all_chunks)
+{
+ H5O_t *oh = NULL; /* Object header protected */
+ H5O_cache_ud_t udata; /* User data for protecting object header */
+ H5O_cont_msgs_t cont_msg_info; /* Continuation message info */
+ unsigned file_intent; /* R/W intent on file */
+ H5O_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, NULL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+
+ /* prot_flags may only contain the H5AC__READ_ONLY_FLAG */
+ HDassert((prot_flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
+
+ /* Check for valid address */
+ if(!H5F_addr_defined(loc->addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "address undefined")
+
+ /* Check for write access on the file */
+ file_intent = H5F_INTENT(loc->file);
+ if((0 == (prot_flags & H5AC__READ_ONLY_FLAG)) && (0 == (file_intent & H5F_ACC_RDWR)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no write intent on file")
+
+ /* Construct the user data for protect callback */
+ udata.made_attempt = FALSE;
+ udata.v1_pfx_nmesgs = 0;
+ udata.chunk0_size = 0;
+ udata.oh = NULL;
+ udata.common.f = loc->file;
+ udata.common.dxpl_id = dxpl_id;
+ udata.common.file_intent = file_intent;
+ udata.common.merged_null_msgs = 0;
+ HDmemset(&cont_msg_info, 0, sizeof(cont_msg_info));
+ udata.common.cont_msg_info = &cont_msg_info;
+ udata.common.addr = loc->addr;
+
+ /* Lock the object header into the cache */
+ if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, &udata, prot_flags)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header")
+
+ /* Check if there are any continuation messages to process */
+ if(cont_msg_info.nmsgs > 0) {
+ size_t curr_msg; /* Current continuation message to process */
+ H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
+
+ /* Sanity check - we should only have continuation messages to process
+ * when the object header is actually loaded from the file.
+ */
+ HDassert(udata.made_attempt == TRUE);
+ HDassert(cont_msg_info.msgs);
+
+ /* Construct the user data for protecting chunks */
+ chk_udata.decoding = TRUE;
+ chk_udata.oh = oh;
+ chk_udata.chunkno = UINT_MAX; /* Set to invalid value, for better error detection */
+ chk_udata.common.f = loc->file;
+ chk_udata.common.dxpl_id = dxpl_id;
+ chk_udata.common.file_intent = file_intent;
+ chk_udata.common.merged_null_msgs = udata.common.merged_null_msgs;
+ chk_udata.common.cont_msg_info = &cont_msg_info;
+
+ /* Read in continuation messages, until there are no more */
+ /* (Note that loading chunks could increase the # of continuation
+ * messages if new ones are found - QAK, 19/11/2016)
+ */
+ curr_msg = 0;
+ while(curr_msg < cont_msg_info.nmsgs) {
+ H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to bring it into memory */
+#ifndef NDEBUG
+ size_t chkcnt = oh->nchunks; /* Count of chunks (for sanity checking) */
+#endif /* NDEBUG */
+
+ /* Bring the chunk into the cache */
+ /* (which adds to the object header) */
+ chk_udata.common.addr = cont_msg_info.msgs[curr_msg].addr;
+ chk_udata.size = cont_msg_info.msgs[curr_msg].size;
+ if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, &chk_udata, prot_flags)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk")
+
+ /* Sanity check */
+ HDassert(chk_proxy->oh == oh);
+ HDassert(chk_proxy->chunkno == chkcnt);
+ HDassert(oh->nchunks == (chkcnt + 1));
+
+ /* Release the chunk from the cache */
+ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, chk_proxy, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header chunk")
+
+ /* Advance to next continuation message */
+ curr_msg++;
+ } /* end while */
+
+ /* Release any continuation messages built up */
+ cont_msg_info.msgs = (H5O_cont_t *)H5FL_SEQ_FREE(H5O_cont_t, cont_msg_info.msgs);
+
+ /* Pass back out some of the chunk's user data */
+ udata.common.merged_null_msgs = chk_udata.common.merged_null_msgs;
+ } /* end if */
+
+ /* Check for incorrect # of object header messages, if we've just loaded
+ * this object header from the file
+ */
+ if(udata.made_attempt) {
+/* Don't enforce the error on an incorrect # of object header messages bug
+ * unless strict format checking is enabled. This allows for older
+ * files, created with a version of the library that had a bug in tracking
+ * the correct # of header messages to be read in without the library
+ * erroring out here. -QAK
+ */
+#ifdef H5_STRICT_FORMAT_CHECKS
+ /* Check for incorrect # of messages in v1 object header */
+ if(oh->version == H5O_VERSION_1 &&
+ (oh->nmesgs + udata.common.merged_null_msgs) != udata.v1_pfx_nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - incorrect # of messages")
+#endif /* H5_STRICT_FORMAT_CHECKS */
+ } /* end if */
+
+#ifdef H5O_DEBUG
+H5O_assert(oh);
+#endif /* H5O_DEBUG */
+
+ /* Pin the other chunks also when requested, so that the object header
+ * proxy can be set up.
+ */
+ if(pin_all_chunks && oh->nchunks > 1) {
+ unsigned u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(oh->swmr_write);
+
+ /* Iterate over chunks > 0 */
+ for(u = 1; u < oh->nchunks; u++) {
+ H5O_chunk_proxy_t *chk_proxy; /* Chunk proxy */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(loc->file, dxpl_id, oh, u)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header chunk")
+
+ /* Pin chunk proxy*/
+ if(H5AC_pin_protected_entry(chk_proxy) < 0 )
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, NULL, "unable to pin object header chunk")
+
+ /* Unprotect chunk */
+ if(H5O_chunk_unprotect(loc->file, dxpl_id, chk_proxy, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to unprotect object header chunk")
+
+ /* Preserve chunk proxy pointer for later */
+ oh->chunk[u].chunk_proxy = chk_proxy;
+ } /* end for */
+
+ /* Set the flag for the unprotect */
+ oh->chunks_pinned = TRUE;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = oh;
+
+done:
+ if(ret_value == NULL && oh)
+ if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pin
+ *
+ * Purpose: Pin an object header down for use during a sequence of message
+ * operations, which prevents the object header from being
+ * evicted from the cache.
+ *
+ * Return: Success: Pointer to the object header structure for the
+ * object.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_t *
+H5O_pin(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(loc);
+
+ /* Get header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header")
+
+ /* Increment the reference count on the object header */
+ /* (which will pin it, if appropriate) */
+ if(H5O_inc_rc(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "unable to increment reference count on object header")
+
+ /* Set the return value */
+ ret_value = oh;
+
+done:
+ /* Release the object header from the cache */
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_pin() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_unpin
+ *
+ * Purpose: Unpin an object header, allowing it to be evicted from the
+ * metadata cache.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_unpin(H5O_t *oh)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh);
+
+ /* Decrement the reference count on the object header */
+ /* (which will unpin it, if appropriate) */
+ if(H5O_dec_rc(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement reference count on object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_unpin() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_unprotect
+ *
+ * Purpose: Wrapper around H5AC_unprotect for use during a H5O_protect->
+ * H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls
+ * during an object's creation.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Dec 31 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_unprotect(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, unsigned oh_flags)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(oh);
+
+ /* Unpin the other chunks */
+ if(oh->chunks_pinned && oh->nchunks > 1) {
+ unsigned u; /* Local index variable */
+
+ /* Sanity check */
+ HDassert(oh->swmr_write);
+
+ /* Iterate over chunks > 0 */
+ for(u = 1; u < oh->nchunks; u++) {
+ if(NULL != oh->chunk[u].chunk_proxy) {
+ /* Release chunk proxy */
+ if(H5AC_unpin_entry(oh->chunk[u].chunk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header chunk")
+ oh->chunk[u].chunk_proxy = NULL;
+ } /* end if */
+ } /* end for */
+
+ /* Reet the flag from the unprotect */
+ oh->chunks_pinned = FALSE;
+ } /* end if */
+
+ /* Unprotect the object header */
+ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, oh->chunk[0].addr, oh, oh_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_touch_oh
+ *
+ * Purpose: If FORCE is non-zero then create a modification time message
+ * unless one already exists. Then update any existing
+ * modification time message with the current time.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ time_t now; /* Current time */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(f);
+ HDassert(oh);
+
+ /* Check if this object header is tracking times */
+ if(oh->flags & H5O_HDR_STORE_TIMES) {
+ /* Get current time */
+ now = H5_now();
+
+ /* Check version, to determine how to store time information */
+ if(oh->version == H5O_VERSION_1) {
+ size_t idx; /* Index of modification time message to update */
+
+ /* Look for existing message */
+ for(idx = 0; idx < oh->nmesgs; idx++)
+ if(H5O_MSG_MTIME == oh->mesg[idx].type || H5O_MSG_MTIME_NEW == oh->mesg[idx].type)
+ break;
+
+ /* Create a new message, if necessary */
+ if(idx == oh->nmesgs) {
+ unsigned mesg_flags = 0; /* Flags for message in object header */
+
+ /* If we would have to create a new message, but we aren't 'forcing' it, get out now */
+ if(!force)
+ HGOTO_DONE(SUCCEED); /*nothing to do*/
+
+ /* Allocate space for the modification time message */
+ if(H5O_msg_alloc(f, dxpl_id, oh, H5O_MSG_MTIME_NEW, &mesg_flags, &now, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message")
+
+ /* Set the message's flags if appropriate */
+ oh->mesg[idx].flags = (uint8_t)mesg_flags;
+ } /* end if */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, oh->mesg[idx].chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Allocate 'native' space, if necessary */
+ if(NULL == oh->mesg[idx].native) {
+ if(NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for modification time message")
+ } /* end if */
+
+ /* Update the message */
+ *((time_t *)(oh->mesg[idx].native)) = now;
+
+ /* Mark the message as dirty */
+ oh->mesg[idx].dirty = TRUE;
+ chk_dirtied = TRUE;
+ } /* end if */
+ else {
+ /* XXX: For now, update access time & change fields in the object header */
+ /* (will need to add some code to update modification time appropriately) */
+ oh->atime = oh->ctime = now;
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Release chunk */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_touch_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_touch
+ *
+ * Purpose: Touch an object by setting the modification time to the
+ * current time and marking the object as dirty. Unless FORCE
+ * is non-zero, nothing happens if there is no MTIME message in
+ * the object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, July 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header to modify */
+ unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Create/Update the modification time message */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, force) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to update object modificaton time")
+
+ /* Mark object header as changed */
+ oh_flags |= H5AC__DIRTIED_FLAG;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, oh_flags) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_touch() */
+
+#ifdef H5O_ENABLE_BOGUS
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_bogus_oh
+ *
+ * Purpose: Create a "bogus" message unless one already exists.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * <koziol@ncsa.uiuc.edu>
+ * Tuesday, January 21, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_bogus_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned bogus_id, unsigned mesg_flags)
+{
+ size_t idx; /* Local index variable */
+ H5O_msg_class_t *type; /* Message class type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(oh);
+
+ /* Look for existing message */
+ for(idx = 0; idx < oh->nmesgs; idx++)
+ if(H5O_MSG_BOGUS_VALID == oh->mesg[idx].type ||
+ H5O_MSG_BOGUS_INVALID == oh->mesg[idx].type)
+ break;
+
+ /* Create a new message */
+ if(idx == oh->nmesgs) {
+ H5O_bogus_t *bogus; /* Pointer to the bogus information */
+
+ /* Allocate the native message in memory */
+ if(NULL == (bogus = H5MM_malloc(sizeof(H5O_bogus_t))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for 'bogus' message")
+
+ /* Update the native value */
+ bogus->u = H5O_BOGUS_VALUE;
+
+ if(bogus_id == H5O_BOGUS_VALID_ID)
+ type = H5O_MSG_BOGUS_VALID;
+ else if(bogus_id == H5O_BOGUS_INVALID_ID)
+ type = H5O_MSG_BOGUS_INVALID;
+ else
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID for 'bogus' message")
+
+ /* Allocate space in the object header for bogus message */
+ if(H5O_msg_alloc(f, dxpl_id, oh, type, &mesg_flags, bogus, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for 'bogus' message")
+
+ /* Point to "bogus" information (take it over) */
+ oh->mesg[idx].native = bogus;
+
+ /* Set the appropriate flags for the message */
+ oh->mesg[idx].flags = mesg_flags;
+
+ /* Mark the message and object header as dirty */
+ oh->mesg[idx].dirty = TRUE;
+ oh->cache_info.is_dirty = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_bogus_oh() */
+#endif /* H5O_ENABLE_BOGUS */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_delete
+ *
+ * Purpose: Delete an object header from a file. This frees the file
+ * space used for the object header (and it's continuation blocks)
+ * and also walks through each header message and asks it to
+ * remove all the pieces of the file referenced by the header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 19 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)
+{
+ H5O_t *oh = NULL; /* Object header information */
+ H5O_loc_t loc; /* Object location for object to delete */
+ unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting object header */
+ hbool_t corked;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, addr, FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+
+ /* Set up the object location */
+ loc.file = f;
+ loc.addr = addr;
+ loc.holding_file = FALSE;
+
+ /* Get the object header information */
+ if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC__NO_FLAGS_SET, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Delete object */
+ if(H5O_delete_oh(f, dxpl_id, oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file")
+
+ /* Uncork cache entries with tag: addr */
+ if(H5AC_cork(f, addr, H5AC__GET_CORKED, &corked) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status")
+ if(corked)
+ if(H5AC_cork(f, addr, H5AC__UNCORK, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNCORK, FAIL, "unable to uncork an object")
+
+ /* Mark object header as deleted */
+ oh_flags = H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+done:
+ if(oh && H5O_unprotect(&loc, dxpl_id, oh, oh_flags) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_delete_oh
+ *
+ * Purpose: Internal function to:
+ * Delete an object header from a file. This frees the file
+ * space used for the object header (and it's continuation blocks)
+ * and also walks through each header message and asks it to
+ * remove all the pieces of the file referenced by the header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 19 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ unsigned u;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Walk through the list of object header messages, asking each one to
+ * delete any file space used
+ */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ /* Free any space referred to in the file from this message */
+ if(H5O_delete_mesg(f, dxpl_id, oh, curr_msg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message")
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_delete_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_obj_type
+ *
+ * Purpose: Retrieves the type of object pointed to by `loc'.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, November 4, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header for location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Load the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Retrieve the type of the object */
+ if(H5O_obj_type_real(oh, obj_type) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_obj_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_obj_type_real
+ *
+ * Purpose: Returns the type of object pointed to by `oh'.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_obj_type_real(H5O_t *oh, H5O_type_t *obj_type)
+{
+ const H5O_obj_class_t *obj_class; /* Class of object for header */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(oh);
+ HDassert(obj_type);
+
+ /* Look up class for object header */
+ if(NULL == (obj_class = H5O_obj_class_real(oh))) {
+ /* Clear error stack from "failed" class lookup */
+ H5E_clear_stack(NULL);
+
+ /* Set type to "unknown" */
+ *obj_type = H5O_TYPE_UNKNOWN;
+ } /* end if */
+ else {
+ /* Set object type */
+ *obj_type = obj_class->type;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_obj_type_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_obj_class
+ *
+ * Purpose: Returns the class of object pointed to by `loc'.
+ *
+ * Return: Success: An object class
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+const H5O_obj_class_t *
+H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header for location */
+ const H5O_obj_class_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, NULL)
+
+ /* Load the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header")
+
+ /* Test whether entry qualifies as a particular type of object */
+ if(NULL == (ret_value = H5O_obj_class_real(oh)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to determine object type")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_obj_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_obj_class_real
+ *
+ * Purpose: Returns the class of object pointed to by `oh'.
+ *
+ * Return: Success: An object class
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static const H5O_obj_class_t *
+H5O_obj_class_real(H5O_t *oh)
+{
+ size_t i; /* Local index variable */
+ const H5O_obj_class_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(oh);
+
+ /* Test whether entry qualifies as a particular type of object */
+ /* (Note: loop is in reverse order, to test specific objects first) */
+ for(i = NELMTS(H5O_obj_class_g); i > 0; --i) {
+ htri_t isa; /* Is entry a particular type? */
+
+ if((isa = (H5O_obj_class_g[i - 1]->isa)(oh)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to determine object type")
+ else if(isa)
+ HGOTO_DONE(H5O_obj_class_g[i - 1])
+ } /* end for */
+
+ if(0 == i)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to determine object type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_obj_class_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_loc
+ *
+ * Purpose: Gets the object location for an object given its ID.
+ *
+ * Return: Success: Pointer to H5O_loc_t
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * July 25 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_loc_t *
+H5O_get_loc(hid_t object_id)
+{
+ H5O_loc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ switch(H5I_get_type(object_id)) {
+ case H5I_GROUP:
+ if(NULL == (ret_value = H5O_OBJ_GROUP->get_oloc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from group ID")
+ break;
+
+ case H5I_DATASET:
+ if(NULL == (ret_value = H5O_OBJ_DATASET->get_oloc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from dataset ID")
+ break;
+
+ case H5I_DATATYPE:
+ if(NULL == (ret_value = H5O_OBJ_DATATYPE->get_oloc(object_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from datatype ID")
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, NULL, "invalid object type")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_loc_reset
+ *
+ * Purpose: Reset a object location to an empty state
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_loc_reset(H5O_loc_t *loc)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(loc);
+
+ /* Clear the object location to an empty state */
+ HDmemset(loc, 0, sizeof(H5O_loc_t));
+ loc->addr = HADDR_UNDEF;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_loc_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_loc_copy
+ *
+ * Purpose: Copy object location information
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Monday, September 19, 2005
+ *
+ * Notes: 'depth' parameter determines how much of the group entry
+ * structure we want to copy. The values are:
+ * H5_COPY_SHALLOW - Copy all the field values from the source
+ * to the destination, but not copying objects pointed to.
+ * (Destination "takes ownership" of objects pointed to)
+ * H5_COPY_DEEP - Copy all the fields from the source to
+ * the destination, deep copying objects pointed to.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_loc_copy(H5O_loc_t *dst, H5O_loc_t *src, H5_copy_depth_t depth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(src);
+ HDassert(dst);
+ HDassert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP);
+
+ /* Copy the top level information */
+ HDmemcpy(dst, src, sizeof(H5O_loc_t));
+
+ /* Deep copy the names */
+ if(depth == H5_COPY_DEEP) {
+ /* If the original entry was holding open the file, this one should
+ * hold it open, too.
+ */
+ if(src->holding_file)
+ H5F_INCR_NOPEN_OBJS(dst->file);
+ } else if(depth == H5_COPY_SHALLOW) {
+ H5O_loc_reset(src);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_loc_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_loc_hold_file
+ *
+ * Purpose: Have this object header hold a file open until it is
+ * released.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Wednesday, August 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_loc_hold_file(H5O_loc_t *loc)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(loc->file);
+
+ /* If this location is not already holding its file open, do so. */
+ if(!loc->holding_file) {
+ H5F_INCR_NOPEN_OBJS(loc->file);
+ loc->holding_file = TRUE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_loc_hold_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_loc_free
+ *
+ * Purpose: Release resources used by this object header location.
+ * Not to be confused with H5O_close; this is used on
+ * locations that don't correspond to open objects.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Wednesday, August 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_loc_free(H5O_loc_t *loc)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+
+ /* If this location is holding its file open try to close the file. */
+ if(loc->holding_file) {
+ H5F_DECR_NOPEN_OBJS(loc->file);
+ loc->holding_file = FALSE;
+ if(H5F_NOPEN_OBJS(loc->file) <= 0) {
+ if(H5F_try_close(loc->file, NULL) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_loc_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_hdr_info
+ *
+ * Purpose: Retrieve the object header information for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * September 22 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_hdr_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_hdr_info_t *hdr)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(hdr);
+
+ /* Reset the object header info structure */
+ HDmemset(hdr, 0, sizeof(*hdr));
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header")
+
+ /* Get the information for the object header */
+ if(H5O_get_hdr_info_real(oh, hdr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object header info")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_hdr_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_hdr_info_real
+ *
+ * Purpose: Internal routine to retrieve the object header information for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * September 22 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_get_hdr_info_real(const H5O_t *oh, H5O_hdr_info_t *hdr)
+{
+ const H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ const H5O_chunk_t *curr_chunk; /* Pointer to current message being operated on */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(oh);
+ HDassert(hdr);
+
+ /* Set the version for the object header */
+ hdr->version = oh->version;
+
+ /* Set the number of messages & chunks */
+ H5_CHECKED_ASSIGN(hdr->nmesgs, unsigned, oh->nmesgs, size_t);
+ H5_CHECKED_ASSIGN(hdr->nchunks, unsigned, oh->nchunks, size_t);
+
+ /* Set the status flags */
+ hdr->flags = oh->flags;
+
+ /* Iterate over all the messages, accumulating message size & type information */
+ hdr->space.meta = (hsize_t)H5O_SIZEOF_HDR(oh) + (hsize_t)(H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1));
+ hdr->space.mesg = 0;
+ hdr->space.free = 0;
+ hdr->mesg.present = 0;
+ hdr->mesg.shared = 0;
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ uint64_t type_flag; /* Flag for message type */
+
+ /* Accumulate space usage information, based on the type of message */
+ if(H5O_NULL_ID == curr_msg->type->id)
+ hdr->space.free += (hsize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size);
+ else if(H5O_CONT_ID == curr_msg->type->id)
+ hdr->space.meta += (hsize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size);
+ else {
+ hdr->space.meta += (hsize_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ hdr->space.mesg += curr_msg->raw_size;
+ } /* end else */
+
+ /* Set flag to indicate presence of message type */
+ type_flag = ((uint64_t)1) << curr_msg->type->id;
+ hdr->mesg.present |= type_flag;
+
+ /* Set flag if the message is shared in some way */
+ if(curr_msg->flags & H5O_MSG_FLAG_SHARED) \
+ hdr->mesg.shared |= type_flag;
+ } /* end for */
+
+ /* Iterate over all the chunks, adding any gaps to the free space */
+ hdr->space.total = 0;
+ for(u = 0, curr_chunk = &oh->chunk[0]; u < oh->nchunks; u++, curr_chunk++) {
+ /* Accumulate the size of the header on disk */
+ hdr->space.total += curr_chunk->size;
+
+ /* If the chunk has a gap, add it to the free space */
+ hdr->space.free += curr_chunk->gap;
+ } /* end for */
+
+ /* Sanity check that all the bytes are accounted for */
+ HDassert(hdr->space.total == (hdr->space.free + hdr->space.meta + hdr->space.mesg));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_get_hdr_info_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_info
+ *
+ * Purpose: Retrieve the information for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 21 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_info(const H5O_loc_t *loc, hid_t dxpl_id, hbool_t want_ih_info,
+ H5O_info_t *oinfo)
+{
+ const H5O_obj_class_t *obj_class; /* Class of object for header */
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(oinfo);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Reset the object info structure */
+ HDmemset(oinfo, 0, sizeof(*oinfo));
+
+ /* Retrieve the file's fileno */
+ H5F_GET_FILENO(loc->file, oinfo->fileno);
+
+ /* Set the object's address */
+ oinfo->addr = loc->addr;
+
+ /* Get class for object */
+ if(NULL == (obj_class = H5O_obj_class_real(oh)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object class")
+
+ /* Retrieve the type of the object */
+ oinfo->type = obj_class->type;
+
+ /* Set the object's reference count */
+ oinfo->rc = oh->nlink;
+
+ /* Get modification time for object */
+ if(oh->version > H5O_VERSION_1) {
+ oinfo->atime = oh->atime;
+ oinfo->mtime = oh->mtime;
+ oinfo->ctime = oh->ctime;
+ oinfo->btime = oh->btime;
+ } /* end if */
+ else {
+ htri_t exists; /* Flag if header message of interest exists */
+
+ /* No information for access & modification fields */
+ /* (we stopped updating the "modification time" header message for
+ * raw data changes, so the "modification time" header message
+ * is closest to the 'change time', in POSIX terms - QAK)
+ */
+ oinfo->atime = 0;
+ oinfo->mtime = 0;
+ oinfo->btime = 0;
+
+ /* Might be information for modification time */
+ if((exists = H5O_msg_exists_oh(oh, H5O_MTIME_ID)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "unable to check for MTIME message")
+ if(exists > 0) {
+ /* Get "old style" modification time info */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_MTIME_ID, &oinfo->ctime))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read MTIME message")
+ } /* end if */
+ else {
+ /* Check for "new style" modification time info */
+ if((exists = H5O_msg_exists_oh(oh, H5O_MTIME_NEW_ID)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "unable to check for MTIME_NEW message")
+ if(exists > 0) {
+ /* Get "new style" modification time info */
+ if(NULL == H5O_msg_read_oh(loc->file, dxpl_id, oh, H5O_MTIME_NEW_ID, &oinfo->ctime))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read MTIME_NEW message")
+ } /* end if */
+ else
+ oinfo->ctime = 0;
+ } /* end else */
+ } /* end else */
+
+ /* Get the information for the object header */
+ if(H5O_get_hdr_info_real(oh, &oinfo->hdr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object header info")
+
+ /* Retrieve # of attributes */
+ if(H5O_attr_count_real(loc->file, dxpl_id, oh, &oinfo->num_attrs) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve attribute count")
+
+ /* Get B-tree & heap metadata storage size, if requested */
+ if(want_ih_info) {
+ /* Check for 'bh_info' callback for this type of object */
+ if(obj_class->bh_info) {
+ /* Call the object's class 'bh_info' routine */
+ if((obj_class->bh_info)(loc, dxpl_id, oh, &oinfo->meta_size.obj) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object's btree & heap info")
+ } /* end if */
+
+ /* Get B-tree & heap info for any attributes */
+ if(oinfo->num_attrs > 0) {
+ if(H5O_attr_bh_info(loc->file, dxpl_id, oh, &oinfo->meta_size.attr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve attribute btree & heap info")
+ } /* end if */
+ } /* end if */
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_create_plist
+ *
+ * Purpose: Retrieve the object creation properties for an object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 28 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_create_plist(const H5O_loc_t *loc, hid_t dxpl_id, H5P_genplist_t *oc_plist)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(oc_plist);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Set property values, if they were used for the object */
+ if(oh->version > H5O_VERSION_1) {
+ uint8_t ohdr_flags; /* "User-visible" object header status flags */
+
+ /* Set attribute storage values */
+ if(H5P_set(oc_plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &oh->max_compact) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set max. # of compact attributes in property list")
+ if(H5P_set(oc_plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &oh->min_dense) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set min. # of dense attributes in property list")
+
+ /* Mask off non-"user visible" flags */
+ ohdr_flags = oh->flags & (H5O_HDR_ATTR_CRT_ORDER_TRACKED | H5O_HDR_ATTR_CRT_ORDER_INDEXED | H5O_HDR_STORE_TIMES);
+
+ /* Set object header flags */
+ if(H5P_set(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object header flags")
+ } /* end if */
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_nlinks
+ *
+ * Purpose: Retrieve the number of link messages read in from the file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * March 11 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_nlinks(const H5O_loc_t *loc, hid_t dxpl_id, hsize_t *nlinks)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(nlinks);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Retrieve the # of link messages seen when the object header was loaded */
+ *nlinks = oh->link_msgs_seen;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_nlinks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_obj_create
+ *
+ * Purpose: Creates an object, in an abstract manner.
+ *
+ * Return: Success: Pointer to object opened
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * April 9 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_obj_create(H5F_t *f, H5O_type_t obj_type, void *crt_info, H5G_loc_t *obj_loc,
+ hid_t dxpl_id)
+{
+ size_t u; /* Local index variable */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(obj_type >= H5O_TYPE_GROUP && obj_type <= H5O_TYPE_NAMED_DATATYPE);
+ HDassert(crt_info);
+ HDassert(obj_loc);
+
+ /* Iterate through the object classes */
+ for(u = 0; u < NELMTS(H5O_obj_class_g); u++) {
+ /* Check for correct type of object to create */
+ if(H5O_obj_class_g[u]->type == obj_type) {
+ /* Call the object class's 'create' routine */
+ HDassert(H5O_obj_class_g[u]->create);
+ if(NULL == (ret_value = H5O_obj_class_g[u]->create(f, crt_info, obj_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object")
+
+ /* Break out of loop */
+ break;
+ } /* end if */
+ } /* end for */
+ HDassert(ret_value);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_obj_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_oh_addr
+ *
+ * Purpose: Retrieve the address of the object header
+ *
+ * Note: This routine participates in the "Inlining C struct access"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Oprivate.h.
+ *
+ * Return: Success: Valid haddr_t
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Quincey Koziol
+ * March 15 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5O_get_oh_addr(const H5O_t *oh)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(oh);
+ HDassert(oh->chunk);
+
+ FUNC_LEAVE_NOAPI(oh->chunk[0].addr)
+} /* end H5O_get_oh_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_rc_and_type
+ *
+ * Purpose: Retrieve an object's reference count and type
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_rc_and_type(const H5O_loc_t *loc, hid_t dxpl_id, unsigned *rc, H5O_type_t *otype)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Set the object's reference count */
+ if(rc)
+ *rc = oh->nlink;
+
+ /* Retrieve the type of the object */
+ if(otype)
+ if(H5O_obj_type_real(oh, otype) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_rc_and_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_free_visit_visited
+ *
+ * Purpose: Free the key for an object visited during a group traversal
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Nov 25, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_free_visit_visited(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *operator_data/*in,out*/)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ item = H5FL_FREE(H5_obj_t, item);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_free_visit_visited() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_visit_cb
+ *
+ * Purpose: Callback function for recursively visiting objects from a group
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Nov 25, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_visit_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info_t *linfo,
+ void *_udata)
+{
+ H5O_iter_visit_ud_t *udata = (H5O_iter_visit_ud_t *)_udata; /* User data for callback */
+ H5G_loc_t obj_loc; /* Location of object */
+ H5G_name_t obj_path; /* Object's group hier. path */
+ H5O_loc_t obj_oloc; /* Object's object location */
+ hbool_t obj_found = FALSE; /* Object at 'name' found */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(name);
+ HDassert(linfo);
+ HDassert(udata);
+
+ /* Check if this is a hard link */
+ if(linfo->type == H5L_TYPE_HARD) {
+ H5_obj_t obj_pos; /* Object "position" for this object */
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object using the LAPL passed in */
+ /* (Correctly handles mounted files) */
+ if(H5G_loc_find(udata->start_loc, name, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+ obj_found = TRUE;
+
+ /* Construct unique "position" for this object */
+ H5F_GET_FILENO(obj_oloc.file, obj_pos.fileno);
+ obj_pos.addr = obj_oloc.addr;
+
+ /* Check if we've seen the object the link references before */
+ if(NULL == H5SL_search(udata->visited, &obj_pos)) {
+ H5O_info_t oinfo; /* Object info */
+
+ /* Get the object's info */
+ if(H5O_get_info(&obj_oloc, udata->dxpl_id, TRUE, &oinfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info")
+
+ /* Make the application callback */
+ ret_value = (udata->op)(udata->obj_id, name, &oinfo, udata->op_data);
+
+ /* Check for continuing to visit objects */
+ if(ret_value == H5_ITER_CONT) {
+ /* If its ref count is > 1, we add it to the list of visited objects */
+ /* (because it could come up again during traversal) */
+ if(oinfo.rc > 1) {
+ H5_obj_t *new_node; /* New object node for visited list */
+
+ /* Allocate new object "position" node */
+ if((new_node = H5FL_MALLOC(H5_obj_t)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate object node")
+
+ /* Set node information */
+ *new_node = obj_pos;
+
+ /* Add to list of visited objects */
+ if(H5SL_insert(udata->visited, new_node, new_node) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert object node into visited list")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(obj_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_visit_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_visit
+ *
+ * Purpose: Recursively visit an object and all the objects reachable
+ * from it. If the starting object is a group, all the objects
+ * linked to from that group will be visited. Links within
+ * each group are visited according to the order within the
+ * specified index (unless the specified index does not exist for
+ * a particular group, then the "name" index is used).
+ *
+ * NOTE: Soft links and user-defined links are ignored during
+ * this operation.
+ *
+ * NOTE: Each _object_ reachable from the initial group will only
+ * be visited once. If multiple hard links point to the same
+ * object, the first link to the object's path (according to the
+ * iteration index and iteration order given) will be used to in
+ * the callback about the object.
+ *
+ * Return: Success: The return value of the first operator that
+ * returns non-zero, or zero if all members were
+ * processed with no operator returning non-zero.
+ *
+ * Failure: Negative if something goes wrong within the
+ * library, or the negative value returned by one
+ * of the operators.
+ *
+ * Programmer: Quincey Koziol
+ * November 24 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_visit(hid_t loc_id, const char *obj_name, H5_index_t idx_type,
+ H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id,
+ hid_t dxpl_id)
+{
+ H5O_iter_visit_ud_t udata; /* User data for callback */
+ H5G_loc_t loc; /* Location of reference object */
+ H5G_loc_t obj_loc; /* Location used to open object */
+ H5G_name_t obj_path; /* Opened object group hier. path */
+ H5O_loc_t obj_oloc; /* Opened object object location */
+ hbool_t loc_found = FALSE; /* Entry at 'name' found */
+ H5O_info_t oinfo; /* Object info struct */
+ hid_t obj_id = (-1); /* ID of object */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Portably initialize user data struct to zeros */
+ HDmemset(&udata, 0, sizeof(udata));
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object's location */
+ if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found")
+ loc_found = TRUE;
+
+ /* Get the object's info */
+ if(H5O_get_info(&obj_oloc, dxpl_id, TRUE, &oinfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get object info")
+
+ /* Open the object */
+ /* (Takes ownership of the obj_loc information) */
+ if((obj_id = H5O_open_by_loc(&obj_loc, lapl_id, dxpl_id, TRUE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+
+ /* Make callback for starting object */
+ if((ret_value = op(obj_id, ".", &oinfo, op_data)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "can't visit objects")
+
+ /* Check return value of first callback */
+ if(ret_value != H5_ITER_CONT)
+ HGOTO_DONE(ret_value);
+
+ /* Check for object being a group */
+ if(oinfo.type == H5O_TYPE_GROUP) {
+ H5G_loc_t start_loc; /* Location of starting group */
+
+ /* Get the location of the starting group */
+ if(H5G_loc(obj_id, &start_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Set up user data for visiting links */
+ udata.obj_id = obj_id;
+ udata.start_loc = &start_loc;
+ udata.lapl_id = lapl_id;
+ udata.dxpl_id = dxpl_id;
+ udata.op = op;
+ udata.op_data = op_data;
+
+ /* Create skip list to store visited object information */
+ if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, NULL)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects")
+
+ /* If its ref count is > 1, we add it to the list of visited objects */
+ /* (because it could come up again during traversal) */
+ if(oinfo.rc > 1) {
+ H5_obj_t *obj_pos; /* New object node for visited list */
+
+ /* Allocate new object "position" node */
+ if((obj_pos = H5FL_MALLOC(H5_obj_t)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "can't allocate object node")
+
+ /* Construct unique "position" for this object */
+ obj_pos->fileno = oinfo.fileno;
+ obj_pos->addr = oinfo.addr;
+
+ /* Add to list of visited objects */
+ if(H5SL_insert(udata.visited, obj_pos, obj_pos) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object node into visited list")
+ } /* end if */
+
+ /* Call internal group visitation routine */
+ if((ret_value = H5G_visit(obj_id, ".", idx_type, order, H5O_visit_cb, &udata, lapl_id, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed")
+ } /* end if */
+
+done:
+ if(obj_id > 0) {
+ if(H5I_dec_app_ref(obj_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close object")
+ } /* end if */
+ else if(loc_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
+ if(udata.visited)
+ H5SL_destroy(udata.visited, H5O_free_visit_visited, NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_visit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_inc_rc
+ *
+ * Purpose: Increments the reference count on an object header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_inc_rc(H5O_t *oh)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh);
+
+ /* Pin the object header when the reference count goes above 0 */
+ if(oh->rc == 0)
+ if(H5AC_pin_protected_entry(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Increment reference count */
+ oh->rc++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_inc_rc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dec_rc
+ *
+ * Purpose: Decrements the reference count on an object header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_dec_rc(H5O_t *oh)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh);
+
+ /* Decrement reference count */
+ oh->rc--;
+
+ /* Unpin the object header when the reference count goes back to 0 */
+ if(oh->rc == 0)
+ if(H5AC_unpin_entry(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dec_rc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dec_rc_by_loc
+ *
+ * Purpose: Decrement the refcount of an object header, using its
+ * object location information.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 08 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_dec_rc_by_loc(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+
+ /* Get header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Decrement the reference count on the object header */
+ /* (which will unpin it, if appropriate) */
+ if(H5O_dec_rc(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement reference count on object header")
+
+done:
+ /* Release the object header from the cache */
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dec_rc_by_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_get_proxy
+ *
+ * Purpose: Retrieve the proxy for the object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * July 24 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+H5AC_proxy_entry_t *
+H5O_get_proxy(const H5O_t *oh)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(oh);
+
+ FUNC_LEAVE_NOAPI(oh->proxy)
+} /* end H5O_get_proxy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__free
+ *
+ * Purpose: Destroys an object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 15 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O__free(H5O_t *oh)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(oh);
+ HDassert(0 == oh->rc);
+
+ /* Destroy chunks */
+ if(oh->chunk) {
+ for(u = 0; u < oh->nchunks; u++)
+ oh->chunk[u].image = H5FL_BLK_FREE(chunk_image, oh->chunk[u].image);
+
+ oh->chunk = (H5O_chunk_t *)H5FL_SEQ_FREE(H5O_chunk_t, oh->chunk);
+ } /* end if */
+
+ /* Destroy messages */
+ if(oh->mesg) {
+ for(u = 0; u < oh->nmesgs; u++) {
+#ifndef NDEBUG
+ /* Verify that message is clean, unless it could have been marked
+ * dirty by decoding */
+ if(oh->ndecode_dirtied && oh->mesg[u].dirty)
+ oh->ndecode_dirtied--;
+ else
+ HDassert(oh->mesg[u].dirty == 0);
+#endif /* NDEBUG */
+
+ H5O_msg_free_mesg(&oh->mesg[u]);
+ } /* end for */
+
+ /* Make sure we accounted for all the messages dirtied by decoding */
+ HDassert(!oh->ndecode_dirtied);
+
+ oh->mesg = (H5O_mesg_t *)H5FL_SEQ_FREE(H5O_mesg_t, oh->mesg);
+ } /* end if */
+
+ /* Destroy the proxy */
+ if(oh->proxy)
+ if(H5AC_proxy_entry_dest(oh->proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy virtual entry used for proxy")
+
+ /* destroy object header */
+ oh = H5FL_FREE(H5O_t, oh);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__free() */
+
diff --git a/src/H5Oainfo.c b/src/H5Oainfo.c
new file mode 100644
index 0000000..d8298a4
--- /dev/null
+++ b/src/H5Oainfo.c
@@ -0,0 +1,543 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oainfo.c
+ * Mar 6 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Attribute Information messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5A_FRIEND /*suppress error about including H5Apkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_ainfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_ainfo_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_ainfo_copy(const void *_mesg, void *_dest);
+static size_t H5O_ainfo_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_ainfo_free(void *_mesg);
+static herr_t H5O_ainfo_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ void *_mesg);
+static herr_t H5O_ainfo_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata);
+static void *H5O_ainfo_copy_file(H5F_t *file_src, void *mesg_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_ainfo_post_copy_file(const H5O_loc_t *src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst,
+ unsigned *mesg_flags, hid_t dxpl_id, H5O_copy_t *cpy_info);
+static herr_t H5O_ainfo_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_AINFO[1] = {{
+ H5O_AINFO_ID, /*message id number */
+ "ainfo", /*message name for debugging */
+ sizeof(H5O_ainfo_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_ainfo_decode, /*decode message */
+ H5O_ainfo_encode, /*encode message */
+ H5O_ainfo_copy, /*copy the native value */
+ H5O_ainfo_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_ainfo_free, /* free method */
+ H5O_ainfo_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ H5O_ainfo_pre_copy_file, /* pre copy native value to file */
+ H5O_ainfo_copy_file, /* copy native value to file */
+ H5O_ainfo_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_ainfo_debug /*debug the message */
+}};
+
+/* Current version of attribute info information */
+#define H5O_AINFO_VERSION 0
+
+/* Flags for attribute info flag encoding */
+#define H5O_AINFO_TRACK_CORDER 0x01
+#define H5O_AINFO_INDEX_CORDER 0x02
+#define H5O_AINFO_ALL_FLAGS (H5O_AINFO_TRACK_CORDER | H5O_AINFO_INDEX_CORDER)
+
+/* Declare a free list to manage the H5O_ainfo_t struct */
+H5FL_DEFINE_STATIC(H5O_ainfo_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_decode
+ *
+ * Purpose: Decode a message and return a pointer to a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native form.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_ainfo_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_ainfo_t *ainfo = NULL; /* Attribute info */
+ unsigned char flags; /* Flags for encoding attribute info */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_AINFO_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (ainfo = H5FL_MALLOC(H5O_ainfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get the flags for the message */
+ flags = *p++;
+ if(flags & ~H5O_AINFO_ALL_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message")
+ ainfo->track_corder = (flags & H5O_AINFO_TRACK_CORDER) ? TRUE : FALSE;
+ ainfo->index_corder = (flags & H5O_AINFO_INDEX_CORDER) ? TRUE : FALSE;
+
+ /* Set the number of attributes on the object to an invalid value, so we query it later */
+ ainfo->nattrs = HSIZET_MAX;
+
+ /* Max. creation order value for the object */
+ if(ainfo->track_corder)
+ UINT16DECODE(p, ainfo->max_crt_idx)
+ else
+ ainfo->max_crt_idx = H5O_MAX_CRT_ORDER_IDX;
+
+ /* Address of fractal heap to store "dense" attributes */
+ H5F_addr_decode(f, &p, &(ainfo->fheap_addr));
+
+ /* Address of v2 B-tree to index names of attributes (names are always indexed) */
+ H5F_addr_decode(f, &p, &(ainfo->name_bt2_addr));
+
+ /* Address of v2 B-tree to index creation order of links, if there is one */
+ if(ainfo->index_corder)
+ H5F_addr_decode(f, &p, &(ainfo->corder_bt2_addr));
+ else
+ ainfo->corder_bt2_addr = HADDR_UNDEF;
+
+ /* Set return value */
+ ret_value = ainfo;
+
+done:
+ if(ret_value == NULL && ainfo != NULL)
+ ainfo = H5FL_FREE(H5O_ainfo_t, ainfo);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ainfo_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_ainfo_t *ainfo = (const H5O_ainfo_t *)_mesg;
+ unsigned char flags; /* Flags for encoding attribute info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(ainfo);
+
+ /* Message version */
+ *p++ = H5O_AINFO_VERSION;
+
+ /* The flags for the attribute indices */
+ flags = ainfo->track_corder ? H5O_AINFO_TRACK_CORDER : 0;
+ flags = (unsigned char)(flags | (ainfo->index_corder ? H5O_AINFO_INDEX_CORDER : 0));
+ *p++ = flags;
+
+ /* Max. creation order value for the object */
+ if(ainfo->track_corder)
+ UINT16ENCODE(p, ainfo->max_crt_idx);
+
+ /* Address of fractal heap to store "dense" attributes */
+ H5F_addr_encode(f, &p, ainfo->fheap_addr);
+
+ /* Address of v2 B-tree to index names of attributes */
+ H5F_addr_encode(f, &p, ainfo->name_bt2_addr);
+
+ /* Address of v2 B-tree to index creation order of attributes, if they are indexed */
+ if(ainfo->index_corder)
+ H5F_addr_encode(f, &p, ainfo->corder_bt2_addr);
+ else
+ HDassert(!H5F_addr_defined(ainfo->corder_bt2_addr));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ainfo_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_ainfo_copy(const void *_mesg, void *_dest)
+{
+ const H5O_ainfo_t *ainfo = (const H5O_ainfo_t *)_mesg;
+ H5O_ainfo_t *dest = (H5O_ainfo_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(ainfo);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_ainfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *ainfo;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ainfo_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_ainfo_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_ainfo_t *ainfo = (const H5O_ainfo_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)(1 /* Version */
+ + 1 /* Index flags */
+ + (ainfo->track_corder ? 2 : 0) /* Curr. max. creation order value */
+ + H5F_SIZEOF_ADDR(f) /* Address of fractal heap to store "dense" attributes */
+ + H5F_SIZEOF_ADDR(f) /* Address of v2 B-tree for indexing names of attributes */
+ + (ainfo->index_corder ? H5F_SIZEOF_ADDR(f) : 0)); /* Address of v2 B-tree for indexing creation order values of attributes */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ainfo_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_ainfo_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ainfo_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_delete
+ *
+ * Purpose: Free file space referenced by message. Note that open_oh
+ * *must* be non-NULL - this means that calls to
+ * H5O_msg_delete must include an oh if the type is ainfo.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_ainfo_t *ainfo = (H5O_ainfo_t *)_mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(open_oh);
+
+ /* If the object is using "dense" attribute storage, delete it */
+ if(H5F_addr_defined(ainfo->fheap_addr)) {
+ /* Delete the attribute */
+ if(H5A_dense_delete(f, dxpl_id, ainfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free dense attribute storage")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ainfo_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 9, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(deleted);
+ HDassert(cpy_info);
+
+ /* If we are not copying attributes into the destination file, indicate
+ * that this message should be deleted.
+ */
+ if(cpy_info->copy_without_attr)
+ *deleted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ainfo_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Peter Cao
+ * July 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_ainfo_copy_file(H5F_t *file_src, void *mesg_src, H5F_t *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata, hid_t dxpl_id)
+{
+ H5O_ainfo_t *ainfo_src = (H5O_ainfo_t *)mesg_src;
+ H5O_ainfo_t *ainfo_dst = NULL;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(file_src);
+ HDassert(ainfo_src);
+ HDassert(file_dst);
+ HDassert(cpy_info);
+ HDassert(!cpy_info->copy_without_attr);
+
+ /* Allocate space for the destination message */
+ if(NULL == (ainfo_dst = H5FL_MALLOC(H5O_ainfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the top level of the information */
+ *ainfo_dst = *ainfo_src;
+
+ if(H5F_addr_defined(ainfo_src->fheap_addr)) {
+ /* Prepare to copy dense attributes - actual copy in post_copy */
+
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(dxpl_id, H5AC__COPIED_TAG, NULL);
+
+ if(H5A_dense_create(file_dst, dxpl_id, ainfo_dst) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINIT, NULL, "unable to create dense storage for attributes")
+
+ /* Reset metadata tag */
+ H5_END_TAG(NULL);
+ } /* end if */
+
+ /* Set return value */
+ ret_value = ainfo_dst;
+
+done:
+ /* Release destination attribute information on failure */
+ if(!ret_value && ainfo_dst)
+ ainfo_dst = H5FL_FREE(H5O_ainfo_t, ainfo_dst);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_ainfo_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files.
+ * We have to copy the values of a reference attribute in the
+ * post copy because H5O_post_copy_file() fails in the case that
+ * an object may have a reference attribute that points to the
+ * object itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * July 25, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
+ H5O_loc_t *dst_oloc, void *mesg_dst, unsigned H5_ATTR_UNUSED *mesg_flags,
+ hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ const H5O_ainfo_t *ainfo_src = (const H5O_ainfo_t *)mesg_src;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(ainfo_src);
+
+ if(H5F_addr_defined(ainfo_src->fheap_addr)) {
+ if(H5A_dense_post_copy_file_all(src_oloc, ainfo_src, dst_oloc,
+ (H5O_ainfo_t *)mesg_dst, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't copy attribute")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_ainfo_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ainfo_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ainfo_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_ainfo_t *ainfo = (const H5O_ainfo_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(ainfo);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of attributes:", ainfo->nattrs);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Track creation order of attributes:", ainfo->track_corder);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Index creation order of attributes:", ainfo->index_corder);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. creation index value:", (unsigned)ainfo->max_crt_idx);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' attribute storage fractal heap address:", ainfo->fheap_addr);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' attribute storage name index v2 B-tree address:", ainfo->name_bt2_addr);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' attribute storage creation order index v2 B-tree address:", ainfo->corder_bt2_addr);
+
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ainfo_debug() */
+
diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c
new file mode 100644
index 0000000..3512d3e
--- /dev/null
+++ b/src/H5Oalloc.c
@@ -0,0 +1,2543 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oalloc.c
+ * Nov 17 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object header allocation routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Opkg.h" /* Object headers */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5O_add_gap(H5F_t *f, H5O_t *oh, unsigned chunkno,
+ hbool_t *chk_dirtied, size_t idx, uint8_t *new_gap_loc, size_t new_gap_size);
+static herr_t H5O_eliminate_gap(H5O_t *oh, hbool_t *chk_dirtied,
+ H5O_mesg_t *mesg, uint8_t *new_gap_loc, size_t new_gap_size);
+static herr_t H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t null_idx,
+ const H5O_msg_class_t *new_type, void *new_native, size_t new_size);
+static htri_t H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ unsigned chunkno, size_t size, size_t *msg_idx);
+static herr_t H5O__alloc_find_best_nonnull(const H5F_t *f, const H5O_t *oh, size_t *size,
+ H5O_msg_alloc_info_t *found_msg);
+static herr_t H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size,
+ size_t *new_idx);
+static herr_t H5O__alloc_find_best_null(const H5O_t *oh, size_t size, size_t *mesg_idx);
+static htri_t H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u);
+static htri_t H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
+static htri_t H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
+static htri_t H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
+static herr_t H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ unsigned chunkno);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare extern the free list for H5O_cont_t's */
+H5FL_EXTERN(H5O_cont_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_add_gap
+ *
+ * Purpose: Add a gap to a chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_add_gap(H5F_t *f, H5O_t *oh, unsigned chunkno, hbool_t *chk_dirtied,
+ size_t idx, uint8_t *new_gap_loc, size_t new_gap_size)
+{
+ hbool_t merged_with_null; /* Whether the gap was merged with a null message */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(oh->version > H5O_VERSION_1);
+ HDassert(chk_dirtied);
+ HDassert(new_gap_loc);
+ HDassert(new_gap_size);
+
+#ifndef NDEBUG
+if(chunkno > 0) {
+ unsigned chk_proxy_status = 0; /* Object header chunk proxy entry cache status */
+
+ /* Check the object header chunk proxy's status in the metadata cache */
+ if(H5AC_get_entry_status(f, oh->chunk[chunkno].addr, &chk_proxy_status) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check metadata cache status for object header chunk proxy")
+
+ /* Make certain that object header is protected */
+ HDassert(chk_proxy_status & H5AC_ES__IS_PROTECTED);
+} /* end if */
+#endif /* NDEBUG */
+
+ /* Check for existing null message in chunk */
+ merged_with_null = FALSE;
+ for(u = 0; u < oh->nmesgs && !merged_with_null; u++) {
+ /* Find a null message in the chunk with the new gap */
+ /* (a null message that's not the one we are eliminating) */
+ if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno
+ && u != idx) {
+ /* Sanity check - chunks with null messages shouldn't have a gap */
+ HDassert(oh->chunk[chunkno].gap == 0);
+
+ /* Eliminate the gap in the chunk */
+ if(H5O_eliminate_gap(oh, chk_dirtied, &oh->mesg[u], new_gap_loc, new_gap_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk")
+
+ /* Set flag to indicate that the gap was handled */
+ merged_with_null = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* If we couldn't find a null message in the chunk, move the gap to the end */
+ if(!merged_with_null) {
+ /* Adjust message offsets after new gap forward in chunk */
+ for(u = 0; u < oh->nmesgs; u++)
+ if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc)
+ oh->mesg[u].raw -= new_gap_size;
+
+ /* Slide raw message info forward in chunk image */
+ HDmemmove(new_gap_loc, new_gap_loc + new_gap_size,
+ (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size)));
+
+ /* Add existing gap size to new gap size */
+ new_gap_size += oh->chunk[chunkno].gap;
+
+ /* Merging with existing gap will allow for a new null message */
+ if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
+ H5O_mesg_t *null_msg; /* Pointer to new null message */
+
+ /* Check if we need to extend message table to hold the new null message */
+ if(oh->nmesgs >= oh->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* Increment new gap size */
+ oh->chunk[chunkno].gap += new_gap_size;
+
+ /* Create new null message, with the tail of the previous null message */
+ null_msg = &(oh->mesg[oh->nmesgs++]);
+ null_msg->type = H5O_MSG_NULL;
+ null_msg->native = NULL;
+ null_msg->raw_size = new_gap_size - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size)
+ - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size);
+ null_msg->chunkno = chunkno;
+
+ /* Zero out new null message's raw data */
+ if(null_msg->raw_size)
+ HDmemset(null_msg->raw, 0, null_msg->raw_size);
+
+ /* Mark message as dirty */
+ null_msg->dirty = TRUE;
+
+ /* Reset size of gap in chunk */
+ oh->chunk[chunkno].gap = 0;
+ } /* end if */
+ else
+ oh->chunk[chunkno].gap = new_gap_size;
+
+ /* Mark the chunk as modified */
+ *chk_dirtied = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_add_gap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_eliminate_gap
+ *
+ * Purpose: Eliminate a gap in a chunk with a null message.
+ *
+ * Note: Sometimes this happens as a result of converting an existing
+ * non-null message to a null message, so we zero out the gap
+ * here, even though it might already be zero (when we're adding
+ * a gap to a chunk with an existing null message). (Mostly,
+ * this just simplifies the code, esp. with the necessary chunk
+ * locking -QAK)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_eliminate_gap(H5O_t *oh, hbool_t *chk_dirtied, H5O_mesg_t *mesg,
+ uint8_t *gap_loc, size_t gap_size)
+{
+ uint8_t *move_start, *move_end; /* Pointers to area of messages to move */
+ hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(oh);
+ HDassert(oh->version > H5O_VERSION_1);
+ HDassert(chk_dirtied);
+ HDassert(mesg);
+ HDassert(gap_loc);
+ HDassert(gap_size);
+
+ /* Check if the null message is before or after the gap produced */
+ null_before_gap = (hbool_t)(mesg->raw < gap_loc);
+
+ /* Set up information about region of messages to move */
+ if(null_before_gap) {
+ move_start = mesg->raw + mesg->raw_size;
+ move_end = gap_loc;
+ } /* end if */
+ else {
+ move_start = gap_loc + gap_size;
+ move_end = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
+ } /* end else */
+
+ /* Check for messages between null message and gap */
+ if(move_end > move_start) {
+ unsigned u; /* Local index variable */
+
+ /* Look for messages that need to move, to adjust raw pointers in chunk */
+ /* (this doesn't change the moved messages 'dirty' state) */
+ for(u = 0; u < oh->nmesgs; u++) {
+ uint8_t *msg_start; /* Start of encoded message in chunk */
+
+ msg_start = oh->mesg[u].raw - H5O_SIZEOF_MSGHDR_OH(oh);
+ if(oh->mesg[u].chunkno == mesg->chunkno
+ && (msg_start >= move_start && msg_start < move_end)) {
+ /* Move message's raw pointer in appropriate direction */
+ if(null_before_gap)
+ oh->mesg[u].raw += gap_size;
+ else
+ oh->mesg[u].raw -= gap_size;
+ } /* end if */
+ } /* end for */
+
+ /* Slide raw message info in chunk image */
+ if(null_before_gap)
+ /* Slide messages down */
+ HDmemmove(move_start + gap_size, move_start, (size_t)(move_end - move_start));
+ else {
+ /* Slide messages up */
+ HDmemmove(move_start - gap_size, move_start, (size_t)(move_end - move_start));
+
+ /* Adjust start of null message */
+ mesg->raw -= gap_size;
+ } /* end else */
+ }
+ else if(move_end == move_start && !null_before_gap) {
+ /* Slide null message up */
+ HDmemmove(move_start - gap_size, move_start, mesg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+
+ /* Adjust start of null message */
+ mesg->raw -= gap_size;
+ } /* end if */
+
+ /* Zero out addition to null message */
+ HDmemset(mesg->raw + mesg->raw_size, 0, gap_size);
+
+ /* Adjust size of null message */
+ mesg->raw_size += gap_size;
+
+ /* Set the gap size to zero for the chunk */
+ oh->chunk[mesg->chunkno].gap = 0;
+
+ /* Mark null message as dirty */
+ mesg->dirty = TRUE;
+ *chk_dirtied = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5O_eliminate_gap() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_alloc_null
+ *
+ * Purpose: Allocate room for a new message from a null message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 22 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t null_idx,
+ const H5O_msg_class_t *new_type, void *new_native, size_t new_size)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flags for unprotecting chunk */
+ H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(new_type);
+ HDassert(new_size);
+
+ /* Point to null message to allocate out of */
+ alloc_msg = &oh->mesg[null_idx];
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, alloc_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Check if there's a need to split the null message */
+ if(alloc_msg->raw_size > new_size) {
+ /* Check for producing a gap in the chunk */
+ if((alloc_msg->raw_size - new_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
+ size_t gap_size = alloc_msg->raw_size - new_size; /* Size of gap produced */
+
+ /* Adjust the size of the null message being eliminated */
+ alloc_msg->raw_size = new_size;
+
+ /* Add the gap to the chunk */
+ if(H5O_add_gap(f, oh, alloc_msg->chunkno, &chk_dirtied, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
+ } /* end if */
+ else {
+ size_t new_mesg_size = new_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */
+ H5O_mesg_t *null_msg; /* Pointer to new null message */
+
+ /* Check if we need to extend message table to hold the new null message */
+ if(oh->nmesgs >= oh->alloc_nmesgs) {
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */
+ alloc_msg = &oh->mesg[null_idx];
+ } /* end if */
+
+ /* Create new null message, with the tail of the previous null message */
+ null_msg = &(oh->mesg[oh->nmesgs++]);
+ null_msg->type = H5O_MSG_NULL;
+ null_msg->native = NULL;
+ null_msg->raw = alloc_msg->raw + new_mesg_size;
+ null_msg->raw_size = alloc_msg->raw_size - new_mesg_size;
+ null_msg->chunkno = alloc_msg->chunkno;
+
+ /* Mark the message as dirty */
+ null_msg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Check for gap in new null message's chunk */
+ if(oh->chunk[null_msg->chunkno].gap > 0) {
+ unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */
+
+ /* Eliminate the gap in the chunk */
+ if(H5O_eliminate_gap(oh, &chk_dirtied, null_msg,
+ ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)),
+ oh->chunk[null_chunkno].gap) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
+ } /* end if */
+
+ /* Set the size of the new "real" message */
+ alloc_msg->raw_size = new_size;
+ } /* end else */
+ } /* end if */
+
+ /* Initialize the new message */
+ alloc_msg->type = new_type;
+ alloc_msg->native = new_native;
+
+ /* Mark the new message as dirty */
+ alloc_msg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+done:
+ /* Release chunk */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc_null() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_alloc_msgs
+ *
+ * Purpose: Allocate more messages for a header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Nov 21 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_alloc_msgs(H5O_t *oh, size_t min_alloc)
+{
+ size_t old_alloc; /* Old number of messages allocated */
+ size_t na; /* New number of messages allocated */
+ H5O_mesg_t *new_mesg; /* Pointer to new message array */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+
+ /* Initialize number of messages information */
+ old_alloc = oh->alloc_nmesgs;
+ na = oh->alloc_nmesgs + MAX(oh->alloc_nmesgs, min_alloc); /* At least double */
+
+ /* Attempt to allocate more memory */
+ if(NULL == (new_mesg = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, na)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Update ohdr information */
+ oh->alloc_nmesgs = na;
+ oh->mesg = new_mesg;
+
+ /* Set new object header info to zeros */
+ HDmemset(&oh->mesg[old_alloc], 0, (oh->alloc_nmesgs - old_alloc) * sizeof(H5O_mesg_t));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc_msgs() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_alloc_extend_chunk
+ *
+ * Purpose: Attempt to extend a chunk that is allocated on disk.
+ *
+ * If the extension is successful, and if the last message
+ * of the chunk is the null message, then that message will
+ * be extended with the chunk. Otherwise a new null message
+ * is created.
+ *
+ * f is the file in which the chunk will be written. It is
+ * included to ensure that there is enough space to extend
+ * this chunk.
+ *
+ * Return: TRUE: The chunk has been extended, and *msg_idx
+ * contains the message index for null message
+ * which is large enough to hold size bytes.
+ *
+ * FALSE: The chunk cannot be extended, and *msg_idx
+ * is undefined.
+ *
+ * FAIL: Some internal error has been detected.
+ *
+ * Programmer: John Mainzer -- 8/16/05
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno,
+ size_t size, size_t *msg_idx)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ size_t delta; /* Change in chunk's size */
+ size_t aligned_size = H5O_ALIGN_OH(oh, size);
+ uint8_t *old_image; /* Old address of chunk's image in memory */
+ size_t old_size; /* Old size of chunk */
+ htri_t was_extended; /* If chunk can be extended */
+ size_t extend_msg = 0; /* Index of null message to extend */
+ hbool_t extended_msg = FALSE; /* Whether an existing message was extended */
+ uint8_t new_size_flags = 0; /* New chunk #0 size flags */
+ hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */
+ size_t extra_prfx_size = 0; /* Extra bytes added to object header prefix */
+ size_t u; /* Local index variable */
+ htri_t ret_value = TRUE; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f != NULL);
+ HDassert(oh != NULL);
+ HDassert(chunkno < oh->nchunks);
+ HDassert(size > 0);
+ HDassert(msg_idx != NULL);
+ HDassert(H5F_addr_defined(oh->chunk[chunkno].addr));
+
+ /* Test to see if the specified chunk ends with a null messages.
+ * If successful, set the index of the the null message in extend_msg.
+ */
+ for(u = 0; u < oh->nmesgs; u++) {
+ /* Check for null message at end of proper chunk */
+ /* (account for possible checksum at end of chunk) */
+ if(oh->mesg[u].chunkno == chunkno && H5O_NULL_ID == oh->mesg[u].type->id &&
+ ((oh->mesg[u].raw + oh->mesg[u].raw_size)
+ == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
+ (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) {
+
+ extend_msg = u;
+ extended_msg = TRUE;
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* If we can extend an existing null message, adjust the delta appropriately */
+ if(extended_msg) {
+ HDassert(oh->chunk[chunkno].gap == 0);
+ delta = aligned_size - oh->mesg[extend_msg].raw_size;
+ } /* end if */
+ else
+ delta = (aligned_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) - oh->chunk[chunkno].gap;
+ delta = H5O_ALIGN_OH(oh, delta);
+
+ /* Check for changing the chunk #0 data size enough to need adjusting the flags */
+ if(oh->version > H5O_VERSION_1 && chunkno == 0) {
+ uint64_t chunk0_size; /* Size of chunk 0's data */
+ size_t orig_prfx_size = (size_t)1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */
+
+ HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
+ chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
+
+ /* Check for moving to a 8-byte size encoding */
+ if(orig_prfx_size < 8 && (chunk0_size + delta) > 4294967295) {
+ extra_prfx_size = 8 - orig_prfx_size;
+ new_size_flags = H5O_HDR_CHUNK0_8;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ /* Check for moving to a 4-byte size encoding */
+ else if(orig_prfx_size < 4 && (chunk0_size + delta) > 65535) {
+ extra_prfx_size = 4 - orig_prfx_size;
+ new_size_flags = H5O_HDR_CHUNK0_4;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ /* Check for moving to a 2-byte size encoding */
+ else if(orig_prfx_size < 2 && (chunk0_size + delta) > 255) {
+ extra_prfx_size = 2 - orig_prfx_size;
+ new_size_flags = H5O_HDR_CHUNK0_2;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ } /* end if */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Determine whether the chunk can be extended */
+ was_extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_OHDR, oh->chunk[chunkno].addr,
+ (hsize_t)(oh->chunk[chunkno].size), (hsize_t)(delta + extra_prfx_size));
+ if(was_extended < 0) /* error */
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, FAIL, "can't tell if we can extend chunk")
+ else if(was_extended == FALSE) /* can't extend -- we are done */
+ HGOTO_DONE(FALSE)
+
+ /* Adjust object header prefix flags */
+ if(adjust_size_flags) {
+ oh->flags = (uint8_t)(oh->flags & ~H5O_HDR_CHUNK0_SIZE);
+ oh->flags |= new_size_flags;
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+ } /* end if */
+
+ /* If we can extend an existing null message, take care of that */
+ if(extended_msg) {
+ /* Adjust message size of existing null message */
+ oh->mesg[extend_msg].raw_size += delta;
+ } /* end if */
+ /* Create new null message for end of chunk */
+ else {
+ /* Create a new null message */
+ if(oh->nmesgs >= oh->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* Set extension message */
+ extend_msg = oh->nmesgs++;
+
+ /* Initialize new null message */
+ oh->mesg[extend_msg].type = H5O_MSG_NULL;
+ oh->mesg[extend_msg].native = NULL;
+ oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size)
+ - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap))
+ + H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[extend_msg].raw_size = (delta + oh->chunk[chunkno].gap) - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[extend_msg].chunkno = chunkno;
+ } /* end else */
+
+ /* Mark the extended message as dirty */
+ oh->mesg[extend_msg].dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Allocate more memory space for chunk's image */
+ old_image = oh->chunk[chunkno].image;
+ old_size = oh->chunk[chunkno].size;
+ oh->chunk[chunkno].size += delta + extra_prfx_size;
+ oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size);
+ if(NULL == oh->chunk[chunkno].image)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't reallocate extended object header chunk")
+ oh->chunk[chunkno].gap = 0;
+
+ /* Wipe new space for chunk */
+ HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size);
+
+ /* Move chunk 0 data up if the size flags changed */
+ if(adjust_size_flags)
+ HDmemmove(oh->chunk[0].image + H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh),
+ oh->chunk[0].image + H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh) - extra_prfx_size,
+ old_size - (size_t)H5O_SIZEOF_HDR(oh) + extra_prfx_size);
+
+ /* Spin through existing messages, adjusting them */
+ for(u = 0; u < oh->nmesgs; u++) {
+ /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */
+ if(oh->mesg[u].chunkno == chunkno)
+ oh->mesg[u].raw = oh->chunk[chunkno].image + extra_prfx_size + (oh->mesg[u].raw - old_image);
+
+ /* Find continuation message which points to this chunk and adjust chunk's size */
+ /* (Chunk 0 doesn't have a continuation message that points to it,
+ * its size is directly encoded in the object header) */
+ if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) &&
+ (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) {
+ H5O_chunk_proxy_t *chk_proxy2 = NULL; /* Chunk that continuation message is in */
+ hbool_t chk_dirtied2 = FALSE; /* Flag for unprotecting chunk */
+ unsigned cont_chunkno = oh->mesg[u].chunkno; /* Chunk # for continuation message */
+
+ /* Protect chunk containing continuation message */
+ if(NULL == (chk_proxy2 = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Adjust size in continuation message */
+ HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size);
+ ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size;
+
+ /* Flag continuation message as dirty */
+ oh->mesg[u].dirty = TRUE;
+ chk_dirtied2 = TRUE;
+
+ /* Release chunk containing continuation message */
+ if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy2, chk_dirtied2) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ } /* end if */
+ } /* end for */
+
+ /* Resize the chunk in the cache */
+ if(H5O_chunk_resize(oh, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize object header chunk")
+
+ /* Set new message index */
+ *msg_idx = extend_msg;
+
+done:
+ /* Release chunk */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc_extend_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__alloc_find_best_nonnull
+ *
+ * Purpose: Find the best fit non-null message for a given size of message
+ * to allocate.
+ *
+ * Note: The algorithm for finding a message to replace with a
+ * continuation message is still fairly limited. It's possible
+ * that two (or more) messages smaller than a continuation message
+ * might occupy a chunk and need to be moved in order to make
+ * room for the continuation message.
+ *
+ * Also, we aren't checking for NULL messages in front of another
+ * message right now...
+ *
+ * Return: Success: Index number of the null message for the
+ * new chunk. The null message will be at
+ * least SIZE bytes not counting the message
+ * ID or size fields.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 21 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__alloc_find_best_nonnull(const H5F_t *f, const H5O_t *oh, size_t *size,
+ H5O_msg_alloc_info_t *found_msg)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
+ size_t cont_size; /* Continuation message size */
+ size_t multi_size; /* Size of all the messages in the last chunk */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(size);
+ HDassert(*size > 0);
+ HDassert(found_msg);
+
+ /*
+ * Find the smallest message that could be moved to make room for the
+ * continuation message.
+ *
+ * Don't ever move continuation message from one chunk to another.
+ *
+ * Avoid moving attributes when possible to preserve their
+ * ordering (although ordering is *not* guaranteed!).
+ *
+ */
+ cont_size = H5O_ALIGN_OH(oh, (size_t)(H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)));
+ multi_size = 0;
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ /* Don't consider continuation messages (for now) */
+ if(H5O_CONT_ID != curr_msg->type->id) {
+ unsigned msg_chunkno = curr_msg->chunkno; /* Chunk that the message is in */
+ uint8_t *end_chunk_data = (oh->chunk[msg_chunkno].image + oh->chunk[msg_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[msg_chunkno].gap); /* End of message data in chunk */
+ uint8_t *end_msg = curr_msg->raw + curr_msg->raw_size; /* End of current message */
+ size_t gap_size = 0; /* Size of gap after current message */
+ size_t null_size = 0; /* Size of NULL message after current message */
+ unsigned null_msgno = 0; /* Index of NULL message after current message */
+ size_t total_size; /* Total size of available space "around" current message */
+
+ /* Check if the message is the last one in the chunk */
+ if(end_msg == end_chunk_data)
+ gap_size = oh->chunk[msg_chunkno].gap;
+ else {
+ H5O_mesg_t *tmp_msg; /* Temp. pointer to message to operate on */
+ unsigned v; /* Local index variable */
+
+ /* Check for null message after this message, in same chunk */
+ for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) {
+ if(tmp_msg->type->id == H5O_NULL_ID && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == end_msg) {
+ null_msgno = v;
+ null_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + tmp_msg->raw_size;
+ break;
+ } /* end if */
+
+ /* XXX: Should also check for NULL message in front of current message... */
+
+ } /* end for */
+ } /* end else */
+
+ /* Add up current message's total available space */
+ total_size = curr_msg->raw_size + gap_size + null_size;
+
+ /* Check if message is large enough to hold continuation info */
+ if(total_size >= cont_size) {
+ hbool_t better = FALSE; /* Whether the current message is better than a previous one */
+
+ /* Check for first message that can be moved */
+ if(found_msg->msgno < 0)
+ better = TRUE;
+ else {
+ /* Prioritize moving non-attributes above attributes */
+ /* (Even attributes with an otherwise better fit */
+ if(found_msg->id == H5O_ATTR_ID && curr_msg->type->id != H5O_ATTR_ID)
+ better = TRUE;
+ /* Either two attributes, or two non-attributes */
+ else {
+ /* Take a smaller one */
+ if(total_size < found_msg->total_size)
+ better = TRUE;
+ /* If they are the same size, choose the earliest one
+ * in the chunk array */
+ /* (Could also bias toward message earlier / later
+ * chunk in, but shouldn't be a big deal - QAK, 2016/10/21)
+ */
+ else if(total_size == found_msg->total_size) {
+ if(msg_chunkno < found_msg->chunkno)
+ better = TRUE;
+ } /* end else-if */
+ } /* end else */
+ } /* end else */
+
+ /* If we found a better message, keep its info */
+ if(better) {
+ found_msg->msgno = (int)u;
+ found_msg->id = curr_msg->type->id;
+ found_msg->chunkno = msg_chunkno;
+ found_msg->gap_size = gap_size;
+ found_msg->null_size = null_size;
+ found_msg->total_size = total_size;
+ found_msg->null_msgno = null_msgno;
+ } /* end if */
+ } /* end if */
+ else if(found_msg->msgno < 0 && msg_chunkno == oh->nchunks - 1)
+ /* Keep track of the total size of smaller messages in the last
+ * chunk, in case we need to move more than 1 message.
+ */
+ multi_size += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ } /* end if */
+ } /* end for */
+
+ /*
+ * If we must move some other message to make room for the null
+ * message, then make sure the new chunk has enough room for that
+ * other message.
+ *
+ * Move other messages first, and attributes only as a last resort.
+ *
+ * If all else fails, move every message in the last chunk.
+ *
+ */
+ if(found_msg->msgno < 0)
+ *size += multi_size;
+ else
+ *size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_msg->msgno].raw_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5O__alloc_find_best_nonnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__alloc_chunk
+ *
+ * Purpose: Allocates and initializes a new chunk for the object header,
+ * including file space.
+ *
+ * Return: Success: SUCCEED, with chunk number for the
+ * new chunk and a pointer to the location in its
+ * image where the first message should be placed.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 21 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O__alloc_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size,
+ size_t found_null, const H5O_msg_alloc_info_t *found_msg, size_t *new_idx)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
+ H5O_chunk_proxy_t *chk_proxy; /* Chunk that message is in */
+ size_t cont_size; /*continuation message size */
+ size_t idx; /* Message number */
+ uint8_t *p = NULL; /* Pointer into new chunk image */
+ H5O_cont_t *cont = NULL; /*native continuation message */
+ unsigned chunkno; /* Chunk allocated */
+ haddr_t new_chunk_addr; /* Address of new chunk in file */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(found_msg);
+ HDassert(new_idx);
+
+ /*
+ * The total chunk size must include the requested space plus enough
+ * for the message header. This must be at least some minimum and
+ * aligned properly.
+ */
+ size = MAX(H5O_MIN_SIZE, size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+ HDassert(size == H5O_ALIGN_OH(oh, size));
+
+ /*
+ * The total chunk size must include enough space for the checksum
+ * on the chunk and the continuation chunk magic #. (which are only present
+ * in later versions of the object header)
+ */
+ size += H5O_SIZEOF_CHKHDR_OH(oh);
+
+ /* Allocate space in file to hold the new chunk */
+ new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size);
+ if(!H5F_addr_defined(new_chunk_addr))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "unable to allocate space for new chunk")
+
+ /* Create the new chunk giving it a file address. */
+ if(oh->nchunks >= oh->alloc_nchunks) {
+ size_t na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
+ H5O_chunk_t *x;
+
+ if(NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate larger chunk array, na = %zu", na)
+ oh->alloc_nchunks = na;
+ oh->chunk = x;
+ } /* end if */
+
+ H5_CHECKED_ASSIGN(chunkno, unsigned, oh->nchunks, size_t);
+ oh->nchunks++;
+ oh->chunk[chunkno].addr = new_chunk_addr;
+ oh->chunk[chunkno].size = size;
+ oh->chunk[chunkno].gap = 0;
+ if(NULL == (oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image, size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate image for chunk, size = %zu", size)
+ oh->chunk[chunkno].chunk_proxy = NULL;
+
+ /* If this is a later version of the object header format, put the magic
+ * # at the beginning of the chunk image.
+ */
+ if(oh->version > H5O_VERSION_1) {
+ HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ p += H5_SIZEOF_MAGIC;
+ } /* end if */
+
+ /*
+ * Make sure we have enough space for all possible new messages
+ * that could be generated below.
+ */
+ if(oh->nmesgs + 3 > oh->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh, (size_t)3) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* Check if we need to move multiple messages, in order to make room for the new message */
+ cont_size = H5O_ALIGN_OH(oh, (size_t)(H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)));
+ if(found_null >= oh->nmesgs) {
+ if(found_msg->msgno < 0) {
+ /* Move all non-null messages in the last chunk to the new chunk. This
+ * should be extremely rare so we don't care too much about minimizing
+ * the space used.
+ */
+ H5O_mesg_t *null_msg; /* Pointer to new null message */
+
+ /* Protect last chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno - 1)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Copy each message to the new location */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
+ if(curr_msg->chunkno == chunkno - 1) {
+ if(curr_msg->type->id == H5O_NULL_ID) {
+ /* Delete the null message */
+ if(u < oh->nmesgs - 1)
+ HDmemmove(curr_msg, curr_msg + 1, ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t));
+ oh->nmesgs--;
+ } /* end if */
+ else {
+ HDassert(curr_msg->type->id != H5O_CONT_ID);
+
+ /* Copy the raw data */
+ HDmemcpy(p, curr_msg->raw - (size_t)H5O_SIZEOF_MSGHDR_OH(oh),
+ curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+
+ /* Update the message info */
+ curr_msg->chunkno = chunkno;
+ curr_msg->raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Account for copied message in new chunk */
+ p += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size;
+ size -= (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size;
+ } /* end else */
+ } /* end if */
+
+ /* Create a null message spanning the entire last chunk */
+ found_null = oh->nmesgs++;
+ null_msg = &(oh->mesg[found_null]);
+ null_msg->type = H5O_MSG_NULL;
+ null_msg->dirty = TRUE;
+ null_msg->native = NULL;
+ null_msg->raw = oh->chunk[chunkno - 1].image
+ + ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh))
+ - H5O_SIZEOF_CHKSUM_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh);
+ null_msg->raw_size = oh->chunk[chunkno - 1].size
+ - ((chunkno == 1) ? (size_t)H5O_SIZEOF_HDR(oh) : (size_t)H5O_SIZEOF_CHKHDR_OH(oh))
+ - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ null_msg->chunkno = chunkno - 1;
+
+ HDassert(null_msg->raw_size >= cont_size);
+
+ /* Remove any gap in the chunk */
+ oh->chunk[chunkno - 1].gap = 0;
+
+ /* Release chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ } /* end if */
+ else {
+ /* Move message (that will be replaced with continuation message)
+ * to new chunk, if necessary.
+ */
+ H5O_mesg_t *null_msg; /* Pointer to new null message */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, oh->mesg[found_msg->msgno].chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Create null message for space that message to copy currently occupies */
+ found_null = oh->nmesgs++;
+ null_msg = &(oh->mesg[found_null]);
+ null_msg->type = H5O_MSG_NULL;
+ null_msg->native = NULL;
+ null_msg->raw = oh->mesg[found_msg->msgno].raw;
+ null_msg->raw_size = oh->mesg[found_msg->msgno].raw_size;
+ null_msg->chunkno = oh->mesg[found_msg->msgno].chunkno;
+
+ /* Copy the message to move (& its prefix) to its new location */
+ HDmemcpy(p, oh->mesg[found_msg->msgno].raw - H5O_SIZEOF_MSGHDR_OH(oh),
+ oh->mesg[found_msg->msgno].raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+
+ /* Switch moved message to point to new location */
+ oh->mesg[found_msg->msgno].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[found_msg->msgno].chunkno = chunkno;
+
+ /* Account for copied message in new chunk */
+ p += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_msg->msgno].raw_size;
+ size -= (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_msg->msgno].raw_size;
+
+ /* Add any available space after the message to move to the new null message */
+ if(found_msg->gap_size > 0) {
+ /* Absorb a gap after the moved message */
+ HDassert(oh->chunk[null_msg->chunkno].gap == found_msg->gap_size);
+ null_msg->raw_size += found_msg->gap_size;
+ oh->chunk[null_msg->chunkno].gap = 0;
+ } /* end if */
+ else if(found_msg->null_size > 0) {
+ H5O_mesg_t *old_null_msg = &oh->mesg[found_msg->null_msgno]; /* Pointer to NULL message to eliminate */
+
+ /* Absorb a null message after the moved message */
+ HDassert((null_msg->raw + null_msg->raw_size) == (old_null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)));
+ null_msg->raw_size += found_msg->null_size;
+
+ /* Release any information/memory for message */
+ H5O_msg_free_mesg(old_null_msg);
+
+ /* Remove null message from list of messages */
+ if(found_msg->null_msgno < (oh->nmesgs - 1))
+ HDmemmove(old_null_msg, old_null_msg + 1, ((oh->nmesgs - 1) - found_msg->null_msgno) * sizeof(H5O_mesg_t));
+
+ /* Decrement # of messages */
+ /* (Don't bother reducing size of message array for now -QAK) */
+ oh->nmesgs--;
+
+ /* Adjust message index for new NULL message */
+ found_null--;
+ } /* end if */
+
+ /* Mark the new null message as dirty */
+ null_msg->dirty = TRUE;
+
+ /* Release chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ } /* end if */
+ } /* end if */
+
+ /* Create null message for [rest of] space in new chunk */
+ /* (account for chunk's magic # & checksum) */
+ idx = oh->nmesgs++;
+ oh->mesg[idx].type = H5O_MSG_NULL;
+ oh->mesg[idx].dirty = TRUE;
+ oh->mesg[idx].native = NULL;
+ oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[idx].raw_size = size - (size_t)(H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh));
+ oh->mesg[idx].chunkno = chunkno;
+
+ /* Insert the new chunk into the cache */
+ if(H5O_chunk_add(f, dxpl_id, oh, chunkno, oh->mesg[found_null].chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't add new chunk to cache")
+
+ /* Initialize the continuation information */
+ if(NULL == (cont = H5FL_MALLOC(H5O_cont_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ cont->addr = oh->chunk[chunkno].addr;
+ cont->size = oh->chunk[chunkno].size;
+ cont->chunkno = chunkno;
+
+ /* Split the null message and point at continuation message */
+ if(H5O_alloc_null(f, dxpl_id, oh, found_null, H5O_MSG_CONT, cont, cont_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't split null message")
+
+ /* Set new message index value */
+ *new_idx = idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O__alloc_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_alloc_new_chunk
+ *
+ * Purpose: Allocates a new chunk for the object header, including
+ * file space.
+ *
+ * One of the other chunks will get an object continuation
+ * message. If there isn't room in any other chunk for the
+ * object continuation message, then some message from
+ * another chunk is moved into this chunk to make room.
+ *
+ * SIZE need not be aligned.
+ *
+ * Note: The algorithm for finding a message to replace with a
+ * continuation message is still fairly limited. It's possible
+ * that two (or more) messages smaller than a continuation message
+ * might occupy a chunk and need to be moved in order to make
+ * room for the continuation message.
+ *
+ * Also, we aren't checking for NULL messages in front of another
+ * message right now...
+ *
+ * Return: Success: Index number of the null message for the
+ * new chunk. The null message will be at
+ * least SIZE bytes not counting the message
+ * ID or size fields.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 7 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size, size_t *new_idx)
+{
+ size_t cont_size; /*continuation message size */
+ size_t idx; /* Message number */
+ H5O_msg_alloc_info_t found_msg; /* Best fit non-null message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(size > 0);
+ size = H5O_ALIGN_OH(oh, size);
+
+ /* Find the smallest null message that could hold a continuation message */
+ idx = oh->nmesgs;
+ cont_size = H5O_ALIGN_OH(oh, (size_t)(H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)));
+ if(H5O__alloc_find_best_null(oh, cont_size, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "error while locating best null header message")
+
+ /* If we couldn't find a null message, locate the best message to move to new chunk */
+ if(idx >= oh->nmesgs) {
+ found_msg.msgno = -1;
+ if(H5O__alloc_find_best_nonnull(f, oh, &size, &found_msg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "error while locating best non-null header message")
+ } /* end if */
+
+ /* Allocate and initialize new chunk in the file */
+ if(H5O__alloc_chunk(f, dxpl_id, oh, size, idx, &found_msg, new_idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate new object header chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc_new_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__alloc_find_best_null
+ *
+ * Purpose: Find the best fit null message for a given size of message
+ * to allocate.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@lbl.gov
+ * Oct 21 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__alloc_find_best_null(const H5O_t *oh, size_t size, size_t *mesg_idx)
+{
+ size_t idx; /* Index of message which fits allocation */
+ ssize_t found_null; /* Best fit null message */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(oh);
+ HDassert(size > 0);
+ HDassert(mesg_idx);
+
+ /* Find the smallest null message that could hold the new object header message */
+ found_null = -1;
+ for(idx = 0; idx < oh->nmesgs; idx++) {
+ if(H5O_NULL_ID == oh->mesg[idx].type->id) {
+ /* If we found an exact fit, use it */
+ if(oh->mesg[idx].raw_size == size) {
+ /* Keep first exact fit */
+ if(found_null < 0)
+ found_null = (ssize_t)idx;
+ else
+ /* If we've got more than one exact fit, choose the one in the earliest chunk */
+ if(oh->mesg[idx].chunkno < oh->mesg[found_null].chunkno) {
+ found_null = (ssize_t)idx;
+
+ /* If we found an exact fit in object header chunk #0, we can get out */
+ /* (Could extend this to look for earliest message in
+ * chunk #0 - QAK, 2016/10/21)
+ */
+ if(0 == oh->mesg[idx].chunkno)
+ break;
+ } /* end if */
+ } /* end if */
+ /* Look for null message that's larger than needed */
+ else if(oh->mesg[idx].raw_size > size) {
+ /* Keep first one found */
+ if(found_null < 0)
+ found_null = (ssize_t)idx;
+ else
+ /* Check for better fit */
+ if(oh->mesg[idx].raw_size < oh->mesg[found_null].raw_size)
+ found_null = (ssize_t)idx;
+ else {
+ /* If they are the same size, choose the one in the earliest chunk */
+ if(oh->mesg[idx].raw_size == oh->mesg[found_null].raw_size) {
+ if(oh->mesg[idx].chunkno < oh->mesg[found_null].chunkno)
+ found_null = (ssize_t)idx;
+ } /* end if */
+ } /* end else */
+ } /* end else-if */
+ /* else: Ignore too-small null messages */
+ } /* end if */
+ } /* end for */
+ if(found_null >= 0)
+ *mesg_idx = (size_t)found_null;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5O__alloc_find_best_null() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_alloc
+ *
+ * Purpose: Allocate enough space in the object header for this message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type,
+ const void *mesg, size_t *mesg_idx)
+{
+ size_t raw_size; /* Raw size of message */
+ size_t aligned_size; /* Size of message including alignment */
+ size_t idx; /* Index of message which fits allocation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh);
+ HDassert(type);
+ HDassert(mesg);
+ HDassert(mesg_idx);
+
+ /* Compute the size needed to store the message in the object header */
+ raw_size = (type->raw_size)(f, FALSE, mesg);
+ if(0 == raw_size)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "can't compute object header message size")
+ if(raw_size >= H5O_MESG_MAX_SIZE)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "object header message is too large")
+ aligned_size = H5O_ALIGN_OH(oh, raw_size);
+
+ /* Find the smallest null message that could hold the new object header message */
+ idx = oh->nmesgs;
+ if(H5O__alloc_find_best_null(oh, aligned_size, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "error while locating best null header message")
+
+ /* if we didn't find one, then allocate more header space */
+ if(idx >= oh->nmesgs) {
+ unsigned chunkno;
+
+ /* check to see if we can extend one of the chunks. If we can,
+ * do so. Otherwise, we will have to allocate a new chunk.
+ *
+ * Note that in this new version of this function, all chunks
+ * must have file space allocated to them.
+ */
+ for(chunkno = 0; chunkno < oh->nchunks; chunkno++) {
+ htri_t tri_result; /* Status from attempting to extend chunk */
+
+ if((tri_result = H5O_alloc_extend_chunk(f, dxpl_id, oh, chunkno, raw_size, &idx)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, FAIL, "can't extend existing chunk")
+ if(tri_result == TRUE)
+ break;
+ } /* end for */
+
+ /* If we were not able to extend a chunk, create a new one */
+ if(idx >= oh->nmesgs)
+ if(H5O_alloc_new_chunk(f, dxpl_id, oh, raw_size, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "unable to create a new object header data chunk")
+ } /* end if */
+ HDassert(idx < oh->nmesgs);
+
+ /* Split the null message and point at continuation message */
+ if(H5O_alloc_null(f, dxpl_id, oh, idx, type, NULL, aligned_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't split null message")
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+
+ /* Set message index value */
+ *mesg_idx = idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_release_mesg
+ *
+ * Purpose: Convert a message into a null message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 22 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg,
+ hbool_t adj_link)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(mesg);
+
+ /* Check if we should operate on the message */
+ if(adj_link) {
+ /* Free any space referred to in the file from this message */
+ if(H5O_delete_mesg(f, dxpl_id, oh, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message")
+ } /* end if */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, mesg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
+
+ /* Free any native information */
+ H5O_msg_free_mesg(mesg);
+
+ /* Change message type to nil and zero it */
+ mesg->type = H5O_MSG_NULL;
+ HDassert(mesg->raw + mesg->raw_size <= (oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap));
+ HDmemset(mesg->raw, 0, mesg->raw_size);
+
+ /* Clear message flags */
+ mesg->flags = 0;
+
+ /* Mark the message as modified */
+ mesg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Check if chunk has a gap currently */
+ if(oh->chunk[mesg->chunkno].gap) {
+ /* Eliminate the gap in the chunk */
+ if(H5O_eliminate_gap(oh, &chk_dirtied, mesg,
+ ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)),
+ oh->chunk[mesg->chunkno].gap) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
+ } /* end if */
+
+done:
+ /* Release chunk, if not already done */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_release_mesg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_move_cont
+ *
+ * Purpose: Check and move message(s) forward into a continuation message
+ *
+ * Return: Success: non-negative (TRUE/FALSE)
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi
+ * Feb. 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that continuation message is in */
+ H5O_mesg_t *cont_msg; /* Pointer to the continuation message */
+ unsigned deleted_chunkno; /* Chunk # to delete */
+ hbool_t chk_dirtied = FALSE; /* Flags for unprotecting chunk */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments. */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Get initial information */
+ cont_msg = &oh->mesg[cont_u];
+ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL)
+ deleted_chunkno = ((H5O_cont_t *)(cont_msg->native))->chunkno;
+
+ /* Check if continuation message is pointing to the last chunk */
+ if(deleted_chunkno == (oh->nchunks - 1)) {
+ size_t nonnull_size; /* Total size of nonnull messages in the chunk pointed to by cont message */
+ H5O_mesg_t *curr_msg; /* Pointer to the current message to operate on */
+ size_t gap_size; /* Size of gap produced */
+ size_t v; /* Local index variable */
+
+ /* Spin through messages */
+ nonnull_size = 0;
+ for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++) {
+ if(curr_msg->chunkno == deleted_chunkno) {
+ /* Find size of all non-null messages in the chunk pointed to by the continuation message */
+ if(curr_msg->type->id != H5O_NULL_ID) {
+ HDassert(curr_msg->type->id != H5O_CONT_ID);
+ nonnull_size += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ /* Size of gap in chunk w/continuation message */
+ gap_size = oh->chunk[cont_msg->chunkno].gap;
+
+ /* Check if messages can fit into the continuation message + gap size */
+ /* (Could count any null messages in the chunk w/the continuation
+ * message also, but that is pretty complex. -QAK)
+ */
+ if(nonnull_size && nonnull_size <= (gap_size + cont_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh))) {
+ uint8_t *move_start, *move_end; /* Pointers to area of messages to move */
+ unsigned cont_chunkno; /* Chunk number for continuation message */
+
+ /* Get continuation info */
+ move_start = cont_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
+ move_end = cont_msg->raw + cont_msg->raw_size;
+ cont_chunkno = cont_msg->chunkno;
+
+ /* Convert continuation message into a null message. Do not delete
+ * the target chunk yet, so we can still copy messages from it. */
+ if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message")
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
+
+ /* Move message(s) forward into continuation message */
+ for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++)
+ /* Look for messages in chunk to delete */
+ if(curr_msg->chunkno == deleted_chunkno) {
+ /* Move messages out of chunk to delete */
+ if(curr_msg->type->id != H5O_NULL_ID) {
+ size_t move_size; /* Size of the message to be moved */
+
+ /* Compute size of message to move */
+ move_size = curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Move message out of deleted chunk */
+ HDmemcpy(move_start, curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), move_size);
+ curr_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh);
+ curr_msg->chunkno = cont_chunkno;
+ chk_dirtied = TRUE;
+
+ /* Adjust location to move messages to */
+ move_start += move_size;
+ } /* end else */
+ } /* end if */
+
+ /* Delete the target chunk */
+ if(H5O_chunk_delete(f, dxpl_id, oh, deleted_chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove chunk from cache")
+
+ HDassert(move_start <= (move_end + gap_size));
+
+ /* Check if there is space remaining in the continuation message */
+ /* (The remaining space can be gap or a null message) */
+ gap_size += (size_t)(move_end - move_start);
+ if(gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
+ /* Adjust size of null (was continuation) message */
+ cont_msg->raw_size = gap_size - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ cont_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh);
+ cont_msg->dirty = TRUE;
+ chk_dirtied = TRUE;
+ } /* end if */
+ else {
+ /* Check if there is space that should be a gap */
+ if(gap_size > 0) {
+ /* Convert remnant into gap in chunk */
+ if(H5O_add_gap(f, oh, cont_chunkno, &chk_dirtied, cont_u, move_start, gap_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
+ } /* end if */
+
+ /* Release any information/memory for continuation message */
+ H5O_msg_free_mesg(cont_msg);
+ if(cont_u < (oh->nmesgs - 1))
+ HDmemmove(&oh->mesg[cont_u], &oh->mesg[cont_u + 1], ((oh->nmesgs - 1) - cont_u) * sizeof(H5O_mesg_t));
+ oh->nmesgs--;
+ } /* end else */
+
+ /* Move message(s) forward into continuation message */
+ /* Note: unsigned v wrapping around at the end */
+ for(v = oh->nmesgs - 1, curr_msg = &oh->mesg[v]; v < oh->nmesgs; v--, curr_msg--)
+ /* Look for messages in chunk to delete */
+ if(curr_msg->chunkno == deleted_chunkno) {
+ /* Remove all null messages in deleted chunk from list of messages */
+ if(curr_msg->type->id == H5O_NULL_ID) {
+ /* Release any information/memory for message */
+ H5O_msg_free_mesg(curr_msg);
+ chk_dirtied = TRUE;
+
+ /* Remove from message list */
+ if(v < (oh->nmesgs - 1))
+ HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t));
+ oh->nmesgs--;
+ } /* end if */
+ } /* end if */
+
+ /* Remove chunk from list of chunks */
+ oh->chunk[deleted_chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[deleted_chunkno].image);
+ oh->nchunks--;
+ } /* end if */
+ else
+ ret_value = FALSE;
+ } /* end if */
+ else
+ ret_value = FALSE;
+
+done:
+ /* Release chunk, if not already done */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_move_cont() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_move_msgs_forward
+ *
+ * Purpose: Move messages toward first chunk
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 17 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
+{
+ H5O_chunk_proxy_t *null_chk_proxy = NULL; /* Chunk that null message is in */
+ H5O_chunk_proxy_t *curr_chk_proxy = NULL; /* Chunk that message is in */
+ H5O_chunk_proxy_t *cont_targ_chk_proxy = NULL; /* Chunk that continuation message points to */
+ hbool_t null_chk_dirtied = FALSE; /* Flags for unprotecting null chunk */
+ hbool_t curr_chk_dirtied = FALSE; /* Flags for unprotecting curr chunk */
+ hbool_t packed_msg; /* Flag to indicate that messages were packed */
+ hbool_t did_packing = FALSE; /* Whether any messages were packed */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+
+ /* Loop until no messages packed */
+ /* (Double loop is not very efficient, but it would be some extra work to
+ * add a list of messages to each chunk -QAK)
+ */
+ do {
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
+ unsigned u; /* Local index variable */
+
+ /* Reset packed messages flag */
+ packed_msg = FALSE;
+
+ /* Scan through messages for messages that can be moved earlier in chunks */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ if(H5O_NULL_ID == curr_msg->type->id) {
+ H5O_chunk_t *chunk; /* Pointer to chunk that null message is in */
+
+ /* Check if null message is not last in chunk */
+ chunk = &(oh->chunk[curr_msg->chunkno]);
+ if((curr_msg->raw + curr_msg->raw_size)
+ != ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) {
+ H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */
+ unsigned v; /* Local index variable */
+
+ /* Loop over messages again, looking for the message in the chunk after the null message */
+ for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) {
+ /* Locate message that is immediately after the null message */
+ if((curr_msg->chunkno == nonnull_msg->chunkno) &&
+ ((curr_msg->raw + curr_msg->raw_size) == (nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)))) {
+ /* Don't swap messages if the second message is also a null message */
+ /* (We'll merge them together later, in another routine) */
+ if(H5O_NULL_ID != nonnull_msg->type->id) {
+ /* Protect chunk */
+ if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Copy raw data for non-null message to new location */
+ HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh),
+ nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+
+ /* Adjust non-null message's offset in chunk */
+ nonnull_msg->raw = curr_msg->raw;
+
+ /* Adjust null message's offset in chunk */
+ curr_msg->raw = nonnull_msg->raw +
+ nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Mark null message dirty */
+ /* (since we need to re-encode its message header) */
+ curr_msg->dirty = TRUE;
+
+ /* Release chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ null_chk_proxy = NULL;
+
+ /* Set the flag to indicate that the null message
+ * was packed - if its not at the end its chunk,
+ * we'll move it again on the next pass.
+ */
+ packed_msg = TRUE;
+ } /* end if */
+
+ /* Break out of loop */
+ break;
+ } /* end if */
+ } /* end for */
+ /* Should have been message after null message */
+ HDassert(v < oh->nmesgs);
+ } /* end if */
+ } /* end if */
+ else {
+ H5O_mesg_t *null_msg; /* Pointer to current message to operate on */
+ size_t v; /* Local index variable */
+
+ /* Check if messages in chunk pointed to can replace continuation message */
+ if(H5O_CONT_ID == curr_msg->type->id) {
+ htri_t status; /* Status from moving messages */
+
+ if((status = H5O_move_cont(f, dxpl_id, oh, u)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "Error in moving messages into cont message")
+ else if(status > 0) { /* Message(s) got moved into "continuation" message */
+ packed_msg = TRUE;
+ break;
+ } /* end else-if */
+ } /* end if */
+
+ /* Loop over messages again, looking for large enough null message in earlier chunk */
+ for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) {
+ if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno
+ && curr_msg->raw_size <= null_msg->raw_size) {
+ unsigned old_chunkno; /* Old message information */
+ uint8_t *old_raw;
+
+ /* Keep old information about non-null message */
+ old_chunkno = curr_msg->chunkno;
+ old_raw = curr_msg->raw;
+
+ /* Protect chunks */
+ if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, null_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+ if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* If the message being moved is a continuation
+ * message and we are doing SWMR writes, we must
+ * update the flush dependencies */
+ if(oh->swmr_write && (H5O_CONT_ID == curr_msg->type->id)) {
+ void *null_chk_mdc_obj; /* The metadata cache object for the null_msg chunk */
+
+ /* Point to the metadata cache object for the
+ * null message chunk, oh if in chunk 0 or the
+ * proxy otherwise */
+ null_chk_mdc_obj = (null_msg->chunkno == 0
+ ? (void *)oh
+ : (void *)null_chk_proxy);
+
+ /* The other chunks involved should never be
+ * chunk 0 */
+ HDassert(curr_msg->chunkno > 0);
+ HDassert(((H5O_cont_t *)(curr_msg->native))->chunkno > 0);
+
+ /* Protect continuation message target chunk */
+ if(NULL == (cont_targ_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, ((H5O_cont_t *)(curr_msg->native))->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Remove flush dependency on old continuation
+ * message chunk */
+ HDassert(cont_targ_chk_proxy);
+ HDassert(cont_targ_chk_proxy->parent);
+ HDassert(curr_chk_proxy);
+ HDassert((void *)curr_chk_proxy == cont_targ_chk_proxy->parent);
+
+ if(H5AC_destroy_flush_dependency(curr_chk_proxy, cont_targ_chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ cont_targ_chk_proxy->parent = NULL;
+
+ /* Create flush dependency on new continuation
+ * message chunk */
+ if(H5AC_create_flush_dependency(null_chk_mdc_obj, cont_targ_chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+ HDassert(null_chk_mdc_obj);
+ HDassert(((H5C_cache_entry_t *)null_chk_mdc_obj)->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)null_chk_mdc_obj)->type);
+ HDassert((((H5C_cache_entry_t *)null_chk_mdc_obj)->type->id == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)null_chk_mdc_obj)->type->id == H5AC_OHDR_CHK_ID));
+
+ cont_targ_chk_proxy->parent = null_chk_mdc_obj;
+
+ /* Unprotect continuation message target chunk
+ */
+ if(H5O_chunk_unprotect(f, dxpl_id, cont_targ_chk_proxy, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ cont_targ_chk_proxy = NULL;
+ } /* end if */
+
+ /* Copy raw data for non-null message to new chunk */
+ HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+
+ /* Point non-null message at null message's space */
+ curr_msg->chunkno = null_msg->chunkno;
+ curr_msg->raw = null_msg->raw;
+ curr_chk_dirtied = TRUE;
+
+ /* Change information for null message */
+ if(curr_msg->raw_size == null_msg->raw_size) {
+ /* Point null message at old non-null space */
+ /* (Instead of freeing it and allocating new message) */
+ null_msg->chunkno = old_chunkno;
+ null_msg->raw = old_raw;
+
+ /* Mark null message dirty */
+ null_msg->dirty = TRUE;
+ null_chk_dirtied = TRUE;
+
+ /* Release current chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ curr_chk_proxy = NULL;
+ curr_chk_dirtied = FALSE;
+
+ /* Check for gap in null message's chunk */
+ if(oh->chunk[old_chunkno].gap > 0) {
+ /* Eliminate the gap in the chunk */
+ if(H5O_eliminate_gap(oh, &null_chk_dirtied, null_msg,
+ ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)),
+ oh->chunk[old_chunkno].gap) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
+ } /* end if */
+
+ /* Release null chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ null_chk_proxy = NULL;
+ null_chk_dirtied = FALSE;
+ } /* end if */
+ else {
+ size_t new_null_msg; /* Message index for new null message */
+
+ /* Check if null message is large enough to still exist */
+ if((null_msg->raw_size - curr_msg->raw_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
+ size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */
+
+ /* Adjust the size of the null message being eliminated */
+ null_msg->raw_size = curr_msg->raw_size;
+
+ /* Mark null message dirty */
+ null_msg->dirty = TRUE;
+ null_chk_dirtied = TRUE;
+
+ /* Add the gap to the chunk */
+ if(H5O_add_gap(f, oh, null_msg->chunkno, &null_chk_dirtied, v, null_msg->raw + null_msg->raw_size, gap_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
+
+ /* Re-use message # for new null message taking place of non-null message */
+ new_null_msg = v;
+ } /* end if */
+ else {
+ /* Adjust null message's size & offset */
+ null_msg->raw += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ null_msg->raw_size -= curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Mark null message dirty */
+ null_msg->dirty = TRUE;
+ null_chk_dirtied = TRUE;
+
+ /* Create new null message for previous location of non-null message */
+ if(oh->nmesgs >= oh->alloc_nmesgs) {
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* "Retarget" 'curr_msg' pointer into newly re-allocated array of messages */
+ curr_msg = &oh->mesg[u];
+ } /* end if */
+
+ /* Get message # for new null message */
+ new_null_msg = oh->nmesgs++;
+ } /* end else */
+
+ /* Release null message's chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ null_chk_proxy = NULL;
+ null_chk_dirtied = FALSE;
+
+ /* Initialize new null message to take over non-null message's location */
+ oh->mesg[new_null_msg].type = H5O_MSG_NULL;
+ oh->mesg[new_null_msg].native = NULL;
+ oh->mesg[new_null_msg].raw = old_raw;
+ oh->mesg[new_null_msg].raw_size = curr_msg->raw_size;
+ oh->mesg[new_null_msg].chunkno = old_chunkno;
+
+ /* Mark new null message dirty */
+ oh->mesg[new_null_msg].dirty = TRUE;
+ curr_chk_dirtied = TRUE;
+
+ /* Check for gap in new null message's chunk */
+ if(oh->chunk[old_chunkno].gap > 0) {
+ /* Eliminate the gap in the chunk */
+ if(H5O_eliminate_gap(oh, &curr_chk_dirtied, &oh->mesg[new_null_msg],
+ ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)),
+ oh->chunk[old_chunkno].gap) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
+ } /* end if */
+
+ /* Release new null message's chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ curr_chk_proxy = NULL;
+ curr_chk_dirtied = FALSE;
+ } /* end else */
+
+ /* Indicate that we packed messages */
+ packed_msg = TRUE;
+
+ /* Break out of loop */
+ /* (If it's possible to move message to even earlier chunk
+ * we'll get it on the next pass - QAK)
+ */
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* If we packed messages, get out of loop and start over */
+ /* (Don't know if this has any benefit one way or the other -QAK) */
+ if(packed_msg)
+ break;
+ } /* end else */
+ } /* end for */
+
+ /* If we did any packing, remember that */
+ if(packed_msg)
+ did_packing = TRUE;
+ } while(packed_msg);
+
+ /* Set return value */
+ ret_value = (htri_t)did_packing;
+
+done:
+ if(ret_value < 0) {
+ if(null_chk_proxy && H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect null object header chunk")
+ if(curr_chk_proxy && H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect current object header chunk")
+ if(cont_targ_chk_proxy && H5O_chunk_unprotect(f, dxpl_id, cont_targ_chk_proxy, FALSE) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect continuation message target object header chunk")
+ } /* end if */
+ else
+ HDassert(!null_chk_proxy && !curr_chk_proxy && !cont_targ_chk_proxy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_move_msgs_forward() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_merge_null
+ *
+ * Purpose: Merge neighboring null messages in an object header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 10 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
+{
+ hbool_t merged_msg; /* Flag to indicate that messages were merged */
+ hbool_t did_merging = FALSE; /* Whether any messages were merged */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh != NULL);
+
+ /* Loop until no messages merged */
+ /* (Double loop is not very efficient, but it would be some extra work to add
+ * a list of messages to each chunk -QAK)
+ */
+ do {
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
+ unsigned u; /* Local index variable */
+
+ /* Reset merged messages flag */
+ merged_msg = FALSE;
+
+ /* Scan messages for adjacent null messages & merge them */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ if(H5O_NULL_ID == curr_msg->type->id) {
+ H5O_mesg_t *curr_msg2; /* Pointer to current message to operate on */
+ unsigned v; /* Local index variable */
+
+ /* Should be no gaps in chunk with null message */
+ HDassert(oh->chunk[curr_msg->chunkno].gap == 0);
+
+ /* Loop over messages again, looking for null message in same chunk */
+ for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) {
+ if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) {
+ ssize_t adj_raw; /* Amount to adjust raw message pointer */
+ size_t adj_raw_size; /* Amount to adjust raw message size */
+
+ /* Check for second message after first message */
+ if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) {
+ /* Extend first null message length to cover second null message */
+ adj_raw = 0;
+ adj_raw_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size;
+
+ /* Message has been merged */
+ merged_msg = TRUE;
+ } /* end if */
+ /* Check for second message before first message */
+ else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) {
+ /* Adjust first message address and extend length to cover second message */
+ adj_raw = -((ssize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size));
+ adj_raw_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size;
+
+ /* Message has been merged */
+ merged_msg = TRUE;
+ } /* end if */
+
+ /* Second message has been merged, delete it */
+ if(merged_msg) {
+ H5O_chunk_proxy_t *curr_chk_proxy; /* Chunk that message is in */
+ htri_t result;
+
+ /* Release any information/memory for second message */
+ H5O_msg_free_mesg(curr_msg2);
+
+ /* Protect chunk */
+ if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Adjust first message address and extend length to cover second message */
+ curr_msg->raw += adj_raw;
+ curr_msg->raw_size += adj_raw_size;
+
+ /* Mark first message as dirty */
+ curr_msg->dirty = TRUE;
+
+ /* Release new null message's chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ /* Remove second message from list of messages */
+ if(v < (oh->nmesgs - 1))
+ HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t));
+
+ /* Decrement # of messages */
+ /* (Don't bother reducing size of message array for now -QAK) */
+ oh->nmesgs--;
+
+ /* The merge null message might span the entire chunk: scan for empty chunk to remove */
+ if((result = H5O_remove_empty_chunks(f, dxpl_id, oh)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk")
+ else if(result > 0)
+ /* Get out of loop */
+ break;
+
+ /* If the merged message is too large, shrink the chunk */
+ if(curr_msg->raw_size >= H5O_MESG_MAX_SIZE)
+ if(H5O_alloc_shrink_chunk(f, dxpl_id, oh, curr_msg->chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "unable to shrink chunk")
+
+ /* Get out of loop */
+ break;
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ /* Get out of loop if we merged messages */
+ if(merged_msg)
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* If we did any merging, remember that */
+ if(merged_msg)
+ did_merging = TRUE;
+ } while(merged_msg);
+
+ /* Set return value */
+ ret_value = (htri_t)did_merging;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_merge_null() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_remove_empty_chunks
+ *
+ * Purpose: Attempt to eliminate empty chunks from object header.
+ *
+ * This examines a chunk to see if it's empty
+ * and removes it (and the continuation message that points to it)
+ * from the object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 17 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
+{
+ hbool_t deleted_chunk; /* Whether to a chunk was deleted */
+ hbool_t did_deleting = FALSE; /* Whether any chunks were deleted */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh != NULL);
+
+ /* Loop until no chunks are freed */
+ do {
+ H5O_mesg_t *null_msg; /* Pointer to null message found */
+ H5O_mesg_t *cont_msg; /* Pointer to continuation message found */
+ unsigned u, v; /* Local index variables */
+
+ /* Reset 'chunk deleted' flag */
+ deleted_chunk = FALSE;
+
+ /* Scan messages for null messages that fill an entire chunk */
+ for(u = 0, null_msg = &oh->mesg[0]; u < oh->nmesgs; u++, null_msg++) {
+ /* If a null message takes up an entire object header chunk (and
+ * its not the "base" chunk), delete that chunk from object header
+ */
+ if(H5O_NULL_ID == null_msg->type->id && null_msg->chunkno > 0 &&
+ ((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + null_msg->raw_size)
+ == (oh->chunk[null_msg->chunkno].size - H5O_SIZEOF_CHKHDR_OH(oh))) {
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
+ unsigned null_msg_no; /* Message # for null message */
+ unsigned deleted_chunkno; /* Chunk # to delete */
+
+ /* Locate continuation message that points to chunk */
+ for(v = 0, cont_msg = &oh->mesg[0]; v < oh->nmesgs; v++, cont_msg++) {
+ if(H5O_CONT_ID == cont_msg->type->id) {
+ /* Decode current continuation message if necessary */
+ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL)
+
+ /* Check if the chunkno needs to be set */
+ /* (should only occur when the continuation message is first decoded) */
+ if(0 == ((H5O_cont_t *)(cont_msg->native))->chunkno) {
+ unsigned w; /* Local index variable */
+
+ /* Find chunk that this continuation message points to */
+ for(w = 0; w < oh->nchunks; w++)
+ if(oh->chunk[w].addr == ((H5O_cont_t *)(cont_msg->native))->addr) {
+ ((H5O_cont_t *)(cont_msg->native))->chunkno = w;
+ break;
+ } /* end if */
+ HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno > 0);
+ } /* end if */
+
+ /* Check for correct chunk to delete */
+ if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr)
+ break;
+ } /* end if */
+ } /* end for */
+ /* Must be a continuation message that points to chunk containing null message */
+ HDassert(v < oh->nmesgs);
+ HDassert(cont_msg);
+ HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno == null_msg->chunkno);
+
+ /* Initialize information about null message */
+ null_msg_no = u;
+ deleted_chunkno = null_msg->chunkno;
+
+ /* Convert continuation message into a null message */
+ if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message")
+
+ /*
+ * Remove chunk from object header's data structure
+ */
+
+ /* Free memory for chunk image */
+ oh->chunk[null_msg->chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image);
+
+ /* Remove chunk from list of chunks */
+ if(null_msg->chunkno < (oh->nchunks - 1)) {
+ HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t));
+
+ /* Adjust chunk number for any chunk proxies that are in the cache */
+ for(u = null_msg->chunkno; u < (oh->nchunks - 1); u++) {
+ unsigned chk_proxy_status = 0; /* Metadata cache status of chunk proxy for chunk */
+
+ /* Check the chunk proxy's status in the metadata cache */
+ if(H5AC_get_entry_status(f, oh->chunk[u].addr, &chk_proxy_status) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check metadata cache status for chunk proxy")
+
+ /* If the entry is in the cache, update its chunk index */
+ if(chk_proxy_status & H5AC_ES__IN_CACHE) {
+ if(H5O_chunk_update_idx(f, dxpl_id, oh, u) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to update index for chunk proxy")
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Decrement # of chunks */
+ /* (Don't bother reducing size of chunk array for now -QAK) */
+ oh->nchunks--;
+
+ /*
+ * Delete null message (in empty chunk that was be freed) from list of messages
+ */
+
+ /* Release any information/memory for message */
+ H5O_msg_free_mesg(null_msg);
+
+ /* Remove null message from list of messages */
+ if(null_msg_no < (oh->nmesgs - 1))
+ HDmemmove(&oh->mesg[null_msg_no], &oh->mesg[null_msg_no + 1], ((oh->nmesgs - 1) - null_msg_no) * sizeof(H5O_mesg_t));
+
+ /* Decrement # of messages */
+ /* (Don't bother reducing size of message array for now -QAK) */
+ oh->nmesgs--;
+
+ /* Adjust chunk # for messages in chunks after deleted chunk */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ /* Sanity check - there should be no messages in deleted chunk */
+ HDassert(curr_msg->chunkno != deleted_chunkno);
+
+ /* Adjust chunk index for messages in later chunks */
+ if(curr_msg->chunkno > deleted_chunkno)
+ curr_msg->chunkno--;
+
+ /* Check for continuation message */
+ if(H5O_CONT_ID == curr_msg->type->id) {
+ /* Decode current continuation message if necessary */
+ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, curr_msg, FAIL)
+
+ /* Check if the chunkno needs to be set */
+ /* (should only occur when the continuation message is first decoded) */
+ if(0 == ((H5O_cont_t *)(curr_msg->native))->chunkno) {
+ unsigned w; /* Local index variable */
+
+ /* Find chunk that this continuation message points to */
+ for(w = 0; w < oh->nchunks; w++)
+ if(oh->chunk[w].addr == ((H5O_cont_t *)(curr_msg->native))->addr) {
+ ((H5O_cont_t *)(curr_msg->native))->chunkno = w;
+ break;
+ } /* end if */
+ HDassert(((H5O_cont_t *)(curr_msg->native))->chunkno > 0);
+ } /* end if */
+ else {
+ /* Check for pointer to chunk after deleted chunk */
+ if(((H5O_cont_t *)(curr_msg->native))->chunkno > deleted_chunkno)
+ ((H5O_cont_t *)(curr_msg->native))->chunkno--;
+ } /* end else */
+ } /* end if */
+ } /* end for */
+
+ /* Found chunk to delete */
+ deleted_chunk = TRUE;
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* If we deleted any chunks, remember that */
+ if(deleted_chunk)
+ did_deleting = TRUE;
+ } while(deleted_chunk);
+
+ /* Set return value */
+ ret_value = (htri_t)did_deleting;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_remove_empty_chunks() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_condense_header
+ *
+ * Purpose: Attempt to eliminate empty chunks from object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Oct 4 2005
+ *
+ * Modifications:
+ * Feb. 2009: Vailin Choi
+ * Add 2 more parameters to H5O_move_msgs_forward() for moving
+ * messages forward into "continuation" message
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
+{
+ hbool_t rescan_header; /* Whether to rescan header */
+ htri_t result; /* Result from packing/merging/etc */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh != NULL);
+
+ /* Loop until no changed to the object header messages & chunks */
+ do {
+ /* Reset 'rescan chunks' flag */
+ rescan_header = FALSE;
+
+ /* Scan for messages that can be moved earlier in chunks */
+ result = H5O_move_msgs_forward(f, dxpl_id, oh);
+ if(result < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward")
+ if(result > 0)
+ rescan_header = TRUE;
+
+ /* Scan for adjacent null messages & merge them */
+ result = H5O_merge_null(f, dxpl_id, oh);
+ if(result < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages")
+ if(result > 0)
+ rescan_header = TRUE;
+
+ /* Scan for empty chunks to remove */
+ result = H5O_remove_empty_chunks(f, dxpl_id, oh);
+ if(result < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk")
+ if(result > 0)
+ rescan_header = TRUE;
+ } while(rescan_header);
+#ifdef H5O_DEBUG
+H5O_assert(oh);
+#endif /* H5O_DEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_condense_header() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5O_alloc_shrink_chunk
+ *
+ * Purpose: Shrinks a chunk, removing all null messages and any gap.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Oct 20 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno)
+{
+ H5O_chunk_t *chunk = &oh->chunk[chunkno]; /* Chunk to shrink */
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Metadata cache proxy for chunk to shrink */
+ H5O_mesg_t *curr_msg; /* Current message to examine */
+ uint8_t *old_image = chunk->image; /* Old address of chunk's image in memory */
+ size_t old_size = chunk->size; /* Old size of chunk */
+ size_t new_size = chunk->size - chunk->gap; /* Size of shrunk chunk */
+ size_t total_msg_size; /* Size of the messages in this chunk */
+ size_t min_chunk_size = H5O_ALIGN_OH(oh, H5O_MIN_SIZE); /* Minimum chunk size */
+ size_t sizeof_chksum = H5O_SIZEOF_CHKSUM_OH(oh); /* Size of chunk checksum */
+ size_t sizeof_msghdr = H5O_SIZEOF_MSGHDR_OH(oh); /* Size of message header */
+ uint8_t new_size_flags = 0; /* New chunk #0 size flags */
+ hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */
+ size_t less_prfx_size = 0; /* Bytes removed from object header prefix */
+ size_t u; /* Index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
+
+ /* Loop backwards to increase the chance of seeing more null messages at the
+ * end of the chunk. Note that we rely on unsigned u wrapping around at the
+ * end.
+ */
+ for(u = oh->nmesgs - 1, curr_msg = &oh->mesg[u]; u < oh->nmesgs; u--, curr_msg--) {
+ if((H5O_NULL_ID == curr_msg->type->id) && (chunkno == curr_msg->chunkno)) {
+ size_t shrink_size = curr_msg->raw_size + sizeof_msghdr; /* Amount to shrink the chunk by */
+
+ /* If the current message is not at the end of the chunk, copy the
+ * data after it (except the checksum).
+ */
+ if(curr_msg->raw + curr_msg->raw_size
+ < old_image + new_size - sizeof_chksum) {
+ unsigned v; /* Index */
+ H5O_mesg_t *curr_msg2;
+ uint8_t *src = curr_msg->raw + curr_msg->raw_size; /* Source location */
+
+ /* Slide down the raw data */
+ HDmemmove(curr_msg->raw - sizeof_msghdr, src,
+ (size_t)(old_image + new_size - sizeof_chksum - src));
+
+ /* Update the raw data pointers for messages after this one */
+ for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++)
+ if((chunkno == curr_msg2->chunkno) && (curr_msg2->raw > curr_msg->raw))
+ curr_msg2->raw -= shrink_size;
+ } /* end if */
+
+ /* Adjust the new chunk size */
+ new_size -= shrink_size;
+
+ /* Release any information/memory for the message */
+ H5O_msg_free_mesg(curr_msg);
+
+ /* Remove the deleted null message from list of messages */
+ if(u < (oh->nmesgs - 1))
+ HDmemmove(&oh->mesg[u], &oh->mesg[u+1], ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t));
+
+ /* Decrement # of messages */
+ /* (Don't bother reducing size of message array for now) */
+ oh->nmesgs--;
+ } /* end if */
+ } /* end for */
+
+ /* Check if the chunk is too small, extend if necessary */
+ total_msg_size = new_size - (size_t)(chunkno == 0 ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh));
+ if(total_msg_size < min_chunk_size) {
+ HDassert(oh->alloc_nmesgs > oh->nmesgs);
+ oh->nmesgs++;
+
+ /* Initialize new null message to make the chunk large enough */
+ oh->mesg[oh->nmesgs].type = H5O_MSG_NULL;
+ oh->mesg[oh->nmesgs].dirty = TRUE;
+ oh->mesg[oh->nmesgs].native = NULL;
+ oh->mesg[oh->nmesgs].raw = old_image + new_size + sizeof_msghdr - sizeof_chksum;
+ oh->mesg[oh->nmesgs].raw_size = MAX(H5O_ALIGN_OH(oh, min_chunk_size - total_msg_size),
+ sizeof_msghdr) - sizeof_msghdr;
+ oh->mesg[oh->nmesgs].chunkno = chunkno;
+
+ /* update the new chunk size */
+ new_size += oh->mesg[oh->nmesgs].raw_size + sizeof_msghdr;
+ } /* end if */
+
+ /* Check for changing the chunk #0 data size enough to need adjusting the flags */
+ if(oh->version > H5O_VERSION_1 && chunkno == 0) {
+ uint64_t chunk0_newsize = new_size - (size_t)H5O_SIZEOF_HDR(oh); /* New size of chunk 0's data */
+ size_t orig_prfx_size = (size_t)1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */
+
+ /* Check for moving to a 1-byte size encoding */
+ if(orig_prfx_size > 1 && chunk0_newsize <= 255) {
+ less_prfx_size = orig_prfx_size - 1;
+ new_size_flags = H5O_HDR_CHUNK0_1;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ /* Check for moving to a 2-byte size encoding */
+ else if(orig_prfx_size > 2 && chunk0_newsize <= 65535) {
+ less_prfx_size = orig_prfx_size - 2;
+ new_size_flags = H5O_HDR_CHUNK0_2;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ /* Check for moving to a 4-byte size encoding */
+ else if(orig_prfx_size > 4 && chunk0_newsize <= 4294967295) {
+ less_prfx_size = orig_prfx_size - 4;
+ new_size_flags = H5O_HDR_CHUNK0_4;
+ adjust_size_flags = TRUE;
+ } /* end if */
+ } /* end if */
+
+ if(adjust_size_flags) {
+ /* Adjust object header prefix flags */
+ oh->flags = (uint8_t)(oh->flags & ~H5O_HDR_CHUNK0_SIZE);
+ oh->flags |= new_size_flags;
+
+ /* Slide chunk 0 data down */
+ HDmemmove(chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum,
+ chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum + less_prfx_size,
+ new_size - (size_t)H5O_SIZEOF_HDR(oh));
+
+ /* Adjust chunk size */
+ new_size -= less_prfx_size;
+ } /* end if */
+
+ /* Allocate less memory space for chunk's image */
+ chunk->size = new_size;
+ chunk->image = H5FL_BLK_REALLOC(chunk_image, old_image, chunk->size);
+ chunk->gap = 0;
+ if(NULL == oh->chunk[chunkno].image)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Spin through existing messages, adjusting them */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ if(adjust_size_flags || (chunk->image != old_image))
+ /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */
+ if(curr_msg->chunkno == chunkno)
+ curr_msg->raw = chunk->image - less_prfx_size + (curr_msg->raw - old_image);
+
+ /* Find continuation message which points to this chunk and adjust chunk's size */
+ /* (Chunk 0 doesn't have a continuation message that points to it and
+ * its size is directly encoded in the object header) */
+ if(chunkno > 0 && (H5O_CONT_ID == curr_msg->type->id) &&
+ (((H5O_cont_t *)(curr_msg->native))->chunkno == chunkno)) {
+ H5O_chunk_proxy_t *cont_chk_proxy; /* Chunk that message is in */
+
+ /* Protect chunk */
+ if(NULL == (cont_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
+
+ /* Adjust size of continuation message */
+ HDassert(((H5O_cont_t *)(curr_msg->native))->size == old_size);
+ ((H5O_cont_t *)(curr_msg->native))->size = chunk->size;
+
+ /* Flag continuation message as dirty */
+ curr_msg->dirty = TRUE;
+
+ /* Release chunk, marking it dirty */
+ if(H5O_chunk_unprotect(f, dxpl_id, cont_chk_proxy, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+ } /* end if */
+ } /* end for */
+
+ HDassert(new_size <= old_size);
+
+ /* Resize the chunk in the cache */
+ if(H5O_chunk_resize(oh, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize object header chunk")
+
+ /* Free the unused space in the file */
+ if(H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chunk->addr + new_size, (hsize_t)(old_size - new_size)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to shrink object header chunk")
+
+done:
+ /* Release chunk, marking it dirty */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_alloc_shrink_chunk() */
+
diff --git a/src/H5Oattr.c b/src/H5Oattr.c
new file mode 100644
index 0000000..cb802ea
--- /dev/null
+++ b/src/H5Oattr.c
@@ -0,0 +1,884 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define H5A_FRIEND /*suppress error about including H5Apkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+#define H5S_FRIEND /*suppress error about including H5Spkg */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Spkg.h" /* Dataspaces */
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5O_attr_encode(H5F_t *f, uint8_t *p, const void *mesg);
+static void *H5O_attr_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static void *H5O_attr_copy(const void *_mesg, void *_dest);
+static size_t H5O_attr_size(const H5F_t *f, const void *_mesg);
+static herr_t H5O_attr_free(void *mesg);
+static herr_t H5O_attr_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata);
+static void *H5O_attr_copy_file(H5F_t *file_src, const H5O_msg_class_t *mesg_type,
+ void *native_src, H5F_t *file_dst, hbool_t *recompute_size,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_attr_post_copy_file(const H5O_loc_t *src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst, hid_t dxpl_id,
+ H5O_copy_t *cpy_info);
+static herr_t H5O_attr_get_crt_index(const void *_mesg, H5O_msg_crt_idx_t *crt_idx);
+static herr_t H5O_attr_set_crt_index(void *_mesg, H5O_msg_crt_idx_t crt_idx);
+static herr_t H5O_attr_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* Set up & include shared message "interface" info */
+#define H5O_SHARED_TYPE H5O_MSG_ATTR
+#define H5O_SHARED_DECODE H5O_attr_shared_decode
+#define H5O_SHARED_DECODE_REAL H5O_attr_decode
+#define H5O_SHARED_ENCODE H5O_attr_shared_encode
+#define H5O_SHARED_ENCODE_REAL H5O_attr_encode
+#define H5O_SHARED_SIZE H5O_attr_shared_size
+#define H5O_SHARED_SIZE_REAL H5O_attr_size
+#define H5O_SHARED_DELETE H5O_attr_shared_delete
+#define H5O_SHARED_DELETE_REAL H5O_attr_delete
+#define H5O_SHARED_LINK H5O_attr_shared_link
+#define H5O_SHARED_LINK_REAL H5O_attr_link
+#define H5O_SHARED_COPY_FILE H5O_attr_shared_copy_file
+#define H5O_SHARED_COPY_FILE_REAL H5O_attr_copy_file
+#define H5O_SHARED_POST_COPY_FILE H5O_attr_shared_post_copy_file
+#define H5O_SHARED_POST_COPY_FILE_REAL H5O_attr_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_UPD
+#define H5O_SHARED_DEBUG H5O_attr_shared_debug
+#define H5O_SHARED_DEBUG_REAL H5O_attr_debug
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_ATTR[1] = {{
+ H5O_ATTR_ID, /* message id number */
+ "attribute", /* message name for debugging */
+ sizeof(H5A_t), /* native message size */
+ H5O_SHARE_IS_SHARABLE, /* messages are sharable? */
+ H5O_attr_shared_decode, /* decode message */
+ H5O_attr_shared_encode, /* encode message */
+ H5O_attr_copy, /* copy the native value */
+ H5O_attr_shared_size, /* size of raw message */
+ H5O_attr_reset, /* reset method */
+ H5O_attr_free, /* free method */
+ H5O_attr_shared_delete, /* file delete method */
+ H5O_attr_shared_link, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ H5O_attr_pre_copy_file, /* pre copy native value to file */
+ H5O_attr_shared_copy_file, /* copy native value to file */
+ H5O_attr_shared_post_copy_file, /* post copy native value to file */
+ H5O_attr_get_crt_index, /* get creation index */
+ H5O_attr_set_crt_index, /* set creation index */
+ H5O_attr_shared_debug /* debug the message */
+}};
+
+/* Flags for attribute flag encoding */
+#define H5O_ATTR_FLAG_TYPE_SHARED 0x01
+#define H5O_ATTR_FLAG_SPACE_SHARED 0x02
+#define H5O_ATTR_FLAG_ALL 0x03
+
+/* Declare external the free list for H5S_t's */
+H5FL_EXTERN(H5S_t);
+
+/* Declare external the free list for H5S_extent_t's */
+H5FL_EXTERN(H5S_extent_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_decode
+ PURPOSE
+ Decode a attribute message and return a pointer to a memory struct
+ with the decoded information
+ USAGE
+ void *H5O_attr_decode(f, dxpl_id, mesg_flags, p)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ hid_t dxpl_id; IN: DXPL for any I/O
+ unsigned mesg_flags; IN: Message flags to influence decoding
+ const uint8_t *p; IN: the raw information buffer
+ RETURNS
+ Pointer to the new message in native order on success, NULL on failure
+ DESCRIPTION
+ This function decodes the "raw" disk form of a attribute message
+ into a struct in memory native format. The struct is allocated within this
+ function using malloc() and is returned to the caller.
+--------------------------------------------------------------------------*/
+static void *
+H5O_attr_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
+ unsigned *ioflags, const uint8_t *p)
+{
+ H5A_t *attr = NULL;
+ H5S_extent_t *extent; /*extent dimensionality information */
+ size_t name_len; /*attribute name length */
+ size_t dt_size; /* Datatype size */
+ hssize_t sds_size; /* Signed Dataspace size */
+ hsize_t ds_size; /* Dataspace size */
+ unsigned flags = 0; /* Attribute flags */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ if(NULL == (attr = H5FL_CALLOC(H5A_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ if(NULL == (attr->shared = H5FL_CALLOC(H5A_shared_t)))
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate shared attr structure")
+
+ /* Version number */
+ attr->shared->version = *p++;
+ if(attr->shared->version < H5O_ATTR_VERSION_1 || attr->shared->version > H5O_ATTR_VERSION_LATEST)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, NULL, "bad version number for attribute message")
+
+ /* Get the flags byte if we have a later version of the attribute */
+ if(attr->shared->version >= H5O_ATTR_VERSION_2) {
+ flags = *p++;
+
+ /* Check for unknown flag */
+ if(flags & (unsigned)~H5O_ATTR_FLAG_ALL)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, NULL, "unknown flag for attribute message")
+ } /* end if */
+ else
+ p++; /* Byte is unused when version<2 */
+
+ /*
+ * Decode the sizes of the parts of the attribute. The sizes stored in
+ * the file are exact but the parts are aligned on 8-byte boundaries.
+ */
+ UINT16DECODE(p, name_len); /*including null*/
+ UINT16DECODE(p, attr->shared->dt_size);
+ UINT16DECODE(p, attr->shared->ds_size);
+
+ /*
+ * Decode the character encoding for the name for versions 3 or later,
+ * as well as some reserved bytes.
+ */
+ if(attr->shared->version >= H5O_ATTR_VERSION_3)
+ attr->shared->encoding = (H5T_cset_t)*p++;
+
+ /* Decode and store the name */
+ if(NULL == (attr->shared->name = H5MM_strdup((const char *)p)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(attr->shared->version < H5O_ATTR_VERSION_2)
+ p += H5O_ALIGN_OLD(name_len); /* advance the memory pointer */
+ else
+ p += name_len; /* advance the memory pointer */
+
+ /* Decode the attribute's datatype */
+ if(NULL == (attr->shared->dt = (H5T_t *)(H5O_MSG_DTYPE->decode)(f, dxpl_id, open_oh,
+ ((flags & H5O_ATTR_FLAG_TYPE_SHARED) ? H5O_MSG_FLAG_SHARED : 0), ioflags, p)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDECODE, NULL, "can't decode attribute datatype")
+ if(attr->shared->version < H5O_ATTR_VERSION_2)
+ p += H5O_ALIGN_OLD(attr->shared->dt_size);
+ else
+ p += attr->shared->dt_size;
+
+ /* decode the attribute dataspace. It can be shared in versions >= 3
+ * What's actually shared, though, is only the extent.
+ */
+ if(NULL == (attr->shared->ds = H5FL_CALLOC(H5S_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Decode attribute's dataspace extent */
+ if((extent = (H5S_extent_t *)(H5O_MSG_SDSPACE->decode)(f, dxpl_id, open_oh,
+ ((flags & H5O_ATTR_FLAG_SPACE_SHARED) ? H5O_MSG_FLAG_SHARED : 0), ioflags, p)) == NULL)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDECODE, NULL, "can't decode attribute dataspace")
+
+ /* Copy the extent information to the dataspace */
+ HDmemcpy(&(attr->shared->ds->extent), extent, sizeof(H5S_extent_t));
+
+ /* Release temporary extent information */
+ extent = H5FL_FREE(H5S_extent_t, extent);
+
+ /* Default to entire dataspace being selected */
+ if(H5S_select_all(attr->shared->ds, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, NULL, "unable to set all selection")
+
+ if(attr->shared->version < H5O_ATTR_VERSION_2)
+ p += H5O_ALIGN_OLD(attr->shared->ds_size);
+ else
+ p += attr->shared->ds_size;
+
+ /* Get the datatype's size */
+ if(0 == (dt_size = H5T_get_size(attr->shared->dt)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "unable to get datatype size")
+
+ /* Get the datatype & dataspace sizes */
+ if(0 == (dt_size = H5T_get_size(attr->shared->dt)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "unable to get datatype size")
+ if((sds_size = H5S_GET_EXTENT_NPOINTS(attr->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "unable to get dataspace size")
+ ds_size = (hsize_t)sds_size;
+
+ /* Compute the size of the data */
+ H5_CHECKED_ASSIGN(attr->shared->data_size, size_t, ds_size * (hsize_t)dt_size, hsize_t);
+
+ /* Go get the data */
+ if(attr->shared->data_size) {
+ if(NULL == (attr->shared->data = H5FL_BLK_MALLOC(attr_buf, attr->shared->data_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(attr->shared->data, p, attr->shared->data_size);
+ } /* end if */
+
+ /* Increment the reference count for this object header message in cache(compact
+ storage) or for the object from dense storage. */
+ attr->shared->nrefs++;
+
+ /* Set return value */
+ ret_value = attr;
+
+done:
+ if(NULL == ret_value)
+ if(attr) {
+ if(attr->shared) {
+ /* Free any dynamicly allocated items */
+ if(H5A_free(attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, NULL, "can't release attribute info")
+
+ /* Destroy shared attribute struct */
+ attr->shared = H5FL_FREE(H5A_shared_t, attr->shared);
+ } /* end if */
+
+ attr = H5FL_FREE(H5A_t, attr);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_decode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_encode
+ PURPOSE
+ Encode a simple attribute message
+ USAGE
+ herr_t H5O_attr_encode(f, p, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const uint8 *p; IN: the raw information buffer
+ const void *mesg; IN: Pointer to the simple datatype struct
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function encodes the native memory form of the attribute
+ message in the "raw" disk form.
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_attr_encode(H5F_t *f, uint8_t *p, const void *mesg)
+{
+ const H5A_t *attr = (const H5A_t *) mesg;
+ size_t name_len; /* Attribute name length */
+ htri_t is_type_shared; /* Flag to indicate that a shared datatype is used for this attribute */
+ htri_t is_space_shared; /* Flag to indicate that a shared dataspace is used for this attribute */
+ unsigned flags = 0; /* Attribute flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(attr);
+
+ /* Check whether datatype and dataspace are shared */
+ if((is_type_shared = H5O_msg_is_shared(H5O_DTYPE_ID, attr->shared->dt)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "can't determine if datatype is shared")
+
+ if((is_space_shared = H5O_msg_is_shared(H5O_SDSPACE_ID, attr->shared->ds)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "can't determine if dataspace is shared")
+
+ /* Encode Version */
+ *p++ = attr->shared->version;
+
+ /* Set attribute flags if version >1 */
+ if(attr->shared->version >= H5O_ATTR_VERSION_2) {
+ flags = (is_type_shared ? H5O_ATTR_FLAG_TYPE_SHARED : 0 );
+ flags |= (is_space_shared ? H5O_ATTR_FLAG_SPACE_SHARED : 0);
+ *p++ = (uint8_t)flags; /* Set flags for attribute */
+ } /* end if */
+ else
+ *p++ = 0; /* Reserved, for version <2 */
+
+ /*
+ * Encode the lengths of the various parts of the attribute message. The
+ * encoded lengths are exact but we pad each part except the data to be a
+ * multiple of eight bytes (in the first version).
+ */
+ name_len = HDstrlen(attr->shared->name) + 1;
+ UINT16ENCODE(p, name_len);
+ UINT16ENCODE(p, attr->shared->dt_size);
+ UINT16ENCODE(p, attr->shared->ds_size);
+
+ /* The character encoding for the attribute's name, in later versions */
+ if(attr->shared->version >= H5O_ATTR_VERSION_3)
+ *p++ = attr->shared->encoding;
+
+ /* Write the name including null terminator */
+ HDmemcpy(p, attr->shared->name, name_len);
+ if(attr->shared->version < H5O_ATTR_VERSION_2) {
+ /* Pad to the correct number of bytes */
+ HDmemset(p + name_len, 0, H5O_ALIGN_OLD(name_len) - name_len);
+ p += H5O_ALIGN_OLD(name_len);
+ } /* end if */
+ else
+ p += name_len;
+
+ /* encode the attribute datatype */
+ if((H5O_MSG_DTYPE->encode)(f, FALSE, p, attr->shared->dt) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute datatype")
+
+ if(attr->shared->version < H5O_ATTR_VERSION_2) {
+ HDmemset(p + attr->shared->dt_size, 0, H5O_ALIGN_OLD(attr->shared->dt_size) - attr->shared->dt_size);
+ p += H5O_ALIGN_OLD(attr->shared->dt_size);
+ } /* end if */
+ else
+ p += attr->shared->dt_size;
+
+ /* encode the attribute dataspace */
+ if((H5O_MSG_SDSPACE->encode)(f, FALSE, p, &(attr->shared->ds->extent)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute dataspace")
+
+ if(attr->shared->version < H5O_ATTR_VERSION_2) {
+ HDmemset(p + attr->shared->ds_size, 0, H5O_ALIGN_OLD(attr->shared->ds_size) - attr->shared->ds_size);
+ p += H5O_ALIGN_OLD(attr->shared->ds_size);
+ } /* end if */
+ else
+ p += attr->shared->ds_size;
+
+ /* Store attribute data. If there's no data, store 0 as fill value. */
+ if(attr->shared->data)
+ HDmemcpy(p, attr->shared->data, attr->shared->data_size);
+ else
+ HDmemset(p, 0, attr->shared->data_size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_attr_encode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_copy
+ PURPOSE
+ Copies a message from MESG to DEST, allocating DEST if necessary.
+ USAGE
+ void *H5O_attr_copy(mesg, dest)
+ const void *mesg; IN: Pointer to the source attribute struct
+ const void *dest; IN: Pointer to the destination attribute struct
+ RETURNS
+ Pointer to DEST on success, NULL on failure
+ DESCRIPTION
+ This function copies a native (memory) attribute message,
+ allocating the destination structure if necessary.
+--------------------------------------------------------------------------*/
+static void *
+H5O_attr_copy(const void *_src, void *_dst)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(_src);
+
+ /* copy */
+ if(NULL == (ret_value = (H5A_t *)H5A_copy((H5A_t *)_dst, (const H5A_t *)_src)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "can't copy attribute")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_size
+ PURPOSE
+ Return the raw message size in bytes
+ USAGE
+ size_t H5O_attr_size(f, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source attribute struct
+ RETURNS
+ Size of message on success, 0 on failure
+ DESCRIPTION
+ This function returns the size of the raw attribute message on
+ success. (Not counting the message type or size fields, only the data
+ portion of the message). It doesn't take into account alignment.
+--------------------------------------------------------------------------*/
+static size_t
+H5O_attr_size(const H5F_t H5_ATTR_UNUSED *f, const void *_mesg)
+{
+ const H5A_t *attr = (const H5A_t *)_mesg;
+ size_t name_len;
+ size_t ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(attr);
+
+ /* Common size information */
+ ret_value = 1 + /*version */
+ 1 + /*reserved/flags */
+ 2 + /*name size inc. null */
+ 2 + /*type size */
+ 2; /*space size */
+
+ /* Length of attribute name */
+ name_len = HDstrlen(attr->shared->name) + 1;
+
+ /* Version-specific size information */
+ if(attr->shared->version == H5O_ATTR_VERSION_1)
+ ret_value += H5O_ALIGN_OLD(name_len) + /*attribute name */
+ H5O_ALIGN_OLD(attr->shared->dt_size) + /*datatype */
+ H5O_ALIGN_OLD(attr->shared->ds_size) + /*dataspace */
+ attr->shared->data_size; /*the data itself */
+ else if(attr->shared->version == H5O_ATTR_VERSION_2)
+ ret_value += name_len + /*attribute name */
+ attr->shared->dt_size + /*datatype */
+ attr->shared->ds_size + /*dataspace */
+ attr->shared->data_size; /*the data itself */
+ else if(attr->shared->version == H5O_ATTR_VERSION_3)
+ ret_value += 1 + /*character encoding */
+ name_len + /*attribute name */
+ attr->shared->dt_size + /*datatype */
+ attr->shared->ds_size + /*dataspace */
+ attr->shared->data_size; /*the data itself */
+ else
+ HDassert(0 && "Bad attribute version");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_reset
+ *
+ * Purpose: Frees resources within a attribute message, but doesn't free
+ * the message itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modification:Raymond Lu
+ * 25 June 2008
+ * Made this function empty. The freeing action is actually
+ * done in H5O_attr_free (see H5O_msg_free_real). But this
+ * empty reset function needs to be here. Otherwise, the
+ * caller function H5O_msg_reset_real will zero-set the whole
+ * message.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_reset(void H5_ATTR_UNUSED *_mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_attr_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 18, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_free(void *mesg)
+{
+ H5A_t *attr = (H5A_t *)mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(mesg);
+
+ if(H5A_close(attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "unable to close attribute object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 26, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *_mesg)
+{
+ H5A_t *attr = (H5A_t *) _mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(attr);
+
+ /* Decrement reference count on datatype in file */
+ if((H5O_MSG_DTYPE->del)(f, dxpl_id, oh, attr->shared->dt) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust datatype link count")
+
+ /* Decrement reference count on dataspace in file */
+ if((H5O_MSG_SDSPACE->del)(f, dxpl_id, oh, attr->shared->ds) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust dataspace link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_link
+ *
+ * Purpose: Increment reference count on any objects referenced by
+ * message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 26, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_link(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *_mesg)
+{
+ H5A_t *attr = (H5A_t *) _mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(attr);
+
+ /* Re-share attribute's datatype and dataspace to increment their
+ * reference count if they're shared.
+ * Otherwise they may be deleted when the attribute
+ * message is deleted.
+ */
+ /* Increment reference count on datatype & dataspace in file */
+ if((H5O_MSG_DTYPE->link)(f, dxpl_id, oh, attr->shared->dt) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust datatype link count")
+ if((H5O_MSG_SDSPACE->link)(f, dxpl_id, oh, attr->shared->ds) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust dataspace link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files for attribute messages.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 26, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(deleted);
+ HDassert(cpy_info);
+
+ /* If we are not copying attributes into the destination file, indicate
+ * that this message should be deleted.
+ */
+ if(cpy_info->copy_without_attr)
+ *deleted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_attr_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * November 1, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_attr_copy_file(H5F_t *file_src, const H5O_msg_class_t H5_ATTR_UNUSED *mesg_type,
+ void *native_src, H5F_t *file_dst, hbool_t *recompute_size,
+ H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata, hid_t dxpl_id)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(native_src);
+ HDassert(file_dst);
+ HDassert(cpy_info);
+ HDassert(!cpy_info->copy_without_attr);
+
+ /* Mark datatype as being on disk now. This step used to be done in a lower level
+ * by H5O_dtype_decode. But it has been moved up. Not an ideal place, but no better
+ * place than here. */
+ if(H5T_set_loc(((H5A_t *)native_src)->shared->dt, file_src, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ if(NULL == (ret_value = H5A_attr_copy_file((H5A_t *)native_src, file_dst, recompute_size, cpy_info, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy attribute")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_attr_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files.
+ * We have to copy the values of a reference attribute in the
+ * post copy because H5O_post_copy_file() fails at the case that
+ * an object may have a reference attribute that points to the
+ * object itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * March 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
+ H5O_loc_t *dst_oloc, void *mesg_dst, hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if ( H5A_attr_post_copy_file(src_oloc, (const H5A_t *)mesg_src,
+ dst_oloc, (H5A_t *)mesg_dst, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't copy attribute")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_attr_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_get_crt_index
+ *
+ * Purpose: Get creation index from the message
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_get_crt_index(const void *_mesg, H5O_msg_crt_idx_t *crt_idx /*out*/)
+{
+ const H5A_t *attr = (const H5A_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(attr);
+ HDassert(crt_idx);
+
+ /* Get the attribute's creation index */
+ *crt_idx = attr->shared->crt_idx;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_attr_get_crt_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_set_crt_index
+ *
+ * Purpose: Set creation index from the message
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_set_crt_index(void *_mesg, H5O_msg_crt_idx_t crt_idx)
+{
+ H5A_t *attr = (H5A_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(attr);
+
+ /* Set the creation index */
+ attr->shared->crt_idx = crt_idx;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_attr_set_crt_index() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_debug
+ PURPOSE
+ Prints debugging information for an attribute message
+ USAGE
+ void *H5O_attr_debug(f, mesg, stream, indent, fwidth)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source attribute struct
+ FILE *stream; IN: Pointer to the stream for output data
+ int indent; IN: Amount to indent information by
+ int fwidth; IN: Field width (?)
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function prints debugging output to the stream passed as a
+ parameter.
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_attr_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream, int indent,
+ int fwidth)
+{
+ const H5A_t *mesg = (const H5A_t *)_mesg;
+ const char *s; /* Temporary string pointer */
+ char buf[128]; /* Temporary string buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s \"%s\"\n", indent, "", fwidth,
+ "Name:",
+ mesg->shared->name);
+ switch(mesg->shared->encoding) {
+ case H5T_CSET_ASCII:
+ s = "ASCII";
+ break;
+
+ case H5T_CSET_UTF8:
+ s = "UTF-8";
+ break;
+
+ case H5T_CSET_RESERVED_2:
+ case H5T_CSET_RESERVED_3:
+ case H5T_CSET_RESERVED_4:
+ case H5T_CSET_RESERVED_5:
+ case H5T_CSET_RESERVED_6:
+ case H5T_CSET_RESERVED_7:
+ case H5T_CSET_RESERVED_8:
+ case H5T_CSET_RESERVED_9:
+ case H5T_CSET_RESERVED_10:
+ case H5T_CSET_RESERVED_11:
+ case H5T_CSET_RESERVED_12:
+ case H5T_CSET_RESERVED_13:
+ case H5T_CSET_RESERVED_14:
+ case H5T_CSET_RESERVED_15:
+ HDsnprintf(buf, sizeof(buf), "H5T_CSET_RESERVED_%d", (int)(mesg->shared->encoding));
+ s = buf;
+ break;
+
+ case H5T_CSET_ERROR:
+ default:
+ HDsnprintf(buf, sizeof(buf), "Unknown character set: %d", (int)(mesg->shared->encoding));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Character Set of Name:",
+ s);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Object opened:",
+ mesg->obj_opened);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Object:",
+ mesg->oloc.addr);
+
+ /* Check for attribute creation order index on the attribute */
+ if(mesg->shared->crt_idx != H5O_MAX_CRT_ORDER_IDX)
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Creation Index:",
+ (unsigned)mesg->shared->crt_idx);
+
+ HDfprintf(stream, "%*sDatatype...\n", indent, "");
+ HDfprintf(stream, "%*s%-*s %lu\n", indent + 3, "", MAX(0,fwidth - 3),
+ "Encoded Size:",
+ (unsigned long)(mesg->shared->dt_size));
+ if((H5O_MSG_DTYPE->debug)(f, dxpl_id, mesg->shared->dt, stream, indent + 3, MAX(0, fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display datatype message info")
+
+ HDfprintf(stream, "%*sDataspace...\n", indent, "");
+ HDfprintf(stream, "%*s%-*s %lu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Encoded Size:",
+ (unsigned long)(mesg->shared->ds_size));
+ if(H5S_debug(f, dxpl_id, mesg->shared->ds, stream, indent + 3, MAX(0, fwidth - 3)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display dataspace message info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_debug() */
+
diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c
new file mode 100644
index 0000000..2223564
--- /dev/null
+++ b/src/H5Oattribute.c
@@ -0,0 +1,2019 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oattribute.c
+ * Dec 11 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object header attribute routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5A_FRIEND /*suppress error about including H5Apkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Fprivate.h" /* File */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for iteration when converting attributes to dense storage */
+typedef struct {
+ H5F_t *f; /* Pointer to file for insertion */
+ hid_t dxpl_id; /* DXPL during iteration */
+ H5O_ainfo_t *ainfo; /* Attribute info struct */
+} H5O_iter_cvt_t;
+
+/* User data for iteration when opening an attribute */
+typedef struct {
+ /* down */
+ const char *name; /* Name of attribute to open */
+
+ /* up */
+ H5A_t *attr; /* Attribute data to update object header with */
+} H5O_iter_opn_t;
+
+/* User data for iteration when updating an attribute */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5A_t *attr; /* Attribute data to update object header with */
+
+ /* up */
+ hbool_t found; /* Whether the attribute was found */
+} H5O_iter_wrt_t;
+
+/* User data for iteration when renaming an attribute */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const char *old_name; /* Old name of attribute */
+ const char *new_name; /* New name of attribute */
+
+ /* up */
+ hbool_t found; /* Whether the attribute was found */
+} H5O_iter_ren_t;
+
+/* User data for iteration when iterating over attributes */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ hid_t loc_id; /* ID of object being iterated over */
+ unsigned skip; /* # of attributes to skip over */
+ H5A_operator_t op; /* Callback routine for each attribute */
+ void *op_data; /* User data for callback */
+
+ /* up */
+ unsigned count; /* Count of attributes examined */
+} H5O_iter_itr_t;
+
+/* User data for iteration when removing an attribute */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const char *name; /* Name of attribute to open */
+
+ /* up */
+ hbool_t found; /* Found attribute to delete */
+} H5O_iter_rm_t;
+
+/* User data for iteration when checking if an attribute exists */
+typedef struct {
+ /* down */
+ const char *name; /* Name of attribute to open */
+
+ /* up */
+ hbool_t found; /* Found attribute */
+} H5O_iter_xst_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static htri_t H5O_attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr,
+ const char* name_to_open);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_to_dense_cb
+ *
+ * Purpose: Object header iterator callback routine to convert compact
+ * attributes to dense attributes
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_cvt_t *udata = (H5O_iter_cvt_t *)_udata; /* Operator user data */
+ H5A_t *attr = (H5A_t *)mesg->native; /* Pointer to attribute to insert */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(udata->ainfo);
+ HDassert(attr);
+
+ /* Insert attribute into dense storage */
+ if(H5A_dense_insert(udata->f, udata->dxpl_id, udata->ainfo, attr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage")
+
+ /* Convert message into a null message in the header */
+ /* (don't delete attribute's space in the file though) */
+ if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message")
+
+ /* Indicate that the object header was modified */
+ *oh_modified = H5O_MODIFY_CONDENSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_to_dense_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_create
+ *
+ * Purpose: Create a new attribute in the object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 8, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(attr);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Check if this object already has attribute information */
+ if(oh->version > H5O_VERSION_1) {
+ hbool_t new_ainfo = FALSE; /* Flag to indicate that the attribute information is new */
+ htri_t ainfo_exists; /* Whether the attribute info was retrieved */
+
+ /* Check for (& retrieve if available) attribute info */
+ if((ainfo_exists = H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ if(!ainfo_exists) {
+ /* Initialize attribute information */
+ ainfo.track_corder = (hbool_t)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? TRUE : FALSE);
+ ainfo.index_corder = (hbool_t)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? TRUE : FALSE);
+ ainfo.max_crt_idx = 0;
+ ainfo.corder_bt2_addr = HADDR_UNDEF;
+ ainfo.nattrs = 0;
+ ainfo.fheap_addr = HADDR_UNDEF;
+ ainfo.name_bt2_addr = HADDR_UNDEF;
+
+ /* Set flag to add attribute information to object header */
+ new_ainfo = TRUE;
+ } /* end if */
+ else {
+ /* Sanity check attribute info read in */
+ HDassert(ainfo.nattrs > 0);
+ HDassert(ainfo.track_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) > 0));
+ HDassert(ainfo.index_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) > 0));
+ } /* end else */
+
+ /* Check if switching to "dense" attribute storage is possible */
+ if(!H5F_addr_defined(ainfo.fheap_addr)) {
+ htri_t sharable; /* Whether the attribute will be shared */
+ size_t raw_size = 0; /* Raw size of message */
+
+ /* Check for attribute being sharable */
+ if((sharable = H5SM_can_share(loc->file, dxpl_id, NULL, NULL, H5O_ATTR_ID, attr)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't determine attribute sharing status")
+ else if(sharable == FALSE) {
+ /* Compute the size needed to encode the attribute */
+ raw_size = (H5O_MSG_ATTR->raw_size)(loc->file, FALSE, attr);
+ } /* end if */
+
+ /* Check for condititions for switching to "dense" attribute storage are met */
+ if(ainfo.nattrs == oh->max_compact || (!sharable && raw_size >= H5O_MESG_MAX_SIZE)) {
+ H5O_iter_cvt_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Create dense storage for attributes */
+ if(H5A_dense_create(loc->file, dxpl_id, &ainfo) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create dense storage for attributes")
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.ainfo = &ainfo;
+
+ /* Iterate over existing attributes, moving them to dense storage */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_to_dense_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCONVERT, FAIL, "error converting attributes to dense storage")
+ } /* end if */
+ } /* end if */
+
+ /* Increment attribute count on object */
+ ainfo.nattrs++;
+
+ /* Check whether we're tracking the creation index on attributes */
+ if(ainfo.track_corder) {
+ /* Check for attribute creation order index on the object wrapping around */
+ if(ainfo.max_crt_idx == H5O_MAX_CRT_ORDER_IDX)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINC, FAIL, "attribute creation index can't be incremented")
+
+ /* Set the creation order index on the attribute & incr. creation order index */
+ attr->shared->crt_idx = ainfo.max_crt_idx++;
+ } /* end if */
+ else
+ /* Set "bogus" creation index for attribute */
+ attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
+
+ /* Add the attribute information message, if one is needed */
+ if(new_ainfo) {
+ if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute info message")
+ } /* end if */
+ /* Otherwise, update existing message */
+ else {
+ if(H5O_msg_write_real(loc->file, dxpl_id, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Set "bogus" creation index for attribute */
+ attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
+
+ /* Set attribute info value to get attribute into object header */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Check for storing attribute with dense storage */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Insert attribute into dense storage */
+ if(H5A_dense_insert(loc->file, dxpl_id, &ainfo, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to add to dense storage")
+ } /* end if */
+ else {
+ /* Append new message to object header */
+ if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_ATTR, 0, 0, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute in header")
+ } /* end else */
+
+ /* Increment reference count for shared attribute object for the
+ * object handle created by the caller function H5A_create. The count
+ * for the cached object header has been incremented in the step above
+ * (in H5O_msg_append_real). The dense storage doesn't need a count. */
+ attr->shared->nrefs += 1;
+
+ /* Was new attribute shared? */
+ if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr)) > 0) {
+ hsize_t attr_rc; /* Attribute's ref count in shared message storage */
+
+ /* Retrieve ref count for shared attribute */
+ if(H5SM_get_refcount(loc->file, dxpl_id, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count")
+
+ /* If this is not the first copy of the attribute in the shared message
+ * storage, decrement the reference count on any shared components
+ * of the attribute. This is done because the shared message
+ * storage's "try delete" call doesn't call the message class's
+ * "delete" callback until the reference count drops to zero.
+ * However, attributes have already increased the reference
+ * count on shared components before passing the attribute
+ * to the shared message code to manage, causing an asymmetry
+ * in the reference counting for any shared components.
+ *
+ * The alternate solution is to have the shared message's "try
+ * delete" code always call the message class's "delete" callback,
+ * even when the reference count is positive. This can be done
+ * without an appreciable performance hit (by using H5HF_op() in
+ * the shared message comparison v2 B-tree callback), but it has
+ * the undesirable side-effect of leaving the reference count on
+ * the attribute's shared components artificially (and possibly
+ * misleadingly) high, because there's only one shared attribute
+ * referencing the shared components, not <refcount for the
+ * shared attribute> objects referencing the shared components.
+ *
+ * *ick* -QAK, 2007/01/08
+ */
+ if(attr_rc > 1) {
+ if(H5O_attr_delete(loc->file, dxpl_id, oh, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute")
+ } /* end if */
+ } /* end if */
+ else if(shared_mesg < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared")
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_open_cb
+ *
+ * Purpose: Object header iterator callback routine to open an
+ * attribute stored compactly.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence,
+ unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_opn_t *udata = (H5O_iter_opn_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->attr);
+
+ /* Check for correct attribute message to modify */
+ if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
+ /* Make a copy of the attribute to return */
+ if(NULL == (udata->attr = H5A_copy(NULL, (H5A_t *)mesg->native)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy attribute")
+
+ /* Assign [somewhat arbitrary] creation order value, for older versions
+ * of the format or if creation order is not tracked */
+ if(oh->version == H5O_VERSION_1
+ || !(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED))
+ udata->attr->shared->crt_idx = sequence;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_open_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_open_by_name
+ *
+ * Purpose: Open an existing attribute in an object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 11, 2006
+ *
+ * Modification:Raymond Lu
+ * 23 June 2008
+ * If the attribute is in dense storage and has already been
+ * opened, make a copy of already opened object to share some
+ * object information.
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ H5A_t *exist_attr = NULL; /* Existing opened attribute object */
+ H5A_t *opened_attr = NULL; /* Newly opened attribute object */
+ htri_t found_open_attr = FALSE; /* Whether opened object is found */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, NULL)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't check for attribute info message")
+ } /* end if */
+
+ /* If found the attribute is already opened, make a copy of it to share the
+ * object information. If not, open attribute as a new object
+ */
+ if((found_open_attr = H5O_attr_find_opened_attr(loc, &exist_attr, name)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute")
+ else if(found_open_attr == TRUE) {
+ if(NULL == (opened_attr = H5A_copy(NULL, exist_attr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute")
+ } /* end else if */
+ else {
+ /* Check for attributes in dense storage */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Open attribute with dense storage */
+ if(NULL == (opened_attr = H5A_dense_open(loc->file, dxpl_id, &ainfo, name)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "can't open attribute")
+ } /* end if */
+ else {
+ H5O_iter_opn_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.name = name;
+ udata.attr = NULL;
+
+ /* Iterate over attributes, to locate correct one to open */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_open_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "error updating attribute")
+
+ /* Check that we found the attribute */
+ if(!udata.attr)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute: '%s'", name)
+
+ /* Get attribute opened from object header */
+ HDassert(udata.attr);
+ opened_attr = udata.attr;
+ } /* end else */
+
+ /* Mark datatype as being on disk now */
+ if(H5T_set_loc(opened_attr->shared->dt, loc->file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location")
+ } /* end else */
+
+ /* Set return value */
+ ret_value = opened_attr;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ /* Release any resources, on error */
+ if(NULL == ret_value && opened_attr)
+ if(H5A_close(opened_attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_attr_open_by_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_open_by_idx_cb
+ *
+ * Purpose: Callback routine opening an attribute by index
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 18 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_open_by_idx_cb(const H5A_t *attr, void *_ret_attr)
+{
+ H5A_t **ret_attr = (H5A_t **)_ret_attr; /* 'User data' passed in */
+ herr_t ret_value = H5_ITER_STOP; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ HDassert(attr);
+ HDassert(ret_attr);
+
+ /* Copy attribute information. Shared some attribute information. */
+ if(NULL == (*ret_attr = H5A_copy(NULL, attr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_open_by_idx_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_open_by_idx
+ *
+ * Purpose: Open an existing attribute in an object header according to
+ * an index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 18, 2006
+ *
+ * Modification:Raymond Lu
+ * 23 June 2008
+ * After opening the attribute, check whether it's in dense
+ * storage and has already been opened. If it has, close the
+ * opened object and make a copy of already opened object.
+ *-------------------------------------------------------------------------
+ */
+H5A_t *
+H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5A_attr_iter_op_t attr_op; /* Attribute operator */
+ H5A_t *exist_attr = NULL; /* Existing opened attribute object */
+ H5A_t *opened_attr = NULL; /* Newly opened attribute object */
+ htri_t found_open_attr = FALSE; /* Whether opened object is found */
+ H5A_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+
+ /* Build attribute operator info */
+ attr_op.op_type = H5A_ATTR_OP_LIB;
+ attr_op.u.lib_op = H5O_attr_open_by_idx_cb;
+
+ /* Iterate over attributes to locate correct one */
+ if(H5O_attr_iterate_real((hid_t)-1, loc, dxpl_id, idx_type, order, n, NULL, &attr_op, &opened_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADITER, NULL, "can't locate attribute")
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header")
+
+ /* Find out whether it has already been opened. If it has, close the object
+ * and make a copy of the already opened object to share the object info.
+ */
+ if(opened_attr) {
+ if((found_open_attr = H5O_attr_find_opened_attr(loc, &exist_attr, opened_attr->shared->name)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute")
+
+ /* If found that the attribute is already opened, make a copy of it
+ * and close the object just opened.
+ */
+ if(found_open_attr && exist_attr) {
+ if(H5A_close(opened_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute")
+ if(NULL == (opened_attr = H5A_copy(NULL, exist_attr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute")
+ } else {
+ /* Mark datatype as being on disk now */
+ if(H5T_set_loc(opened_attr->shared->dt, loc->file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location")
+ } /* end if */
+ } /* end if */
+
+ /* Set return value */
+ ret_value = opened_attr;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ /* Release any resources, on error */
+ if(NULL == ret_value && opened_attr)
+ if(H5A_close(opened_attr) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_open_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_find_opened_attr
+ *
+ * Purpose: Find out whether an attribute has been opened by giving
+ * the name. Return the pointer to the object if found.
+ *
+ * Return: TRUE: found the already opened object
+ * FALSE: didn't find the opened object
+ * FAIL: function failed.
+ *
+ * Programmer: Raymond Lu
+ * 23 June 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char* name_to_open)
+{
+ hid_t *attr_id_list = NULL; /* List of IDs for opened attributes */
+ unsigned long loc_fnum; /* File serial # for object */
+ size_t num_open_attr; /* Number of opened attributes */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get file serial number for the location of attribute */
+ if(H5F_get_fileno(loc->file, &loc_fnum) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number")
+
+ /* Count all opened attributes */
+ if(H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, FALSE, &num_open_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't count opened attributes")
+
+ /* Find out whether the attribute has been opened */
+ if(num_open_attr) {
+ size_t check_num_attr; /* Number of open attribute IDs */
+ size_t u; /* Local index variable */
+
+ /* Allocate space for the attribute ID list */
+ if(NULL == (attr_id_list = (hid_t *)H5MM_malloc(num_open_attr * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "unable to allocate memory for attribute ID list")
+
+ /* Retrieve the IDs of all opened attributes */
+ if(H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, FALSE, &check_num_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get IDs of opened attributes")
+ if(check_num_attr != num_open_attr)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "open attribute count mismatch")
+
+ /* Iterate over the attributes */
+ for(u = 0; u < num_open_attr; u++) {
+ unsigned long attr_fnum; /* Attributes file serial number */
+
+ /* Get pointer to attribute */
+ if(NULL == (*attr = (H5A_t *)H5I_object_verify(attr_id_list[u], H5I_ATTR)))
+ HGOTO_ERROR(H5E_ATTR, H5E_BADTYPE, FAIL, "not an attribute")
+
+ /* Get file serial number for attribute */
+ if(H5F_get_fileno((*attr)->oloc.file, &attr_fnum) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number")
+
+ /* Verify whether it's the right object. The attribute name, object
+ * address to which the attribute is attached, and file serial
+ * number should all match.
+ */
+ if(!HDstrcmp(name_to_open, (*attr)->shared->name) &&
+ loc->addr == (*attr)->oloc.addr &&
+ loc_fnum == attr_fnum) {
+ ret_value = TRUE;
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+done:
+ if(attr_id_list)
+ H5MM_free(attr_id_list);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_find_opened_attr */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_update_shared
+ *
+ * Purpose: Update a shared attribute.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jan 2 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_update_shared(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5A_t *attr,
+ H5O_shared_t *update_sh_mesg)
+{
+ H5O_shared_t sh_mesg; /* Shared object header message */
+ hsize_t attr_rc; /* Attribute's ref count in shared message storage */
+ htri_t shared_mesg; /* Whether the message should be shared */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(attr);
+
+ /* Extract shared message info from current attribute (for later use) */
+ if(H5O_set_shared(&sh_mesg, &(attr->sh_loc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message")
+
+ /* Reset existing sharing information */
+ if(H5O_msg_reset_share(H5O_ATTR_ID, attr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to reset attribute sharing")
+
+ /* Store new version of message as a SOHM */
+ /* (should always work, since we're not changing the size of the attribute) */
+ if((shared_mesg = H5SM_try_share(f, dxpl_id, oh, 0, H5O_ATTR_ID, attr, NULL)) == 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "attribute changed sharing status")
+ else if(shared_mesg < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't share attribute")
+
+ /* Retrieve shared message storage ref count for new shared attribute */
+ if(H5SM_get_refcount(f, dxpl_id, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count")
+
+ /* If the newly shared attribute needs to share "ownership" of the shared
+ * components (ie. its reference count is 1), increment the reference
+ * count on any shared components of the attribute, so that they won't
+ * be removed from the file by the following "delete" operation on the
+ * original attribute shared message info. (Essentially a "copy on
+ * write" operation).
+ *
+ * *ick* -QAK, 2007/01/08
+ */
+ if(attr_rc == 1) {
+ /* Increment reference count on attribute components */
+ if(H5O_attr_link(f, dxpl_id, oh, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count")
+ } /* end if */
+
+ /* Remove the old attribute from the SOHM storage */
+ if(H5SM_delete(f, dxpl_id, oh, &sh_mesg) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute in shared storage")
+
+ /* Extract updated shared message info from modified attribute, if requested */
+ if(update_sh_mesg)
+ if(H5O_set_shared(update_sh_mesg, &(attr->sh_loc)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_update_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_write_cb
+ *
+ * Purpose: Object header iterator callback routine to update an
+ * attribute stored compactly.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ * Modification:Raymond Lu
+ * 4 June 2008
+ * Took out the data copying part because the attribute data
+ * is shared between attribute handle and object header.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_wrt_t *udata = (H5O_iter_wrt_t *)_udata; /* Operator user data */
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for correct attribute message to modify */
+ if(0 == HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->attr->shared->name)) {
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(udata->f, udata->dxpl_id, oh, mesg->chunkno)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk")
+
+ /* Because the attribute structure is shared now. The only situation that requires
+ * copying the data is when the metadata cache evicts and reloads this attribute.
+ * The shared attribute structure will be different in that situation. SLU-2010/7/29 */
+ if(((H5A_t *)mesg->native)->shared != udata->attr->shared) {
+ /* Sanity check */
+ HDassert(((H5A_t *)mesg->native)->shared->data);
+ HDassert(udata->attr->shared->data);
+ HDassert(((H5A_t *)mesg->native)->shared->data != udata->attr->shared->data);
+
+ /* (Needs to occur before updating the shared message, or the hash
+ * value on the old & new messages will be the same) */
+ HDmemcpy(((H5A_t *)mesg->native)->shared->data, udata->attr->shared->data, udata->attr->shared->data_size);
+ } /* end if */
+
+ /* Mark the message as modified */
+ mesg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Release chunk */
+ if(H5O_chunk_unprotect(udata->f, udata->dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk")
+ chk_proxy = NULL;
+
+ /* Update the shared attribute in the SOHM storage */
+ if(mesg->flags & H5O_MSG_FLAG_SHARED)
+ if(H5O_attr_update_shared(udata->f, udata->dxpl_id, oh, udata->attr, (H5O_shared_t *)mesg->native) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR, "unable to update attribute in shared storage")
+
+ /* Indicate that the object header was modified */
+ *oh_modified = H5O_MODIFY;
+
+ /* Indicate that the attribute was found */
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ /* Release chunk, if not already done */
+ if(chk_proxy && H5O_chunk_unprotect(udata->f, udata->dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_write_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_write
+ *
+ * Purpose: Write a new value to an attribute.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(attr);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Modify the attribute data in dense storage */
+ if(H5A_dense_write(loc->file, dxpl_id, &ainfo, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+ } /* end if */
+ else {
+ H5O_iter_wrt_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.attr = attr;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to locate correct one to update */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_write_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+
+ /* Check that we found the attribute */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate open attribute?")
+ } /* end else */
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_write */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename_chk_cb
+ *
+ * Purpose: Object header iterator callback routine to check for
+ * duplicate name during rename
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_rename_chk_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for existing attribute with new name */
+ if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->new_name) == 0) {
+ /* Indicate that we found an existing attribute with the new name*/
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_rename_chk_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename_mod_cb
+ *
+ * Purpose: Object header iterator callback routine to change name of
+ * attribute during rename
+ *
+ * Note: This routine doesn't currently allow an attribute to change
+ * its "shared" status, if the name change would cause a size
+ * difference that would put it into a different category.
+ * Something for later...
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Find correct attribute message to rename */
+ if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->old_name) == 0) {
+ unsigned old_version = ((H5A_t *)mesg->native)->shared->version; /* Old version of the attribute */
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(udata->f, udata->dxpl_id, oh, mesg->chunkno)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk")
+
+ /* Change the name for the attribute */
+ H5MM_xfree(((H5A_t *)mesg->native)->shared->name);
+ ((H5A_t *)mesg->native)->shared->name = H5MM_xstrdup(udata->new_name);
+
+ /* Recompute the version to encode the attribute with */
+ if(H5A_set_version(udata->f, ((H5A_t *)mesg->native)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, H5_ITER_ERROR, "unable to update attribute version")
+
+ /* Mark the message as modified */
+ mesg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Release chunk */
+ if(H5O_chunk_unprotect(udata->f, udata->dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk")
+ chk_proxy = NULL;
+
+ /* Check for shared message */
+ if(mesg->flags & H5O_MSG_FLAG_SHARED) {
+ /* Update the shared attribute in the SOHM storage */
+ if(H5O_attr_update_shared(udata->f, udata->dxpl_id, oh, (H5A_t *)mesg->native, NULL) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR, "unable to update attribute in shared storage")
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(H5O_msg_is_shared(H5O_ATTR_ID, (H5A_t *)mesg->native) == FALSE);
+
+ /* Check for attribute message changing size */
+ if(HDstrlen(udata->new_name) != HDstrlen(udata->old_name) ||
+ old_version != ((H5A_t *)mesg->native)->shared->version) {
+ H5A_t *attr; /* Attribute to re-add */
+
+ /* Take ownership of the message's native info (the attribute)
+ * so any shared objects in the file aren't adjusted (and
+ * possibly deleted) when the message is released.
+ */
+ /* (We do this more complicated sequence of actions because the
+ * simpler solution of adding the modified attribute first
+ * and then deleting the old message can re-allocate the
+ * list of messages during the "add the modified attribute"
+ * step, invalidating the message pointer we have here - QAK)
+ */
+ attr = (H5A_t *)mesg->native;
+ mesg->native = NULL;
+
+ /* Delete old attribute */
+ /* (doesn't decrement the link count on shared components becuase
+ * the "native" pointer has been reset)
+ */
+ if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to release previous attribute")
+
+ *oh_modified = H5O_MODIFY_CONDENSE;
+
+ /* Append renamed attribute to object header */
+ /* (Don't let it become shared) */
+ if(H5O_msg_append_real(udata->f, udata->dxpl_id, oh, H5O_MSG_ATTR, (mesg->flags | H5O_MSG_FLAG_DONTSHARE), 0, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to relocate renamed attribute in header")
+
+ /* Sanity check */
+ HDassert(H5O_msg_is_shared(H5O_ATTR_ID, attr) == FALSE);
+
+ /* Close the local copy of the attribute */
+ H5A_close(attr);
+ } /* end if */
+ } /* end else */
+
+ /* Indicate that the object header was modified */
+ *oh_modified |= H5O_MODIFY;
+
+ /* Indicate that we found an existing attribute with the old name */
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ /* Release chunk, if not already done */
+ if(chk_proxy && H5O_chunk_unprotect(udata->f, udata->dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_rename_mod_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename
+ *
+ * Purpose: Rename an attribute.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name,
+ const char *new_name)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(old_name);
+ HDassert(new_name);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Rename the attribute data in dense storage */
+ if(H5A_dense_rename(loc->file, dxpl_id, &ainfo, old_name, new_name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+ } /* end if */
+ else {
+ H5O_iter_ren_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.old_name = old_name;
+ udata.new_name = new_name;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to check if "new name" exists already */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_rename_chk_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+
+ /* If the new name was found, indicate an error */
+ if(udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_EXISTS, FAIL, "attribute with new name already exists")
+
+ /* Iterate over attributes again, to actually rename attribute with old name */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_rename_mod_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+
+ /* Check that we found the attribute to rename */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute with old name")
+ } /* end else */
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_rename */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_iterate_real
+ *
+ * Purpose: Internal routine to iterate over attributes for an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip,
+ hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(attr_op);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Check for skipping too many attributes */
+ if(skip > 0 && skip >= ainfo.nattrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+
+ /* Release the object header */
+ if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+ oh = NULL;
+
+ /* Iterate over attributes in dense storage */
+ if((ret_value = H5A_dense_iterate(loc->file, dxpl_id, loc_id, &ainfo, idx_type, order, skip, last_attr, attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+ } /* end if */
+ else {
+ /* Build table of attributes for compact storage */
+ if(H5A_compact_build_table(loc->file, dxpl_id, oh, idx_type, order, &atable) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table")
+
+ /* Release the object header */
+ if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+ oh = NULL;
+
+ /* Check for skipping too many attributes */
+ if(skip > 0 && skip >= atable.nattrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+
+ /* Iterate over attributes in table */
+ if((ret_value = H5A_attr_iterate_table(&atable, skip, last_attr, loc_id, attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed");
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+ if(atable.attrs && H5A_attr_release_table(&atable) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_iterate_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_iterate
+ *
+ * Purpose: Iterate over attributes for an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_iterate(hid_t loc_id, hid_t dxpl_id,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t skip,
+ hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data)
+{
+ H5G_loc_t loc; /* Object location */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(attr_op);
+
+ /* Look up location for location ID */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+ /* Iterate over attributes to locate correct one */
+ if((ret_value = H5O_attr_iterate_real(loc_id, loc.oloc, dxpl_id, idx_type, order, skip, last_attr, attr_op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_remove_update
+ *
+ * Purpose: Check for reverting from dense to compact attribute storage
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 14, 2007
+ *
+ * Modification:Raymond Lu
+ * 24 June 2008
+ * When converting storage from dense to compact, if found
+ * the attribute is already opened, use the opened message
+ * to insert. If not, still use the message in the attribute
+ * table. This will guarantee that the attribute message is
+ * shared between the object in metadata cache and the opened
+ * object.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, H5O_ainfo_t *ainfo,
+ hid_t dxpl_id)
+{
+ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(oh);
+ HDassert(ainfo);
+
+ /* Decrement the number of attributes on the object */
+ ainfo->nattrs--;
+
+ /* Check for shifting from dense storage back to compact storage */
+ if(H5F_addr_defined(ainfo->fheap_addr) && ainfo->nattrs < oh->min_dense) {
+ hbool_t can_convert = TRUE; /* Whether converting to attribute messages is possible */
+ size_t u; /* Local index */
+
+ /* Build the table of attributes for this object */
+ if(H5A_dense_build_table(loc->file, dxpl_id, ainfo, H5_INDEX_NAME, H5_ITER_NATIVE, &atable) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table")
+
+ /* Inspect attributes in table for ones that can't be converted back
+ * into attribute message form (currently only attributes which
+ * can't fit into an object header message)
+ */
+ for(u = 0; u < ainfo->nattrs; u++)
+ if(H5O_msg_size_oh(loc->file, oh, H5O_ATTR_ID, (atable.attrs[u]), (size_t)0) >= H5O_MESG_MAX_SIZE) {
+ can_convert = FALSE;
+ break;
+ } /* end if */
+
+ /* If ok, insert attributes as object header messages */
+ if(can_convert) {
+ H5A_t *exist_attr = NULL;
+ htri_t found_open_attr = FALSE;
+
+ /* Iterate over attributes, to put them into header */
+ for(u = 0; u < ainfo->nattrs; u++) {
+ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
+
+ /* Check if attribute is shared */
+ if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, (atable.attrs[u]))) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared")
+ else if(shared_mesg == 0) {
+ /* Increment reference count on attribute components */
+ /* (so that they aren't deleted when the dense attribute storage is deleted) */
+ if(H5O_attr_link(loc->file, dxpl_id, oh, (atable.attrs[u])) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count")
+ } /* end if */
+ else {
+ /* Reset 'shared' status, so attribute will be shared again */
+ (atable.attrs[u])->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
+ } /* end else */
+
+ /* Insert attribute message into object header (Will increment
+ reference count on shared attributes) */
+ /* Find out whether the attribute has been opened */
+ if((found_open_attr = H5O_attr_find_opened_attr(loc, &exist_attr, (atable.attrs[u])->shared->name)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "failed in finding opened attribute")
+
+ /* If found the attribute is already opened, use the opened message to insert.
+ If not, still use the message in the attribute table. */
+ if(found_open_attr && exist_attr) {
+ if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_ATTR, 0, 0, exist_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message")
+
+ } else {
+ if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_ATTR, 0, 0, (atable.attrs[u])) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message")
+ }
+ } /* end for */
+
+ /* Remove the dense storage */
+ if(H5A_dense_delete(loc->file, dxpl_id, ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete dense attribute storage")
+ } /* end if */
+ } /* end if */
+
+ /* Check if we have deleted all the attributes and the attribute info
+ * message should be deleted itself.
+ */
+ if(ainfo->nattrs == 0) {
+ if(H5O_msg_remove_real(loc->file, oh, H5O_MSG_AINFO, H5O_ALL, NULL, NULL, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute info")
+ } /* end if */
+ else {
+ if(H5O_msg_write_real(loc->file, dxpl_id, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message")
+ } /* end else */
+
+done:
+ /* Release resources */
+ if(atable.attrs && H5A_attr_release_table(&atable) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_remove_update() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_remove_cb
+ *
+ * Purpose: Object header iterator callback routine to remove an
+ * attribute stored compactly.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_remove_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_rm_t *udata = (H5O_iter_rm_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for correct attribute message to modify */
+ if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
+ /* Convert message into a null message (i.e. delete it) */
+ if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message")
+
+ /* Indicate that the object header was modified */
+ *oh_modified = H5O_MODIFY_CONDENSE;
+
+ /* Indicate that this message is the attribute to be deleted */
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_remove_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_remove
+ *
+ * Purpose: Delete an attribute on an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if((ainfo_exists = H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Delete attribute from dense storage */
+ if(H5A_dense_remove(loc->file, dxpl_id, &ainfo, name) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage")
+ } /* end if */
+ else {
+ H5O_iter_rm_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.name = name;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to locate correct one to delete */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_remove_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute")
+
+ /* Check that we found the attribute */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute")
+ } /* end else */
+
+ /* Update the attribute information after removing an attribute */
+ if(ainfo_exists)
+ if(H5O_attr_remove_update(loc, oh, &ainfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info")
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_remove_by_idx
+ *
+ * Purpose: Delete an attribute on an object, according to an order within
+ * an index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 14, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type,
+ H5_iter_order_t order, hsize_t n, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */
+ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check arguments */
+ HDassert(loc);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if((ainfo_exists = H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Delete attribute from dense storage */
+ if(H5A_dense_remove_by_idx(loc->file, dxpl_id, &ainfo, idx_type, order, n) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage")
+ } /* end if */
+ else {
+ H5O_iter_rm_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Build table of attributes for compact storage */
+ if(H5A_compact_build_table(loc->file, dxpl_id, oh, idx_type, order, &atable) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table")
+
+ /* Check for skipping too many attributes */
+ if(n >= atable.nattrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+
+ /* Set up user data for callback, to remove the attribute by name */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.name = ((atable.attrs[n])->shared)->name;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to locate correct one to delete */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_remove_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute")
+
+ /* Check that we found the attribute */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute")
+ } /* end else */
+
+ /* Update the attribute information after removing an attribute */
+ if(ainfo_exists)
+ if(H5O_attr_remove_update(loc, oh, &ainfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info")
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+ if(atable.attrs && H5A_attr_release_table(&atable) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_remove_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_count_real
+ *
+ * Purpose: Determine the # of attributes on an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 9, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_count_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hsize_t *nattrs)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(nattrs);
+
+ /* Check for attributes stored densely */
+ if(oh->version > H5O_VERSION_1) {
+ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+
+ /* Attempt to get the attribute information from the object header */
+ if((ainfo_exists = H5A_get_ainfo(f, dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ else if(ainfo_exists > 0)
+ *nattrs = ainfo.nattrs;
+ else
+ *nattrs = 0;
+ } /* end if */
+ else {
+ hsize_t attr_count; /* Number of attributes found */
+ unsigned u; /* Local index variable */
+
+ /* Loop over all messages, counting the attributes */
+ attr_count = 0;
+ for(u = 0; u < oh->nmesgs; u++)
+ if(oh->mesg[u].type == H5O_MSG_ATTR)
+ attr_count++;
+ *nattrs = attr_count;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_count_real */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_exists_cb
+ *
+ * Purpose: Object header iterator callback routine to check for an
+ * attribute stored compactly, by name.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 11 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_exists_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_rm_t *udata = (H5O_iter_rm_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for correct attribute message */
+ if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
+ /* Indicate that this message is the attribute sought */
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_exists_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_exists
+ *
+ * Purpose: Determine if an attribute with a particular name exists on an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, FAIL)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(name);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Check if attribute exists in dense storage */
+ if((ret_value = H5A_dense_exists(loc->file, dxpl_id, &ainfo, name)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute")
+ } /* end if */
+ else {
+ H5O_iter_rm_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.name = name;
+ udata.found = FALSE;
+
+ /* Iterate over existing attributes, checking for attribute with same name */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O_attr_exists_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute")
+
+ /* Check that we found the attribute */
+ ret_value = (htri_t)udata.found;
+ } /* end else */
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_attr_exists */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_bh_info
+ *
+ * Purpose: For 1.8 attribute, returns storage amount for btree and fractal heap
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * June 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_bh_info(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(oh);
+ HDassert(bh_info);
+
+ /* Attributes are only stored in fractal heap & indexed w/v2 B-tree in later versions */
+ if(oh->version > H5O_VERSION_1) {
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */
+
+ /* Check for (& retrieve if available) attribute info */
+ if((ainfo_exists = H5A_get_ainfo(f, dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ else if(ainfo_exists > 0) {
+ /* Check if name index available */
+ if(H5F_addr_defined(ainfo.name_bt2_addr)) {
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(f, dxpl_id, ainfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Get name index B-tree size */
+ if(H5B2_size(bt2_name, dxpl_id, &(bh_info->index_size)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
+ } /* end if */
+
+ /* Check if creation order index available */
+ if(H5F_addr_defined(ainfo.corder_bt2_addr)) {
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(f, dxpl_id, ainfo.corder_bt2_addr, NULL)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Get creation order index B-tree size */
+ if(H5B2_size(bt2_corder, dxpl_id, &(bh_info->index_size)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
+ } /* end if */
+
+ /* Get storage size of fractal heap, if it's used */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Open the fractal heap for attributes */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, ainfo.fheap_addr)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Get heap storage size */
+ if(H5HF_size(fheap, dxpl_id, &(bh_info->heap_size)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2_name && H5B2_close(bt2_name, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, dxpl_id) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_attr_bh_info() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_count
+ *
+ * Purpose: Determine the # of attributes on an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ hsize_t nattrs; /* Number of attributes */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(loc);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Retrieve # of attributes on object */
+ if(H5O_attr_count_real(loc->file, dxpl_id, oh, &nattrs) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve attribute count")
+
+ /* Set return value */
+ ret_value = (int)nattrs;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_count */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Obogus.c b/src/H5Obogus.c
new file mode 100644
index 0000000..a3531ed
--- /dev/null
+++ b/src/H5Obogus.c
@@ -0,0 +1,240 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Obogus.c
+ * Jan 21 2003
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: "bogus" message. This message is guaranteed to never
+ * be found in a valid HDF5 file and is only used to
+ * generate a test file which verifies the library's
+ * correct operation when parsing unknown object header
+ * messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+
+#ifdef H5O_ENABLE_BOGUS
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_bogus_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_bogus_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static size_t H5O_bogus_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_bogus_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_BOGUS_VALID[1] = {{
+ H5O_BOGUS_VALID_ID, /*message id number */
+ "bogus valid", /*message name for debugging */
+ 0, /*native message size */
+ 0, /* messages are sharable? */
+ H5O_bogus_decode, /*decode message */
+ H5O_bogus_encode, /*encode message */
+ NULL, /*copy the native value */
+ H5O_bogus_size, /*raw message size */
+ NULL, /*free internal memory */
+ NULL, /*free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_bogus_debug /*debug the message */
+}};
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_BOGUS_INVALID[1] = {{
+ H5O_BOGUS_INVALID_ID, /*message id number */
+ "bogus invalid", /*message name for debugging */
+ 0, /*native message size */
+ 0, /* messages are sharable? */
+ H5O_bogus_decode, /*decode message */
+ H5O_bogus_encode, /*encode message */
+ NULL, /*copy the native value */
+ H5O_bogus_size, /*raw message size */
+ NULL, /*free internal memory */
+ NULL, /*free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_bogus_debug /*debug the message */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_bogus_decode
+ *
+ * Purpose: Decode a "bogus" message and return a pointer to a new
+ * native message struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 21 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_bogus_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_bogus_t *mesg = NULL;
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Allocate the bogus message */
+ if(NULL == (mesg = (H5O_bogus_t *)H5MM_calloc(sizeof(H5O_bogus_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* decode */
+ UINT32DECODE(p, mesg->u);
+
+ /* Validate the bogus info */
+ if(mesg->u != H5O_BOGUS_VALUE)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "invalid bogus value :-)")
+
+ /* Set return value */
+ ret_value = mesg;
+
+done:
+ if(ret_value == NULL && mesg != NULL)
+ H5MM_xfree(mesg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_bogus_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_bogus_encode
+ *
+ * Purpose: Encodes a "bogus" message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 21 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_bogus_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void H5_ATTR_UNUSED *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* encode */
+ UINT32ENCODE(p, H5O_BOGUS_VALUE);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_bogus_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_bogus_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not
+ * counting the message typ or size fields, but only the data
+ * fields. This function doesn't take into account
+ * alignment.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 21 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_bogus_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(4)
+} /* end H5O_bogus_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_bogus_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 21 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_bogus_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_bogus_t *mesg = (const H5O_bogus_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s `%u'\n", indent, "", fwidth,
+ "Bogus Value:", mesg->u);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_bogus_debug() */
+#endif /* H5O_ENABLE_BOGUS */
+
diff --git a/src/H5Obtreek.c b/src/H5Obtreek.c
new file mode 100644
index 0000000..4fd0577
--- /dev/null
+++ b/src/H5Obtreek.c
@@ -0,0 +1,257 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, March 1, 2007
+ *
+ * Purpose: A message holding non-default v1 B-tree 'K' value
+ * information in the superblock extension.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object headers */
+#include "H5MMprivate.h" /* Memory management */
+
+static void *H5O_btreek_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_btreek_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_btreek_copy(const void *_mesg, void *_dest);
+static size_t H5O_btreek_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_btreek_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_BTREEK[1] = {{
+ H5O_BTREEK_ID, /*message id number */
+ "v1 B-tree 'K' values", /*message name for debugging */
+ sizeof(H5O_btreek_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_btreek_decode, /*decode message */
+ H5O_btreek_encode, /*encode message */
+ H5O_btreek_copy, /*copy the native value */
+ H5O_btreek_size, /*raw message size */
+ NULL, /*free internal memory */
+ NULL, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_btreek_debug /*debug the message */
+}};
+
+/* Current version of v1 B-tree 'K' value information */
+#define H5O_BTREEK_VERSION 0
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_btreek_decode
+ *
+ * Purpose: Decode a shared message table message and return a pointer
+ * to a newly allocated H5O_btreek_t struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_btreek_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_btreek_t *mesg; /* Native message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_BTREEK_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (mesg = (H5O_btreek_t *)H5MM_calloc(sizeof(H5O_btreek_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for v1 B-tree 'K' message")
+
+ /* Retrieve non-default B-tree 'K' values */
+ UINT16DECODE(p, mesg->btree_k[H5B_CHUNK_ID]);
+ UINT16DECODE(p, mesg->btree_k[H5B_SNODE_ID]);
+ UINT16DECODE(p, mesg->sym_leaf_k);
+
+ /* Set return value */
+ ret_value = (void *)mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_btreek_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_btreek_encode
+ *
+ * Purpose: Encode a v1 B-tree 'K' value message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_btreek_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_btreek_t *mesg = (const H5O_btreek_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* Store version and non-default v1 B-tree 'K' values */
+ *p++ = H5O_BTREEK_VERSION;
+ UINT16ENCODE(p, mesg->btree_k[H5B_CHUNK_ID]);
+ UINT16ENCODE(p, mesg->btree_k[H5B_SNODE_ID]);
+ UINT16ENCODE(p, mesg->sym_leaf_k);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_btreek_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_btreek_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_btreek_copy(const void *_mesg, void *_dest)
+{
+ const H5O_btreek_t *mesg = (const H5O_btreek_t *)_mesg;
+ H5O_btreek_t *dest = (H5O_btreek_t *)_dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(mesg);
+
+ if(!dest && NULL == (dest = (H5O_btreek_t *)H5MM_malloc(sizeof(H5O_btreek_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for shared message table message")
+
+ /* All this message requires is a shallow copy */
+ *dest = *mesg;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_btreek_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_btreek_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_btreek_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+
+ ret_value = 1 + /* Version number */
+ 2 + /* Chunked storage internal B-tree 'K' value */
+ 2 + /* Symbol table node internal B-tree 'K' value */
+ 2; /* Symbol table node leaf 'K' value */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_btreek_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_btreek_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_btreek_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_btreek_t *mesg = (const H5O_btreek_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Chunked storage internal B-tree 'K' value:", mesg->btree_k[H5B_CHUNK_ID]);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Symbol table node internal B-tree 'K' value:", mesg->btree_k[H5B_SNODE_ID]);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Symbol table node leaf 'K' value:", mesg->sym_leaf_k);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_btreek_debug() */
+
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
new file mode 100644
index 0000000..8f4c155
--- /dev/null
+++ b/src/H5Ocache.c
@@ -0,0 +1,1671 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ocache.c
+ * Sep 28 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Object header metadata cache virtual functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+static herr_t H5O__cache_get_initial_load_size(void *udata, size_t *image_len);
+static herr_t H5O__cache_get_final_load_size(const void *image_ptr, size_t image_len,
+ void *udata, size_t *actual_len);
+static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5O__cache_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5O__cache_image_len(const void *thing, size_t *image_len);
+static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5O__cache_notify(H5AC_notify_action_t action, void *_thing);
+static herr_t H5O__cache_free_icr(void *thing);
+
+static herr_t H5O__cache_chk_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5O__cache_chk_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len);
+static herr_t H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing);
+static herr_t H5O__cache_chk_free_icr(void *thing);
+
+/* Prefix routines */
+static herr_t H5O__prefix_deserialize(const uint8_t *image,
+ H5O_cache_ud_t *udata);
+
+/* Chunk routines */
+static herr_t H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len,
+ const uint8_t *image, H5O_common_cache_ud_t *udata, hbool_t *dirty);
+static herr_t H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno);
+
+/* Misc. routines */
+static herr_t H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info,
+ const H5O_cont_t *cont);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5O object header prefix inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_OHDR[1] = {{
+ H5AC_OHDR_ID, /* Metadata client ID */
+ "object header", /* Metadata client name (for debugging) */
+ H5FD_MEM_OHDR, /* File space memory type for client */
+ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
+ H5O__cache_get_initial_load_size, /* 'get_initial_load_size' callback */
+ H5O__cache_get_final_load_size, /* 'get_final_load_size' callback */
+ H5O__cache_verify_chksum, /* 'verify_chksum' callback */
+ H5O__cache_deserialize, /* 'deserialize' callback */
+ H5O__cache_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5O__cache_serialize, /* 'serialize' callback */
+ H5O__cache_notify, /* 'notify' callback */
+ H5O__cache_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5O object header chunk inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_OHDR_CHK[1] = {{
+ H5AC_OHDR_CHK_ID, /* Metadata client ID */
+ "object header continuation chunk", /* Metadata client name (for debugging) */
+ H5FD_MEM_OHDR, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5O__cache_chk_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5O__cache_chk_verify_chksum, /* 'verify_chksum' callback */
+ H5O__cache_chk_deserialize, /* 'deserialize' callback */
+ H5O__cache_chk_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5O__cache_chk_serialize, /* 'serialize' callback */
+ H5O__cache_chk_notify, /* 'notify' callback */
+ H5O__cache_chk_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* Declare external the free list for H5O_unknown_t's */
+H5FL_EXTERN(H5O_unknown_t);
+
+/* Declare extern the free list for H5O_chunk_proxy_t's */
+H5FL_EXTERN(H5O_chunk_proxy_t);
+
+/* Declare the free list for H5O_cont_t sequences */
+H5FL_SEQ_DEFINE(H5O_cont_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_get_initial_load_size()
+ *
+ * Purpose: Tell the metadata cache how much data to read from file in
+ * the first speculative read for the object header.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = H5O_SPEC_READ_SIZE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__cache_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_get_final_load_size()
+ *
+ * Purpose: Tell the metadata cache the final size of an object header.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_get_final_load_size(const void *image, size_t image_len,
+ void *_udata, size_t *actual_len)
+{
+ H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(actual_len);
+ HDassert(*actual_len == image_len);
+
+ /* Deserialize the object header prefix */
+ if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't deserialize object header prefix")
+
+ /* Sanity check */
+ HDassert(udata->oh);
+
+ /* Set the final size for the cache image */
+ *actual_len = udata->chunk0_size + (size_t)H5O_SIZEOF_HDR(udata->oh);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_get_final_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+ HDassert(udata->oh);
+
+ /* There is no checksum for version 1 */
+ if(udata->oh->version != H5O_VERSION_1) {
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_deserialize
+ *
+ * Purpose: Attempt to deserialize the object header contained in the
+ * supplied buffer, load the data into an instance of H5O_t, and
+ * return a pointer to the new instance.
+ *
+ * Note that the object header is read with with a speculative read.
+ * If the initial read is too small, make note of this fact and return
+ * without error. H5C_load_entry() will note the size discrepency
+ * and retry the deserialize operation with the correct size read.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__cache_deserialize(const void *image, size_t len, void *_udata,
+ hbool_t *dirty)
+{
+ H5O_t *oh = NULL; /* Object header read in */
+ H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(udata->common.f);
+ HDassert(udata->common.cont_msg_info);
+ HDassert(dirty);
+
+ /* Check for partially deserialized object header */
+ /* (Object header prefix will be deserialized if the object header came
+ * through the 'get_final_load_size' callback and not deserialized if
+ * the object header is coming from a cache image - QAK, 2016/12/14)
+ */
+ if(NULL == udata->oh) {
+ /* Deserialize the object header prefix */
+ if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't deserialize object header prefix")
+
+ /* Sanity check */
+ HDassert(udata->oh);
+ } /* end if */
+
+ /* Retrieve partially deserialized object header from user data */
+ oh = udata->oh;
+
+ /* Set SWMR flag, if appropriate */
+ oh->swmr_write = !!(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE);
+
+ /* Create object header proxy if doing SWMR writes */
+ if(oh->swmr_write) {
+ /* Create virtual entry, for use as proxy */
+ if(NULL == (oh->proxy = H5AC_proxy_entry_create()))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, NULL, "can't create object header proxy")
+ } /* end if */
+ else
+ oh->proxy = NULL;
+
+ /* Parse the first chunk */
+ if(H5O__chunk_deserialize(oh, udata->common.addr, udata->chunk0_size, (const uint8_t *)image, &(udata->common), dirty) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk")
+
+ /* Note that we've loaded the object header from the file */
+ udata->made_attempt = TRUE;
+
+ /* Set return value */
+ ret_value = oh;
+
+done:
+ /* Release the [possibly partially initialized] object header on errors */
+ if(!ret_value && oh)
+ if(H5O__free(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header data")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_image_len
+ *
+ * Purpose: Compute the size in bytes of the specified instance of
+ * H5O_t on disk, and return it in *image_len. On failure,
+ * the value of *image_len is undefined.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_image_len(const void *_thing, size_t *image_len)
+{
+ const H5O_t *oh = (const H5O_t *)_thing; /* Object header to query */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(oh);
+ HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(oh->cache_info.type == H5AC_OHDR);
+ HDassert(image_len);
+
+ /* Report the object header's prefix+first chunk length */
+ *image_len = oh->chunk[0].size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__cache_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_serialize
+ *
+ * Purpose: Serialize the contents of the supplied object header, and
+ * load this data into the supplied buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
+{
+ H5O_t *oh = (H5O_t *)_thing; /* Object header to encode */
+ uint8_t *chunk_image; /* Pointer to object header prefix buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(oh);
+ HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(oh->cache_info.type == H5AC_OHDR);
+ HDassert(oh->chunk[0].size == len);
+#ifdef H5O_DEBUG
+ H5O_assert(oh);
+#endif /* H5O_DEBUG */
+
+ /* Point to raw data 'image' for first chunk, which
+ * has room for the prefix
+ */
+ chunk_image = oh->chunk[0].image;
+
+ /* Later versions of object header prefix have different format and
+ * also require that chunk 0 always be updated, since the checksum
+ * on the entire block of memory needs to be updated if anything is
+ * modified
+ */
+ if(oh->version > H5O_VERSION_1) {
+ uint64_t chunk0_size; /* Size of chunk 0's data */
+
+ HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
+ chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
+
+ /* Verify magic number */
+ HDassert(!HDmemcmp(chunk_image, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC));
+ chunk_image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ *chunk_image++ = oh->version;
+
+ /* Flags */
+ *chunk_image++ = oh->flags;
+
+ /* Time fields */
+ if(oh->flags & H5O_HDR_STORE_TIMES) {
+ UINT32ENCODE(chunk_image, oh->atime);
+ UINT32ENCODE(chunk_image, oh->mtime);
+ UINT32ENCODE(chunk_image, oh->ctime);
+ UINT32ENCODE(chunk_image, oh->btime);
+ } /* end if */
+
+ /* Attribute fields */
+ if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
+ UINT16ENCODE(chunk_image, oh->max_compact);
+ UINT16ENCODE(chunk_image, oh->min_dense);
+ } /* end if */
+
+ /* First chunk size */
+ switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
+ case 0: /* 1 byte size */
+ HDassert(chunk0_size < 256);
+ *chunk_image++ = (uint8_t)chunk0_size;
+ break;
+
+ case 1: /* 2 byte size */
+ HDassert(chunk0_size < 65536);
+ UINT16ENCODE(chunk_image, chunk0_size);
+ break;
+
+ case 2: /* 4 byte size */
+ /* use <= 2**32 -1 to stay within 4 bytes integer range */
+ HDassert(chunk0_size <= 4294967295UL);
+ UINT32ENCODE(chunk_image, chunk0_size);
+ break;
+
+ case 3: /* 8 byte size */
+ UINT64ENCODE(chunk_image, chunk0_size);
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
+ } /* end switch */
+ } /* end if */
+ else {
+ /* Version */
+ *chunk_image++ = oh->version;
+
+ /* Reserved */
+ *chunk_image++ = 0;
+
+ /* Number of messages */
+#ifdef H5O_ENABLE_BAD_MESG_COUNT
+ if(oh->store_bad_mesg_count)
+ UINT16ENCODE(chunk_image, (oh->nmesgs - 1))
+ else
+#endif /* H5O_ENABLE_BAD_MESG_COUNT */
+ UINT16ENCODE(chunk_image, oh->nmesgs);
+
+ /* Link count */
+ UINT32ENCODE(chunk_image, oh->nlink);
+
+ /* First chunk size */
+ UINT32ENCODE(chunk_image, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh)));
+
+ /* Zero to alignment */
+ HDmemset(chunk_image, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12));
+ chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - 12);
+ } /* end else */
+
+ HDassert((size_t)(chunk_image - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
+
+ /* Serialize messages for this chunk */
+ if(H5O__chunk_serialize(f, oh, (unsigned)0) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk")
+
+ /* copy the chunk into the image -- this is potentially expensive.
+ * Can we rework things so that the object header and the cache
+ * share a buffer?
+ */
+ HDmemcpy(image, oh->chunk[0].image, len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Jul 23 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5O_t *oh = (H5O_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(oh);
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ if(oh->swmr_write) {
+ /* Sanity check */
+ HDassert(oh->proxy);
+
+ /* Register the object header as a parent of the virtual entry */
+ if(H5AC_proxy_entry_add_parent(oh->proxy, oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header as parent of proxy")
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ {
+ unsigned u; /* Local index variable */
+
+ /* Mark messages stored with the object header (i.e. messages in chunk 0) as clean */
+ for(u = 0; u < oh->nmesgs; u++)
+ if(oh->mesg[u].chunkno == 0)
+ oh->mesg[u].dirty = FALSE;
+#ifndef NDEBUG
+ /* Reset the number of messages dirtied by decoding */
+ oh->ndecode_dirtied = 0;
+#endif /* NDEBUG */
+ }
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ if(oh->swmr_write) {
+ /* Unregister the object header as a parent of the virtual entry */
+ if(H5AC_proxy_entry_remove_parent(oh->proxy, oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header as parent of proxy")
+ } /* end if */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_free_icr
+ *
+ * Purpose: Free the in core representation of the supplied object header.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_free_icr(void *_thing)
+{
+ H5O_t *oh = (H5O_t *)_thing; /* Object header to destroy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(oh);
+ HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(oh->cache_info.type == H5AC_OHDR);
+
+ /* Destroy object header */
+ if(H5O__free(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_get_initial_load_size()
+ *
+ * Purpose: Tell the metadata cache how large the on disk image of the
+ * chunk proxy is, so it can load the image into a buffer for the
+ * deserialize call.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_chk_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->oh);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__cache_chk_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_chk_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* There is no checksum for version 1 */
+ if(udata->oh->version != H5O_VERSION_1) {
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_chk_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_deserialize
+ *
+ * Purpose: Attempt to deserialize the object header continuation chunk
+ * contained in the supplied buffer, load the data into an instance
+ * of H5O_chunk_proxy_t, and return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata,
+ hbool_t *dirty)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */
+ H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(udata->oh);
+ HDassert(dirty);
+
+ /* Allocate space for the object header data structure */
+ if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Check if we are still decoding the object header */
+ /* (as opposed to bringing a piece of it back from the file) */
+ if(udata->decoding) {
+ /* Sanity check */
+ HDassert(udata->common.f);
+ HDassert(udata->common.cont_msg_info);
+
+ /* Parse the chunk */
+ if(H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, (const uint8_t *)image, &(udata->common), dirty) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk")
+
+ /* Set the chunk number for the chunk proxy */
+ H5_CHECKED_ASSIGN(chk_proxy->chunkno, unsigned, udata->oh->nchunks - 1, size_t);
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(udata->chunkno < udata->oh->nchunks);
+
+ /* Set the chunk number for the chunk proxy */
+ chk_proxy->chunkno = udata->chunkno;
+
+ /* Sanity check that the chunk representation we have in memory is
+ * the same as the one being brought in from disk.
+ */
+ HDassert(0 == HDmemcmp(image, udata->oh->chunk[chk_proxy->chunkno].image, udata->oh->chunk[chk_proxy->chunkno].size));
+ } /* end else */
+
+ /* Increment reference count of object header */
+ if(H5O_inc_rc(udata->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
+ chk_proxy->oh = udata->oh;
+
+ /* Set return value */
+ ret_value = chk_proxy;
+
+done:
+ if(NULL == ret_value)
+ if(chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_chk_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_image_len
+ *
+ * Purpose: Return the on disk image size of a object header chunk to the
+ * metadata cache via the image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_chk_image_len(const void *_thing, size_t *image_len)
+{
+ const H5O_chunk_proxy_t * chk_proxy = (const H5O_chunk_proxy_t *)_thing; /* Chunk proxy to query */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(chk_proxy);
+ HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
+ HDassert(chk_proxy->oh);
+ HDassert(image_len);
+
+ *image_len = chk_proxy->oh->chunk[chk_proxy->chunkno].size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__cache_chk_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_serialize
+ *
+ * Purpose: Given a pointer to an instance of an object header chunk and an
+ * appropriately sized buffer, serialize the contents of the
+ * instance for writing to disk, and copy the serialized data
+ * into the buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
+{
+ H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to serialize */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(chk_proxy);
+ HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
+ HDassert(chk_proxy->oh);
+ HDassert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len);
+
+ /* Serialize messages for this chunk */
+ if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk")
+
+ /* copy the chunk into the image -- this is potentially expensive.
+ * Can we rework things so that the chunk and the cache share a buffer?
+ */
+ HDmemcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_chk_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Mar 20 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing;
+ H5O_chunk_proxy_t *cont_chk_proxy = NULL; /* Proxy for chunk containing continuation message that points to this chunk, if not chunk 0 */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(chk_proxy);
+ HDassert(chk_proxy->oh);
+
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ if(chk_proxy->oh->swmr_write) {
+ /* Add flush dependency on chunk parent */
+ {
+ void *parent; /* Chunk containing continuation message that points to this chunk */
+
+ /* Determine the parent of the chunk */
+ if(chk_proxy->cont_chunkno == 0)
+ parent = chk_proxy->oh;
+ else {
+ if(NULL == (cont_chk_proxy = H5O_chunk_protect(chk_proxy->f, H5AC_ind_read_dxpl_id, chk_proxy->oh, chk_proxy->cont_chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+ parent = cont_chk_proxy;
+ } /* end else */
+
+ /* Sanity checks */
+ HDassert(parent);
+ HDassert(((H5C_cache_entry_t *)parent)->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)parent)->type);
+ HDassert((((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID)
+ || (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_CHK_ID));
+
+ /* Add flush dependency from chunk containing the continuation message
+ * that points to this chunk (either oh or another chunk proxy object)
+ */
+ if(H5AC_create_flush_dependency(parent, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+ /* Make note of the address and pointer of the flush dependency
+ * parent so we can take the dependency down on eviction.
+ */
+ chk_proxy->parent = parent;
+ }
+
+ /* Add flush dependency on object header proxy, if proxy exists */
+ {
+ /* Sanity check */
+ HDassert(chk_proxy->oh->proxy);
+
+ /* Register the object header chunk as a parent of the virtual entry */
+ if(H5AC_proxy_entry_add_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header chunk as parent of proxy")
+ }
+ } /* end if */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ {
+ unsigned u; /* Local index variable */
+
+ /* Mark messages in chunk as clean */
+ for(u = 0; u < chk_proxy->oh->nmesgs; u++)
+ if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno)
+ chk_proxy->oh->mesg[u].dirty = FALSE;
+ }
+ break;
+
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ if(chk_proxy->oh->swmr_write) {
+ /* Remove flush dependency on parent object header chunk */
+ {
+ /* Sanity checks */
+ HDassert(chk_proxy->parent != NULL);
+ HDassert(((H5C_cache_entry_t *)(chk_proxy->parent))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)(chk_proxy->parent))->type);
+ HDassert((((H5C_cache_entry_t *)(chk_proxy->parent))->type->id == H5AC_OHDR_ID) || (((H5C_cache_entry_t *)(chk_proxy->parent))->type->id == H5AC_OHDR_CHK_ID));
+
+ if(H5AC_destroy_flush_dependency(chk_proxy->parent, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ }
+
+ /* Unregister the object header chunk as a parent of the virtual entry */
+ if(H5AC_proxy_entry_remove_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header chunk as parent of proxy")
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+
+done:
+ if(cont_chk_proxy)
+ if(H5O_chunk_unprotect(chk_proxy->f, H5AC_ind_read_dxpl_id, cont_chk_proxy, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_chk_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__cache_chk_free_icr
+ *
+ * Purpose: Free the in core memory associated with the supplied object
+ * header continuation chunk.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__cache_chk_free_icr(void *_thing)
+{
+ H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk proxy to release */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(chk_proxy);
+ HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
+
+ /* Destroy object header chunk proxy */
+ if(H5O__chunk_dest(chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__cache_chk_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__add_cont_msg
+ *
+ * Purpose: Add information from a continuation message to the list of
+ * continuation messages in the object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont)
+{
+ size_t contno; /* Continuation message index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(cont_msg_info);
+ HDassert(cont);
+
+ /* Increase chunk array size, if necessary */
+ if(cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) {
+ size_t na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2); /* Double # of messages allocated */
+ H5O_cont_t *x;
+
+ if(NULL == (x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, na)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed")
+ cont_msg_info->alloc_nmsgs = na;
+ cont_msg_info->msgs = x;
+ } /* end if */
+
+ /* Init the continuation message info */
+ contno = cont_msg_info->nmsgs++;
+ cont_msg_info->msgs[contno].addr = cont->addr;
+ cont_msg_info->msgs[contno].size = cont->size;
+ cont_msg_info->msgs[contno].chunkno = cont->chunkno;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O__add_cont_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__prefix_deserialize()
+ *
+ * Purpose: Deserialize an object header prefix
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * December 14, 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__prefix_deserialize(const uint8_t *_image, H5O_cache_ud_t *udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5O_t *oh = NULL; /* Object header read in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate space for the new object header data structure */
+ if(NULL == (oh = H5FL_CALLOC(H5O_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* File-specific, non-stored information */
+ oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f);
+ oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f);
+
+ /* Check for presence of magic number */
+ /* (indicates version 2 or later) */
+ if(!HDmemcmp(image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) {
+ /* Magic number */
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ oh->version = *image++;
+ if(H5O_VERSION_2 != oh->version)
+ HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
+
+ /* Flags */
+ oh->flags = *image++;
+ if(oh->flags & ~H5O_HDR_ALL_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown object header status flag(s)")
+
+ /* Number of links to object (unless overridden by refcount message) */
+ oh->nlink = 1;
+
+ /* Time fields */
+ if(oh->flags & H5O_HDR_STORE_TIMES) {
+ uint32_t tmp; /* Temporary value */
+
+ UINT32DECODE(image, tmp);
+ oh->atime = (time_t)tmp;
+ UINT32DECODE(image, tmp);
+ oh->mtime = (time_t)tmp;
+ UINT32DECODE(image, tmp);
+ oh->ctime = (time_t)tmp;
+ UINT32DECODE(image, tmp);
+ oh->btime = (time_t)tmp;
+ } /* end if */
+ else
+ oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
+
+ /* Attribute fields */
+ if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
+ UINT16DECODE(image, oh->max_compact);
+ UINT16DECODE(image, oh->min_dense);
+ if(oh->max_compact < oh->min_dense)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header attribute phase change values")
+ } /* end if */
+ else {
+ oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF;
+ oh->min_dense = H5O_CRT_ATTR_MIN_DENSE_DEF;
+ } /* end else */
+
+ /* First chunk size */
+ switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
+ case 0: /* 1 byte size */
+ udata->chunk0_size = *image++;
+ break;
+
+ case 1: /* 2 byte size */
+ UINT16DECODE(image, udata->chunk0_size);
+ break;
+
+ case 2: /* 4 byte size */
+ UINT32DECODE(image, udata->chunk0_size);
+ break;
+
+ case 3: /* 8 byte size */
+ UINT64DECODE(image, udata->chunk0_size);
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
+ } /* end switch */
+ if(udata->chunk0_size > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
+ } /* end if */
+ else {
+ /* Version */
+ oh->version = *image++;
+ if(H5O_VERSION_1 != oh->version)
+ HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
+
+ /* Flags */
+ oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
+
+ /* Reserved */
+ image++;
+
+ /* Number of messages */
+ UINT16DECODE(image, udata->v1_pfx_nmesgs);
+
+ /* Link count */
+ UINT32DECODE(image, oh->nlink);
+
+ /* Reset unused time fields */
+ oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
+
+ /* Reset unused attribute fields */
+ oh->max_compact = 0;
+ oh->min_dense = 0;
+
+ /* First chunk size */
+ UINT32DECODE(image, udata->chunk0_size);
+ if((udata->v1_pfx_nmesgs > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
+ (udata->v1_pfx_nmesgs == 0 && udata->chunk0_size > 0))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
+
+ /* Reserved, in version 1 (for 8-byte alignment padding) */
+ image += 4;
+ } /* end else */
+
+ /* Verify object header prefix length */
+ HDassert((size_t)(image - _image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
+
+ /* Save the object header for later use in 'deserialize' callback */
+ udata->oh = oh;
+ oh = NULL;
+
+done:
+ /* Release the [possibly partially initialized] object header on errors */
+ if(ret_value < 0 && oh)
+ if(H5O__free(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header data")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__prefix_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__chunk_deserialize
+ *
+ * Purpose: Deserialize a chunk for an object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image,
+ H5O_common_cache_ud_t *udata, hbool_t *dirty)
+{
+ const uint8_t *chunk_image; /* Pointer into buffer to decode */
+ uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */
+ unsigned merged_null_msgs = 0; /* Number of null messages merged together */
+ unsigned chunkno; /* Current chunk's index */
+#ifndef NDEBUG
+ unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */
+#endif /* NDEBUG */
+ hbool_t mesgs_modified = FALSE; /* Whether any messages were modified when the object header was deserialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(oh);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(image);
+ HDassert(udata->f);
+ HDassert(udata->cont_msg_info);
+
+ /* Increase chunk array size, if necessary */
+ if(oh->nchunks >= oh->alloc_nchunks) {
+ size_t na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
+ H5O_chunk_t *x;
+
+ if(NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ oh->alloc_nchunks = na;
+ oh->chunk = x;
+ } /* end if */
+
+ /* Init the chunk data info */
+ chunkno = (unsigned)oh->nchunks++;
+ oh->chunk[chunkno].gap = 0;
+ oh->chunk[chunkno].addr = addr;
+ if(chunkno == 0)
+ /* First chunk's 'image' includes room for the object header prefix */
+ oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh);
+ else
+ oh->chunk[chunkno].size = len;
+ if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ oh->chunk[chunkno].chunk_proxy = NULL;
+
+ /* Copy disk image into chunk's image */
+ HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size);
+
+ /* Point into chunk image to decode */
+ chunk_image = oh->chunk[chunkno].image;
+
+ /* Handle chunk 0 as special case */
+ if(chunkno == 0)
+ /* Skip over [already decoded] prefix */
+ chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh));
+ /* Check for magic # on chunks > 0 in later versions of the format */
+ else if(chunkno > 0 && oh->version > H5O_VERSION_1) {
+ /* Magic number */
+ if(HDmemcmp(chunk_image, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature")
+ chunk_image += H5_SIZEOF_MAGIC;
+ } /* end if */
+
+ /* Decode messages from this chunk */
+ eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
+#ifndef NDEBUG
+ nullcnt = 0;
+#endif /* NDEBUG */
+ while(chunk_image < eom_ptr) {
+ size_t mesg_size; /* Size of message read in */
+ unsigned id; /* ID (type) of current message */
+ uint8_t flags; /* Flags for current message */
+ H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */
+
+ /* Decode message prefix info */
+
+ /* Version # */
+ if(oh->version == H5O_VERSION_1)
+ UINT16DECODE(chunk_image, id)
+ else
+ id = *chunk_image++;
+
+ /* Message size */
+ UINT16DECODE(chunk_image, mesg_size);
+ HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size));
+
+ /* Message flags */
+ flags = *chunk_image++;
+ if(flags & ~H5O_MSG_FLAG_BITS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message")
+ if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+ if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+ if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+ if((flags & H5O_MSG_FLAG_SHAREABLE)
+ && H5O_msg_class_g[id]
+ && !(H5O_msg_class_g[id]->share_flags & H5O_SHARE_IS_SHARABLE))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message of unsharable class flagged as sharable")
+
+ /* Reserved bytes/creation index */
+ if(oh->version == H5O_VERSION_1)
+ chunk_image += 3; /*reserved*/
+ else {
+ /* Only decode creation index if they are being tracked */
+ if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
+ UINT16DECODE(chunk_image, crt_idx);
+ } /* end else */
+
+ /* Try to detect invalidly formatted object header message that
+ * extends past end of chunk.
+ */
+ if(chunk_image + mesg_size > eom_ptr)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header")
+
+#ifndef NDEBUG
+ /* Increment count of null messages */
+ if(H5O_NULL_ID == id)
+ nullcnt++;
+#endif /* NDEBUG */
+
+ /* Check for combining two adjacent 'null' messages */
+ if((udata->file_intent & H5F_ACC_RDWR) &&
+ H5O_NULL_ID == id && oh->nmesgs > 0 &&
+ H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
+ oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
+ size_t mesgno; /* Current message to operate on */
+
+ /* Combine adjacent null messages */
+ mesgno = oh->nmesgs - 1;
+ oh->mesg[mesgno].raw_size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
+ oh->mesg[mesgno].dirty = TRUE;
+ merged_null_msgs++;
+ } /* end if */
+ else {
+ H5O_mesg_t *mesg; /* Pointer to new message */
+ unsigned ioflags = 0; /* Flags for decode routine */
+
+ /* Check if we need to extend message table to hold the new message */
+ if(oh->nmesgs >= oh->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages")
+
+ /* Get pointer to message to set up */
+ mesg = &oh->mesg[oh->nmesgs];
+
+ /* Increment # of messages */
+ oh->nmesgs++;
+
+ /* Initialize information about message */
+ mesg->dirty = FALSE;
+ mesg->flags = flags;
+ mesg->crt_idx = crt_idx;
+ mesg->native = NULL;
+ mesg->raw = (uint8_t *)chunk_image; /* Casting away const OK - QAK */
+ mesg->raw_size = mesg_size;
+ mesg->chunkno = chunkno;
+
+ /* Point unknown messages at 'unknown' message class */
+ /* (Usually from future versions of the library) */
+ if(id >= H5O_UNKNOWN_ID ||
+#ifdef H5O_ENABLE_BOGUS
+ id == H5O_BOGUS_VALID_ID ||
+#endif
+ NULL == H5O_msg_class_g[id]) {
+
+ H5O_unknown_t *unknown; /* Pointer to "unknown" message info */
+
+ /* Allocate "unknown" message info */
+ if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Save the original message type ID */
+ *unknown = id;
+
+ /* Save 'native' form of unknown message */
+ mesg->native = unknown;
+
+ /* Set message to "unknown" class */
+ mesg->type = H5O_msg_class_g[H5O_UNKNOWN_ID];
+
+ /* Check for "fail if unknown" message flags */
+ if(((udata->file_intent & H5F_ACC_RDWR) &&
+ (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
+ || (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unknown message with 'fail if unknown' flag found")
+ /* Check for "mark if unknown" message flag, etc. */
+ else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) &&
+ !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
+ (udata->file_intent & H5F_ACC_RDWR)) {
+
+ /* Mark the message as "unknown" */
+ /* This is a bit aggressive, since the application may
+ * never change anything about the object (metadata or
+ * raw data), but we can sort out the finer details
+ * when/if we start using the flag - QAK
+ */
+ /* Also, it's possible that this functionality may not
+ * get invoked if the object header is brought into
+ * the metadata cache in some other "weird" way, like
+ * using H5Ocopy() - QAK
+ */
+ mesg->flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
+
+ /* Mark the message and chunk as dirty */
+ mesg->dirty = TRUE;
+ mesgs_modified = TRUE;
+ } /* end if */
+ } /* end if */
+ else
+ /* Set message class for "known" messages */
+ mesg->type = H5O_msg_class_g[id];
+
+ /* Do some inspection/interpretation of new messages from this chunk */
+ /* (detect continuation messages, ref. count messages, etc.) */
+
+ /* Check if message is a continuation message */
+ if(H5O_CONT_ID == id) {
+ H5O_cont_t *cont;
+
+ /* Decode continuation message */
+ cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, mesg->raw);
+ H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1, size_t); /* the next continuation message/chunk */
+
+ /* Save 'native' form of continuation message */
+ mesg->native = cont;
+
+ /* Add to continuation messages left to interpret */
+ if(H5O__add_cont_msg(udata->cont_msg_info, cont) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message")
+ } /* end if */
+ /* Check if message is a ref. count message */
+ else if(H5O_REFCOUNT_ID == id) {
+ H5O_refcount_t *refcount;
+
+ /* Decode ref. count message */
+ HDassert(oh->version > H5O_VERSION_1);
+ refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, mesg->raw);
+
+ /* Save 'native' form of ref. count message */
+ mesg->native = refcount;
+
+ /* Set object header values */
+ oh->has_refcount_msg = TRUE;
+ oh->nlink = *refcount;
+ } /* end if */
+ /* Check if message is a link message */
+ else if(H5O_LINK_ID == id) {
+ /* Increment the count of link messages */
+ oh->link_msgs_seen++;
+ } /* end if */
+ /* Check if message is an attribute message */
+ else if(H5O_ATTR_ID == id) {
+ /* Increment the count of attribute messages */
+ oh->attr_msgs_seen++;
+ } /* end if */
+
+ /* Mark the message & chunk as dirty if the message was changed by decoding */
+ if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
+ mesg->dirty = TRUE;
+ mesgs_modified = TRUE;
+ } /* end if */
+ } /* end else */
+
+ /* Advance decode pointer past message */
+ chunk_image += mesg_size;
+
+ /* Check for 'gap' at end of chunk */
+ if((eom_ptr - chunk_image) > 0 && (eom_ptr - chunk_image) < H5O_SIZEOF_MSGHDR_OH(oh)) {
+ /* Gaps can only occur in later versions of the format */
+ HDassert(oh->version > H5O_VERSION_1);
+
+ /* Gaps should only occur in chunks with no null messages */
+ HDassert(nullcnt == 0);
+
+ /* Set gap information for chunk */
+ oh->chunk[chunkno].gap = (size_t)(eom_ptr - chunk_image);
+
+ /* Increment location in chunk */
+ chunk_image += oh->chunk[chunkno].gap;
+ } /* end if */
+ } /* end while */
+
+ /* Check for correct checksum on chunks, in later versions of the format */
+ if(oh->version > H5O_VERSION_1) {
+ uint32_t stored_chksum; /* Checksum from file */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(chunk_image, stored_chksum);
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(chunk_image == oh->chunk[chunkno].image + oh->chunk[chunkno].size);
+
+ /* Mark the chunk dirty if we've modified messages */
+ if(mesgs_modified)
+ *dirty = TRUE;
+
+ /* Mark the chunk dirty if we've merged null messages */
+ if(merged_null_msgs > 0) {
+ udata->merged_null_msgs += merged_null_msgs;
+ *dirty = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O__chunk_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__chunk_serialize
+ *
+ * Purpose: Serialize a chunk for an object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Encode any dirty messages in this chunk */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
+ if(curr_msg->dirty && curr_msg->chunkno == chunkno)
+ /* Casting away const OK -QAK */
+ if(H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
+
+ /* Sanity checks */
+ if(oh->version > H5O_VERSION_1)
+ /* Make certain the magic # is present */
+ HDassert(!HDmemcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
+ else
+ /* Gaps should never occur in version 1 of the format */
+ HDassert(oh->chunk[chunkno].gap == 0);
+
+ /* Extra work, for later versions of the format */
+ if(oh->version > H5O_VERSION_1) {
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ uint8_t *chunk_image; /* Pointer into object header chunk */
+
+ /* Check for gap in chunk & zero it out */
+ if(oh->chunk[chunkno].gap)
+ HDmemset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
+ (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap), 0, oh->chunk[chunkno].gap);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
+
+ /* Metadata checksum */
+ chunk_image = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM);
+ UINT32ENCODE(chunk_image, metadata_chksum);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O__chunk_serialize() */
+
diff --git a/src/H5Ocache_image.c b/src/H5Ocache_image.c
new file mode 100644
index 0000000..29b2503
--- /dev/null
+++ b/src/H5Ocache_image.c
@@ -0,0 +1,377 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ocache_image.c
+ * June 21, 2015
+ * John Mainzer
+ *
+ * Purpose: A message indicating that a metadata cache image block
+ * of the indicated length exists at the specified offset
+ * in the HDF5 file.
+ *
+ * The mdci_msg only appears in the superblock extension.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Opkg.h" /* Object headers */
+#include "H5MFprivate.h" /* File space management */
+
+/* Callbacks for message class */
+static void *H5O__mdci_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O__mdci_encode(H5F_t *f, hbool_t disable_shared,
+ uint8_t *p, const void *_mesg);
+static void *H5O__mdci_copy(const void *_mesg, void *_dest);
+static size_t H5O__mdci_size(const H5F_t *f, hbool_t disable_shared,
+ const void *_mesg);
+static herr_t H5O__mdci_free(void *mesg);
+static herr_t H5O__mdci_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ void *_mesg);
+static herr_t H5O__mdci_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE *stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_MDCI[1] = {{
+ H5O_MDCI_MSG_ID, /* message id number */
+ "mdci", /* message name for debugging */
+ sizeof(H5O_mdci_t), /* native message size */
+ 0, /* messages are sharable? */
+ H5O__mdci_decode, /* decode message */
+ H5O__mdci_encode, /* encode message */
+ H5O__mdci_copy, /* copy method */
+ H5O__mdci_size, /* size of mdc image message */
+ NULL, /* reset method */
+ H5O__mdci_free, /* free method */
+ H5O__mdci_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /* set share method */
+ NULL, /* can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O__mdci_debug /* debugging */
+}};
+
+/* Only one version of the metadata cache image message at present */
+#define H5O_MDCI_VERSION_0 0
+
+/* Declare the free list for H5O_mdci_t's */
+H5FL_DEFINE(H5O_mdci_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_decode
+ *
+ * Purpose: Decode a metadata cache image message and return a
+ * pointer to a newly allocated H5O_mdci_t struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__mdci_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
+ unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_mdci_t *mesg; /* Native message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_MDCI_VERSION_0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (mesg = (H5O_mdci_t *)H5FL_MALLOC(H5O_mdci_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for metadata cache image message")
+
+ /* Decode */
+ H5F_addr_decode(f, &p, &(mesg->addr));
+ H5F_DECODE_LENGTH(f, p, mesg->size);
+
+ /* Set return value */
+ ret_value = (void *)mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__mdci_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_encode
+ *
+ * Purpose: Encode metadata cache image message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__mdci_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared,
+ uint8_t *p, const void *_mesg)
+{
+ const H5O_mdci_t *mesg = (const H5O_mdci_t *)_mesg;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* encode */
+ *p++ = H5O_MDCI_VERSION_0;
+ H5F_addr_encode(f, &p, mesg->addr);
+ H5F_ENCODE_LENGTH(f, p, mesg->size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__mdci_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__mdci_copy(const void *_mesg, void *_dest)
+{
+ const H5O_mdci_t *mesg = (const H5O_mdci_t *)_mesg;
+ H5O_mdci_t *dest = (H5O_mdci_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(mesg);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_mdci_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *mesg;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_mdci__copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ *
+ * Failure: zero
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O__mdci_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared,
+ const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)( 1 + /* Version number */
+ H5F_SIZEOF_ADDR(f) + /* addr of metadata cache */
+ /* image block */
+ H5F_SIZEOF_SIZE(f) ); /* length of metadata cache */
+ /* image block */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__mdci_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_free
+ *
+ * Purpose: Free the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__mdci_free(void *mesg)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_mdci_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__mdci_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, March 19, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__mdci_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_mdci_t *mesg = (H5O_mdci_t *)_mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(open_oh);
+ HDassert(mesg);
+
+ /* Free file space for cache image */
+ if(H5F_addr_defined(mesg->addr)) {
+ /* The space for the cache image block was allocated directly
+ * from the VFD layer at the end of file. As this was the
+ * last file space allocation before shutdown, the cache image
+ * should still be the last item in the file.
+ *
+ * If the hack to work around the self referential free space
+ * manager issue is in use, file space for the non-empty self
+ * referential free space managers was also allocated from VFD
+ * layer at the end of file. Since these allocations directly
+ * preceeded the cache image allocation they should be directly
+ * adjacent to the cache image block at the end of file.
+ *
+ * In this case, just call H5MF_tidy_self_referential_fsm_hack().
+ *
+ * That routine will float the self referential free space
+ * managers, and reduce the eoa to its value just prior to
+ * allocation of space for same. Since the cache image appears
+ * just after the self referential free space managers, this
+ * will release the file space for the cache image as well.
+ *
+ * Note that in this case, there must not have been any file
+ * space allocations / deallocations prior to the free of the
+ * cache image. Verify this to the extent possible.
+ *
+ * If the hack to work around the persistant self referential
+ * free space manager issue is NOT in use, just call H5MF_xfree()
+ * to release the cache iamge. In principle, we should be able
+ * to just reduce the EOA to the base address of the cache
+ * image block, as there shouldn't be any file space allocation
+ * before the first metadata cache access. However, given
+ * time constraints, I don't want to go there now.
+ */
+ if(H5F_FIRST_ALLOC_DEALLOC(f)) {
+ HDassert(HADDR_UNDEF !=H5F_EOA_PRE_FSM_FSALLOC(f));
+ HDassert(H5F_addr_ge(mesg->addr, H5F_EOA_PRE_FSM_FSALLOC(f)));
+ if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed")
+ } /* end if */
+ else {
+ if(H5MF_xfree(f, H5FD_MEM_SUPER, dxpl_id, mesg->addr, mesg->size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free file space for cache image block")
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__mdci_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__mdci_debug
+ *
+ * Purpose: Prints debugging info.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/22/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__mdci_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id,
+ const void *_mesg, FILE * stream, int indent, int fwidth)
+{
+ const H5O_mdci_t *mdci = (const H5O_mdci_t *) _mesg;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mdci);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Metadata Cache Image Block address:", mdci->addr);
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Metadata Cache Image Block size in bytes:", mdci->size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__mdci_debug() */
+
diff --git a/src/H5Ochunk.c b/src/H5Ochunk.c
new file mode 100644
index 0000000..dbc894c
--- /dev/null
+++ b/src/H5Ochunk.c
@@ -0,0 +1,451 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ochunk.c
+ * Jul 13 2008
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object header chunk routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object headers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare the free list for H5O_chunk_proxy_t's */
+H5FL_DEFINE(H5O_chunk_proxy_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_add
+ *
+ * Purpose: Add new chunk for object header to metadata cache
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_chunk_add(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx,
+ unsigned cont_chunkno)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Proxy for chunk, to mark it dirty in the cache */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(idx < oh->nchunks);
+ HDassert(idx > 0);
+
+ /* Allocate space for the object header data structure */
+ if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Increment reference count on object header */
+ if(H5O_inc_rc(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "can't increment reference count on object header")
+
+ /* Set the values in the chunk proxy */
+ chk_proxy->f = f;
+ chk_proxy->oh = oh;
+ chk_proxy->chunkno = idx;
+ chk_proxy->cont_chunkno = cont_chunkno;
+
+ /* Insert the chunk proxy into the cache */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header chunk")
+
+ chk_proxy = NULL;
+
+done:
+ if(ret_value < 0)
+ if(chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_chunk_add() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_protect
+ *
+ * Purpose: Protect an object header chunk for modifications
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 17 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_chunk_proxy_t *
+H5O_chunk_protect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Proxy for protected chunk */
+ H5O_chunk_proxy_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oh->cache_info.addr, NULL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(idx < oh->nchunks);
+
+ /* Check for protecting first chunk */
+ if(0 == idx) {
+ /* Create new "fake" chunk proxy for first chunk */
+ /* (since the first chunk is already handled by the H5O_t object) */
+ if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Increment reference count on object header */
+ if(H5O_inc_rc(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
+
+ /* Set chunk proxy fields */
+ chk_proxy->f = f;
+ chk_proxy->oh = oh;
+ chk_proxy->chunkno = idx;
+ } /* end if */
+ else {
+ H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
+
+ /* Construct the user data for protecting chunk proxy */
+ /* (and _not_ decoding it) */
+ HDmemset(&chk_udata, 0, sizeof(chk_udata));
+ chk_udata.oh = oh;
+ chk_udata.chunkno = idx;
+ chk_udata.size = oh->chunk[idx].size;
+
+ /* Get the chunk proxy */
+ if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk")
+
+ /* Sanity check */
+ HDassert(chk_proxy->oh == oh);
+ HDassert(chk_proxy->chunkno == idx);
+ } /* end else */
+
+ /* Set return value */
+ ret_value = chk_proxy;
+
+done:
+ /* Cleanup on error */
+ if(!ret_value)
+ if(0 == idx && chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_chunk_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_unprotect
+ *
+ * Purpose: Unprotect an object header chunk after modifications
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 17 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_chunk_unprotect(H5F_t *f, hid_t dxpl_id, H5O_chunk_proxy_t *chk_proxy,
+ hbool_t dirtied)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(chk_proxy);
+
+ /* Check for releasing first chunk */
+ if(0 == chk_proxy->chunkno) {
+ /* Check for dirtying the first chunk */
+ if(dirtied) {
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(chk_proxy->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+ } /* end else/if */
+
+ /* Decrement reference count of object header */
+ if(H5O_dec_rc(chk_proxy->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header")
+
+ /* Free fake chunk proxy */
+ chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy);
+ } /* end if */
+ else {
+ /* Release the chunk proxy from the cache, possibly marking it dirty */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, chk_proxy->oh->chunk[chk_proxy->chunkno].addr, chk_proxy, (dirtied ? H5AC__DIRTIED_FLAG : H5AC__NO_FLAGS_SET)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_chunk_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_resize
+ *
+ * Purpose: Resize an object header chunk
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 6 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_chunk_resize(H5O_t *oh, H5O_chunk_proxy_t *chk_proxy)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(oh);
+ HDassert(chk_proxy);
+
+ /* Check for resizing first chunk */
+ if(0 == chk_proxy->chunkno) {
+ /* Resize object header in cache */
+ if(H5AC_resize_entry(oh, oh->chunk[0].size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize chunk in cache")
+ } /* end if */
+ else {
+ /* Resize chunk in cache */
+ if(H5AC_resize_entry(chk_proxy, oh->chunk[chk_proxy->chunkno].size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize chunk in cache")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_chunk_resize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_update_idx
+ *
+ * Purpose: Update the chunk index for a chunk proxy
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_chunk_update_idx(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx)
+{
+ H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to mark it dirty in the cache */
+ H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(idx < oh->nchunks);
+ HDassert(idx > 0);
+
+ /* Construct the user data for protecting chunk proxy */
+ /* (and _not_ decoding it) */
+ HDmemset(&chk_udata, 0, sizeof(chk_udata));
+ chk_udata.oh = oh;
+ chk_udata.chunkno = idx;
+ chk_udata.size = oh->chunk[idx].size;
+
+ /* Get the chunk proxy */
+ if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Update index for chunk proxy in cache */
+ chk_proxy->chunkno = idx;
+
+ /* Release the chunk proxy from the cache, marking it deleted */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__DIRTIED_FLAG) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_chunk_update_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_delete
+ *
+ * Purpose: Notify metadata cache that a chunk has been deleted
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 13 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx)
+{
+ H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to mark it dirty in the cache */
+ H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
+ unsigned cache_flags = H5AC__DELETED_FLAG; /* Flags for unprotecting proxy */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(idx < oh->nchunks);
+ HDassert(idx > 0);
+
+ /* Construct the user data for protecting chunk proxy */
+ /* (and _not_ decoding it) */
+ HDmemset(&chk_udata, 0, sizeof(chk_udata));
+ chk_udata.oh = oh;
+ chk_udata.chunkno = idx;
+ chk_udata.size = oh->chunk[idx].size;
+
+ /* Get the chunk proxy */
+ if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
+
+ /* Sanity check */
+ HDassert(chk_proxy->oh == oh);
+ HDassert(chk_proxy->chunkno == idx);
+
+ /* Only free file space if not doing SWMR writes */
+ if(!oh->swmr_write)
+ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
+
+ /* Release the chunk proxy from the cache, marking it deleted */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, cache_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_chunk_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__chunk_dest
+ *
+ * Purpose: Destroy a chunk proxy object
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 13, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O__chunk_dest(H5O_chunk_proxy_t *chk_proxy)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check arguments */
+ HDassert(chk_proxy);
+
+ /* Decrement reference count of object header */
+ if(chk_proxy->oh && H5O_dec_rc(chk_proxy->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header")
+
+ /* Release the chunk proxy object */
+ chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O__chunk_dest() */
+
diff --git a/src/H5Ocont.c b/src/H5Ocont.c
new file mode 100644
index 0000000..b002a32
--- /dev/null
+++ b/src/H5Ocont.c
@@ -0,0 +1,288 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ocont.c
+ * Aug 6 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: The object header continuation message. This
+ * message is only generated and read from within
+ * the H5O package. Therefore, do not change
+ * any definitions in this file!
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_cont_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_cont_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static size_t H5O_cont_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_cont_free(void *mesg);
+static herr_t H5O_cont_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg);
+static herr_t H5O_cont_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_CONT[1] = {{
+ H5O_CONT_ID, /*message id number */
+ "hdr continuation", /*message name for debugging */
+ sizeof(H5O_cont_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_cont_decode, /*decode message */
+ H5O_cont_encode, /*encode message */
+ NULL, /*no copy method */
+ H5O_cont_size, /*size of header continuation */
+ NULL, /*reset method */
+ H5O_cont_free, /* free method */
+ H5O_cont_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_cont_debug /*debugging */
+}};
+
+/* Declare the free list for H5O_cont_t's */
+H5FL_DEFINE(H5O_cont_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_decode
+ *
+ * Purpose: Decode the raw header continuation message.
+ *
+ * Return: Success: Ptr to the new native message
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_cont_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_cont_t *cont = NULL;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Allocate space for the message */
+ if(NULL == (cont = H5FL_MALLOC(H5O_cont_t)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+
+ /* Decode */
+ H5F_addr_decode(f, &p, &(cont->addr));
+ H5F_DECODE_LENGTH(f, p, cont->size);
+ cont->chunkno = 0;
+
+ /* Set return value */
+ ret_value = cont;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cont_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_encode
+ *
+ * Purpose: Encodes a continuation message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 7 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cont_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_cont_t *cont = (const H5O_cont_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(cont);
+ HDassert(H5F_addr_defined(cont->addr));
+ HDassert(cont->size > 0);
+
+ /* encode */
+ H5F_addr_encode(f, &p, cont->addr);
+ H5F_ENCODE_LENGTH(f, p, cont->size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_cont_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ *
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_cont_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)(H5F_SIZEOF_ADDR(f) + /* Continuation header address */
+ H5F_SIZEOF_SIZE(f)); /* Continuation header length */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cont_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 15, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cont_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_cont_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_cont_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 10, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cont_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_cont_t *mesg = (H5O_cont_t *) _mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Notify the cache that the chunk has been deleted */
+ /* (releases the space for the chunk) */
+ if(H5O_chunk_delete(f, dxpl_id, open_oh, mesg->chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove chunk from cache")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cont_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cont_debug
+ *
+ * Purpose: Prints debugging info.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cont_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_cont_t *cont = (const H5O_cont_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(cont);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Continuation address:", cont->addr);
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Continuation size in bytes:",
+ (unsigned long) (cont->size));
+ HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Points to chunk number:",
+ (int) (cont->chunkno));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_cont_debug() */
diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c
new file mode 100644
index 0000000..597af63
--- /dev/null
+++ b/src/H5Ocopy.c
@@ -0,0 +1,1989 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ocopy.c
+ * Nov 6 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object copying routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Aprivate.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Lprivate.h" /* Links */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Key object for skiplist of committed datatypes */
+typedef struct H5O_copy_search_comm_dt_key_t {
+ H5T_t *dt; /* Datatype */
+ unsigned long fileno; /* File number */
+} H5O_copy_search_comm_dt_key_t;
+
+/* Callback struct for building a list of committed datatypes */
+typedef struct H5O_copy_search_comm_dt_ud_t {
+ H5SL_t *dst_dt_list; /* Skip list of committed datatypes */
+ H5G_loc_t *dst_root_loc; /* Starting location for iteration */
+ H5O_loc_t obj_oloc; /* Object location (for attribute iteration callback) */
+ hid_t dxpl_id; /* Dataset transfer property list id */
+} H5O_copy_search_comm_dt_ud_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5O_copy_free_addrmap_cb(void *item, void *key, void *op_data);
+static herr_t H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
+ hid_t dxpl_id, H5O_copy_t *cpy_info, H5O_type_t *obj_type, void **udata);
+static herr_t H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
+ hid_t dxpl_id, hid_t ocpypl_id);
+static herr_t H5O_copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc,
+ const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id, hid_t dxpl_id);
+static herr_t H5O_copy_obj_by_ref(H5O_loc_t *src_oloc, hid_t dxpl_id,
+ H5O_loc_t *dst_oloc, H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info);
+static herr_t H5O_copy_free_comm_dt_cb(void *item, void *key, void *op_data);
+static int H5O_copy_comm_dt_cmp(const void *dt1, const void *dt2);
+static herr_t H5O_copy_search_comm_dt_cb(hid_t group, const char *name,
+ const H5L_info_t *linfo, void *udata);
+static htri_t H5O_copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src,
+ H5O_loc_t *oloc_dst/*in, out*/, hid_t dxpl_id, H5O_copy_t *cpy_info);
+static herr_t H5O_copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src,
+ H5O_loc_t *oloc_dst, hid_t dxpl_id, H5O_copy_t *cpy_info);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5O_addr_map_t struct */
+H5FL_DEFINE(H5O_addr_map_t);
+
+/* Declare a free list to manage the H5O_copy_search_comm_dt_key_t struct */
+H5FL_DEFINE(H5O_copy_search_comm_dt_key_t);
+
+/* Declare a free list to manage haddr_t variables */
+H5FL_DEFINE(haddr_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ocopy
+ *
+ * Purpose: Copy an object (group or dataset) to destination location
+ * within a file or cross files. PLIST_ID is a property list
+ * which is used to pass user options and properties to the
+ * copy. The name, dst_name, must not already be taken by some
+ * other object in the destination group.
+ *
+ * H5Ocopy() will fail if the name of the destination object
+ * exists in the destination group. For example,
+ * H5Ocopy(fid_src, "/dset", fid_dst, "/dset", ...)
+ * will fail if "/dset" exists in the destination file
+ *
+ * OPTIONS THAT HAVE BEEN IMPLEMENTED.
+ * H5O_COPY_SHALLOW_HIERARCHY_FLAG
+ * If this flag is specified, only immediate members of
+ * the group are copied. Otherwise (default), it will
+ * recursively copy all objects below the group
+ * H5O_COPY_EXPAND_SOFT_LINK_FLAG
+ * If this flag is specified, it will copy the objects
+ * pointed by the soft links. Otherwise (default), it
+ * will copy the soft link as they are
+ * H5O_COPY_WITHOUT_ATTR_FLAG
+ * If this flag is specified, it will copy object without
+ * copying attributes. Otherwise (default), it will
+ * copy object along with all its attributes
+ * H5O_COPY_EXPAND_REFERENCE_FLAG
+ * 1) Copy object between two different files:
+ * When this flag is specified, it will copy objects that
+ * are pointed by the references and update the values of
+ * references in the destination file. Otherwise (default)
+ * the values of references in the destination will set to
+ * zero
+ * The current implementation does not handle references
+ * inside of other datatype structure. For example, if
+ * a member of compound datatype is reference, H5Ocopy()
+ * will copy that field as it is. It will not set the
+ * value to zero as default is used nor copy the object
+ * pointed by that field the flag is set
+ * 2) Copy object within the same file:
+ * This flag does not have any effect to the H5Ocopy().
+ * Datasets or attributes of references are copied as they
+ * are, i.e. values of references of the destination object
+ * are the same as the values of the source object
+ *
+ * OPTIONS THAT MAY APPLY TO COPY IN THE FUTURE.
+ * H5O_COPY_EXPAND_EXT_LINK_FLAG
+ * If this flag is specified, it will expand the external links
+ * into new objects, Otherwise (default), it will keep external
+ * links as they are (default)
+ *
+ * PROPERTIES THAT MAY APPLY TO COPY IN FUTURE
+ * Change data layout such as chunk size
+ * Add filter such as data compression.
+ * Add an attribute to the copied object(s) that say the date/time
+ * for the copy or other information about the source file.
+ *
+ * The intermediate group creation property should be passed in
+ * using the lcpl instead of the ocpypl.
+ *
+ * Usage: H5Ocopy(src_loc_id, src_name, dst_loc_id, dst_name, ocpypl_id, lcpl_id)
+ * hid_t src_loc_id IN: Source file or group identifier.
+ * const char *src_name IN: Name of the source object to be copied
+ * hid_t dst_loc_id IN: Destination file or group identifier
+ * const char *dst_name IN: Name of the destination object
+ * hid_t ocpypl_id IN: Properties which apply to the copy
+ * hid_t lcpl_id IN: Properties which apply to the new hard link
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * June 4, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Ocopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id)
+{
+ H5G_loc_t loc; /* Source group group location */
+ H5G_loc_t src_loc; /* Source object group location */
+ H5G_loc_t dst_loc; /* Destination group location */
+
+ /* for opening the destination object */
+ H5G_name_t src_path; /* Opened source object hier. path */
+ H5O_loc_t src_oloc; /* Opened source object object location */
+ htri_t dst_exists; /* Does destination name exist already? */
+ hbool_t loc_found = FALSE; /* Location at 'name' found */
+ hbool_t obj_open = FALSE; /* Entry at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name,
+ ocpypl_id, lcpl_id);
+
+ /* Check arguments */
+ if(H5G_loc(src_loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(H5G_loc(dst_loc_id, &dst_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!src_name || !*src_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source name specified")
+ if(!dst_name || !*dst_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified")
+
+ /* check if destination name already exists */
+ if((dst_exists = H5L_exists_tolerant(&dst_loc, dst_name, H5P_DEFAULT, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check if destination name exists")
+ if(TRUE == dst_exists)
+ HGOTO_ERROR(H5E_OHDR, H5E_EXISTS, FAIL, "destination object already exists")
+
+ /* Set up opened group location to fill in */
+ src_loc.oloc = &src_oloc;
+ src_loc.path = &src_path;
+ H5G_loc_reset(&src_loc);
+
+ /* Find the source object to copy */
+ if(H5G_loc_find(&loc, src_name, &src_loc/*out*/, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found")
+ loc_found = TRUE;
+
+ /* Open source object's object header */
+ if(H5O_open(&src_oloc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+ obj_open = TRUE;
+
+ /* Get correct property lists */
+ if(H5P_DEFAULT == lcpl_id) {
+ if((lcpl_id = H5L_get_default_lcpl()) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to get default lcpl")
+ } /* end if */
+ else
+ if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list")
+
+ /* Get object copy property list */
+ if(H5P_DEFAULT == ocpypl_id)
+ ocpypl_id = H5P_OBJECT_COPY_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(ocpypl_id, H5P_OBJECT_COPY))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not object copy property list")
+
+ /* Do the actual copying of the object */
+ if(H5O_copy_obj(&src_loc, &dst_loc, dst_name, ocpypl_id, lcpl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+done:
+ if(loc_found && H5G_loc_free(&src_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
+ if(obj_open && H5O_close(&src_oloc, NULL) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Ocopy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_header_real
+ *
+ * Purpose: Copy header object from one location to another using
+ * pre-copy, copy, and post-copy callbacks for each message
+ * type.
+ *
+ * The source header object is compressed into a single chunk
+ * (since we know how big it is) and any continuation messages
+ * are converted into NULL messages.
+ *
+ * By default, NULL messages are not copied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * May 30, 2005
+ *
+ * Modifications:
+ * Vailin Choi; Feb 2012
+ * Bug fix for HDFFV-7853
+ * When the object is opened, call the object's flush class action
+ * to ensure that cached data is flushed so that H5Ocopy will get
+ * the correct data.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
+ hid_t dxpl_id, H5O_copy_t *cpy_info, H5O_type_t *obj_type,
+ void **udata /*out*/)
+{
+ H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */
+ H5O_t *oh_src = NULL; /* Object header for source object */
+ H5O_t *oh_dst = NULL; /* Object header for destination object */
+ unsigned mesgno = 0;
+ haddr_t addr_new = HADDR_UNDEF;
+ hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */
+ hbool_t inserted = FALSE; /* Whether the destination object header has been inserted into the cache */
+ size_t null_msgs; /* Number of NULL messages found in each loop */
+ size_t orig_dst_msgs; /* Original # of messages in dest. object */
+ H5O_mesg_t *mesg_src; /* Message in source object header */
+ H5O_mesg_t *mesg_dst; /* Message in destination object header */
+ const H5O_msg_class_t *copy_type; /* Type of message to use for copying */
+ const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */
+ void *cpy_udata = NULL; /* User data for passing to message callbacks */
+ uint64_t dst_oh_size; /* Total size of the destination OH */
+ size_t dst_oh_null; /* Size of the null message to add to destination OH */
+ size_t dst_oh_gap; /* Size of the gap in chunk #0 of destination OH */
+ uint8_t *current_pos; /* Current position in destination image */
+ size_t msghdr_size;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, oloc_src->addr, FAIL)
+
+ HDassert(oloc_src);
+ HDassert(oloc_src->file);
+ HDassert(H5F_addr_defined(oloc_src->addr));
+ HDassert(oloc_dst->file);
+ HDassert(cpy_info);
+
+ /* Get pointer to object class for this object */
+ if(NULL == (obj_class = H5O_obj_class(oloc_src, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+ /* Check if the object at the address is already open in the file */
+ if(H5FO_opened(oloc_src->file, oloc_src->addr) != NULL) {
+ H5G_loc_t tmp_loc; /* Location of object */
+ H5O_loc_t tmp_oloc; /* Location of object */
+ H5G_name_t tmp_path; /* Object's path */
+ void *obj_ptr = NULL; /* Object pointer */
+ hid_t tmp_id = -1; /* Object ID */
+
+ tmp_loc.oloc = &tmp_oloc;
+ tmp_loc.path = &tmp_path;
+ tmp_oloc.file = oloc_src->file;
+ tmp_oloc.addr = oloc_src->addr;
+ tmp_oloc.holding_file = FALSE;
+ H5G_name_reset(tmp_loc.path);
+
+ /* Get a temporary ID */
+ if((tmp_id = obj_class->open(&tmp_loc, H5P_DEFAULT, dxpl_id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to open object")
+
+ /* Get object pointer */
+ obj_ptr = H5I_object(tmp_id);
+
+ /* Flush the object */
+ if(obj_class->flush && obj_class->flush(obj_ptr, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
+
+ /* Release the temporary ID */
+ if(tmp_id != -1 && H5I_dec_app_ref(tmp_id))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close temporary ID")
+ } /* end if */
+
+ /* Get source object header */
+ if(NULL == (oh_src = H5O_protect(oloc_src, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Retrieve user data for particular type of object to copy */
+ if(obj_class->get_copy_file_udata && (NULL == (cpy_udata = (obj_class->get_copy_file_udata)())))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data")
+
+ /* If we are merging committed datatypes, check for a match in the destination
+ * file now */
+ if(cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
+ unsigned long fileno_src; /* fileno for source file */
+ unsigned long fileno_dst; /* fileno for destination file */
+ htri_t merge; /* Whether we found a match in the destination file */
+
+ /* Check if the source and dest file are the same. If so, just return
+ * the source object address */
+ H5F_GET_FILENO(oloc_src->file, fileno_src);
+ H5F_GET_FILENO(oloc_dst->file, fileno_dst);
+ if(fileno_src == fileno_dst) {
+ merge = TRUE;
+ oloc_dst->addr = oloc_src->addr;
+ } /* end if */
+ else
+ /* Search for a matching committed datatype, building the list if
+ * necessary */
+ if((merge = H5O_copy_search_comm_dt(oloc_src->file, oh_src, oloc_dst, dxpl_id, cpy_info)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't search for matching committed datatype")
+
+ if(merge) {
+ /* Found a match, add to skip list and exit */
+ /* Allocate space for the address mapping of the object copied */
+ if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Insert the address mapping for the found object into the copied
+ * list */
+ addr_map->src_obj_pos.fileno = fileno_src;
+ addr_map->src_obj_pos.addr = oloc_src->addr;
+ addr_map->dst_addr = oloc_dst->addr;
+ addr_map->is_locked = TRUE; /* We've locked the object currently */
+ addr_map->inc_ref_count = 0; /* Start with no additional ref counts to add */
+ addr_map->obj_class = obj_class;
+ addr_map->udata = cpy_udata;
+
+ /* Insert into skip list */
+ if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
+ addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+ } /* end if */
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+ } /* end if */
+
+ /* Flush any dirty messages in source object header to update the header chunks */
+ if(H5O_flush_msgs(oloc_src->file, oh_src) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages")
+
+ /* Allocate the destination object header and fill in header fields */
+ if(NULL == (oh_dst = H5FL_CALLOC(H5O_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize header information */
+ oh_dst->version = oh_src->version;
+ oh_dst->flags = oh_src->flags;
+ oh_dst->link_msgs_seen = oh_src->link_msgs_seen;
+ oh_dst->attr_msgs_seen = oh_src->attr_msgs_seen;
+ oh_dst->sizeof_size = H5F_SIZEOF_SIZE(oloc_dst->file);
+ oh_dst->sizeof_addr = H5F_SIZEOF_ADDR(oloc_dst->file);
+ oh_dst->swmr_write = !!(H5F_INTENT(oloc_dst->file) & H5F_ACC_SWMR_WRITE);
+
+ /* Copy time fields */
+ oh_dst->atime = oh_src->atime;
+ oh_dst->mtime = oh_src->mtime;
+ oh_dst->ctime = oh_src->ctime;
+ oh_dst->btime = oh_src->btime;
+
+ /* Copy attribute storage information */
+ oh_dst->max_compact = oh_src->max_compact;
+ oh_dst->min_dense = oh_src->min_dense;
+
+ /* Create object header proxy if doing SWMR writes */
+ if(oh_dst->swmr_write) {
+ /* Create virtual entry, for use as proxy */
+ if(NULL == (oh_dst->proxy = H5AC_proxy_entry_create()))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy")
+ } /* end if */
+ else
+ oh_dst->proxy = NULL;
+
+ /* Initialize size of chunk array. Start off with zero chunks so this field
+ * is consistent with the current state of the chunk array. This is
+ * important if an error occurs.
+ */
+ oh_dst->alloc_nchunks = oh_dst->nchunks = 0;
+
+ /* Allocate memory for the chunk array - always start with 1 chunk */
+ if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Update number of allocated chunks. There are still no chunks used. */
+ oh_dst->alloc_nchunks = 1;
+
+ /* Allocate memory for "deleted" array. This array marks the message in
+ * the source that shouldn't be copied to the destination.
+ */
+ if(NULL == (deleted = (hbool_t *)H5MM_malloc(sizeof(hbool_t) * oh_src->nmesgs)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDmemset(deleted, FALSE, sizeof(hbool_t) * oh_src->nmesgs);
+
+ /* "pre copy" pass over messages, to gather information for actual message copy operation
+ * (for messages which depend on information from other messages)
+ * Keep track of how many NULL or deleted messages we find (or create)
+ */
+ null_msgs = 0;
+ for(mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) {
+ /* Set up convenience variables */
+ mesg_src = &(oh_src->mesg[mesgno]);
+
+ /* Sanity check */
+ HDassert(!mesg_src->dirty); /* Should be cleared by earlier call to flush messages */
+
+ /* Get message class to operate on */
+ copy_type = mesg_src->type;
+
+ /* Check for continuation message; these are converted to NULL
+ * messages because the destination OH will have only one chunk
+ */
+ if(H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) {
+ deleted[mesgno] = TRUE;
+ ++null_msgs;
+ copy_type = H5O_MSG_NULL;
+ } /* end if */
+ HDassert(copy_type);
+
+ if(copy_type->pre_copy_file) {
+ /* Decode the message if necessary. */
+ H5O_LOAD_NATIVE(oloc_src->file, dxpl_id, 0, oh_src, mesg_src, FAIL)
+
+ /* Perform "pre copy" operation on message */
+ if((copy_type->pre_copy_file)(oloc_src->file, mesg_src->native,
+ &(deleted[mesgno]), cpy_info, cpy_udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'pre copy' operation on message")
+
+ /* Check if the message should be deleted in the destination */
+ if(deleted[mesgno])
+ /* Mark message as deleted */
+ ++null_msgs;
+ } /* end if(copy_type->pre_copy_file) */
+ } /* end for */
+
+ /* Initialize size of message list. It may or may not include the NULL messages
+ * detected above.
+ */
+ if(cpy_info->preserve_null)
+ oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs;
+ else
+ oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs);
+
+ /* Allocate memory for destination message array */
+ if(oh_dst->alloc_nmesgs > 0)
+ if(NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* "copy" pass over messages, to perform main message copying */
+ null_msgs = 0;
+ for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
+ /* Skip any deleted or NULL messages in the source unless the
+ * preserve_null flag is set
+ */
+ if(FALSE == cpy_info->preserve_null) {
+ while(deleted[mesgno + null_msgs]) {
+ ++null_msgs;
+ HDassert(mesgno + null_msgs < oh_src->nmesgs);
+ } /* end while */
+ } /* end if */
+
+ /* Set up convenience variables */
+ mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
+ mesg_dst = &(oh_dst->mesg[mesgno]);
+
+ /* Initialize non-zero components of destination message */
+ mesg_dst->crt_idx = mesg_src->crt_idx;
+ mesg_dst->flags = mesg_src->flags;
+ mesg_dst->raw_size = mesg_src->raw_size;
+ mesg_dst->type = mesg_src->type;
+
+ /* If we're preserving deleted messages, set their types to 'NULL'
+ * in the destination.
+ */
+ if(cpy_info->preserve_null && deleted[mesgno]) {
+ mesg_dst->type = H5O_MSG_NULL;
+ mesg_dst->flags = 0;
+ mesg_dst->dirty = TRUE;
+ } /* end if */
+
+ /* Check for message class to operate on */
+ /* (Use destination message, in case the message has been removed (i.e
+ * converted to a nil message) in the destination -QAK)
+ */
+ copy_type = mesg_dst->type;
+ HDassert(copy_type);
+
+ /* copy this message into destination file */
+ if(copy_type->copy_file) {
+ hbool_t recompute_size; /* Whether copy_file callback created a shared message */
+ unsigned mesg_flags; /* Message flags */
+
+ /* Decode the message if necessary. */
+ H5O_LOAD_NATIVE(oloc_src->file, dxpl_id, 0, oh_src, mesg_src, FAIL)
+
+ /* Get destination message flags, and unset shared and shareable
+ * flags. mesg_dst->flags will contain the original flags for now.
+ */
+ mesg_flags = (unsigned)mesg_dst->flags & ~H5O_MSG_FLAG_SHARED
+ & ~H5O_MSG_FLAG_SHAREABLE;
+
+ /* Copy the source message */
+ recompute_size = FALSE;
+ if((mesg_dst->native = H5O_msg_copy_file(copy_type, oloc_src->file,
+ mesg_src->native, oloc_dst->file, &recompute_size,
+ &mesg_flags, cpy_info, cpy_udata, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message")
+
+ /* Check if the sharing state changed, and recompute the size if so
+ */
+ if(!(mesg_flags & H5O_MSG_FLAG_SHARED)
+ != !(mesg_dst->flags & H5O_MSG_FLAG_SHARED))
+ recompute_size = TRUE;
+
+ /* Set destination message flags */
+ mesg_dst->flags = (uint8_t)mesg_flags;
+
+ /* Recompute message's size */
+ /* (its sharing status or one of its components (for attributes)
+ * could have changed)
+ */
+ if(recompute_size)
+ mesg_dst->raw_size = H5O_ALIGN_OH(oh_dst,
+ H5O_msg_raw_size(oloc_dst->file, mesg_dst->type->id, FALSE, mesg_dst->native));
+
+ /* Mark the message in the destination as dirty, so it'll get encoded when the object header is flushed */
+ mesg_dst->dirty = TRUE;
+ } /* end if (mesg_src->type->copy_file) */
+ } /* end of mesgno loop */
+
+
+ /* Allocate the destination header and copy any messages that didn't have
+ * copy callbacks. They get copied directly from the source image to the
+ * destination image.
+ */
+
+ /* Calculate how big the destination object header will be on disk.
+ * This isn't necessarily the same size as the original.
+ */
+
+ /* Compute space for messages. */
+ dst_oh_size = 0;
+ for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
+ dst_oh_size += (uint64_t)H5O_SIZEOF_MSGHDR_OH(oh_dst);
+ dst_oh_size += oh_dst->mesg[mesgno].raw_size;
+ } /* end for */
+
+ /* Check if we need to determine correct value for chunk #0 size bits */
+ if(oh_dst->version > H5O_VERSION_1) {
+ /* Reset destination object header's "chunk 0 size" flags */
+ oh_dst->flags = (uint8_t)(oh_dst->flags & ~H5O_HDR_CHUNK0_SIZE);
+
+ /* Determine correct value for chunk #0 size bits */
+ if(dst_oh_size > 4294967295)
+ oh_dst->flags |= H5O_HDR_CHUNK0_8;
+ else if(dst_oh_size > 65535)
+ oh_dst->flags |= H5O_HDR_CHUNK0_4;
+ else if(dst_oh_size > 255)
+ oh_dst->flags |= H5O_HDR_CHUNK0_2;
+ } /* end if */
+
+ /* Check if the chunk's data portion is too small */
+ dst_oh_gap = dst_oh_null = 0;
+ if(dst_oh_size < H5O_MIN_SIZE) {
+ size_t delta = (size_t)(H5O_MIN_SIZE - dst_oh_size); /* Delta in chunk size needed */
+
+ /* Sanity check */
+ HDassert((oh_dst->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1);
+
+ /* Determine whether to create gap or NULL message */
+ if(delta < H5O_SIZEOF_MSGHDR_OH(oh_dst))
+ dst_oh_gap = delta;
+ else
+ dst_oh_null = delta;
+
+ /* Increase destination object header size */
+ dst_oh_size += delta;
+
+ /* Sanity check */
+ HDassert(dst_oh_size <= 255);
+ } /* end if */
+
+ /* Add in destination's object header size now */
+ dst_oh_size += (uint64_t)H5O_SIZEOF_HDR(oh_dst);
+
+ /* Allocate space for chunk in destination file */
+ if(HADDR_UNDEF == (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, dxpl_id, (hsize_t)dst_oh_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header")
+ addr_new = oh_dst->chunk[0].addr;
+
+ /* Create memory image for the new chunk */
+ /* Note: we use calloc() instead of malloc() here because older versions of
+ * some messages don't initialize "unused" bytes and because we want to
+ * write out the same version of the object header and older versions of
+ * object headers aligned messages. In both those situations, it's
+ * complex and error-prone to determine all the proper ways/places to
+ * clear to zero bytes, so we just set the buffer to zero's here.
+ * (QAK - 2010/08/17)
+ */
+ if(NULL == (oh_dst->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, (size_t)dst_oh_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Set dest. chunk information */
+ oh_dst->chunk[0].size = (size_t)dst_oh_size;
+ oh_dst->chunk[0].gap = dst_oh_gap;
+
+ /* Update size of chunk array. The destination now has one chunk. */
+ oh_dst->nchunks = 1;
+
+ /* Set up raw pointers and copy messages that didn't need special
+ * treatment. This has to happen after the destination header has been
+ * allocated.
+ */
+ HDassert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst));
+ msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_dst);
+
+ current_pos = oh_dst->chunk[0].image;
+
+ /* Write the magic number for versions > 1 and skip the rest of the
+ * header. This will be written when the header is flushed to disk.
+ */
+ if(oh_dst->version > H5O_VERSION_1)
+ HDmemcpy(current_pos, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ current_pos += H5O_SIZEOF_HDR(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst);
+
+ /* Loop through destination messages, updating their "raw" info */
+ null_msgs = 0;
+ for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
+ /* Skip any deleted or NULL messages in the source unless the
+ * preserve_null flag is set.
+ */
+ if(FALSE == cpy_info->preserve_null) {
+ while(deleted[mesgno + null_msgs]) {
+ ++null_msgs;
+ HDassert(mesgno + null_msgs < oh_src->nmesgs);
+ } /* end while */
+ } /* end if */
+
+ /* Set up convenience variables */
+ mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
+ mesg_dst = &(oh_dst->mesg[mesgno]);
+
+ /* Copy each message that wasn't dirtied above */
+ if(!mesg_dst->dirty)
+ /* Copy the message header plus the message's raw data. */
+ HDmemcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size);
+
+ /* Set message's raw pointer to destination chunk's new "image" */
+ mesg_dst->raw = current_pos + msghdr_size;
+
+ /* Move to location where next message should go */
+ current_pos += mesg_dst->raw_size + msghdr_size;
+ } /* end for */
+
+ /* Save this in case more messages are added during NULL message checking */
+ orig_dst_msgs = oh_dst->nmesgs;
+
+ /* Check if we need to add a NULL message to this header */
+ if(dst_oh_null > 0) {
+ size_t null_idx; /* Index of new NULL message */
+
+ /* Make sure we have enough space for new NULL message */
+ if(oh_dst->nmesgs + 1 > oh_dst->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh_dst, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* Create null message for [rest of] space in new chunk */
+ /* (account for chunk's magic # & checksum) */
+ null_idx = oh_dst->nmesgs++;
+ oh_dst->mesg[null_idx].type = H5O_MSG_NULL;
+ oh_dst->mesg[null_idx].dirty = TRUE;
+ oh_dst->mesg[null_idx].native = NULL;
+ oh_dst->mesg[null_idx].raw = current_pos + msghdr_size;
+ oh_dst->mesg[null_idx].raw_size = dst_oh_null - msghdr_size;
+ oh_dst->mesg[null_idx].chunkno = 0;
+ } /* end if */
+
+ /* Make sure we filled the chunk, except for room at the end for a checksum */
+ HDassert(current_pos + dst_oh_gap + dst_oh_null + H5O_SIZEOF_CHKSUM_OH(oh_dst) == (size_t)dst_oh_size + oh_dst->chunk[0].image);
+
+ /* Set the dest. object location to the first chunk address */
+ HDassert(H5F_addr_defined(addr_new));
+ oloc_dst->addr = addr_new;
+
+
+ /* If we are merging committed datatypes and this is a committed datatype, insert
+ * the copied datatype into the list of committed datatypes in the target file.
+ */
+ if(cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE)
+ if(H5O_copy_insert_comm_dt(oloc_src->file, oh_src, oloc_dst, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't insert committed datatype into destination list")
+
+ /* Allocate space for the address mapping of the object copied */
+ if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Insert the address mapping for the new object into the copied list */
+ /* (Do this here, because "post copy" possibly checks it) */
+ H5F_GET_FILENO(oloc_src->file, addr_map->src_obj_pos.fileno);
+ addr_map->src_obj_pos.addr = oloc_src->addr;
+ addr_map->dst_addr = oloc_dst->addr;
+ addr_map->is_locked = TRUE; /* We've locked the object currently */
+ addr_map->inc_ref_count = 0; /* Start with no additional ref counts to add */
+ addr_map->obj_class = obj_class;
+ addr_map->udata = cpy_udata;
+
+ /* Insert into skip list */
+ if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
+ addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+ } /* end if */
+
+ /* "post copy" loop over messages, to fix up any messages which require a complete
+ * object header for destination object
+ */
+ null_msgs = 0;
+ for(mesgno = 0; mesgno < orig_dst_msgs; mesgno++) {
+ /* Skip any deleted or NULL messages in the source unless the
+ * preserve_null flag is set
+ */
+ if(FALSE == cpy_info->preserve_null) {
+ while(deleted[mesgno + null_msgs]) {
+ ++null_msgs;
+ HDassert(mesgno + null_msgs < oh_src->nmesgs);
+ } /* end while */
+ } /* end if */
+
+ /* Set up convenience variables */
+ mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
+ mesg_dst = &(oh_dst->mesg[mesgno]);
+
+ /* Check for message class to operate on */
+ /* (Use destination message, in case the message has been removed (i.e
+ * converted to a nil message) in the destination -QAK)
+ */
+ copy_type = mesg_dst->type;
+ HDassert(copy_type);
+
+ if(copy_type->post_copy_file && mesg_src->native) {
+ unsigned mesg_flags; /* Message flags */
+
+ /* Sanity check destination message */
+ HDassert(mesg_dst->type == mesg_src->type);
+ HDassert(mesg_dst->native);
+
+ /* Get destination message flags. mesg_dst->flags will contain the
+ * original flags for now. */
+ mesg_flags = (unsigned)mesg_dst->flags;
+
+ /* the object header is needed in the post copy for shared message */
+ cpy_info->oh_dst = oh_dst;
+
+ /* Perform "post copy" operation on message */
+ if((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst,
+ mesg_dst->native, &mesg_flags, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'post copy' operation on message")
+
+ /* Verify that the flags did not change */
+ HDassert(mesg_flags == (unsigned) mesg_dst->flags);
+ } /* end if */
+ } /* end for */
+
+ /* Indicate that the destination address will no longer be locked */
+ addr_map->is_locked = FALSE;
+
+ /* Increment object header's reference count, if any descendents have created links to this object */
+ if(addr_map->inc_ref_count) {
+ H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, unsigned);
+ oh_dst->nlink += (unsigned)addr_map->inc_ref_count;
+ } /* end if */
+
+ /* Retag all copied metadata to apply the destination object's tag */
+ if(H5AC_retag_copied_metadata(oloc_dst->file, oloc_dst->addr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to re-tag metadata entries")
+
+ /* Set metadata tag for destination object's object header */
+ H5_BEGIN_TAG(dxpl_id, oloc_dst->addr, FAIL);
+
+ /* Insert destination object header in cache */
+ if(H5AC_insert_entry(oloc_dst->file, dxpl_id, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header")
+ oh_dst = NULL;
+ inserted = TRUE;
+
+ /* Reset metadat tag */
+ H5_END_TAG(FAIL);
+
+ /* Set obj_type and udata, if requested */
+ if(obj_type) {
+ HDassert(udata);
+ *obj_type = obj_class->type;
+ *udata = cpy_udata;
+ } /* end if */
+
+done:
+ /* Free deleted array */
+ if(deleted)
+ H5MM_free(deleted);
+
+ /* Release pointer to source object header and its derived objects */
+ if(oh_src && H5O_unprotect(oloc_src, dxpl_id, oh_src, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ /* Free destination object header on failure */
+ if(ret_value < 0 && oh_dst && !inserted) {
+ if(H5O__free(oh_dst) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
+ if(H5O_loc_reset(oloc_dst) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_copy_header_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_header_map
+ *
+ * Purpose: Copy header object from one location to another, detecting
+ * already mapped objects, etc.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 1, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
+ hid_t dxpl_id, H5O_copy_t *cpy_info, hbool_t inc_depth,
+ H5O_type_t *obj_type, void **udata /*out*/)
+{
+ H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */
+ H5_obj_t src_obj_pos; /* Position of source object */
+ hbool_t inc_link; /* Whether to increment the link count for the object */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(oloc_src);
+ HDassert(oloc_src->file);
+ HDassert(oloc_dst);
+ HDassert(oloc_dst->file);
+ HDassert(cpy_info);
+
+ /* Create object "position" struct */
+ H5F_GET_FILENO(oloc_src->file, src_obj_pos.fileno);
+ src_obj_pos.addr = oloc_src->addr;
+
+ /* Search for the object in the skip list of copied objects */
+ addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list,
+ &src_obj_pos);
+
+ /* Check if address is already in list of objects copied */
+ if(addr_map == NULL) {
+ /* Copy object for the first time */
+
+ /* Check for incrementing the depth of copy */
+ /* (Can't do this for all copies, since committed datatypes should always be copied) */
+ if(inc_depth)
+ cpy_info->curr_depth++;
+
+ /* Copy object referred to */
+ if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, cpy_info, obj_type,
+ udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Check for incrementing the depth of copy */
+ if(inc_depth)
+ cpy_info->curr_depth--;
+
+ /* When an object is copied for the first time, increment it's link */
+ inc_link = TRUE;
+
+ /* indicate that a new object is created */
+ ret_value++;
+ } /* end if */
+ else {
+ /* Object has already been copied, set its address in destination file */
+ oloc_dst->addr = addr_map->dst_addr;
+
+ /* Return saved obj_type and udata, if requested */
+ if(obj_type) {
+ HDassert(udata);
+ *obj_type = addr_map->obj_class->type;
+ *udata = addr_map->udata;
+ } /* end if */
+
+ /* If the object is locked currently (because we are copying a group
+ * hierarchy and this is a link to a group higher in the hierarchy),
+ * increment it's deferred reference count instead of incrementing the
+ * reference count now.
+ */
+ if(addr_map->is_locked) {
+ addr_map->inc_ref_count++;
+ inc_link = FALSE;
+ } /* end if */
+ else
+ inc_link = TRUE;
+ } /* end else */
+
+ /* Increment destination object's link count, if allowed */
+ if(inc_link)
+ if(H5O_link(oloc_dst, 1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to increment object link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_header_map() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_copy_free_addrmap_cb
+ PURPOSE
+ Internal routine to free address maps from the skip list for copying objects
+ USAGE
+ herr_t H5O_copy_free_addrmap_cb(item, key, op_data)
+ void *item; IN/OUT: Pointer to addr
+ void *key; IN/OUT: (unused)
+ void *op_data; IN: (unused)
+ RETURNS
+ Returns zero on success, negative on failure.
+ DESCRIPTION
+ Releases the memory for the address.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_copy_free_addrmap_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *op_data)
+{
+ H5O_addr_map_t *item = (H5O_addr_map_t *)_item;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(item);
+
+ /* Release user data for particular type of object */
+ if(item->udata) {
+ HDassert(item->obj_class);
+ HDassert(item->obj_class->free_copy_file_udata);
+ (item->obj_class->free_copy_file_udata)(item->udata);
+ } /* end if */
+
+ /* Release the item */
+ item = H5FL_FREE(H5O_addr_map_t, item);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5O_copy_free_addrmap_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_header
+ *
+ * Purpose: copy header object from one location to another.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * May 30, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
+ hid_t dxpl_id, hid_t ocpypl_id)
+{
+ H5O_copy_t cpy_info; /* Information for copying object */
+ H5P_genplist_t *ocpy_plist; /* Object copy property list created */
+ H5O_copy_dtype_merge_list_t *dt_list = NULL; /* List of datatype merge suggestions */
+ H5O_mcdt_cb_info_t cb_info; /* Callback info struct */
+ unsigned cpy_option = 0; /* Copy options */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(oloc_src);
+ HDassert(oloc_src->file);
+ HDassert(H5F_addr_defined(oloc_src->addr));
+ HDassert(oloc_dst->file);
+
+ /* Intialize copy info before errors can be thrown */
+ HDmemset(&cpy_info, 0, sizeof(H5O_copy_t));
+
+ /* Get the copy property list */
+ if(NULL == (ocpy_plist = (H5P_genplist_t *)H5I_object(ocpypl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Retrieve the copy parameters */
+ if(H5P_get(ocpy_plist, H5O_CPY_OPTION_NAME, &cpy_option) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object copy flag")
+
+ /* Retrieve the marge committed datatype list */
+ if(H5P_peek(ocpy_plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &dt_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get merge committed datatype list")
+
+ /* Get callback info */
+ if(H5P_get(ocpy_plist, H5O_CPY_MCDT_SEARCH_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info")
+
+ /* Convert copy flags into copy struct */
+ if((cpy_option & H5O_COPY_SHALLOW_HIERARCHY_FLAG) > 0) {
+ cpy_info.copy_shallow = TRUE;
+ cpy_info.max_depth = 1;
+ } /* end if */
+ else
+ cpy_info.max_depth = -1; /* Current default is for full, recursive hier. copy */
+ cpy_info.curr_depth = 0;
+ if((cpy_option & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
+ cpy_info.expand_soft_link = TRUE;
+ if((cpy_option & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0)
+ cpy_info.expand_ext_link = TRUE;
+ if((cpy_option & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0)
+ cpy_info.expand_ref = TRUE;
+ if((cpy_option & H5O_COPY_WITHOUT_ATTR_FLAG) > 0)
+ cpy_info.copy_without_attr = TRUE;
+ if((cpy_option & H5O_COPY_PRESERVE_NULL_FLAG) > 0)
+ cpy_info.preserve_null = TRUE;
+ if((cpy_option & H5O_COPY_MERGE_COMMITTED_DTYPE_FLAG) > 0)
+ cpy_info.merge_comm_dt = TRUE;
+
+ /* Add dt_list to copy struct */
+ cpy_info.dst_dt_suggestion_list = dt_list;
+
+ /* Add set callback information */
+ cpy_info.mcdt_cb = cb_info.func;
+ cpy_info.mcdt_ud = cb_info.user_data;
+
+ /* Create a skip list to keep track of which objects are copied */
+ if(NULL == (cpy_info.map_list = H5SL_create(H5SL_TYPE_OBJ, NULL)))
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list")
+
+ /* copy the object from the source file to the destination file */
+ if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, &cpy_info, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+done:
+ if(cpy_info.map_list)
+ H5SL_destroy(cpy_info.map_list, H5O_copy_free_addrmap_cb, NULL);
+ if(cpy_info.dst_dt_list)
+ H5SL_destroy(cpy_info.dst_dt_list, H5O_copy_free_comm_dt_cb, NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_header() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_obj
+ *
+ * Purpose: Copy an object to destination location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * June 4, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc, const char *dst_name,
+ hid_t ocpypl_id, hid_t lcpl_id, hid_t dxpl_id)
+{
+ H5G_name_t new_path; /* Copied object group hier. path */
+ H5O_loc_t new_oloc; /* Copied object object location */
+ H5G_loc_t new_loc; /* Group location of object copied */
+ H5F_t *cached_dst_file; /* Cached destination file */
+ hbool_t entry_inserted = FALSE; /* Flag to indicate that the new entry was inserted into a group */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(src_loc);
+ HDassert(src_loc->oloc->file);
+ HDassert(dst_loc);
+ HDassert(dst_loc->oloc->file);
+ HDassert(dst_name);
+
+ /* Set up copied object location to fill in */
+ new_loc.oloc = &new_oloc;
+ new_loc.path = &new_path;
+ H5G_loc_reset(&new_loc);
+ new_oloc.file = dst_loc->oloc->file;
+
+ /* Make a copy of the destination file, in case the original is changed by
+ * H5O_copy_header. If and when oloc's point to the shared file struct,
+ * this will no longer be necessary, so this code can be removed. */
+ cached_dst_file = dst_loc->oloc->file;
+
+ /* Copy the object from the source file to the destination file */
+ if(H5O_copy_header(src_loc->oloc, &new_oloc, dxpl_id, ocpypl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Patch dst_loc. Again, this can be removed once oloc's point to shared
+ * file structs. */
+ dst_loc->oloc->file = cached_dst_file;
+
+ /* Insert the new object in the destination file's group */
+ if(H5L_link(dst_loc, dst_name, &new_loc, lcpl_id, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link")
+ entry_inserted = TRUE;
+
+done:
+ /* Free the ID to name buffers */
+ if(entry_inserted)
+ H5G_loc_free(&new_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_obj() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_obj_by_ref
+ *
+ * Purpose: Copy the object pointed by _src_ref.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_obj_by_ref(H5O_loc_t *src_oloc, hid_t dxpl_id, H5O_loc_t *dst_oloc,
+ H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(src_oloc);
+ HDassert(dst_oloc);
+
+ /* Perform the copy, or look up existing copy */
+ if((ret_value = H5O_copy_header_map(src_oloc, dst_oloc, dxpl_id, cpy_info,
+ FALSE, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Check if a new valid object is copied to the destination */
+ if(H5F_addr_defined(dst_oloc->addr) && (ret_value > SUCCEED)) {
+ char tmp_obj_name[80];
+ H5G_name_t new_path;
+ H5O_loc_t new_oloc;
+ H5G_loc_t new_loc;
+
+ /* Set up group location for new object */
+ new_loc.oloc = &new_oloc;
+ new_loc.path = &new_path;
+ H5G_loc_reset(&new_loc);
+ new_oloc.file = dst_oloc->file;
+ new_oloc.addr = dst_oloc->addr;
+
+ /* Pick a default name for the new object */
+ HDsnprintf(tmp_obj_name, sizeof(tmp_obj_name), "~obj_pointed_by_%llu", (unsigned long long)dst_oloc->addr);
+
+ /* Create a link to the newly copied object */
+ /* Note: since H5O_copy_header_map actually copied the target object, it
+ * must exist either in cache or on disk, therefore it is is safe to not
+ * pass the obj_type and udata fields returned by H5O_copy_header_map.
+ * This could be changed in the future to slightly improve performance
+ * --NAF */
+ if(H5L_link(dst_root_loc, tmp_obj_name, &new_loc, H5P_DEFAULT, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link")
+
+ H5G_loc_free(&new_loc);
+ } /* if (H5F_addr_defined(dst_oloc.addr)) */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_obj_by_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_expand_ref
+ *
+ * Purpose: Copy the object pointed by _src_ref.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * Aug 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_copy_expand_ref(H5F_t *file_src, void *_src_ref, hid_t dxpl_id,
+ H5F_t *file_dst, void *_dst_ref, size_t ref_count, H5R_type_t ref_type,
+ H5O_copy_t *cpy_info)
+{
+ H5O_loc_t dst_oloc; /* Copied object object location */
+ H5O_loc_t src_oloc; /* Temporary object location for source object */
+ H5G_loc_t dst_root_loc; /* The location of root group of the destination file */
+ const uint8_t *q; /* Pointer to source OID to store */
+ uint8_t *p; /* Pointer to destination OID to store */
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(file_src);
+ HDassert(_src_ref);
+ HDassert(file_dst);
+ HDassert(_dst_ref);
+ HDassert(ref_count);
+ HDassert(cpy_info);
+
+ /* Initialize object locations */
+ H5O_loc_reset(&src_oloc);
+ H5O_loc_reset(&dst_oloc);
+ src_oloc.file = file_src;
+ dst_oloc.file = file_dst;
+
+ /* Set up the root group in the destination file */
+ if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(file_dst))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(file_dst))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Copy object references */
+ if(H5R_OBJECT == ref_type) {
+ hobj_ref_t *src_ref = (hobj_ref_t *)_src_ref;
+ hobj_ref_t *dst_ref = (hobj_ref_t *)_dst_ref;
+
+ /* Making equivalent references in the destination file */
+ for(i = 0; i < ref_count; i++) {
+ /* Set up for the object copy for the reference */
+ q = (uint8_t *)(&src_ref[i]);
+ H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(src_oloc.addr));
+ dst_oloc.addr = HADDR_UNDEF;
+
+ /* Attempt to copy object from source to destination file */
+ if(src_oloc.addr != (haddr_t)0) {
+ if(H5O_copy_obj_by_ref(&src_oloc, dxpl_id, &dst_oloc, &dst_root_loc, cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+ } /* end if */
+ else
+ /* Set parameters so the reference is written as all 0's */
+ HDmemset(&dst_oloc.addr, 0, sizeof(dst_oloc.addr));
+
+ /* Set the object reference info for the destination file */
+ p = (uint8_t *)(&dst_ref[i]);
+ H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr);
+ } /* end for */
+ } /* end if */
+ /* Copy region references */
+ else if(H5R_DATASET_REGION == ref_type) {
+ hdset_reg_ref_t *src_ref = (hdset_reg_ref_t *)_src_ref;
+ hdset_reg_ref_t *dst_ref = (hdset_reg_ref_t *)_dst_ref;
+ uint8_t *buf = NULL; /* Buffer to store serialized selection in */
+ H5HG_t hobjid; /* Heap object ID */
+ size_t buf_size; /* Length of object in heap */
+
+ /* Making equivalent references in the destination file */
+ for(i = 0; i < ref_count; i++) {
+ /* Get the heap ID for the dataset region */
+ q = (const uint8_t *)(&src_ref[i]);
+ H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(hobjid.addr));
+ UINT32DECODE(q, hobjid.idx);
+
+ if(hobjid.addr != (haddr_t)0) {
+ /* Get the dataset region from the heap (allocate inside routine) */
+ if((buf = (uint8_t *)H5HG_read(src_oloc.file, dxpl_id, &hobjid, NULL, &buf_size)) == NULL)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information")
+
+ /* Get the object oid for the dataset */
+ q = (const uint8_t *)buf;
+ H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(src_oloc.addr));
+ dst_oloc.addr = HADDR_UNDEF;
+
+ /* copy the object pointed by the ref to the destination */
+ if(H5O_copy_obj_by_ref(&src_oloc, dxpl_id, &dst_oloc, &dst_root_loc, cpy_info) < 0) {
+ H5MM_xfree(buf);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+ } /* end if */
+
+ /* Serialize object ID */
+ p = (uint8_t *)buf;
+ H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr);
+
+ /* Save the serialized buffer to the destination */
+ if(H5HG_insert(dst_oloc.file, dxpl_id, buf_size, buf, &hobjid) < 0) {
+ H5MM_xfree(buf);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "Unable to write dataset region information")
+ } /* end if */
+ } /* end if */
+ else
+ /* Set parameters so the reference is written as all 0's */
+ HDmemset(&hobjid, 0, sizeof(hobjid));
+
+ /* Set the dataset region reference info for the destination file */
+ p = (uint8_t *)(&dst_ref[i]);
+ H5F_addr_encode(dst_oloc.file, &p, hobjid.addr);
+ UINT32ENCODE(p, hobjid.idx);
+
+ /* Free the buffer allocated in H5HG_read() */
+ H5MM_xfree(buf);
+ } /* end for */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_expand_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_free_comm_dt_cb
+ *
+ * Purpose: Frees the merge committed dt skip list key and object.
+ *
+ * Return: SUCCEED (never fails)
+ *
+ * Programmer: Neil Fortner
+ * Oct 6 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_free_comm_dt_cb(void *item, void *_key, void H5_ATTR_UNUSED *op_data)
+{
+ haddr_t *addr = (haddr_t *)item;
+ H5O_copy_search_comm_dt_key_t *key = (H5O_copy_search_comm_dt_key_t *)_key;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(addr);
+ HDassert(key);
+ HDassert(key->dt);
+
+ key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
+ key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
+ addr = H5FL_FREE(haddr_t, addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_copy_free_comm_dt_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_comm_dt_cmp
+ *
+ * Purpose: Skiplist callback used to compare 2 keys for the merge
+ * committed dt list. Mostly a wrapper for H5T_cmp.
+ *
+ * Return: 0 if key1 and key2 are equal.
+ * <0 if key1 is less than key2.
+ * >0 if key1 is greater than key2.
+ *
+ * Programmer: Neil Fortner
+ * Oct 6 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5O_copy_comm_dt_cmp(const void *_key1, const void *_key2)
+{
+ const H5O_copy_search_comm_dt_key_t *key1 = (const H5O_copy_search_comm_dt_key_t *)_key1;
+ const H5O_copy_search_comm_dt_key_t *key2 = (const H5O_copy_search_comm_dt_key_t *)_key2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check fileno. It is unlikely to be different so check if they are equal
+ * first so only one comparison needs to be made. */
+ if(key1->fileno != key2->fileno) {
+ if(key1->fileno < key2->fileno)
+ HGOTO_DONE(-1)
+ if(key1->fileno > key2->fileno)
+ HGOTO_DONE(1)
+ } /* end if */
+
+ ret_value = H5T_cmp(key1->dt, key2->dt, FALSE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_comm_dt_cmp */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_search_comm_dt_attr_cb
+ *
+ * Purpose: Callback for H5O_attr_iterate_real from
+ * H5O_copy_search_comm_dt_check. Checks if the attribute's
+ * datatype is committed. If it is, adds it to the merge
+ * committed dt skiplist present in udata if it does not match
+ * any already present.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Nov 3 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_search_comm_dt_attr_cb(const H5A_t *attr, void *_udata)
+{
+ H5O_copy_search_comm_dt_ud_t *udata = (H5O_copy_search_comm_dt_ud_t *)_udata;
+ H5T_t *dt = NULL; /* Datatype */
+ H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
+ haddr_t *addr = NULL; /* Destination address */
+ hbool_t obj_inserted = FALSE; /* Object inserted into skip list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(attr);
+ HDassert(udata);
+ HDassert(udata->dst_dt_list);
+ HDassert(H5F_addr_defined(udata->obj_oloc.addr));
+
+ /* Get attribute datatype */
+ if(NULL == (dt = H5A_type(attr)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get attribute datatype")
+
+ /* Check if the datatype is committed and search the skip list if so */
+ if(H5T_committed(dt)) {
+ /* Allocate key */
+ if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy datatype into key */
+ if(NULL == (key->dt = (H5T_t *)H5O_msg_copy(H5O_DTYPE_ID, dt, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy datatype message")
+
+ /* Get datatype object fileno */
+ H5F_GET_FILENO(udata->obj_oloc.file, key->fileno);
+
+ if(!H5SL_search(udata->dst_dt_list, key)) {
+ /* Allocate destination address */
+ if(NULL == (addr = H5FL_MALLOC(haddr_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Add the destination datatype to the skip list */
+ *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
+ if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+ obj_inserted = TRUE;
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(!obj_inserted) {
+ if(key) {
+ if(key->dt)
+ key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
+ key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
+ } /* end if */
+ if(addr) {
+ HDassert(ret_value < 0);
+ addr = H5FL_FREE(haddr_t, addr);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_search_comm_dt_attr_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_search_comm_dt_check
+ *
+ * Purpose: Check if the object at obj_oloc is or contains a reference
+ * to a committed datatype. If it does, adds it to the merge
+ * committed dt skiplist present in udata if it does not match
+ * any already present.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Nov 3 2011
+ *
+ * Modifications:
+ * Vailin Choi; August 2012
+ * Use H5O_obj_class to get object type instead of
+ * H5O_get_info(...TRUE....) saving time in traversing metadata.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_search_comm_dt_check(H5O_loc_t *obj_oloc,
+ H5O_copy_search_comm_dt_ud_t *udata)
+{
+ H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
+ haddr_t *addr = NULL; /* Destination address */
+ hbool_t obj_inserted = FALSE; /* Object inserted into skip list */
+ H5A_attr_iter_op_t attr_op; /* Attribute iteration operator */
+ const H5O_obj_class_t *obj_class = NULL; /* Type of object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(obj_oloc);
+ HDassert(udata);
+ HDassert(udata->dst_dt_list);
+ HDassert(udata->dst_root_loc);
+
+ /* Get pointer to object class for this object */
+ if((obj_class = H5O_obj_class(obj_oloc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+ /* Check if the object is a datatype, a dataset using a committed
+ * datatype, or contains an attribute using a committed datatype */
+ if(obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
+ /* Allocate key */
+ if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Read the destination datatype */
+ if(NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL, udata->dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
+
+ /* Get destination object fileno */
+ H5F_GET_FILENO(obj_oloc->file, key->fileno);
+
+ /* Check if the datatype is already present in the skip list */
+ if(!H5SL_search(udata->dst_dt_list, key)) {
+ /* Allocate destination address */
+ if(NULL == (addr = H5FL_MALLOC(haddr_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Add the destination datatype to the skip list */
+ *addr = obj_oloc->addr;
+ if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+ obj_inserted = TRUE;
+ } /* end if */
+ } /* end if */
+ else if(obj_class->type == H5O_TYPE_DATASET) {
+ /* Allocate key */
+ if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Read the destination datatype */
+ if(NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL, udata->dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
+
+ /* Check if the datatype is committed and search the skip list if so
+ */
+ if(H5T_committed(key->dt)) {
+ /* Get datatype object fileno */
+ H5F_GET_FILENO(obj_oloc->file, key->fileno);
+
+ if(!H5SL_search(udata->dst_dt_list, key)) {
+ /* Allocate destination address */
+ if(NULL == (addr = H5FL_MALLOC(haddr_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Add the destination datatype to the skip list */
+ *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
+ if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+ obj_inserted = TRUE;
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Search within attributes */
+ attr_op.op_type = H5A_ATTR_OP_LIB;
+ attr_op.u.lib_op = H5O_copy_search_comm_dt_attr_cb;
+ udata->obj_oloc.file = obj_oloc->file;
+ udata->obj_oloc.addr = obj_oloc->addr;
+ if(H5O_attr_iterate_real((hid_t)-1, obj_oloc, udata->dxpl_id, H5_INDEX_NAME,
+ H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op, udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "error iterating over attributes");
+
+done:
+ /* Release resources */
+ if(!obj_inserted) {
+ if(key) {
+ if(key->dt)
+ key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
+ key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
+ } /* end if */
+ if(addr) {
+ HDassert(ret_value < 0);
+ addr = H5FL_FREE(haddr_t, addr);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_search_comm_dt_check */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_search_comm_dt_cb
+ *
+ * Purpose: H5G_visit callback to add committed datatypes to the merge
+ * committed dt skiplist. Mostly a wrapper for
+ * H5O_copy_search_comm_dt_check.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Oct 6 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_search_comm_dt_cb(hid_t H5_ATTR_UNUSED group, const char *name,
+ const H5L_info_t *linfo, void *_udata)
+{
+ H5O_copy_search_comm_dt_ud_t *udata = (H5O_copy_search_comm_dt_ud_t *)_udata; /* Skip list of dtypes in dest file */
+ H5G_loc_t obj_loc; /* Location of object */
+ H5O_loc_t obj_oloc; /* Object's object location */
+ H5G_name_t obj_path; /* Object's group hier. path */
+ hbool_t obj_found = FALSE; /* Object at 'name' found */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(name);
+ HDassert(linfo);
+ HDassert(udata);
+ HDassert(udata->dst_dt_list);
+ HDassert(udata->dst_root_loc);
+
+ /* Check if this is a hard link */
+ if(linfo->type == H5L_TYPE_HARD) {
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object */
+ if(H5G_loc_find(udata->dst_root_loc, name, &obj_loc/*out*/, H5P_LINK_ACCESS_DEFAULT, udata->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+ obj_found = TRUE;
+
+ /* Check object and add to skip list if appropriate */
+ if(H5O_copy_search_comm_dt_check(&obj_oloc, udata) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "can't check object")
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(obj_found && H5G_loc_free(&obj_loc) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_search_comm_dt_cb */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_search_comm_dt
+ *
+ * Purpose: Checks if the committed datatype present in oh_src matches any
+ * in the destination file, building the destination file
+ * skiplist as necessary.
+ *
+ * Return: TRUE if a match is found in the destination file
+ * - oloc_dst will contain the address
+ * FALSE if a match is not found
+ * Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Sep 27 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src,
+ H5O_loc_t *oloc_dst/*in, out*/, hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
+ haddr_t *dst_addr; /* Destination datatype address */
+ H5G_loc_t dst_root_loc = {NULL, NULL}; /* Destination root group location */
+ H5O_copy_search_comm_dt_ud_t udata; /* Group iteration user data */
+ herr_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(oh_src);
+ HDassert(oloc_dst);
+ HDassert(oloc_dst->file);
+ HDassert(H5F_FILE_ID(oloc_dst->file) >= 0);
+ HDassert(cpy_info);
+
+ /* Allocate key */
+ if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Read the source datatype */
+ if(NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, dxpl_id, oh_src, H5O_DTYPE_ID, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
+
+ /* Get destination object fileno */
+ H5F_GET_FILENO(oloc_dst->file, key->fileno);
+
+ /* Check if the destination dtype list exists, create it if it does not */
+ if(!cpy_info->dst_dt_list) {
+ /* Create the skip list */
+ if(NULL == (cpy_info->dst_dt_list = H5SL_create(H5SL_TYPE_GENERIC, H5O_copy_comm_dt_cmp)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for committed datatypes")
+
+ /* Add suggested types to list, if they are present */
+ if(cpy_info->dst_dt_suggestion_list) {
+ H5O_copy_dtype_merge_list_t *suggestion = cpy_info->dst_dt_suggestion_list;
+ H5G_loc_t obj_loc; /* Location of object */
+ H5O_loc_t obj_oloc; /* Object's object location */
+ H5G_name_t obj_path; /* Object's group hier. path */
+
+ /* Set up the root group in the destination file */
+ if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+
+ /* Set up opened group location to fill in */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Build udata */
+ udata.dst_dt_list = cpy_info->dst_dt_list;
+ udata.dst_root_loc = &dst_root_loc;
+ udata.obj_oloc.file = NULL;
+ udata.obj_oloc.addr = HADDR_UNDEF;
+ udata.dxpl_id = dxpl_id;
+
+ /* Walk through the list of datatype suggestions */
+ while(suggestion) {
+ /* Find the object */
+ if(H5G_loc_find(&dst_root_loc, suggestion->path, &obj_loc/*out*/, H5P_LINK_ACCESS_DEFAULT, dxpl_id) < 0)
+ /* Ignore errors - i.e. suggestions not present in
+ * destination file */
+ H5E_clear_stack(NULL);
+ else
+ /* Check object and add to skip list if appropriate */
+ if(H5O_copy_search_comm_dt_check(&obj_oloc, &udata) < 0) {
+ if(H5G_loc_free(&obj_loc) < 0)
+ HERROR(H5E_OHDR, H5E_CANTRELEASE, "can't free location");
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't check object")
+ } /* end if */
+
+ /* Free location */
+ if(H5G_loc_free(&obj_loc) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location");
+
+ /* Advance the suggestion pointer */
+ suggestion = suggestion->next;
+ } /* end while */
+ } /* end if */
+ }
+
+ if(!cpy_info->dst_dt_list_complete) {
+ /* Search for the type in the destination file, and return its address
+ * if found, but only if the list is populated with and only with
+ * suggested types. We will search complete lists later. */
+ if(cpy_info->dst_dt_suggestion_list
+ && NULL != (dst_addr = (haddr_t *)H5SL_search(
+ cpy_info->dst_dt_list, key))) {
+ oloc_dst->addr = *dst_addr;
+ ret_value = TRUE;
+ } /* end if */
+ else {
+ H5O_mcdt_search_ret_t search_cb_ret = H5O_MCDT_SEARCH_CONT;
+
+ /* Make callback to see if we should search destination file */
+ if(cpy_info->mcdt_cb)
+ if((search_cb_ret = cpy_info->mcdt_cb(cpy_info->mcdt_ud)) == H5O_MCDT_SEARCH_ERROR)
+ HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "callback returned error")
+
+ if(search_cb_ret == H5O_MCDT_SEARCH_CONT) {
+ /* Build the complete dst dt list */
+ /* Set up the root group in the destination file, if necessary */
+ if(!dst_root_loc.oloc) {
+ HDassert(!dst_root_loc.path);
+ if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
+ if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
+ } /* end if */
+ else
+ HDassert(dst_root_loc.path);
+
+ /* Build udata. Note that this may be done twice in some cases, but
+ * it should be rare and should be cheaper on average than trying to
+ * keep track of whether it was done before. */
+ udata.dst_dt_list = cpy_info->dst_dt_list;
+ udata.dst_root_loc = &dst_root_loc;
+ udata.obj_oloc.file = NULL;
+ udata.obj_oloc.addr = HADDR_UNDEF;
+ udata.dxpl_id = dxpl_id;
+
+ /* Traverse the destination file, adding committed datatypes to the skip
+ * list */
+ if(H5G_visit(H5F_FILE_ID(oloc_dst->file), "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5O_copy_search_comm_dt_cb, &udata, H5P_LINK_ACCESS_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed")
+ cpy_info->dst_dt_list_complete = TRUE;
+ } /* end if */
+ else
+ if(search_cb_ret != H5O_MCDT_SEARCH_STOP)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown return value for callback")
+ } /* end if */
+ } /* end if */
+
+ /* Search for the type in the destination file, and return its address if
+ * found, but only if the list is complete */
+ if(cpy_info->dst_dt_list_complete) {
+ if(NULL != (dst_addr = (haddr_t *)H5SL_search(cpy_info->dst_dt_list, key))) {
+ oloc_dst->addr = *dst_addr;
+ ret_value = TRUE;
+ } /* end if */
+ } /* end if */
+
+done:
+ if(key) {
+ if(key->dt)
+ key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
+ key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_search_comm_dt */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_copy_insert_comm_dt
+ *
+ * Purpose: Insert the committed datatype at oloc_dst into the merge committed
+ * dt skiplist. The datatype must not be present already.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Oct 6 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst,
+ hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
+ haddr_t *addr = NULL; /* Destination object address */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(oh_src);
+ HDassert(oloc_dst);
+ HDassert(oloc_dst->file);
+ HDassert(oloc_dst->addr != HADDR_UNDEF);
+ HDassert(cpy_info);
+ HDassert(cpy_info->dst_dt_list);
+
+ /* Allocate key */
+ if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Read the datatype. Read from the source file because the destination
+ * object could be changed in the post-copy. */
+ if(NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, dxpl_id, oh_src, H5O_DTYPE_ID, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
+
+ /* Get destination object fileno */
+ H5F_GET_FILENO(oloc_dst->file, key->fileno);
+
+ /* Allocate destination address */
+ if(NULL == (addr = H5FL_MALLOC(haddr_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Add the destination datatype to the skip list */
+ *addr = oloc_dst->addr;
+ if(H5SL_insert(cpy_info->dst_dt_list, addr, key) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
+
+done:
+ if(ret_value < 0) {
+ if(key) {
+ if(key->dt)
+ key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
+ key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
+ } /* end if */
+ if(addr)
+ addr = H5FL_FREE(haddr_t, addr);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_copy_insert_comm_dt */
+
diff --git a/src/H5Odbg.c b/src/H5Odbg.c
new file mode 100644
index 0000000..483c5fd
--- /dev/null
+++ b/src/H5Odbg.c
@@ -0,0 +1,591 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Odbg.c
+ * Nov 17 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object header debugging routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Ppublic.h" /* Property Lists */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifdef H5O_DEBUG
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_assert
+ *
+ * Purpose: Sanity check the information for an object header data
+ * structure.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Oct 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_assert(const H5O_t *oh)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message to examine */
+ H5O_mesg_t *tmp_msg; /* Pointer to temporary message to examine */
+ unsigned cont_msgs_found = 0; /* # of continuation messages for object */
+ size_t meta_space; /* Size of header metadata */
+ size_t mesg_space; /* Size of message raw data */
+ size_t free_space; /* Size of free space in header */
+ size_t hdr_size; /* Size of header's chunks */
+ unsigned u, v; /* Local index variables */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Initialize the tracking variables */
+ hdr_size = 0;
+ meta_space = (size_t)H5O_SIZEOF_HDR(oh) + (size_t)(H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1));
+ mesg_space = 0;
+ free_space = 0;
+
+ /* Loop over all chunks in object header */
+ for(u = 0; u < oh->nchunks; u++) {
+ /* Accumulate the size of the header on header */
+ hdr_size += oh->chunk[u].size;
+
+ /* If the chunk has a gap, add it to the free space */
+ free_space += oh->chunk[u].gap;
+
+ /* Check for valid raw data image */
+ HDassert(oh->chunk[u].image);
+ HDassert(oh->chunk[u].size > (size_t)H5O_SIZEOF_CHKHDR_OH(oh));
+
+ /* All chunks must be allocated on disk */
+ HDassert(H5F_addr_defined(oh->chunk[u].addr));
+
+ /* Version specific checks */
+ if(oh->version > H5O_VERSION_1) {
+ /* Make certain that the magic number is correct for each chunk */
+ HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
+
+ /* Check for valid gap size */
+ HDassert(oh->chunk[u].gap < (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
+ } /* end if */
+ else
+ /* Gaps should never occur in version 1 of the format */
+ HDassert(oh->chunk[u].gap == 0);
+ } /* end for */
+
+ /* Check for correct chunk #0 size flags */
+ if(oh->version > H5O_VERSION_1) {
+ uint64_t chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
+
+ if(chunk0_size <= 255)
+ HDassert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1);
+ else if(chunk0_size <= 65535)
+ HDassert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_2);
+ else if(chunk0_size <= 4294967295)
+ HDassert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_4);
+ else
+ HDassert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_8);
+ } /* end if */
+
+ /* Loop over all messages in object header */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ uint8_t *curr_hdr; /* Start of current message header */
+ size_t curr_tot_size; /* Total size of current message (including header) */
+
+ curr_hdr = curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
+ curr_tot_size = curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Accumulate information, based on the type of message */
+ if(H5O_NULL_ID == curr_msg->type->id)
+ free_space += curr_tot_size;
+ else if(H5O_CONT_ID == curr_msg->type->id) {
+ H5O_cont_t *cont = (H5O_cont_t *)curr_msg->native;
+ hbool_t found_chunk = FALSE; /* Found a chunk that matches */
+
+ HDassert(cont);
+
+ /* Increment # of continuation messages found */
+ cont_msgs_found++;
+
+ /* Sanity check that every continuation message has a matching chunk */
+ /* (and only one) */
+ for(v = 0; v < oh->nchunks; v++) {
+ if(H5F_addr_eq(cont->addr, oh->chunk[v].addr) && cont->size == oh->chunk[v].size) {
+ HDassert(cont->chunkno == v);
+ HDassert(!found_chunk);
+ found_chunk = TRUE;
+ } /* end if */
+ } /* end for */
+ HDassert(found_chunk);
+
+ meta_space += curr_tot_size;
+ } /* end if */
+ else {
+ meta_space += (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+ mesg_space += curr_msg->raw_size;
+
+ /* Make sure the message has a native form if it is marked dirty */
+ HDassert(curr_msg->native || !curr_msg->dirty);
+ } /* end else */
+
+ /* Make certain that the message is in a valid chunk */
+ HDassert(curr_msg->chunkno < oh->nchunks);
+
+ /* Make certain null messages aren't in chunks with gaps */
+ if(H5O_NULL_ID == curr_msg->type->id)
+ HDassert(oh->chunk[curr_msg->chunkno].gap == 0);
+
+ /* Make certain that the message is completely in a chunk message area */
+ HDassert(curr_tot_size <= (oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap));
+ if(curr_msg->chunkno == 0)
+ HDassert(curr_hdr >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
+ else
+ HDassert(curr_hdr >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_CHKHDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
+ HDassert(curr_msg->raw + curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap));
+
+ /* Make certain that no other messages overlap this message */
+ for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) {
+ if(u != v)
+ HDassert(!((tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) >= curr_hdr
+ && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh))
+ < (curr_hdr + curr_tot_size)));
+ } /* end for */
+ } /* end for */
+
+ /* Sanity check that the # of cont. messages is correct for the # of chunks */
+ HDassert(oh->nchunks == (cont_msgs_found + 1));
+
+ /* Sanity check that all the bytes are accounted for */
+ HDassert(hdr_size == (free_space + meta_space + mesg_space));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_assert() */
+#endif /* H5O_DEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_debug_id
+ *
+ * Purpose: Act as a proxy for calling the 'debug' method for a
+ * particular class of object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 13 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->debug);
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Call the debug method in the class */
+ if((ret_value = (type->debug)(f, dxpl_id, mesg, stream, indent, fwidth)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_debug_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_debug_real
+ *
+ * Purpose: Prints debugging info about an object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ * Feb. 2009: Vailin Choi
+ * Fixed bug in the accumulation of chunk_total
+ * Used the appropriate flag when printing creation order tracked/indexed
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth)
+{
+ size_t mesg_total = 0, chunk_total = 0, gap_total = 0;
+ unsigned *sequence = NULL;
+ unsigned i; /* Local index variable */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* debug */
+ HDfprintf(stream, "%*sObject Header...\n", indent, "");
+
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Dirty:",
+ oh->cache_info.is_dirty);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Version:",
+ oh->version);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Header size (in bytes):",
+ (unsigned)H5O_SIZEOF_HDR(oh));
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of links:",
+ oh->nlink);
+
+ /* Extra information for later versions */
+ if(oh->version > H5O_VERSION_1) {
+ /* Display object's status flags */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Attribute creation order tracked:",
+ (oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? "Yes" : "No");
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Attribute creation order indexed:",
+ (oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? "Yes" : "No");
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Attribute storage phase change values:",
+ (oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) ? "Non-default" : "Default");
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Timestamps:",
+ (oh->flags & H5O_HDR_STORE_TIMES) ? "Enabled" : "Disabled");
+ if(oh->flags & ~H5O_HDR_ALL_FLAGS)
+ HDfprintf(stream, "*** UNKNOWN OBJECT HEADER STATUS FLAG: %02x!\n",
+ (unsigned)oh->flags);
+
+ /* Only dump times, if they are tracked */
+ if(oh->flags & H5O_HDR_STORE_TIMES) {
+ struct tm *tm; /* Time structure */
+ char buf[128]; /* Buffer for formatting time info */
+
+ /* Time fields */
+ tm = HDlocaltime(&oh->atime);
+ HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Access Time:", buf);
+ tm = HDlocaltime(&oh->mtime);
+ HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Modification Time:", buf);
+ tm = HDlocaltime(&oh->ctime);
+ HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Change Time:", buf);
+ tm = HDlocaltime(&oh->btime);
+ HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Birth Time:", buf);
+ } /* end if */
+
+ /* Attribute tracking fields */
+ if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. compact attributes:",
+ (unsigned)oh->max_compact);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Min. dense attributes:",
+ (unsigned)oh->min_dense);
+ } /* end if */
+ } /* end if */
+
+ HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth,
+ "Number of messages (allocated):",
+ oh->nmesgs, oh->alloc_nmesgs);
+ HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth,
+ "Number of chunks (allocated):",
+ oh->nchunks, oh->alloc_nchunks);
+
+ /* debug each chunk */
+ for(i = 0, chunk_total = 0; i < oh->nchunks; i++) {
+ size_t chunk_size;
+
+ HDfprintf(stream, "%*sChunk %d...\n", indent, "", i);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Address:",
+ oh->chunk[i].addr);
+
+ /* Decrement chunk 0's size by the object header prefix size */
+ if(0 == i) {
+ if(H5F_addr_ne(oh->chunk[i].addr, addr))
+ HDfprintf(stream, "*** WRONG ADDRESS FOR CHUNK #0!\n");
+ chunk_size = oh->chunk[i].size - (size_t)H5O_SIZEOF_HDR(oh);
+ } /* end if */
+ else
+ chunk_size = oh->chunk[i].size;
+
+ /* Accumulate chunk's size to total */
+ chunk_total += chunk_size;
+ gap_total += oh->chunk[i].gap;
+
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Size in bytes:",
+ chunk_size);
+
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Gap:",
+ oh->chunk[i].gap);
+ } /* end for */
+
+ /* debug each message */
+ if(NULL == (sequence = (unsigned *)H5MM_calloc(NELMTS(H5O_msg_class_g) * sizeof(unsigned))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ for(i = 0, mesg_total = 0; i < oh->nmesgs; i++) {
+ const H5O_msg_class_t *debug_type; /* Type of message to use for callbacks */
+ unsigned chunkno; /* Chunk for message */
+
+ /* Accumulate message's size to total */
+ mesg_total += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[i].raw_size;
+
+ /* For version 2 object header, add size of "OCHK" for continuation chunk */
+ if (oh->mesg[i].type->id == H5O_CONT_ID)
+ mesg_total += H5O_SIZEOF_CHKHDR_OH(oh);
+
+ HDfprintf(stream, "%*sMessage %d...\n", indent, "", i);
+
+ /* check for bad message id */
+ if(oh->mesg[i].type->id >= (int)NELMTS(H5O_msg_class_g)) {
+ HDfprintf(stream, "*** BAD MESSAGE ID 0x%04x\n",
+ oh->mesg[i].type->id);
+ continue;
+ } /* end if */
+
+ /* message name and size */
+ HDfprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n",
+ indent + 3, "", MAX(0, fwidth - 3),
+ "Message ID (sequence number):",
+ (unsigned) (oh->mesg[i].type->id),
+ oh->mesg[i].type->name,
+ sequence[oh->mesg[i].type->id]++);
+ HDfprintf(stream, "%*s%-*s %t\n", indent + 3, "", MAX (0, fwidth - 3),
+ "Dirty:",
+ oh->mesg[i].dirty);
+ HDfprintf(stream, "%*s%-*s ", indent + 3, "", MAX (0, fwidth - 3),
+ "Message flags:");
+ if(oh->mesg[i].flags) {
+ hbool_t flag_printed = FALSE;
+
+ /* Sanity check that all flags in format are covered below */
+ HDcompile_assert(H5O_MSG_FLAG_BITS == (H5O_MSG_FLAG_CONSTANT|H5O_MSG_FLAG_SHARED|H5O_MSG_FLAG_DONTSHARE|H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE|H5O_MSG_FLAG_MARK_IF_UNKNOWN|H5O_MSG_FLAG_WAS_UNKNOWN|H5O_MSG_FLAG_SHAREABLE|H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS));
+
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_CONSTANT) {
+ HDfprintf(stream, "%sC", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_SHARED) {
+ HDfprintf(stream, "%sS", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_DONTSHARE) {
+ HDfprintf(stream, "%sDS", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE) {
+ HDfprintf(stream, "%sFIUW", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) {
+ HDfprintf(stream, "%sMIU", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_WAS_UNKNOWN) {
+ HDassert(oh->mesg[i].flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN);
+ HDfprintf(stream, "%sWU", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_SHAREABLE) {
+ HDfprintf(stream, "%sSA", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(oh->mesg[i].flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS) {
+ HDfprintf(stream, "%sFIUA", (flag_printed ? ", " : "<"));
+ flag_printed = TRUE;
+ } /* end if */
+ if(!flag_printed)
+ HDfprintf(stream, "-");
+ HDfprintf(stream, ">\n");
+ if(oh->mesg[i].flags & ~H5O_MSG_FLAG_BITS)
+ HDfprintf(stream, "%*s%-*s 0x%02x\n", indent + 3,"", MAX(0, fwidth - 3),
+ "*** ADDITIONAL UNKNOWN FLAGS --->",
+ oh->mesg[i].flags & ~H5O_MSG_FLAG_BITS);
+ } /* end if */
+ else
+ HDfprintf(stream, "<none>\n");
+ HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Chunk number:",
+ oh->mesg[i].chunkno);
+ chunkno = oh->mesg[i].chunkno;
+ if(chunkno >= oh->nchunks)
+ HDfprintf(stream, "*** BAD CHUNK NUMBER\n");
+ HDfprintf(stream, "%*s%-*s (%Zu, %Zu) bytes\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Raw message data (offset, size) in chunk:",
+ (size_t)(oh->mesg[i].raw - oh->chunk[chunkno].image),
+ oh->mesg[i].raw_size);
+
+ /* check the size */
+ if((oh->mesg[i].raw + oh->mesg[i].raw_size >
+ oh->chunk[chunkno].image + oh->chunk[chunkno].size) ||
+ (oh->mesg[i].raw < oh->chunk[chunkno].image))
+ HDfprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n");
+
+ /* decode the message */
+ debug_type = oh->mesg[i].type;
+ if(NULL == oh->mesg[i].native && debug_type->decode)
+ H5O_LOAD_NATIVE(f, dxpl_id, H5O_DECODEIO_NOCHANGE, oh, &oh->mesg[i], FAIL)
+
+ /* print the message */
+ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Message Information:");
+ if(debug_type->debug && oh->mesg[i].native != NULL)
+ (debug_type->debug)(f, dxpl_id, oh->mesg[i].native, stream, indent + 6, MAX(0, fwidth - 6));
+ else
+ HDfprintf(stream, "%*s<No info for this message>\n", indent + 6, "");
+ } /* end for */
+
+ if((mesg_total + gap_total) != chunk_total)
+ HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n");
+
+done:
+ /* Release resources */
+ if(sequence)
+ sequence = (unsigned *)H5MM_xfree(sequence);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_debug_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_debug
+ *
+ * Purpose: Prints debugging info about an object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth)
+{
+ H5O_t *oh = NULL; /* Object header to display */
+ H5O_loc_t loc; /* Object location for object to delete */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Set up the object location */
+ loc.file = f;
+ loc.addr = addr;
+ loc.holding_file = FALSE;
+
+ if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* debug */
+ H5O_debug_real(f, dxpl_id, oh, addr, stream, indent, fwidth);
+
+done:
+ if(oh && H5O_unprotect(&loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_debug() */
+
diff --git a/src/H5Odrvinfo.c b/src/H5Odrvinfo.c
new file mode 100644
index 0000000..b9dea26
--- /dev/null
+++ b/src/H5Odrvinfo.c
@@ -0,0 +1,313 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, March 1, 2007
+ *
+ * Purpose: A message holding driver info settings
+ * in the superblock extension.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object headers */
+#include "H5MMprivate.h" /* Memory management */
+
+static void *H5O_drvinfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_drvinfo_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_drvinfo_copy(const void *_mesg, void *_dest);
+static size_t H5O_drvinfo_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_drvinfo_reset(void *_mesg);
+static herr_t H5O_drvinfo_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_DRVINFO[1] = {{
+ H5O_DRVINFO_ID, /*message id number */
+ "driver info", /*message name for debugging */
+ sizeof(H5O_drvinfo_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_drvinfo_decode, /*decode message */
+ H5O_drvinfo_encode, /*encode message */
+ H5O_drvinfo_copy, /*copy the native value */
+ H5O_drvinfo_size, /*raw message size */
+ H5O_drvinfo_reset, /*free internal memory */
+ NULL, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_drvinfo_debug /*debug the message */
+}};
+
+/* Current version of driver info information */
+#define H5O_DRVINFO_VERSION 0
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_decode
+ *
+ * Purpose: Decode a shared message table message and return a pointer
+ * to a newly allocated H5O_drvinfo_t struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_drvinfo_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_drvinfo_t *mesg; /* Native message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_DRVINFO_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (mesg = (H5O_drvinfo_t *)H5MM_calloc(sizeof(H5O_drvinfo_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for driver info message")
+
+ /* Retrieve driver name */
+ HDmemcpy(mesg->name, p, 8);
+ mesg->name[8] = '\0';
+ p += 8;
+
+ /* Decode buffer size */
+ UINT16DECODE(p, mesg->len);
+ HDassert(mesg->len);
+
+ /* Allocate space for buffer */
+ if(NULL == (mesg->buf = (uint8_t *)H5MM_malloc(mesg->len))) {
+ mesg = (H5O_drvinfo_t *)H5MM_xfree(mesg);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for driver info buffer")
+ } /* end if */
+
+ /* Copy encoded driver info into buffer */
+ HDmemcpy(mesg->buf, p, mesg->len);
+
+ /* Set return value */
+ ret_value = (void *)mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_drvinfo_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_encode
+ *
+ * Purpose: Encode a v1 B-tree 'K' value message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_drvinfo_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_drvinfo_t *mesg = (const H5O_drvinfo_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* Store version, driver name, buffer length, & encoded buffer */
+ *p++ = H5O_DRVINFO_VERSION;
+ HDmemcpy(p, mesg->name, 8);
+ p += 8;
+ HDassert(mesg->len <= 65535);
+ UINT16ENCODE(p, mesg->len);
+ HDmemcpy(p, mesg->buf, mesg->len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_drvinfo_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_drvinfo_copy(const void *_mesg, void *_dest)
+{
+ const H5O_drvinfo_t *mesg = (const H5O_drvinfo_t *)_mesg;
+ H5O_drvinfo_t *dest = (H5O_drvinfo_t *)_dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(mesg);
+
+ if(!dest && NULL == (dest = (H5O_drvinfo_t *)H5MM_malloc(sizeof(H5O_drvinfo_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for shared message table message")
+
+ /* Shallow copy the fields */
+ *dest = *mesg;
+
+ /* Copy the buffer */
+ if(NULL == (dest->buf = (uint8_t *)H5MM_malloc(mesg->len))) {
+ if(dest != _dest)
+ dest = (H5O_drvinfo_t *)H5MM_xfree(dest);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ } /* end if */
+ HDmemcpy(dest->buf, mesg->buf, mesg->len);
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_drvinfo_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_drvinfo_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_drvinfo_t *mesg = (const H5O_drvinfo_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(mesg);
+
+ ret_value = 1 + /* Version number */
+ 8 + /* Driver name */
+ 2 + /* Buffer length */
+ mesg->len; /* Buffer */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_drvinfo_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_reset
+ *
+ * Purpose: Frees internal pointers and resets the message to an
+ * initial state.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 1 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_drvinfo_reset(void *_mesg)
+{
+ H5O_drvinfo_t *mesg = (H5O_drvinfo_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(mesg);
+
+ /* reset */
+ mesg->buf = (uint8_t *)H5MM_xfree(mesg->buf);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_drvinfo_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_drvinfo_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Mar 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_drvinfo_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_drvinfo_t *mesg = (const H5O_drvinfo_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Driver name:", mesg->name);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Buffer size:", mesg->len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_drvinfo_debug() */
+
+
diff --git a/src/H5Odtype.c b/src/H5Odtype.c
new file mode 100644
index 0000000..a1c24b6
--- /dev/null
+++ b/src/H5Odtype.c
@@ -0,0 +1,2166 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+#define H5T_FRIEND /*prevent warning from including H5Tpkg */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Gprivate.h" /* Groups */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Tpkg.h" /* Datatypes */
+#include "H5VMprivate.h" /* Vectors and arrays */
+
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5O_dtype_encode(H5F_t *f, uint8_t *p, const void *mesg);
+static void *H5O_dtype_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static void *H5O_dtype_copy(const void *_mesg, void *_dest);
+static size_t H5O_dtype_size(const H5F_t *f, const void *_mesg);
+static herr_t H5O_dtype_reset(void *_mesg);
+static herr_t H5O__dtype_free(void *_mesg);
+static herr_t H5O_dtype_set_share(void *_mesg, const H5O_shared_t *sh);
+static htri_t H5O_dtype_can_share(const void *_mesg);
+static herr_t H5O_dtype_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *_udata);
+static void *H5O_dtype_copy_file(H5F_t *file_src, const H5O_msg_class_t *mesg_type,
+ void *native_src, H5F_t *file_dst, hbool_t *recompute_size,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_dtype_shared_post_copy_upd(const H5O_loc_t *src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst, hid_t dxpl_id,
+ H5O_copy_t *cpy_info);
+
+static herr_t H5O_dtype_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* Set up & include shared message "interface" info */
+#define H5O_SHARED_TYPE H5O_MSG_DTYPE
+#define H5O_SHARED_DECODE H5O_dtype_shared_decode
+#define H5O_SHARED_DECODE_REAL H5O_dtype_decode
+#define H5O_SHARED_ENCODE H5O_dtype_shared_encode
+#define H5O_SHARED_ENCODE_REAL H5O_dtype_encode
+#define H5O_SHARED_SIZE H5O_dtype_shared_size
+#define H5O_SHARED_SIZE_REAL H5O_dtype_size
+#define H5O_SHARED_DELETE H5O_dtype_shared_delete
+#undef H5O_SHARED_DELETE_REAL
+#define H5O_SHARED_LINK H5O_dtype_shared_link
+#undef H5O_SHARED_LINK_REAL
+#define H5O_SHARED_COPY_FILE H5O_dtype_shared_copy_file
+#define H5O_SHARED_COPY_FILE_REAL H5O_dtype_copy_file
+#define H5O_SHARED_POST_COPY_FILE H5O_dtype_shared_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_REAL
+#define H5O_SHARED_POST_COPY_FILE_UPD H5O_dtype_shared_post_copy_upd
+#define H5O_SHARED_DEBUG H5O_dtype_shared_debug
+#define H5O_SHARED_DEBUG_REAL H5O_dtype_debug
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* Macros to check for the proper version of a datatype */
+#ifdef H5_STRICT_FORMAT_CHECKS
+/* If the version is too low, give an error. No error if nochange is set
+ * because in that case we are either debugging or deleting the object header */
+#define H5O_DTYPE_CHECK_VERSION(DT, VERS, MIN_VERS, IOF, CLASS, ERR) \
+ if(((VERS) < (MIN_VERS)) && !(*(IOF) & H5O_DECODEIO_NOCHANGE)) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_VERSION, ERR, "incorrect " CLASS " datatype version")
+#else /* H5_STRICT_FORMAT_CHECKS */
+/* If the version is too low and we are allowed to change the message, upgrade
+ * it and mark the object header as dirty */
+#define H5O_DTYPE_CHECK_VERSION(DT, VERS, MIN_VERS, IOF, CLASS, ERR) \
+ if(((VERS) < (MIN_VERS)) && !(*(IOF) & H5O_DECODEIO_NOCHANGE)) { \
+ (VERS) = (MIN_VERS); \
+ if(H5T__upgrade_version((DT), (VERS)) < 0) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't upgrade " CLASS " encoding version") \
+ *(IOF) |= H5O_DECODEIO_DIRTY; \
+ } /* end if */
+#endif /* H5_STRICT_FORMAT_CHECKS */
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_DTYPE[1] = {{
+ H5O_DTYPE_ID, /* message id number */
+ "datatype", /* message name for debugging */
+ sizeof(H5T_t), /* native message size */
+ H5O_SHARE_IS_SHARABLE|H5O_SHARE_IN_OHDR, /* messages are sharable? */
+ H5O_dtype_shared_decode, /* decode message */
+ H5O_dtype_shared_encode, /* encode message */
+ H5O_dtype_copy, /* copy the native value */
+ H5O_dtype_shared_size, /* size of raw message */
+ H5O_dtype_reset, /* reset method */
+ H5O__dtype_free, /* free method */
+ H5O_dtype_shared_delete, /* file delete method */
+ H5O_dtype_shared_link, /* link method */
+ H5O_dtype_set_share, /* set share method */
+ H5O_dtype_can_share, /* can share method */
+ H5O_dtype_pre_copy_file, /* pre copy native value to file */
+ H5O_dtype_shared_copy_file, /* copy native value to file */
+ H5O_dtype_shared_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_dtype_shared_debug /* debug the message */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_decode_helper
+ *
+ * Purpose: Decodes a datatype
+ *
+ * Return: TRUE if we can upgrade the parent type's version even
+ * with strict format checks
+ * FALSE if we cannot
+ * Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_dtype_decode_helper(H5F_t *f, unsigned *ioflags/*in,out*/, const uint8_t **pp, H5T_t *dt)
+{
+ unsigned flags, version;
+ unsigned i;
+ size_t z;
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(pp && *pp);
+ HDassert(dt && dt->shared);
+
+ /* Version, class & flags */
+ UINT32DECODE(*pp, flags);
+ version = (flags>>4) & 0x0f;
+ if(version < H5O_DTYPE_VERSION_1 || version > H5O_DTYPE_VERSION_3)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTLOAD, FAIL, "bad version number for datatype message")
+ dt->shared->version = version;
+ dt->shared->type = (H5T_class_t)(flags & 0x0f);
+ flags >>= 8;
+
+ /* Size */
+ UINT32DECODE(*pp, dt->shared->size);
+
+ switch(dt->shared->type) {
+ case H5T_INTEGER:
+ /*
+ * Integer types...
+ */
+ dt->shared->u.atomic.order = (flags & 0x1) ? H5T_ORDER_BE : H5T_ORDER_LE;
+ dt->shared->u.atomic.lsb_pad = (flags & 0x2) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ dt->shared->u.atomic.msb_pad = (flags & 0x4) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ dt->shared->u.atomic.u.i.sign = (flags & 0x8) ? H5T_SGN_2 : H5T_SGN_NONE;
+ UINT16DECODE(*pp, dt->shared->u.atomic.offset);
+ UINT16DECODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_FLOAT:
+ /*
+ * Floating-point types...
+ */
+ dt->shared->u.atomic.order = (flags & 0x1) ? H5T_ORDER_BE : H5T_ORDER_LE;
+ if(version >= H5O_DTYPE_VERSION_3) {
+ /* Unsupported byte order*/
+ if((flags & 0x40) && !(flags & 0x1))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bad byte order for datatype message")
+
+ /* VAX order if both 1st and 6th bits are turned on*/
+ if(flags & 0x40)
+ dt->shared->u.atomic.order = H5T_ORDER_VAX;
+ } /* end if */
+ dt->shared->u.atomic.lsb_pad = (flags & 0x2) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ dt->shared->u.atomic.msb_pad = (flags & 0x4) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ dt->shared->u.atomic.u.f.pad = (flags & 0x8) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ switch((flags >> 4) & 0x03) {
+ case 0:
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_NONE;
+ break;
+
+ case 1:
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_MSBSET;
+ break;
+
+ case 2:
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown floating-point normalization")
+ } /* end switch */
+ dt->shared->u.atomic.u.f.sign = (flags >> 8) & 0xff;
+ UINT16DECODE(*pp, dt->shared->u.atomic.offset);
+ UINT16DECODE(*pp, dt->shared->u.atomic.prec);
+ dt->shared->u.atomic.u.f.epos = *(*pp)++;
+ dt->shared->u.atomic.u.f.esize = *(*pp)++;
+ HDassert(dt->shared->u.atomic.u.f.esize > 0);
+ dt->shared->u.atomic.u.f.mpos = *(*pp)++;
+ dt->shared->u.atomic.u.f.msize = *(*pp)++;
+ HDassert(dt->shared->u.atomic.u.f.msize > 0);
+ UINT32DECODE(*pp, dt->shared->u.atomic.u.f.ebias);
+ break;
+
+ case H5T_TIME: /* Time datatypes */
+ dt->shared->u.atomic.order = (flags & 0x1) ? H5T_ORDER_BE : H5T_ORDER_LE;
+ UINT16DECODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_STRING:
+ /*
+ * Character string types...
+ */
+ dt->shared->u.atomic.order = H5T_ORDER_NONE;
+ dt->shared->u.atomic.prec = 8 * dt->shared->size;
+ dt->shared->u.atomic.offset = 0;
+ dt->shared->u.atomic.lsb_pad = H5T_PAD_ZERO;
+ dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO;
+
+ dt->shared->u.atomic.u.s.pad = (H5T_str_t)(flags & 0x0f);
+ dt->shared->u.atomic.u.s.cset = (H5T_cset_t)((flags >> 4) & 0x0f);
+ break;
+
+ case H5T_BITFIELD:
+ /*
+ * Bit fields...
+ */
+ dt->shared->u.atomic.order = (flags & 0x1) ? H5T_ORDER_BE : H5T_ORDER_LE;
+ dt->shared->u.atomic.lsb_pad = (flags & 0x2) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ dt->shared->u.atomic.msb_pad = (flags & 0x4) ? H5T_PAD_ONE : H5T_PAD_ZERO;
+ UINT16DECODE(*pp, dt->shared->u.atomic.offset);
+ UINT16DECODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_OPAQUE:
+ /*
+ * Opaque types...
+ */
+ z = flags & (H5T_OPAQUE_TAG_MAX - 1);
+ HDassert(0 == (z & 0x7)); /*must be aligned*/
+ if(NULL == (dt->shared->u.opaque.tag = (char *)H5MM_malloc(z + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDmemcpy(dt->shared->u.opaque.tag, *pp, z);
+ dt->shared->u.opaque.tag[z] = '\0';
+ *pp += z;
+ break;
+
+ case H5T_COMPOUND:
+ {
+ unsigned offset_nbytes; /* Size needed to encode member offsets */
+ size_t max_memb_pos = 0; /* Maximum member covered, so far */
+ unsigned max_version = 0; /* Maximum member version */
+ unsigned upgrade_to = 0; /* Version number we can "soft" upgrade to */
+ unsigned j;
+
+ /* Compute the # of bytes required to store a member offset */
+ offset_nbytes = H5VM_limit_enc_size((uint64_t)dt->shared->size);
+
+ /*
+ * Compound datatypes...
+ */
+ dt->shared->u.compnd.nmembs = flags & 0xffff;
+ if(dt->shared->u.compnd.nmembs == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid number of members: %u", dt->shared->u.compnd.nmembs)
+ dt->shared->u.compnd.nalloc = dt->shared->u.compnd.nmembs;
+ dt->shared->u.compnd.memb = (H5T_cmemb_t *)H5MM_calloc(dt->shared->u.compnd.nalloc * sizeof(H5T_cmemb_t));
+ dt->shared->u.compnd.memb_size = 0;
+ if(NULL == dt->shared->u.compnd.memb)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ unsigned ndims = 0; /* Number of dimensions of the array field */
+ htri_t can_upgrade; /* Whether we can upgrade this type's version */
+ hsize_t dim[H5O_LAYOUT_NDIMS]; /* Dimensions of the array */
+ H5T_t *array_dt; /* Temporary pointer to the array datatype */
+ H5T_t *temp_type; /* Temporary pointer to the field's datatype */
+
+ /* Decode the field name */
+ dt->shared->u.compnd.memb[i].name = H5MM_xstrdup((const char *)*pp);
+
+ /* Version 3 of the datatype message eliminated the padding to multiple of 8 bytes */
+ if(version >= H5O_DTYPE_VERSION_3)
+ /* Advance past name, including null terminator */
+ *pp += HDstrlen((const char *)*pp) + 1;
+ else
+ /* Advance multiple of 8 w/ null terminator */
+ *pp += ((HDstrlen((const char *)*pp) + 8) / 8) * 8;
+
+ /* Decode the field offset */
+ /* (starting with version 3 of the datatype message, use the minimum # of bytes required) */
+ if(version >= H5O_DTYPE_VERSION_3)
+ UINT32DECODE_VAR(*pp, dt->shared->u.compnd.memb[i].offset, offset_nbytes)
+ else
+ UINT32DECODE(*pp, dt->shared->u.compnd.memb[i].offset)
+
+ /* Older versions of the library allowed a field to have
+ * intrinsic 'arrayness'. Newer versions of the library
+ * use the separate array datatypes. */
+ if(version == H5O_DTYPE_VERSION_1) {
+ /* Decode the number of dimensions */
+ ndims = *(*pp)++;
+
+ /* Check that ndims is valid */
+ if(ndims > 4)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "invalid number of dimensions for array")
+
+ *pp += 3; /*reserved bytes */
+
+ /* Skip dimension permutation */
+ *pp += 4;
+
+ /* Skip reserved bytes */
+ *pp += 4;
+
+ /* Decode array dimension sizes */
+ for(j = 0; j < 4; j++)
+ UINT32DECODE(*pp, dim[j]);
+ } /* end if */
+
+ /* Allocate space for the field's datatype */
+ if(NULL == (temp_type = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Decode the field's datatype information */
+ if((can_upgrade = H5O_dtype_decode_helper(f, ioflags, pp, temp_type)) < 0) {
+ for(j = 0; j <= i; j++)
+ H5MM_xfree(dt->shared->u.compnd.memb[j].name);
+ H5MM_xfree(dt->shared->u.compnd.memb);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "unable to decode member type")
+ } /* end if */
+
+ /* Upgrade the version if we can and it is necessary */
+ if(can_upgrade && temp_type->shared->version > version) {
+ upgrade_to = temp_type->shared->version;
+
+ /* Pass "can_upgrade" flag down to parent type */
+ ret_value = TRUE;
+ } /* end if */
+
+ /* Go create the array datatype now, for older versions of the datatype message */
+ if(version == H5O_DTYPE_VERSION_1) {
+ /* Check if this member is an array field */
+ if(ndims > 0) {
+ /* Create the array datatype for the field */
+ if((array_dt = H5T__array_create(temp_type, ndims, dim)) == NULL) {
+ for(j = 0; j <= i; j++)
+ H5MM_xfree(dt->shared->u.compnd.memb[j].name);
+ H5MM_xfree(dt->shared->u.compnd.memb);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to create array datatype")
+ } /* end if */
+
+ /* Close the base type for the array */
+ H5T_close(temp_type);
+
+ /* Make the array type the type that is set for the field */
+ temp_type = array_dt;
+
+ /* Reset array version if NOCHANGE is specified (i.e. h5debug) */
+ if(*ioflags & H5O_DECODEIO_NOCHANGE)
+ temp_type->shared->version = H5O_DTYPE_VERSION_1;
+ else {
+ /* Otherwise upgrade the compound version */
+ if(upgrade_to < temp_type->shared->version)
+ upgrade_to = temp_type->shared->version;
+
+ /* Set the return value to indicate that we should freely
+ * upgrade parent types */
+ ret_value = TRUE;
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ /* Keep track of the maximum member version found */
+ if(temp_type->shared->version > max_version)
+ max_version = temp_type->shared->version;
+
+ /*
+ * Set the "force conversion" flag if VL datatype fields exist in this
+ * type or any component types
+ */
+ if(temp_type->shared->force_conv == TRUE)
+ dt->shared->force_conv = TRUE;
+
+ /* Member size */
+ dt->shared->u.compnd.memb[i].size = temp_type->shared->size;
+ dt->shared->u.compnd.memb_size += temp_type->shared->size;
+
+ /* Set the field datatype (finally :-) */
+ dt->shared->u.compnd.memb[i].type = temp_type;
+
+ /* Check if this field overlaps with a prior field */
+ /* (probably indicates that the file is corrupt) */
+ if(i > 0 && dt->shared->u.compnd.memb[i].offset < max_memb_pos) {
+ for(j = 0; j < i; j++)
+ if(dt->shared->u.compnd.memb[i].offset >= dt->shared->u.compnd.memb[j].offset
+ && dt->shared->u.compnd.memb[i].offset < (dt->shared->u.compnd.memb[j].offset + dt->shared->u.compnd.memb[j].size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "member overlaps with previous member")
+ } /* end if */
+
+ /* Update the maximum member position covered */
+ max_memb_pos = MAX(max_memb_pos, (dt->shared->u.compnd.memb[i].offset + dt->shared->u.compnd.memb[i].size));
+ } /* end for */
+
+ /* Check if the compound type is packed */
+ H5T__update_packed(dt);
+
+ /* Upgrade the compound if requested */
+ if(version < upgrade_to) {
+ version = upgrade_to;
+ if(H5T__upgrade_version(dt, upgrade_to) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't upgrade compound encoding version")
+ /* We won't mark the message dirty since there were no
+ * errors in the file, simply type versions that we will no
+ * longer encode. */
+ } /* end if */
+
+ /* Check that no member of this compound has a version greater
+ * than the compound itself. */
+ H5O_DTYPE_CHECK_VERSION(dt, version, max_version, ioflags, "compound", FAIL)
+ }
+ break;
+
+ case H5T_REFERENCE: /* Reference datatypes... */
+ dt->shared->u.atomic.order = H5T_ORDER_NONE;
+ dt->shared->u.atomic.prec = 8 * dt->shared->size;
+ dt->shared->u.atomic.offset = 0;
+ dt->shared->u.atomic.lsb_pad = H5T_PAD_ZERO;
+ dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO;
+
+ /* Set reference type */
+ dt->shared->u.atomic.u.r.rtype = (H5R_type_t)(flags & 0x0f);
+
+ /* Set extra information for object references, so the hobj_ref_t gets swizzled correctly */
+ if(dt->shared->u.atomic.u.r.rtype == H5R_OBJECT) {
+ /* Mark location this type as undefined for now. The caller function should
+ * decide the location. */
+ dt->shared->u.atomic.u.r.loc = H5T_LOC_BADLOC;
+
+ /* This type needs conversion */
+ dt->shared->force_conv = TRUE;
+ } /* end if */
+ break;
+
+ case H5T_ENUM:
+ /*
+ * Enumeration datatypes...
+ */
+ dt->shared->u.enumer.nmembs = dt->shared->u.enumer.nalloc = flags & 0xffff;
+ if(NULL == (dt->shared->parent = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(H5O_dtype_decode_helper(f, ioflags, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "unable to decode parent datatype")
+
+ /* Check if the parent of this enum has a version greater than the
+ * enum itself. */
+ H5O_DTYPE_CHECK_VERSION(dt, version, dt->shared->parent->shared->version,
+ ioflags, "enum", FAIL)
+
+ if(NULL == (dt->shared->u.enumer.name = (char **)H5MM_calloc(dt->shared->u.enumer.nalloc * sizeof(char*))) ||
+ NULL == (dt->shared->u.enumer.value = (uint8_t *)H5MM_calloc(dt->shared->u.enumer.nalloc * dt->shared->parent->shared->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Names */
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++) {
+ dt->shared->u.enumer.name[i] = H5MM_xstrdup((const char*)*pp);
+
+ /* Version 3 of the datatype message eliminated the padding to multiple of 8 bytes */
+ if(version >= H5O_DTYPE_VERSION_3)
+ /* Advance past name, including null terminator */
+ *pp += HDstrlen((const char *)*pp) + 1;
+ else
+ /* Advance multiple of 8 w/ null terminator */
+ *pp += ((HDstrlen((const char *)*pp) + 8) / 8) * 8;
+ } /* end for */
+
+ /* Values */
+ HDmemcpy(dt->shared->u.enumer.value, *pp,
+ dt->shared->u.enumer.nmembs * dt->shared->parent->shared->size);
+ *pp += dt->shared->u.enumer.nmembs * dt->shared->parent->shared->size;
+ break;
+
+ case H5T_VLEN: /* Variable length datatypes... */
+ /* Set the type of VL information, either sequence or string */
+ dt->shared->u.vlen.type = (H5T_vlen_type_t)(flags & 0x0f);
+ if(dt->shared->u.vlen.type == H5T_VLEN_STRING) {
+ dt->shared->u.vlen.pad = (H5T_str_t)((flags >> 4) & 0x0f);
+ dt->shared->u.vlen.cset = (H5T_cset_t)((flags >> 8) & 0x0f);
+ } /* end if */
+
+ /* Decode base type of VL information */
+ if(NULL == (dt->shared->parent = H5T__alloc()))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(H5O_dtype_decode_helper(f, ioflags, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "unable to decode VL parent type")
+
+ /* Check if the parent of this vlen has a version greater than the
+ * vlen itself. */
+ H5O_DTYPE_CHECK_VERSION(dt, version, dt->shared->parent->shared->version,
+ ioflags, "vlen", FAIL)
+
+ dt->shared->force_conv=TRUE;
+
+ /* Mark location this type as undefined for now. The caller function should
+ * decide the location. */
+ if(H5T_set_loc(dt, f, H5T_LOC_BADLOC) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid datatype location")
+ break;
+
+ case H5T_ARRAY: /* Array datatypes */
+ /* Decode the number of dimensions */
+ dt->shared->u.array.ndims = *(*pp)++;
+
+ /* Double-check the number of dimensions */
+ if(dt->shared->u.array.ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTLOAD, FAIL, "too many dimensions for array datatype")
+
+ /* Skip reserved bytes, if version has them */
+ if(version < H5O_DTYPE_VERSION_3)
+ *pp += 3;
+
+ /* Decode array dimension sizes & compute number of elements */
+ for(i = 0, dt->shared->u.array.nelem = 1; i < (unsigned)dt->shared->u.array.ndims; i++) {
+ UINT32DECODE(*pp, dt->shared->u.array.dim[i]);
+ dt->shared->u.array.nelem *= dt->shared->u.array.dim[i];
+ } /* end for */
+
+ /* Skip array dimension permutations, if version has them */
+ if(version < H5O_DTYPE_VERSION_3)
+ *pp += dt->shared->u.array.ndims * 4;
+
+ /* Decode base type of array */
+ if(NULL == (dt->shared->parent = H5T__alloc()))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(H5O_dtype_decode_helper(f, ioflags, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "unable to decode array parent type")
+
+ /* Check if the parent of this array has a version greater than the
+ * array itself. */
+ H5O_DTYPE_CHECK_VERSION(dt, version, dt->shared->parent->shared->version,
+ ioflags, "array", FAIL)
+
+ /* There should be no array datatypes with version < 2. */
+ H5O_DTYPE_CHECK_VERSION(dt, version, H5O_DTYPE_VERSION_2, ioflags,
+ "array", FAIL)
+
+ /*
+ * Set the "force conversion" flag if a VL base datatype is used or
+ * or if any components of the base datatype are VL types.
+ */
+ if(dt->shared->parent->shared->force_conv == TRUE)
+ dt->shared->force_conv = TRUE;
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown datatype class found")
+ } /* end switch */
+
+done:
+ if(ret_value < 0) {
+ if(dt != NULL) {
+ if(dt->shared != NULL)
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+ dt = H5FL_FREE(H5T_t, dt);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_decode_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_encode_helper
+ *
+ * Purpose: Encodes a datatype.
+ *
+ * Note: When changing the format of a datatype (or adding a new one),
+ * remember to change the upgrade version callback
+ * (H5T_upgrade_version_cb).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_dtype_encode_helper(const H5F_t *f, uint8_t **pp, const H5T_t *dt)
+{
+ unsigned flags = 0;
+ uint8_t *hdr = (uint8_t *)*pp;
+ unsigned i;
+ size_t n, z;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(pp && *pp);
+ HDassert(dt);
+
+ /* skip the type and class bit-field for now */
+ *pp += 4;
+ UINT32ENCODE(*pp, dt->shared->size);
+
+ switch(dt->shared->type) {
+ case H5T_INTEGER:
+ /*
+ * Integer datatypes...
+ */
+ switch (dt->shared->u.atomic.order) {
+ case H5T_ORDER_LE:
+ break; /*nothing */
+
+ case H5T_ORDER_BE:
+ flags |= 0x01;
+ break;
+
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "byte order is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.lsb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x02;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.msb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ case H5T_PAD_ONE:
+ flags |= 0x04;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.u.i.sign) {
+ case H5T_SGN_NONE:
+ break; /*nothing */
+
+ case H5T_SGN_2:
+ flags |= 0x08;
+ break;
+
+ case H5T_SGN_ERROR:
+ case H5T_NSGN:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "sign scheme is not supported in file format yet")
+ } /* end switch */
+
+ UINT16ENCODE(*pp, dt->shared->u.atomic.offset);
+ UINT16ENCODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_FLOAT:
+ /*
+ * Floating-point types...
+ */
+ switch (dt->shared->u.atomic.order) {
+ case H5T_ORDER_LE:
+ break; /*nothing*/
+
+ case H5T_ORDER_BE:
+ flags |= 0x01;
+ break;
+
+ case H5T_ORDER_VAX: /*turn on 1st and 6th (reserved before adding VAX) bits*/
+ flags |= 0x41;
+ HDassert(dt->shared->version >= H5O_DTYPE_VERSION_3);
+ break;
+
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "byte order is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.lsb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x02;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.msb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x04;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.u.f.pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x08;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.u.f.norm) {
+ case H5T_NORM_NONE:
+ break; /*nothing */
+
+ case H5T_NORM_MSBSET:
+ flags |= 0x10;
+ break;
+
+ case H5T_NORM_IMPLIED:
+ flags |= 0x20;
+ break;
+
+ case H5T_NORM_ERROR:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "normalization scheme is not supported in file format yet")
+ } /* end switch */
+
+ flags = (unsigned)(flags | ((dt->shared->u.atomic.u.f.sign << 8) & 0xff00));
+ UINT16ENCODE(*pp, dt->shared->u.atomic.offset);
+ UINT16ENCODE(*pp, dt->shared->u.atomic.prec);
+ HDassert(dt->shared->u.atomic.u.f.epos <= 255);
+ *(*pp)++ = (uint8_t)(dt->shared->u.atomic.u.f.epos);
+ HDassert(dt->shared->u.atomic.u.f.esize <= 255);
+ *(*pp)++ = (uint8_t)(dt->shared->u.atomic.u.f.esize);
+ HDassert(dt->shared->u.atomic.u.f.mpos <= 255);
+ *(*pp)++ = (uint8_t)(dt->shared->u.atomic.u.f.mpos);
+ HDassert(dt->shared->u.atomic.u.f.msize <= 255);
+ *(*pp)++ = (uint8_t)(dt->shared->u.atomic.u.f.msize);
+ UINT32ENCODE(*pp, dt->shared->u.atomic.u.f.ebias);
+ break;
+
+ case H5T_TIME: /* Time datatypes... */
+ switch (dt->shared->u.atomic.order) {
+ case H5T_ORDER_LE:
+ break; /*nothing */
+
+ case H5T_ORDER_BE:
+ flags |= 0x01;
+ break;
+
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "byte order is not supported in file format yet")
+ } /* end switch */
+ UINT16ENCODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_STRING:
+ /*
+ * Character string types... (not fully implemented)
+ */
+ HDassert(dt->shared->u.atomic.order == H5T_ORDER_NONE);
+ HDassert(dt->shared->u.atomic.prec == 8 * dt->shared->size);
+ HDassert(dt->shared->u.atomic.offset == 0);
+ HDassert(dt->shared->u.atomic.lsb_pad == H5T_PAD_ZERO);
+ HDassert(dt->shared->u.atomic.msb_pad == H5T_PAD_ZERO);
+
+ flags = (unsigned)(flags | (dt->shared->u.atomic.u.s.pad & 0x0f));
+ flags = (unsigned)(flags | ((((unsigned)dt->shared->u.atomic.u.s.cset) & 0x0f) << 4));
+ break;
+
+ case H5T_BITFIELD:
+ /*
+ * Bitfield datatypes...
+ */
+ switch (dt->shared->u.atomic.order) {
+ case H5T_ORDER_LE:
+ break; /*nothing */
+
+ case H5T_ORDER_BE:
+ flags |= 0x01;
+ break;
+
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "byte order is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.lsb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x02;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ switch (dt->shared->u.atomic.msb_pad) {
+ case H5T_PAD_ZERO:
+ break; /*nothing */
+
+ case H5T_PAD_ONE:
+ flags |= 0x04;
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "bit padding is not supported in file format yet")
+ } /* end switch */
+
+ UINT16ENCODE(*pp, dt->shared->u.atomic.offset);
+ UINT16ENCODE(*pp, dt->shared->u.atomic.prec);
+ break;
+
+ case H5T_OPAQUE:
+ /*
+ * Opaque datatypes... The tag is stored in a field which is a
+ * multiple of eight characters and null padded (not necessarily
+ * null terminated).
+ */
+ {
+ size_t aligned;
+
+ z = HDstrlen(dt->shared->u.opaque.tag);
+ aligned = (z + 7) & (H5T_OPAQUE_TAG_MAX - 8);
+ flags = (unsigned)(flags | aligned);
+ HDmemcpy(*pp, dt->shared->u.opaque.tag, MIN(z,aligned));
+ for(n = MIN(z, aligned); n < aligned; n++)
+ (*pp)[n] = 0;
+ *pp += aligned;
+ }
+ break;
+
+ case H5T_COMPOUND:
+ {
+ unsigned offset_nbytes; /* Size needed to encode member offsets */
+
+ /* Compute the # of bytes required to store a member offset */
+ offset_nbytes = H5VM_limit_enc_size((uint64_t)dt->shared->size);
+
+ /*
+ * Compound datatypes...
+ */
+ flags = dt->shared->u.compnd.nmembs & 0xffff;
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ /* Sanity check */
+ /* (compound datatypes w/array members must be encoded w/version >= 2) */
+ HDassert(dt->shared->u.compnd.memb[i].type->shared->type != H5T_ARRAY || dt->shared->version >= H5O_DTYPE_VERSION_2);
+
+ /* Check that the version is at least as great as the member */
+ HDassert(dt->shared->version >= dt->shared->u.compnd.memb[i].type->shared->version);
+
+ /* Name */
+ HDstrcpy((char*)(*pp), dt->shared->u.compnd.memb[i].name);
+
+ /* Version 3 of the datatype message removed the padding to multiple of 8 bytes */
+ n = HDstrlen(dt->shared->u.compnd.memb[i].name);
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ *pp += n + 1;
+ else {
+ /* Pad name to multiple of 8 bytes */
+ for(z = n + 1; z % 8; z++)
+ (*pp)[z] = '\0';
+ *pp += z;
+ } /* end if */
+
+ /* Member offset */
+ /* (starting with version 3 of the datatype message, use the minimum # of bytes required) */
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ UINT32ENCODE_VAR(*pp, (uint32_t)dt->shared->u.compnd.memb[i].offset, offset_nbytes)
+ else
+ UINT32ENCODE(*pp, dt->shared->u.compnd.memb[i].offset)
+
+ /* If we don't have any array fields, write out the old style
+ * member information, for better backward compatibility
+ * Write out all zeros for the array information, though...
+ */
+ if(dt->shared->version == H5O_DTYPE_VERSION_1) {
+ unsigned j;
+
+ /* Dimensionality */
+ *(*pp)++ = 0;
+
+ /* Reserved */
+ *(*pp)++ = 0;
+ *(*pp)++ = 0;
+ *(*pp)++ = 0;
+
+ /* Dimension permutation */
+ UINT32ENCODE(*pp, 0);
+
+ /* Reserved */
+ UINT32ENCODE(*pp, 0);
+
+ /* Dimensions */
+ for(j = 0; j < 4; j++)
+ UINT32ENCODE(*pp, 0);
+ } /* end if */
+
+ /* Subtype */
+ if(H5O_dtype_encode_helper(f, pp, dt->shared->u.compnd.memb[i].type) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "unable to encode member type")
+ } /* end for */
+ }
+ break;
+
+ case H5T_REFERENCE:
+ flags |= (dt->shared->u.atomic.u.r.rtype & 0x0f);
+ break;
+
+ case H5T_ENUM:
+ /* Check that the version is at least as great as the parent */
+ HDassert(dt->shared->version >= dt->shared->parent->shared->version);
+
+ /*
+ * Enumeration datatypes...
+ */
+ flags = dt->shared->u.enumer.nmembs & 0xffff;
+
+ /* Parent type */
+ if(H5O_dtype_encode_helper(f, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "unable to encode parent datatype")
+
+ /* Names, each a multiple of eight bytes */
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++) {
+ /* Name */
+ HDstrcpy((char*)(*pp), dt->shared->u.enumer.name[i]);
+
+ /* Version 3 of the datatype message removed the padding to multiple of 8 bytes */
+ n = HDstrlen(dt->shared->u.enumer.name[i]);
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ *pp += n + 1;
+ else {
+ /* Pad to multiple of 8 bytes */
+ for(z = n + 1; z % 8; z++)
+ (*pp)[z] = '\0';
+ *pp += z;
+ } /* end for */
+ } /* end for */
+
+ /* Values */
+ HDmemcpy(*pp, dt->shared->u.enumer.value, dt->shared->u.enumer.nmembs * dt->shared->parent->shared->size);
+ *pp += dt->shared->u.enumer.nmembs * dt->shared->parent->shared->size;
+ break;
+
+ case H5T_VLEN: /* Variable length datatypes... */
+ /* Check that the version is at least as great as the parent */
+ HDassert(dt->shared->version >= dt->shared->parent->shared->version);
+
+ flags |= (dt->shared->u.vlen.type & 0x0f);
+ if(dt->shared->u.vlen.type == H5T_VLEN_STRING) {
+ flags = (unsigned)(flags | (((unsigned)dt->shared->u.vlen.pad & 0x0f) << 4));
+ flags = (unsigned)(flags | (((unsigned)dt->shared->u.vlen.cset & 0x0f) << 8));
+ } /* end if */
+
+ /* Encode base type of VL information */
+ if(H5O_dtype_encode_helper(f, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "unable to encode VL parent type")
+ break;
+
+ case H5T_ARRAY: /* Array datatypes */
+ /* Double-check the number of dimensions */
+ HDassert(dt->shared->u.array.ndims <= H5S_MAX_RANK);
+
+ /* Check that the version is valid */
+ HDassert(dt->shared->version >= H5O_DTYPE_VERSION_2);
+
+ /* Check that the version is at least as great as the parent */
+ HDassert(dt->shared->version >= dt->shared->parent->shared->version);
+
+ /* Encode the number of dimensions */
+ HDassert(dt->shared->u.array.ndims <= UCHAR_MAX);
+ *(*pp)++ = (uint8_t)dt->shared->u.array.ndims;
+
+ /* Drop this information for Version 3 of the format */
+ if(dt->shared->version < H5O_DTYPE_VERSION_3) {
+ /* Reserved */
+ *(*pp)++ = '\0';
+ *(*pp)++ = '\0';
+ *(*pp)++ = '\0';
+ } /* end if */
+
+ /* Encode array dimensions */
+ for(i = 0; i < (unsigned)dt->shared->u.array.ndims; i++)
+ UINT32ENCODE(*pp, dt->shared->u.array.dim[i]);
+
+ /* Drop this information for Version 3 of the format */
+ if(dt->shared->version < H5O_DTYPE_VERSION_3) {
+ /* Encode 'fake' array dimension permutations */
+ for(i = 0; i < (unsigned)dt->shared->u.array.ndims; i++)
+ UINT32ENCODE(*pp, i);
+ } /* end if */
+
+ /* Encode base type of array's information */
+ if(H5O_dtype_encode_helper(f, pp, dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "unable to encode VL parent type")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /*nothing */
+ break;
+ } /* end switch */
+
+ /* Encode the type's class, version and bit field */
+ *hdr++ = (uint8_t)(((unsigned)(dt->shared->type) & 0x0f) | (dt->shared->version << 4));
+ *hdr++ = (uint8_t)((flags >> 0) & 0xff);
+ *hdr++ = (uint8_t)((flags >> 8) & 0xff);
+ *hdr++ = (uint8_t)((flags >> 16) & 0xff);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_encode_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_dtype_decode
+ PURPOSE
+ Decode a message and return a pointer to a memory struct
+ with the decoded information
+ USAGE
+ void *H5O_dtype_decode(f, dxpl_id, mesg_flags, p)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ hid_t dxpl_id; IN: DXPL for any I/O
+ unsigned mesg_flags; IN: Message flags to influence decoding
+ const uint8 *p; IN: the raw information buffer
+ RETURNS
+ Pointer to the new message in native order on success, NULL on failure
+ DESCRIPTION
+ This function decodes the "raw" disk form of a simple datatype message
+ into a struct in memory native format. The struct is allocated within this
+ function using malloc() and is returned to the caller.
+--------------------------------------------------------------------------*/
+static void *
+H5O_dtype_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
+ unsigned *ioflags/*in,out*/, const uint8_t *p)
+{
+ H5T_t *dt = NULL;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(p);
+
+ /* Allocate datatype message */
+ if(NULL == (dt = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Perform actual decode of message */
+ if(H5O_dtype_decode_helper(f, ioflags, &p, dt) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, NULL, "can't decode type")
+
+ /* Set return value */
+ ret_value = dt;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_decode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_dtype_encode
+ PURPOSE
+ Encode a simple datatype message
+ USAGE
+ herr_t H5O_dtype_encode(f, raw_size, p, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ size_t raw_size; IN: size of the raw information buffer
+ const uint8 *p; IN: the raw information buffer
+ const void *mesg; IN: Pointer to the simple datatype struct
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function encodes the native memory form of the simple datatype
+ message in the "raw" disk form.
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_dtype_encode(H5F_t *f, uint8_t *p, const void *mesg)
+{
+ const H5T_t *dt = (const H5T_t *) mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(dt);
+
+ /* encode */
+ if(H5O_dtype_encode_helper(f, &p, dt) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_encode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_dtype_copy
+ PURPOSE
+ Copies a message from MESG to DEST, allocating DEST if necessary.
+ USAGE
+ void *H5O_dtype_copy(mesg, dest)
+ const void *mesg; IN: Pointer to the source simple datatype
+ struct
+ const void *dest; IN: Pointer to the destination simple
+ datatype struct
+ RETURNS
+ Pointer to DEST on success, NULL on failure
+ DESCRIPTION
+ This function copies a native (memory) simple datatype message,
+ allocating the destination structure if necessary.
+--------------------------------------------------------------------------*/
+static void *
+H5O_dtype_copy(const void *_src, void *_dst)
+{
+ const H5T_t *src = (const H5T_t *) _src;
+ H5T_t *dst;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(src);
+
+ /* Copy */
+ if(NULL == (dst = H5T_copy(src, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "can't copy type")
+
+ /* Was result already allocated? */
+ if(_dst) {
+ *((H5T_t *) _dst) = *dst;
+ dst = H5FL_FREE(H5T_t, dst);
+ dst = (H5T_t *) _dst;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dst;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_dtype_size
+ PURPOSE
+ Return the raw message size in bytes
+ USAGE
+ void *H5O_dtype_size(f, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source simple datatype struct
+ RETURNS
+ Size of message on success, 0 on failure
+ DESCRIPTION
+ This function returns the size of the raw simple datatype message on
+ success. (Not counting the message type or size fields, only the data
+ portion of the message). It doesn't take into account alignment.
+--------------------------------------------------------------------------*/
+static size_t
+H5O_dtype_size(const H5F_t *f, const void *_mesg)
+{
+ const H5T_t *dt = (const H5T_t *)_mesg;
+ unsigned u; /* Local index variable */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(dt);
+
+ /* Set the common size information */
+ ret_value = 4 + /* Type, class & flags */
+ 4; /* Size of datatype */
+
+ /* Add in the property field length for each datatype class */
+ switch(dt->shared->type) {
+ case H5T_INTEGER:
+ ret_value += 4;
+ break;
+
+ case H5T_FLOAT:
+ ret_value += 12;
+ break;
+
+ case H5T_TIME:
+ ret_value += 2;
+ break;
+
+ case H5T_BITFIELD:
+ ret_value += 4;
+ break;
+
+ case H5T_OPAQUE:
+ ret_value += (HDstrlen(dt->shared->u.opaque.tag) + 7) & (H5T_OPAQUE_TAG_MAX - 8);
+ break;
+
+ case H5T_COMPOUND:
+ {
+ unsigned offset_nbytes; /* Size needed to encode member offsets */
+
+ /* Compute the # of bytes required to store a member offset */
+ offset_nbytes = H5VM_limit_enc_size((uint64_t)dt->shared->size);
+
+ /* Compute the total size needed to encode compound datatype */
+ for(u = 0; u < dt->shared->u.compnd.nmembs; u++) {
+ size_t name_len; /* Length of field's name */
+
+ /* Get length of field's name */
+ name_len = HDstrlen(dt->shared->u.compnd.memb[u].name);
+
+ /* Versions of the format >= 3 don't pad out the name */
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ ret_value += name_len + 1;
+ else
+ ret_value += ((name_len + 8) / 8) * 8;
+
+ /* Check for encoding array datatype or using the latest file format */
+ /* (starting with version 3 of the datatype message, use the minimum # of bytes required) */
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ ret_value += offset_nbytes; /*member offset*/
+ else if(dt->shared->version == H5O_DTYPE_VERSION_2)
+ ret_value += 4; /*member offset*/
+ else
+ ret_value += 4 + /*member offset*/
+ 1 + /*dimensionality*/
+ 3 + /*reserved*/
+ 4 + /*permutation*/
+ 4 + /*reserved*/
+ 16; /*dimensions*/
+ ret_value += H5O_dtype_size(f, dt->shared->u.compnd.memb[u].type);
+ } /* end for */
+ }
+ break;
+
+ case H5T_ENUM:
+ ret_value += H5O_dtype_size(f, dt->shared->parent);
+ for(u = 0; u < dt->shared->u.enumer.nmembs; u++) {
+ size_t name_len; /* Length of field's name */
+
+ /* Get length of field's name */
+ name_len = HDstrlen(dt->shared->u.enumer.name[u]);
+
+ /* Versions of the format >= 3 don't pad out the name */
+ if(dt->shared->version >= H5O_DTYPE_VERSION_3)
+ ret_value += name_len + 1;
+ else
+ ret_value += ((name_len + 8) / 8) * 8;
+ } /* end for */
+ ret_value += dt->shared->u.enumer.nmembs * dt->shared->parent->shared->size;
+ break;
+
+ case H5T_VLEN:
+ ret_value += H5O_dtype_size(f, dt->shared->parent);
+ break;
+
+ case H5T_ARRAY:
+ ret_value += 1; /* ndims */
+ if(dt->shared->version < H5O_DTYPE_VERSION_3)
+ ret_value += 3; /* reserved bytes*/
+ ret_value += 4 * dt->shared->u.array.ndims; /* dimensions */
+ if(dt->shared->version < H5O_DTYPE_VERSION_3)
+ ret_value += 4 * dt->shared->u.array.ndims; /* dimension permutations */
+ ret_value += H5O_dtype_size(f, dt->shared->parent);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_STRING:
+ case H5T_REFERENCE:
+ case H5T_NCLASSES:
+ default:
+ /*no properties */
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_dtype_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_reset
+ *
+ * Purpose: Frees resources within a message, but doesn't free
+ * the message itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_dtype_reset(void *_mesg)
+{
+ H5T_t *dt = (H5T_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(dt)
+ H5T__free(dt);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_dtype_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__dtype_free
+ *
+ * Purpose: Frees the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 30, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__dtype_free(void *mesg)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(mesg);
+
+ /* Release the datatype */
+ if(H5T_close((H5T_t *)mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free datatype")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__dtype_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_set_share
+ *
+ * Purpose: Copies sharing information from SH into the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_dtype_set_share(void *_mesg/*in,out*/, const H5O_shared_t *sh)
+{
+ H5T_t *dt = (H5T_t *)_mesg;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(dt);
+ HDassert(sh);
+
+ /* Make sure the shared message location is initialized, so that it
+ * either has valid sharing information or is set to 0.
+ */
+ HDassert(sh->type <= H5O_SHARE_TYPE_HERE);
+
+ /* Make sure we're not sharing a committed type in the heap */
+ HDassert(sh->type == H5O_SHARE_TYPE_COMMITTED ||
+ (dt->shared->state != H5T_STATE_OPEN && dt->shared->state != H5T_STATE_NAMED));
+
+ /* Copy the shared information */
+ if(H5O_set_shared(&(dt->sh_loc), sh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy shared message info")
+
+ /* If this is now a committed datatype, set its state properly. */
+ if(sh->type == H5O_SHARE_TYPE_COMMITTED) {
+ dt->shared->state = H5T_STATE_NAMED;
+
+ /* Set up the object location for the datatype also */
+ if(H5O_loc_reset(&(dt->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to reset location")
+ dt->oloc.file = sh->file;
+ dt->oloc.addr = sh->u.loc.oh_addr;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_set_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_can_share
+ *
+ * Purpose: Determines if this datatype is allowed to be shared or
+ * not. Immutable datatypes or datatypes that are already
+ * shared cannot be shared (again).
+ *
+ * Return: TRUE if datatype can be shared
+ * FALSE if datatype may not shared
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, October 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_dtype_can_share(const void *_mesg)
+{
+ const H5T_t *mesg = (const H5T_t *)_mesg;
+ htri_t tri_ret;
+ htri_t ret_value = TRUE;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(mesg);
+
+ /* Don't share immutable datatypes */
+ if((tri_ret = H5T_is_immutable(mesg)) > 0)
+ HGOTO_DONE(FALSE)
+ else if(tri_ret < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "can't tell if datatype is immutable")
+
+ /* Don't share committed datatypes */
+ if((tri_ret = H5T_committed(mesg)) > 0)
+ HGOTO_DONE(FALSE)
+ else if(tri_ret < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "can't tell if datatype is shared")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_can_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_dtype_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t H5_ATTR_UNUSED *deleted, const H5O_copy_t H5_ATTR_UNUSED *cpy_info,
+ void *_udata)
+{
+ const H5T_t *dt_src = (const H5T_t *)mesg_src; /* Source datatype */
+ H5D_copy_file_ud_t *udata = (H5D_copy_file_ud_t *)_udata; /* Dataset copying user data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(file_src);
+ HDassert(dt_src);
+
+ /* If the user data is non-NULL, assume we are copying a dataset
+ * and check if we need to make a copy of the datatype for later in
+ * the object copying process. (We currently only need to make a copy
+ * of the datatype if it's a vlen or reference datatype, or if the layout
+ * message is an early version, but since the layout information isn't
+ * available here, we just make a copy in all situations)
+ */
+ if(udata) {
+ /* Create a memory copy of the variable-length datatype */
+ if(NULL == (udata->src_dtype = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy")
+
+ /* Set the location of the source datatype to describe the disk form of the data */
+ if(H5T_set_loc(udata->src_dtype, file_src, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_copy_file
+ *
+ * Purpose: Copy a native datatype message from one file to another.
+ *
+ * Return: Success: Native copy of message
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * December 12, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_dtype_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const H5O_msg_class_t *mesg_type,
+ void *native_src, H5F_t *file_dst, hbool_t H5_ATTR_UNUSED *recompute_size,
+ H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_t *dst_mesg; /* Destination datatype */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Perform a normal copy of the object header message */
+ if(NULL == (dst_mesg = (H5T_t *)H5O_dtype_copy(native_src, NULL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy")
+
+ /* The datatype will be in the new file; set its location. */
+ if(H5T_set_loc(dst_mesg, file_dst, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to set location")
+
+ ret_value = dst_mesg;
+
+done:
+ if(NULL == ret_value)
+ H5O_msg_free(mesg_type->id, dst_mesg);
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_shared_post_copy_upd
+ *
+ * Purpose: Update a message after the shared message operations
+ * during the post-copy loop
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * November 8, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_dtype_shared_post_copy_upd(const H5O_loc_t H5_ATTR_UNUSED *src_oloc,
+ const void H5_ATTR_UNUSED *mesg_src, H5O_loc_t H5_ATTR_UNUSED *dst_oloc, void *mesg_dst,
+ hid_t H5_ATTR_UNUSED dxpl_id, H5O_copy_t H5_ATTR_UNUSED *cpy_info)
+{
+ H5T_t *dt_dst = (H5T_t *)mesg_dst; /* Destination datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(dt_dst->sh_loc.type == H5O_SHARE_TYPE_COMMITTED) {
+ HDassert(H5T_committed(dt_dst));
+ if(H5O_loc_reset(&(dt_dst->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to reset location")
+ dt_dst->oloc.file = dt_dst->sh_loc.file;
+ dt_dst->oloc.addr = dt_dst->sh_loc.u.loc.oh_addr;
+ } /* end if */
+ else
+ HDassert(!H5T_committed(dt_dst));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_shared_post_copy_upd */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_dtype_debug
+ PURPOSE
+ Prints debugging information for a message
+ USAGE
+ void *H5O_dtype_debug(f, mesg, stream, indent, fwidth)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source simple datatype
+ struct
+ FILE *stream; IN: Pointer to the stream for output data
+ int indent; IN: Amount to indent information by
+ int fwidth; IN: Field width (?)
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function prints debugging output to the stream passed as a
+ parameter.
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_dtype_debug(H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5T_t *dt = (const H5T_t*)mesg;
+ const char *s;
+ char buf[256];
+ unsigned i;
+ size_t k;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(dt);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ switch (dt->shared->type) {
+ case H5T_INTEGER:
+ s = "integer";
+ break;
+
+ case H5T_FLOAT:
+ s = "floating-point";
+ break;
+
+ case H5T_TIME:
+ s = "date and time";
+ break;
+
+ case H5T_STRING:
+ s = "text string";
+ break;
+
+ case H5T_BITFIELD:
+ s = "bit field";
+ break;
+
+ case H5T_OPAQUE:
+ s = "opaque";
+ break;
+
+ case H5T_COMPOUND:
+ s = "compound";
+ break;
+
+ case H5T_REFERENCE:
+ s = "reference";
+ break;
+
+ case H5T_ENUM:
+ s = "enum";
+ break;
+
+ case H5T_ARRAY:
+ s = "array";
+ break;
+
+ case H5T_VLEN:
+ s = "vlen";
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ HDsprintf(buf, "H5T_CLASS_%d", (int)(dt->shared->type));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Type class:",
+ s);
+
+ HDfprintf(stream, "%*s%-*s %lu byte%s\n", indent, "", fwidth,
+ "Size:",
+ (unsigned long)(dt->shared->size), 1 == dt->shared->size ? "" : "s");
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Version:", dt->shared->version);
+
+ if (H5T_COMPOUND == dt->shared->type) {
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of members:",
+ dt->shared->u.compnd.nmembs);
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ HDsprintf(buf, "Member %u:", i);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ buf,
+ dt->shared->u.compnd.memb[i].name);
+ HDfprintf(stream, "%*s%-*s %lu\n", indent+3, "", MAX(0, fwidth-3),
+ "Byte offset:",
+ (unsigned long)(dt->shared->u.compnd.memb[i].offset));
+ H5O_dtype_debug(f, dxpl_id, dt->shared->u.compnd.memb[i].type, stream,
+ indent + 3, MAX(0, fwidth - 3));
+ } /* end for */
+ } /* end if */
+ else if(H5T_ENUM == dt->shared->type) {
+ HDfprintf(stream, "%*s%s\n", indent, "", "Base type:");
+ H5O_dtype_debug(f, dxpl_id, dt->shared->parent, stream, indent+3, MAX(0, fwidth-3));
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of members:",
+ dt->shared->u.enumer.nmembs);
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++) {
+ HDsprintf(buf, "Member %u:", i);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ buf,
+ dt->shared->u.enumer.name[i]);
+ HDfprintf(stream, "%*s%-*s 0x", indent, "", fwidth,
+ "Raw bytes of value:");
+ for(k = 0; k < dt->shared->parent->shared->size; k++)
+ HDfprintf(stream, "%02x", dt->shared->u.enumer.value[i*dt->shared->parent->shared->size + k]);
+ HDfprintf(stream, "\n");
+ } /* end for */
+ } /* end else if */
+ else if(H5T_OPAQUE == dt->shared->type) {
+ HDfprintf(stream, "%*s%-*s \"%s\"\n", indent, "", fwidth,
+ "Tag:", dt->shared->u.opaque.tag);
+ } /* end else if */
+ else if(H5T_REFERENCE == dt->shared->type) {
+ HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth,
+ "Fix dumping reference types!");
+ } /* end else if */
+ else if(H5T_STRING == dt->shared->type) {
+ switch(dt->shared->u.atomic.u.s.cset) {
+ case H5T_CSET_ASCII:
+ s = "ASCII";
+ break;
+
+ case H5T_CSET_UTF8:
+ s = "UTF-8";
+ break;
+
+ case H5T_CSET_RESERVED_2:
+ case H5T_CSET_RESERVED_3:
+ case H5T_CSET_RESERVED_4:
+ case H5T_CSET_RESERVED_5:
+ case H5T_CSET_RESERVED_6:
+ case H5T_CSET_RESERVED_7:
+ case H5T_CSET_RESERVED_8:
+ case H5T_CSET_RESERVED_9:
+ case H5T_CSET_RESERVED_10:
+ case H5T_CSET_RESERVED_11:
+ case H5T_CSET_RESERVED_12:
+ case H5T_CSET_RESERVED_13:
+ case H5T_CSET_RESERVED_14:
+ case H5T_CSET_RESERVED_15:
+ HDsprintf(buf, "H5T_CSET_RESERVED_%d", (int)(dt->shared->u.atomic.u.s.cset));
+ s = buf;
+ break;
+
+ case H5T_CSET_ERROR:
+ default:
+ HDsprintf(buf, "Unknown character set: %d", (int)(dt->shared->u.atomic.u.s.cset));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Character Set:",
+ s);
+
+ switch(dt->shared->u.atomic.u.s.pad) {
+ case H5T_STR_NULLTERM:
+ s = "NULL Terminated";
+ break;
+
+ case H5T_STR_NULLPAD:
+ s = "NULL Padded";
+ break;
+
+ case H5T_STR_SPACEPAD:
+ s = "Space Padded";
+ break;
+
+ case H5T_STR_RESERVED_3:
+ case H5T_STR_RESERVED_4:
+ case H5T_STR_RESERVED_5:
+ case H5T_STR_RESERVED_6:
+ case H5T_STR_RESERVED_7:
+ case H5T_STR_RESERVED_8:
+ case H5T_STR_RESERVED_9:
+ case H5T_STR_RESERVED_10:
+ case H5T_STR_RESERVED_11:
+ case H5T_STR_RESERVED_12:
+ case H5T_STR_RESERVED_13:
+ case H5T_STR_RESERVED_14:
+ case H5T_STR_RESERVED_15:
+ HDsprintf(buf, "H5T_STR_RESERVED_%d", (int)(dt->shared->u.atomic.u.s.pad));
+ s = buf;
+ break;
+
+ case H5T_STR_ERROR:
+ default:
+ HDsprintf(buf, "Unknown string padding: %d", (int)(dt->shared->u.atomic.u.s.pad));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "String Padding:",
+ s);
+ } /* end else if */
+ else if(H5T_VLEN == dt->shared->type) {
+ switch(dt->shared->u.vlen.type) {
+ case H5T_VLEN_SEQUENCE:
+ s = "sequence";
+ break;
+
+ case H5T_VLEN_STRING:
+ s = "string";
+ break;
+
+ case H5T_VLEN_BADTYPE:
+ case H5T_VLEN_MAXTYPE:
+ default:
+ HDsprintf(buf, "H5T_VLEN_%d", dt->shared->u.vlen.type);
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Vlen type:", s);
+
+ switch(dt->shared->u.vlen.loc) {
+ case H5T_LOC_MEMORY:
+ s = "memory";
+ break;
+
+ case H5T_LOC_DISK:
+ s = "disk";
+ break;
+
+ case H5T_LOC_BADLOC:
+ case H5T_LOC_MAXLOC:
+ default:
+ HDsprintf(buf, "H5T_LOC_%d", (int)dt->shared->u.vlen.loc);
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Location:", s);
+
+ /* Extra information for VL-strings */
+ if(dt->shared->u.vlen.type == H5T_VLEN_STRING) {
+ switch(dt->shared->u.vlen.cset) {
+ case H5T_CSET_ASCII:
+ s = "ASCII";
+ break;
+
+ case H5T_CSET_UTF8:
+ s = "UTF-8";
+ break;
+
+ case H5T_CSET_RESERVED_2:
+ case H5T_CSET_RESERVED_3:
+ case H5T_CSET_RESERVED_4:
+ case H5T_CSET_RESERVED_5:
+ case H5T_CSET_RESERVED_6:
+ case H5T_CSET_RESERVED_7:
+ case H5T_CSET_RESERVED_8:
+ case H5T_CSET_RESERVED_9:
+ case H5T_CSET_RESERVED_10:
+ case H5T_CSET_RESERVED_11:
+ case H5T_CSET_RESERVED_12:
+ case H5T_CSET_RESERVED_13:
+ case H5T_CSET_RESERVED_14:
+ case H5T_CSET_RESERVED_15:
+ HDsprintf(buf, "H5T_CSET_RESERVED_%d", (int)(dt->shared->u.vlen.cset));
+ s = buf;
+ break;
+
+ case H5T_CSET_ERROR:
+ default:
+ HDsprintf(buf, "Unknown character set: %d", (int)(dt->shared->u.vlen.cset));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Character Set:",
+ s);
+
+ switch(dt->shared->u.vlen.pad) {
+ case H5T_STR_NULLTERM:
+ s = "NULL Terminated";
+ break;
+
+ case H5T_STR_NULLPAD:
+ s = "NULL Padded";
+ break;
+
+ case H5T_STR_SPACEPAD:
+ s = "Space Padded";
+ break;
+
+ case H5T_STR_RESERVED_3:
+ case H5T_STR_RESERVED_4:
+ case H5T_STR_RESERVED_5:
+ case H5T_STR_RESERVED_6:
+ case H5T_STR_RESERVED_7:
+ case H5T_STR_RESERVED_8:
+ case H5T_STR_RESERVED_9:
+ case H5T_STR_RESERVED_10:
+ case H5T_STR_RESERVED_11:
+ case H5T_STR_RESERVED_12:
+ case H5T_STR_RESERVED_13:
+ case H5T_STR_RESERVED_14:
+ case H5T_STR_RESERVED_15:
+ HDsprintf(buf, "H5T_STR_RESERVED_%d", (int)(dt->shared->u.vlen.pad));
+ s = buf;
+ break;
+
+ case H5T_STR_ERROR:
+ default:
+ HDsprintf(buf, "Unknown string padding: %d", (int)(dt->shared->u.vlen.pad));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "String Padding:",
+ s);
+ } /* end if */
+ } /* end else if */
+ else if(H5T_ARRAY == dt->shared->type) {
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Rank:",
+ dt->shared->u.array.ndims);
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Dim Size:");
+ for(i = 0; i < dt->shared->u.array.ndims; i++)
+ HDfprintf(stream, "%s%u", (i ? ", " : ""), (unsigned)dt->shared->u.array.dim[i]);
+ HDfprintf(stream, "}\n");
+ HDfprintf(stream, "%*s%s\n", indent, "", "Base type:");
+ H5O_dtype_debug(f, dxpl_id, dt->shared->parent, stream, indent + 3, MAX(0, fwidth - 3));
+ } /* end else if */
+ else {
+ switch (dt->shared->u.atomic.order) {
+ case H5T_ORDER_LE:
+ s = "little endian";
+ break;
+
+ case H5T_ORDER_BE:
+ s = "big endian";
+ break;
+
+ case H5T_ORDER_VAX:
+ s = "VAX";
+ break;
+
+ case H5T_ORDER_NONE:
+ s = "none";
+ break;
+
+ case H5T_ORDER_MIXED:
+ s = "mixed";
+ break;
+
+ case H5T_ORDER_ERROR:
+ default:
+ HDsprintf(buf, "H5T_ORDER_%d", dt->shared->u.atomic.order);
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Byte order:",
+ s);
+
+ HDfprintf(stream, "%*s%-*s %lu bit%s\n", indent, "", fwidth,
+ "Precision:",
+ (unsigned long)(dt->shared->u.atomic.prec),
+ 1==dt->shared->u.atomic.prec?"":"s");
+
+ HDfprintf(stream, "%*s%-*s %lu bit%s\n", indent, "", fwidth,
+ "Offset:",
+ (unsigned long)(dt->shared->u.atomic.offset),
+ 1==dt->shared->u.atomic.offset?"":"s");
+
+ switch (dt->shared->u.atomic.lsb_pad) {
+ case H5T_PAD_ZERO:
+ s = "zero";
+ break;
+
+ case H5T_PAD_ONE:
+ s = "one";
+ break;
+
+ case H5T_PAD_BACKGROUND:
+ s = "background";
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_NPAD:
+ default:
+ s = "pad?";
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Low pad type:", s);
+
+ switch (dt->shared->u.atomic.msb_pad) {
+ case H5T_PAD_ZERO:
+ s = "zero";
+ break;
+
+ case H5T_PAD_ONE:
+ s = "one";
+ break;
+
+ case H5T_PAD_BACKGROUND:
+ s = "background";
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_NPAD:
+ default:
+ s = "pad?";
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "High pad type:", s);
+
+ if (H5T_FLOAT == dt->shared->type) {
+ switch (dt->shared->u.atomic.u.f.pad) {
+ case H5T_PAD_ZERO:
+ s = "zero";
+ break;
+
+ case H5T_PAD_ONE:
+ s = "one";
+ break;
+
+ case H5T_PAD_BACKGROUND:
+ s = "background";
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_NPAD:
+ default:
+ if (dt->shared->u.atomic.u.f.pad < 0)
+ HDsprintf(buf, "H5T_PAD_%d", -(dt->shared->u.atomic.u.f.pad));
+ else
+ HDsprintf(buf, "bit-%d", dt->shared->u.atomic.u.f.pad);
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Internal pad type:", s);
+
+ switch (dt->shared->u.atomic.u.f.norm) {
+ case H5T_NORM_IMPLIED:
+ s = "implied";
+ break;
+
+ case H5T_NORM_MSBSET:
+ s = "msb set";
+ break;
+
+ case H5T_NORM_NONE:
+ s = "none";
+ break;
+
+ case H5T_NORM_ERROR:
+ default:
+ HDsprintf(buf, "H5T_NORM_%d", (int) (dt->shared->u.atomic.u.f.norm));
+ s = buf;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Normalization:", s);
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Sign bit location:",
+ (unsigned long) (dt->shared->u.atomic.u.f.sign));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Exponent location:",
+ (unsigned long) (dt->shared->u.atomic.u.f.epos));
+
+ HDfprintf(stream, "%*s%-*s 0x%08lx\n", indent, "", fwidth,
+ "Exponent bias:",
+ (unsigned long) (dt->shared->u.atomic.u.f.ebias));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Exponent size:",
+ (unsigned long) (dt->shared->u.atomic.u.f.esize));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Mantissa location:",
+ (unsigned long) (dt->shared->u.atomic.u.f.mpos));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Mantissa size:",
+ (unsigned long) (dt->shared->u.atomic.u.f.msize));
+
+ } /* end if */
+ else if (H5T_INTEGER == dt->shared->type) {
+ switch (dt->shared->u.atomic.u.i.sign) {
+ case H5T_SGN_NONE:
+ s = "none";
+ break;
+
+ case H5T_SGN_2:
+ s = "2's comp";
+ break;
+
+ case H5T_SGN_ERROR:
+ case H5T_NSGN:
+ default:
+ HDsprintf(buf, "H5T_SGN_%d", (int) (dt->shared->u.atomic.u.i.sign));
+ s = buf;
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Sign scheme:", s);
+ } /* end else if */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_dtype_debug() */
+
diff --git a/src/H5Oefl.c b/src/H5Oefl.c
new file mode 100644
index 0000000..0456b00
--- /dev/null
+++ b/src/H5Oefl.c
@@ -0,0 +1,574 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Tuesday, November 25, 1997
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_efl_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_efl_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_efl_copy(const void *_mesg, void *_dest);
+static size_t H5O_efl_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_efl_reset(void *_mesg);
+static void *H5O_efl_copy_file(H5F_t *file_src, void *mesg_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_efl_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_EFL[1] = {{
+ H5O_EFL_ID, /*message id number */
+ "external file list", /*message name for debugging */
+ sizeof(H5O_efl_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_efl_decode, /*decode message */
+ H5O_efl_encode, /*encode message */
+ H5O_efl_copy, /*copy native value */
+ H5O_efl_size, /*size of message on disk */
+ H5O_efl_reset, /*reset method */
+ NULL, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ H5O_efl_copy_file, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_efl_debug /*debug the message */
+}};
+
+#define H5O_EFL_VERSION 1
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_decode
+ *
+ * Purpose: Decode an external file list message and return a pointer to
+ * the message (and some other data).
+ *
+ * Return: Success: Ptr to a new message struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ * Modification:
+ * Raymond Lu
+ * 11 April 2011
+ * We allow zero dimension size starting from the 1.8.7 release.
+ * The dataset size of external storage can be zero.
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_efl_decode(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_efl_t *mesg = NULL;
+ int version;
+ const char *s = NULL;
+ H5HL_t *heap;
+ size_t u; /* Local index variable */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(p);
+
+ if(NULL == (mesg = (H5O_efl_t *)H5MM_calloc(sizeof(H5O_efl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Version */
+ version = *p++;
+ if(version != H5O_EFL_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for external file list message")
+
+ /* Reserved */
+ p += 3;
+
+ /* Number of slots */
+ UINT16DECODE(p, mesg->nalloc);
+ HDassert(mesg->nalloc>0);
+ UINT16DECODE(p, mesg->nused);
+ HDassert(mesg->nused <= mesg->nalloc);
+
+ /* Heap address */
+ H5F_addr_decode(f, &p, &(mesg->heap_addr));
+
+#ifndef NDEBUG
+ HDassert(H5F_addr_defined(mesg->heap_addr));
+
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value")
+
+ s = (const char *)H5HL_offset_into(heap, 0);
+
+ HDassert(s && !*s);
+
+ if(H5HL_unprotect(heap) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read unprotect link value")
+ heap = NULL;
+#endif
+
+ /* Decode the file list */
+ mesg->slot = (H5O_efl_entry_t *)H5MM_calloc(mesg->nalloc * sizeof(H5O_efl_entry_t));
+ if(NULL == mesg->slot)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value")
+ for(u = 0; u < mesg->nused; u++) {
+ /* Name */
+ H5F_DECODE_LENGTH (f, p, mesg->slot[u].name_offset);
+
+ s = (const char *)H5HL_offset_into(heap, mesg->slot[u].name_offset);
+ HDassert(s && *s);
+ mesg->slot[u].name = H5MM_xstrdup (s);
+ HDassert(mesg->slot[u].name);
+
+ /* File offset */
+ H5F_DECODE_LENGTH (f, p, mesg->slot[u].offset);
+
+ /* Size */
+ H5F_DECODE_LENGTH (f, p, mesg->slot[u].size);
+ } /* end for */
+
+ if(H5HL_unprotect(heap) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read unprotect link value")
+ heap = NULL;
+
+ /* Set return value */
+ ret_value = mesg;
+
+done:
+ if(ret_value == NULL)
+ if(mesg != NULL)
+ H5MM_xfree(mesg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_efl_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_efl_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_efl_t *mesg = (const H5O_efl_t *)_mesg;
+ size_t u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(p);
+
+ /* Version */
+ *p++ = H5O_EFL_VERSION;
+
+ /* Reserved */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+
+ /* Number of slots */
+ HDassert(mesg->nalloc > 0);
+ UINT16ENCODE(p, mesg->nused); /*yes, twice*/
+ HDassert(mesg->nused > 0 && mesg->nused <= mesg->nalloc);
+ UINT16ENCODE(p, mesg->nused);
+
+ /* Heap address */
+ HDassert(H5F_addr_defined(mesg->heap_addr));
+ H5F_addr_encode(f, &p, mesg->heap_addr);
+
+ /* Encode file list */
+ for(u = 0; u < mesg->nused; u++) {
+ /*
+ * The name should have been added to the heap when the dataset was
+ * created.
+ */
+ HDassert(mesg->slot[u].name_offset);
+ H5F_ENCODE_LENGTH(f, p, mesg->slot[u].name_offset);
+ H5F_ENCODE_LENGTH(f, p, (hsize_t)mesg->slot[u].offset);
+ H5F_ENCODE_LENGTH(f, p, mesg->slot[u].size);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_efl_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_efl_copy(const void *_mesg, void *_dest)
+{
+ const H5O_efl_t *mesg = (const H5O_efl_t *) _mesg;
+ H5O_efl_t *dest = (H5O_efl_t *) _dest;
+ size_t u; /* Local index variable */
+ hbool_t slot_allocated = FALSE; /* Flag to indicate that dynamic allocation has begun */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(mesg);
+
+ /* Allocate destination message, if necessary */
+ if(!dest && NULL == (dest = (H5O_efl_t *)H5MM_calloc(sizeof(H5O_efl_t))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't allocate efl message")
+
+ /* copy */
+ *dest = *mesg;
+
+ /* Deep copy allocated information */
+ if(dest->nalloc > 0) {
+ if(NULL == (dest->slot = (H5O_efl_entry_t *)H5MM_calloc(dest->nalloc * sizeof(H5O_efl_entry_t))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't allocate efl message slots")
+ slot_allocated = TRUE;
+ for(u = 0; u < mesg->nused; u++) {
+ dest->slot[u] = mesg->slot[u];
+ if(NULL == (dest->slot[u].name = H5MM_xstrdup(mesg->slot[u].name)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't allocate efl message slot name")
+ } /* end for */
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ if(NULL == ret_value) {
+ if(slot_allocated) {
+ for(u = 0; u < dest->nused; u++)
+ if(dest->slot[u].name != NULL && dest->slot[u].name != mesg->slot[u].name)
+ dest->slot[u].name = (char *)H5MM_xfree(dest->slot[u].name);
+ dest->slot = (H5O_efl_entry_t *)H5MM_xfree(dest->slot);
+ } /* end if */
+ if(NULL == _dest)
+ dest = (H5O_efl_t *)H5MM_xfree(dest);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_efl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields. This
+ * function doesn't take into account message alignment. This
+ * function doesn't count unused slots.
+ *
+ * Return: Success: Message data size in bytes.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_efl_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_efl_t *mesg = (const H5O_efl_t *) _mesg;
+ size_t ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ ret_value = (size_t)H5F_SIZEOF_ADDR(f) + /*heap address */
+ 2 + /*slots allocated*/
+ 2 + /*num slots used*/
+ 4 + /*reserved */
+ mesg->nused * ((size_t)H5F_SIZEOF_SIZE(f) + /*name offset */
+ (size_t)H5F_SIZEOF_SIZE(f) + /*file offset */
+ (size_t)H5F_SIZEOF_SIZE(f)); /*file size */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_efl_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_reset
+ *
+ * Purpose: Frees internal pointers and resets the message to an
+ * initialial state.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_efl_reset(void *_mesg)
+{
+ H5O_efl_t *mesg = (H5O_efl_t *) _mesg;
+ size_t u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(mesg);
+
+ /* reset */
+ if(mesg->slot) {
+ for(u = 0; u < mesg->nused; u++) {
+ mesg->slot[u].name = (char *)H5MM_xfree(mesg->slot[u].name);
+ mesg->slot[u].name_offset = 0;
+ } /* end for */
+ mesg->slot = (H5O_efl_entry_t *)H5MM_xfree(mesg->slot);
+ } /* end if */
+ mesg->heap_addr = HADDR_UNDEF;
+ mesg->nused = mesg->nalloc = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_efl_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_total_size
+ *
+ * Purpose: Return the total size of the external file list by summing
+ * the sizes of all of the files.
+ *
+ * Return: Success: Total reserved size for external data.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5O_efl_total_size (H5O_efl_t *efl)
+{
+ hsize_t ret_value = 0, tmp;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(efl->nused > 0 && H5O_EFL_UNLIMITED == efl->slot[efl->nused - 1].size)
+ ret_value = H5O_EFL_UNLIMITED;
+ else {
+ size_t u; /* Local index variable */
+
+ for(u = 0; u < efl->nused; u++, ret_value = tmp) {
+ tmp = ret_value + efl->slot[u].size;
+ if(tmp <= ret_value)
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, 0, "total external storage size overflowed");
+ } /* end for */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_efl_total_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_copy_file
+ *
+ * Purpose: Copies an efl message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Peter Cao
+ * September 29, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_efl_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *mesg_src, H5F_t *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *_udata, hid_t dxpl_id)
+{
+ H5O_efl_t *efl_src = (H5O_efl_t *) mesg_src;
+ H5O_efl_t *efl_dst = NULL;
+ H5HL_t *heap = NULL; /* Pointer to local heap for EFL file names */
+ size_t idx, size, name_offset, heap_size;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__COPIED_TAG, NULL)
+
+ /* check args */
+ HDassert(efl_src);
+ HDassert(file_dst);
+
+ /* Allocate space for the destination efl */
+ if(NULL == (efl_dst = (H5O_efl_t *)H5MM_calloc(sizeof(H5O_efl_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the "top level" information */
+ HDmemcpy(efl_dst, efl_src, sizeof(H5O_efl_t));
+
+ /* Determine size needed for destination heap */
+ heap_size = H5HL_ALIGN(1); /* "empty" name */
+ for(idx = 0; idx < efl_src->nused; idx++)
+ heap_size += H5HL_ALIGN(HDstrlen(efl_src->slot[idx].name) + 1);
+
+ /* Create name heap */
+ if(H5HL_create(file_dst, dxpl_id, heap_size, &efl_dst->heap_addr/*out*/) < 0)
+ HGOTO_ERROR(H5E_EFL, H5E_CANTINIT, NULL, "can't create heap")
+
+ /* Pin the heap down in memory */
+ if(NULL == (heap = H5HL_protect(file_dst, dxpl_id, efl_dst->heap_addr, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_EFL, H5E_PROTECT, NULL, "unable to protect EFL file name heap")
+
+ /* Insert "empty" name first */
+ if(UFAIL == (name_offset = H5HL_insert(file_dst, dxpl_id, heap, (size_t)1, "")))
+ HGOTO_ERROR(H5E_EFL, H5E_CANTINSERT, NULL, "can't insert file name into heap")
+ HDassert(0 == name_offset);
+
+ /* allocate array of external file entries */
+ if(efl_src->nalloc > 0) {
+ size = efl_src->nalloc * sizeof(H5O_efl_entry_t);
+ if((efl_dst->slot = (H5O_efl_entry_t *)H5MM_calloc(size)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy content from the source. Need to update later */
+ HDmemcpy(efl_dst->slot, efl_src->slot, size);
+ } /* end if */
+
+ /* copy the name from the source */
+ for(idx = 0; idx < efl_src->nused; idx++) {
+ efl_dst->slot[idx].name = H5MM_xstrdup(efl_src->slot[idx].name);
+ if(UFAIL == (efl_dst->slot[idx].name_offset = H5HL_insert(file_dst, dxpl_id, heap,
+ HDstrlen(efl_dst->slot[idx].name) + 1, efl_dst->slot[idx].name)))
+ HGOTO_ERROR(H5E_EFL, H5E_CANTINSERT, NULL, "can't insert file name into heap")
+ } /* end for */
+
+ /* Set return value */
+ ret_value = efl_dst;
+
+done:
+ /* Release resources */
+ if(heap && H5HL_unprotect(heap) < 0)
+ HDONE_ERROR(H5E_EFL, H5E_PROTECT, NULL, "unable to unprotect EFL file name heap")
+ if(!ret_value)
+ if(efl_dst)
+ H5MM_xfree(efl_dst);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_efl_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_efl_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, November 25, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_efl_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_efl_t *mesg = (const H5O_efl_t *) _mesg;
+ size_t u;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Heap address:", mesg->heap_addr);
+
+ HDfprintf(stream, "%*s%-*s %u/%u\n", indent, "", fwidth,
+ "Slots used/allocated:",
+ mesg->nused, mesg->nalloc);
+
+ for(u = 0; u < mesg->nused; u++) {
+ char buf[64];
+
+ HDsnprintf(buf, sizeof(buf), "File %u", (unsigned)u);
+ HDfprintf(stream, "%*s%s:\n", indent, "", buf);
+
+ HDfprintf(stream, "%*s%-*s \"%s\"\n", indent+3, "", MAX (fwidth-3, 0),
+ "Name:",
+ mesg->slot[u].name);
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent+3, "", MAX (fwidth-3, 0),
+ "Name offset:",
+ (unsigned long)(mesg->slot[u].name_offset));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent+3, "", MAX (fwidth-3, 0),
+ "Offset of data in file:",
+ (unsigned long)(mesg->slot[u].offset));
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent+3, "", MAX (fwidth-3, 0),
+ "Bytes reserved for data:",
+ (unsigned long)(mesg->slot[u].size));
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_efl_debug() */
+
diff --git a/src/H5Ofill.c b/src/H5Ofill.c
new file mode 100644
index 0000000..5419762
--- /dev/null
+++ b/src/H5Ofill.c
@@ -0,0 +1,1024 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, September 30, 1998
+ *
+ * Purpose: The fill message indicates a bit pattern to use for
+ * uninitialized data points of a dataset.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Sprivate.h" /* Dataspaces */
+
+
+static void *H5O_fill_old_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_fill_old_encode(H5F_t *f, uint8_t *p, const void *_mesg);
+static size_t H5O_fill_old_size(const H5F_t *f, const void *_mesg);
+static void *H5O_fill_new_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_fill_new_encode(H5F_t *f, uint8_t *p, const void *_mesg);
+static size_t H5O_fill_new_size(const H5F_t *f, const void *_mesg);
+static void *H5O_fill_copy(const void *_mesg, void *_dest);
+static herr_t H5O_fill_reset(void *_mesg);
+static herr_t H5O_fill_free(void *_mesg);
+static herr_t H5O_fill_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* Set up & include shared message "interface" info */
+#define H5O_SHARED_TYPE H5O_MSG_FILL
+#define H5O_SHARED_DECODE H5O_fill_shared_decode
+#define H5O_SHARED_DECODE_REAL H5O_fill_old_decode
+#define H5O_SHARED_ENCODE H5O_fill_shared_encode
+#define H5O_SHARED_ENCODE_REAL H5O_fill_old_encode
+#define H5O_SHARED_SIZE H5O_fill_shared_size
+#define H5O_SHARED_SIZE_REAL H5O_fill_old_size
+#define H5O_SHARED_DELETE H5O_fill_shared_delete
+#undef H5O_SHARED_DELETE_REAL
+#define H5O_SHARED_LINK H5O_fill_shared_link
+#undef H5O_SHARED_LINK_REAL
+#define H5O_SHARED_COPY_FILE H5O_fill_shared_copy_file
+#undef H5O_SHARED_COPY_FILE_REAL
+#define H5O_SHARED_POST_COPY_FILE H5O_fill_shared_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_REAL
+#undef H5O_SHARED_POST_COPY_FILE_UPD
+#define H5O_SHARED_DEBUG H5O_fill_shared_debug
+#define H5O_SHARED_DEBUG_REAL H5O_fill_debug
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* Set up & include shared message "interface" info */
+/* (Kludgy 'undef's in order to re-include the H5Oshared.h header) */
+#undef H5O_SHARED_TYPE
+#define H5O_SHARED_TYPE H5O_MSG_FILL_NEW
+#undef H5O_SHARED_DECODE
+#define H5O_SHARED_DECODE H5O_fill_new_shared_decode
+#undef H5O_SHARED_DECODE_REAL
+#define H5O_SHARED_DECODE_REAL H5O_fill_new_decode
+#undef H5O_SHARED_ENCODE
+#define H5O_SHARED_ENCODE H5O_fill_new_shared_encode
+#undef H5O_SHARED_ENCODE_REAL
+#define H5O_SHARED_ENCODE_REAL H5O_fill_new_encode
+#undef H5O_SHARED_SIZE
+#define H5O_SHARED_SIZE H5O_fill_new_shared_size
+#undef H5O_SHARED_SIZE_REAL
+#define H5O_SHARED_SIZE_REAL H5O_fill_new_size
+#undef H5O_SHARED_DELETE
+#define H5O_SHARED_DELETE H5O_fill_new_shared_delete
+#undef H5O_SHARED_DELETE_REAL
+#undef H5O_SHARED_LINK
+#define H5O_SHARED_LINK H5O_fill_new_shared_link
+#undef H5O_SHARED_LINK_REAL
+#undef H5O_SHARED_COPY_FILE
+#define H5O_SHARED_COPY_FILE H5O_fill_new_shared_copy_file
+#undef H5O_SHARED_COPY_FILE_REAL
+#undef H5O_SHARED_POST_COPY_FILE
+#define H5O_SHARED_POST_COPY_FILE H5O_fill_new_shared_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_REAL
+#undef H5O_SHARED_POST_COPY_FILE_UPD
+#undef H5O_SHARED_DEBUG
+#define H5O_SHARED_DEBUG H5O_fill_new_shared_debug
+#undef H5O_SHARED_DEBUG_REAL
+#define H5O_SHARED_DEBUG_REAL H5O_fill_debug
+#undef H5Oshared_H
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* This message derives from H5O message class, for old fill value before version 1.5 */
+const H5O_msg_class_t H5O_MSG_FILL[1] = {{
+ H5O_FILL_ID, /*message id number */
+ "fill", /*message name for debugging */
+ sizeof(H5O_fill_t), /*native message size */
+ H5O_SHARE_IS_SHARABLE|H5O_SHARE_IN_OHDR, /* messages are sharable? */
+ H5O_fill_shared_decode, /*decode message */
+ H5O_fill_shared_encode, /*encode message */
+ H5O_fill_copy, /*copy the native value */
+ H5O_fill_shared_size, /*raw message size */
+ H5O_fill_reset, /*free internal memory */
+ H5O_fill_free, /* free method */
+ H5O_fill_shared_delete, /* file delete method */
+ H5O_fill_shared_link, /* link method */
+ NULL, /* set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ H5O_fill_shared_copy_file, /* copy native value to file */
+ H5O_fill_shared_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_fill_shared_debug /*debug the message */
+}};
+
+/* This message derives from H5O message class, for new fill value after version 1.4 */
+const H5O_msg_class_t H5O_MSG_FILL_NEW[1] = {{
+ H5O_FILL_NEW_ID, /*message id number */
+ "fill_new", /*message name for debugging */
+ sizeof(H5O_fill_t), /*native message size */
+ H5O_SHARE_IS_SHARABLE|H5O_SHARE_IN_OHDR, /* messages are sharable? */
+ H5O_fill_new_shared_decode, /*decode message */
+ H5O_fill_new_shared_encode, /*encode message */
+ H5O_fill_copy, /*copy the native value */
+ H5O_fill_new_shared_size, /*raw message size */
+ H5O_fill_reset, /*free internal memory */
+ H5O_fill_free, /* free method */
+ H5O_fill_new_shared_delete, /* file delete method */
+ H5O_fill_new_shared_link, /* link method */
+ NULL, /* set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ H5O_fill_new_shared_copy_file, /* copy native value to file */
+ H5O_fill_new_shared_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_fill_new_shared_debug /*debug the message */
+}};
+
+/* Masks, shift values & flags for fill value message */
+#define H5O_FILL_MASK_ALLOC_TIME 0x03
+#define H5O_FILL_SHIFT_ALLOC_TIME 0
+#define H5O_FILL_MASK_FILL_TIME 0x03
+#define H5O_FILL_SHIFT_FILL_TIME 2
+#define H5O_FILL_FLAG_UNDEFINED_VALUE 0x10
+#define H5O_FILL_FLAG_HAVE_VALUE 0x20
+#define H5O_FILL_FLAGS_ALL (H5O_FILL_MASK_ALLOC_TIME | (H5O_FILL_MASK_FILL_TIME << H5O_FILL_SHIFT_FILL_TIME) | H5O_FILL_FLAG_UNDEFINED_VALUE | H5O_FILL_FLAG_HAVE_VALUE)
+
+/* Declare a free list to manage the H5O_fill_t struct */
+H5FL_DEFINE(H5O_fill_t);
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_new_decode
+ *
+ * Purpose: Decode a new fill value message. The new fill value
+ * message is fill value plus space allocation time and
+ * fill value writing time and whether fill value is defined.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * Feb 26, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_fill_new_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_fill_t *fill = NULL;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(f);
+ HDassert(p);
+
+ if(NULL == (fill = H5FL_CALLOC(H5O_fill_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value message")
+
+ /* Version */
+ fill->version = *p++;
+ if(fill->version < H5O_FILL_VERSION_1 || fill->version > H5O_FILL_VERSION_LATEST)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for fill value message")
+
+ /* Decode each version */
+ if(fill->version < H5O_FILL_VERSION_3) {
+ /* Space allocation time */
+ fill->alloc_time = (H5D_alloc_time_t)*p++;
+
+ /* Fill value write time */
+ fill->fill_time = (H5D_fill_time_t)*p++;
+
+ /* Whether fill value is defined */
+ fill->fill_defined = *p++;
+
+ /* Only decode fill value information if one is defined */
+ if(fill->fill_defined) {
+ INT32DECODE(p, fill->size);
+ if(fill->size > 0) {
+ H5_CHECK_OVERFLOW(fill->size, ssize_t, size_t);
+ if(NULL == (fill->buf = H5MM_malloc((size_t)fill->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value")
+ HDmemcpy(fill->buf, p, (size_t)fill->size);
+ } /* end if */
+ } /* end if */
+ else
+ fill->size = (-1);
+ } /* end if */
+ else {
+ unsigned flags; /* Status flags */
+
+ /* Flags */
+ flags = *p++;
+
+ /* Check for unknown flags */
+ if(flags & (unsigned)~H5O_FILL_FLAGS_ALL)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown flag for fill value message")
+
+ /* Space allocation time */
+ fill->alloc_time = (H5D_alloc_time_t)((flags >> H5O_FILL_SHIFT_ALLOC_TIME) & H5O_FILL_MASK_ALLOC_TIME);
+
+ /* Fill value write time */
+ fill->fill_time = (H5D_fill_time_t)((flags >> H5O_FILL_SHIFT_FILL_TIME) & H5O_FILL_MASK_FILL_TIME);
+
+ /* Check for undefined fill value */
+ if(flags & H5O_FILL_FLAG_UNDEFINED_VALUE) {
+ /* Sanity check */
+ HDassert(!(flags & H5O_FILL_FLAG_HAVE_VALUE));
+
+ /* Set value for "undefined" fill value */
+ fill->size = (-1);
+ } /* end if */
+ else if(flags & H5O_FILL_FLAG_HAVE_VALUE) {
+ /* Fill value size */
+ UINT32DECODE(p, fill->size);
+
+ /* Fill value */
+ H5_CHECK_OVERFLOW(fill->size, ssize_t, size_t);
+ if(NULL == (fill->buf = H5MM_malloc((size_t)fill->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value")
+ HDmemcpy(fill->buf, p, (size_t)fill->size);
+
+ /* Set the "defined" flag */
+ fill->fill_defined = TRUE;
+ } /* end else */
+ else {
+ /* Set the "defined" flag */
+ fill->fill_defined = TRUE;
+ } /* end else */
+ } /* end else */
+
+ /* Set return value */
+ ret_value = (void *)fill;
+
+done:
+ if(!ret_value && fill) {
+ if(fill->buf)
+ H5MM_xfree(fill->buf);
+ fill = H5FL_FREE(H5O_fill_t, fill);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_new_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_old_decode
+ *
+ * Purpose: Decode an old fill value message.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_fill_old_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_fill_t *fill = NULL; /* Decoded fill value message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(f);
+ HDassert(p);
+
+ if(NULL == (fill = H5FL_CALLOC(H5O_fill_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value message")
+
+ /* Set non-zero default fields */
+ fill->version = H5O_FILL_VERSION_2;
+ fill->alloc_time = H5D_ALLOC_TIME_LATE;
+ fill->fill_time = H5D_FILL_TIME_IFSET;
+
+ /* Fill value size */
+ UINT32DECODE(p, fill->size);
+
+ /* Only decode the fill value itself if there is one */
+ if(fill->size > 0) {
+ if(NULL == (fill->buf = H5MM_malloc((size_t)fill->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value")
+ HDmemcpy(fill->buf, p, (size_t)fill->size);
+ fill->fill_defined = TRUE;
+ } /* end if */
+ else
+ fill->size = (-1);
+
+ /* Set return value */
+ ret_value = (void*)fill;
+
+done:
+ if(!ret_value && fill) {
+ if(fill->buf)
+ H5MM_xfree(fill->buf);
+ fill = H5FL_FREE(H5O_fill_t, fill);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_old_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_new_encode
+ *
+ * Purpose: Encode a new fill value message. The new fill value
+ * message is fill value plus space allocation time and
+ * fill value writing time and whether fill value is defined.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Feb 26, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fill_new_encode(H5F_t H5_ATTR_UNUSED *f, uint8_t *p, const void *_fill)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)_fill;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(p);
+ HDassert(fill && NULL == fill->type);
+
+ /* Version */
+ *p++ = (uint8_t)fill->version;
+
+ if(fill->version < H5O_FILL_VERSION_3) {
+ /* Space allocation time */
+ *p++ = fill->alloc_time;
+
+ /* Fill value writing time */
+ *p++ = fill->fill_time;
+
+ /* Whether fill value is defined */
+ *p++ = (uint8_t)fill->fill_defined;
+
+ /* Only write out the size and fill value if it is defined */
+ if(fill->fill_defined) {
+ UINT32ENCODE(p, fill->size);
+ if(fill->size > 0)
+ if(fill->buf) {
+ H5_CHECK_OVERFLOW(fill->size, ssize_t, size_t);
+ HDmemcpy(p, fill->buf, (size_t)fill->size);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ else {
+ uint8_t flags = 0; /* Fill value setting flags */
+
+ /* Encode space allocation time */
+ HDassert(fill->alloc_time == (H5O_FILL_MASK_ALLOC_TIME & fill->alloc_time));
+ flags = (uint8_t)(flags | ((H5O_FILL_MASK_ALLOC_TIME & fill->alloc_time) << H5O_FILL_SHIFT_ALLOC_TIME));
+
+ /* Encode fill value writing time */
+ HDassert(fill->fill_time == (H5O_FILL_MASK_FILL_TIME & fill->fill_time));
+ flags = (uint8_t)(flags | ((H5O_FILL_MASK_FILL_TIME & fill->fill_time) << H5O_FILL_SHIFT_FILL_TIME));
+
+ /* Check if we need to encode a fill value size */
+ if(fill->size < 0) {
+ /* Indicate that the fill value has been "undefined" by the user */
+ flags |= H5O_FILL_FLAG_UNDEFINED_VALUE;
+
+ /* Flags */
+ *p++ = (uint8_t)flags;
+
+ /* Sanity check */
+ HDassert(!fill->buf);
+ } /* end if */
+ else if(fill->size > 0) {
+ /* Indicate that a fill value size is present */
+ flags |= H5O_FILL_FLAG_HAVE_VALUE;
+
+ /* Flags */
+ *p++ = (uint8_t)flags;
+
+ /* Encode the size of fill value */
+ INT32ENCODE(p, fill->size);
+
+ /* Encode the fill value */
+ HDassert(fill->buf);
+ H5_CHECK_OVERFLOW(fill->size, ssize_t, size_t);
+ HDmemcpy(p, fill->buf, (size_t)fill->size);
+ } /* end if */
+ else {
+ /* Flags */
+ *p++ = (uint8_t)flags;
+
+ /* Sanity check */
+ HDassert(!fill->buf);
+ } /* end else */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_new_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_old_encode
+ *
+ * Purpose: Encode an old fill value message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fill_old_encode(H5F_t H5_ATTR_UNUSED *f, uint8_t *p, const void *_fill)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)_fill;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(p);
+ HDassert(fill && NULL == fill->type);
+
+ UINT32ENCODE(p, fill->size);
+ if(fill->buf)
+ HDmemcpy(p, fill->buf, (size_t)fill->size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_old_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary. The new fill value message is fill value plus
+ * space allocation time and fill value writing time and
+ * whether fill value is defined.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * Feb 26, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_fill_copy(const void *_src, void *_dst)
+{
+ const H5O_fill_t *src = (const H5O_fill_t *)_src;
+ H5O_fill_t *dst = (H5O_fill_t *)_dst;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(src);
+
+ if(!dst && NULL == (dst = H5FL_MALLOC(H5O_fill_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill message")
+
+ /* Shallow copy basic fields */
+ *dst = *src;
+
+ /* Copy data type of fill value */
+ if(src->type) {
+ if(NULL == (dst->type = H5T_copy(src->type, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "can't copy datatype")
+ } /* end if */
+ else
+ dst->type = NULL;
+
+ /* Copy fill value and its size */
+ if(src->buf) {
+ H5_CHECK_OVERFLOW(src->size, ssize_t, size_t);
+ if(NULL == (dst->buf = H5MM_malloc((size_t)src->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fill value")
+ HDmemcpy(dst->buf, src->buf, (size_t)src->size);
+
+ /* Check for needing to convert/copy fill value */
+ if(src->type) {
+ H5T_path_t *tpath; /* Conversion information */
+
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(src->type, dst->type, NULL, NULL, H5AC_noio_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_UNSUPPORTED, NULL, "unable to convert between src and dst data types")
+
+ /* If necessary, convert fill value datatypes (which copies VL components, etc.) */
+ if(!H5T_path_noop(tpath)) {
+ hid_t dst_id, src_id; /* Source & destination datatypes for type conversion */
+ uint8_t *bkg_buf = NULL; /* Background conversion buffer */
+ size_t bkg_size; /* Size of background buffer */
+
+ /* Wrap copies of types to convert */
+ dst_id = H5I_register(H5I_DATATYPE, H5T_copy(dst->type, H5T_COPY_TRANSIENT), FALSE);
+ if(dst_id < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy/register datatype")
+ src_id = H5I_register(H5I_DATATYPE, H5T_copy(src->type, H5T_COPY_ALL), FALSE);
+ if(src_id < 0) {
+ H5I_dec_ref(dst_id);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy/register datatype")
+ } /* end if */
+
+ /* Allocate a background buffer */
+ bkg_size = MAX(H5T_get_size(dst->type), H5T_get_size(src->type));
+ if(H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size))) {
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ } /* end if */
+
+ /* Convert fill value */
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, dst->buf, bkg_buf, H5AC_noio_dxpl_id) < 0) {
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCONVERT, NULL, "datatype conversion failed")
+ } /* end if */
+
+ /* Release the background buffer */
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ else
+ dst->buf = NULL;
+
+ /* Set return value */
+ ret_value = dst;
+
+done:
+ if(!ret_value && dst) {
+ if(dst->buf)
+ H5MM_xfree(dst->buf);
+ if(dst->type)
+ H5T_close(dst->type);
+ if(!_dst)
+ dst = H5FL_FREE(H5O_fill_t, dst);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_new_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields. This
+ * function doesn't take into account alignment. The new fill
+ * value message is fill value plus space allocation time and
+ * fill value writing time and whether fill value is defined.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ * Failure: 0
+ *
+ * Programmer: Raymond Lu
+ * Feb 26, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_fill_new_size(const H5F_t H5_ATTR_UNUSED *f, const void *_fill)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)_fill;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(fill);
+
+ /* Determine size for different versions */
+ if(fill->version < H5O_FILL_VERSION_3) {
+ ret_value = 1 + /* Version number */
+ 1 + /* Space allocation time */
+ 1 + /* Fill value write time */
+ 1; /* Fill value defined */
+ if(fill->fill_defined)
+ ret_value += 4 + /* Fill value size */
+ (fill->size > 0 ? (size_t)fill->size : 0); /* Size of fill value */
+ } /* end if */
+ else {
+ ret_value = 1 + /* Version number */
+ 1; /* Status flags */
+ if(fill->size > 0)
+ ret_value += 4 + /* Fill value size */
+ (size_t)fill->size; /* Size of fill value */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_new_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_old_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields. This
+ * function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_fill_old_size(const H5F_t H5_ATTR_UNUSED *f, const void *_fill)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)_fill;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(fill);
+
+ FUNC_LEAVE_NOAPI(4 + (size_t)fill->size)
+} /* end H5O_fill_old_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_reset_dyn
+ *
+ * Purpose: Resets dynamic fill value fields
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, January 22, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_fill_reset_dyn(H5O_fill_t *fill)
+{
+ hid_t fill_type_id = -1; /* Datatype ID for fill value datatype when reclaiming VL fill values */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fill);
+
+ if(fill->buf) {
+ if(fill->type && H5T_detect_class(fill->type, H5T_VLEN, FALSE) > 0) {
+ H5T_t *fill_type; /* Copy of fill value datatype */
+ H5S_t *fill_space; /* Scalar dataspace for fill value element */
+
+ /* Copy the fill value datatype and get an ID for it */
+ if(NULL == (fill_type = H5T_copy(fill->type, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy fill value datatype")
+ if((fill_type_id = H5I_register(H5I_DATATYPE, fill_type, FALSE)) < 0) {
+ H5T_close(fill_type);
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTREGISTER, FAIL, "unable to register fill value datatype")
+ } /* end if */
+
+ /* Create a scalar dataspace for the fill value element */
+ if(NULL == (fill_space = H5S_create(H5S_SCALAR)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create scalar dataspace")
+
+ /* Reclaim any variable length components of the fill value */
+ if(H5D_vlen_reclaim(fill_type_id, fill_space, H5AC_noio_dxpl_id, fill->buf) < 0) {
+ H5S_close(fill_space);
+ HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "unable to reclaim variable-length fill value data")
+ } /* end if */
+
+ /* Release the scalar fill value dataspace */
+ H5S_close(fill_space);
+ } /* end if */
+
+ /* Release the fill value buffer now */
+ fill->buf = H5MM_xfree(fill->buf);
+ } /* end if */
+ fill->size = 0;
+ if(fill->type) {
+ H5T_close(fill->type);
+ fill->type = NULL;
+ } /* end if */
+
+done:
+ if(fill_type_id > 0 && H5I_dec_ref(fill_type_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for temp ID")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_reset_dyn() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_reset
+ *
+ * Purpose: Resets a message to an initial state.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fill_reset(void *_fill)
+{
+ H5O_fill_t *fill = (H5O_fill_t *)_fill;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(fill);
+
+ /* Reset dynamic fields */
+ H5O_fill_reset_dyn(fill);
+
+ /* Reset value fields */
+ fill->alloc_time = H5D_ALLOC_TIME_LATE;
+ fill->fill_time = H5D_FILL_TIME_IFSET;
+ fill->fill_defined = FALSE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_free
+ *
+ * Purpose: Frees the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, December 5, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fill_free(void *fill)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(fill);
+
+ fill = H5FL_FREE(H5O_fill_t, fill);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fill_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_fill, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)_fill;
+ H5D_fill_value_t fill_status; /* Whether the fill value is defined */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f);
+ HDassert(fill);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Space Allocation Time:");
+ switch(fill->alloc_time) {
+ case H5D_ALLOC_TIME_EARLY:
+ fprintf(stream,"Early\n");
+ break;
+
+ case H5D_ALLOC_TIME_LATE:
+ fprintf(stream,"Late\n");
+ break;
+
+ case H5D_ALLOC_TIME_INCR:
+ fprintf(stream,"Incremental\n");
+ break;
+
+ case H5D_ALLOC_TIME_DEFAULT:
+ case H5D_ALLOC_TIME_ERROR:
+ default:
+ fprintf(stream,"Unknown!\n");
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Fill Time:");
+ switch(fill->fill_time) {
+ case H5D_FILL_TIME_ALLOC:
+ fprintf(stream,"On Allocation\n");
+ break;
+
+ case H5D_FILL_TIME_NEVER:
+ fprintf(stream,"Never\n");
+ break;
+
+ case H5D_FILL_TIME_IFSET:
+ fprintf(stream,"If Set\n");
+ break;
+
+ case H5D_FILL_TIME_ERROR:
+ default:
+ fprintf(stream,"Unknown!\n");
+ break;
+
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Fill Value Defined:");
+ H5P_is_fill_value_defined((const H5O_fill_t *)fill, &fill_status);
+ switch(fill_status) {
+ case H5D_FILL_VALUE_UNDEFINED:
+ fprintf(stream,"Undefined\n");
+ break;
+
+ case H5D_FILL_VALUE_DEFAULT:
+ fprintf(stream,"Default\n");
+ break;
+
+ case H5D_FILL_VALUE_USER_DEFINED:
+ fprintf(stream,"User Defined\n");
+ break;
+
+ case H5D_FILL_VALUE_ERROR:
+ default:
+ fprintf(stream,"Unknown!\n");
+ break;
+
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %Zd\n", indent, "", fwidth,
+ "Size:", fill->size);
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Data type:");
+ if(fill->type) {
+ H5T_debug(fill->type, stream);
+ fprintf(stream, "\n");
+ } /* end if */
+ else
+ fprintf(stream, "<dataset type>\n");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_convert
+ *
+ * Purpose: Convert a fill value from whatever data type it currently has
+ * to the specified dataset type. The `type' field of the fill
+ * value struct will be set to NULL to indicate that it has the
+ * same type as the dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_fill_convert(H5O_fill_t *fill, H5T_t *dset_type, hbool_t *fill_changed, hid_t dxpl_id)
+{
+ H5T_path_t *tpath; /* Type conversion info */
+ void *buf = NULL, *bkg = NULL; /* Conversion buffers */
+ hid_t src_id = -1, dst_id = -1; /* Datatype identifiers */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(fill);
+ HDassert(dset_type);
+ HDassert(fill_changed);
+
+ /* No-op cases */
+ if(!fill->buf || !fill->type || 0 == H5T_cmp(fill->type, dset_type, FALSE)) {
+ /* Don't need datatype for fill value */
+ if(fill->type)
+ H5T_close(fill->type);
+ fill->type = NULL;
+
+ /* Note that the fill value info has changed */
+ *fill_changed = TRUE;
+
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /*
+ * Can we convert between source and destination data types?
+ */
+ if(NULL == (tpath = H5T_path_find(fill->type, dset_type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes")
+
+ /* Don't bother doing anything if there will be no actual conversion */
+ if(!H5T_path_noop(tpath)) {
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill->type, H5T_COPY_ALL), FALSE)) < 0 ||
+ (dst_id = H5I_register(H5I_DATATYPE, H5T_copy(dset_type, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy/register data type")
+
+ /*
+ * Datatype conversions are always done in place, so we need a buffer
+ * that is large enough for both source and destination.
+ */
+ if(H5T_get_size(fill->type) >= H5T_get_size(dset_type))
+ buf = fill->buf;
+ else {
+ if(NULL == (buf = H5MM_malloc(H5T_get_size(dset_type))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ HDmemcpy(buf, fill->buf, H5T_get_size(fill->type));
+ } /* end else */
+
+ /* Use CALLOC here to clear the buffer in case later the library thinks there's
+ * data in the background. */
+ if(H5T_path_bkg(tpath) && NULL == (bkg = H5MM_calloc(H5T_get_size(dset_type))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+
+ /* Do the conversion */
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ /* Update the fill message */
+ if(buf != fill->buf) {
+ H5T_vlen_reclaim_elmt(fill->buf, fill->type, dxpl_id);
+ H5MM_xfree(fill->buf);
+ fill->buf = buf;
+ } /* end if */
+ H5T_close(fill->type);
+ fill->type = NULL;
+ H5_CHECKED_ASSIGN(fill->size, ssize_t, H5T_get_size(dset_type), size_t);
+
+ /* Note that the fill value info has changed */
+ *fill_changed = TRUE;
+ } /* end if */
+
+done:
+ if(src_id >= 0 && H5I_dec_ref(src_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for temp ID")
+ if(dst_id >= 0 && H5I_dec_ref(dst_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for temp ID")
+ if(buf != fill->buf)
+ H5MM_xfree(buf);
+ if(bkg)
+ H5MM_xfree(bkg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fill_convert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fill_set_latest_version
+ *
+ * Purpose: Set the encoding for a fill value to the latest version.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 24, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_fill_set_latest_version(H5O_fill_t *fill)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(fill);
+
+ /* Set encoding of fill value to latest version */
+ fill->version = H5O_FILL_VERSION_LATEST;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fill_set_latest_version() */
+
diff --git a/src/H5Oflush.c b/src/H5Oflush.c
new file mode 100644
index 0000000..2d93221
--- /dev/null
+++ b/src/H5Oflush.c
@@ -0,0 +1,419 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oflush.c
+ * Aug 19, 2010
+ * Mike McGreevy <mamcgree@hdfgroup.org>
+ *
+ * Purpose: Object flush/refresh routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+/***********/
+/* Headers */
+/***********/
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Errors */
+#include "H5Fprivate.h" /* Files */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Objects */
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag);
+
+/*************/
+/* Functions */
+/*************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Oflush
+ *
+ * Purpose: Flushes all buffers associated with an object to disk.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Oflush(hid_t obj_id)
+{
+ H5O_loc_t *oloc; /* object location */
+ void *obj_ptr; /* Pointer to object */
+ const H5O_obj_class_t *obj_class = NULL; /* Class of object */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", obj_id);
+
+ /* Check args */
+ if(NULL == (oloc = H5O_get_loc(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
+
+ /* Get the object pointer */
+ if(NULL == (obj_ptr = H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
+
+ /* Get the object class */
+ if(NULL == (obj_class = H5O_obj_class(oloc, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object class")
+
+ /* Flush the object of this class */
+ if(obj_class->flush && obj_class->flush(obj_ptr, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
+
+ /* Flush the object metadata and invoke flush callback */
+ if(H5O_flush_common(oloc, obj_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oflush() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_flush_common
+ *
+ * Purpose: Flushes the object's metadata
+ * Invokes the user-defined callback if there is one.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id, hid_t dxpl_id)
+{
+ haddr_t tag = 0;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Retrieve tag for object */
+ if(H5O_oh_tag(oloc, dxpl_id, &tag) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object metadata")
+
+ /* Flush metadata based on tag value of the object */
+ if(H5F_flush_tagged_metadata(oloc->file, tag, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
+
+ /* Check to invoke callback */
+ if(H5F_object_flush_cb(oloc->file, obj_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to do object flush callback")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_flush_common() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_oh_tag
+ *
+ * Purpose: Get object header's address--tag value for the object
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(oloc);
+
+ /* Get object header for object */
+ if(NULL == (oh = H5O_protect(oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header")
+
+ /* Get object header's address (i.e. the tag value for this object) */
+ if(HADDR_UNDEF == (*tag = H5O_OH_GET_ADDR(oh)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header")
+
+done:
+ /* Unprotect object header on failure */
+ if(oh && H5O_unprotect(oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_oh_tag() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Orefresh
+ *
+ * Purpose: Refreshes all buffers associated with an object.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * July 28, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Orefresh(hid_t oid)
+{
+ H5O_loc_t *oloc; /* object location */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", oid);
+
+ /* Check args */
+ if(NULL == (oloc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
+
+ /* Private function */
+ if(H5O_refresh_metadata(oid, *oloc, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Orefresh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata
+ *
+ * Purpose: Refreshes all buffers associated with an object.
+ *
+ * Note: This is based on the original H5O_refresh_metadata() but
+ * is split into 2 routines.
+ * This is done so that H5Fstart_swmr_write() can use these
+ * 2 routines to refresh opened objects. This may be
+ * restored back to the original code when H5Fstart_swmr_write()
+ * uses a different approach to handle issues with opened objects.
+ * H5Fstart_swmr_write() no longer calls the 1st routine. (12/24/15)
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id)
+{
+ hbool_t objs_incr = FALSE; /* Whether the object count in the file was incremented */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* If the file is opened with write access, no need to perform refresh actions. */
+ if(!(H5F_INTENT(oloc.file) & H5F_ACC_RDWR)) {
+ H5G_loc_t obj_loc;
+ H5O_loc_t obj_oloc;
+ H5G_name_t obj_path;
+
+ /* Create empty object location */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* "Fake" another open object in the file, so that it doesn't get closed
+ * if this object is the only thing holding the file open.
+ */
+ H5F_incr_nopen_objs(oloc.file);
+ objs_incr = TRUE;
+
+ /* Close object & evict its metadata */
+ if((H5O_refresh_metadata_close(oid, oloc, &obj_loc, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
+
+ /* Re-open the object, re-fetching its metadata */
+ if((H5O_refresh_metadata_reopen(oid, &obj_loc, dxpl_id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
+ } /* end if */
+
+done:
+ if(objs_incr)
+ H5F_decr_nopen_objs(oloc.file);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata_close
+ *
+ * Purpose: This is the first part of the original routine H5O_refresh_metadata().
+ * (1) Save object location information.
+ * (2) Handle multiple dataset opens
+ * (3) Get object cork status
+ * (4) Close the object
+ * (5) Flush and evict object metadata
+ * (6) Re-cork the object if needed
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ haddr_t tag = 0; /* Tag for object */
+ hbool_t corked = FALSE; /* Whether object's metadata is corked */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Make deep local copy of object's location information */
+ if(obj_loc) {
+ H5G_loc_t tmp_loc;
+
+ H5G_loc(oid, &tmp_loc);
+ H5G_loc_copy(obj_loc, &tmp_loc, H5_COPY_DEEP);
+ } /* end if */
+
+ /* Get object's type */
+ if(H5I_get_type(oid) == H5I_DATASET)
+ if(H5D_mult_refresh_close(oid, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to prepare refresh for dataset")
+
+ /* Retrieve tag for object */
+ if(H5O_oh_tag(&oloc, dxpl_id, &tag) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to get object header address")
+
+ /* Get cork status of the object with tag */
+ if(H5AC_cork(oloc.file, tag, H5AC__GET_CORKED, &corked) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to retrieve an object's cork status")
+
+ /* Close the object */
+ if(H5I_dec_ref(oid) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close object")
+
+ /* Flush metadata based on tag value of the object */
+ if(H5F_flush_tagged_metadata(oloc.file, tag, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
+
+ /* Evict the object's tagged metadata */
+ if(H5F_evict_tagged_metadata(oloc.file, tag, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict metadata")
+
+ /* Re-cork object with tag */
+ if(corked)
+ if(H5AC_cork(oloc.file, tag, H5AC__SET_CORK, &corked) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to cork the object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata_reopen
+ *
+ * Purpose: This is the second part of the original routine H5O_refresh_metadata().
+ * (1) Re-open object with the saved object location information.
+ * (2) Re-register object ID with the re-opened object.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hid_t dxpl_id, hbool_t start_swmr)
+{
+ void *object = NULL; /* Dataset for this operation */
+ H5I_type_t type; /* Type of object for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object's type */
+ type = H5I_get_type(oid);
+
+ switch(type) {
+ case(H5I_GROUP):
+ /* Re-open the group */
+ if(NULL == (object = H5G_open(obj_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ break;
+
+ case(H5I_DATATYPE):
+ /* Re-open the named datatype */
+ if(NULL == (object = H5T_open(obj_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype")
+ break;
+
+ case(H5I_DATASET):
+ /* Re-open the dataset */
+ if(NULL == (object = H5D_open(obj_loc, H5P_DATASET_ACCESS_DEFAULT, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
+ if(!start_swmr) /* No need to handle multiple opens when H5Fstart_swmr_write() */
+ if(H5D_mult_refresh_reopen((H5D_t *)object, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to finish refresh for dataset")
+ break;
+
+ case(H5I_UNINIT):
+ case(H5I_BADID):
+ case(H5I_FILE):
+ case(H5I_DATASPACE):
+ case(H5I_ATTR):
+ case(H5I_REFERENCE):
+ case(H5I_VFL):
+ case(H5I_GENPROP_CLS):
+ case(H5I_GENPROP_LST):
+ case(H5I_ERROR_CLASS):
+ case(H5I_ERROR_MSG):
+ case(H5I_ERROR_STACK):
+ case(H5I_NTYPES):
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)")
+ break;
+ } /* end switch */
+
+ /* Re-register ID for the object */
+ if((H5I_register_with_id(type, object, TRUE, oid)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to re-register object atom")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata_reopen() */
+
diff --git a/src/H5Ofsinfo.c b/src/H5Ofsinfo.c
new file mode 100644
index 0000000..89dc8ee
--- /dev/null
+++ b/src/H5Ofsinfo.c
@@ -0,0 +1,406 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ofsinfo.c
+ * Feb 2009
+ * Vailin Choi
+ *
+ * Purpose: File space info message.
+ *
+ *-------------------------------------------------------------------------
+ */
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_fsinfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_fsinfo_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_fsinfo_copy(const void *_mesg, void *_dest);
+static size_t H5O_fsinfo_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_fsinfo_free(void *mesg);
+static herr_t H5O_fsinfo_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_FSINFO[1] = {{
+ H5O_FSINFO_ID, /* message id number */
+ "fsinfo", /* message name for debugging */
+ sizeof(H5O_fsinfo_t), /* native message size */
+ 0, /* messages are sharable? */
+ H5O_fsinfo_decode, /* decode message */
+ H5O_fsinfo_encode, /* encode message */
+ H5O_fsinfo_copy, /* copy the native value */
+ H5O_fsinfo_size, /* size of free-space manager info message */
+ NULL, /* default reset method */
+ H5O_fsinfo_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /* set share method */
+ NULL, /* can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_fsinfo_debug /* debug the message */
+}};
+
+/* Current version of free-space manager info information */
+#define H5O_FSINFO_VERSION_0 0
+#define H5O_FSINFO_VERSION_1 1
+
+/* Declare a free list to manage the H5O_fsinfo_t struct */
+H5FL_DEFINE_STATIC(H5O_fsinfo_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_decode
+ *
+ * Purpose: Decode a message and return a pointer to a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native form.
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_fsinfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_fsinfo_t *fsinfo = NULL; /* File space info message */
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+ unsigned vers; /* message version */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Allocate space for message */
+ if(NULL == (fsinfo = H5FL_CALLOC(H5O_fsinfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ for(ptype = H5F_MEM_PAGE_SUPER; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ fsinfo->fs_addr[ptype - 1] = HADDR_UNDEF;
+
+ /* Version of message */
+ vers = *p++;
+
+ if(vers == H5O_FSINFO_VERSION_0) {
+ H5F_file_space_type_t strategy; /* Strategy */
+ hsize_t threshold; /* Threshold */
+ H5FD_mem_t type; /* Memory type for iteration */
+
+ fsinfo->persist = H5F_FREE_SPACE_PERSIST_DEF;
+ fsinfo->threshold = H5F_FREE_SPACE_THRESHOLD_DEF;
+ fsinfo->page_size = H5F_FILE_SPACE_PAGE_SIZE_DEF;
+ fsinfo->pgend_meta_thres = H5F_FILE_SPACE_PGEND_META_THRES;
+ fsinfo->eoa_pre_fsm_fsalloc = HADDR_UNDEF;
+
+ strategy = (H5F_file_space_type_t)*p++; /* File space strategy */
+ H5F_DECODE_LENGTH(f, p, threshold); /* Free-space section threshold */
+
+ /* Map version 0 (deprecated) to version 1 message */
+ switch(strategy) {
+
+ case H5F_FILE_SPACE_ALL_PERSIST:
+ fsinfo->strategy = H5F_FSPACE_STRATEGY_FSM_AGGR;
+ fsinfo->persist = TRUE;
+ fsinfo->threshold = threshold;
+ if(HADDR_UNDEF == (fsinfo->eoa_pre_fsm_fsalloc = H5F_get_eoa(f, H5FD_MEM_DEFAULT)) )
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to get file size")
+ for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type))
+ H5F_addr_decode(f, &p, &(fsinfo->fs_addr[type-1]));
+ break;
+
+ case H5F_FILE_SPACE_ALL:
+ fsinfo->strategy = H5F_FSPACE_STRATEGY_FSM_AGGR;
+ fsinfo->threshold = threshold;
+ break;
+
+ case H5F_FILE_SPACE_AGGR_VFD:
+ fsinfo->strategy = H5F_FSPACE_STRATEGY_AGGR;
+ break;
+
+ case H5F_FILE_SPACE_VFD:
+ fsinfo->strategy = H5F_FSPACE_STRATEGY_NONE;
+ break;
+
+ case H5F_FILE_SPACE_NTYPES:
+ case H5F_FILE_SPACE_DEFAULT:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file space strategy")
+ } /* end switch */
+
+ fsinfo->mapped = TRUE;
+
+ } else {
+ HDassert(vers == H5O_FSINFO_VERSION_1);
+
+ fsinfo->strategy = (H5F_fspace_strategy_t)*p++; /* File space strategy */
+ fsinfo->persist = *p++; /* Free-space persist or not */
+ H5F_DECODE_LENGTH(f, p, fsinfo->threshold); /* Free-space section threshold */
+
+ H5F_DECODE_LENGTH(f, p, fsinfo->page_size); /* File space page size */
+ UINT16DECODE(p, fsinfo->pgend_meta_thres); /* Page end metdata threshold */
+ H5F_addr_decode(f, &p, &(fsinfo->eoa_pre_fsm_fsalloc)); /* EOA before free-space header and section info */
+
+ /* Decode addresses of free space managers, if persisting */
+ if(fsinfo->persist) {
+ for(ptype = H5F_MEM_PAGE_SUPER; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ H5F_addr_decode(f, &p, &(fsinfo->fs_addr[ptype - 1]));
+ } /* end if */
+
+ fsinfo->mapped = FALSE;
+ }
+
+ /* Set return value */
+ ret_value = fsinfo;
+
+done:
+ if(ret_value == NULL && fsinfo != NULL)
+ fsinfo = H5FL_FREE(H5O_fsinfo_t, fsinfo);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fsinfo_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fsinfo_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_fsinfo_t *fsinfo = (const H5O_fsinfo_t *)_mesg;
+ H5F_mem_page_t ptype; /* Memory type for iteration */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(fsinfo);
+
+ *p++ = H5O_FSINFO_VERSION_1; /* message version */
+ *p++ = fsinfo->strategy; /* File space strategy */
+ *p++ = (unsigned char)fsinfo->persist; /* Free-space persist or not */
+ H5F_ENCODE_LENGTH(f, p, fsinfo->threshold); /* Free-space section size threshold */
+
+ H5F_ENCODE_LENGTH(f, p, fsinfo->page_size); /* File space page size */
+ UINT16ENCODE(p, fsinfo->pgend_meta_thres); /* Page end metadata threshold */
+ H5F_addr_encode(f, &p, fsinfo->eoa_pre_fsm_fsalloc); /* EOA before free-space header and section info */
+
+ /* Store addresses of free-space managers, if persisting */
+ if(fsinfo->persist) {
+ /* Addresses of free-space managers */
+ for(ptype = H5F_MEM_PAGE_SUPER; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ H5F_addr_encode(f, &p, fsinfo->fs_addr[ptype - 1]);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fsinfo_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_fsinfo_copy(const void *_mesg, void *_dest)
+{
+ const H5O_fsinfo_t *fsinfo = (const H5O_fsinfo_t *)_mesg;
+ H5O_fsinfo_t *dest = (H5O_fsinfo_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(fsinfo);
+ if(!dest && NULL == (dest = H5FL_CALLOC(H5O_fsinfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *fsinfo;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fsinfo_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ * Failure: zero
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_fsinfo_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_fsinfo_t *fsinfo = (const H5O_fsinfo_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ ret_value = 3 /* Version, strategy & persist */
+ + (size_t)H5F_SIZEOF_SIZE(f) /* Free-space section threshold */
+ + (size_t)H5F_SIZEOF_SIZE(f) /* File space page size */
+ + 2 /* Page end meta threshold */
+ + (size_t)H5F_SIZEOF_ADDR(f);
+
+ /* Free-space manager addresses */
+ if(fsinfo->persist)
+ ret_value += (H5F_MEM_PAGE_NTYPES - 1) * (size_t)H5F_SIZEOF_ADDR(f);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_fsinfo_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fsinfo_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_fsinfo_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fsinfo_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_fsinfo_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_fsinfo_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_fsinfo_t *fsinfo = (const H5O_fsinfo_t *) _mesg;
+ H5F_mem_page_t ptype; /* Free-space types for iteration */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(fsinfo);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "File space strategy:");
+ switch(fsinfo->strategy) {
+ case H5F_FSPACE_STRATEGY_FSM_AGGR:
+ HDfprintf(stream, "%s\n", "H5F_FSPACE_STRATEGY_FSM_AGGR");
+ break;
+
+ case H5F_FSPACE_STRATEGY_PAGE:
+ HDfprintf(stream, "%s\n", "H5F_FSPACE_STRATEGY_PAGE");
+ break;
+
+ case H5F_FSPACE_STRATEGY_AGGR:
+ HDfprintf(stream, "%s\n", "H5F_FSPACE_STRATEGY_AGGR");
+ break;
+
+ case H5F_FSPACE_STRATEGY_NONE:
+ HDfprintf(stream, "%s\n", "H5F_FSPACE_STRATEGY_NONE");
+ break;
+
+ case H5F_FSPACE_STRATEGY_NTYPES:
+ default:
+ HDfprintf(stream, "%s\n", "unknown");
+ } /* end switch */
+
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Free-space persist:", fsinfo->persist);
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Free-space section threshold:", fsinfo->threshold);
+
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "File space page size:", fsinfo->page_size);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Page end metadata threshold:", fsinfo->pgend_meta_thres);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "eoa_pre_fsm_fsalloc:", fsinfo->eoa_pre_fsm_fsalloc);
+
+ if(fsinfo->persist) {
+ for(ptype = H5F_MEM_PAGE_SUPER; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype))
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Free space manager address:", fsinfo->fs_addr[ptype-1]);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_fsinfo_debug() */
+
diff --git a/src/H5Oginfo.c b/src/H5Oginfo.c
new file mode 100644
index 0000000..468e07a
--- /dev/null
+++ b/src/H5Oginfo.c
@@ -0,0 +1,351 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oginfo.c
+ * Aug 23 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Group Information messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_ginfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_ginfo_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_ginfo_copy(const void *_mesg, void *_dest);
+static size_t H5O_ginfo_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_ginfo_free(void *_mesg);
+static herr_t H5O_ginfo_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_GINFO[1] = {{
+ H5O_GINFO_ID, /*message id number */
+ "ginfo", /*message name for debugging */
+ sizeof(H5O_ginfo_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_ginfo_decode, /*decode message */
+ H5O_ginfo_encode, /*encode message */
+ H5O_ginfo_copy, /*copy the native value */
+ H5O_ginfo_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_ginfo_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_ginfo_debug /*debug the message */
+}};
+
+/* Current version of group info information */
+#define H5O_GINFO_VERSION 0
+
+/* Flags for group info flag encoding */
+#define H5O_GINFO_STORE_PHASE_CHANGE 0x01
+#define H5O_GINFO_STORE_EST_ENTRY_INFO 0x02
+#define H5O_GINFO_ALL_FLAGS (H5O_GINFO_STORE_PHASE_CHANGE | H5O_GINFO_STORE_EST_ENTRY_INFO)
+
+/* Declare a free list to manage the H5O_ginfo_t struct */
+H5FL_DEFINE_STATIC(H5O_ginfo_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_decode
+ *
+ * Purpose: Decode a message and return a pointer to
+ * a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native order.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_ginfo_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_ginfo_t *ginfo = NULL; /* Pointer to group information message */
+ unsigned char flags; /* Flags for encoding group info */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_GINFO_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (ginfo = H5FL_CALLOC(H5O_ginfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get the flags for the group */
+ flags = *p++;
+ if(flags & ~H5O_GINFO_ALL_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message")
+ ginfo->store_link_phase_change = (flags & H5O_GINFO_STORE_PHASE_CHANGE) ? TRUE : FALSE;
+ ginfo->store_est_entry_info = (flags & H5O_GINFO_STORE_EST_ENTRY_INFO) ? TRUE : FALSE;
+
+ /* Get the max. # of links to store compactly & the min. # of links to store densely */
+ if(ginfo->store_link_phase_change) {
+ UINT16DECODE(p, ginfo->max_compact)
+ UINT16DECODE(p, ginfo->min_dense)
+ } /* end if */
+ else {
+ ginfo->max_compact = H5G_CRT_GINFO_MAX_COMPACT;
+ ginfo->min_dense = H5G_CRT_GINFO_MIN_DENSE;
+ } /* end else */
+
+ /* Get the estimated # of entries & name lengths */
+ if(ginfo->store_est_entry_info) {
+ UINT16DECODE(p, ginfo->est_num_entries)
+ UINT16DECODE(p, ginfo->est_name_len)
+ } /* end if */
+ else {
+ ginfo->est_num_entries = H5G_CRT_GINFO_EST_NUM_ENTRIES;
+ ginfo->est_name_len = H5G_CRT_GINFO_EST_NAME_LEN;
+ } /* end if */
+
+ /* Set return value */
+ ret_value = ginfo;
+
+done:
+ if(ret_value == NULL)
+ if(ginfo != NULL)
+ ginfo = H5FL_FREE(H5O_ginfo_t, ginfo);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ginfo_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ginfo_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_ginfo_t *ginfo = (const H5O_ginfo_t *) _mesg;
+ unsigned char flags; /* Flags for encoding group info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(p);
+ HDassert(ginfo);
+
+ /* Message version */
+ *p++ = H5O_GINFO_VERSION;
+
+ /* The flags for the group info */
+ flags = ginfo->store_link_phase_change ? H5O_GINFO_STORE_PHASE_CHANGE : 0;
+ flags = (unsigned char)(flags | (ginfo->store_est_entry_info ? H5O_GINFO_STORE_EST_ENTRY_INFO : 0));
+ *p++ = flags;
+
+ /* Store the max. # of links to store compactly & the min. # of links to store densely */
+ if(ginfo->store_link_phase_change) {
+ UINT16ENCODE(p, ginfo->max_compact)
+ UINT16ENCODE(p, ginfo->min_dense)
+ } /* end if */
+
+ /* Estimated # of entries & name lengths */
+ if(ginfo->store_est_entry_info) {
+ UINT16ENCODE(p, ginfo->est_num_entries)
+ UINT16ENCODE(p, ginfo->est_name_len)
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ginfo_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_ginfo_copy(const void *_mesg, void *_dest)
+{
+ const H5O_ginfo_t *ginfo = (const H5O_ginfo_t *)_mesg;
+ H5O_ginfo_t *dest = (H5O_ginfo_t *)_dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(ginfo);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_ginfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *ginfo;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ginfo_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ *
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_ginfo_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_ginfo_t *ginfo = (const H5O_ginfo_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = 1 + /* Version */
+ 1 + /* Flags */
+ (ginfo->store_link_phase_change ? (
+ (size_t)(2 + /* "Max compact" links */
+ 2) /* "Min dense" links */
+ ) : 0) + /* "Min dense" links */
+ (ginfo->store_est_entry_info ? (
+ (size_t)(2 + /* Estimated # of entries in group */
+ 2) /* Estimated length of name of entry in group */
+ ) : 0);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_ginfo_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 30, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ginfo_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_ginfo_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ginfo_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_ginfo_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_ginfo_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_ginfo_t *ginfo = (const H5O_ginfo_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(ginfo);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Max. compact links:", ginfo->max_compact);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Min. dense links:", ginfo->min_dense);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Estimated # of objects in group:", ginfo->est_num_entries);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Estimated length of object in group's name:", ginfo->est_name_len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_ginfo_debug() */
+
diff --git a/src/H5Olayout.c b/src/H5Olayout.c
new file mode 100644
index 0000000..838a80f
--- /dev/null
+++ b/src/H5Olayout.c
@@ -0,0 +1,1284 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, October 8, 1997
+ *
+ * Purpose: Messages related to data layout.
+ */
+
+#define H5D_FRIEND /*suppress error about including H5Dpkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File space management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+
+
+/* Local macros */
+
+/* Version # of encoded virtual dataset global heap blocks */
+#define H5O_LAYOUT_VDS_GH_ENC_VERS 0
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O__layout_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O__layout_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O__layout_copy(const void *_mesg, void *_dest);
+static size_t H5O__layout_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O__layout_reset(void *_mesg);
+static herr_t H5O__layout_free(void *_mesg);
+static herr_t H5O__layout_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ void *_mesg);
+static void *H5O__layout_copy_file(H5F_t *file_src, void *mesg_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O__layout_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_LAYOUT[1] = {{
+ H5O_LAYOUT_ID, /* message id number */
+ "layout", /* message name for debugging */
+ sizeof(H5O_layout_t), /* native message size */
+ 0, /* messages are sharable? */
+ H5O__layout_decode, /* decode message */
+ H5O__layout_encode, /* encode message */
+ H5O__layout_copy, /* copy the native value */
+ H5O__layout_size, /* size of message on disk */
+ H5O__layout_reset, /* reset method */
+ H5O__layout_free, /* free the struct */
+ H5O__layout_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /* set share method */
+ NULL, /* can share method */
+ NULL, /* pre copy native value to file */
+ H5O__layout_copy_file, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O__layout_debug /* debug the message */
+}};
+
+
+/* Declare a free list to manage the H5O_layout_t struct */
+H5FL_DEFINE(H5O_layout_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_decode
+ *
+ * Purpose: Decode an data layout message and return a pointer to a
+ * new one created with malloc().
+ *
+ * Return: Success: Ptr to new message in native order.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__layout_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_layout_t *mesg = NULL;
+ uint8_t *heap_block = NULL;
+ unsigned u;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(NULL == (mesg = H5FL_CALLOC(H5O_layout_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ mesg->storage.type = H5D_LAYOUT_ERROR;
+
+ mesg->version = *p++;
+ if(mesg->version < H5O_LAYOUT_VERSION_1 || mesg->version > H5O_LAYOUT_VERSION_4)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for layout message")
+
+ if(mesg->version < H5O_LAYOUT_VERSION_3) {
+ unsigned ndims; /* Num dimensions in chunk */
+
+ /* Dimensionality */
+ ndims = *p++;
+ if(ndims > H5O_LAYOUT_NDIMS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "dimensionality is too large")
+
+ /* Layout class */
+ mesg->type = (H5D_layout_t)*p++;
+ HDassert(H5D_CONTIGUOUS == mesg->type || H5D_CHUNKED == mesg->type || H5D_COMPACT == mesg->type);
+
+ /* Set the storage type */
+ mesg->storage.type = mesg->type;
+
+ /* Reserved bytes */
+ p += 5;
+
+ /* Address */
+ if(mesg->type == H5D_CONTIGUOUS) {
+ H5F_addr_decode(f, &p, &(mesg->storage.u.contig.addr));
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_CONTIG;
+ } /* end if */
+ else if(mesg->type == H5D_CHUNKED) {
+ H5F_addr_decode(f, &p, &(mesg->storage.u.chunk.idx_addr));
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_CHUNK;
+
+ /* Set the chunk operations */
+ /* (Only "btree" indexing type currently supported in this version) */
+ mesg->storage.u.chunk.idx_type = H5D_CHUNK_IDX_BTREE;
+ mesg->storage.u.chunk.ops = H5D_COPS_BTREE;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(mesg->type == H5D_COMPACT);
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_COMPACT;
+ } /* end else */
+
+ /* Read the size */
+ if(mesg->type != H5D_CHUNKED) {
+ /* Don't compute size of contiguous storage here, due to possible
+ * truncation of the dimension sizes when they were stored in this
+ * version of the layout message. Compute the contiguous storage
+ * size in the dataset code, where we've got the dataspace
+ * information available also. - QAK 5/26/04
+ */
+ p += ndims * 4; /* Skip over dimension sizes (32-bit quantities) */
+ } /* end if */
+ else {
+ mesg->u.chunk.ndims=ndims;
+ for(u = 0; u < ndims; u++)
+ UINT32DECODE(p, mesg->u.chunk.dim[u]);
+
+ /* Compute chunk size */
+ for(u = 1, mesg->u.chunk.size = mesg->u.chunk.dim[0]; u < ndims; u++)
+ mesg->u.chunk.size *= mesg->u.chunk.dim[u];
+ } /* end if */
+
+ if(mesg->type == H5D_COMPACT) {
+ UINT32DECODE(p, mesg->storage.u.compact.size);
+ if(mesg->storage.u.compact.size > 0) {
+ if(NULL == (mesg->storage.u.compact.buf = H5MM_malloc(mesg->storage.u.compact.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for compact data buffer")
+ HDmemcpy(mesg->storage.u.compact.buf, p, mesg->storage.u.compact.size);
+ p += mesg->storage.u.compact.size;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ else {
+ /* Layout & storage class */
+ mesg->type = mesg->storage.type = (H5D_layout_t)*p++;
+
+ /* Interpret the rest of the message according to the layout class */
+ switch(mesg->type) {
+ case H5D_COMPACT:
+ /* Compact data size */
+ UINT16DECODE(p, mesg->storage.u.compact.size);
+
+ if(mesg->storage.u.compact.size > 0) {
+ /* Allocate space for compact data */
+ if(NULL == (mesg->storage.u.compact.buf = H5MM_malloc(mesg->storage.u.compact.size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed for compact data buffer")
+
+ /* Compact data */
+ HDmemcpy(mesg->storage.u.compact.buf, p, mesg->storage.u.compact.size);
+ p += mesg->storage.u.compact.size;
+ } /* end if */
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_COMPACT;
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Contiguous storage address */
+ H5F_addr_decode(f, &p, &(mesg->storage.u.contig.addr));
+
+ /* Contiguous storage size */
+ H5F_DECODE_LENGTH(f, p, mesg->storage.u.contig.size);
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_CONTIG;
+ break;
+
+ case H5D_CHUNKED:
+ if(mesg->version < H5O_LAYOUT_VERSION_4) {
+ /* Set the chunked layout flags */
+ mesg->u.chunk.flags = (uint8_t)0;
+
+ /* Dimensionality */
+ mesg->u.chunk.ndims = *p++;
+ if(mesg->u.chunk.ndims > H5O_LAYOUT_NDIMS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "dimensionality is too large")
+
+ /* B-tree address */
+ H5F_addr_decode(f, &p, &(mesg->storage.u.chunk.idx_addr));
+
+ /* Chunk dimensions */
+ for(u = 0; u < mesg->u.chunk.ndims; u++)
+ UINT32DECODE(p, mesg->u.chunk.dim[u]);
+
+ /* Compute chunk size */
+ for(u = 1, mesg->u.chunk.size = mesg->u.chunk.dim[0]; u < mesg->u.chunk.ndims; u++)
+ mesg->u.chunk.size *= mesg->u.chunk.dim[u];
+
+ /* Set the chunk operations */
+ /* (Only "btree" indexing type supported with v3 of message format) */
+ mesg->storage.u.chunk.idx_type = H5D_CHUNK_IDX_BTREE;
+ mesg->storage.u.chunk.ops = H5D_COPS_BTREE;
+ } /* end if */
+ else {
+ /* Get the chunked layout flags */
+ mesg->u.chunk.flags = *p++;
+
+ /* Check for valid flags */
+ /* (Currently issues an error for all non-zero values,
+ * until features are added for the flags)
+ */
+ if(mesg->u.chunk.flags & ~H5O_LAYOUT_ALL_CHUNK_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad flag value for message")
+
+ /* Dimensionality */
+ mesg->u.chunk.ndims = *p++;
+ if(mesg->u.chunk.ndims > H5O_LAYOUT_NDIMS)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "dimensionality is too large")
+
+ /* Encoded # of bytes for each chunk dimension */
+ mesg->u.chunk.enc_bytes_per_dim = *p++;
+ if(mesg->u.chunk.enc_bytes_per_dim == 0 || mesg->u.chunk.enc_bytes_per_dim > 8)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "encoded chunk dimension size is too large")
+
+ /* Chunk dimensions */
+ for(u = 0; u < mesg->u.chunk.ndims; u++)
+ UINT64DECODE_VAR(p, mesg->u.chunk.dim[u], mesg->u.chunk.enc_bytes_per_dim);
+
+ /* Compute chunk size */
+ for(u = 1, mesg->u.chunk.size = mesg->u.chunk.dim[0]; u < mesg->u.chunk.ndims; u++)
+ mesg->u.chunk.size *= mesg->u.chunk.dim[u];
+
+ /* Chunk index type */
+ mesg->u.chunk.idx_type = (H5D_chunk_index_t)*p++;
+ if(mesg->u.chunk.idx_type >= H5D_CHUNK_IDX_NTYPES)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "unknown chunk index type")
+ mesg->storage.u.chunk.idx_type = mesg->u.chunk.idx_type;
+
+ switch(mesg->u.chunk.idx_type) {
+ case H5D_CHUNK_IDX_BTREE:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "v1 B-tree index type should never be in a v4 layout message")
+ break;
+
+ case H5D_CHUNK_IDX_NONE: /* Implicit Index */
+ mesg->storage.u.chunk.ops = H5D_COPS_NONE;
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE: /* Single Chunk Index */
+ if(mesg->u.chunk.flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
+ H5F_DECODE_LENGTH(f, p, mesg->storage.u.chunk.u.single.nbytes);
+ UINT32DECODE(p, mesg->storage.u.chunk.u.single.filter_mask);
+ } /* end if */
+
+ /* Set the chunk operations */
+ mesg->storage.u.chunk.ops = H5D_COPS_SINGLE;
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ /* Fixed array creation parameters */
+ mesg->u.chunk.u.farray.cparam.max_dblk_page_nelmts_bits = *p++;
+ if(0 == mesg->u.chunk.u.farray.cparam.max_dblk_page_nelmts_bits)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid fixed array creation parameter")
+
+ /* Set the chunk operations */
+ mesg->storage.u.chunk.ops = H5D_COPS_FARRAY;
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ /* Extensible array creation parameters */
+ mesg->u.chunk.u.earray.cparam.max_nelmts_bits = *p++;
+ if(0 == mesg->u.chunk.u.earray.cparam.max_nelmts_bits)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid extensible array creation parameter")
+ mesg->u.chunk.u.earray.cparam.idx_blk_elmts = *p++;
+ if(0 == mesg->u.chunk.u.earray.cparam.idx_blk_elmts)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid extensible array creation parameter")
+ mesg->u.chunk.u.earray.cparam.sup_blk_min_data_ptrs = *p++;
+ if(0 == mesg->u.chunk.u.earray.cparam.sup_blk_min_data_ptrs)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid extensible array creation parameter")
+ mesg->u.chunk.u.earray.cparam.data_blk_min_elmts = *p++;
+ if(0 == mesg->u.chunk.u.earray.cparam.data_blk_min_elmts)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid extensible array creation parameter")
+ mesg->u.chunk.u.earray.cparam.max_dblk_page_nelmts_bits = *p++;
+ if(0 == mesg->u.chunk.u.earray.cparam.max_dblk_page_nelmts_bits)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid extensible array creation parameter")
+
+ /* Set the chunk operations */
+ mesg->storage.u.chunk.ops = H5D_COPS_EARRAY;
+ break;
+
+ case H5D_CHUNK_IDX_BT2: /* v2 B-tree index */
+ UINT32DECODE(p, mesg->u.chunk.u.btree2.cparam.node_size);
+ mesg->u.chunk.u.btree2.cparam.split_percent = *p++;
+ mesg->u.chunk.u.btree2.cparam.merge_percent = *p++;
+
+ /* Set the chunk operations */
+ mesg->storage.u.chunk.ops = H5D_COPS_BT2;
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "Invalid chunk index type")
+ } /* end switch */
+
+ /* Chunk index address */
+ H5F_addr_decode(f, &p, &(mesg->storage.u.chunk.idx_addr));
+ } /* end else */
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_CHUNK;
+ break;
+
+ case H5D_VIRTUAL:
+ /* Check version */
+ if(mesg->version < H5O_LAYOUT_VERSION_4)
+ HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "invalid layout version with virtual layout")
+
+ /* Heap information */
+ H5F_addr_decode(f, &p, &(mesg->storage.u.virt.serial_list_hobjid.addr));
+ UINT32DECODE(p, mesg->storage.u.virt.serial_list_hobjid.idx);
+
+ /* Initialize other fields */
+ mesg->storage.u.virt.list_nused = 0;
+ mesg->storage.u.virt.list = NULL;
+ mesg->storage.u.virt.list_nalloc = 0;
+ mesg->storage.u.virt.view = H5D_VDS_ERROR;
+ mesg->storage.u.virt.printf_gap = HSIZE_UNDEF;
+ mesg->storage.u.virt.source_fapl = -1;
+ mesg->storage.u.virt.source_dapl = -1;
+ mesg->storage.u.virt.init = FALSE;
+
+ /* Decode heap block if it exists */
+ if(mesg->storage.u.virt.serial_list_hobjid.addr != HADDR_UNDEF) {
+ const uint8_t *heap_block_p;
+ uint8_t heap_vers;
+ size_t block_size = 0;
+ size_t tmp_size;
+ hsize_t tmp_hsize;
+ uint32_t stored_chksum;
+ uint32_t computed_chksum;
+ size_t i;
+
+ /* Read heap */
+ if(NULL == (heap_block = (uint8_t *)H5HG_read(f, dxpl_id, &(mesg->storage.u.virt.serial_list_hobjid), NULL, &block_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "Unable to read global heap block")
+
+ heap_block_p = (const uint8_t *)heap_block;
+
+ /* Decode the version number of the heap block encoding */
+ heap_vers = (uint8_t)*heap_block_p++;
+ if((uint8_t)H5O_LAYOUT_VDS_GH_ENC_VERS != heap_vers)
+ HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad version # of encoded VDS heap information, expected %u, got %u", (unsigned)H5O_LAYOUT_VDS_GH_ENC_VERS, (unsigned)heap_vers)
+
+ /* Number of entries */
+ H5F_DECODE_LENGTH(f, heap_block_p, tmp_hsize)
+
+ /* Allocate entry list */
+ if(NULL == (mesg->storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_calloc((size_t)tmp_hsize * sizeof(H5O_storage_virtual_ent_t))))
+ HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, NULL, "unable to allocate heap block")
+ mesg->storage.u.virt.list_nalloc = (size_t)tmp_hsize;
+ mesg->storage.u.virt.list_nused = (size_t)tmp_hsize;
+
+ /* Decode each entry */
+ for(i = 0; i < mesg->storage.u.virt.list_nused; i++) {
+ /* Source file name */
+ tmp_size = HDstrlen((const char *)heap_block_p) + 1;
+ if(NULL == (mesg->storage.u.virt.list[i].source_file_name = (char *)H5MM_malloc(tmp_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, NULL, "unable to allocate memory for source file name")
+ (void)HDmemcpy(mesg->storage.u.virt.list[i].source_file_name, heap_block_p, tmp_size);
+ heap_block_p += tmp_size;
+
+ /* Source dataset name */
+ tmp_size = HDstrlen((const char *)heap_block_p) + 1;
+ if(NULL == (mesg->storage.u.virt.list[i].source_dset_name = (char *)H5MM_malloc(tmp_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, NULL, "unable to allocate memory for source dataset name")
+ (void)HDmemcpy(mesg->storage.u.virt.list[i].source_dset_name, heap_block_p, tmp_size);
+ heap_block_p += tmp_size;
+
+ /* Source selection */
+ if(H5S_SELECT_DESERIALIZE(&mesg->storage.u.virt.list[i].source_select, &heap_block_p) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't decode source space selection")
+
+ /* Virtual selection */
+ if(H5S_SELECT_DESERIALIZE(&mesg->storage.u.virt.list[i].source_dset.virtual_select, &heap_block_p) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't decode virtual space selection")
+
+ /* Parse source file and dataset names for "printf"
+ * style format specifiers */
+ if(H5D_virtual_parse_source_name(mesg->storage.u.virt.list[i].source_file_name, &mesg->storage.u.virt.list[i].parsed_source_file_name, &mesg->storage.u.virt.list[i].psfn_static_strlen, &mesg->storage.u.virt.list[i].psfn_nsubs) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't parse source file name")
+ if(H5D_virtual_parse_source_name(mesg->storage.u.virt.list[i].source_dset_name, &mesg->storage.u.virt.list[i].parsed_source_dset_name, &mesg->storage.u.virt.list[i].psdn_static_strlen, &mesg->storage.u.virt.list[i].psdn_nsubs) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't parse source dataset name")
+
+ /* Set source names in source_dset struct */
+ if((mesg->storage.u.virt.list[i].psfn_nsubs == 0)
+ && (mesg->storage.u.virt.list[i].psdn_nsubs == 0)) {
+ if(mesg->storage.u.virt.list[i].parsed_source_file_name)
+ mesg->storage.u.virt.list[i].source_dset.file_name = mesg->storage.u.virt.list[i].parsed_source_file_name->name_segment;
+ else
+ mesg->storage.u.virt.list[i].source_dset.file_name = mesg->storage.u.virt.list[i].source_file_name;
+ if(mesg->storage.u.virt.list[i].parsed_source_dset_name)
+ mesg->storage.u.virt.list[i].source_dset.dset_name = mesg->storage.u.virt.list[i].parsed_source_dset_name->name_segment;
+ else
+ mesg->storage.u.virt.list[i].source_dset.dset_name = mesg->storage.u.virt.list[i].source_dset_name;
+ } /* end if */
+
+ /* unlim_dim fields */
+ mesg->storage.u.virt.list[i].unlim_dim_source = H5S_get_select_unlim_dim(mesg->storage.u.virt.list[i].source_select);
+ mesg->storage.u.virt.list[i].unlim_dim_virtual = H5S_get_select_unlim_dim(mesg->storage.u.virt.list[i].source_dset.virtual_select);
+ mesg->storage.u.virt.list[i].unlim_extent_source = HSIZE_UNDEF;
+ mesg->storage.u.virt.list[i].unlim_extent_virtual = HSIZE_UNDEF;
+ mesg->storage.u.virt.list[i].clip_size_source = HSIZE_UNDEF;
+ mesg->storage.u.virt.list[i].clip_size_virtual = HSIZE_UNDEF;
+
+ /* Clipped selections */
+ if(mesg->storage.u.virt.list[i].unlim_dim_virtual < 0) {
+ mesg->storage.u.virt.list[i].source_dset.clipped_source_select = mesg->storage.u.virt.list[i].source_select;
+ mesg->storage.u.virt.list[i].source_dset.clipped_virtual_select = mesg->storage.u.virt.list[i].source_dset.virtual_select;
+ } /* end if */
+
+ /* Check mapping for validity (do both pre and post
+ * checks here, since we had to allocate the entry list
+ * before decoding the selections anyways) */
+ if(H5D_virtual_check_mapping_pre(mesg->storage.u.virt.list[i].source_dset.virtual_select, mesg->storage.u.virt.list[i].source_select, H5O_VIRTUAL_STATUS_INVALID) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "invalid mapping selections")
+ if(H5D_virtual_check_mapping_post(&mesg->storage.u.virt.list[i]) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid mapping entry")
+
+ /* Update min_dims */
+ if(H5D_virtual_update_min_dims(mesg, i) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to update virtual dataset minimum dimensions")
+ } /* end for */
+
+ /* Read stored checksum */
+ UINT32DECODE(heap_block_p, stored_chksum)
+
+ /* Compute checksum */
+ computed_chksum = H5_checksum_metadata(heap_block, block_size - (size_t)4, 0);
+
+ /* Verify checksum */
+ if(stored_chksum != computed_chksum)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect metadata checksum for global heap block")
+
+ /* Verify that the heap block size is correct */
+ if((size_t)(heap_block_p - heap_block) != block_size)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect heap block size")
+ } /* end if */
+
+ /* Set the layout operations */
+ mesg->ops = H5D_LOPS_VIRTUAL;
+
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "Invalid layout class")
+ } /* end switch */
+ } /* end else */
+
+ /* Set return value */
+ ret_value = mesg;
+
+done:
+ if(ret_value == NULL)
+ if(mesg) {
+ if(mesg->type == H5D_VIRTUAL)
+ if(H5D__virtual_reset_layout(mesg) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, "unable to reset virtual layout")
+ mesg = H5FL_FREE(H5O_layout_t, mesg);
+ } /* end if */
+
+ heap_block = (uint8_t *)H5MM_xfree(heap_block);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ * Note:
+ * Quincey Koziol, 2004-5-21
+ * We write out version 3 messages by default now.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__layout_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_layout_t *mesg = (const H5O_layout_t *) _mesg;
+ uint8_t *heap_block = NULL;
+ size_t *str_size = NULL;
+ unsigned u;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(p);
+
+ /* Message version */
+ *p++ = (uint8_t)((mesg->version < H5O_LAYOUT_VERSION_3) ?
+ H5O_LAYOUT_VERSION_3 : mesg->version);
+
+ /* Layout class */
+ *p++ = mesg->type;
+
+ /* Write out layout class specific information */
+ switch(mesg->type) {
+ case H5D_COMPACT:
+ /* Size of raw data */
+ UINT16ENCODE(p, mesg->storage.u.compact.size);
+
+ /* Raw data */
+ if(mesg->storage.u.compact.size > 0) {
+ if(mesg->storage.u.compact.buf)
+ HDmemcpy(p, mesg->storage.u.compact.buf, mesg->storage.u.compact.size);
+ else
+ HDmemset(p, 0, mesg->storage.u.compact.size);
+ p += mesg->storage.u.compact.size;
+ } /* end if */
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Contiguous storage address */
+ H5F_addr_encode(f, &p, mesg->storage.u.contig.addr);
+
+ /* Contiguous storage size */
+ H5F_ENCODE_LENGTH(f, p, mesg->storage.u.contig.size);
+ break;
+
+ case H5D_CHUNKED:
+ if(mesg->version < H5O_LAYOUT_VERSION_4) {
+ /* Number of dimensions */
+ HDassert(mesg->u.chunk.ndims > 0 && mesg->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ *p++ = (uint8_t)mesg->u.chunk.ndims;
+
+ /* B-tree address */
+ H5F_addr_encode(f, &p, mesg->storage.u.chunk.idx_addr);
+
+ /* Dimension sizes */
+ for(u = 0; u < mesg->u.chunk.ndims; u++)
+ UINT32ENCODE(p, mesg->u.chunk.dim[u]);
+ } /* end if */
+ else {
+ /* Chunk feature flags */
+ *p++ = mesg->u.chunk.flags;
+
+ /* Number of dimensions */
+ HDassert(mesg->u.chunk.ndims > 0 && mesg->u.chunk.ndims <= H5O_LAYOUT_NDIMS);
+ *p++ = (uint8_t)mesg->u.chunk.ndims;
+
+ /* Encoded # of bytes for each chunk dimension */
+ HDassert(mesg->u.chunk.enc_bytes_per_dim > 0 && mesg->u.chunk.enc_bytes_per_dim <= 8);
+ *p++ = (uint8_t)mesg->u.chunk.enc_bytes_per_dim;
+
+ /* Dimension sizes */
+ for(u = 0; u < mesg->u.chunk.ndims; u++)
+ UINT64ENCODE_VAR(p, mesg->u.chunk.dim[u], mesg->u.chunk.enc_bytes_per_dim);
+
+ /* Chunk index type */
+ *p++ = (uint8_t)mesg->u.chunk.idx_type;
+
+ switch(mesg->u.chunk.idx_type) {
+ case H5D_CHUNK_IDX_BTREE:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "v1 B-tree index type should never be in a v4 layout message")
+ break;
+
+ case H5D_CHUNK_IDX_NONE: /* Implicit */
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE: /* Single Chunk */
+ /* Filter information */
+ if(mesg->u.chunk.flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
+ H5F_ENCODE_LENGTH(f, p, mesg->storage.u.chunk.u.single.nbytes);
+ UINT32ENCODE(p, mesg->storage.u.chunk.u.single.filter_mask);
+ } /* end if */
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ /* Fixed array creation parameters */
+ *p++ = mesg->u.chunk.u.farray.cparam.max_dblk_page_nelmts_bits;
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ /* Extensible array creation parameters */
+ *p++ = mesg->u.chunk.u.earray.cparam.max_nelmts_bits;
+ *p++ = mesg->u.chunk.u.earray.cparam.idx_blk_elmts;
+ *p++ = mesg->u.chunk.u.earray.cparam.sup_blk_min_data_ptrs;
+ *p++ = mesg->u.chunk.u.earray.cparam.data_blk_min_elmts;
+ *p++ = mesg->u.chunk.u.earray.cparam.max_dblk_page_nelmts_bits;
+ break;
+
+ case H5D_CHUNK_IDX_BT2: /* v2 B-tree index */
+ UINT32ENCODE(p, mesg->u.chunk.u.btree2.cparam.node_size);
+ *p++ = mesg->u.chunk.u.btree2.cparam.split_percent;
+ *p++ = mesg->u.chunk.u.btree2.cparam.merge_percent;
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "Invalid chunk index type")
+ } /* end switch */
+
+ /*
+ * Implicit index: Address of the chunks
+ * Single chunk index: address of the single chunk
+ * Other indexes: chunk index address
+ */
+ H5F_addr_encode(f, &p, mesg->storage.u.chunk.idx_addr);
+ } /* end else */
+ break;
+
+ case H5D_VIRTUAL:
+ /* Create heap block if it has not been created yet */
+ /* Note that we assume here that the contents of the heap block
+ * cannot change! If this ever stops being the case we must change
+ * this code to allow overwrites of the heap block. -NAF */
+ if((mesg->storage.u.virt.serial_list_hobjid.addr == HADDR_UNDEF)
+ && (mesg->storage.u.virt.list_nused > 0)) {
+ uint8_t *heap_block_p;
+ size_t block_size;
+ hssize_t select_serial_size;
+ hsize_t tmp_hsize;
+ uint32_t chksum;
+ size_t i;
+
+ /* Allocate array for caching results of strlen */
+ if(NULL == (str_size = (size_t *)H5MM_malloc(2 * mesg->storage.u.virt.list_nused *sizeof(size_t))))
+ HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate string length array")
+
+ /*
+ * Calculate heap block size
+ */
+ /* Version and number of entries */
+ block_size = (size_t)1 + H5F_SIZEOF_SIZE(f);
+
+ /* Calculate size of each entry */
+ for(i = 0; i < mesg->storage.u.virt.list_nused; i++) {
+ HDassert(mesg->storage.u.virt.list[i].source_file_name);
+ HDassert(mesg->storage.u.virt.list[i].source_dset_name);
+ HDassert(mesg->storage.u.virt.list[i].source_select);
+ HDassert(mesg->storage.u.virt.list[i].source_dset.virtual_select);
+
+ /* Source file name */
+ str_size[2 * i] = HDstrlen(mesg->storage.u.virt.list[i].source_file_name) + (size_t)1;
+ block_size += str_size[2 * i];
+
+ /* Source dset name */
+ str_size[(2 * i) + 1] = HDstrlen(mesg->storage.u.virt.list[i].source_dset_name) + (size_t)1;
+ block_size += str_size[(2 * i) + 1];
+
+ /* Source selection */
+ if((select_serial_size = H5S_SELECT_SERIAL_SIZE(mesg->storage.u.virt.list[i].source_select)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size")
+ block_size += (size_t)select_serial_size;
+
+ /* Virtual dataset selection */
+ if((select_serial_size = H5S_SELECT_SERIAL_SIZE(mesg->storage.u.virt.list[i].source_dset.virtual_select)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to check dataspace selection size")
+ block_size += (size_t)select_serial_size;
+ } /* end for */
+
+ /* Checksum */
+ block_size += 4;
+
+ /* Allocate heap block */
+ if(NULL == (heap_block = (uint8_t *)H5MM_malloc(block_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate heap block")
+
+ /*
+ * Encode heap block
+ */
+ heap_block_p = heap_block;
+
+ /* Encode heap block encoding version */
+ *heap_block_p++ = (uint8_t)H5O_LAYOUT_VDS_GH_ENC_VERS;
+
+ /* Number of entries */
+ tmp_hsize = (hsize_t)mesg->storage.u.virt.list_nused;
+ H5F_ENCODE_LENGTH(f, heap_block_p, tmp_hsize)
+
+ /* Encode each entry */
+ for(i = 0; i < mesg->storage.u.virt.list_nused; i++) {
+ /* Source file name */
+ (void)HDmemcpy((char *)heap_block_p, mesg->storage.u.virt.list[i].source_file_name, str_size[2 * i]);
+ heap_block_p += str_size[2 * i];
+
+ /* Source dataset name */
+ (void)HDmemcpy((char *)heap_block_p, mesg->storage.u.virt.list[i].source_dset_name, str_size[(2 * i) + 1]);
+ heap_block_p += str_size[(2 * i) + 1];
+
+ /* Source selection */
+ if(H5S_SELECT_SERIALIZE(mesg->storage.u.virt.list[i].source_select, &heap_block_p) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize source selection")
+
+ /* Virtual selection */
+ if(H5S_SELECT_SERIALIZE(mesg->storage.u.virt.list[i].source_dset.virtual_select, &heap_block_p) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to serialize virtual selection")
+ } /* end for */
+
+ /* Checksum */
+ chksum = H5_checksum_metadata(heap_block, block_size - (size_t)4, 0);
+ UINT32ENCODE(heap_block_p, chksum)
+
+ /* Insert block into global heap */
+ if(H5HG_insert(f, H5AC_ind_read_dxpl_id, block_size, heap_block, &((H5O_layout_t *)mesg)->storage.u.virt.serial_list_hobjid) < 0) /* Casting away const OK --NAF */
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to insert virtual dataset heap block")
+ } /* end if */
+
+ /* Heap information */
+ H5F_addr_encode(f, &p, mesg->storage.u.virt.serial_list_hobjid.addr);
+ UINT32ENCODE(p, mesg->storage.u.virt.serial_list_hobjid.idx);
+
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "Invalid layout class")
+ } /* end switch */
+
+done:
+ heap_block = (uint8_t *)H5MM_xfree(heap_block);
+ str_size = (size_t *)H5MM_xfree(str_size);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__layout_copy(const void *_mesg, void *_dest)
+{
+ const H5O_layout_t *mesg = (const H5O_layout_t *) _mesg;
+ H5O_layout_t *dest = (H5O_layout_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(mesg);
+
+ /* Allocate destination message, if necessary */
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_layout_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "layout message allocation failed")
+
+ /* copy */
+ *dest = *mesg;
+
+ /* Special actions for each type of layout */
+ switch(mesg->type) {
+ case H5D_COMPACT:
+ /* Deep copy the buffer for compact datasets also */
+ if(mesg->storage.u.compact.size > 0) {
+ /* Sanity check */
+ HDassert(mesg->storage.u.compact.buf);
+
+ /* Allocate memory for the raw data */
+ if(NULL == (dest->storage.u.compact.buf = H5MM_malloc(dest->storage.u.compact.size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "unable to allocate memory for compact dataset")
+
+ /* Copy over the raw data */
+ HDmemcpy(dest->storage.u.compact.buf, mesg->storage.u.compact.buf, dest->storage.u.compact.size);
+ } /* end if */
+ else
+ HDassert(dest->storage.u.compact.buf == NULL);
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Nothing required */
+ break;
+
+ case H5D_CHUNKED:
+ /* Reset the pointer of the chunked storage index but not the address */
+ if(dest->storage.u.chunk.ops)
+ H5D_chunk_idx_reset(&dest->storage.u.chunk, FALSE);
+ break;
+
+ case H5D_VIRTUAL:
+ if(H5D__virtual_copy_layout(dest) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy virtual layout")
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, NULL, "Invalid layout class")
+ } /* end switch */
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ if(ret_value == NULL)
+ if(NULL == _dest)
+ dest = H5FL_FREE(H5O_layout_t, dest);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_size
+ *
+ * Purpose: Returns the size of the raw message in bytes. If it's
+ * compact dataset, the data part is also included.
+ * This function doesn't take into account message alignment.
+ *
+ * Return: Success: Message data size in bytes
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O__layout_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_layout_t *mesg = (const H5O_layout_t *) _mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Compute serialized size */
+ /* (including possibly compact data) */
+ ret_value = H5D__layout_meta_size(f, mesg, TRUE);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_reset
+ *
+ * Purpose: Frees resources within a data type message, but doesn't free
+ * the message itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 13, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__layout_reset(void *_mesg)
+{
+ H5O_layout_t *mesg = (H5O_layout_t *)_mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(mesg) {
+ /* Free the compact storage buffer */
+ if(H5D_COMPACT == mesg->type)
+ mesg->storage.u.compact.buf = H5MM_xfree(mesg->storage.u.compact.buf);
+ else if(H5D_VIRTUAL == mesg->type)
+ /* Free the virtual entry list */
+ if(H5D__virtual_reset_layout(mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to reset virtual layout")
+
+ /* Reset the message */
+ mesg->type = H5D_CONTIGUOUS;
+ mesg->version = H5O_LAYOUT_VERSION_DEFAULT;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 11, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__layout_free(void *_mesg)
+{
+ H5O_layout_t *mesg = (H5O_layout_t *) _mesg;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(mesg);
+
+ /* Free resources within the message */
+ H5O__layout_reset(mesg);
+
+ (void)H5FL_FREE(H5O_layout_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__layout_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, March 19, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__layout_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_layout_t *mesg = (H5O_layout_t *) _mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(open_oh);
+ HDassert(mesg);
+
+ /* Perform different actions, depending on the type of storage */
+ switch(mesg->type) {
+ case H5D_COMPACT: /* Compact data storage */
+ /* Nothing required */
+ break;
+
+ case H5D_CONTIGUOUS: /* Contiguous block on disk */
+ /* Free the file space for the raw data */
+ if(H5D__contig_delete(f, dxpl_id, &mesg->storage) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free raw data")
+ break;
+
+ case H5D_CHUNKED: /* Chunked blocks on disk */
+ /* Free the file space for the index & chunk raw data */
+ if(H5D__chunk_delete(f, dxpl_id, open_oh, &mesg->storage) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free raw data")
+ break;
+
+ case H5D_VIRTUAL: /* Virtual dataset */
+ /* Free the file space virtual dataset */
+ if(H5D__virtual_delete(f, dxpl_id, &mesg->storage) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free raw data")
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "not valid storage type")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Peter Cao
+ * July 23, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O__layout_copy_file(H5F_t *file_src, void *mesg_src, H5F_t *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t *cpy_info, void *_udata, hid_t dxpl_id)
+{
+ H5D_copy_file_ud_t *udata = (H5D_copy_file_ud_t *)_udata; /* Dataset copying user data */
+ H5O_layout_t *layout_src = (H5O_layout_t *) mesg_src;
+ H5O_layout_t *layout_dst = NULL;
+ hbool_t copied = FALSE; /* Whether the data was copied */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(file_src);
+ HDassert(layout_src);
+ HDassert(file_dst);
+
+ /* Copy the layout information */
+ if(NULL == (layout_dst = (H5O_layout_t *)H5O__layout_copy(layout_src, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy layout")
+
+ /* Copy the layout type specific information */
+ switch(layout_src->type) {
+ case H5D_COMPACT:
+ if(layout_src->storage.u.compact.buf) {
+ /* copy compact raw data */
+ if(H5D__compact_copy(file_src, &layout_src->storage.u.compact, file_dst, &layout_dst->storage.u.compact, udata->src_dtype, cpy_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy chunked storage")
+ copied = TRUE;
+ } /* end if */
+ break;
+
+ case H5D_CONTIGUOUS:
+ /* Compute the size of the contiguous storage for versions of the
+ * layout message less than version 3 because versions 1 & 2 would
+ * truncate the dimension sizes to 32-bits of information. - QAK 5/26/04
+ */
+ if(layout_src->version < H5O_LAYOUT_VERSION_3)
+ layout_dst->storage.u.contig.size = H5S_extent_nelem(udata->src_space_extent) *
+ H5T_get_size(udata->src_dtype);
+
+ if(H5D__contig_is_space_alloc(&layout_src->storage)) {
+ /* copy contiguous raw data */
+ if(H5D__contig_copy(file_src, &layout_src->storage.u.contig, file_dst, &layout_dst->storage.u.contig, udata->src_dtype, cpy_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy contiguous storage")
+ copied = TRUE;
+ } /* end if */
+ break;
+
+ case H5D_CHUNKED:
+ if(H5D__chunk_is_space_alloc(&layout_src->storage)) {
+ /* Create chunked layout */
+ if(H5D__chunk_copy(file_src, &layout_src->storage.u.chunk, &layout_src->u.chunk, file_dst, &layout_dst->storage.u.chunk, udata->src_space_extent, udata->src_dtype, udata->common.src_pline, cpy_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy chunked storage")
+ copied = TRUE;
+ } /* end if */
+ break;
+
+ case H5D_VIRTUAL:
+ /* Copy virtual layout. Always copy so the memory fields get copied
+ * properly. */
+ if(H5D__virtual_copy(file_dst, layout_dst, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy virtual storage")
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "Invalid layout class")
+ } /* end switch */
+
+ /* Check if copy routine was invoked (which frees the source datatype) */
+ if(copied)
+ udata->src_dtype = NULL;
+
+ /* Set return value */
+ ret_value = layout_dst;
+
+done:
+ if(!ret_value)
+ if(layout_dst)
+ layout_dst = H5FL_FREE(H5O_layout_t, layout_dst);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__layout_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__layout_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__layout_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth)
+{
+ const H5O_layout_t *mesg = (const H5O_layout_t *) _mesg;
+ size_t u;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Version:", mesg->version);
+ switch(mesg->type) {
+ case H5D_CHUNKED:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Type:", "Chunked");
+
+ /* Chunk # of dims & size */
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Number of dimensions:",
+ (unsigned long)(mesg->u.chunk.ndims));
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Size:");
+ for(u = 0; u < (size_t)mesg->u.chunk.ndims; u++)
+ HDfprintf(stream, "%s%lu", u ? ", " : "", (unsigned long)(mesg->u.chunk.dim[u]));
+ HDfprintf(stream, "}\n");
+
+ /* Index information */
+ switch(mesg->u.chunk.idx_type) {
+ case H5D_CHUNK_IDX_BTREE:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "v1 B-tree");
+ break;
+
+ case H5D_CHUNK_IDX_NONE:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "Implicit");
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "Single Chunk");
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "Fixed Array");
+ /* (Should print the fixed array creation parameters) */
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "Extensible Array");
+ /* (Should print the extensible array creation parameters) */
+ break;
+
+ case H5D_CHUNK_IDX_BT2:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Index Type:", "v2 B-tree");
+ /* (Should print the v2-Btree creation parameters) */
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ default:
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Index Type:", "Unknown", (unsigned)mesg->u.chunk.idx_type);
+ break;
+ } /* end switch */
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Index address:", mesg->storage.u.chunk.idx_addr);
+ break;
+
+ case H5D_CONTIGUOUS:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Type:", "Contiguous");
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Data address:", mesg->storage.u.contig.addr);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Data Size:", mesg->storage.u.contig.size);
+ break;
+
+ case H5D_COMPACT:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Type:", "Compact");
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Data Size:", mesg->storage.u.compact.size);
+ break;
+
+ case H5D_VIRTUAL:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Type:", "Virtual");
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Global heap address:", mesg->storage.u.virt.serial_list_hobjid.addr);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "Global heap index:", mesg->storage.u.virt.serial_list_hobjid.idx);
+ for(u = 0; u < mesg->storage.u.virt.list_nused; u++) {
+ HDfprintf(stream, "%*sMapping %u:\n", indent, "", u);
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth - 3,
+ "Virtual selection:", "<Not yet implemented>");
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth - 3,
+ "Source file name:", mesg->storage.u.virt.list[u].source_file_name);
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth - 3,
+ "Source dataset name:", mesg->storage.u.virt.list[u].source_dset_name);
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth - 3,
+ "Source selection:", "<Not yet implemented>");
+ } /* end for */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Type:", "Unknown", (unsigned)mesg->type);
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O__layout_debug() */
+
diff --git a/src/H5Olinfo.c b/src/H5Olinfo.c
new file mode 100644
index 0000000..cac4ed1
--- /dev/null
+++ b/src/H5Olinfo.c
@@ -0,0 +1,592 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Olinfo.c
+ * Aug 23 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Link Information messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#define H5L_FRIEND /*suppress error about including H5Lpkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Lpkg.h" /* Links */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_linfo_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_linfo_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_linfo_copy(const void *_mesg, void *_dest);
+static size_t H5O_linfo_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_linfo_free(void *_mesg);
+static herr_t H5O_linfo_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ void *_mesg);
+static void *H5O_linfo_copy_file(H5F_t *file_src, void *native_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_linfo_post_copy_file(const H5O_loc_t *parent_src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst,
+ unsigned *mesg_flags, hid_t dxpl_id, H5O_copy_t *cpy_info);
+static herr_t H5O_linfo_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_LINFO[1] = {{
+ H5O_LINFO_ID, /*message id number */
+ "linfo", /*message name for debugging */
+ sizeof(H5O_linfo_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_linfo_decode, /*decode message */
+ H5O_linfo_encode, /*encode message */
+ H5O_linfo_copy, /*copy the native value */
+ H5O_linfo_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_linfo_free, /* free method */
+ H5O_linfo_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ H5O_linfo_copy_file, /* copy native value to file */
+ H5O_linfo_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_linfo_debug /*debug the message */
+}};
+
+/* Current version of link info information */
+#define H5O_LINFO_VERSION 0
+
+/* Flags for link info index flag encoding */
+#define H5O_LINFO_TRACK_CORDER 0x01
+#define H5O_LINFO_INDEX_CORDER 0x02
+#define H5O_LINFO_ALL_FLAGS (H5O_LINFO_TRACK_CORDER | H5O_LINFO_INDEX_CORDER)
+
+/* Data exchange structure to use when copying links from src to dst */
+typedef struct {
+ const H5O_loc_t *src_oloc; /* Source object location */
+ H5O_loc_t *dst_oloc; /* Destination object location */
+ H5O_linfo_t *dst_linfo; /* Destination object's link info message */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5O_copy_t *cpy_info; /* Information for copy operation */
+} H5O_linfo_postcopy_ud_t;
+
+/* Declare a free list to manage the H5O_linfo_t struct */
+H5FL_DEFINE_STATIC(H5O_linfo_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_decode
+ *
+ * Purpose: Decode a message and return a pointer to a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native form.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_linfo_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_linfo_t *linfo = NULL; /* Link info */
+ unsigned char index_flags; /* Flags for encoding link index info */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_LINFO_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (linfo = H5FL_MALLOC(H5O_linfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get the index flags for the group */
+ index_flags = *p++;
+ if(index_flags & ~H5O_LINFO_ALL_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message")
+ linfo->track_corder = (index_flags & H5O_LINFO_TRACK_CORDER) ? TRUE : FALSE;
+ linfo->index_corder = (index_flags & H5O_LINFO_INDEX_CORDER) ? TRUE : FALSE;
+
+ /* Set the number of links in the group to an invalid value, so we query it later */
+ linfo->nlinks = HSIZET_MAX;
+
+ /* Max. link creation order value for the group, if tracked */
+ if(linfo->track_corder)
+ INT64DECODE(p, linfo->max_corder)
+ else
+ linfo->max_corder = 0;
+
+ /* Address of fractal heap to store "dense" links */
+ H5F_addr_decode(f, &p, &(linfo->fheap_addr));
+
+ /* Address of v2 B-tree to index names of links (names are always indexed) */
+ H5F_addr_decode(f, &p, &(linfo->name_bt2_addr));
+
+ /* Address of v2 B-tree to index creation order of links, if there is one */
+ if(linfo->index_corder)
+ H5F_addr_decode(f, &p, &(linfo->corder_bt2_addr));
+ else
+ linfo->corder_bt2_addr = HADDR_UNDEF;
+
+ /* Set return value */
+ ret_value = linfo;
+
+done:
+ if(ret_value == NULL)
+ if(linfo != NULL)
+ linfo = H5FL_FREE(H5O_linfo_t, linfo);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_linfo_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_linfo_t *linfo = (const H5O_linfo_t *)_mesg;
+ unsigned char index_flags; /* Flags for encoding link index info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(linfo);
+
+ /* Message version */
+ *p++ = H5O_LINFO_VERSION;
+
+ /* The flags for the link indices */
+ index_flags = linfo->track_corder ? H5O_LINFO_TRACK_CORDER : 0;
+ index_flags = (uint8_t)(index_flags | (linfo->index_corder ? H5O_LINFO_INDEX_CORDER : 0));
+ *p++ = index_flags;
+
+ /* Max. link creation order value for the group, if tracked */
+ if(linfo->track_corder)
+ INT64ENCODE(p, linfo->max_corder)
+
+ /* Address of fractal heap to store "dense" links */
+ H5F_addr_encode(f, &p, linfo->fheap_addr);
+
+ /* Address of v2 B-tree to index names of links */
+ H5F_addr_encode(f, &p, linfo->name_bt2_addr);
+
+ /* Address of v2 B-tree to index creation order of links, if they are indexed */
+ if(linfo->index_corder)
+ H5F_addr_encode(f, &p, linfo->corder_bt2_addr);
+ else
+ HDassert(!H5F_addr_defined(linfo->corder_bt2_addr));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_linfo_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_linfo_copy(const void *_mesg, void *_dest)
+{
+ const H5O_linfo_t *linfo = (const H5O_linfo_t *)_mesg;
+ H5O_linfo_t *dest = (H5O_linfo_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(linfo);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_linfo_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *linfo;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_linfo_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_linfo_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_linfo_t *linfo = (const H5O_linfo_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = 1 /* Version */
+ + 1 /* Index flags */
+ + (linfo->track_corder ? (size_t)8 : 0) /* Curr. max. creation order value */
+ + (size_t)H5F_SIZEOF_ADDR(f) /* Address of fractal heap to store "dense" links */
+ + (size_t)H5F_SIZEOF_ADDR(f) /* Address of v2 B-tree for indexing names of links */
+ + (linfo->index_corder ? (size_t)H5F_SIZEOF_ADDR(f) : 0); /* Address of v2 B-tree for indexing creation order values of links */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_linfo_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 23, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_linfo_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_linfo_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, September 16, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_delete(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, void *_mesg)
+{
+ H5O_linfo_t *linfo = (H5O_linfo_t *)_mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(linfo);
+
+ /* If the group is using "dense" link storage, delete it */
+ if(H5F_addr_defined(linfo->fheap_addr))
+ if(H5G__dense_delete(f, dxpl_id, linfo, TRUE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free dense link storage")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_linfo_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * June 26, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_linfo_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *native_src, H5F_t *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t *cpy_info, void *_udata, hid_t dxpl_id)
+{
+ H5O_linfo_t *linfo_src = (H5O_linfo_t *) native_src;
+ H5O_linfo_t *linfo_dst = NULL;
+ H5G_copy_file_ud_t *udata = (H5G_copy_file_ud_t *) _udata;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__COPIED_TAG, NULL)
+
+ /* check args */
+ HDassert(linfo_src);
+ HDassert(cpy_info);
+
+ /* Copy the source message */
+ if(NULL == (linfo_dst = (H5O_linfo_t *)H5O_linfo_copy(linfo_src, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "memory allocation failed")
+
+ /* If we are performing a 'shallow hierarchy' copy, and the links in this
+ * group won't be included in the destination, reset the link info for
+ * this group.
+ */
+ if(cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth) {
+ linfo_dst->nlinks = 0;
+ linfo_dst->max_corder = 0;
+ linfo_dst->fheap_addr = HADDR_UNDEF;
+ linfo_dst->name_bt2_addr = HADDR_UNDEF;
+ linfo_dst->corder_bt2_addr = HADDR_UNDEF;
+ } /* end if */
+ else {
+ /* Create the components of the dense link storage for the destination group */
+ /* (XXX: should probably get the "creation" parameters for the source group's
+ * dense link storage components and use those - QAK)
+ */
+ if(H5F_addr_defined(linfo_src->fheap_addr)) {
+ /* Create the dense link storage */
+ if(H5G__dense_create(file_dst, dxpl_id, linfo_dst, udata->common.src_pline) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "unable to create 'dense' form of new format group")
+ } /* end if */
+ } /* end else */
+
+ /* Set return value */
+ ret_value = linfo_dst;
+
+done:
+ if(!ret_value)
+ if(linfo_dst)
+ linfo_dst = H5FL_FREE(H5O_linfo_t, linfo_dst);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* H5O_linfo_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_post_copy_file_cb
+ *
+ * Purpose: Callback routine for copying links from src to dst file
+ * during "post copy" routine
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Sept 26 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_post_copy_file_cb(const H5O_link_t *src_lnk, void *_udata)
+{
+ H5O_linfo_postcopy_ud_t *udata = (H5O_linfo_postcopy_ud_t *)_udata; /* 'User data' passed in */
+ H5O_link_t dst_lnk; /* Destination link to insert */
+ hbool_t dst_lnk_init = FALSE; /* Whether the destination link is initialized */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check arguments */
+ HDassert(src_lnk);
+ HDassert(udata);
+
+ /* Copy the link (and the object it points to) */
+ if(H5L_link_copy_file(udata->dst_oloc->file, udata->dxpl_id, src_lnk,
+ udata->src_oloc, &dst_lnk, udata->cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy link")
+ dst_lnk_init = TRUE;
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(udata->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* Insert the new object in the destination file's group */
+ /* (Doesn't increment the link count - that's already been taken care of for hard links) */
+ if(H5G__dense_insert(udata->dst_oloc->file, udata->dxpl_id, udata->dst_linfo, &dst_lnk) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to insert destination link")
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+done:
+ /* Check if the destination link has been initialized */
+ if(dst_lnk_init)
+ H5O_msg_reset(H5O_LINK_ID, &dst_lnk);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_linfo_post_copy_file_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 26, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
+ H5O_loc_t *dst_oloc, void *mesg_dst, unsigned H5_ATTR_UNUSED *mesg_flags,
+ hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ const H5O_linfo_t *linfo_src = (const H5O_linfo_t *)mesg_src;
+ H5O_linfo_t *linfo_dst = (H5O_linfo_t *)mesg_dst;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(src_oloc && src_oloc->file);
+ HDassert(linfo_src);
+ HDassert(dst_oloc && dst_oloc->file);
+ HDassert(H5F_addr_defined(dst_oloc->addr));
+ HDassert(linfo_dst);
+ HDassert(cpy_info);
+
+ /* If we are performing a 'shallow hierarchy' copy, get out now */
+ if(cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth)
+ HGOTO_DONE(SUCCEED)
+
+ /* Check for copying dense link storage */
+ if(H5F_addr_defined(linfo_src->fheap_addr)) {
+ H5O_linfo_postcopy_ud_t udata; /* User data for iteration callback */
+
+ /* Set up dense link iteration user data */
+ udata.src_oloc = src_oloc;
+ udata.dst_oloc = dst_oloc;
+ udata.dst_linfo = linfo_dst;
+ udata.dxpl_id = dxpl_id;
+ udata.cpy_info = cpy_info;
+
+ /* Iterate over the links in the group, building a table of the link messages */
+ if(H5G__dense_iterate(src_oloc->file, dxpl_id, linfo_src, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, H5O_linfo_post_copy_file_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_linfo_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_linfo_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 23 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_linfo_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_linfo_t *linfo = (const H5O_linfo_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(linfo);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Track creation order of links:", linfo->track_corder);
+ HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth,
+ "Index creation order of links:", linfo->index_corder);
+ HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth,
+ "Number of links:", linfo->nlinks);
+ HDfprintf(stream, "%*s%-*s %Hd\n", indent, "", fwidth,
+ "Max. creation order value:", linfo->max_corder);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' link storage fractal heap address:", linfo->fheap_addr);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' link storage name index v2 B-tree address:", linfo->name_bt2_addr);
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "'Dense' link storage creation order index v2 B-tree address:", linfo->corder_bt2_addr);
+
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_linfo_debug() */
+
diff --git a/src/H5Olink.c b/src/H5Olink.c
new file mode 100644
index 0000000..77872ad
--- /dev/null
+++ b/src/H5Olink.c
@@ -0,0 +1,877 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Olink.c
+ * Aug 29 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Link messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#define H5L_FRIEND /*suppress error about including H5Lpkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lpkg.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_link_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_link_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_link_copy(const void *_mesg, void *_dest);
+static size_t H5O_link_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_link_reset(void *_mesg);
+static herr_t H5O_link_free(void *_mesg);
+static herr_t H5O_link_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata);
+static void *H5O_link_copy_file(H5F_t *file_src, void *native_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+static herr_t H5O_link_post_copy_file(const H5O_loc_t *src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst,
+ unsigned *mesg_flags, hid_t dxpl_id, H5O_copy_t *cpy_info);
+static herr_t H5O_link_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_LINK[1] = {{
+ H5O_LINK_ID, /*message id number */
+ "link", /*message name for debugging */
+ sizeof(H5O_link_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_link_decode, /*decode message */
+ H5O_link_encode, /*encode message */
+ H5O_link_copy, /*copy the native value */
+ H5O_link_size, /*size of symbol table entry */
+ H5O_link_reset, /* reset method */
+ H5O_link_free, /* free method */
+ H5O_link_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ H5O_link_pre_copy_file, /* pre copy native value to file */
+ H5O_link_copy_file, /* copy native value to file */
+ H5O_link_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_link_debug /*debug the message */
+}};
+
+/* Current version of link information */
+#define H5O_LINK_VERSION 1
+
+/* Flags for link flag encoding */
+#define H5O_LINK_NAME_SIZE 0x03 /* 2-bit field for size of name length */
+#define H5O_LINK_STORE_CORDER 0x04 /* Whether to store creation index */
+#define H5O_LINK_STORE_LINK_TYPE 0x08 /* Whether to store non-default link type */
+#define H5O_LINK_STORE_NAME_CSET 0x10 /* Whether to store non-default name character set */
+#define H5O_LINK_ALL_FLAGS (H5O_LINK_NAME_SIZE | H5O_LINK_STORE_CORDER | H5O_LINK_STORE_LINK_TYPE | H5O_LINK_STORE_NAME_CSET)
+
+/* Individual definitions of name size values */
+#define H5O_LINK_NAME_1 0x00 /* Use 1-byte value for name length */
+#define H5O_LINK_NAME_2 0x01 /* Use 2-byte value for name length */
+#define H5O_LINK_NAME_4 0x02 /* Use 4-byte value for name length */
+#define H5O_LINK_NAME_8 0x03 /* Use 8-byte value for name length */
+
+/* Declare a free list to manage the H5O_link_t struct */
+H5FL_DEFINE_STATIC(H5O_link_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_decode
+ *
+ * Purpose: Decode a message and return a pointer to
+ * a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native order.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_link_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_link_t *lnk = NULL; /* Pointer to link message */
+ size_t len = 0; /* Length of a string in the message */
+ unsigned char link_flags; /* Flags for encoding link info */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(*p++ != H5O_LINK_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (lnk = H5FL_CALLOC(H5O_link_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get the encoding flags for the link */
+ link_flags = *p++;
+ if(link_flags & ~H5O_LINK_ALL_FLAGS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message")
+
+ /* Check for non-default link type */
+ if(link_flags & H5O_LINK_STORE_LINK_TYPE) {
+ /* Get the type of the link */
+ lnk->type = (H5L_type_t)*p++;
+ if(lnk->type < H5L_TYPE_HARD || lnk->type > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad link type")
+ } /* end if */
+ else
+ lnk->type = H5L_TYPE_HARD;
+
+ /* Get the link creation time from the file */
+ if(link_flags & H5O_LINK_STORE_CORDER) {
+ INT64DECODE(p, lnk->corder)
+ lnk->corder_valid = TRUE;
+ } /* end if */
+ else {
+ lnk->corder = 0;
+ lnk->corder_valid = FALSE;
+ } /* end else */
+
+ /* Check for non-default name character set */
+ if(link_flags & H5O_LINK_STORE_NAME_CSET) {
+ /* Get the link name's character set */
+ lnk->cset = (H5T_cset_t)*p++;
+ if(lnk->cset < H5T_CSET_ASCII || lnk->cset > H5T_CSET_UTF8)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad cset type")
+ } /* end if */
+ else
+ lnk->cset = H5T_CSET_ASCII;
+
+ /* Get the length of the link's name */
+ switch(link_flags & H5O_LINK_NAME_SIZE) {
+ case 0: /* 1 byte size */
+ len = *p++;
+ break;
+
+ case 1: /* 2 byte size */
+ UINT16DECODE(p, len);
+ break;
+
+ case 2: /* 4 byte size */
+ UINT32DECODE(p, len);
+ break;
+
+ case 3: /* 8 byte size */
+ UINT64DECODE(p, len);
+ break;
+
+ default:
+ HDassert(0 && "bad size for name");
+ } /* end switch */
+ if(len == 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid name length")
+
+ /* Get the link's name */
+ if(NULL == (lnk->name = (char *)H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(lnk->name, p, len);
+ lnk->name[len] = '\0';
+ p += len;
+
+ /* Get the appropriate information for each type of link */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ /* Get the address of the object the link points to */
+ H5F_addr_decode(f, &p, &(lnk->u.hard.addr));
+ break;
+
+ case H5L_TYPE_SOFT:
+ /* Get the link value */
+ UINT16DECODE(p, len)
+ if(len == 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid link length")
+ if(NULL == (lnk->u.soft.name = (char *)H5MM_malloc((size_t)len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(lnk->u.soft.name, p, len);
+ lnk->u.soft.name[len] = '\0';
+ p += len;
+ break;
+
+ /* User-defined links */
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_MAX:
+ default:
+ if(lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown link type")
+
+ /* A UD link. Get the user-supplied data */
+ UINT16DECODE(p, len)
+ lnk->u.ud.size = len;
+ if(len > 0)
+ {
+ if(NULL == (lnk->u.ud.udata = H5MM_malloc((size_t)len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(lnk->u.ud.udata, p, len);
+ p += len;
+ }
+ else
+ lnk->u.ud.udata = NULL;
+ } /* end switch */
+
+ /* Set return value */
+ ret_value = lnk;
+
+done:
+ if(ret_value == NULL)
+ if(lnk != NULL) {
+ if(lnk->name != NULL)
+ H5MM_xfree(lnk->name);
+ if(lnk->type == H5L_TYPE_SOFT && lnk->u.soft.name != NULL)
+ H5MM_xfree(lnk->u.soft.name);
+ if(lnk->type >= H5L_TYPE_UD_MIN && lnk->u.ud.size > 0 && lnk->u.ud.udata != NULL)
+ H5MM_xfree(lnk->u.ud.udata);
+ lnk = H5FL_FREE(H5O_link_t, lnk);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_encode
+ *
+ * Purpose: Encodes a link message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *) _mesg;
+ uint64_t len; /* Length of a string in the message */
+ unsigned char link_flags; /* Flags for encoding link info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(lnk);
+
+ /* Get length of link's name */
+ len = (uint64_t)HDstrlen(lnk->name);
+ HDassert(len > 0);
+
+ /* encode */
+ *p++ = H5O_LINK_VERSION;
+
+ /* The encoding flags for the link */
+ if(len > 4294967295)
+ link_flags = H5O_LINK_NAME_8;
+ else if(len > 65535)
+ link_flags = H5O_LINK_NAME_4;
+ else if(len > 255)
+ link_flags = H5O_LINK_NAME_2;
+ else
+ link_flags = H5O_LINK_NAME_1;
+ link_flags = (unsigned char)(link_flags | (lnk->corder_valid ? H5O_LINK_STORE_CORDER : 0));
+ link_flags = (unsigned char)(link_flags | ((lnk->type != H5L_TYPE_HARD) ? H5O_LINK_STORE_LINK_TYPE : 0));
+ link_flags = (unsigned char)(link_flags | ((lnk->cset != H5T_CSET_ASCII) ? H5O_LINK_STORE_NAME_CSET : 0));
+ *p++ = link_flags;
+
+ /* Store the type of a non-default link */
+ if(link_flags & H5O_LINK_STORE_LINK_TYPE)
+ *p++ = lnk->type;
+
+ /* Store the link creation order in the file, if its valid */
+ if(lnk->corder_valid)
+ INT64ENCODE(p, lnk->corder)
+
+ /* Store a non-default link name character set */
+ if(link_flags & H5O_LINK_STORE_NAME_CSET)
+ *p++ = (uint8_t)lnk->cset;
+
+ /* Store the link name's length */
+ switch(link_flags & H5O_LINK_NAME_SIZE) {
+ case 0: /* 1 byte size */
+ *p++ = (uint8_t)len;
+ break;
+
+ case 1: /* 2 byte size */
+ UINT16ENCODE(p, len);
+ break;
+
+ case 2: /* 4 byte size */
+ UINT32ENCODE(p, len);
+ break;
+
+ case 3: /* 8 byte size */
+ UINT64ENCODE(p, len);
+ break;
+
+ default:
+ HDassert(0 && "bad size for name");
+ } /* end switch */
+
+ /* Store the link's name */
+ HDmemcpy(p, lnk->name, (size_t)len);
+ p += len;
+
+ /* Store the appropriate information for each type of link */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ /* Store the address of the object the link points to */
+ H5F_addr_encode(f, &p, lnk->u.hard.addr);
+ break;
+
+ case H5L_TYPE_SOFT:
+ /* Store the link value */
+ len = (uint16_t)HDstrlen(lnk->u.soft.name);
+ HDassert(len > 0);
+ UINT16ENCODE(p, len)
+ HDmemcpy(p, lnk->u.soft.name, (size_t)len);
+ p += len;
+ break;
+
+ /* User-defined links */
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_MAX:
+ default:
+ HDassert(lnk->type >= H5L_TYPE_UD_MIN && lnk->type <= H5L_TYPE_MAX);
+
+ /* Store the user-supplied data, however long it is */
+ len = (uint16_t)lnk->u.ud.size;
+ UINT16ENCODE(p, len)
+ if(len > 0)
+ {
+ HDmemcpy(p, lnk->u.ud.udata, (size_t)len);
+ p+=len;
+ }
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_link_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_link_copy(const void *_mesg, void *_dest)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *) _mesg;
+ H5O_link_t *dest = (H5O_link_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(lnk);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_link_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy static information */
+ *dest = *lnk;
+
+ /* Duplicate the link's name */
+ HDassert(lnk->name);
+ if(NULL == (dest->name = H5MM_xstrdup(lnk->name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate link name")
+
+ /* Copy other information needed for different link types */
+ if(lnk->type == H5L_TYPE_SOFT) {
+ if(NULL == (dest->u.soft.name = H5MM_xstrdup(lnk->u.soft.name)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate soft link value")
+ } /* end if */
+ else if(lnk->type >= H5L_TYPE_UD_MIN) {
+ if(lnk->u.ud.size > 0) {
+ if(NULL == (dest->u.ud.udata = H5MM_malloc(lnk->u.ud.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(dest->u.ud.udata, lnk->u.ud.udata, lnk->u.ud.size);
+ } /* end if */
+ } /* end if */
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ if(NULL == ret_value)
+ if(dest) {
+ if(dest->name && dest->name != lnk->name)
+ dest->name = (char *)H5MM_xfree(dest->name);
+ if(NULL == _dest)
+ dest = H5FL_FREE(H5O_link_t ,dest);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ *
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_link_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg;
+ uint64_t name_len; /* Length of name */
+ size_t name_size; /* Size of encoded name length */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(uint64_t) >= sizeof(size_t));
+
+ /* Get name's length */
+ name_len = (uint64_t)HDstrlen(lnk->name);
+
+ /* Determine correct value for name size bits */
+ if(name_len > 4294967295)
+ name_size = 8;
+ else if(name_len > 65535)
+ name_size = 4;
+ else if(name_len > 255)
+ name_size = 2;
+ else
+ name_size = 1;
+
+ /* Set return value */
+ ret_value = 1 + /* Version */
+ 1 + /* Link encoding flags */
+ (lnk->type != H5L_TYPE_HARD ? (size_t)1 : 0) + /* Link type */
+ (lnk->corder_valid ? 8 : 0) + /* Creation order */
+ (lnk->cset != H5T_CSET_ASCII ? 1 : 0) + /* Character set */
+ name_size + /* Name length */
+ name_len; /* Name */
+
+ /* Add the appropriate length for each type of link */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ ret_value += H5F_SIZEOF_ADDR(f);
+ break;
+
+ case H5L_TYPE_SOFT:
+ ret_value += 2 + /* Link value length */
+ HDstrlen(lnk->u.soft.name); /* Link value */
+ break;
+
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_MAX:
+ default: /* Default is user-defined link type */
+ HDassert(lnk->type >= H5L_TYPE_UD_MIN);
+ ret_value += 2 + /* User-defined data size */
+ lnk->u.ud.size; /* User-defined data */
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_reset
+ *
+ * Purpose: Frees resources within a message, but doesn't free
+ * the message itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 29, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_reset(void *_mesg)
+{
+ H5O_link_t *lnk = (H5O_link_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(lnk) {
+ /* Free information for link (but don't free link pointer) */
+ if(lnk->type == H5L_TYPE_SOFT)
+ lnk->u.soft.name = (char *)H5MM_xfree(lnk->u.soft.name);
+ else if (lnk->type >= H5L_TYPE_UD_MIN) {
+ if(lnk->u.ud.size > 0)
+ lnk->u.ud.udata = H5MM_xfree(lnk->u.ud.udata);
+ } /* end if */
+ lnk->name = (char *)H5MM_xfree(lnk->name);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_link_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_free
+ *
+ * Purpose: Free's the message contents and the message itself
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 29, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_free(void *_mesg)
+{
+ H5O_link_t *lnk = (H5O_link_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(lnk);
+
+ /* Free information for link */
+ H5O_link_reset(lnk);
+ lnk = H5FL_FREE(H5O_link_t, lnk);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_link_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 29, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_link_delete(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, void *_mesg)
+{
+ H5O_link_t *lnk = (H5O_link_t *)_mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(lnk);
+
+ /* Check for adjusting the link count when the link is removed */
+ /* Adjust the reference count of the object when a hard link is removed */
+ if(lnk->type == H5L_TYPE_HARD) {
+ H5O_loc_t oloc;
+
+ /* Construct object location for object, in order to decrement it's ref count */
+ H5O_loc_reset(&oloc);
+ oloc.file = f;
+ HDassert(H5F_addr_defined(lnk->u.hard.addr));
+ oloc.addr = lnk->u.hard.addr;
+
+ /* Decrement the ref count for the object */
+ if(H5O_link(&oloc, -1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to decrement object link count")
+ } /* end if */
+ /* Perform the "delete" callback when a user-defined link is removed */
+ else if(lnk->type >= H5L_TYPE_UD_MIN) {
+ const H5L_class_t *link_class; /* User-defined link class */
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(lnk->type)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTREGISTERED, FAIL, "link class not registered")
+
+ /* Check for delete callback */
+ if(link_class->del_func) {
+ hid_t file_id; /* ID for the file the link is located in (passed to user callback) */
+
+ /* Get a file ID for the file the link is in */
+ if((file_id = H5F_get_id(f, FALSE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get file ID")
+
+ /* Call user-defined link's 'delete' callback */
+ if((link_class->del_func)(lnk->name, file_id, lnk->u.ud.udata, lnk->u.ud.size) < 0) {
+ H5I_dec_ref(file_id);
+ HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "link deletion callback returned failure")
+ } /* end if */
+
+ /* Release the file ID */
+ if(H5I_dec_ref(file_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "can't close file")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files for link messages.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 26, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(deleted);
+ HDassert(cpy_info);
+
+ /* If we are performing a 'shallow hierarchy' copy, and this link won't
+ * be included in the final group, indicate that it should be deleted
+ * in the destination object header before performing any other actions
+ * on it.
+ */
+ if(cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth)
+ *deleted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_link_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_link_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *native_src, H5F_t H5_ATTR_UNUSED *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5O_link_t *link_src = (H5O_link_t *)native_src;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(link_src);
+ HDassert(cpy_info);
+ HDassert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth);
+
+ /* Sanity check source link type */
+ if(link_src->type > H5L_TYPE_SOFT && link_src->type < H5L_TYPE_UD_MIN)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "unrecognized built-in link type")
+
+ /* Allocate "blank" link for destination */
+ /* (values will be filled in during 'post copy' operation) */
+ if(NULL == (ret_value = H5FL_CALLOC(H5O_link_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_link_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
+ H5O_loc_t *dst_oloc, void *mesg_dst, unsigned H5_ATTR_UNUSED *mesg_flags,
+ hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ const H5O_link_t *link_src = (const H5O_link_t *)mesg_src;
+ H5O_link_t *link_dst = (H5O_link_t *)mesg_dst;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(link_src);
+ HDassert(dst_oloc);
+ HDassert(H5F_addr_defined(dst_oloc->addr));
+ HDassert(dst_oloc->file);
+ HDassert(link_dst);
+ HDassert(cpy_info);
+ HDassert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth);
+
+ /* Copy the link (and the object it points to) */
+ if(H5L_link_copy_file(dst_oloc->file, dxpl_id, link_src, src_oloc, link_dst,
+ cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy link")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_link_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_link_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_link_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *) _mesg;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(lnk);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Link Type:", (lnk->type == H5L_TYPE_HARD ? "Hard" :
+ (lnk->type == H5L_TYPE_SOFT ? "Soft" :
+ (lnk->type == H5L_TYPE_EXTERNAL ? "External" :
+ (lnk->type >= H5L_TYPE_UD_MIN ? "User-defined" : "Unknown")))));
+
+ if(lnk->corder_valid)
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Creation Order:", lnk->corder);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Link Name Character Set:", (lnk->cset == H5T_CSET_ASCII ?
+ "ASCII" : (lnk->cset == H5T_CSET_UTF8 ? "UTF-8" : "Unknown")));
+ HDfprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth,
+ "Link Name:", lnk->name);
+
+ /* Display link-specific information */
+ switch(lnk->type) {
+ case H5L_TYPE_HARD:
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Object address:", lnk->u.hard.addr);
+ break;
+
+ case H5L_TYPE_SOFT:
+ HDfprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth,
+ "Link Value:", lnk->u.soft.name);
+ break;
+
+ case H5L_TYPE_ERROR:
+ case H5L_TYPE_EXTERNAL:
+ case H5L_TYPE_MAX:
+ default:
+ if(lnk->type >= H5L_TYPE_UD_MIN) {
+ if(lnk->type == H5L_TYPE_EXTERNAL) {
+ const char *objname = (const char *)lnk->u.ud.udata + (HDstrlen((const char *)lnk->u.ud.udata) + 1);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "External File Name:", lnk->u.ud.udata);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "External Object Name:", objname);
+ } /* end if */
+ else {
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent, "", fwidth,
+ "User-Defined Link Size:", lnk->u.ud.size);
+ } /* end else */
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type")
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_link_debug() */
+
diff --git a/src/H5Omessage.c b/src/H5Omessage.c
new file mode 100644
index 0000000..158701b
--- /dev/null
+++ b/src/H5Omessage.c
@@ -0,0 +1,2305 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Omessage.c
+ * Dec 3 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object header message routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Aprivate.h" /* Attributes */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for iteration while removing a message */
+typedef struct {
+ H5F_t *f; /* Pointer to file for insertion */
+ hid_t dxpl_id; /* DXPL during iteration */
+ int sequence; /* Sequence # to search for */
+ unsigned nfailed; /* # of failed message removals */
+ H5O_operator_t op; /* Callback routine for removal operations */
+ void *op_data; /* Callback data for removal operations */
+ hbool_t adj_link; /* Whether to adjust links when removing messages */
+} H5O_iter_rm_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5O__msg_reset_real(const H5O_msg_class_t *type, void *native);
+static herr_t H5O__msg_remove_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned sequence, unsigned *oh_modified, void *_udata/*in,out*/);
+static herr_t H5O__copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t idx,
+ const H5O_msg_class_t *type, const void *mesg, unsigned mesg_flags,
+ unsigned update_flags);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_create
+ *
+ * Purpose: Create a new object header message
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 1 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags,
+ unsigned update_flags, void *mesg, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+ HDassert(mesg);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Go append message to object header */
+ if(H5O_msg_append_oh(loc->file, dxpl_id, oh, type_id, mesg_flags, update_flags, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to append to object header")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_append_oh
+ *
+ * Purpose: Simplified version of H5O_msg_create, used when creating a new
+ * object header message (usually during object creation) and
+ * several messages will be added to the object header at once.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Dec 31 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_append_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id,
+ unsigned mesg_flags, unsigned update_flags, void *mesg)
+{
+ const H5O_msg_class_t *type; /* Original H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+ HDassert(mesg);
+
+ /* Append new message to object header */
+ if(H5O_msg_append_real(f, dxpl_id, oh, type, mesg_flags, update_flags, mesg) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new message in header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_append_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_append_real
+ *
+ * Purpose: Append a new message to an object header.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 8 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type,
+ unsigned mesg_flags, unsigned update_flags, void *mesg)
+{
+ size_t idx; /* Index of message to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type);
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+ HDassert(mesg);
+
+ /* Allocate space for a new message */
+ if(H5O_msg_alloc(f, dxpl_id, oh, type, &mesg_flags, mesg, &idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "unable to create new message")
+
+ /* Copy the information for the message */
+ if(H5O__copy_mesg(f, dxpl_id, oh, idx, type, mesg, mesg_flags, update_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to write message")
+#ifdef H5O_DEBUG
+H5O_assert(oh);
+#endif /* H5O_DEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_append_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_write
+ *
+ * Purpose: Modifies an existing message or creates a new message.
+ *
+ * The UPDATE_FLAGS argument are flags that allow the caller
+ * to skip updating the modification time or reseting the message
+ * data. This is useful when several calls to H5O_msg_write will be
+ * made in a sequence.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_write(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags,
+ unsigned update_flags, void *mesg, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header to use */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(mesg);
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Call the "real" modify routine */
+ if(H5O_msg_write_real(loc->file, dxpl_id, oh, type, mesg_flags, update_flags, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_write_oh
+ *
+ * Purpose: Modifies an existing message or creates a new message.
+ *
+ * The UPDATE_FLAGS argument are flags that allow the caller
+ * to skip updating the modification time or reseting the message
+ * data. This is useful when several calls to H5O_msg_write will be
+ * made in a sequence.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_write_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id,
+ unsigned mesg_flags, unsigned update_flags, void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, oh->cache_info.addr, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(mesg);
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+
+ /* Call the "real" modify routine */
+ if(H5O_msg_write_real(f, dxpl_id, oh, type, mesg_flags, update_flags, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message")
+
+done:
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_msg_write_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_write_real
+ *
+ * Purpose: Modifies an existing message or creates a new message.
+ *
+ * The UPDATE_FLAGS argument are flags that allow the caller
+ * to skip updating the modification time or reseting the message
+ * data. This is useful when several calls to H5O_msg_write will be
+ * made in a sequence.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_write_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type,
+ unsigned mesg_flags, unsigned update_flags, void *mesg)
+{
+ H5O_mesg_t *idx_msg; /* Pointer to message to modify */
+ size_t idx; /* Index of message to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type);
+ HDassert(type != H5O_MSG_ATTR);
+ HDassert(mesg);
+ HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
+
+ /* Locate message of correct type */
+ for(idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
+ if(type == idx_msg->type)
+ break;
+ if(idx == oh->nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message type not found")
+
+ /* Check for modifying a constant message */
+ if(!(update_flags & H5O_UPDATE_FORCE) && (idx_msg->flags & H5O_MSG_FLAG_CONSTANT))
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify constant message")
+ /* This message is shared, but it's being modified. */
+ else if((idx_msg->flags & H5O_MSG_FLAG_SHARED) || (idx_msg->flags & H5O_MSG_FLAG_SHAREABLE)) {
+ htri_t status; /* Status of "try share" call */
+
+ /* First, sanity check to make sure it's not a committed message;
+ * these can't ever be modified.
+ */
+ HDassert(((H5O_shared_t *)idx_msg->native)->type != H5O_SHARE_TYPE_COMMITTED);
+
+ /* Also, sanity check that a message doesn't switch status from being
+ * shared (or sharable) to being unsharable. (Which could cause
+ * a message to increase in size in the object header)
+ */
+ HDassert(!(mesg_flags & H5O_MSG_FLAG_DONTSHARE));
+
+ /* Remove the old message from the SOHM index */
+ /* (It would be more efficient to try to share the message first, then
+ * delete it (avoiding thrashing the index in the case the ref.
+ * count on the message is one), but this causes problems when
+ * the location of the object changes (from in another object's
+ * header to the SOHM heap), so just delete it first -QAK)
+ */
+ if(H5SM_delete(f, dxpl_id, oh, (H5O_shared_t *)idx_msg->native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete message from SOHM index")
+
+ /* If we're replacing a shared message, the new message must be shared
+ * (or else it may increase in size!), so pass in NULL for the OH
+ * location.
+ *
+ * XXX: This doesn't handle freeing extra space in object header from
+ * a message shrinking.
+ */
+ if((status = H5SM_try_share(f, dxpl_id, ((mesg_flags & H5O_MSG_FLAG_SHARED) ? NULL : oh), 0, idx_msg->type->id, mesg, &mesg_flags)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "error while trying to share message")
+ if(status == FALSE && (mesg_flags & H5O_MSG_FLAG_SHARED))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "message changed sharing status")
+ } /* end if */
+
+ /* Copy the information for the message */
+ if(H5O__copy_mesg(f, dxpl_id, oh, idx, type, mesg, mesg_flags, update_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message")
+#ifdef H5O_DEBUG
+H5O_assert(oh);
+#endif /* H5O_DEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_write_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_read
+ *
+ * Purpose: Reads a message from an object header and returns a pointer
+ * to it. The caller will usually supply the memory through
+ * MESG and the return value will be MESG. But if MESG is
+ * the null pointer, then this function will malloc() memory
+ * to hold the result and return its pointer instead.
+ *
+ * Return: Success: Ptr to message in native format. The message
+ * should be freed by calling H5O_msg_reset(). If
+ * MESG is a null pointer then the caller should
+ * also call H5MM_xfree() on the return value
+ * after calling H5O_msg_reset().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_read(const H5O_loc_t *loc, unsigned type_id, void *mesg,
+ hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header to use */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, NULL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header")
+
+ /* Call the "real" read routine */
+ if(NULL == (ret_value = H5O_msg_read_oh(loc->file, dxpl_id, oh, type_id, mesg)))
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header message")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, NULL)
+} /* end H5O_msg_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_read_oh
+ *
+ * Purpose: Reads a message from an object header and returns a pointer
+ * to it. The caller will usually supply the memory through
+ * MESG and the return value will be MESG. But if MESG is
+ * the null pointer, then this function will malloc() memory
+ * to hold the result and return its pointer instead.
+ *
+ * Return: Success: Ptr to message in native format. The message
+ * should be freed by calling H5O_msg_reset(). If
+ * MESG is a null pointer then the caller should
+ * also call H5MM_xfree() on the return value
+ * after calling H5O_msg_reset().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_read_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id,
+ void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ unsigned idx; /* Message's index in object header */
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Scan through the messages looking for the right one */
+ for(idx = 0; idx < oh->nmesgs; idx++)
+ if(type == oh->mesg[idx].type)
+ break;
+ if(idx == oh->nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "message type not found")
+
+ /*
+ * Decode the message if necessary. If the message is shared then retrieve
+ * native message through the shared interface.
+ */
+ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, &(oh->mesg[idx]), NULL)
+
+ /*
+ * The object header caches the native message (along with
+ * the raw message) so we must copy the native message before
+ * returning.
+ */
+ if(NULL == (ret_value = (type->copy)(oh->mesg[idx].native, mesg)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy message to user space")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_read_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_reset
+ *
+ * Purpose: Some message data structures have internal fields that
+ * need to be freed. This function does that if appropriate
+ * but doesn't free NATIVE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_reset(unsigned type_id, void *native)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Call the "real" reset routine */
+ if(H5O__msg_reset_real(type, native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRESET, FAIL, "unable to reset object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__msg_reset_real
+ *
+ * Purpose: Some message data structures have internal fields that
+ * need to be freed. This function does that if appropriate
+ * but doesn't free NATIVE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__msg_reset_real(const H5O_msg_class_t *type, void *native)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(type);
+
+ if(native) {
+ if(type->reset) {
+ if((type->reset)(native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "reset method failed")
+ } /* end if */
+ else
+ HDmemset(native, 0, type->native_size);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__msg_reset_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_free
+ *
+ * Purpose: Similar to H5O_msg_reset() except it also frees the message
+ * pointer.
+ *
+ * Return: Success: NULL
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_free(unsigned type_id, void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Call the "real" free routine */
+ ret_value = H5O_msg_free_real(type, mesg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_free_mesg
+ *
+ * Purpose: Call H5O_msg_free_real() on a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sep 6, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_free_mesg(H5O_mesg_t *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(mesg);
+
+ /* Free any native information */
+ mesg->native = H5O_msg_free_real(mesg->type, mesg->native);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_msg_free_mesg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_free_real
+ *
+ * Purpose: Similar to H5O_msg_reset() except it also frees the message
+ * pointer.
+ *
+ * Return: Success: NULL
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_free_real(const H5O_msg_class_t *type, void *msg_native)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(type);
+
+ if(msg_native) {
+ H5O__msg_reset_real(type, msg_native);
+ if(NULL != (type->free))
+ (type->free)(msg_native);
+ else
+ H5MM_xfree(msg_native);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5O_msg_free_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_copy
+ *
+ * Purpose: Copies a message. If MESG is is the null pointer then a null
+ * pointer is returned with no error.
+ *
+ * Return: Success: Ptr to the new message
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_copy(unsigned type_id, const void *mesg, void *dst)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(mesg);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Call the message class's copy routine */
+ if(NULL == (ret_value = (type->copy)(mesg, dst)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy object header message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_count
+ *
+ * Purpose: Counts the number of messages in an object header which are a
+ * certain type.
+ *
+ * Return: Success: Number of messages of specified type.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, April 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5O_msg_count(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header to operate on */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ unsigned msg_count; /* Message count */
+ int ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Load the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Count the messages of the correct type */
+ msg_count = H5O_msg_count_real(oh, type);
+ H5_CHECKED_ASSIGN(ret_value, int, msg_count, unsigned);
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_count_real
+ *
+ * Purpose: Counts the number of messages in an object header which are a
+ * certain type.
+ *
+ * Return: Success: Number of messages of specified type.
+ *
+ * Failure: (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+unsigned
+H5O_msg_count_real(const H5O_t *oh, const H5O_msg_class_t *type)
+{
+ unsigned u; /* Local index variable */
+ unsigned ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(oh);
+ HDassert(type);
+
+ /* Loop over all messages, counting the ones of the type looked for */
+ for(u = ret_value = 0; u < oh->nmesgs; u++)
+ if(oh->mesg[u].type == type)
+ ret_value++;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_count_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_exists
+ *
+ * Purpose: Determines if a particular message exists in an object
+ * header without trying to decode the message.
+ *
+ * Return: Success: FALSE if the message does not exist; TRUE if
+ * th message exists.
+ *
+ * Failure: FAIL if the existence of the message could
+ * not be determined due to some error such as
+ * not being able to read the object header.
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_msg_exists(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header for location */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, FAIL)
+
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+
+ /* Load the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Call the "real" exists routine */
+ if((ret_value = H5O_msg_exists_oh(oh, type_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message")
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5O_msg_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_exists_oh
+ *
+ * Purpose: Determines if a particular message exists in an object
+ * header without trying to decode the message.
+ *
+ * Return: Success: FALSE if the message does not exist; TRUE if
+ * th message exists.
+ *
+ * Failure: FAIL if the existence of the message could
+ * not be determined due to some error such as
+ * not being able to read the object header.
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_msg_exists_oh(const H5O_t *oh, unsigned type_id)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ unsigned u; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(oh);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Scan through the messages looking for the right one */
+ for(u = 0; u < oh->nmesgs; u++)
+ if(type == oh->mesg[u].type)
+ HGOTO_DONE(TRUE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_exists_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_remove
+ *
+ * Purpose: Removes the specified message from the object header.
+ * If sequence is H5O_ALL (-1) then all messages of the
+ * specified type are removed. Removing a message causes
+ * the sequence numbers to change for subsequent messages of
+ * the same type.
+ *
+ * No attempt is made to join adjacent free areas of the
+ * object header into a single larger free area.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 28 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_remove(const H5O_loc_t *loc, unsigned type_id, int sequence, hbool_t adj_link,
+ hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Call the "real" remove routine */
+ if((ret_value = H5O_msg_remove_real(loc->file, oh, type, sequence, NULL, NULL, adj_link, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_remove_op
+ *
+ * Purpose: Removes messages from the object header that a callback
+ * routine indicates should be removed.
+ *
+ * No attempt is made to join adjacent free areas of the
+ * object header into a single larger free area.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_remove_op(const H5O_loc_t *loc, unsigned type_id, int sequence,
+ H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Pin the object header */
+ if(NULL == (oh = H5O_pin(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header")
+
+ /* Call the "real" remove routine */
+ if((ret_value = H5O_msg_remove_real(loc->file, oh, type, sequence, op, op_data, adj_link, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message")
+
+done:
+ if(oh && H5O_unpin(oh) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_remove_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__msg_remove_cb
+ *
+ * Purpose: Object header iterator callback routine to remove messages
+ * of a particular type that match a particular sequence number,
+ * or all messages if the sequence number is H5O_ALL (-1).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__msg_remove_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence,
+ unsigned *oh_modified, void *_udata/*in,out*/)
+{
+ H5O_iter_rm_t *udata = (H5O_iter_rm_t *)_udata; /* Operator user data */
+ htri_t try_remove = FALSE; /* Whether to try removing a message */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(mesg);
+
+ /* Check for callback routine */
+ if(udata->op) {
+ /* Call the iterator callback */
+ if((try_remove = (udata->op)(mesg->native, sequence, udata->op_data)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "object header message deletion callback failed")
+ } /* end if */
+ else {
+ /* If there's no callback routine, does the sequence # match? */
+ if((int)sequence == udata->sequence || H5O_ALL == udata->sequence)
+ try_remove = TRUE;
+ } /* end else */
+
+ /* Try removing the message, if indicated */
+ if(try_remove) {
+ /*
+ * Keep track of how many times we failed trying to remove constant
+ * messages.
+ * (OK to remove constant messages - QAK)
+ */
+ /* Convert message into a null message */
+ if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, udata->adj_link) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to release message")
+
+ /* Indicate that the object header was modified */
+ *oh_modified = H5O_MODIFY_CONDENSE;
+
+ /* Break out now, if we've found the correct message */
+ if(udata->sequence == H5O_FIRST || udata->sequence != H5O_ALL)
+ HGOTO_DONE(H5_ITER_STOP)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__msg_remove_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_remove_real
+ *
+ * Purpose: Removes the specified message from the object header.
+ * If sequence is H5O_ALL (-1) then all messages of the
+ * specified type are removed. Removing a message causes
+ * the sequence numbers to change for subsequent messages of
+ * the same type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 28 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_remove_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type,
+ int sequence, H5O_operator_t app_op, void *op_data, hbool_t adj_link,
+ hid_t dxpl_id)
+{
+ H5O_iter_rm_t udata; /* User data for iterator */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type);
+
+ /* Make certain we are allowed to modify the file */
+ if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /* Set up iterator operator data */
+ udata.f = f;
+ udata.dxpl_id = dxpl_id;
+ udata.sequence = sequence;
+ udata.nfailed = 0;
+ udata.op = app_op;
+ udata.op_data = op_data;
+ udata.adj_link = adj_link;
+
+ /* Iterate over the messages, deleting appropriate one(s) */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5O__msg_remove_cb;
+ if(H5O_msg_iterate_real(f, oh, type, &op, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "error iterating over messages")
+
+ /* Fail if we tried to remove any constant messages */
+ if(udata.nfailed)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to remove constant message(s)")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_remove_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_iterate
+ *
+ * Purpose: Iterate through object headers of a certain type.
+ *
+ * Return: Returns a negative value if something is wrong, the return
+ * value of the last operator if it was non-zero, or zero if all
+ * object headers were processed.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Nov 19 2004
+ *
+ * Description:
+ * This function interates over the object headers of an object
+ * specified with 'loc' of type 'type_id'. For each object header of the
+ * object, the 'op_data' and some additional information (specified below) are
+ * passed to the 'op' function.
+ * The operation receives a pointer to the object header message for the
+ * object being iterated over ('mesg'), and the pointer to the operator data
+ * passed in to H5O_msg_iterate ('op_data'). The return values from an operator
+ * are:
+ * A. Zero causes the iterator to continue, returning zero when all
+ * object headers of that type have been processed.
+ * B. Positive causes the iterator to immediately return that positive
+ * value, indicating short-circuit success.
+ * C. Negative causes the iterator to immediately return that value,
+ * indicating failure.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_iterate(const H5O_loc_t *loc, unsigned type_id,
+ const H5O_mesg_operator_t *op, void *op_data, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(op);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Call the "real" iterate routine */
+ if((ret_value = H5O_msg_iterate_real(loc->file, oh, type, op, op_data, dxpl_id)) < 0)
+ HERROR(H5E_OHDR, H5E_BADITER, "unable to iterate over object header messages");
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_iterate_real
+ *
+ * Purpose: Iterate through object headers of a certain type.
+ *
+ * Return: Returns a negative value if something is wrong, the return
+ * value of the last operator if it was non-zero, or zero if all
+ * object headers were processed.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ * Description:
+ * This function interates over the object headers of an object
+ * specified with 'ent' of type 'type_id'. For each object header of the
+ * object, the 'op_data' and some additional information (specified below) are
+ * passed to the 'op' function.
+ * The operation receives a pointer to the object header message for the
+ * object being iterated over ('mesg'), and the pointer to the operator data
+ * passed in to H5O_msg_iterate ('op_data'). The return values from an operator
+ * are:
+ * A. Zero causes the iterator to continue, returning zero when all
+ * object headers of that type have been processed.
+ * B. Positive causes the iterator to immediately return that positive
+ * value, indicating short-circuit success.
+ * C. Negative causes the iterator to immediately return that value,
+ * indicating failure.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_iterate_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type,
+ const H5O_mesg_operator_t *op, void *op_data, hid_t dxpl_id)
+{
+ H5O_mesg_t *idx_msg; /* Pointer to current message */
+ unsigned idx; /* Absolute index of current message in all messages */
+ unsigned sequence; /* Relative index of current message for messages of type */
+ unsigned oh_modified = 0; /* Whether the callback modified the object header */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type);
+ HDassert(op);
+ HDassert(op->u.app_op);
+
+ /* Iterate over messages */
+ for(sequence = 0, idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs && !ret_value; idx++, idx_msg++) {
+ if(type == idx_msg->type) {
+ /* Decode the message if necessary. */
+ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, idx_msg, FAIL)
+
+ /* Check for making an "internal" (i.e. within the H5O package) callback */
+ if(op->op_type == H5O_MESG_OP_LIB)
+ ret_value = (op->u.lib_op)(oh, idx_msg, sequence, &oh_modified, op_data);
+ else
+ ret_value = (op->u.app_op)(idx_msg->native, sequence, op_data);
+
+ /* Check for iterator callback indicating to get out of loop */
+ if(ret_value != 0)
+ break;
+
+ /* Increment sequence value for message type */
+ sequence++;
+ } /* end if */
+ } /* end for */
+
+ /* Check for error from iterator */
+ if(ret_value < 0)
+ HERROR(H5E_OHDR, H5E_CANTLIST, "iterator function failed");
+
+done:
+ /* Check if object message was modified */
+ if(oh_modified) {
+ /* Try to condense object header info */
+ /* (Since this routine is used to remove messages from an
+ * object header, the header will be condensed after each
+ * message removal)
+ */
+ if(oh_modified & H5O_MODIFY_CONDENSE)
+ if(H5O_condense_header(f, oh, dxpl_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack object header")
+
+ /* Mark object header as changed */
+ if(H5O_touch_oh(f, dxpl_id, oh, FALSE) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+ /* Mark object header as dirty in cache */
+ if(H5AC_mark_entry_dirty(oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_iterate_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_raw_size
+ *
+ * Purpose: Call the 'raw_size' method for a
+ * particular class of object header.
+ *
+ * Return: Size of message on success, 0 on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 13 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5O_msg_raw_size(const H5F_t *f, unsigned type_id, hbool_t disable_shared,
+ const void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->raw_size);
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Compute the raw data size for the mesg */
+ if(0 == (ret_value = (type->raw_size)(f, disable_shared, mesg)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_raw_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_size_f
+ *
+ * Purpose: Calculate the final size of an encoded message in an object
+ * header.
+ *
+ * Note: This routine assumes that the message size will be used in the
+ * creation of a new object header.
+ *
+ * Return: Size of message on success, 0 on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5O_msg_size_f(const H5F_t *f, hid_t ocpl_id, unsigned type_id,
+ const void *mesg, size_t extra_raw)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ H5P_genplist_t *ocpl; /* Object Creation Property list */
+ uint8_t oh_flags; /* Object header status flags */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->raw_size);
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Get the property list */
+ if(NULL == (ocpl = (H5P_genplist_t *)H5I_object(ocpl_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, 0, "not a property list")
+
+ /* Get any object header status flags set by properties */
+ if(H5P_get(ocpl, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "can't get object header flags")
+
+
+ /* Compute the raw data size for the mesg */
+ if((ret_value = (type->raw_size)(f, FALSE, mesg)) == 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message")
+
+ /* Add in "extra" raw space */
+ ret_value += extra_raw;
+
+ /* Adjust size for alignment, if necessary */
+ ret_value = (size_t)H5O_ALIGN_F(f, ret_value);
+
+ /* Add space for message header */
+ ret_value += (size_t)H5O_SIZEOF_MSGHDR_F(f,
+ (H5F_STORE_MSG_CRT_IDX(f) || oh_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_size_f() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_size_oh
+ *
+ * Purpose: Calculate the final size of an encoded message in an object
+ * header.
+ *
+ * Note: This routine assumes that the message is already used in
+ * an object header.
+ *
+ * Return: Size of message on success, 0 on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 7 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5O_msg_size_oh(const H5F_t *f, const H5O_t *oh, unsigned type_id,
+ const void *mesg, size_t extra_raw)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->raw_size);
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Compute the raw data size for the mesg */
+ if((ret_value = (type->raw_size)(f, FALSE, mesg)) == 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message")
+
+ /* Add in "extra" raw space */
+ ret_value += extra_raw;
+
+ /* Adjust size for alignment, if necessary */
+ ret_value = (size_t)H5O_ALIGN_OH(oh, ret_value);
+
+ /* Add space for message header */
+ ret_value += (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_size_oh() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_can_share
+ *
+ * Purpose: Call the 'can share' method for a
+ * particular class of object header. This returns TRUE
+ * if the message is allowed to be put in the shared message
+ * heap and false otherwise (e.g., for committed or immutable
+ * datatypes).
+ *
+ * Return: Object can be shared: TRUE
+ * Object cannot be shared: FALSE
+ *
+ * Programmer: James Laird
+ * January 12 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_msg_can_share(unsigned type_id, const void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(mesg);
+
+ /* If there is a can_share callback, use it */
+ if(type->can_share)
+ ret_value = (type->can_share)(mesg);
+ else {
+ /* Otherwise, the message can be shared if messages of this type are
+ * shareable in general; i.e., if they have the "is_sharable" flag
+ * in the "share_flags" class member set.
+ */
+ ret_value = (type->share_flags & H5O_SHARE_IS_SHARABLE) ? TRUE : FALSE;
+ } /* end else */
+
+ /* If the message is shareable, both copy_file and post_copy_file must be
+ * defined */
+ HDassert((type->post_copy_file && type->copy_file) || ret_value == FALSE);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_can_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_can_share_in_ohdr
+ *
+ * Purpose: Check if the message class allows its messages to be shared
+ * in the object's header.
+ *
+ * Return: Object can be shared: TRUE
+ * Object cannot be shared: FALSE
+ *
+ * Programmer: Quincey Koziol
+ * March 15 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_msg_can_share_in_ohdr(unsigned type_id)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Otherwise, the message can be shared if messages of this type are
+ * shareable in general; i.e., if they have the "is_sharable" flag
+ * in the "share_flags" class member set.
+ */
+ ret_value = (type->share_flags & H5O_SHARE_IN_OHDR) ? TRUE : FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_can_share_in_ohdr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_is_shared
+ *
+ * Purpose: Call the 'is_shared' method for a
+ * particular class of object header.
+ *
+ * Return: Object is shared: TRUE
+ * Object is not shared: FALSE
+ *
+ * Programmer: James Laird
+ * jlaird@ncsa.uiuc.edu
+ * April 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5O_msg_is_shared(unsigned type_id, const void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(mesg);
+
+ /* If messages in a class aren't sharable, then obviously this message isn't shared! :-) */
+ if(type->share_flags & H5O_SHARE_IS_SHARABLE)
+ ret_value = H5O_IS_STORED_SHARED(((const H5O_shared_t *)mesg)->type);
+ else
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_is_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_set_share
+ *
+ * Purpose: Set the shared information for an object header message.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * jlaird@hdfgroup.org
+ * November 1 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_set_share(unsigned type_id, const H5O_shared_t *share, void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->share_flags & H5O_SHARE_IS_SHARABLE);
+ HDassert(mesg);
+ HDassert(share);
+ HDassert(share->type != H5O_SHARE_TYPE_UNSHARED);
+
+ /* If there's a special action for this class that needs to be performed
+ * when setting the shared component, do that
+ */
+ if(type->set_share) {
+ if((type->set_share)(mesg, share) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to set shared message information")
+ } /* end if */
+ else {
+ /* Set this message as the shared component for the message, wiping out
+ * any information that was there before
+ */
+ if(H5O_set_shared((H5O_shared_t *)mesg, share) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to set shared message information")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_set_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_reset_share
+ *
+ * Purpose: Reset the shared information for an object header message.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * jlaird@hdfgroup.org
+ * Oct 17 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_reset_share(unsigned type_id, void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(type->share_flags & H5O_SHARE_IS_SHARABLE);
+ HDassert(mesg);
+
+ /* Reset the shared component in the message to zero. */
+ HDmemset((H5O_shared_t *)mesg, 0, sizeof(H5O_shared_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_msg_reset_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_get_crt_index
+ *
+ * Purpose: Call the 'get creation index' method for a message.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * March 15 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_get_crt_index(unsigned type_id, const void *mesg, H5O_msg_crt_idx_t *crt_idx)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+ HDassert(mesg);
+ HDassert(crt_idx);
+
+ /* If there is a "get_crt_index callback, use it */
+ if(type->get_crt_index) {
+ /* Retrieve the creation index from the native message */
+ if((type->get_crt_index)(mesg, crt_idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve creation index")
+ } /* end if */
+ else
+ *crt_idx = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_get_crt_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_encode
+ *
+ * Purpose: Encode an object(data type and simple data space only)
+ * description into a buffer.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 13, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_encode(H5F_t *f, unsigned type_id, hbool_t disable_shared,
+ unsigned char *buf, const void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Encode */
+ if((type->encode)(f, disable_shared, buf, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_decode
+ *
+ * Purpose: Decode a binary object description and return a new
+ * object handle.
+ *
+ * Return: Success: Pointer to object(data type or space)
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ * Modifications: Neil Fortner
+ * Feb 4 2009
+ * Added open_oh parameter. This parameter is optional and
+ * contains this message's protected object header
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned type_id,
+ const unsigned char *buf)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ unsigned ioflags = 0; /* Flags for decode routine */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* decode */
+ if((ret_value = (type->decode)(f, dxpl_id, open_oh, 0, &ioflags, buf)) == NULL)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_copy_file
+ *
+ * Purpose: Copies a message to file. If MESG is is the null pointer then a null
+ * pointer is returned with no error.
+ *
+ * Attempts to share the message in the destination and sets
+ * SHARED to TRUE or FALSE depending on whether this succeeds.
+ *
+ * Return: Success: Ptr to the new message
+ *
+ * Failure: NULL
+ *
+ * Programmer: Peter Cao
+ * June 4, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_msg_copy_file(const H5O_msg_class_t *type, H5F_t *file_src,
+ void *native_src, H5F_t *file_dst, hbool_t *recompute_size,
+ unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(type);
+ HDassert(type->copy_file);
+ HDassert(file_src);
+ HDassert(native_src);
+ HDassert(file_dst);
+ HDassert(recompute_size);
+ HDassert(cpy_info);
+
+ /* The copy_file callback will return an H5O_shared_t only if the message
+ * to be copied is a committed datatype.
+ */
+ if(NULL == (ret_value = (type->copy_file)(file_src, native_src, file_dst, recompute_size, mesg_flags, cpy_info, udata, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy object header message to file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_alloc
+ *
+ * Purpose: Create a new message in an object header
+ *
+ * Return: Success: Index of message
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 3, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type,
+ unsigned *mesg_flags, void *native, size_t *mesg_idx)
+{
+ size_t new_idx; /* New index for message */
+ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(mesg_flags);
+ HDassert(!(*mesg_flags & H5O_MSG_FLAG_SHARED));
+ HDassert(type);
+ HDassert(native);
+ HDassert(mesg_idx);
+
+ /* Check if message is already shared */
+ if((shared_mesg = H5O_msg_is_shared(type->id, native)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "error determining if message is shared")
+ else if(shared_mesg > 0) {
+ /* Increment message's reference count */
+ if(type->link && (type->link)(f, dxpl_id, oh, native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared message ref count")
+ *mesg_flags |= H5O_MSG_FLAG_SHARED;
+ } /* end if */
+ else {
+ /* Attempt to share message */
+ if(H5SM_try_share(f, dxpl_id, oh, 0, type->id, native, mesg_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "error determining if message should be shared")
+ } /* end else */
+
+ /* Allocate space in the object header for the message */
+ if(H5O_alloc(f, dxpl_id, oh, type, native, &new_idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for message")
+
+ /* Get the message's "creation index", if it has one */
+ if(type->get_crt_index) {
+ /* Retrieve the creation index from the native message */
+ if((type->get_crt_index)(native, &oh->mesg[new_idx].crt_idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve creation index")
+ } /* end if */
+
+ /* Set new message index */
+ *mesg_idx = new_idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O__copy_mesg
+ *
+ * Purpose: Make a copy of the native object for an object header's
+ * native message info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 3, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O__copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t idx,
+ const H5O_msg_class_t *type, const void *mesg, unsigned mesg_flags,
+ unsigned update_flags)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
+ H5O_mesg_t *idx_msg = &oh->mesg[idx]; /* Pointer to message to modify */
+ hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(type);
+ HDassert(type->copy);
+ HDassert(mesg);
+
+ /* Protect chunk */
+ if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, idx_msg->chunkno)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
+
+ /* Reset existing native information for the header's message */
+ H5O__msg_reset_real(type, idx_msg->native);
+
+ /* Copy the native object for the message */
+ if(NULL == (idx_msg->native = (type->copy)(mesg, idx_msg->native)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy message to object header")
+
+ /* Update the message flags */
+ idx_msg->flags = (uint8_t)mesg_flags;
+
+ /* Mark the message as modified */
+ idx_msg->dirty = TRUE;
+ chk_dirtied = TRUE;
+
+ /* Release chunk */
+ if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
+ chk_proxy = NULL;
+
+ /* Update the modification time, if requested */
+ if(update_flags & H5O_UPDATE_TIME)
+ if(H5O_touch_oh(f, dxpl_id, oh, FALSE) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ /* Release chunk, if not already released */
+ if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O__copy_mesg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_delete
+ *
+ * Purpose: Calls a message's delete callback.
+ *
+ * This is mostly redundant with H5O_delete_mesg below,
+ * but H5O_delete_mesg only works on messages in object headers
+ * (while the shared message code needs to delete messages in
+ * the heap).
+ *
+ * open_oh is a pointer to a currently open object header so
+ * that the library doesn't try to re-protect it. If there is
+ * no such object header, it should be NULL.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * December 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned type_id,
+ void *mesg)
+{
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* delete */
+ if((type->del) && (type->del)(f, dxpl_id, open_oh, mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_delete_mesg
+ *
+ * Purpose: Internal function to:
+ * Delete an object header message from a file. This frees the file
+ * space used for anything referred to in the object header message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * September 26 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg)
+{
+ const H5O_msg_class_t *type = mesg->type; /* Type of object to free */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(oh);
+
+ /* Check if there is a file space deletion callback for this type of message */
+ if(type->del) {
+ /* Decode the message if necessary. */
+ H5O_LOAD_NATIVE(f, dxpl_id, H5O_DECODEIO_NOCHANGE, oh, mesg, FAIL)
+
+ if((type->del)(f, dxpl_id, oh, mesg->native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_delete_mesg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_flush
+ *
+ * Purpose: Flushes a message for an object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 14 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_flush(H5F_t *f, H5O_t *oh, H5O_mesg_t *mesg)
+{
+ uint8_t *p; /* Temporary pointer to encode with */
+ unsigned msg_id; /* ID for message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Point into message's chunk's image */
+ p = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
+
+ /* Retrieve actual message ID, for unknown messages */
+ if(mesg->type == H5O_MSG_UNKNOWN)
+ msg_id = *(H5O_unknown_t *)(mesg->native);
+ else
+ msg_id = (uint8_t)mesg->type->id;
+
+ /* Encode the message prefix */
+ if(oh->version == H5O_VERSION_1)
+ UINT16ENCODE(p, msg_id)
+ else
+ *p++ = (uint8_t)msg_id;
+ HDassert(mesg->raw_size < H5O_MESG_MAX_SIZE);
+ UINT16ENCODE(p, mesg->raw_size);
+ *p++ = mesg->flags;
+
+ /* Only encode reserved bytes for version 1 of format */
+ if(oh->version == H5O_VERSION_1) {
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ } /* end for */
+ /* Only encode creation index for version 2+ of format */
+ else {
+ /* Only encode creation index if they are being tracked */
+ if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
+ UINT16ENCODE(p, mesg->crt_idx);
+ } /* end else */
+ HDassert(p == mesg->raw);
+
+#ifndef NDEBUG
+ /* Make certain that null messages aren't in chunks w/gaps */
+ if(H5O_NULL_ID == msg_id)
+ HDassert(oh->chunk[mesg->chunkno].gap == 0);
+ else
+ /* Non-null messages should always have a native pointer */
+ HDassert(mesg->native);
+#endif /* NDEBUG */
+
+ /* Encode the message itself, if it's not an "unknown" message */
+ if(mesg->native && mesg->type != H5O_MSG_UNKNOWN) {
+ /*
+ * Encode the message. If the message is shared then we
+ * encode a Shared Object message instead of the object
+ * which is being shared.
+ */
+ HDassert(mesg->raw >= oh->chunk[mesg->chunkno].image);
+ HDassert(mesg->raw_size == H5O_ALIGN_OH(oh, mesg->raw_size));
+ HDassert(mesg->raw + mesg->raw_size <=
+ oh->chunk[mesg->chunkno].image + (oh->chunk[mesg->chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)));
+#ifndef NDEBUG
+/* Sanity check that the message won't overwrite past it's allocated space */
+{
+ size_t msg_size;
+
+ msg_size = mesg->type->raw_size(f, FALSE, mesg->native);
+ msg_size = H5O_ALIGN_OH(oh, msg_size);
+ HDassert(msg_size <= mesg->raw_size);
+}
+#endif /* NDEBUG */
+ HDassert(mesg->type->encode);
+ if((mesg->type->encode)(f, FALSE, mesg->raw, mesg->native) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
+ } /* end if */
+
+ /* Mark the message as clean now */
+ mesg->dirty = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_flush_msgs
+ *
+ * Purpose: Flushes messages for object header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Nov 21 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_flush_msgs(H5F_t *f, H5O_t *oh)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Encode any dirty messages */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
+ if(curr_msg->dirty)
+ if(H5O_msg_flush(f, oh, curr_msg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
+
+ /* Sanity check for the correct # of messages in object header */
+ if(oh->nmesgs != u)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "corrupt object header - too few messages")
+
+#ifndef NDEBUG
+ /* Reset the number of messages dirtied by decoding, as they have all
+ * been flushed */
+ oh->ndecode_dirtied = 0;
+#endif /* NDEBUG */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_flush_msgs() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_msg_get_flags
+ *
+ * Purpose: Queries a message's message flags in the object header
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin; Jan 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_msg_get_flags(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id, uint8_t *flags)
+{
+ H5O_t *oh = NULL; /* Object header to use */
+ const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
+ H5O_mesg_t *idx_msg; /* Pointer to message to modify */
+ unsigned idx; /* Index of message to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(loc);
+ HDassert(loc->file);
+ HDassert(H5F_addr_defined(loc->addr));
+ HDassert(type_id < NELMTS(H5O_msg_class_g));
+ type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Locate message of correct type */
+ for(idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
+ if(type == idx_msg->type)
+ break;
+
+ if(idx == oh->nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message type not found")
+
+ /* Set return value */
+ *flags = idx_msg->flags;
+
+done:
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_msg_get_flags() */
diff --git a/src/H5Omodule.h b/src/H5Omodule.h
new file mode 100644
index 0000000..df3ab56
--- /dev/null
+++ b/src/H5Omodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5O package. Including this header means that the source file
+ * is part of the H5O package.
+ */
+#ifndef _H5Omodule_H
+#define _H5Omodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5O_MODULE
+#define H5_MY_PKG H5O
+#define H5_MY_PKG_ERR H5E_OHDR
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Omodule_H */
+
diff --git a/src/H5Omtime.c b/src/H5Omtime.c
new file mode 100644
index 0000000..7e7baea
--- /dev/null
+++ b/src/H5Omtime.c
@@ -0,0 +1,500 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, July 24, 1998
+ *
+ * Purpose: The object modification time message.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+
+
+static void *H5O_mtime_new_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_mtime_new_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static size_t H5O_mtime_new_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+
+static void *H5O_mtime_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_mtime_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_mtime_copy(const void *_mesg, void *_dest);
+static size_t H5O_mtime_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_mtime_reset(void *_mesg);
+static herr_t H5O_mtime_free(void *_mesg);
+static herr_t H5O_mtime_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_MTIME[1] = {{
+ H5O_MTIME_ID, /*message id number */
+ "mtime", /*message name for debugging */
+ sizeof(time_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_mtime_decode, /*decode message */
+ H5O_mtime_encode, /*encode message */
+ H5O_mtime_copy, /*copy the native value */
+ H5O_mtime_size, /*raw message size */
+ H5O_mtime_reset, /* reset method */
+ H5O_mtime_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_mtime_debug /*debug the message */
+}};
+
+/* This message derives from H5O message class */
+/* (Only encode, decode & size routines are different from old mtime routines) */
+const H5O_msg_class_t H5O_MSG_MTIME_NEW[1] = {{
+ H5O_MTIME_NEW_ID, /*message id number */
+ "mtime_new", /*message name for debugging */
+ sizeof(time_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_mtime_new_decode, /*decode message */
+ H5O_mtime_new_encode, /*encode message */
+ H5O_mtime_copy, /*copy the native value */
+ H5O_mtime_new_size, /*raw message size */
+ H5O_mtime_reset, /* reset method */
+ H5O_mtime_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_mtime_debug /*debug the message */
+}};
+
+/* Current version of new mtime information */
+#define H5O_MTIME_VERSION 1
+
+/* Declare a free list to manage the time_t struct */
+H5FL_DEFINE(time_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_new_decode
+ *
+ * Purpose: Decode a new modification time message and return a pointer to
+ * a new time_t value.
+ *
+ * The new modification time message format was added due to the
+ * performance overhead of the old format.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 3 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_mtime_new_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ time_t *mesg;
+ uint32_t tmp_time; /* Temporary copy of the time */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(*p++ != H5O_MTIME_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for mtime message");
+
+ /* Skip reserved bytes */
+ p+=3;
+
+ /* Get the time_t from the file */
+ UINT32DECODE(p, tmp_time);
+
+ /* The return value */
+ if (NULL==(mesg = H5FL_MALLOC(time_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+ *mesg = (time_t)tmp_time;
+
+ /* Set return value */
+ ret_value=mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_mtime_new_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_decode
+ *
+ * Purpose: Decode a modification time message and return a pointer to a
+ * new time_t value.
+ *
+ * The new modification time message format was added due to the
+ * performance overhead of the old format.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 24 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_mtime_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ time_t *mesg, the_time;
+ struct tm tm;
+ int i; /* Local index variable */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ for(i = 0; i < 14; i++)
+ if(!HDisdigit(p[i]))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "badly formatted modification time message")
+
+ /* Convert YYYYMMDDhhmmss UTC to a time_t. */
+ HDmemset(&tm, 0, sizeof tm);
+ tm.tm_year = (p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + (p[3]-'0') - 1900;
+ tm.tm_mon = (p[4]-'0')*10 + (p[5]-'0') - 1;
+ tm.tm_mday = (p[6]-'0')*10 + (p[7]-'0');
+ tm.tm_hour = (p[8]-'0')*10 + (p[9]-'0');
+ tm.tm_min = (p[10]-'0')*10 + (p[11]-'0');
+ tm.tm_sec = (p[12]-'0')*10 + (p[13]-'0');
+ tm.tm_isdst = -1; /* (figure it out) */
+ if((time_t)-1 == (the_time = H5_make_time(&tm)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't construct time info")
+
+ /* The return value */
+ if(NULL == (mesg = H5FL_MALLOC(time_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ *mesg = the_time;
+
+ /* Set return value */
+ ret_value = mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_mtime_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_new_encode
+ *
+ * Purpose: Encodes a new modification time message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 3 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_mtime_new_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const time_t *mesg = (const time_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* Version */
+ *p++ = H5O_MTIME_VERSION;
+
+ /* Reserved bytes */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+
+ /* Encode time */
+ UINT32ENCODE(p, *mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_mtime_new_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_encode
+ *
+ * Purpose: Encodes a modification time message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 24 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_mtime_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const time_t *mesg = (const time_t *) _mesg;
+ struct tm *tm;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* encode */
+ tm = HDgmtime(mesg);
+ sprintf((char*)p, "%04d%02d%02d%02d%02d%02d",
+ 1900+tm->tm_year, 1+tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 24 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_mtime_copy(const void *_mesg, void *_dest)
+{
+ const time_t *mesg = (const time_t *) _mesg;
+ time_t *dest = (time_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(mesg);
+ if (!dest && NULL==(dest = H5FL_MALLOC(time_t)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+
+ /* copy */
+ *dest = *mesg;
+
+ /* Set return value */
+ ret_value=dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_new_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not
+ * counting the message type or size fields, but only the data
+ * fields. This function doesn't take into account
+ * alignment.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ *
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Jan 3 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_mtime_new_size(const H5F_t H5_ATTR_UNUSED * f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED * mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ FUNC_LEAVE_NOAPI(8)
+} /* end H5O_mtime_new_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not
+ * counting the message type or size fields, but only the data
+ * fields. This function doesn't take into account
+ * alignment.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 14 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_mtime_size(const H5F_t H5_ATTR_UNUSED * f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED * mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ FUNC_LEAVE_NOAPI(16)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_reset
+ *
+ * Purpose: Frees resources within a modification time message, but doesn't free
+ * the message itself.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Mondey, December 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_mtime_reset(void H5_ATTR_UNUSED *_mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 30, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_mtime_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(time_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_mtime_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_mtime_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jul 24 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_mtime_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const time_t *mesg = (const time_t *)_mesg;
+ struct tm *tm;
+ char buf[128];
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* debug */
+ tm = HDlocaltime(mesg);
+
+ HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Time:", buf);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
diff --git a/src/H5Oname.c b/src/H5Oname.c
new file mode 100644
index 0000000..6292883
--- /dev/null
+++ b/src/H5Oname.c
@@ -0,0 +1,307 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oname.c
+ * Aug 12 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Object name message.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_name_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_name_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_name_copy(const void *_mesg, void *_dest);
+static size_t H5O_name_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_name_reset(void *_mesg);
+static herr_t H5O_name_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_NAME[1] = {{
+ H5O_NAME_ID, /*message id number */
+ "name", /*message name for debugging */
+ sizeof(H5O_name_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_name_decode, /*decode message */
+ H5O_name_encode, /*encode message */
+ H5O_name_copy, /*copy the native value */
+ H5O_name_size, /*raw message size */
+ H5O_name_reset, /*free internal memory */
+ NULL, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_name_debug /*debug the message */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_decode
+ *
+ * Purpose: Decode a name message and return a pointer to a new
+ * native message struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_name_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_name_t *mesg;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(NULL == (mesg = (H5O_name_t *)H5MM_calloc(sizeof(H5O_name_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ if(NULL == (mesg->s = (char *)H5MM_strdup((const char *)p)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set return value */
+ ret_value = mesg;
+
+done:
+ if(NULL == ret_value) {
+ if(mesg)
+ mesg = (H5O_name_t *)H5MM_xfree(mesg);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_name_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_encode
+ *
+ * Purpose: Encodes a name message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_name_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_name_t *mesg = (const H5O_name_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg && mesg->s);
+
+ /* encode */
+ HDstrcpy((char*)p, mesg->s);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_name_copy(const void *_mesg, void *_dest)
+{
+ const H5O_name_t *mesg = (const H5O_name_t *) _mesg;
+ H5O_name_t *dest = (H5O_name_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(mesg);
+
+ if(!dest && NULL == (dest = (H5O_name_t *)H5MM_calloc(sizeof(H5O_name_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *mesg;
+ if(NULL == (dest->s = H5MM_xstrdup(mesg->s)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ if(NULL == ret_value)
+ if(dest && NULL == _dest)
+ dest = (H5O_name_t *)H5MM_xfree(dest);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_name_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not
+ * counting the message typ or size fields, but only the data
+ * fields. This function doesn't take into account
+ * alignment.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_name_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_name_t *mesg = (const H5O_name_t *) _mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ ret_value = mesg->s ? HDstrlen(mesg->s) + 1 : 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_reset
+ *
+ * Purpose: Frees internal pointers and resets the message to an
+ * initial state.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_name_reset(void *_mesg)
+{
+ H5O_name_t *mesg = (H5O_name_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(mesg);
+
+ /* reset */
+ mesg->s = (char *)H5MM_xfree(mesg->s);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_name_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_name_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_name_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_name_t *mesg = (const H5O_name_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ fprintf(stream, "%*s%-*s `%s'\n", indent, "", fwidth,
+ "Name:",
+ mesg->s);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
diff --git a/src/H5Onull.c b/src/H5Onull.c
new file mode 100644
index 0000000..5697455
--- /dev/null
+++ b/src/H5Onull.c
@@ -0,0 +1,55 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Onull.c
+ * Aug 6 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: The null message.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_NULL[1] = {{
+ H5O_NULL_ID, /*message id number */
+ "null", /*message name for debugging */
+ 0, /*native message size */
+ 0, /* messages are sharable? */
+ NULL, /*no decode method */
+ NULL, /*no encode method */
+ NULL, /*no copy method */
+ NULL, /*no size method */
+ NULL, /*no reset method */
+ NULL, /*no free method */
+ NULL, /*no file delete method */
+ NULL, /*no link method */
+ NULL, /*no set share method */
+ NULL, /*no can share method */
+ NULL, /*no pre copy native value to file */
+ NULL, /*no copy native value to file */
+ NULL, /*no post copy native value to file */
+ NULL, /*no get creation index */
+ NULL, /*no set creation index */
+ NULL /*no debug method */
+}};
+
diff --git a/src/H5Opkg.h b/src/H5Opkg.h
new file mode 100644
index 0000000..b0c67d1
--- /dev/null
+++ b/src/H5Opkg.h
@@ -0,0 +1,666 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !(defined H5O_FRIEND || defined H5O_MODULE)
+#error "Do not include this file outside the H5O package!"
+#endif
+
+#ifndef _H5Opkg_H
+#define _H5Opkg_H
+
+/* Get package's private header */
+#include "H5Oprivate.h" /* Object headers */
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5FLprivate.h" /* Free Lists */
+
+/* Object header macros */
+#define H5O_NMESGS 8 /*initial number of messages */
+#define H5O_NCHUNKS 2 /*initial number of chunks */
+#define H5O_MIN_SIZE 22 /* Min. obj header data size (must be big enough for a message prefix and a continuation message) */
+#define H5O_MSG_TYPES 27 /* # of types of messages */
+#define H5O_MAX_CRT_ORDER_IDX 65535 /* Max. creation order index value */
+
+/* Versions of object header structure */
+
+/* Initial version of the object header format */
+#define H5O_VERSION_1 1
+
+/* Revised version - leaves out reserved bytes and alignment padding, and adds
+ * magic number as prefix and checksum as suffix for all chunks.
+ */
+#define H5O_VERSION_2 2
+
+/* The latest version of the format. Look through the 'flush'
+ * and 'size' callback for places to change when updating this. */
+#define H5O_VERSION_LATEST H5O_VERSION_2
+
+/*
+ * Align messages on 8-byte boundaries because we would like to copy the
+ * object header chunks directly into memory and operate on them there, even
+ * on 64-bit architectures. This allows us to reduce the number of disk I/O
+ * requests with a minimum amount of mem-to-mem copies.
+ *
+ * Note: We no longer attempt to do this. - QAK, 10/16/06
+ */
+#define H5O_ALIGN_OLD(X) (8 * (((X) + 7) / 8))
+#define H5O_ALIGN_VERS(V, X) \
+ (((V) == H5O_VERSION_1) ? \
+ H5O_ALIGN_OLD(X) \
+ : \
+ (X) \
+ )
+#define H5O_ALIGN_OH(O, X) \
+ H5O_ALIGN_VERS((O)->version, X)
+#define H5O_ALIGN_F(F, X) \
+ H5O_ALIGN_VERS((H5F_USE_LATEST_FLAGS(F, H5F_LATEST_OBJ_HEADER) ? H5O_VERSION_LATEST : H5O_VERSION_1), X)
+
+/* Size of checksum (on disk) */
+#define H5O_SIZEOF_CHKSUM 4
+
+/* ========= Object Creation properties ============ */
+/* Default values for some of the object creation properties */
+/* NOTE: The H5O_CRT_ATTR_MAX_COMPACT_DEF & H5O_CRT_ATTR_MIN_DENSE_DEF values
+ * are "built into" the file format, make certain existing files with
+ * default attribute phase change storage are handled correctly if they
+ * are changed.
+ */
+#define H5O_CRT_ATTR_MAX_COMPACT_DEF 8
+#define H5O_CRT_ATTR_MIN_DENSE_DEF 6
+#define H5O_CRT_OHDR_FLAGS_DEF H5O_HDR_STORE_TIMES
+
+/* Object header status flag definitions */
+#define H5O_HDR_CHUNK0_1 0x00 /* Use 1-byte value for chunk #0 size */
+#define H5O_HDR_CHUNK0_2 0x01 /* Use 2-byte value for chunk #0 size */
+#define H5O_HDR_CHUNK0_4 0x02 /* Use 4-byte value for chunk #0 size */
+#define H5O_HDR_CHUNK0_8 0x03 /* Use 8-byte value for chunk #0 size */
+
+/*
+ * Size of object header prefix.
+ */
+#define H5O_SIZEOF_HDR(O) \
+ (((O)->version == H5O_VERSION_1) \
+ ? \
+ H5O_ALIGN_OLD(1 + /*version number */ \
+ 1 + /*reserved */ \
+ 2 + /*number of messages */ \
+ 4 + /*reference count */ \
+ 4) /*chunk data size */ \
+ : \
+ (H5_SIZEOF_MAGIC + /*magic number */ \
+ 1 + /*version number */ \
+ 1 + /*flags */ \
+ (((O)->flags & H5O_HDR_STORE_TIMES) ? ( \
+ 4 + /*access time */ \
+ 4 + /*modification time */ \
+ 4 + /*change time */ \
+ 4 /*birth time */ \
+ ) : 0) + \
+ (((O)->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) ? ( \
+ 2 + /*max compact attributes */ \
+ 2 /*min dense attributes */ \
+ ) : 0) + \
+ (1 << ((O)->flags & H5O_HDR_CHUNK0_SIZE)) + /*chunk 0 data size */ \
+ H5O_SIZEOF_CHKSUM) /*checksum size */ \
+ )
+
+/*
+ * Size of object header message prefix
+ */
+#define H5O_SIZEOF_MSGHDR_VERS(V,C) \
+ (((V) == H5O_VERSION_1) \
+ ? \
+ H5O_ALIGN_OLD(2 + /*message type */ \
+ 2 + /*sizeof message data */ \
+ 1 + /*flags */ \
+ 3) /*reserved */ \
+ : \
+ (1 + /*message type */ \
+ 2 + /*sizeof message data */ \
+ 1 + /*flags */ \
+ ((C) ? ( \
+ 2 /*creation index */ \
+ ) : 0)) \
+ )
+#define H5O_SIZEOF_MSGHDR_OH(O) \
+ H5O_SIZEOF_MSGHDR_VERS((O)->version, (O)->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
+#define H5O_SIZEOF_MSGHDR_F(F, C) \
+ H5O_SIZEOF_MSGHDR_VERS((H5F_USE_LATEST_FLAGS(F, H5F_LATEST_OBJ_HEADER) || H5F_STORE_MSG_CRT_IDX(F)) ? H5O_VERSION_LATEST : H5O_VERSION_1, (C))
+
+/*
+ * Size of chunk "header" for each chunk
+ */
+#define H5O_SIZEOF_CHKHDR_VERS(V) \
+ (((V) == H5O_VERSION_1) \
+ ? \
+ 0 + /*no magic # */ \
+ 0 /*no checksum */ \
+ : \
+ H5_SIZEOF_MAGIC + /*magic # */ \
+ H5O_SIZEOF_CHKSUM /*checksum */ \
+ )
+#define H5O_SIZEOF_CHKHDR_OH(O) \
+ H5O_SIZEOF_CHKHDR_VERS((O)->version)
+
+/*
+ * Size of checksum for each chunk
+ */
+#define H5O_SIZEOF_CHKSUM_VERS(V) \
+ (((V) == H5O_VERSION_1) \
+ ? \
+ 0 /*no checksum */ \
+ : \
+ H5O_SIZEOF_CHKSUM /*checksum */ \
+ )
+#define H5O_SIZEOF_CHKSUM_OH(O) \
+ H5O_SIZEOF_CHKSUM_VERS((O)->version)
+
+/* Input/output flags for decode functions */
+#define H5O_DECODEIO_NOCHANGE 0x01u /* IN: do not modify values */
+#define H5O_DECODEIO_DIRTY 0x02u /* OUT: message has been changed */
+
+/* Macro to incremend ndecode_dirtied (only if we are debugging) */
+#ifndef NDEBUG
+#define INCR_NDECODE_DIRTIED(OH) (OH)->ndecode_dirtied++;
+#else /* NDEBUG */
+#define INCR_NDECODE_DIRTIED(OH) ;
+#endif /* NDEBUG */
+
+/* Load native information for a message, if it's not already present */
+/* (Only works for messages with decode callback) */
+#define H5O_LOAD_NATIVE(F, DXPL, IOF, OH, MSG, ERR) \
+ if(NULL == (MSG)->native) { \
+ const H5O_msg_class_t *msg_type = (MSG)->type; \
+ unsigned ioflags = (IOF); \
+ \
+ /* Decode the message */ \
+ HDassert(msg_type->decode); \
+ if(NULL == ((MSG)->native = (msg_type->decode)((F), (DXPL), (OH), (MSG)->flags, &ioflags, (MSG)->raw))) \
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, ERR, "unable to decode message") \
+ \
+ /* Mark the message dirty if it was changed by decoding */ \
+ if((ioflags & H5O_DECODEIO_DIRTY) && (H5F_get_intent((F)) & H5F_ACC_RDWR)) { \
+ (MSG)->dirty = TRUE; \
+ /* Increment the count of messages dirtied by decoding, but */ \
+ /* only ifndef NDEBUG */ \
+ INCR_NDECODE_DIRTIED(OH) \
+ } \
+ \
+ /* Set the message's "shared info", if it's shareable */ \
+ if((MSG)->flags & H5O_MSG_FLAG_SHAREABLE) { \
+ HDassert(msg_type->share_flags & H5O_SHARE_IS_SHARABLE); \
+ H5O_UPDATE_SHARED((H5O_shared_t *)(MSG)->native, H5O_SHARE_TYPE_HERE, (F), msg_type->id, (MSG)->crt_idx, (OH)->chunk[0].addr) \
+ } /* end if */ \
+ \
+ /* Set the message's "creation index", if it has one */ \
+ if(msg_type->set_crt_index) { \
+ /* Set the creation index for the message */ \
+ if((msg_type->set_crt_index)((MSG)->native, (MSG)->crt_idx) < 0) \
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, ERR, "unable to set creation index") \
+ } /* end if */ \
+ } /* end if */
+
+/* Flags for a message class's "sharability" */
+#define H5O_SHARE_IS_SHARABLE 0x01
+#define H5O_SHARE_IN_OHDR 0x02
+
+/* Set the object header size to speculatively read in */
+/* (needs to be more than the object header prefix size to work at all and
+ * should be larger than the largest object type's default object header
+ * size to save the extra I/O operations) */
+#define H5O_SPEC_READ_SIZE 512
+
+
+/* The "message class" type */
+struct H5O_msg_class_t {
+ unsigned id; /*message type ID on disk */
+ const char *name; /*for debugging */
+ size_t native_size; /*size of native message */
+ unsigned share_flags; /* Message sharing settings */
+ void *(*decode)(H5F_t *, hid_t, H5O_t *, unsigned, unsigned *, const uint8_t *);
+ herr_t (*encode)(H5F_t *, hbool_t, uint8_t *, const void *);
+ void *(*copy)(const void *, void *); /*copy native value */
+ size_t (*raw_size)(const H5F_t *, hbool_t, const void *);/*sizeof encoded message */
+ herr_t (*reset)(void *); /*free nested data structs */
+ herr_t (*free)(void *); /*free main data struct */
+ herr_t (*del)(H5F_t *, hid_t, H5O_t *, void *); /* Delete space in file referenced by this message */
+ herr_t (*link)(H5F_t *, hid_t, H5O_t *, void *); /* Increment any links in file reference by this message */
+ herr_t (*set_share)(void*, const H5O_shared_t*); /* Set shared information */
+ htri_t (*can_share)(const void *); /* Is message allowed to be shared? */
+ herr_t (*pre_copy_file)(H5F_t *, const void *, hbool_t *, const H5O_copy_t *, void *); /*"pre copy" action when copying native value to file */
+ void *(*copy_file)(H5F_t *, void *, H5F_t *, hbool_t *, unsigned *, H5O_copy_t *, void *, hid_t); /*copy native value to file */
+ herr_t (*post_copy_file)(const H5O_loc_t *, const void *, H5O_loc_t *, void *, unsigned *, hid_t, H5O_copy_t *); /*"post copy" action when copying native value to file */
+ herr_t (*get_crt_index)(const void *, H5O_msg_crt_idx_t *); /* Get message's creation index */
+ herr_t (*set_crt_index)(void *, H5O_msg_crt_idx_t); /* Set message's creation index */
+ herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int);
+};
+
+struct H5O_mesg_t {
+ const H5O_msg_class_t *type; /*type of message */
+ hbool_t dirty; /*raw out of date wrt native */
+ uint8_t flags; /*message flags */
+ H5O_msg_crt_idx_t crt_idx; /*message creation index */
+ unsigned chunkno; /*chunk number for this mesg */
+ void *native; /*native format message */
+ uint8_t *raw; /*ptr to raw data */
+ size_t raw_size; /*size with alignment */
+};
+
+/* Struct for storing information about "best" message to move to new chunk */
+typedef struct H5O_msg_alloc_info_t {
+ int msgno; /* Index in message array */
+ unsigned id; /* Message type ID on disk */
+ unsigned chunkno; /* Index in chunk array */
+ size_t gap_size; /* Size of any "gap" in the chunk immediately after message */
+ size_t null_size; /* Size of any null message in the chunk immediately after message */
+ size_t total_size; /* Total size of "available" space around message */
+ unsigned null_msgno; /* Message index of null message immediately after message */
+} H5O_msg_alloc_info_t;
+
+typedef struct H5O_chunk_t {
+ haddr_t addr; /*chunk file address */
+ size_t size; /*chunk size */
+ size_t gap; /*space at end of chunk too small for null message */
+ uint8_t *image; /*image of file */
+ struct H5O_chunk_proxy_t *chunk_proxy; /* Pointer to a chunk's proxy when chunk protected */
+} H5O_chunk_t;
+
+struct H5O_t {
+ H5AC_info_t cache_info; /* Information for metadata cache functions, _must_ be */
+ /* first field in structure */
+
+ /* File-specific information (not stored) */
+ size_t sizeof_size; /* Size of file sizes */
+ size_t sizeof_addr; /* Size of file addresses */
+ hbool_t swmr_write; /* Whether we are doing SWMR writes */
+
+ /* Debugging information (not stored) */
+#ifdef H5O_ENABLE_BAD_MESG_COUNT
+ hbool_t store_bad_mesg_count; /* Flag to indicate that a bad message count should be stored */
+ /* (This is to simulate a bug in earlier
+ * versions of the library)
+ */
+#endif /* H5O_ENABLE_BAD_MESG_COUNT */
+#ifndef NDEBUG
+ size_t ndecode_dirtied; /* Number of messages dirtied by decoding */
+#endif /* NDEBUG */
+
+ /* Chunk management information (not stored) */
+ size_t rc; /* Reference count of [continuation] chunks using this structure */
+
+ /* Object information (stored) */
+ hbool_t has_refcount_msg; /* Whether the object has a ref. count message */
+ unsigned nlink; /*link count */
+ uint8_t version; /*version number */
+ uint8_t flags; /*flags */
+
+ /* Time information (stored, for versions > 1 & H5O_HDR_STORE_TIMES flag set) */
+ time_t atime; /*access time */
+ time_t mtime; /*modification time */
+ time_t ctime; /*change time */
+ time_t btime; /*birth time */
+
+ /* Attribute information (stored, for versions > 1) */
+ unsigned max_compact; /* Maximum # of compact attributes */
+ unsigned min_dense; /* Minimum # of "dense" attributes */
+
+ /* Message management (stored, encoded in chunks) */
+ size_t nmesgs; /*number of messages */
+ size_t alloc_nmesgs; /*number of message slots */
+ H5O_mesg_t *mesg; /*array of messages */
+ size_t link_msgs_seen; /* # of link messages seen when loading header */
+ size_t attr_msgs_seen; /* # of attribute messages seen when loading header */
+
+ /* Chunk management (not stored) */
+ size_t nchunks; /*number of chunks */
+ size_t alloc_nchunks; /*chunks allocated */
+ H5O_chunk_t *chunk; /*array of chunks */
+ hbool_t chunks_pinned; /* Whether chunks are pinned from ohdr protect */
+
+ /* Object header proxy information (not stored) */
+ H5AC_proxy_entry_t *proxy; /* Proxy cache entry for all ohdr entries */
+};
+
+/* Class for types of objects in file */
+typedef struct H5O_obj_class_t {
+ H5O_type_t type; /*object type on disk */
+ const char *name; /*for debugging */
+ void *(*get_copy_file_udata)(void); /*retrieve user data for 'copy file' operation */
+ void (*free_copy_file_udata)(void *); /*free user data for 'copy file' operation */
+ htri_t (*isa)(H5O_t *); /*if a header matches an object class */
+ hid_t (*open)(const H5G_loc_t *, hid_t, hid_t, hbool_t ); /*open an object of this class */
+ void *(*create)(H5F_t *, void *, H5G_loc_t *, hid_t ); /*create an object of this class */
+ H5O_loc_t *(*get_oloc)(hid_t ); /*get the object header location for an object */
+ herr_t (*bh_info)(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info); /*get the index & heap info for an object */
+ herr_t (*flush)(void *obj_ptr, hid_t dxpl_id); /*flush an opened object of this class */
+} H5O_obj_class_t;
+
+/* Node in skip list to map addresses from one file to another during object header copy */
+typedef struct H5O_addr_map_t {
+ H5_obj_t src_obj_pos; /* Location of source object */
+ haddr_t dst_addr; /* Address of object in destination file */
+ hbool_t is_locked; /* Indicate that the destination object is locked currently */
+ hsize_t inc_ref_count; /* Number of deferred increments to reference count */
+ const H5O_obj_class_t *obj_class; /* Object class */
+ void *udata; /* Object class copy file udata */
+} H5O_addr_map_t;
+
+/* Stack of continuation messages to interpret */
+typedef struct H5O_cont_msgs_t {
+ size_t nmsgs; /* Number of continuation messages found so far */
+ size_t alloc_nmsgs; /* Continuation messages allocated */
+ H5O_cont_t *msgs; /* Array of continuation messages */
+} H5O_cont_msgs_t;
+
+/* Common callback information for loading object header prefix from disk */
+typedef struct H5O_common_cache_ud_t {
+ H5F_t *f; /* Pointer to file for object header/chunk */
+ hid_t dxpl_id; /* DXPL for operation */
+ unsigned file_intent; /* Read/write intent for file */
+ unsigned merged_null_msgs; /* Number of null messages merged together */
+ H5O_cont_msgs_t *cont_msg_info; /* Pointer to continuation messages to work on */
+ haddr_t addr; /* Address of the prefix or chunk */
+} H5O_common_cache_ud_t;
+
+/* Callback information for loading object header prefix from disk */
+typedef struct H5O_cache_ud_t {
+ hbool_t made_attempt; /* Whether the deserialize routine was already attempted */
+ unsigned v1_pfx_nmesgs; /* Number of messages from v1 prefix header */
+ size_t chunk0_size; /* Size of serialized first chunk */
+ H5O_t *oh; /* Partially deserialized object header, for later use */
+ H5O_common_cache_ud_t common; /* Common object header cache callback info */
+} H5O_cache_ud_t;
+
+/* Structure representing each chunk in the cache */
+typedef struct H5O_chunk_proxy_t {
+ H5AC_info_t cache_info; /* Information for metadata cache functions, _must_ be */
+ /* first field in structure */
+
+ H5F_t *f; /* Pointer to file for object header/chunk */
+ H5O_t *oh; /* Object header for this chunk */
+ unsigned chunkno; /* Chunk number for this chunk */
+ unsigned cont_chunkno; /* Chunk number for the chunk containing the continuation message that points to this chunk */
+
+ /* Flush depencency parent information (not stored)
+ *
+ * The following field is used to store a pointer
+ * to the in-core representation of the chunk proxy's flush dependency
+ * parent -- if it exists. If it does not exist, this field will
+ * contain NULL.
+ *
+ * If the file is opened in SWMR write mode, the flush dependency
+ * parent of the chunk proxy will be either its object header
+ * (if cont_chunkno == 0) or the chunk proxy indicated by the
+ * cont_chunkno field (if cont_chunkno > 0).
+ */
+ void *parent; /* Pointer to flush dependency parent */
+} H5O_chunk_proxy_t;
+
+/* Callback information for loading object header chunk from disk */
+typedef struct H5O_chk_cache_ud_t {
+ hbool_t decoding; /* Whether the object header is being decoded */
+ H5O_t *oh; /* Object header for this chunk */
+ unsigned chunkno; /* Index of chunk being brought in (for re-loads) */
+ size_t size; /* Size of chunk in the file */
+ H5O_common_cache_ud_t common; /* Common object header cache callback info */
+} H5O_chk_cache_ud_t;
+
+
+/* Header message ID to class mapping */
+H5_DLLVAR const H5O_msg_class_t *const H5O_msg_class_g[H5O_MSG_TYPES];
+
+/* Declare external the free list for H5O_t's */
+H5FL_EXTERN(H5O_t);
+
+/* Declare external the free list for H5O_mesg_t sequences */
+H5FL_SEQ_EXTERN(H5O_mesg_t);
+
+/* Declare external the free list for H5O_chunk_t sequences */
+H5FL_SEQ_EXTERN(H5O_chunk_t);
+
+/* Declare external the free list for chunk_image blocks */
+H5FL_BLK_EXTERN(chunk_image);
+
+/*
+ * Object header messages
+ */
+
+/* Null Message. (0x0000) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_NULL[1];
+
+/* Simple Dataspace Message. (0x0001) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_SDSPACE[1];
+
+/* Link Information Message. (0x0002) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_LINFO[1];
+
+/* Datatype Message. (0x0003) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_DTYPE[1];
+
+/* Old Fill Value Message. (0x0004) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_FILL[1];
+
+/* New Fill Value Message. (0x0005) */
+/*
+ * The new fill value message is fill value plus
+ * space allocation time and fill value writing time and whether fill
+ * value is defined.
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_FILL_NEW[1];
+
+/* Link Message. (0x0006) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_LINK[1];
+
+/* External File List Message. (0x0007) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_EFL[1];
+
+/* Data Layout Message. (0x0008) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_LAYOUT[1];
+
+#ifdef H5O_ENABLE_BOGUS
+/* "Bogus valid" Message. (0x0009) */
+/* "Bogus invalid" Message. (0x0019) */
+/*
+ * Used for debugging - should never be found in valid HDF5 file.
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_BOGUS_VALID[1];
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_BOGUS_INVALID[1];
+#endif /* H5O_ENABLE_BOGUS */
+
+/* Group Information Message. (0x000a) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_GINFO[1];
+
+/* Filter pipeline message. (0x000b) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_PLINE[1];
+
+/* Attribute Message. (0x000c) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_ATTR[1];
+
+/* Object name message. (0x000d) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_NAME[1];
+
+/* Modification Time Message. (0x000e) */
+/*
+ * The message is just a `time_t'.
+ * (See also the "new" modification time message)
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_MTIME[1];
+
+/* Shared Message information message (0x000f)
+ * A message for the superblock extension, holding information about
+ * the file-wide shared message "SOHM" table
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_SHMESG[1];
+
+/* Object Header Continuation Message. (0x0010) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_CONT[1];
+
+/* Symbol Table Message. (0x0011) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_STAB[1];
+
+/* New Modification Time Message. (0x0012) */
+/*
+ * The message is just a `time_t'.
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_MTIME_NEW[1];
+
+/* v1 B-tree 'K' value message (0x0013)
+ * A message for the superblock extension, holding information about
+ * the file-wide v1 B-tree 'K' values.
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_BTREEK[1];
+
+/* Driver info message (0x0014)
+ * A message for the superblock extension, holding information about
+ * the file driver settings
+ */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_DRVINFO[1];
+
+/* Attribute Information Message. (0x0015) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_AINFO[1];
+
+/* Reference Count Message. (0x0016) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_REFCOUNT[1];
+
+/* Free-space Manager Info message. (0x0017) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_FSINFO[1];
+
+/* Metadata Cache Image message. (0x0018) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_MDCI[1];
+
+/* Placeholder for unknown message. (0x0019) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_UNKNOWN[1];
+
+
+/*
+ * Object header "object" types
+ */
+
+/* Group Object. (H5O_TYPE_GROUP - 0) */
+H5_DLLVAR const H5O_obj_class_t H5O_OBJ_GROUP[1];
+
+/* Dataset Object. (H5O_TYPE_DATASET - 1) */
+H5_DLLVAR const H5O_obj_class_t H5O_OBJ_DATASET[1];
+
+/* Datatype Object. (H5O_TYPE_NAMED_DATATYPE - 2) */
+H5_DLLVAR const H5O_obj_class_t H5O_OBJ_DATATYPE[1];
+
+
+/* Package-local function prototypes */
+H5_DLL herr_t H5O_msg_flush(H5F_t *f, H5O_t *oh, H5O_mesg_t *mesg);
+H5_DLL herr_t H5O_flush_msgs(H5F_t *f, H5O_t *oh);
+H5_DLL hid_t H5O_open_by_loc(const H5G_loc_t *obj_loc, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref);
+H5_DLL herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, H5O_mesg_t *mesg);
+H5_DLL const H5O_obj_class_t * H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id);
+H5_DLL int H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, hbool_t *deleted);
+H5_DLL herr_t H5O_inc_rc(H5O_t *oh);
+H5_DLL herr_t H5O_dec_rc(H5O_t *oh);
+H5_DLL herr_t H5O__free(H5O_t *oh);
+
+/* Object header message routines */
+H5_DLL herr_t H5O_msg_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ const H5O_msg_class_t *type, unsigned *mesg_flags, void *mesg,
+ size_t *mesg_idx);
+H5_DLL herr_t H5O_msg_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ const H5O_msg_class_t *type, unsigned mesg_flags, unsigned update_flags,
+ void *mesg);
+H5_DLL herr_t H5O_msg_write_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ const H5O_msg_class_t *type, unsigned mesg_flags, unsigned update_flags,
+ void *mesg);
+H5_DLL void *H5O_msg_free_real(const H5O_msg_class_t *type, void *mesg);
+H5_DLL herr_t H5O_msg_free_mesg(H5O_mesg_t *mesg);
+H5_DLL unsigned H5O_msg_count_real(const H5O_t *oh, const H5O_msg_class_t *type);
+H5_DLL herr_t H5O_msg_remove_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type,
+ int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id);
+H5_DLL void *H5O_msg_copy_file(const H5O_msg_class_t *type, H5F_t *file_src,
+ void *mesg_src, H5F_t *file_dst, hbool_t *recompute_size,
+ unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata, hid_t dxpl_id);
+H5_DLL herr_t H5O_msg_iterate_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type,
+ const H5O_mesg_operator_t *op, void *op_data, hid_t dxpl_id);
+
+/* Object header chunk routines */
+H5_DLL herr_t H5O_chunk_add(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx,
+ unsigned cont_chunkno);
+H5_DLL H5O_chunk_proxy_t *H5O_chunk_protect(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ unsigned idx);
+H5_DLL herr_t H5O_chunk_unprotect(H5F_t *f, hid_t dxpl_id,
+ H5O_chunk_proxy_t *chk_proxy, hbool_t chk_dirtied);
+H5_DLL herr_t H5O_chunk_update_idx(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx);
+H5_DLL herr_t H5O_chunk_resize(H5O_t *oh, H5O_chunk_proxy_t *chk_proxy);
+H5_DLL herr_t H5O_chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx);
+H5_DLL herr_t H5O__chunk_dest(H5O_chunk_proxy_t *chunk_proxy);
+
+/* Collect storage info for btree and heap */
+H5_DLL herr_t H5O_attr_bh_info(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ H5_ih_info_t *bh_info);
+
+/* Object header allocation routines */
+H5_DLL herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc);
+H5_DLL herr_t H5O__alloc_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size,
+ size_t found_null, const H5O_msg_alloc_info_t *found_msg, size_t *new_idx);
+H5_DLL herr_t H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ const H5O_msg_class_t *type, const void *mesg, size_t *mesg_idx);
+H5_DLL herr_t H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id);
+H5_DLL herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ H5O_mesg_t *mesg, hbool_t adj_link);
+
+/* Shared object operators */
+H5_DLL void * H5O_shared_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned *ioflags, const uint8_t *buf, const H5O_msg_class_t *type);
+H5_DLL herr_t H5O_shared_encode(const H5F_t *f, uint8_t *buf/*out*/, const H5O_shared_t *sh_mesg);
+H5_DLL size_t H5O_shared_size(const H5F_t *f, const H5O_shared_t *sh_mesg);
+H5_DLL herr_t H5O_shared_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ const H5O_msg_class_t *mesg_type, H5O_shared_t *sh_mesg);
+H5_DLL herr_t H5O_shared_link(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ const H5O_msg_class_t *mesg_type, H5O_shared_t *sh_mesg);
+H5_DLL herr_t H5O_shared_copy_file(H5F_t *file_src, H5F_t *file_dst,
+ const H5O_msg_class_t *mesg_type, const void *_native_src, void *_native_dst,
+ hbool_t *recompute_size, unsigned *mesg_flags, H5O_copy_t *cpy_info,
+ void *udata, hid_t dxpl_id);
+H5_DLL herr_t H5O_shared_post_copy_file (H5F_t *f,
+ const H5O_msg_class_t *mesg_type, const H5O_shared_t *shared_src,
+ H5O_shared_t *shared_dst, unsigned *mesg_flags, hid_t dxpl_id,
+ H5O_copy_t *cpy_info);
+H5_DLL herr_t H5O_shared_debug(const H5O_shared_t *mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* Attribute message operators */
+H5_DLL herr_t H5O_attr_reset(void *_mesg);
+H5_DLL herr_t H5O_attr_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg);
+H5_DLL herr_t H5O_attr_link(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg);
+H5_DLL herr_t H5O_attr_count_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ hsize_t *nattrs);
+
+/* Testing functions */
+#ifdef H5O_TESTING
+H5_DLL htri_t H5O_is_attr_empty_test(hid_t oid);
+H5_DLL htri_t H5O_is_attr_dense_test(hid_t oid);
+H5_DLL herr_t H5O_num_attrs_test(hid_t oid, hsize_t *nattrs);
+H5_DLL herr_t H5O_attr_dense_info_test(hid_t oid, hsize_t *name_count, hsize_t *corder_count);
+H5_DLL herr_t H5O_check_msg_marked_test(hid_t oid, hbool_t flag_val);
+H5_DLL herr_t H5O_expunge_chunks_test(const H5O_loc_t *oloc, hid_t dxpl_id);
+H5_DLL herr_t H5O_get_rc(const H5O_loc_t *oloc, hid_t dxpl_id, unsigned *rc);
+H5_DLL herr_t H5O_msg_get_chunkno_test(hid_t oid, unsigned msg_type,
+ unsigned *chunk_num);
+H5_DLL herr_t H5O_msg_move_to_new_chunk_test(hid_t oid, unsigned msg_type);
+#endif /* H5O_TESTING */
+
+/* Object header debugging routines */
+#ifdef H5O_DEBUG
+H5_DLL herr_t H5O_assert(const H5O_t *oh);
+#endif /* H5O_DEBUG */
+H5_DLL herr_t H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth);
+
+#endif /* _H5Opkg_H */
+
diff --git a/src/H5Opline.c b/src/H5Opline.c
new file mode 100644
index 0000000..2e52dbb
--- /dev/null
+++ b/src/H5Opline.c
@@ -0,0 +1,691 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, April 15, 1998
+ *
+ * Purpose: Data filter pipeline message.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+#define H5Z_FRIEND /*suppress error about including H5Zpkg */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Zpkg.h" /* Data filters */
+
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5O_pline_encode(H5F_t *f, uint8_t *p, const void *mesg);
+static void *H5O_pline_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static void *H5O_pline_copy(const void *_mesg, void *_dest);
+static size_t H5O_pline_size(const H5F_t *f, const void *_mesg);
+static herr_t H5O_pline_reset(void *_mesg);
+static herr_t H5O_pline_free(void *_mesg);
+static herr_t H5O_pline_pre_copy_file(H5F_t *file_src,
+ const void *mesg_src, hbool_t *deleted, const H5O_copy_t *cpy_info, void *_udata);
+static herr_t H5O_pline_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* Set up & include shared message "interface" info */
+#define H5O_SHARED_TYPE H5O_MSG_PLINE
+#define H5O_SHARED_DECODE H5O_pline_shared_decode
+#define H5O_SHARED_DECODE_REAL H5O_pline_decode
+#define H5O_SHARED_ENCODE H5O_pline_shared_encode
+#define H5O_SHARED_ENCODE_REAL H5O_pline_encode
+#define H5O_SHARED_SIZE H5O_pline_shared_size
+#define H5O_SHARED_SIZE_REAL H5O_pline_size
+#define H5O_SHARED_DELETE H5O_pline_shared_delete
+#undef H5O_SHARED_DELETE_REAL
+#define H5O_SHARED_LINK H5O_pline_shared_link
+#undef H5O_SHARED_LINK_REAL
+#define H5O_SHARED_COPY_FILE H5O_pline_shared_copy_file
+#undef H5O_SHARED_COPY_FILE_REAL
+#define H5O_SHARED_POST_COPY_FILE H5O_pline_shared_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_REAL
+#undef H5O_SHARED_POST_COPY_FILE_UPD
+#define H5O_SHARED_DEBUG H5O_pline_shared_debug
+#define H5O_SHARED_DEBUG_REAL H5O_pline_debug
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_PLINE[1] = {{
+ H5O_PLINE_ID, /* message id number */
+ "filter pipeline", /* message name for debugging */
+ sizeof(H5O_pline_t), /* native message size */
+ H5O_SHARE_IS_SHARABLE|H5O_SHARE_IN_OHDR, /* messages are sharable? */
+ H5O_pline_shared_decode, /* decode message */
+ H5O_pline_shared_encode, /* encode message */
+ H5O_pline_copy, /* copy the native value */
+ H5O_pline_shared_size, /* size of raw message */
+ H5O_pline_reset, /* reset method */
+ H5O_pline_free, /* free method */
+ H5O_pline_shared_delete, /* file delete method */
+ H5O_pline_shared_link, /* link method */
+ NULL, /* set share method */
+ NULL, /*can share method */
+ H5O_pline_pre_copy_file, /* pre copy native value to file */
+ H5O_pline_shared_copy_file, /* copy native value to file */
+ H5O_pline_shared_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_pline_shared_debug /* debug the message */
+}};
+
+
+/* Declare a free list to manage the H5O_pline_t struct */
+H5FL_DEFINE(H5O_pline_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_decode
+ *
+ * Purpose: Decodes a filter pipeline message.
+ *
+ * Return: Success: Ptr to the native message.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_pline_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_pline_t *pline = NULL; /* Pipeline message */
+ H5Z_filter_info_t *filter; /* Filter to decode */
+ size_t name_length; /* Length of filter name */
+ size_t i; /* Local index variable */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(p);
+
+ /* Allocate space for I/O pipeline message */
+ if(NULL == (pline = H5FL_CALLOC(H5O_pline_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Version */
+ pline->version = *p++;
+ if(pline->version < H5O_PLINE_VERSION_1 || pline->version > H5O_PLINE_VERSION_LATEST)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, NULL, "bad version number for filter pipeline message")
+
+ /* Number of filters */
+ pline->nused = *p++;
+ if(pline->nused > H5Z_MAX_NFILTERS)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, NULL, "filter pipeline message has too many filters")
+
+ /* Reserved */
+ if(pline->version == H5O_PLINE_VERSION_1)
+ p += 6;
+
+ /* Allocate array for filters */
+ pline->nalloc = pline->nused;
+ if(NULL == (pline->filter = (H5Z_filter_info_t *)H5MM_calloc(pline->nalloc * sizeof(pline->filter[0]))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Decode filters */
+ for(i = 0, filter = &pline->filter[0]; i < pline->nused; i++, filter++) {
+ /* Filter ID */
+ UINT16DECODE(p, filter->id);
+
+ /* Length of filter name */
+ if(pline->version > H5O_PLINE_VERSION_1 && filter->id < H5Z_FILTER_RESERVED)
+ name_length = 0;
+ else {
+ UINT16DECODE(p, name_length);
+ if(pline->version == H5O_PLINE_VERSION_1 && name_length % 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, NULL, "filter name length is not a multiple of eight")
+ } /* end if */
+
+ /* Filter flags */
+ UINT16DECODE(p, filter->flags);
+
+ /* Number of filter parameters ("client data elements") */
+ UINT16DECODE(p, filter->cd_nelmts);
+
+ /* Filter name, if there is one */
+ if(name_length) {
+ size_t actual_name_length; /* Actual length of name */
+
+ /* Determine actual name length (without padding, but with null terminator) */
+ actual_name_length = HDstrlen((const char *)p) + 1;
+ HDassert(actual_name_length <= name_length);
+
+ /* Allocate space for the filter name, or use the internal buffer */
+ if(actual_name_length > H5Z_COMMON_NAME_LEN) {
+ filter->name = (char *)H5MM_malloc(actual_name_length);
+ if(NULL == filter->name)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for filter name")
+ } /* end if */
+ else
+ filter->name = filter->_name;
+
+ HDstrncpy(filter->name, (const char *)p, actual_name_length);
+ p += name_length;
+ } /* end if */
+
+ /* Filter parameters */
+ if(filter->cd_nelmts) {
+ size_t j; /* Local index variable */
+
+ /* Allocate space for the client data elements, or use the internal buffer */
+ if(filter->cd_nelmts > H5Z_COMMON_CD_VALUES) {
+ filter->cd_values = (unsigned *)H5MM_malloc(filter->cd_nelmts * sizeof(unsigned));
+ if(NULL == filter->cd_values)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for client data")
+ } /* end if */
+ else
+ filter->cd_values = filter->_cd_values;
+
+ /*
+ * Read the client data values and the padding
+ */
+ for(j = 0; j < filter->cd_nelmts; j++)
+ UINT32DECODE(p, filter->cd_values[j]);
+ if(pline->version == H5O_PLINE_VERSION_1)
+ if(filter->cd_nelmts % 2)
+ p += 4; /*padding*/
+ } /* end if */
+ } /* end for */
+
+ /* Set return value */
+ ret_value = pline;
+
+done:
+ if(NULL == ret_value && pline) {
+ H5O_pline_reset(pline);
+ H5O_pline_free(pline);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_pline_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_encode
+ *
+ * Purpose: Encodes message MESG into buffer P.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_pline_encode(H5F_t H5_ATTR_UNUSED *f, uint8_t *p/*out*/, const void *mesg)
+{
+ const H5O_pline_t *pline = (const H5O_pline_t*)mesg; /* Pipeline message to encode */
+ const H5Z_filter_info_t *filter; /* Filter to encode */
+ size_t i, j; /* Local index variables */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(p);
+ HDassert(mesg);
+
+ /* Message header */
+ *p++ = (uint8_t)pline->version;
+ *p++ = (uint8_t)(pline->nused);
+ if(pline->version == H5O_PLINE_VERSION_1) {
+ *p++ = 0; /*reserved 1*/
+ *p++ = 0; /*reserved 2*/
+ *p++ = 0; /*reserved 3*/
+ *p++ = 0; /*reserved 4*/
+ *p++ = 0; /*reserved 5*/
+ *p++ = 0; /*reserved 6*/
+ } /* end if */
+
+ /* Encode filters */
+ for(i = 0, filter = &pline->filter[0]; i < pline->nused; i++, filter++) {
+ const char *name; /* Filter name */
+ size_t name_length; /* Length of filter name */
+
+ /* Filter ID */
+ UINT16ENCODE(p, filter->id);
+
+ /* Skip writing the name length & name if the filter is an internal filter */
+ if(pline->version > H5O_PLINE_VERSION_1 && filter->id < H5Z_FILTER_RESERVED) {
+ name_length = 0;
+ name = NULL;
+ } /* end if */
+ else {
+ H5Z_class2_t *cls; /* Filter class */
+
+ /*
+ * Get the filter name. If the pipeline message has a name in it then
+ * use that one. Otherwise try to look up the filter and get the name
+ * as it was registered.
+ */
+ if(NULL == (name = filter->name) && (cls = H5Z_find(filter->id)))
+ name = cls->name;
+ name_length = name ? HDstrlen(name) + 1 : 0;
+
+ /* Filter name length */
+ UINT16ENCODE(p, pline->version == H5O_PLINE_VERSION_1 ? H5O_ALIGN_OLD(name_length) : name_length);
+ } /* end else */
+
+ /* Filter flags */
+ UINT16ENCODE(p, filter->flags);
+
+ /* # of filter parameters */
+ UINT16ENCODE(p, filter->cd_nelmts);
+
+ /* Encode name, if there is one to encode */
+ if(name_length > 0) {
+ /* Store name, with null terminator */
+ HDmemcpy(p, name, name_length);
+ p += name_length;
+
+ /* Pad out name to alignment, in older versions */
+ if(pline->version == H5O_PLINE_VERSION_1)
+ while(name_length++ % 8)
+ *p++ = 0;
+ } /* end if */
+
+ /* Filter parameters */
+ for(j = 0; j < filter->cd_nelmts; j++)
+ UINT32ENCODE(p, filter->cd_values[j]);
+
+ /* Align the parameters for older versions of the format */
+ if(pline->version == H5O_PLINE_VERSION_1)
+ if(filter->cd_nelmts % 2)
+ UINT32ENCODE(p, 0);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_pline_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_copy
+ *
+ * Purpose: Copies a filter pipeline message from SRC to DST allocating
+ * DST if necessary. If DST is already allocated then we assume
+ * that it isn't initialized.
+ *
+ * Return: Success: Ptr to DST or allocated result.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_pline_copy(const void *_src, void *_dst/*out*/)
+{
+ const H5O_pline_t *src = (const H5O_pline_t *)_src; /* Source pipeline message */
+ H5O_pline_t *dst = (H5O_pline_t *)_dst; /* Destination pipeline message */
+ size_t i; /* Local index variable */
+ H5O_pline_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate pipeline message, if not provided */
+ if(!dst && NULL == (dst = H5FL_MALLOC(H5O_pline_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Shallow copy basic fields */
+ *dst = *src;
+
+ /* Copy over filters, if any */
+ dst->nalloc = dst->nused;
+ if(dst->nalloc) {
+ /* Allocate array to hold filters */
+ if(NULL == (dst->filter = (H5Z_filter_info_t *)H5MM_calloc(dst->nalloc * sizeof(dst->filter[0]))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Deep-copy filters */
+ for(i = 0; i < src->nused; i++) {
+ /* Basic filter information */
+ dst->filter[i] = src->filter[i];
+
+ /* Filter name */
+ if(src->filter[i].name) {
+ size_t namelen; /* Length of source filter name, including null terminator */
+
+ namelen = HDstrlen(src->filter[i].name) + 1;
+
+ /* Allocate space for the filter name, or use the internal buffer */
+ if(namelen > H5Z_COMMON_NAME_LEN) {
+ dst->filter[i].name = (char *)H5MM_strdup(src->filter[i].name);
+ if(NULL == dst->filter[i].name)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for filter name")
+ } /* end if */
+ else
+ dst->filter[i].name = dst->filter[i]._name;
+ } /* end if */
+
+ /* Filter parameters */
+ if(src->filter[i].cd_nelmts > 0) {
+ /* Allocate space for the client data elements, or use the internal buffer */
+ if(src->filter[i].cd_nelmts > H5Z_COMMON_CD_VALUES) {
+ if(NULL == (dst->filter[i].cd_values = (unsigned *)H5MM_malloc(src->filter[i].cd_nelmts* sizeof(unsigned))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ HDmemcpy(dst->filter[i].cd_values, src->filter[i].cd_values,
+ src->filter[i].cd_nelmts * sizeof(unsigned));
+ } /* end if */
+ else
+ dst->filter[i].cd_values = dst->filter[i]._cd_values;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else
+ dst->filter = NULL;
+
+ /* Set return value */
+ ret_value = dst;
+
+done:
+ if(!ret_value && dst) {
+ H5O_pline_reset(dst);
+ if(!_dst)
+ H5O_pline_free(dst);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_pline_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_size
+ *
+ * Purpose: Determines the size of a raw filter pipeline message.
+ *
+ * Return: Success: Size of message.
+ *
+ * Failure: zero
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_pline_size(const H5F_t H5_ATTR_UNUSED *f, const void *mesg)
+{
+ const H5O_pline_t *pline = (const H5O_pline_t*)mesg; /* Pipeline message */
+ size_t i; /* Local index variable */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Message header */
+ ret_value = 1 + /*version */
+ 1 + /*number of filters */
+ (pline->version == H5O_PLINE_VERSION_1 ? 6 : 0); /*reserved */
+
+ /* Calculate size of each filter in pipeline */
+ for(i = 0; i < pline->nused; i++) {
+ size_t name_len; /* Length of filter name */
+ const char *name; /* Filter name */
+
+ /* Don't write the name length & name if the filter is an internal filter */
+ if(pline->version > H5O_PLINE_VERSION_1 && pline->filter[i].id < H5Z_FILTER_RESERVED)
+ name_len = 0;
+ else {
+ H5Z_class2_t *cls; /* Filter class */
+
+ /* Get the name of the filter, same as done with H5O_pline_encode() */
+ if(NULL == (name = pline->filter[i].name) && (cls = H5Z_find(pline->filter[i].id)))
+ name = cls->name;
+ name_len = name ? HDstrlen(name) + 1 : 0;
+ } /* end else */
+
+ ret_value += 2 + /*filter identification number */
+ (size_t)((pline->version == H5O_PLINE_VERSION_1 || pline->filter[i].id >= H5Z_FILTER_RESERVED) ? 2 : 0) + /*name length */
+ 2 + /*flags */
+ 2 + /*number of client data values */
+ (pline->version == H5O_PLINE_VERSION_1 ? (size_t)H5O_ALIGN_OLD(name_len) : name_len); /*length of the filter name */
+
+ ret_value += pline->filter[i].cd_nelmts * 4;
+ if(pline->version == H5O_PLINE_VERSION_1)
+ if(pline->filter[i].cd_nelmts % 2)
+ ret_value += 4;
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_pline_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_reset
+ *
+ * Purpose: Resets a filter pipeline message by clearing all filters.
+ * The MESG buffer is not freed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_pline_reset(void *mesg)
+{
+ H5O_pline_t *pline = (H5O_pline_t*)mesg; /* Pipeline message */
+ size_t i; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(pline);
+
+ /* Free information for each filter */
+ for(i = 0; i < pline->nused; i++) {
+ if(pline->filter[i].name && pline->filter[i].name != pline->filter[i]._name)
+ HDassert((HDstrlen(pline->filter[i].name) + 1) > H5Z_COMMON_NAME_LEN);
+ if(pline->filter[i].name != pline->filter[i]._name)
+ pline->filter[i].name = (char *)H5MM_xfree(pline->filter[i].name);
+ if(pline->filter[i].cd_values && pline->filter[i].cd_values != pline->filter[i]._cd_values)
+ HDassert(pline->filter[i].cd_nelmts > H5Z_COMMON_CD_VALUES);
+ if(pline->filter[i].cd_values != pline->filter[i]._cd_values)
+ pline->filter[i].cd_values = (unsigned *)H5MM_xfree(pline->filter[i].cd_values);
+ } /* end for */
+
+ /* Free filter array */
+ if(pline->filter)
+ pline->filter = (H5Z_filter_info_t *)H5MM_xfree(pline->filter);
+
+ /* Reset # of filters */
+ pline->nused = pline->nalloc = 0;
+
+ /* Reset version # of pipeline message */
+ pline->version = H5O_PLINE_VERSION_1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_pline_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 11, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_pline_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_pline_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_pline_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Peter Cao
+ * December 27, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_pline_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void *mesg_src,
+ hbool_t H5_ATTR_UNUSED *deleted, const H5O_copy_t H5_ATTR_UNUSED *cpy_info, void *_udata)
+{
+ const H5O_pline_t *pline_src = (const H5O_pline_t *)mesg_src; /* Source datatype */
+ H5O_copy_file_ud_common_t *udata = (H5O_copy_file_ud_common_t *)_udata; /* Object copying user data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(pline_src);
+
+ /* If the user data is non-NULL, assume we are copying a dataset or group
+ * and make a copy of the filter pipeline for later in
+ * the object copying process.
+ */
+ if(udata)
+ if(NULL == (udata->src_pline = (H5O_pline_t *)H5O_pline_copy(pline_src, NULL)))
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to copy")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_pline_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_debug
+ *
+ * Purpose: Prints debugging information for filter pipeline message MESG
+ * on output stream STREAM. Each line is indented INDENT
+ * characters and the field name takes up FWIDTH characters.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_pline_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_pline_t *pline = (const H5O_pline_t *)mesg;
+ size_t i, j;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(pline);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %Zu/%Zu\n", indent, "", fwidth,
+ "Number of filters:",
+ pline->nused,
+ pline->nalloc);
+
+ /* Loop over all the filters */
+ for(i = 0; i < pline->nused; i++) {
+ char name[32];
+
+ HDsnprintf(name, sizeof(name), "Filter at position %u", (unsigned)i);
+ HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth, name);
+ HDfprintf(stream, "%*s%-*s 0x%04x\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Filter identification:",
+ (unsigned)(pline->filter[i].id));
+ if(pline->filter[i].name)
+ HDfprintf(stream, "%*s%-*s \"%s\"\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Filter name:",
+ pline->filter[i].name);
+ else
+ HDfprintf(stream, "%*s%-*s NONE\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Filter name:");
+ HDfprintf(stream, "%*s%-*s 0x%04x\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Flags:",
+ pline->filter[i].flags);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3),
+ "Num CD values:",
+ pline->filter[i].cd_nelmts);
+
+ /* Filter parameters */
+ for(j = 0; j < pline->filter[i].cd_nelmts; j++) {
+ char field_name[32];
+
+ HDsnprintf(field_name, sizeof(field_name), "CD value %lu", (unsigned long)j);
+ HDfprintf(stream, "%*s%-*s %u\n", indent + 6, "", MAX(0, fwidth - 6),
+ field_name,
+ pline->filter[i].cd_values[j]);
+ } /* end for */
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_pline_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_pline_set_latest_version
+ *
+ * Purpose: Set the encoding for a I/O filter pipeline to the latest version.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 24, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_pline_set_latest_version(H5O_pline_t *pline)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(pline);
+
+ /* Set encoding of I/O pipeline to latest version */
+ pline->version = H5O_PLINE_VERSION_LATEST;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_pline_set_latest_version() */
+
diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h
new file mode 100644
index 0000000..0f798b2
--- /dev/null
+++ b/src/H5Oprivate.h
@@ -0,0 +1,976 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Oprivate.h
+ * Aug 5 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Object header private include file.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Oprivate_H
+#define _H5Oprivate_H
+
+/* Include the public header file for this API */
+#include "H5Opublic.h" /* Object header functions */
+
+/* Public headers needed by this file */
+#include "H5Dpublic.h" /* Dataset functions */
+#include "H5Lpublic.h" /* Link functions */
+#include "H5Spublic.h" /* Dataspace functions */
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Fprivate.h" /* File access */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5SLprivate.h" /* Skip lists */
+#include "H5Tprivate.h" /* Datatype functions */
+#include "H5Zprivate.h" /* I/O pipeline filters */
+
+/* Forward references of package typedefs */
+typedef struct H5O_msg_class_t H5O_msg_class_t;
+typedef struct H5O_mesg_t H5O_mesg_t;
+typedef struct H5O_t H5O_t;
+
+/* Values used to create the shared message & attribute heaps */
+/* (Note that these parameters have been tuned so that the resulting heap ID
+ * is exactly 8 bytes. This is an efficient size as it can be stored
+ * directly in an 8 byte integer in memory, think carefully before changing it.
+ * -QAK)
+ */
+#define H5O_FHEAP_MAN_WIDTH 4
+#define H5O_FHEAP_MAN_START_BLOCK_SIZE 1024
+#define H5O_FHEAP_MAN_MAX_DIRECT_SIZE (64 * 1024)
+#define H5O_FHEAP_MAN_MAX_INDEX 40
+#define H5O_FHEAP_MAN_START_ROOT_ROWS 1
+#define H5O_FHEAP_CHECKSUM_DBLOCKS TRUE
+#define H5O_FHEAP_MAX_MAN_SIZE (4 * 1024)
+#define H5O_FHEAP_ID_LEN 8
+
+/* Object header macros */
+#define H5O_MESG_MAX_SIZE 65536 /*max obj header message size */
+#define H5O_ALL (-1) /* Operate on all messages of type */
+#define H5O_FIRST (-2) /* Operate on first message of type */
+
+/* Flags needed when encoding messages */
+#define H5O_MSG_NO_FLAGS_SET 0x00u
+#define H5O_MSG_FLAG_CONSTANT 0x01u
+#define H5O_MSG_FLAG_SHARED 0x02u
+#define H5O_MSG_FLAG_DONTSHARE 0x04u
+#define H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE 0x08u
+#define H5O_MSG_FLAG_MARK_IF_UNKNOWN 0x10u
+#define H5O_MSG_FLAG_WAS_UNKNOWN 0x20u
+#define H5O_MSG_FLAG_SHAREABLE 0x40u
+#define H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS 0x80u
+#define H5O_MSG_FLAG_BITS (H5O_MSG_FLAG_CONSTANT|H5O_MSG_FLAG_SHARED|H5O_MSG_FLAG_DONTSHARE|H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE|H5O_MSG_FLAG_MARK_IF_UNKNOWN|H5O_MSG_FLAG_WAS_UNKNOWN|H5O_MSG_FLAG_SHAREABLE|H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS)
+
+/* Flags for updating messages */
+#define H5O_UPDATE_TIME 0x01u
+#define H5O_UPDATE_FORCE 0x02u /* Force updating the message */
+
+/* Hash value constants */
+#define H5O_HASH_SIZE 32
+
+/* Enable reading/writing "bogus" messages */
+/* #define H5O_ENABLE_BOGUS */
+
+/* ========= Object Creation properties ============ */
+#define H5O_CRT_ATTR_MAX_COMPACT_NAME "max compact attr" /* Max. # of attributes to store compactly */
+#define H5O_CRT_ATTR_MIN_DENSE_NAME "min dense attr" /* Min. # of attributes to store densely */
+#define H5O_CRT_OHDR_FLAGS_NAME "object header flags" /* Object header flags */
+#define H5O_CRT_PIPELINE_NAME "pline" /* Filter pipeline */
+#define H5O_CRT_PIPELINE_DEF {{0, NULL, H5O_NULL_ID, {{0, HADDR_UNDEF}}}, H5O_PLINE_VERSION_1, 0, 0, NULL}
+#ifdef H5O_ENABLE_BOGUS
+#define H5O_BOGUS_MSG_FLAGS_NAME "bogus msg flags" /* Flags for 'bogus' message */
+#define H5O_BOGUS_MSG_FLAGS_SIZE sizeof(uint8_t)
+
+/* bogus ID can be either (a) H5O_BOGUS_VALID_ID or (b) H5O_BOGUS_INVALID_ID */
+#define H5O_BOGUS_MSG_ID_NAME "bogus msg id" /* ID for 'bogus' message */
+#define H5O_BOGUS_MSG_ID_SIZE sizeof(unsigned)
+
+#endif /* H5O_ENABLE_BOGUS */
+
+#ifdef H5O_ENABLE_BAD_MESG_COUNT
+#define H5O_BAD_MESG_COUNT_NAME "bad message count" /* Flag setting bad message count */
+#define H5O_BAD_MESG_COUNT_SIZE sizeof(hbool_t)
+#endif /* H5O_ENABLE_BAD_MESG_COUNT */
+
+/* ========= Object Copy properties ============ */
+#define H5O_CPY_OPTION_NAME "copy object" /* Copy options */
+#define H5O_CPY_MERGE_COMM_DT_LIST_NAME "merge committed dtype list" /* List of datatype paths to search in the dest file for merging */
+#define H5O_CPY_MCDT_SEARCH_CB_NAME "committed dtype list search" /* Callback function when the search for a matching committed datatype is complete */
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5O_MODULE
+#define H5O_OH_GET_ADDR(O) ((O)->chunk[0].addr)
+#else /* H5O_MODULE */
+#define H5O_OH_GET_ADDR(O) (H5O_get_oh_addr(O))
+#endif /* H5O_MODULE */
+
+/* Set the fields in a shared message structure */
+#define H5O_UPDATE_SHARED(SH_MESG, SH_TYPE, F, MSG_TYPE, CRT_IDX, OH_ADDR) \
+ { \
+ (SH_MESG)->type = (SH_TYPE); \
+ (SH_MESG)->file = (F); \
+ (SH_MESG)->msg_type_id = (MSG_TYPE); \
+ (SH_MESG)->u.loc.index = (CRT_IDX); \
+ (SH_MESG)->u.loc.oh_addr = (OH_ADDR); \
+ } /* end block */
+
+
+/* Fractal heap ID type for shared message & attribute heap IDs. */
+typedef union {
+ uint8_t id[H5O_FHEAP_ID_LEN]; /* Buffer to hold ID, for encoding/decoding */
+ uint64_t val; /* Value, for quick comparisons */
+} H5O_fheap_id_t;
+
+/* The object location information for an object */
+typedef struct H5O_loc_t {
+ H5F_t *file; /* File that object header is located within */
+ haddr_t addr; /* File address of object header */
+ hbool_t holding_file; /* True if this object header has incremented
+ * its file's count of open objects. */
+} H5O_loc_t;
+
+/* Typedef for linked list of datatype merge suggestions */
+typedef struct H5O_copy_dtype_merge_list_t {
+ char *path; /* Path to datatype in destination file */
+ struct H5O_copy_dtype_merge_list_t *next; /* Next object in list */
+} H5O_copy_dtype_merge_list_t;
+
+/* Structure for callback property before searching the global list of committed datatypes at destination */
+typedef struct H5O_mcdt_cb_info_t {
+ H5O_mcdt_search_cb_t func;
+ void *user_data;
+} H5O_mcdt_cb_info_t;
+
+/* Settings/flags for copying an object */
+typedef struct H5O_copy_t {
+ hbool_t copy_shallow; /* Flag to perform shallow hierarchy copy */
+ hbool_t expand_soft_link; /* Flag to expand soft links */
+ hbool_t expand_ext_link; /* Flag to expand external links */
+ hbool_t expand_ref; /* Flag to expand object references */
+ hbool_t copy_without_attr; /* Flag to not copy attributes */
+ hbool_t preserve_null; /* Flag to not delete NULL messages */
+ hbool_t merge_comm_dt; /* Flag to merge committed datatypes in dest file */
+ H5O_copy_dtype_merge_list_t *dst_dt_suggestion_list; /* Suggestions for merging committed datatypes */
+ int curr_depth; /* Current depth in hierarchy copied */
+ int max_depth; /* Maximum depth in hierarchy to copy */
+ H5SL_t *map_list; /* Skip list to hold address mappings */
+ H5SL_t *dst_dt_list; /* Skip list to hold committed datatypes in dest file */
+ hbool_t dst_dt_list_complete; /* Whether the destination datatype list is complete (i.e. not only populated with "suggestions" from H5Padd_merge_committed_dtype_path) */
+ H5O_t *oh_dst; /* The destination object header */
+ H5O_mcdt_search_cb_t mcdt_cb; /* The callback to invoke before searching the global list of committed datatypes at destination */
+ void *mcdt_ud; /* User data passed to callback */
+} H5O_copy_t;
+
+/* Header message IDs */
+#define H5O_NULL_ID 0x0000 /* Null Message. */
+#define H5O_SDSPACE_ID 0x0001 /* Dataspace Message. */
+#define H5O_LINFO_ID 0x0002 /* Link info Message. */
+#define H5O_DTYPE_ID 0x0003 /* Datatype Message. */
+#define H5O_FILL_ID 0x0004 /* Fill Value Message. (Old) */
+#define H5O_FILL_NEW_ID 0x0005 /* Fill Value Message. (New) */
+#define H5O_LINK_ID 0x0006 /* Link Message. */
+#define H5O_EFL_ID 0x0007 /* External File List Message */
+#define H5O_LAYOUT_ID 0x0008 /* Data Layout Message. */
+#define H5O_BOGUS_VALID_ID 0x0009 /* "Bogus valid" Message. */
+#define H5O_GINFO_ID 0x000a /* Group info Message. */
+#define H5O_PLINE_ID 0x000b /* Filter pipeline message. */
+#define H5O_ATTR_ID 0x000c /* Attribute Message. */
+#define H5O_NAME_ID 0x000d /* Object name message. */
+#define H5O_MTIME_ID 0x000e /* Modification time message. (Old) */
+#define H5O_SHMESG_ID 0x000f /* Shared message "SOHM" table. */
+#define H5O_CONT_ID 0x0010 /* Object header continuation message. */
+#define H5O_STAB_ID 0x0011 /* Symbol table message. */
+#define H5O_MTIME_NEW_ID 0x0012 /* Modification time message. (New) */
+#define H5O_BTREEK_ID 0x0013 /* v1 B-tree 'K' values message. */
+#define H5O_DRVINFO_ID 0x0014 /* Driver info message. */
+#define H5O_AINFO_ID 0x0015 /* Attribute info message. */
+#define H5O_REFCOUNT_ID 0x0016 /* Reference count message. */
+#define H5O_FSINFO_ID 0x0017 /* File space info message. */
+#define H5O_MDCI_MSG_ID 0x0018 /* Metadata Cache Image Message */
+#define H5O_UNKNOWN_ID 0x0019 /* Placeholder message ID for unknown message. */
+ /* (this should never exist in a file) */
+/*
+ * Note: Must increment H5O_MSG_TYPES in H5Opkg.h and update H5O_msg_class_g
+ * in H5O.c when creating a new message type. Also bump the value of
+ * H5O_BOGUS_INVALID_ID, below, to be one greater than the value of
+ * H5O_UNKNOWN_ID.
+ *
+ * (this should never exist in a file)
+ */
+#define H5O_BOGUS_INVALID_ID 0x001A /* "Bogus invalid" Message. */
+
+/* Shared object message types.
+ * Shared objects can be committed, in which case the shared message contains
+ * the location of the object header that holds the message, or shared in the
+ * heap, in which case the shared message holds their heap ID.
+ */
+#define H5O_SHARE_TYPE_UNSHARED 0 /* Message is not shared */
+#define H5O_SHARE_TYPE_SOHM 1 /* Message is stored in SOHM heap */
+#define H5O_SHARE_TYPE_COMMITTED 2 /* Message is stored in another object header */
+#define H5O_SHARE_TYPE_HERE 3 /* Message is stored in this object header, but is sharable */
+
+/* Detect messages that aren't stored in message's object header */
+#define H5O_IS_STORED_SHARED(T) ((((T) == H5O_SHARE_TYPE_SOHM) || ((T) == H5O_SHARE_TYPE_COMMITTED)) ? TRUE : FALSE)
+
+/* Detect shared messages that are "tracked" in some other location */
+#define H5O_IS_TRACKED_SHARED(T) ((T) > 0)
+
+
+/* Specify the object header address and index needed
+ * to locate a message in another object header.
+ */
+typedef struct H5O_mesg_loc_t {
+ H5O_msg_crt_idx_t index; /* index within object header */
+ haddr_t oh_addr; /* address of object header */
+} H5O_mesg_loc_t;
+
+
+/*
+ * Shared object header message info.
+ *
+ * (This structure is used in other messages that can be shared and will
+ * include a H5O_shared_t struct as the first field in their "native" type)
+ */
+typedef struct H5O_shared_t {
+ unsigned type; /* Type describing how message is shared */
+ H5F_t *file; /* File that message is located within */
+ unsigned msg_type_id; /* Message's type ID */
+ union {
+ H5O_mesg_loc_t loc; /* Object location info */
+ H5O_fheap_id_t heap_id; /* ID within the SOHM heap */
+ } u;
+} H5O_shared_t;
+
+
+/*
+ * Link Info Message.
+ * (Contains dynamic information about links in a group)
+ * (Data structure in memory)
+ * (if the fields in this struct are changed, remember to change the default
+ * link info structure in src/H5Gprivate.h - QAK)
+ * (if the fields in this struct are changed, also look at the code that
+ * creates intermediate groups in src/H5Gtraverse.c - QAK)
+ * (The "max. creation order" field is signed so that we might have an easy
+ * way to add links to the front of the creation ordering (with negative
+ * values) as well as the end of the creation ordering - QAK)
+ */
+typedef struct H5O_linfo_t {
+ /* Creation order info */
+ hbool_t track_corder; /* Are creation order values tracked on links? */
+ hbool_t index_corder; /* Are creation order values indexed on links? */
+ int64_t max_corder; /* Current max. creation order value for group */
+ haddr_t corder_bt2_addr; /* Address of v2 B-tree for indexing creation order values of links */
+
+ /* Storage management info */
+ hsize_t nlinks; /* Number of links in the group */
+ haddr_t fheap_addr; /* Address of fractal heap for storing "dense" links */
+ haddr_t name_bt2_addr; /* Address of v2 B-tree for indexing names of links */
+} H5O_linfo_t;
+
+/* Initial version of the "old" fill value information */
+/* (It doesn't look like this value was ever used in the file -QAK) */
+#define H5O_FILL_VERSION_1 1
+/* Revised version of the "new" fill value information */
+#define H5O_FILL_VERSION_2 2
+/* Version of the "new" fill value information with smaller default format */
+#define H5O_FILL_VERSION_3 3
+
+/* The latest version of the format. Look through the 'encode', 'decode'
+ * and 'size' callback for places to change when updating this. */
+#define H5O_FILL_VERSION_LATEST H5O_FILL_VERSION_3
+
+/*
+ * Fill Value Message.
+ * (Data structure in memory for both "old" and "new" fill value messages)
+ *
+ * The fill value message is fill value plus space allocation time, fill value
+ * writing time, whether fill value is defined, and the location of the
+ * message if it's shared.
+ */
+
+typedef struct H5O_fill_t {
+ H5O_shared_t sh_loc; /* Shared message info (must be first) */
+
+ unsigned version; /* Encoding version number */
+ H5T_t *type; /*type. Null implies same as dataset */
+ ssize_t size; /*number of bytes in the fill value */
+ void *buf; /*the fill value */
+ H5D_alloc_time_t alloc_time; /* time to allocate space */
+ H5D_fill_time_t fill_time; /* time to write fill value */
+ hbool_t fill_defined; /* whether fill value is defined */
+} H5O_fill_t;
+
+/*
+ * Link message.
+ * (Data structure in memory)
+ */
+typedef struct H5O_link_hard_t {
+ haddr_t addr; /* Object header address */
+} H5O_link_hard_t;
+
+typedef struct H5O_link_soft_t {
+ char *name; /* Destination name */
+} H5O_link_soft_t;
+
+typedef struct H5O_link_ud_t {
+ void *udata; /* Opaque data supplied by the user */
+ size_t size; /* Size of udata */
+} H5O_link_ud_t;
+
+typedef struct H5O_link_t {
+ H5L_type_t type; /* Type of link */
+ hbool_t corder_valid; /* Creation order for link is valid (not stored) */
+ int64_t corder; /* Creation order for link (stored if it's valid) */
+ H5T_cset_t cset; /* Character set of link name */
+ char *name; /* Link name */
+ union {
+ H5O_link_hard_t hard; /* Information for hard links */
+ H5O_link_soft_t soft; /* Information for soft links */
+ H5O_link_ud_t ud; /* Information for user-defined links */
+ } u;
+} H5O_link_t;
+
+/*
+ * External File List Message
+ * (Data structure in memory)
+ */
+#define H5O_EFL_ALLOC 16 /*number of slots to alloc at once */
+#define H5O_EFL_UNLIMITED H5F_UNLIMITED /*max possible file size */
+
+typedef struct H5O_efl_entry_t {
+ size_t name_offset; /*offset of name within heap */
+ char *name; /*malloc'd name */
+ HDoff_t offset; /*offset of data within file */
+ hsize_t size; /*size allocated within file */
+} H5O_efl_entry_t;
+
+typedef struct H5O_efl_t {
+ haddr_t heap_addr; /*address of name heap */
+ size_t nalloc; /*number of slots allocated */
+ size_t nused; /*number of slots used */
+ H5O_efl_entry_t *slot; /*array of external file entries */
+} H5O_efl_t;
+
+
+/*
+ * Data Layout Message.
+ * (Data structure in file)
+ */
+#define H5O_LAYOUT_NDIMS (H5S_MAX_RANK+1)
+
+/* Flags for chunked layout feature encoding */
+#define H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS 0x01
+#define H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER 0x02
+#define H5O_LAYOUT_ALL_CHUNK_FLAGS ( \
+ H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS \
+ | H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER \
+ )
+
+/* Initial version of the layout information. Used when space is allocated */
+#define H5O_LAYOUT_VERSION_1 1
+
+/* This version added support for delaying allocation */
+#define H5O_LAYOUT_VERSION_2 2
+
+/* This version is revised to store just the information needed for each
+ * storage type, and to straighten out problems with contiguous layout's
+ * sizes (was encoding them as 4-byte values when they were really n-byte
+ * values (where n usually is 8)).
+ */
+#define H5O_LAYOUT_VERSION_3 3
+
+/* This version adds different types of indices to chunked datasets, allows
+ * for larger chunk dimensions, stores chunk indices into their own
+ * message (the "layout index" message), adds features for compact/dense
+ * storage of elements and/or chunk records, adds features for abbreviating
+ * the storage used for partial chunks on boundaries, adds the virtual
+ * layout type, etc.
+ */
+#define H5O_LAYOUT_VERSION_4 4
+
+/* The default version of the format. (Earlier versions had bugs) */
+#define H5O_LAYOUT_VERSION_DEFAULT H5O_LAYOUT_VERSION_3
+
+/* The latest version of the format. Look through the 'encode'
+ * and 'size' callbacks for places to change when updating this. */
+#define H5O_LAYOUT_VERSION_LATEST H5O_LAYOUT_VERSION_4
+
+/* Forward declaration of structs used below */
+struct H5D_layout_ops_t; /* Defined in H5Dpkg.h */
+struct H5D_chunk_ops_t; /* Defined in H5Dpkg.h */
+
+typedef struct H5O_storage_contig_t {
+ haddr_t addr; /* File address of data */
+ hsize_t size; /* Size of data in bytes */
+} H5O_storage_contig_t;
+
+typedef struct H5O_storage_chunk_btree_t {
+ haddr_t dset_ohdr_addr; /* File address dataset's object header */
+ H5UC_t *shared; /* Ref-counted shared info for B-tree nodes */
+} H5O_storage_chunk_btree_t;
+
+/* Forward declaration of structs used below */
+struct H5FA_t; /* Defined in H5FAprivate.h */
+
+typedef struct H5O_storage_chunk_farray_t {
+ haddr_t dset_ohdr_addr; /* File address dataset's object header */
+ struct H5FA_t *fa; /* Pointer to fixed index array struct */
+} H5O_storage_chunk_farray_t;
+
+/* Forward declaration of structs used below */
+struct H5EA_t; /* Defined in H5EAprivate.h */
+
+typedef struct H5O_storage_chunk_earray_t {
+ haddr_t dset_ohdr_addr; /* File address dataset's object header */
+ struct H5EA_t *ea; /* Pointer to extensible index array struct */
+} H5O_storage_chunk_earray_t;
+
+/* Filtered info for single chunk index */
+typedef struct H5O_storage_chunk_single_filt_t {
+ uint32_t nbytes; /* Size of chunk (in file) */
+ uint32_t filter_mask; /* Excluded filters for chunk */
+} H5O_storage_chunk_single_filt_t;
+
+/* Forward declaration of structs used below */
+struct H5B2_t; /* Defined in H5B2pkg.h */
+
+typedef struct H5O_storage_chunk_bt2_t {
+ haddr_t dset_ohdr_addr; /* File address dataset's object header */
+ struct H5B2_t *bt2; /* Pointer to b-tree 2 struct */
+} H5O_storage_chunk_bt2_t;
+
+typedef struct H5O_storage_chunk_t {
+ H5D_chunk_index_t idx_type; /* Type of chunk index */
+ haddr_t idx_addr; /* File address of chunk index */
+ const struct H5D_chunk_ops_t *ops; /* Pointer to chunked storage operations */
+ union {
+ H5O_storage_chunk_btree_t btree; /* Information for v1 B-tree index */
+ H5O_storage_chunk_bt2_t btree2; /* Information for v2 B-tree index */
+ H5O_storage_chunk_earray_t earray; /* Information for extensible array index */
+ H5O_storage_chunk_farray_t farray; /* Information for fixed array index */
+ H5O_storage_chunk_single_filt_t single; /* Information for single chunk w/ filters index */
+ } u;
+} H5O_storage_chunk_t;
+
+typedef struct H5O_storage_compact_t {
+ hbool_t dirty; /* Dirty flag for compact dataset */
+ size_t size; /* Size of buffer in bytes */
+ void *buf; /* Buffer for compact dataset */
+} H5O_storage_compact_t;
+
+typedef struct H5O_storage_virtual_srcdset_t {
+ /* Stored */
+ struct H5S_t *virtual_select; /* Selection in the virtual dataset that is mapped to source selection */
+
+ /* Not stored */
+ char *file_name; /* Source file name used for virtual dataset mapping */
+ char *dset_name; /* Source dataset name used for virtual dataset mapping */
+ struct H5S_t *clipped_source_select; /* Clipped version of source_select */
+ struct H5S_t *clipped_virtual_select; /* Clipped version of virtual_select */
+ struct H5D_t *dset; /* Source dataset */
+ hbool_t dset_exists; /* Whether the dataset exists (was opened successfully) */
+
+ /* Temporary - only used during I/O operation, NULL at all other times */
+ struct H5S_t *projected_mem_space; /* Selection within mem_space for this mapping */
+} H5O_storage_virtual_srcdset_t;
+
+typedef struct H5O_storage_virtual_name_seg_t {
+ char *name_segment; /* String for this name segment */
+ struct H5O_storage_virtual_name_seg_t *next; /* Next name segment */
+} H5O_storage_virtual_name_seg_t;
+
+typedef enum H5O_virtual_space_status_t {
+ H5O_VIRTUAL_STATUS_INVALID = 0, /* Space extent is invalid */
+ H5O_VIRTUAL_STATUS_SEL_BOUNDS, /* Space extent set to bounds of selection */
+ H5O_VIRTUAL_STATUS_USER, /* Space extent provided by application */
+ H5O_VIRTUAL_STATUS_CORRECT /* Space extent matches dataset */
+} H5O_virtual_space_status_t;
+
+typedef struct H5O_storage_virtual_ent_t {
+ /* Stored */
+ H5O_storage_virtual_srcdset_t source_dset; /* Information about the source dataset */
+ char *source_file_name; /* Original (unparsed) source file name */
+ char *source_dset_name; /* Original (unparsed) source dataset name */
+ struct H5S_t *source_select; /* Selection in the source dataset for mapping */
+
+ /* Not stored */
+ H5O_storage_virtual_srcdset_t *sub_dset; /* Array of sub-source dataset info structs */
+ size_t sub_dset_nalloc; /* Number of slots allocated in sub_dset */
+ size_t sub_dset_nused; /* Number of slots "used" in sub_dset - essentially the farthest sub dataset in the extent */
+ size_t sub_dset_io_start; /* First element in sub_dset involved in current I/O op. Field has no meaning and may be uninitialized at all other times */
+ size_t sub_dset_io_end; /* First element in sub_dset outside of current I/O op. Field has no meaning and may be uninitialized at all other times */
+ H5O_storage_virtual_name_seg_t *parsed_source_file_name; /* Parsed version of source_dset.file_name */
+ size_t psfn_static_strlen; /* Length of parsed_source_file_name without block number substitutions */
+ size_t psfn_nsubs; /* Number of block number substitutions in parsed_source_file_name */
+ H5O_storage_virtual_name_seg_t *parsed_source_dset_name; /* Parsed version of source_dset.dset_name */
+ size_t psdn_static_strlen; /* Length of parsed_source_dset_name without block number substitutions */
+ size_t psdn_nsubs; /* Number of block number substitutions in parsed_source_dset_name */
+ int unlim_dim_source; /* Unlimited dimension in source_select */
+ int unlim_dim_virtual; /* Unlimited dimension in virtual_select */
+ hsize_t unlim_extent_source; /* Extent of unlimited dimension in source dset last time virtual_select was patched to match selection */
+ hsize_t unlim_extent_virtual; /* Extent of unlimited dimension in virtual dset last time source_select was patched to match selection */
+ hsize_t clip_size_virtual; /* Size selection would be clipped to in virtual selection, ignoring other mappings, when source extent == unlim_extent_source */
+ hsize_t clip_size_source; /* Size selection would be clipped to in source selection when virtual extent == unlim_extent_virtual */
+ H5O_virtual_space_status_t source_space_status; /* Extent patching status of source_select */
+ H5O_virtual_space_status_t virtual_space_status; /* Extent patching status of virtual_select */
+} H5O_storage_virtual_ent_t;
+
+typedef struct H5O_storage_virtual_t {
+ /* Stored in message */
+ H5HG_t serial_list_hobjid; /* Global heap ID for the list of virtual mapping entries stored on disk */
+
+ /* Stored in heap */
+ size_t list_nused; /* Number of array elements used in list */
+ H5O_storage_virtual_ent_t *list; /* Array of virtual dataset mapping entries */
+
+ /* Not stored */
+ size_t list_nalloc; /* Number of slots allocated */
+ hsize_t min_dims[H5S_MAX_RANK]; /* Minimum extent of VDS (maximum of all non-unlimited selection bounds) */
+ H5D_vds_view_t view; /* Method for calculating the extent of the virtual dataset with unlimited selections */
+ hsize_t printf_gap; /* Maximum number of sequential missing source datasets before terminating the search for more */
+ hid_t source_fapl; /* FAPL to use to open source files */
+ hid_t source_dapl; /* DAPL to use to open source datasets */
+ hbool_t init; /* Whether all information has been completely initialized */
+} H5O_storage_virtual_t;
+
+typedef struct H5O_storage_t {
+ H5D_layout_t type; /* Type of layout */
+ union {
+ H5O_storage_contig_t contig; /* Information for contiguous storage */
+ H5O_storage_chunk_t chunk; /* Information for chunked storage */
+ H5O_storage_compact_t compact; /* Information for compact storage */
+ H5O_storage_virtual_t virt; /* Information for virtual storage */
+ } u;
+} H5O_storage_t;
+
+typedef struct H5O_layout_chunk_farray_t {
+ /* Creation parameters for fixed array data structure */
+ struct {
+ uint8_t max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in a data block page) -
+ i.e. # of bits needed to store max. # of elements
+ in a data block page */
+ } cparam;
+} H5O_layout_chunk_farray_t;
+
+typedef struct H5O_layout_chunk_earray_t {
+ /* Creation parameters for extensible array data structure */
+ struct {
+ uint8_t max_nelmts_bits; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */
+ uint8_t idx_blk_elmts; /* # of elements to store in index block */
+ uint8_t data_blk_min_elmts; /* Min. # of elements per data block */
+ uint8_t sup_blk_min_data_ptrs; /* Min. # of data block pointers for a super block */
+ uint8_t max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */
+ } cparam;
+
+ unsigned unlim_dim; /* Rank of unlimited dimension for dataset */
+ uint32_t swizzled_dim[H5O_LAYOUT_NDIMS]; /* swizzled chunk dimensions */
+ hsize_t swizzled_down_chunks[H5O_LAYOUT_NDIMS]; /* swizzled "down" size of number of chunks in each dimension */
+ hsize_t swizzled_max_down_chunks[H5O_LAYOUT_NDIMS]; /* swizzled max "down" size of number of chunks in each dimension */
+} H5O_layout_chunk_earray_t;
+
+typedef struct H5O_layout_chunk_bt2_t {
+ /* Creation parameters for v2 B-tree data structure */
+ struct {
+ uint32_t node_size; /* Size of each node (in bytes) */
+ uint8_t split_percent; /* % full to split nodes */
+ uint8_t merge_percent; /* % full to merge nodes */
+ } cparam;
+} H5O_layout_chunk_bt2_t;
+
+typedef struct H5O_layout_chunk_t {
+ H5D_chunk_index_t idx_type; /* Type of chunk index */
+ uint8_t flags; /* Chunk layout flags */
+ unsigned ndims; /* Num dimensions in chunk */
+ uint32_t dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in elements */
+ unsigned enc_bytes_per_dim; /* Encoded # of bytes for storing each chunk dimension */
+ uint32_t size; /* Size of chunk in bytes */
+ hsize_t nchunks; /* Number of chunks in dataset */
+ hsize_t max_nchunks; /* Max. number of chunks in dataset */
+ hsize_t chunks[H5O_LAYOUT_NDIMS]; /* # of chunks in each dataset dimension */
+ hsize_t max_chunks[H5O_LAYOUT_NDIMS]; /* # of chunks in each dataset's max. dimension */
+ hsize_t down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of chunks in each dimension */
+ hsize_t max_down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of chunks in each max dim */
+ union {
+ H5O_layout_chunk_farray_t farray; /* Information for fixed array index */
+ H5O_layout_chunk_earray_t earray; /* Information for extensible array index */
+ H5O_layout_chunk_bt2_t btree2; /* Information for v2 B-tree index */
+ } u;
+} H5O_layout_chunk_t;
+
+typedef struct H5O_layout_t {
+ H5D_layout_t type; /* Type of layout */
+ unsigned version; /* Version of message */
+ const struct H5D_layout_ops_t *ops; /* Pointer to data layout I/O operations */
+ union {
+ H5O_layout_chunk_t chunk; /* Information for chunked layout */
+ } u;
+ H5O_storage_t storage; /* Information for storing dataset elements */
+} H5O_layout_t;
+
+#ifdef H5O_ENABLE_BOGUS
+/*
+ * "Bogus" Message.
+ * (Data structure in memory)
+ */
+#define H5O_BOGUS_VALUE 0xdeadbeef
+typedef struct H5O_bogus_t {
+ unsigned u; /* Hold the bogus info */
+} H5O_bogus_t;
+#endif /* H5O_ENABLE_BOGUS */
+
+/*
+ * Group info message.
+ * (Contains constant information about a group)
+ * (Data structure in memory)
+ * (if the fields in this struct are changed, remember to change the default
+ * group info structure in src/H5Gprivate.h - QAK)
+ */
+typedef struct H5O_ginfo_t {
+ /* "Old" format group info (not stored) */
+ uint32_t lheap_size_hint; /* Local heap size hint */
+
+ /* "New" format group info (stored) */
+
+ /* (storage management info) */
+ hbool_t store_link_phase_change;/* Whether to store the link phase change values */
+ uint16_t max_compact; /* Maximum # of compact links */
+ uint16_t min_dense; /* Minimum # of "dense" links */
+
+ /* (initial object header size info) */
+ hbool_t store_est_entry_info; /* Whether to store the est. entry values */
+ uint16_t est_num_entries; /* Estimated # of entries in group */
+ uint16_t est_name_len; /* Estimated length of entry name */
+} H5O_ginfo_t;
+
+/*
+ * Filter pipeline message.
+ * (Data structure in memory)
+ */
+
+/* The initial version of the format */
+#define H5O_PLINE_VERSION_1 1
+
+/* This version encodes the message fields more efficiently */
+/* (Drops the reserved bytes, doesn't align the name and doesn't encode the
+ * filter name at all if it's a filter provided by the library)
+ */
+#define H5O_PLINE_VERSION_2 2
+
+/* The latest version of the format. Look through the 'encode' and 'size'
+ * callbacks for places to change when updating this. */
+#define H5O_PLINE_VERSION_LATEST H5O_PLINE_VERSION_2
+
+typedef struct H5O_pline_t {
+ H5O_shared_t sh_loc; /* Shared message info (must be first) */
+
+ unsigned version; /* Encoding version number */
+ size_t nalloc; /*num elements in `filter' array */
+ size_t nused; /*num filters defined */
+ H5Z_filter_info_t *filter; /*array of filters */
+} H5O_pline_t;
+
+/*
+ * Object name message.
+ * (Data structure in memory)
+ */
+
+typedef struct H5O_name_t {
+ char *s; /*ptr to malloc'd memory */
+} H5O_name_t;
+
+/*
+ * Shared message table message
+ * Information about file-wide shared message table, stored in superblock
+ * extension
+ * (Data structure in memory)
+ */
+typedef struct H5O_shmesg_table_t {
+ haddr_t addr; /*file address of SOHM table */
+ unsigned version; /*SOHM table version number */
+ unsigned nindexes; /*number of indexes in the table */
+} H5O_shmesg_table_t;
+
+/*
+ * Object header continuation message.
+ * (Data structure in memory)
+ */
+
+typedef struct H5O_cont_t {
+ haddr_t addr; /*address of continuation block */
+ size_t size; /*size of continuation block */
+
+ /* the following field(s) do not appear on disk */
+ unsigned chunkno; /*chunk this mesg refers to */
+} H5O_cont_t;
+
+/*
+ * Symbol table message.
+ * (Data structure in memory)
+ */
+typedef struct H5O_stab_t {
+ haddr_t btree_addr; /*address of B-tree */
+ haddr_t heap_addr; /*address of name heap */
+} H5O_stab_t;
+
+/*
+ * v1 B-tree 'K' value message
+ * Information about file-wide non-default v1 B-tree 'K' values, stored in
+ * superblock extension
+ * (Data structure in memory)
+ */
+typedef struct H5O_btreek_t {
+ unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree internal node 'K' values */
+ unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */
+} H5O_btreek_t;
+
+/*
+ * Driver info message
+ * Information about driver info, stored in superblock extension
+ * (Data structure in memory)
+ */
+typedef struct H5O_drvinfo_t {
+/* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+ char name[9]; /* Driver name */
+ size_t len; /* Length of encoded buffer */
+ uint8_t *buf; /* Buffer for encoded info */
+} H5O_drvinfo_t;
+
+/*
+ * Attribute Info Message.
+ * (Contains dynamic information about attributes on an object)
+ * (Data structure in memory)
+ */
+typedef struct H5O_ainfo_t {
+ /* Creation order info */
+ hbool_t track_corder; /* Are creation order values tracked on attributes? */
+ hbool_t index_corder; /* Are creation order values indexed on attributes? */
+ H5O_msg_crt_idx_t max_crt_idx; /* Maximum attribute creation index used */
+ haddr_t corder_bt2_addr; /* Address of v2 B-tree for indexing creation order values of "dense" attributes */
+
+ /* Storage management info */
+ hsize_t nattrs; /* Number of attributes on the object */
+ haddr_t fheap_addr; /* Address of fractal heap for storing "dense" attributes */
+ haddr_t name_bt2_addr; /* Address of v2 B-tree for indexing names of "dense" attributes */
+} H5O_ainfo_t;
+
+/*
+ * Reference Count Message.
+ * (Data structure in memory)
+ */
+typedef uint32_t H5O_refcount_t; /* Contains # of links to object, if >1 */
+
+/*
+ * "Unknown" Message.
+ * (Data structure in memory)
+ */
+typedef unsigned H5O_unknown_t; /* Original message type ID */
+
+/*
+ * File space info Message.
+ * Contains file space management info and
+ * addresses of free space managers for file memory
+ * (Data structure in memory)
+ */
+typedef struct H5O_fsinfo_t {
+ H5F_fspace_strategy_t strategy; /* File space strategy */
+ hbool_t persist; /* Persisting free-space or not */
+ hsize_t threshold; /* Free-space section threshold */
+ hsize_t page_size; /* For paged aggregation: file space page size */
+ size_t pgend_meta_thres; /* For paged aggregation: page end metadata threshold */
+ haddr_t eoa_pre_fsm_fsalloc; /* For paged aggregation: the eoa before free-space headers & sinfo */
+ haddr_t fs_addr[H5F_MEM_PAGE_NTYPES - 1]; /* 13 addresses of free-space managers */
+ /* For non-paged aggregation: only 6 addresses are used */
+ hbool_t mapped; /* Not stored */
+ /* Indicate the message is mapped from version 0 to version 1 */
+} H5O_fsinfo_t;
+
+/*
+ * Metadata Cache Image Message.
+ * Contains base address and length of the metadata cache image.
+ * (Data structure in memory)
+ */
+typedef struct H5O_mdci_t {
+ haddr_t addr; /* address of MDC image block */
+ hsize_t size; /* size of MDC image block */
+} H5O_mdci_t;
+
+/* Typedef for "application" iteration operations */
+typedef herr_t (*H5O_operator_t)(const void *mesg/*in*/, unsigned idx,
+ void *operator_data/*in,out*/);
+
+/* Typedef for "internal library" iteration operations */
+typedef herr_t (*H5O_lib_operator_t)(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned sequence, unsigned *oh_modified/*out*/, void *operator_data/*in,out*/);
+
+/* Some syntactic sugar to make the compiler happy with two different kinds of iterator callbacks */
+typedef enum H5O_mesg_operator_type_t {
+ H5O_MESG_OP_APP, /* Application callback */
+ H5O_MESG_OP_LIB /* Library internal callback */
+} H5O_mesg_operator_type_t;
+
+#define H5O_MODIFY_CONDENSE 0x01
+#define H5O_MODIFY 0x02
+
+typedef struct {
+ H5O_mesg_operator_type_t op_type;
+ union {
+ H5O_operator_t app_op; /* Application callback for each message */
+ H5O_lib_operator_t lib_op; /* Library internal callback for each message */
+ } u;
+} H5O_mesg_operator_t;
+
+
+/* Typedef for abstract object creation */
+typedef struct {
+ H5O_type_t obj_type; /* Type of object to create */
+ void *crt_info; /* Information for object creation callback */
+ void *new_obj; /* Pointer to new object created */
+} H5O_obj_create_t;
+
+/* Forward declarations for prototype arguments */
+struct H5P_genplist_t;
+
+/* Object header routines */
+H5_DLL herr_t H5O_init(void);
+H5_DLL herr_t H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint,
+ size_t initial_rc, hid_t ocpl_id, H5O_loc_t *loc/*out*/);
+H5_DLL herr_t H5O_open(H5O_loc_t *loc);
+H5_DLL herr_t H5O_close(H5O_loc_t *loc, hbool_t *file_closed/*out*/);
+H5_DLL int H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id);
+H5_DLL H5O_t *H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id,
+ unsigned prot_flags, hbool_t pin_all_chunks);
+H5_DLL H5O_t *H5O_pin(const H5O_loc_t *loc, hid_t dxpl_id);
+H5_DLL herr_t H5O_unpin(H5O_t *oh);
+H5_DLL herr_t H5O_dec_rc_by_loc(const H5O_loc_t *loc, hid_t dxpl_id);
+H5_DLL herr_t H5O_unprotect(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh,
+ unsigned oh_flags);
+H5_DLL herr_t H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id);
+H5_DLL herr_t H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ hbool_t force);
+#ifdef H5O_ENABLE_BOGUS
+H5_DLL herr_t H5O_bogus_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned mesg_id, unsigned mesg_flags);
+#endif /* H5O_ENABLE_BOGUS */
+H5_DLL herr_t H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr);
+H5_DLL herr_t H5O_get_hdr_info(const H5O_loc_t *oloc, hid_t dxpl_id, H5O_hdr_info_t *hdr);
+H5_DLL herr_t H5O_get_info(const H5O_loc_t *oloc, hid_t dxpl_id, hbool_t want_ih_info,
+ H5O_info_t *oinfo);
+H5_DLL herr_t H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id);
+H5_DLL herr_t H5O_get_create_plist(const H5O_loc_t *loc, hid_t dxpl_id, struct H5P_genplist_t *oc_plist);
+H5_DLL hid_t H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref);
+H5_DLL herr_t H5O_get_nlinks(const H5O_loc_t *loc, hid_t dxpl_id, hsize_t *nlinks);
+H5_DLL void *H5O_obj_create(H5F_t *f, H5O_type_t obj_type, void *crt_info, H5G_loc_t *obj_loc, hid_t dxpl_id);
+H5_DLL haddr_t H5O_get_oh_addr(const H5O_t *oh);
+H5_DLL herr_t H5O_get_rc_and_type(const H5O_loc_t *oloc, hid_t dxpl_id, unsigned *rc, H5O_type_t *otype);
+H5_DLL H5AC_proxy_entry_t *H5O_get_proxy(const H5O_t *oh);
+
+/* Object header message routines */
+H5_DLL herr_t H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags,
+ unsigned update_flags, void *mesg, hid_t dxpl_id);
+H5_DLL herr_t H5O_msg_append_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id,
+ unsigned mesg_flags, unsigned update_flags, void *mesg);
+H5_DLL herr_t H5O_msg_write(const H5O_loc_t *loc, unsigned type_id,
+ unsigned mesg_flags, unsigned update_flags, void *mesg, hid_t dxpl_id);
+H5_DLL herr_t H5O_msg_write_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ unsigned type_id, unsigned mesg_flags, unsigned update_flags, void *mesg);
+H5_DLL void *H5O_msg_read(const H5O_loc_t *loc, unsigned type_id, void *mesg,
+ hid_t dxpl_id);
+H5_DLL void *H5O_msg_read_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id,
+ void *mesg);
+H5_DLL herr_t H5O_msg_reset(unsigned type_id, void *native);
+H5_DLL void *H5O_msg_free(unsigned type_id, void *mesg);
+H5_DLL void *H5O_msg_copy(unsigned type_id, const void *mesg, void *dst);
+H5_DLL int H5O_msg_count(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id);
+H5_DLL htri_t H5O_msg_exists(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id);
+H5_DLL htri_t H5O_msg_exists_oh(const H5O_t *oh, unsigned type_id);
+H5_DLL herr_t H5O_msg_remove(const H5O_loc_t *loc, unsigned type_id, int sequence,
+ hbool_t adj_link, hid_t dxpl_id);
+H5_DLL herr_t H5O_msg_remove_op(const H5O_loc_t *loc, unsigned type_id, int sequence,
+ H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id);
+H5_DLL herr_t H5O_msg_iterate(const H5O_loc_t *loc, unsigned type_id,
+ const H5O_mesg_operator_t *op, void *op_data, hid_t dxpl_id);
+H5_DLL size_t H5O_msg_raw_size(const H5F_t *f, unsigned type_id,
+ hbool_t disable_shared, const void *mesg);
+H5_DLL size_t H5O_msg_size_f(const H5F_t *f, hid_t ocpl_id, unsigned type_id,
+ const void *mesg, size_t extra_raw);
+H5_DLL size_t H5O_msg_size_oh(const H5F_t *f, const H5O_t *oh, unsigned type_id,
+ const void *mesg, size_t extra_raw);
+H5_DLL htri_t H5O_msg_is_shared(unsigned type_id, const void *mesg);
+H5_DLL htri_t H5O_msg_can_share(unsigned type_id, const void *mesg);
+H5_DLL htri_t H5O_msg_can_share_in_ohdr(unsigned type_id);
+H5_DLL herr_t H5O_msg_set_share(unsigned type_id, const H5O_shared_t *share,
+ void *mesg);
+H5_DLL herr_t H5O_msg_reset_share(unsigned type_id, void *mesg);
+H5_DLL herr_t H5O_msg_get_crt_index(unsigned type_id, const void *mesg,
+ H5O_msg_crt_idx_t *crt_idx);
+H5_DLL herr_t H5O_msg_encode(H5F_t *f, unsigned type_id, hbool_t disable_shared,
+ unsigned char *buf, const void *obj);
+H5_DLL void* H5O_msg_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned type_id, const unsigned char *buf);
+H5_DLL herr_t H5O_msg_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned type_id, void *mesg);
+H5_DLL herr_t H5O_msg_get_flags(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id, uint8_t *flags);
+
+/* Object metadata flush/refresh routines */
+H5_DLL herr_t H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hid_t dxpl_id, hbool_t start_swmr);
+
+/* Object copying routines */
+H5_DLL herr_t H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
+ hid_t dxpl_id, H5O_copy_t *cpy_info, hbool_t inc_depth,
+ H5O_type_t *obj_type, void **udata);
+H5_DLL herr_t H5O_copy_expand_ref(H5F_t *file_src, void *_src_ref, hid_t dxpl_id,
+ H5F_t *file_dst, void *_dst_ref, size_t ref_count, H5R_type_t ref_type,
+ H5O_copy_t *cpy_info);
+
+/* Debugging routines */
+H5_DLL herr_t H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth);
+H5_DLL herr_t H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent,
+ int fwidth);
+
+/* These functions operate on object locations */
+H5_DLL herr_t H5O_loc_reset(H5O_loc_t *loc);
+H5_DLL herr_t H5O_loc_copy(H5O_loc_t *dst, H5O_loc_t *src, H5_copy_depth_t depth);
+H5_DLL herr_t H5O_loc_hold_file(H5O_loc_t *loc);
+H5_DLL herr_t H5O_loc_free(H5O_loc_t *loc);
+H5_DLL H5O_loc_t *H5O_get_loc(hid_t id);
+
+/* EFL operators */
+H5_DLL hsize_t H5O_efl_total_size(H5O_efl_t *efl);
+
+/* Fill value operators */
+H5_DLL herr_t H5O_fill_reset_dyn(H5O_fill_t *fill);
+H5_DLL herr_t H5O_fill_convert(H5O_fill_t *fill, H5T_t *type, hbool_t *fill_changed, hid_t dxpl_id);
+H5_DLL herr_t H5O_fill_set_latest_version(H5O_fill_t *fill);
+
+/* Link operators */
+H5_DLL herr_t H5O_link_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ void *_mesg);
+
+/* Filter pipeline operators */
+H5_DLL herr_t H5O_pline_set_latest_version(H5O_pline_t *pline);
+
+/* Shared message operators */
+H5_DLL herr_t H5O_set_shared(H5O_shared_t *dst, const H5O_shared_t *src);
+
+#endif /* _H5Oprivate_H */
+
diff --git a/src/H5Opublic.h b/src/H5Opublic.h
new file mode 100644
index 0000000..8d6dda4
--- /dev/null
+++ b/src/H5Opublic.h
@@ -0,0 +1,215 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Opublic.h
+ * Aug 5 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Public declarations for the H5O (object header)
+ * package.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Opublic_H
+#define _H5Opublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h" /* Generic Functions */
+#include "H5Ipublic.h" /* IDs */
+#include "H5Lpublic.h" /* Links */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Flags for object copy (H5Ocopy) */
+#define H5O_COPY_SHALLOW_HIERARCHY_FLAG (0x0001u) /* Copy only immediate members */
+#define H5O_COPY_EXPAND_SOFT_LINK_FLAG (0x0002u) /* Expand soft links into new objects */
+#define H5O_COPY_EXPAND_EXT_LINK_FLAG (0x0004u) /* Expand external links into new objects */
+#define H5O_COPY_EXPAND_REFERENCE_FLAG (0x0008u) /* Copy objects that are pointed by references */
+#define H5O_COPY_WITHOUT_ATTR_FLAG (0x0010u) /* Copy object without copying attributes */
+#define H5O_COPY_PRESERVE_NULL_FLAG (0x0020u) /* Copy NULL messages (empty space) */
+#define H5O_COPY_MERGE_COMMITTED_DTYPE_FLAG (0x0040u) /* Merge committed datatypes in dest file */
+#define H5O_COPY_ALL (0x007Fu) /* All object copying flags (for internal checking) */
+
+/* Flags for shared message indexes.
+ * Pass these flags in using the mesg_type_flags parameter in
+ * H5P_set_shared_mesg_index.
+ * (Developers: These flags correspond to object header message type IDs,
+ * but we need to assign each kind of message to a different bit so that
+ * one index can hold multiple types.)
+ */
+#define H5O_SHMESG_NONE_FLAG 0x0000 /* No shared messages */
+#define H5O_SHMESG_SDSPACE_FLAG ((unsigned)1 << 0x0001) /* Simple Dataspace Message. */
+#define H5O_SHMESG_DTYPE_FLAG ((unsigned)1 << 0x0003) /* Datatype Message. */
+#define H5O_SHMESG_FILL_FLAG ((unsigned)1 << 0x0005) /* Fill Value Message. */
+#define H5O_SHMESG_PLINE_FLAG ((unsigned)1 << 0x000b) /* Filter pipeline message. */
+#define H5O_SHMESG_ATTR_FLAG ((unsigned)1 << 0x000c) /* Attribute Message. */
+#define H5O_SHMESG_ALL_FLAG (H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_FILL_FLAG | H5O_SHMESG_PLINE_FLAG | H5O_SHMESG_ATTR_FLAG)
+
+/* Object header status flag definitions */
+#define H5O_HDR_CHUNK0_SIZE 0x03 /* 2-bit field indicating # of bytes to store the size of chunk 0's data */
+#define H5O_HDR_ATTR_CRT_ORDER_TRACKED 0x04 /* Attribute creation order is tracked */
+#define H5O_HDR_ATTR_CRT_ORDER_INDEXED 0x08 /* Attribute creation order has index */
+#define H5O_HDR_ATTR_STORE_PHASE_CHANGE 0x10 /* Non-default attribute storage phase change values stored */
+#define H5O_HDR_STORE_TIMES 0x20 /* Store access, modification, change & birth times for object */
+#define H5O_HDR_ALL_FLAGS (H5O_HDR_CHUNK0_SIZE | H5O_HDR_ATTR_CRT_ORDER_TRACKED | H5O_HDR_ATTR_CRT_ORDER_INDEXED | H5O_HDR_ATTR_STORE_PHASE_CHANGE | H5O_HDR_STORE_TIMES)
+
+/* Maximum shared message values. Number of indexes is 8 to allow room to add
+ * new types of messages.
+ */
+#define H5O_SHMESG_MAX_NINDEXES 8
+#define H5O_SHMESG_MAX_LIST_SIZE 5000
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/* Types of objects in file */
+typedef enum H5O_type_t {
+ H5O_TYPE_UNKNOWN = -1, /* Unknown object type */
+ H5O_TYPE_GROUP, /* Object is a group */
+ H5O_TYPE_DATASET, /* Object is a dataset */
+ H5O_TYPE_NAMED_DATATYPE, /* Object is a named data type */
+ H5O_TYPE_NTYPES /* Number of different object types (must be last!) */
+} H5O_type_t;
+
+/* Information struct for object header metadata (for H5Oget_info/H5Oget_info_by_name/H5Oget_info_by_idx) */
+typedef struct H5O_hdr_info_t {
+ unsigned version; /* Version number of header format in file */
+ unsigned nmesgs; /* Number of object header messages */
+ unsigned nchunks; /* Number of object header chunks */
+ unsigned flags; /* Object header status flags */
+ struct {
+ hsize_t total; /* Total space for storing object header in file */
+ hsize_t meta; /* Space within header for object header metadata information */
+ hsize_t mesg; /* Space within header for actual message information */
+ hsize_t free; /* Free space within object header */
+ } space;
+ struct {
+ uint64_t present; /* Flags to indicate presence of message type in header */
+ uint64_t shared; /* Flags to indicate message type is shared in header */
+ } mesg;
+} H5O_hdr_info_t;
+
+/* Information struct for object (for H5Oget_info/H5Oget_info_by_name/H5Oget_info_by_idx) */
+typedef struct H5O_info_t {
+ unsigned long fileno; /* File number that object is located in */
+ haddr_t addr; /* Object address in file */
+ H5O_type_t type; /* Basic object type (group, dataset, etc.) */
+ unsigned rc; /* Reference count of object */
+ time_t atime; /* Access time */
+ time_t mtime; /* Modification time */
+ time_t ctime; /* Change time */
+ time_t btime; /* Birth time */
+ hsize_t num_attrs; /* # of attributes attached to object */
+ H5O_hdr_info_t hdr; /* Object header information */
+ /* Extra metadata storage for obj & attributes */
+ struct {
+ H5_ih_info_t obj; /* v1/v2 B-tree & local/fractal heap for groups, B-tree for chunked datasets */
+ H5_ih_info_t attr; /* v2 B-tree & heap for attributes */
+ } meta_size;
+} H5O_info_t;
+
+/* Typedef for message creation indexes */
+typedef uint32_t H5O_msg_crt_idx_t;
+
+/* Prototype for H5Ovisit/H5Ovisit_by_name() operator */
+typedef herr_t (*H5O_iterate_t)(hid_t obj, const char *name, const H5O_info_t *info,
+ void *op_data);
+
+typedef enum H5O_mcdt_search_ret_t {
+ H5O_MCDT_SEARCH_ERROR = -1, /* Abort H5Ocopy */
+ H5O_MCDT_SEARCH_CONT, /* Continue the global search of all committed datatypes in the destination file */
+ H5O_MCDT_SEARCH_STOP /* Stop the search, but continue copying. The committed datatype will be copied but not merged. */
+} H5O_mcdt_search_ret_t;
+
+/* Callback to invoke when completing the search for a matching committed datatype from the committed dtype list */
+typedef H5O_mcdt_search_ret_t (*H5O_mcdt_search_cb_t)(void *op_data);
+
+/********************/
+/* Public Variables */
+/********************/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+H5_DLL hid_t H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id);
+H5_DLL hid_t H5Oopen_by_addr(hid_t loc_id, haddr_t addr);
+H5_DLL hid_t H5Oopen_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id);
+H5_DLL htri_t H5Oexists_by_name(hid_t loc_id, const char *name, hid_t lapl_id);
+H5_DLL herr_t H5Oget_info(hid_t loc_id, H5O_info_t *oinfo);
+H5_DLL herr_t H5Oget_info_by_name(hid_t loc_id, const char *name, H5O_info_t *oinfo,
+ hid_t lapl_id);
+H5_DLL herr_t H5Oget_info_by_idx(hid_t loc_id, const char *group_name,
+ H5_index_t idx_type, H5_iter_order_t order, hsize_t n, H5O_info_t *oinfo,
+ hid_t lapl_id);
+H5_DLL herr_t H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name,
+ hid_t lcpl_id, hid_t lapl_id);
+H5_DLL herr_t H5Oincr_refcount(hid_t object_id);
+H5_DLL herr_t H5Odecr_refcount(hid_t object_id);
+H5_DLL herr_t H5Ocopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
+ const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id);
+H5_DLL herr_t H5Oset_comment(hid_t obj_id, const char *comment);
+H5_DLL herr_t H5Oset_comment_by_name(hid_t loc_id, const char *name,
+ const char *comment, hid_t lapl_id);
+H5_DLL ssize_t H5Oget_comment(hid_t obj_id, char *comment, size_t bufsize);
+H5_DLL ssize_t H5Oget_comment_by_name(hid_t loc_id, const char *name,
+ char *comment, size_t bufsize, hid_t lapl_id);
+H5_DLL herr_t H5Ovisit(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order,
+ H5O_iterate_t op, void *op_data);
+H5_DLL herr_t H5Ovisit_by_name(hid_t loc_id, const char *obj_name,
+ H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op,
+ void *op_data, hid_t lapl_id);
+H5_DLL herr_t H5Oclose(hid_t object_id);
+H5_DLL herr_t H5Oflush(hid_t obj_id);
+H5_DLL herr_t H5Orefresh(hid_t oid);
+H5_DLL herr_t H5Odisable_mdc_flushes(hid_t object_id);
+H5_DLL herr_t H5Oenable_mdc_flushes(hid_t object_id);
+H5_DLL herr_t H5Oare_mdc_flushes_disabled(hid_t object_id, hbool_t *are_disabled);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+/* Typedefs */
+
+/* A struct that's part of the H5G_stat_t structure (deprecated) */
+typedef struct H5O_stat_t {
+ hsize_t size; /* Total size of object header in file */
+ hsize_t free; /* Free space within object header */
+ unsigned nmesgs; /* Number of object header messages */
+ unsigned nchunks; /* Number of object header chunks */
+} H5O_stat_t;
+
+/* Function prototypes */
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Opublic_H */
+
diff --git a/src/H5Orefcount.c b/src/H5Orefcount.c
new file mode 100644
index 0000000..af68417
--- /dev/null
+++ b/src/H5Orefcount.c
@@ -0,0 +1,324 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Orefcount.c
+ * Mar 10 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object ref. count messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_refcount_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_refcount_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_refcount_copy(const void *_mesg, void *_dest);
+static size_t H5O_refcount_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_refcount_free(void *_mesg);
+static herr_t H5O_refcount_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata);
+static herr_t H5O_refcount_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_REFCOUNT[1] = {{
+ H5O_REFCOUNT_ID, /*message id number */
+ "refcount", /*message name for debugging */
+ sizeof(H5O_refcount_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_refcount_decode, /*decode message */
+ H5O_refcount_encode, /*encode message */
+ H5O_refcount_copy, /*copy the native value */
+ H5O_refcount_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_refcount_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ H5O_refcount_pre_copy_file, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_refcount_debug /*debug the message */
+}};
+
+/* Current version of ref. count information */
+#define H5O_REFCOUNT_VERSION 0
+
+/* Declare a free list to manage the H5O_refcount_t struct */
+H5FL_DEFINE_STATIC(H5O_refcount_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_decode
+ *
+ * Purpose: Decode a message and return a pointer to a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native form.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_refcount_decode(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_refcount_t *refcount = NULL; /* Reference count */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_REFCOUNT_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (refcount = H5FL_MALLOC(H5O_refcount_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get ref. count for object */
+ UINT32DECODE(p, *refcount)
+
+ /* Set return value */
+ ret_value = refcount;
+
+done:
+ if(ret_value == NULL && refcount != NULL)
+ refcount = H5FL_FREE(H5O_refcount_t, refcount);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(refcount);
+
+ /* Message version */
+ *p++ = H5O_REFCOUNT_VERSION;
+
+ /* Object's ref. count */
+ UINT32ENCODE(p, *refcount);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_refcount_copy(const void *_mesg, void *_dest)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg;
+ H5O_refcount_t *dest = (H5O_refcount_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(refcount);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_refcount_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *refcount;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_refcount_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared,
+ const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = 1 /* Version */
+ + 4; /* Ref. count */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 10, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_refcount_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 10, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src,
+ hbool_t *deleted, const H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(deleted);
+ HDassert(cpy_info);
+
+ /* Always delete this message when copying objects between files. Let
+ * the copy routine set the correct ref. count.
+ */
+ *deleted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(refcount);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of links:", (unsigned)*refcount);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_debug() */
+
diff --git a/src/H5Osdspace.c b/src/H5Osdspace.c
new file mode 100644
index 0000000..3fe5652
--- /dev/null
+++ b/src/H5Osdspace.c
@@ -0,0 +1,539 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+#define H5S_FRIEND /*prevent warning from including H5Spkg.h */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Gprivate.h" /* Groups */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Spkg.h" /* Dataspaces */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_sdspace_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_sdspace_encode(H5F_t *f, uint8_t *p, const void *_mesg);
+static void *H5O_sdspace_copy(const void *_mesg, void *_dest);
+static size_t H5O_sdspace_size(const H5F_t *f, const void *_mesg);
+static herr_t H5O_sdspace_reset(void *_mesg);
+static herr_t H5O_sdspace_free(void *_mesg);
+static herr_t H5O_sdspace_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *_udata);
+static herr_t H5O_sdspace_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* Set up & include shared message "interface" info */
+#define H5O_SHARED_TYPE H5O_MSG_SDSPACE
+#define H5O_SHARED_DECODE H5O_sdspace_shared_decode
+#define H5O_SHARED_DECODE_REAL H5O_sdspace_decode
+#define H5O_SHARED_ENCODE H5O_sdspace_shared_encode
+#define H5O_SHARED_ENCODE_REAL H5O_sdspace_encode
+#define H5O_SHARED_SIZE H5O_sdspace_shared_size
+#define H5O_SHARED_SIZE_REAL H5O_sdspace_size
+#define H5O_SHARED_DELETE H5O_sdspace_shared_delete
+#undef H5O_SHARED_DELETE_REAL
+#define H5O_SHARED_LINK H5O_sdspace_shared_link
+#undef H5O_SHARED_LINK_REAL
+#define H5O_SHARED_COPY_FILE H5O_sdspace_shared_copy_file
+#undef H5O_SHARED_COPY_FILE_REAL
+#define H5O_SHARED_POST_COPY_FILE H5O_sdspace_shared_post_copy_file
+#undef H5O_SHARED_POST_COPY_FILE_REAL
+#undef H5O_SHARED_POST_COPY_FILE_UPD
+#define H5O_SHARED_DEBUG H5O_sdspace_shared_debug
+#define H5O_SHARED_DEBUG_REAL H5O_sdspace_debug
+#include "H5Oshared.h" /* Shared Object Header Message Callbacks */
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_SDSPACE[1] = {{
+ H5O_SDSPACE_ID, /* message id number */
+ "dataspace", /* message name for debugging */
+ sizeof(H5S_extent_t), /* native message size */
+ H5O_SHARE_IS_SHARABLE|H5O_SHARE_IN_OHDR, /* messages are sharable? */
+ H5O_sdspace_shared_decode, /* decode message */
+ H5O_sdspace_shared_encode, /* encode message */
+ H5O_sdspace_copy, /* copy the native value */
+ H5O_sdspace_shared_size, /* size of symbol table entry */
+ H5O_sdspace_reset, /* default reset method */
+ H5O_sdspace_free, /* free method */
+ H5O_sdspace_shared_delete, /* file delete method */
+ H5O_sdspace_shared_link, /* link method */
+ NULL, /* set share method */
+ NULL, /*can share method */
+ H5O_sdspace_pre_copy_file, /* pre copy native value to file */
+ H5O_sdspace_shared_copy_file,/* copy native value to file */
+ H5O_sdspace_shared_post_copy_file,/* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_sdspace_shared_debug /* debug the message */
+}};
+
+/* Declare external the free list for H5S_extent_t's */
+H5FL_EXTERN(H5S_extent_t);
+
+/* Declare external the free list for hsize_t arrays */
+H5FL_ARR_EXTERN(hsize_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_sdspace_decode
+ PURPOSE
+ Decode a simple dimensionality message and return a pointer to a memory
+ struct with the decoded information
+ USAGE
+ void *H5O_sdspace_decode(f, dxpl_id, mesg_flags, p)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ hid_t dxpl_id; IN: DXPL for any I/O
+ unsigned mesg_flags; IN: Message flags to influence decoding
+ const uint8 *p; IN: the raw information buffer
+ RETURNS
+ Pointer to the new message in native order on success, NULL on failure
+ DESCRIPTION
+ This function decodes the "raw" disk form of a simple dimensionality
+ message into a struct in memory native format. The struct is allocated
+ within this function using malloc() and is returned to the caller.
+--------------------------------------------------------------------------*/
+static void *
+H5O_sdspace_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5S_extent_t *sdim = NULL;/* New extent dimensionality structure */
+ unsigned flags, version;
+ unsigned i; /* Local counting variable */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(NULL == (sdim = H5FL_CALLOC(H5S_extent_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, NULL, "dataspace structure allocation failed")
+
+ /* Check version */
+ version = *p++;
+ if(version < H5O_SDSPACE_VERSION_1 || version > H5O_SDSPACE_VERSION_2)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "wrong version number in dataspace message")
+ sdim->version = version;
+
+ /* Get rank */
+ sdim->rank = *p++;
+ if(sdim->rank > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "simple dataspace dimensionality is too large")
+
+ /* Get dataspace flags for later */
+ flags = *p++;
+
+ /* Get or determine the type of the extent */
+ if(version >= H5O_SDSPACE_VERSION_2)
+ sdim->type = (H5S_class_t)*p++;
+ else {
+ /* Set the dataspace type to be simple or scalar as appropriate */
+ if(sdim->rank > 0)
+ sdim->type = H5S_SIMPLE;
+ else
+ sdim->type = H5S_SCALAR;
+
+ /* Increment past reserved byte */
+ p++;
+ } /* end else */
+ HDassert(sdim->type != H5S_NULL || sdim->version >= H5O_SDSPACE_VERSION_2);
+
+ /* Only Version 1 has these reserved bytes */
+ if(version == H5O_SDSPACE_VERSION_1)
+ p += 4; /*reserved*/
+
+ /* Decode dimension sizes */
+ if(sdim->rank > 0) {
+ if(NULL == (sdim->size = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)sdim->rank)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ for(i = 0; i < sdim->rank; i++)
+ H5F_DECODE_LENGTH(f, p, sdim->size[i]);
+
+ if(flags & H5S_VALID_MAX) {
+ if(NULL == (sdim->max = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)sdim->rank)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ for(i = 0; i < sdim->rank; i++)
+ H5F_DECODE_LENGTH (f, p, sdim->max[i]);
+ } /* end if */
+ } /* end if */
+
+ /* Compute the number of elements in the extent */
+ if(sdim->type == H5S_NULL)
+ sdim->nelem = 0;
+ else {
+ for(i = 0, sdim->nelem = 1; i < sdim->rank; i++)
+ sdim->nelem *= sdim->size[i];
+ } /* end else */
+
+ /* Set return value */
+ ret_value = (void*)sdim; /*success*/
+
+done:
+ if(!ret_value && sdim) {
+ H5S_extent_release(sdim);
+ sdim = H5FL_FREE(H5S_extent_t, sdim);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_sdspace_decode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_sdspace_encode
+ PURPOSE
+ Encode a simple dimensionality message
+ USAGE
+ herr_t H5O_sdspace_encode(f, raw_size, p, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ size_t raw_size; IN: size of the raw information buffer
+ const uint8 *p; IN: the raw information buffer
+ const void *mesg; IN: Pointer to the extent dimensionality struct
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function encodes the native memory form of the simple
+ dimensionality message in the "raw" disk form.
+
+ MODIFICATIONS
+ Robb Matzke, 1998-04-09
+ The current and maximum dimensions are now H5F_SIZEOF_SIZET bytes
+ instead of just four bytes.
+
+ Robb Matzke, 1998-07-20
+ Added a version number and reformatted the message for aligment.
+
+ Raymond Lu
+ April 8, 2004
+ Added the type of dataspace into this header message using a reserved
+ byte.
+
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_sdspace_encode(H5F_t *f, uint8_t *p, const void *_mesg)
+{
+ const H5S_extent_t *sdim = (const H5S_extent_t *)_mesg;
+ unsigned flags = 0;
+ unsigned u; /* Local counting variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(sdim);
+
+ /* Version */
+ HDassert(sdim->version > 0);
+ HDassert(sdim->type != H5S_NULL || sdim->version >= H5O_SDSPACE_VERSION_2);
+ *p++ = (uint8_t)sdim->version;
+
+ /* Rank */
+ *p++ = (uint8_t)sdim->rank;
+
+ /* Flags */
+ if(sdim->max)
+ flags |= H5S_VALID_MAX;
+ *p++ = (uint8_t)flags;
+
+ /* Dataspace type */
+ if(sdim->version > H5O_SDSPACE_VERSION_1)
+ *p++ = sdim->type;
+ else {
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ *p++ = 0; /*reserved*/
+ } /* end else */
+
+ /* Current & maximum dimensions */
+ if(sdim->rank > 0) {
+ for(u = 0; u < sdim->rank; u++)
+ H5F_ENCODE_LENGTH(f, p, sdim->size[u]);
+ if(flags & H5S_VALID_MAX) {
+ for(u = 0; u < sdim->rank; u++)
+ H5F_ENCODE_LENGTH(f, p, sdim->max[u]);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_sdspace_encode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_sdspace_copy
+ PURPOSE
+ Copies a message from MESG to DEST, allocating DEST if necessary.
+ USAGE
+ void *H5O_sdspace_copy(_mesg, _dest)
+ const void *_mesg; IN: Pointer to the source extent dimensionality struct
+ const void *_dest; IN: Pointer to the destination extent dimensionality struct
+ RETURNS
+ Pointer to DEST on success, NULL on failure
+ DESCRIPTION
+ This function copies a native (memory) simple dimensionality message,
+ allocating the destination structure if necessary.
+--------------------------------------------------------------------------*/
+static void *
+H5O_sdspace_copy(const void *_mesg, void *_dest)
+{
+ const H5S_extent_t *mesg = (const H5S_extent_t *)_mesg;
+ H5S_extent_t *dest = (H5S_extent_t *)_dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(mesg);
+ if(!dest && NULL == (dest = H5FL_CALLOC(H5S_extent_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy extent information */
+ if(H5S_extent_copy_real(dest, mesg, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy extent")
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ if(NULL == ret_value)
+ if(dest && NULL == _dest)
+ dest = H5FL_FREE(H5S_extent_t, dest);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_sdspace_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_sdspace_size
+ PURPOSE
+ Return the raw message size in bytes
+ USAGE
+ void *H5O_sdspace_size(f, mesg)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source extent dimensionality struct
+ RETURNS
+ Size of message on success, zero on failure
+ DESCRIPTION
+ This function returns the size of the raw simple dimensionality message on
+ success. (Not counting the message type or size fields, only the data
+ portion of the message). It doesn't take into account alignment.
+
+ MODIFICATIONS
+ Robb Matzke, 1998-04-09
+ The current and maximum dimensions are now H5F_SIZEOF_SIZET bytes
+ instead of just four bytes.
+--------------------------------------------------------------------------*/
+static size_t
+H5O_sdspace_size(const H5F_t *f, const void *_mesg)
+{
+ const H5S_extent_t *space = (const H5S_extent_t *)_mesg;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Basic information for all dataspace messages */
+ ret_value = 1 + /* Version */
+ 1 + /* Rank */
+ 1 + /* Flags */
+ 1 + /* Dataspace type/reserved */
+ ((space->version > H5O_SDSPACE_VERSION_1) ? 0 : 4); /* Eliminated/reserved */
+
+ /* Add in the dimension sizes */
+ ret_value += space->rank * H5F_SIZEOF_SIZE(f);
+
+ /* Add in the space for the maximum dimensions, if they are present */
+ ret_value += space->max ? (space->rank * H5F_SIZEOF_SIZE(f)) : 0;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_sdspace_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_sdspace_reset
+ *
+ * Purpose: Frees the inside of a dataspace message and resets it to some
+ * initial value.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_sdspace_reset(void *_mesg)
+{
+ H5S_extent_t *mesg = (H5S_extent_t*)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5S_extent_release(mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_sdsdpace_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 30, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_sdspace_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5S_extent_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_sdspace_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_sdspace_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * November 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_sdspace_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void *mesg_src,
+ hbool_t H5_ATTR_UNUSED *deleted, const H5O_copy_t H5_ATTR_UNUSED *cpy_info, void *_udata)
+{
+ const H5S_extent_t *src_space_extent = (const H5S_extent_t *)mesg_src; /* Source dataspace extent */
+ H5D_copy_file_ud_t *udata = (H5D_copy_file_ud_t *)_udata; /* Dataset copying user data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(file_src);
+ HDassert(src_space_extent);
+
+ /* If the user data is non-NULL, assume we are copying a dataset
+ * and make a copy of the dataspace extent for later in the object copying
+ * process. (We currently only need to make a copy of the dataspace extent
+ * if the layout is an early version, but that information isn't
+ * available here, so we just make a copy of it in all cases)
+ */
+ if(udata) {
+ /* Allocate copy of dataspace extent */
+ if(NULL == (udata->src_space_extent = H5FL_CALLOC(H5S_extent_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "dataspace extent allocation failed")
+
+ /* Create a copy of the dataspace extent */
+ if(H5S_extent_copy_real(udata->src_space_extent, src_space_extent, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy extent")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dspace_pre_copy_file() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_sdspace_debug
+ PURPOSE
+ Prints debugging information for a simple dimensionality message
+ USAGE
+ void *H5O_sdspace_debug(f, mesg, stream, indent, fwidth)
+ H5F_t *f; IN: pointer to the HDF5 file struct
+ const void *mesg; IN: Pointer to the source extent dimensionality struct
+ FILE *stream; IN: Pointer to the stream for output data
+ int indent; IN: Amount to indent information by
+ int fwidth; IN: Field width (?)
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function prints debugging output to the stream passed as a
+ parameter.
+--------------------------------------------------------------------------*/
+static herr_t
+H5O_sdspace_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *mesg,
+ FILE * stream, int indent, int fwidth)
+{
+ const H5S_extent_t *sdim = (const H5S_extent_t *)mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(sdim);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth,
+ "Rank:",
+ (unsigned long) (sdim->rank));
+
+ if(sdim->rank > 0) {
+ unsigned u; /* local counting variable */
+
+ HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Dim Size:");
+ for(u = 0; u < sdim->rank; u++)
+ HDfprintf (stream, "%s%Hu", u?", ":"", sdim->size[u]);
+ HDfprintf (stream, "}\n");
+
+ HDfprintf(stream, "%*s%-*s ", indent, "", fwidth, "Dim Max:");
+ if(sdim->max) {
+ HDfprintf (stream, "{");
+ for(u = 0; u < sdim->rank; u++) {
+ if(H5S_UNLIMITED==sdim->max[u])
+ HDfprintf (stream, "%sUNLIM", u?", ":"");
+ else
+ HDfprintf (stream, "%s%Hu", u?", ":"", sdim->max[u]);
+ } /* end for */
+ HDfprintf (stream, "}\n");
+ } /* end if */
+ else
+ HDfprintf (stream, "CONSTANT\n");
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_sdspace_debug() */
+
diff --git a/src/H5Oshared.c b/src/H5Oshared.c
new file mode 100644
index 0000000..db2d0cc
--- /dev/null
+++ b/src/H5Oshared.c
@@ -0,0 +1,762 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, April 1, 1998
+ *
+ * Purpose: Functions that operate on a shared message. The shared
+ * message doesn't ever actually appear in the object header as
+ * a normal message. Instead, if a message is shared, the
+ * H5O_FLAG_SHARED bit is set and the message body is that
+ * defined here for H5O_SHARED. The message ID is the ID of the
+ * pointed-to message and the pointed-to message is stored in
+ * the global heap.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gprivate.h" /* Groups */
+#include "H5HFprivate.h" /* Fractal heap */
+#include "H5Opkg.h" /* Object headers */
+#include "H5SMprivate.h" /* Shared object header messages */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* First version, with full symbol table entry as link for object header sharing */
+#define H5O_SHARED_VERSION_1 1
+
+/* Older version, with just address of object as link for object header sharing */
+#define H5O_SHARED_VERSION_2 2
+
+/* Newest version, which recognizes messages that are stored in the SOHM heap */
+#define H5O_SHARED_VERSION_3 3
+#define H5O_SHARED_VERSION_LATEST H5O_SHARED_VERSION_3
+
+/* Size of stack buffer for serialized messages */
+#define H5O_MESG_BUF_SIZE 128
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_read
+ *
+ * Purpose: Reads a message referred to by a shared message.
+ *
+ * Return: Success: Ptr to message in native format. The message
+ * should be freed by calling H5O_msg_reset().
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 24 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_shared_read(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned *ioflags,
+ const H5O_shared_t *shared, const H5O_msg_class_t *type)
+{
+ H5HF_t *fheap = NULL;
+ H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */
+ uint8_t mesg_buf[H5O_MESG_BUF_SIZE]; /* Buffer for deserializing messages */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(shared);
+ HDassert(type);
+ HDassert(type->share_flags & H5O_SHARE_IS_SHARABLE);
+
+ /* This message could have a heap ID (SOHM) or the address of an object
+ * header on disk (named datatype)
+ */
+ HDassert(H5O_IS_STORED_SHARED(shared->type));
+
+ /* Check for implicit shared object header message */
+ if(shared->type == H5O_SHARE_TYPE_SOHM) {
+ haddr_t fheap_addr; /* Address of SOHM heap */
+ uint8_t *mesg_ptr; /* Pointer to raw message in heap */
+ size_t mesg_size; /* Size of message */
+
+ /* Retrieve the fractal heap address for shared messages */
+ if(H5SM_get_fheap_addr(f, dxpl_id, type->id, &fheap_addr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "can't get fheap address for shared messages")
+
+ /* Open the fractal heap */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, fheap_addr)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap")
+
+ /* Get the size of the message in the heap */
+ if(H5HF_get_obj_len(fheap, dxpl_id, &(shared->u.heap_id), &mesg_size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "can't get message size from fractal heap.")
+
+ /* Wrap the local buffer for serialized message */
+ if(NULL == (wb = H5WB_wrap(mesg_buf, sizeof(mesg_buf))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for message */
+ if(NULL == (mesg_ptr = (uint8_t *)H5WB_actual(wb, mesg_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer")
+
+ /* Retrieve the message from the heap */
+ if(H5HF_read(fheap, dxpl_id, &(shared->u.heap_id), mesg_ptr) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "can't read message from fractal heap.")
+
+ /* Decode the message */
+ if(NULL == (ret_value = (type->decode)(f, dxpl_id, open_oh, 0, ioflags, mesg_ptr)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't decode shared message.")
+ } /* end if */
+ else {
+ H5O_loc_t oloc; /* Location for object header where message is stored */
+
+ HDassert(shared->type == H5O_SHARE_TYPE_COMMITTED);
+
+ /* Build the object location for the shared message's object header */
+ oloc.file = f;
+ oloc.addr = shared->u.loc.oh_addr;
+ oloc.holding_file = FALSE;
+
+ if(open_oh && oloc.addr == H5O_OH_GET_ADDR(open_oh)) {
+ /* The shared message is in the already opened object header. This
+ * is possible, for example, if an attribute's datatype is shared in
+ * the same object header the attribute is in. Read the message
+ * directly. */
+ if(NULL == (ret_value = H5O_msg_read_oh(f, dxpl_id, open_oh, type->id, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read message")
+ } else
+ /* The shared message is in another object header */
+ if(NULL == (ret_value = H5O_msg_read(&oloc, type->id, NULL, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read message")
+ } /* end else */
+
+ /* Mark the message as shared */
+ if(H5O_msg_set_share(type->id, shared, ret_value) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to set sharing information")
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "can't close fractal heap")
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, NULL, "can't close wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_link_adj
+ *
+ * Purpose: Changes the link count for the object referenced by a shared
+ * message.
+ *
+ * This function changes the object header link count and is
+ * only relevant for committed messages. Messages shared in
+ * the heap are re-shared each time they're written, so their
+ * reference count is stored in the file-wide shared message
+ * index and is changed in a different place in the code.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_shared_link_adj(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ const H5O_msg_class_t *type, H5O_shared_t *shared, int adjust)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(shared);
+
+ /* Check for type of shared message */
+ if(shared->type == H5O_SHARE_TYPE_COMMITTED) {
+ H5O_loc_t oloc; /* Location for object header where message is stored */
+
+ /*
+ * The shared message is stored in some object header.
+ * The other object header must be in the same file as the
+ * new object header. Adjust the reference count on that
+ * object header.
+ */
+ /* Unfortunately, it is possible for the shared->file pointer to become
+ * invalid if the oh is kept in cache (which is contained in
+ * shared->file->shared while shared->file is closed. Just ignore
+ * shared->file until the "top-level" file pointer is removed at some
+ * point in the future. -NAF */
+ /* This is related to Jira issue #7638 and should be uncommented after
+ * the library has been refactored to shift to using shared file
+ * pointers for file operations, instead of using top file pointers.
+ * -QAK */
+ /*if(shared->file->shared != f->shared)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "interfile hard links are not allowed")*/
+
+ /* Build the object location for the shared message's object header */
+ oloc.file = f;
+ oloc.addr = shared->u.loc.oh_addr;
+ oloc.holding_file = FALSE;
+
+ if(open_oh && oloc.addr == H5O_OH_GET_ADDR(open_oh)) {
+ /* The shared message is in the already opened object header. This
+ * is possible, for example, if an attribute's datatype is shared in
+ * the same object header the attribute is in. Adjust the link
+ * count directly. */
+ hbool_t deleted = FALSE; /* This is used only to satisfy H5O_link_oh */
+
+ if(H5O_link_oh(f, adjust, dxpl_id, open_oh, &deleted) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count")
+
+ HDassert(!deleted);
+ } else
+ /* The shared message is in another object header */
+ if(H5O_link(&oloc, adjust, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count")
+ } /* end if */
+ else {
+ HDassert(shared->type == H5O_SHARE_TYPE_SOHM || shared->type == H5O_SHARE_TYPE_HERE);
+
+ /* Check for decrementing reference count on shared message */
+ if(adjust < 0) {
+ if(H5SM_delete(f, dxpl_id, open_oh, shared) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to delete message from SOHM table")
+ } /* end if */
+ /* Check for incrementing reference count on message */
+ else if(adjust > 0) {
+ if(H5SM_try_share(f, dxpl_id, open_oh, 0, type->id, shared, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "error trying to share message")
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_link_adj() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_decode
+ *
+ * Purpose: Decodes a shared object message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, January 22, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_shared_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned *ioflags,
+ const uint8_t *buf, const H5O_msg_class_t *type)
+{
+ H5O_shared_t sh_mesg; /* Shared message info */
+ unsigned version; /* Shared message version */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(buf);
+ HDassert(type);
+
+ /* Version */
+ version = *buf++;
+ if(version < H5O_SHARED_VERSION_1 || version > H5O_SHARED_VERSION_LATEST)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for shared object message")
+
+ /* Get the shared information type
+ * Flags are unused before version 3.
+ */
+ if(version >= H5O_SHARED_VERSION_2)
+ sh_mesg.type = *buf++;
+ else {
+ sh_mesg.type = H5O_SHARE_TYPE_COMMITTED;
+ buf++;
+ } /* end else */
+
+ /* Skip reserved bytes (for version 1) */
+ if(version == H5O_SHARED_VERSION_1)
+ buf += 6;
+
+ /* Body */
+ if(version == H5O_SHARED_VERSION_1) {
+ /* Initialize other location fields */
+ sh_mesg.u.loc.index = 0;
+
+ /* Decode stored "symbol table entry" into message location */
+ buf += H5F_SIZEOF_SIZE(f); /* Skip over local heap address */
+ H5F_addr_decode(f, &buf, &(sh_mesg.u.loc.oh_addr));
+ } /* end if */
+ else if (version >= H5O_SHARED_VERSION_2) {
+ /* If this message is in the heap, copy a heap ID.
+ * Otherwise, it is a named datatype, so copy an H5O_loc_t.
+ */
+ if(sh_mesg.type == H5O_SHARE_TYPE_SOHM) {
+ HDassert(version >= H5O_SHARED_VERSION_3);
+ HDmemcpy(&sh_mesg.u.heap_id, buf, sizeof(sh_mesg.u.heap_id));
+ } /* end if */
+ else {
+ /* The H5O_COMMITTED_FLAG should be set if this message
+ * is from an older version before the flag existed.
+ */
+ if(version < H5O_SHARED_VERSION_3)
+ sh_mesg.type = H5O_SHARE_TYPE_COMMITTED;
+
+ sh_mesg.u.loc.index = 0;
+ H5F_addr_decode(f, &buf, &sh_mesg.u.loc.oh_addr);
+ } /* end else */
+ } /* end else if */
+
+ /* Set file pointer & message type for all types of shared messages */
+ sh_mesg.file = f;
+ sh_mesg.msg_type_id = type->id;
+
+ /* Retrieve actual message, through decoded shared message info */
+ if(NULL == (ret_value = H5O_shared_read(f, dxpl_id, open_oh, ioflags, &sh_mesg, type)))
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to retrieve native message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_encode
+ *
+ * Purpose: Encodes message _MESG into buffer BUF.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_encode(const H5F_t *f, uint8_t *buf/*out*/, const H5O_shared_t *sh_mesg)
+{
+ unsigned version;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(f);
+ HDassert(buf);
+ HDassert(sh_mesg);
+
+ /* If this message is shared in the heap, we need to use version 3 of the
+ * encoding and encode the SHARED_IN_HEAP flag.
+ */
+ if(sh_mesg->type == H5O_SHARE_TYPE_SOHM)
+ version = H5O_SHARED_VERSION_LATEST;
+ else {
+ HDassert(sh_mesg->type == H5O_SHARE_TYPE_COMMITTED);
+ version = H5O_SHARED_VERSION_2; /* version 1 is no longer used */
+ } /* end else */
+
+ *buf++ = (uint8_t)version;
+ *buf++ = (uint8_t)sh_mesg->type;
+
+ /* Encode either the heap ID of the message or the address of the
+ * object header that holds it.
+ */
+ if(sh_mesg->type == H5O_SHARE_TYPE_SOHM)
+ HDmemcpy(buf, &(sh_mesg->u.heap_id), sizeof(sh_mesg->u.heap_id));
+ else
+ H5F_addr_encode(f, &buf, sh_mesg->u.loc.oh_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_shared_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_set_shared
+ *
+ * Purpose: Sets the shared component for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_set_shared(H5O_shared_t *dst, const H5O_shared_t *src)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(dst);
+ HDassert(src);
+
+ /* copy */
+ *dst = *src;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_set_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_size
+ *
+ * Purpose: Returns the length of a shared object message.
+ *
+ * Return: Success: Length
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5O_shared_size(const H5F_t *f, const H5O_shared_t *sh_mesg)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(sh_mesg->type == H5O_SHARE_TYPE_COMMITTED) {
+ ret_value = (size_t)1 + /*version */
+ (size_t)1 + /*the type field */
+ (size_t)H5F_SIZEOF_ADDR(f); /*sharing by another obj hdr */
+ } /* end if */
+ else {
+ HDassert(sh_mesg->type == H5O_SHARE_TYPE_SOHM);
+ ret_value = 1 + /*version */
+ 1 + /*the type field */
+ H5O_FHEAP_ID_LEN; /* Shared in the heap */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 26, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ const H5O_msg_class_t *type, H5O_shared_t *sh_mesg)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(sh_mesg);
+
+ /*
+ * Committed datatypes increment the OH of the original message when they
+ * are written (in H5O_shared_link) and decrement it here.
+ * SOHMs in the heap behave differently; their refcount is incremented
+ * during H5SM_share when they are going to be written (in H5O_msg_append
+ * or H5O_msg_write). Their refcount in the SOHM indexes still needs to
+ * be decremented when they're deleted (in H5O_shared_link_adj).
+ */
+
+ /* Decrement the reference count on the shared object */
+ if(H5O_shared_link_adj(f, dxpl_id, open_oh, type, sh_mesg, -1) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_link
+ *
+ * Purpose: Increment reference count on any objects referenced by
+ * message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 26, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_link(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ const H5O_msg_class_t *type, H5O_shared_t *sh_mesg)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(sh_mesg);
+
+ /* Increment the reference count on the shared object */
+ if(H5O_shared_link_adj(f, dxpl_id, open_oh, type, sh_mesg, 1) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * January 22, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_copy_file(H5F_t *file_src, H5F_t *file_dst,
+ const H5O_msg_class_t *mesg_type, const void *_native_src, void *_native_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned *mesg_flags, H5O_copy_t *cpy_info,
+ void H5_ATTR_UNUSED *udata, hid_t dxpl_id)
+{
+ const H5O_shared_t *shared_src = (const H5O_shared_t *)_native_src; /* Alias to shared info in native source */
+ H5O_shared_t *shared_dst = (H5O_shared_t *)_native_dst; /* Alias to shared info in native destination message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(file_src);
+ HDassert(file_dst);
+ HDassert(mesg_type);
+ HDassert(shared_src);
+ HDassert(shared_dst);
+ HDassert(recompute_size);
+ HDassert(cpy_info);
+
+ /* Committed shared messages create a shared message at the destination
+ * and also copy the committed object that they point to.
+ *
+ * Other messages simulate sharing the destination message to determine how
+ * it will eventually be shared (if at all), but do not actually share the
+ * message until "post copy". The "H5O_shared_t" part of the message will
+ * be updated (to allow calculation of the final size) but the message is
+ * not actually shared.
+ */
+ if(shared_src->type != H5O_SHARE_TYPE_COMMITTED) {
+ /* Simulate trying to share new message in the destination file. */
+ /* Set copied metadata tag */
+ H5_BEGIN_TAG(dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ if(H5SM_try_share(file_dst, dxpl_id, NULL, H5SM_DEFER, mesg_type->id, _native_dst, mesg_flags) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to determine if message should be shared")
+
+ /* Reset metadata tag */
+ H5_END_TAG(FAIL);
+ } /* end if */
+ else {
+ /* Mark the message as committed - as it will be committed in post copy
+ */
+ H5O_UPDATE_SHARED(shared_dst, H5O_SHARE_TYPE_COMMITTED, file_dst, mesg_type->id, 0, HADDR_UNDEF)
+ *mesg_flags |= H5O_MSG_FLAG_SHARED;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_shared_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_post_copy_file
+ *
+ * Purpose: Delate a shared message and replace with a new one.
+ * The function is needed at cases such as coping a shared reg_ref attribute.
+ * When a shared reg_ref attribute is copied from one file to
+ * another, the values in file need to be replaced. The only way
+ * to complish that is to delete the old message and write the
+ * new message with the correct values.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * xcao@hdfgroup.org
+ * May 24 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_post_copy_file(H5F_t *f, const H5O_msg_class_t *mesg_type,
+ const H5O_shared_t *shared_src, H5O_shared_t *shared_dst,
+ unsigned *mesg_flags, hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(shared_src);
+ HDassert(shared_dst);
+
+ /* Copy the target of committed messages, try to share others */
+ if(shared_src->type == H5O_SHARE_TYPE_COMMITTED) {
+ H5O_loc_t dst_oloc;
+ H5O_loc_t src_oloc;
+
+ /* Copy the shared object from source to destination */
+ H5O_loc_reset(&dst_oloc);
+ dst_oloc.file = f;
+ src_oloc.file = shared_src->file;
+ src_oloc.addr = shared_src->u.loc.oh_addr;
+ if(H5O_copy_header_map(&src_oloc, &dst_oloc, dxpl_id, cpy_info, FALSE,
+ NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
+
+ /* Set up destination message's shared info */
+ H5O_UPDATE_SHARED(shared_dst, H5O_SHARE_TYPE_COMMITTED, f, mesg_type->id, 0, dst_oloc.addr)
+ } /* end if */
+ else
+ /* Share the message */
+ if(H5SM_try_share(f, dxpl_id, NULL, H5SM_WAS_DEFERRED, mesg_type->id,
+ shared_dst, mesg_flags) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "can't share message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shared_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shared_debug
+ *
+ * Purpose: Prints debugging info for the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_shared_debug(const H5O_shared_t *mesg, FILE *stream, int indent, int fwidth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ switch(mesg->type) {
+ case H5O_SHARE_TYPE_UNSHARED:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Shared Message type:",
+ "Unshared");
+ break;
+
+ case H5O_SHARE_TYPE_COMMITTED:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Shared Message type:",
+ "Obj Hdr");
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Object address:",
+ mesg->u.loc.oh_addr);
+ break;
+
+ case H5O_SHARE_TYPE_SOHM:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Shared Message type:",
+ "SOHM");
+ HDfprintf(stream, "%*s%-*s %016llx\n", indent, "", fwidth,
+ "Heap ID:",
+ (unsigned long long)mesg->u.heap_id.val);
+ break;
+
+ case H5O_SHARE_TYPE_HERE:
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "Shared Message type:",
+ "Here");
+ break;
+
+ default:
+ HDfprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth,
+ "Shared Message type:",
+ "Unknown", (unsigned)mesg->type);
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_shared_debug() */
+
diff --git a/src/H5Oshared.h b/src/H5Oshared.h
new file mode 100644
index 0000000..2465e65
--- /dev/null
+++ b/src/H5Oshared.h
@@ -0,0 +1,489 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Friday, January 19, 2007
+ *
+ * Purpose: This file contains inline definitions for "generic" routines
+ * supporting a "shared message interface" (ala Java) for object
+ * header messages that can be shared. This interface is
+ * dependent on a bunch of macros being defined which define
+ * the name of the interface and "real" methods which need to
+ * be implemented for each message class that supports the
+ * shared message interface.
+ */
+
+#ifndef H5Oshared_H
+#define H5Oshared_H
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_DECODE
+ *
+ * Purpose: Decode an object header message that may be shared.
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Pointer to the new message in native form
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE void *
+H5O_SHARED_DECODE(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned mesg_flags,
+ unsigned *ioflags, const uint8_t *p)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_DECODE
+#error "Need to define H5O_SHARED_DECODE macro!"
+#endif /* H5O_SHARED_DECODE */
+#ifndef H5O_SHARED_DECODE_REAL
+#error "Need to define H5O_SHARED_DECODE_REAL macro!"
+#endif /* H5O_SHARED_DECODE_REAL */
+
+ /* Check for shared message */
+ if(mesg_flags & H5O_MSG_FLAG_SHARED) {
+ /* Retrieve native message info indirectly through shared message */
+ if(NULL == (ret_value = H5O_shared_decode(f, dxpl_id, open_oh, ioflags, p, H5O_SHARED_TYPE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode shared message")
+
+ /* We currently do not support automatically fixing shared messages */
+#ifdef H5_STRICT_FORMAT_CHECKS
+ if(*ioflags & H5O_DECODEIO_DIRTY)
+ HGOTO_ERROR(H5E_OHDR, H5E_UNSUPPORTED, NULL, "unable to mark shared message dirty")
+#else /* H5_STRICT_FORMAT_CHECKS */
+ *ioflags &= ~H5O_DECODEIO_DIRTY;
+#endif /* H5_STRICT_FORMAT_CHECKS */
+ } /* end if */
+ else {
+ /* Decode native message directly */
+ if(NULL == (ret_value = H5O_SHARED_DECODE_REAL(f, dxpl_id, open_oh, mesg_flags, ioflags, p)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode native message")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_DECODE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_ENCODE
+ *
+ * Purpose: Encode an object header message that may be shared.
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE herr_t
+H5O_SHARED_ENCODE(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_shared_t *sh_mesg = (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_ENCODE
+#error "Need to define H5O_SHARED_ENCODE macro!"
+#endif /* H5O_SHARED_ENCODE */
+#ifndef H5O_SHARED_ENCODE_REAL
+#error "Need to define H5O_SHARED_ENCODE_REAL macro!"
+#endif /* H5O_SHARED_ENCODE_REAL */
+
+ /* Sanity check */
+ HDassert(sh_mesg->type == H5O_SHARE_TYPE_UNSHARED || sh_mesg->msg_type_id == H5O_SHARED_TYPE->id);
+
+ /* Check for message stored elsewhere */
+ if(H5O_IS_STORED_SHARED(sh_mesg->type) && !disable_shared) {
+ /* Encode shared message into buffer */
+ if(H5O_shared_encode(f, p, sh_mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode shared message")
+ } /* end if */
+ else {
+ /* Encode native message directly */
+ if(H5O_SHARED_ENCODE_REAL(f, p, _mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode native message")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_ENCODE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_SIZE
+ *
+ * Purpose: Returns the length of an encoded message.
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Length
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE size_t
+H5O_SHARED_SIZE(const H5F_t *f, hbool_t disable_shared, const void *_mesg)
+{
+ const H5O_shared_t *sh_mesg = (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_SIZE
+#error "Need to define H5O_SHARED_SIZE macro!"
+#endif /* H5O_SHARED_SIZE */
+#ifndef H5O_SHARED_SIZE_REAL
+#error "Need to define H5O_SHARED_SIZE_REAL macro!"
+#endif /* H5O_SHARED_SIZE_REAL */
+
+ /* Check for message stored elsewhere */
+ if(H5O_IS_STORED_SHARED(sh_mesg->type) && !disable_shared) {
+ /* Retrieve encoded size of shared message */
+ if(0 == (ret_value = H5O_shared_size(f, sh_mesg)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, 0, "unable to retrieve encoded size of shared message")
+ } /* end if */
+ else {
+ /* Retrieve size of native message directly */
+ if(0 == (ret_value = H5O_SHARED_SIZE_REAL(f, _mesg)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, 0, "unable to retrieve encoded size of native message")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_SIZE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_DELETE
+ *
+ * Purpose: Decrement reference count on any objects referenced by
+ * message
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE herr_t
+H5O_SHARED_DELETE(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_shared_t *sh_mesg = (H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_DELETE
+#error "Need to define H5O_SHARED_DELETE macro!"
+#endif /* H5O_SHARED_DELETE */
+
+ /* Check for message tracked elsewhere */
+ if(H5O_IS_TRACKED_SHARED(sh_mesg->type)) {
+ /* Decrement the reference count on the shared message/object */
+ if(H5O_shared_delete(f, dxpl_id, open_oh, H5O_SHARED_TYPE, sh_mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for shared message")
+ } /* end if */
+#ifdef H5O_SHARED_DELETE_REAL
+ else {
+ /* Decrement the reference count on the native message directly */
+ if(H5O_SHARED_DELETE_REAL(f, dxpl_id, open_oh, _mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for native message")
+ } /* end else */
+#endif /* H5O_SHARED_DELETE_REAL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_DELETE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_LINK
+ *
+ * Purpose: Increment reference count on any objects referenced by
+ * message
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE herr_t
+H5O_SHARED_LINK(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg)
+{
+ H5O_shared_t *sh_mesg = (H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_LINK
+#error "Need to define H5O_SHARED_LINK macro!"
+#endif /* H5O_SHARED_LINK */
+
+ /* Check for message tracked elsewhere */
+ if(H5O_IS_TRACKED_SHARED(sh_mesg->type)) {
+ /* Increment the reference count on the shared message/object */
+ if(H5O_shared_link(f, dxpl_id, open_oh, H5O_SHARED_TYPE, sh_mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "unable to increment ref count for shared message")
+ } /* end if */
+#ifdef H5O_SHARED_LINK_REAL
+ else {
+ /* Increment the reference count on the native message directly */
+ if(H5O_SHARED_LINK_REAL(f, dxpl_id, open_oh, _mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "unable to increment ref count for native message")
+ } /* end else */
+#endif /* H5O_SHARED_LINK_REAL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_LINK() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_COPY_FILE
+ *
+ * Purpose: Copies a message from _SRC to _DEST in file
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, January 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE void *
+H5O_SHARED_COPY_FILE(H5F_t *file_src, void *_native_src, H5F_t *file_dst,
+ hbool_t *recompute_size, unsigned *mesg_flags, H5O_copy_t *cpy_info,
+ void *udata, hid_t dxpl_id)
+{
+ void *dst_mesg = NULL; /* Destination message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_COPY_FILE
+#error "Need to define H5O_SHARED_COPY_FILE macro!"
+#endif /* H5O_SHARED_COPY_FILE */
+
+#ifdef H5O_SHARED_COPY_FILE_REAL
+ /* Call native message's copy file callback to copy the message */
+ if(NULL == (dst_mesg = H5O_SHARED_COPY_FILE_REAL(file_src, H5O_SHARED_TYPE, _native_src, file_dst, recompute_size, cpy_info, udata, dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy native message to another file")
+#else /* H5O_SHARED_COPY_FILE_REAL */
+ /* No copy file callback defined, just copy the message itself */
+ if(NULL == (dst_mesg = (H5O_SHARED_TYPE->copy)(_native_src, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy native message")
+#endif /* H5O_SHARED_COPY_FILE_REAL */
+
+ /* Reset shared message info for new message */
+ HDmemset(dst_mesg, 0, sizeof(H5O_shared_t));
+
+ /* Handle sharing destination message */
+ if(H5O_shared_copy_file(file_src, file_dst, H5O_SHARED_TYPE, _native_src,
+ dst_mesg, recompute_size, mesg_flags, cpy_info, udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, NULL, "unable to determine if message should be shared")
+
+ /* Set return value */
+ ret_value = dst_mesg;
+
+done:
+ if(!ret_value)
+ if(dst_mesg)
+ H5O_msg_free(H5O_SHARED_TYPE->id, dst_mesg);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_COPY_FILE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_POST_COPY_FILE
+ *
+ * Purpose: Copies a message from _SRC to _DEST in file
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Peter Cao
+ * May 25, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE herr_t
+H5O_SHARED_POST_COPY_FILE(const H5O_loc_t *oloc_src, const void *mesg_src,
+ H5O_loc_t *oloc_dst, void *mesg_dst, unsigned *mesg_flags, hid_t dxpl_id,
+ H5O_copy_t *cpy_info)
+{
+ const H5O_shared_t *shared_src = (const H5O_shared_t *)mesg_src; /* Alias to shared info in native source */
+ H5O_shared_t *shared_dst = (H5O_shared_t *)mesg_dst; /* Alias to shared info in native destination */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(oloc_src->file);
+ HDassert(oloc_dst->file);
+ HDassert(mesg_src);
+ HDassert(mesg_dst);
+ HDassert(cpy_info);
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_POST_COPY_FILE
+#error "Need to define H5O_SHARED_POST_COPY_FILE macro!"
+#endif /* H5O_SHARED_POST_COPY_FILE */
+
+#ifdef H5O_SHARED_POST_COPY_FILE_REAL
+ /* Call native message's post copy file callback to copy the message */
+ if(H5O_SHARED_POST_COPY_FILE_REAL(oloc_src, mesg_src, oloc_dst, mesg_dst, dxpl_id, cpy_info) <0 )
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy native message to another file")
+#endif /* H5O_SHARED_POST_COPY_FILE_REAL */
+
+ /* Update shared message after the post copy - will short circuit in
+ * production if the DEFER pass determined it will not be shared; debug mode
+ * verifies that it is indeed the case */
+ if(H5O_shared_post_copy_file(oloc_dst->file, H5O_SHARED_TYPE,
+ shared_src, shared_dst, mesg_flags, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to fix shared message in post copy")
+
+#ifdef H5O_SHARED_POST_COPY_FILE_UPD
+ /* Call native message's post copy file update callback to update the
+ * message */
+ if(H5O_SHARED_POST_COPY_FILE_UPD(oloc_src, mesg_src, oloc_dst, mesg_dst, dxpl_id, cpy_info) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to update native message")
+#endif /* H5O_SHARED_POST_COPY_FILE_UPD */
+
+ /* Make sure that if the the source or destination is committed, both are
+ * committed */
+ HDassert((shared_src->type == H5O_SHARE_TYPE_COMMITTED)
+ == (shared_dst->type == H5O_SHARE_TYPE_COMMITTED));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_POST_COPY_FILE() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_SHARED_DEBUG
+ *
+ * Purpose: Prints debugging info for a potentially shared message.
+ *
+ * Note: The actual name of this routine can be different in each source
+ * file that this header file is included in, and must be defined
+ * prior to including this header file.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 3, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE herr_t
+H5O_SHARED_DEBUG(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_shared_t *sh_mesg = (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+#ifndef H5O_SHARED_TYPE
+#error "Need to define H5O_SHARED_TYPE macro!"
+#endif /* H5O_SHARED_TYPE */
+#ifndef H5O_SHARED_DEBUG
+#error "Need to define H5O_SHARED_DEBUG macro!"
+#endif /* H5O_SHARED_DEBUG */
+#ifndef H5O_SHARED_DEBUG_REAL
+#error "Need to define H5O_SHARED_DEBUG_REAL macro!"
+#endif /* H5O_SHARED_DEBUG_REAL */
+
+ /* Check for message stored elsewhere */
+ if(H5O_IS_STORED_SHARED(sh_mesg->type)) {
+ /* Print shared message information */
+ if(H5O_shared_debug(sh_mesg, stream, indent, fwidth) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display shared message info")
+ } /* end if */
+
+ /* Call native message's debug callback */
+ if(H5O_SHARED_DEBUG_REAL(f, dxpl_id, _mesg, stream, indent, fwidth) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display native message info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_SHARED_DEBUG() */
+
+#endif /* H5Oshared_H */
+
diff --git a/src/H5Oshmesg.c b/src/H5Oshmesg.c
new file mode 100644
index 0000000..1cbfb05
--- /dev/null
+++ b/src/H5Oshmesg.c
@@ -0,0 +1,247 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/* Programmer: James Laird <jlaird@hdfgroup.org>
+ * Monday, January 29, 2007
+ *
+ * Purpose: A message holding "implicitly shared object header message"
+ * information in the superblock extension.
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object headers */
+#include "H5MMprivate.h" /* Memory management */
+
+static void *H5O_shmesg_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_shmesg_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_shmesg_copy(const void *_mesg, void *_dest);
+static size_t H5O_shmesg_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_shmesg_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_SHMESG[1] = {{
+ H5O_SHMESG_ID, /*message id number */
+ "shared message table", /*message name for debugging */
+ sizeof(H5O_shmesg_table_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_shmesg_decode, /*decode message */
+ H5O_shmesg_encode, /*encode message */
+ H5O_shmesg_copy, /*copy the native value */
+ H5O_shmesg_size, /*raw message size */
+ NULL, /*free internal memory */
+ NULL, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /* set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_shmesg_debug /*debug the message */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shmesg_decode
+ *
+ * Purpose: Decode a shared message table message and return a pointer
+ * to a newly allocated H5O_shmesg_table_t struct.
+ *
+ * Return: Success: Ptr to new message in native struct.
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Jan 29, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_shmesg_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_shmesg_table_t *mesg; /* Native message */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+
+ if(NULL == (mesg = (H5O_shmesg_table_t *)H5MM_calloc(sizeof(H5O_shmesg_table_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for shared message table message")
+
+ /* Retrieve version, table address, and number of indexes */
+ mesg->version = *p++;
+ H5F_addr_decode(f, &p, &(mesg->addr));
+ mesg->nindexes = *p++;
+
+ /* Set return value */
+ ret_value = (void *)mesg;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shmesg_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shmesg_encode
+ *
+ * Purpose: Encode a shared message table message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Jan 29, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_shmesg_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_shmesg_table_t *mesg = (const H5O_shmesg_table_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(p);
+ HDassert(mesg);
+
+ /* Store version, table address, and number of indexes */
+ *p++ = (uint8_t)mesg->version;
+ H5F_addr_encode(f, &p, mesg->addr);
+ *p++ = (uint8_t)mesg->nindexes;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_shmesg_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shmesg_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Jan 29, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_shmesg_copy(const void *_mesg, void *_dest)
+{
+ const H5O_shmesg_table_t *mesg = (const H5O_shmesg_table_t *)_mesg;
+ H5O_shmesg_table_t *dest = (H5O_shmesg_table_t *)_dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(mesg);
+
+ if(!dest && NULL == (dest = (H5O_shmesg_table_t *)H5MM_malloc(sizeof(H5O_shmesg_table_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for shared message table message")
+
+ /* All this message requires is a shallow copy */
+ *dest = *mesg;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shmesg_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shmesg_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting the
+ * message type or size fields, but only the data fields.
+ *
+ * Return: Success: Message data size in bytes w/o alignment.
+ * Failure: 0
+ *
+ * Programmer: James Laird
+ * Jan 29, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_shmesg_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+
+ ret_value = (size_t)(1 + /* Version number */
+ H5F_SIZEOF_ADDR(f) + /* Table address */
+ 1); /* Number of indexes */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_shmesg_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_shmesg_debug
+ *
+ * Purpose: Prints debugging info for the message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Jan 29, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_shmesg_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth)
+{
+ const H5O_shmesg_table_t *mesg = (const H5O_shmesg_table_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Version:", mesg->version);
+ HDfprintf(stream, "%*s%-*s %a (rel)\n", indent, "", fwidth,
+ "Shared message table address:", mesg->addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of indexes:", mesg->nindexes);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_shmesg_debug() */
+
diff --git a/src/H5Ostab.c b/src/H5Ostab.c
new file mode 100644
index 0000000..5c840a6
--- /dev/null
+++ b/src/H5Ostab.c
@@ -0,0 +1,449 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ostab.c
+ * Aug 6 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Symbol table messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5G_FRIEND /*suppress error about including H5Gpkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_stab_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned mesg_flags, unsigned *ioflags, const uint8_t *p);
+static herr_t H5O_stab_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_stab_copy(const void *_mesg, void *_dest);
+static size_t H5O_stab_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_stab_free(void *_mesg);
+static herr_t H5O_stab_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg);
+static void *H5O_stab_copy_file(H5F_t *file_src, void *native_src,
+ H5F_t *file_dst, hbool_t *recompute_size, unsigned *mesg_flags,
+ H5O_copy_t *cpy_info, void *_udata, hid_t dxpl_id);
+static herr_t H5O_stab_post_copy_file(const H5O_loc_t *src_oloc,
+ const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst,
+ unsigned *mesg_flags, hid_t dxpl_id, H5O_copy_t *cpy_info);
+static herr_t H5O_stab_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_STAB[1] = {{
+ H5O_STAB_ID, /*message id number */
+ "stab", /*message name for debugging */
+ sizeof(H5O_stab_t), /*native message size */
+ 0, /* messages are sharable? */
+ H5O_stab_decode, /*decode message */
+ H5O_stab_encode, /*encode message */
+ H5O_stab_copy, /*copy the native value */
+ H5O_stab_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_stab_free, /* free method */
+ H5O_stab_delete, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ H5O_stab_copy_file, /* copy native value to file */
+ H5O_stab_post_copy_file, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_stab_debug /*debug the message */
+}};
+
+/* Declare a free list to manage the H5O_stab_t struct */
+H5FL_DEFINE_STATIC(H5O_stab_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_decode
+ *
+ * Purpose: Decode a symbol table message and return a pointer to
+ * a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native order.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_stab_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh,
+ unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p)
+{
+ H5O_stab_t *stab = NULL;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* decode */
+ if(NULL == (stab = H5FL_CALLOC(H5O_stab_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ H5F_addr_decode(f, &p, &(stab->btree_addr));
+ H5F_addr_decode(f, &p, &(stab->heap_addr));
+
+ /* Set return value */
+ ret_value = stab;
+
+done:
+ if(ret_value == NULL) {
+ if(stab != NULL)
+ stab = H5FL_FREE(H5O_stab_t, stab);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_stab_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_encode
+ *
+ * Purpose: Encodes a symbol table message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_stab_t *stab = (const H5O_stab_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(stab);
+
+ /* encode */
+ H5F_addr_encode(f, &p, stab->btree_addr);
+ H5F_addr_encode(f, &p, stab->heap_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_stab_copy(const void *_mesg, void *_dest)
+{
+ const H5O_stab_t *stab = (const H5O_stab_t *) _mesg;
+ H5O_stab_t *dest = (H5O_stab_t *) _dest;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(stab);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_stab_t)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+
+ /* copy */
+ *dest = *stab;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_stab_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ *
+ * Failure: zero
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_stab_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, const void H5_ATTR_UNUSED *_mesg)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set return value */
+ ret_value = (size_t)(2 * H5F_SIZEOF_ADDR(f));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 30, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_stab_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_stab_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_delete(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, void *mesg)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Free the file space for the symbol table */
+ if(H5G__stab_delete(f, dxpl_id, (const H5O_stab_t *)mesg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free symbol table")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_stab_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_copy_file
+ *
+ * Purpose: Copies a message from _MESG to _DEST in file
+ *
+ * Return: Success: Ptr to _DEST
+ *
+ * Failure: NULL
+ *
+ * Programmer: Peter Cao
+ * September 10, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_stab_copy_file(H5F_t *file_src, void *native_src, H5F_t *file_dst,
+ hbool_t H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
+ H5O_copy_t H5_ATTR_UNUSED *cpy_info, void *_udata, hid_t dxpl_id)
+{
+ H5O_stab_t *stab_src = (H5O_stab_t *) native_src;
+ H5O_stab_t *stab_dst = NULL;
+ H5G_copy_file_ud_t *udata = (H5G_copy_file_ud_t *)_udata;
+ size_t size_hint; /* Local heap initial size */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(stab_src);
+ HDassert(file_dst);
+
+ /* Allocate space for the destination stab */
+ if(NULL == (stab_dst = H5FL_MALLOC(H5O_stab_t)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get the old local heap's size and use that as the hint for the new heap */
+ if(H5HL_get_size(file_src, dxpl_id, stab_src->heap_addr, &size_hint) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, NULL, "can't query local heap size")
+
+ /* Set copy metadata tag */
+ H5_BEGIN_TAG(dxpl_id, H5AC__COPIED_TAG, NULL);
+
+ /* Create components of symbol table message */
+ if(H5G__stab_create_components(file_dst, stab_dst, size_hint, dxpl_id) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_CANTINIT, NULL, "can't create symbol table components")
+
+ /* Reset metadata tag */
+ H5_END_TAG(NULL);
+
+ /* Cache stab in udata */
+ udata->cache_type = H5G_CACHED_STAB;
+ udata->cache.stab.btree_addr = stab_dst->btree_addr;
+ udata->cache.stab.heap_addr = stab_dst->heap_addr;
+
+ /* Set return value */
+ ret_value = stab_dst;
+
+done:
+ if(!ret_value)
+ if(stab_dst)
+ stab_dst = H5FL_FREE(H5O_stab_t, stab_dst);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_stab_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_post_copy_file
+ *
+ * Purpose: Finish copying a message from between files
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * September 28, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
+ H5O_loc_t *dst_oloc, void *mesg_dst, unsigned H5_ATTR_UNUSED *mesg_flags,
+ hid_t dxpl_id, H5O_copy_t *cpy_info)
+{
+ const H5O_stab_t *stab_src = (const H5O_stab_t *)mesg_src;
+ H5O_stab_t *stab_dst = (H5O_stab_t *)mesg_dst;
+ H5G_bt_it_cpy_t udata; /* B-tree user data */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(stab_src);
+ HDassert(H5F_addr_defined(dst_oloc->addr));
+ HDassert(dst_oloc->file);
+ HDassert(stab_dst);
+ HDassert(cpy_info);
+
+ /* If we are performing a 'shallow hierarchy' copy, get out now */
+ if(cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth)
+ HGOTO_DONE(SUCCEED)
+
+ /* Set up B-tree iteration user data */
+ udata.src_oloc = src_oloc;
+ udata.src_heap_addr = stab_src->heap_addr;
+ udata.dst_file = dst_oloc->file;
+ udata.dst_stab = stab_dst;
+ udata.cpy_info = cpy_info;
+
+ /* Iterate over objects in group, copying them */
+ if((H5B_iterate(src_oloc->file, dxpl_id, H5B_SNODE, stab_src->btree_addr, H5G__node_copy, &udata)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_stab_post_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_stab_debug
+ *
+ * Purpose: Prints debugging info for a symbol table message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_stab_t *stab = (const H5O_stab_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(f);
+ HDassert(stab);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "B-tree address:", stab->btree_addr);
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth,
+ "Name heap address:", stab->heap_addr);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
diff --git a/src/H5Otest.c b/src/H5Otest.c
new file mode 100644
index 0000000..f0deade
--- /dev/null
+++ b/src/H5Otest.c
@@ -0,0 +1,747 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Monday, December 4, 2006
+ *
+ * Purpose: Object header testing functions.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5A_FRIEND /*suppress error about including H5Apkg */
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+#define H5O_TESTING /*suppress warning about H5O testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Apkg.h" /* Attributes */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Object headers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_is_attr_dense_test
+ PURPOSE
+ Determine whether attributes for an object are stored "densely"
+ USAGE
+ htri_t H5O_is_attr_dense_test(oid)
+ hid_t oid; IN: object to check
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the object is storing attributes in the "dense" or
+ "compact" form.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5O_is_attr_dense_test(hid_t oid)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, H5AC_ind_read_dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check if dense storage is being used */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Check for any messages in object header */
+ HDassert(H5O_msg_count_real(oh, H5O_MSG_ATTR) == 0);
+
+ ret_value = TRUE;
+ } /* end if */
+ else
+ ret_value = FALSE;
+
+done:
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_is_attr_dense_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_is_attr_empty_test
+ PURPOSE
+ Determine whether there are any attributes for an object
+ USAGE
+ htri_t H5O_is_attr_empty_test(oid)
+ hid_t oid; IN: object to check
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the object is storing any attributes.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5O_is_attr_empty_test(hid_t oid)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ hsize_t nattrs; /* Number of attributes */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if((ainfo_exists = H5A_get_ainfo(loc->file, H5AC_ind_read_dxpl_id, oh, &ainfo)) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Retrieve the number of attribute messages in header */
+ nattrs = H5O_msg_count_real(oh, H5O_MSG_ATTR);
+
+ /* Check for later version of object header format & attribute info available */
+ if(oh->version > H5O_VERSION_1) {
+ if(ainfo_exists) {
+ /* Check for using dense storage */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Check for any messages in object header */
+ HDassert(nattrs == 0);
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(H5AC_ind_read_dxpl_id, loc->addr, FAIL);
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(loc->file, H5AC_ind_read_dxpl_id, ainfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+ /* Retrieve # of records in name index */
+ if(H5B2_get_nrec(bt2_name, &nattrs) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from name index")
+ } /* end if */
+
+ /* Verify that attribute count in object header is correct */
+ HDassert(nattrs == ainfo.nattrs);
+ } /* end if */
+ else
+ HDassert(nattrs == 0);
+ } /* end if */
+
+ /* Set the return value */
+ ret_value = (nattrs == 0) ? TRUE : FALSE;
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_is_attr_empty_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_num_attrs_test
+ PURPOSE
+ Determine whether there are any attributes for an object
+ USAGE
+ herr_t H5O_num_attrs_test(oid, nattrs)
+ hid_t oid; IN: object to check
+ hsize_t *nattrs; OUT: Number of attributes on object
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Checks the # of attributes on an object
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_num_attrs_test(hid_t oid, hsize_t *nattrs)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ hsize_t obj_nattrs; /* Number of attributes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, H5AC_ind_read_dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Retrieve the number of attribute messages in header */
+ obj_nattrs = H5O_msg_count_real(oh, H5O_MSG_ATTR);
+
+ /* Check for later version of object header format */
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for using dense storage */
+ if(H5F_addr_defined(ainfo.fheap_addr)) {
+ /* Check for any messages in object header */
+ HDassert(obj_nattrs == 0);
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(H5AC_ind_read_dxpl_id, loc->addr, FAIL);
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(loc->file, H5AC_ind_read_dxpl_id, ainfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+ /* Retrieve # of records in name index */
+ if(H5B2_get_nrec(bt2_name, &obj_nattrs) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from name index")
+ } /* end if */
+
+ /* Verify that attribute count in object header is correct */
+ HDassert(obj_nattrs == ainfo.nattrs);
+ } /* end if */
+
+ /* Set the number of attributes */
+ *nattrs = obj_nattrs;
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_num_attrs_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_attr_dense_info_test
+ PURPOSE
+ Retrieve information about the state of the "dense" storage for attributes
+ USAGE
+ herr_t H5O_attr_dense_info_test(oid, name_count, corder_count)
+ hid_t oid; IN: Object to check
+ hsize_t *name_count; OUT: Number of attributes in name index
+ hsize_t *corder_count; OUT: Number of attributes in creation order index
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Currently, just retrieves the number of attributes in each index and returns
+ them.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_attr_dense_info_test(hid_t oid, hsize_t *name_count, hsize_t *corder_count)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
+ H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
+ H5O_ainfo_t ainfo; /* Attribute information for object */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Set metadata tag in dxpl_id */
+ H5_BEGIN_TAG(H5AC_ind_read_dxpl_id, loc->addr, FAIL);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Check for attribute info stored */
+ ainfo.fheap_addr = HADDR_UNDEF;
+ if(oh->version > H5O_VERSION_1) {
+ /* Check for (& retrieve if available) attribute info */
+ if(H5A_get_ainfo(loc->file, H5AC_ind_read_dxpl_id, oh, &ainfo) < 0)
+ HGOTO_ERROR_TAG(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message")
+ } /* end if */
+
+ /* Check for 'dense' attribute storage file addresses being defined */
+ if(!H5F_addr_defined(ainfo.fheap_addr))
+ HGOTO_DONE_TAG(FAIL, FAIL)
+ if(!H5F_addr_defined(ainfo.name_bt2_addr))
+ HGOTO_DONE_TAG(FAIL, FAIL)
+
+ /* Open the name index v2 B-tree */
+ if(NULL == (bt2_name = H5B2_open(loc->file, H5AC_ind_read_dxpl_id, ainfo.name_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index")
+
+ /* Retrieve # of records in name index */
+ if(H5B2_get_nrec(bt2_name, name_count) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from name index")
+
+ /* Check if there is a creation order index */
+ if(H5F_addr_defined(ainfo.corder_bt2_addr)) {
+ /* Open the creation order index v2 B-tree */
+ if(NULL == (bt2_corder = H5B2_open(loc->file, H5AC_ind_read_dxpl_id, ainfo.corder_bt2_addr, NULL)))
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index")
+
+ /* Retrieve # of records in creation order index */
+ if(H5B2_get_nrec(bt2_corder, corder_count) < 0)
+ HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to retrieve # of records from creation order index")
+ } /* end if */
+ else
+ *corder_count = 0;
+
+ /* Reset metadata tag in dxpl_id */
+ H5_END_TAG(FAIL);
+
+done:
+ /* Release resources */
+ if(bt2_name && H5B2_close(bt2_name, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index")
+ if(bt2_corder && H5B2_close(bt2_corder, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index")
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_attr_dense_info_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_check_msg_marked_test
+ PURPOSE
+ Check if an unknown message with the "mark if unknown" flag actually gets
+ marked.
+ USAGE
+ herr_t H5O_check_msg_marked_test(oid, flag_val)
+ hid_t oid; IN: Object to check
+ hbool_t flag_val; IN: Desired flag value
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Locates the "unknown" message and checks that the "was unknown" flag is set
+ correctly.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_check_msg_marked_test(hid_t oid, hbool_t flag_val)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ H5O_mesg_t *idx_msg; /* Pointer to message */
+ unsigned idx; /* Index of message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Locate "unknown" message */
+ for(idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
+ if(idx_msg->type->id == H5O_UNKNOWN_ID) {
+ /* Check for "unknown" message having the correct flags */
+ if(((idx_msg->flags & H5O_MSG_FLAG_WAS_UNKNOWN) > 0) != flag_val)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "'unknown' message has incorrect 'was unknown' flag value")
+
+ /* Break out of loop, to indicate that the "unknown" message was found */
+ break;
+ } /* end if */
+
+ /* Check for not finding an "unknown" message */
+ if(idx == oh->nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "'unknown' message type not found")
+
+done:
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_check_msg_marked_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_expunge_chunks_test
+ PURPOSE
+ Expunge all the chunks for an object header from the cache.
+ USAGE
+ herr_t H5O_expunge_chunks_test(f, dxpl_id, loc)
+ H5F_t *f; IN: Pointer to file that object is within
+ hid_t dxpl_id; IN: DXPL to use for operation
+ H5O_loc_t *loc; IN: Object location for object header to expunge
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Iterates over all the chunks for an object header an expunges each from the
+ metadata cache.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_expunge_chunks_test(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5O_t *oh = NULL; /* Object header */
+ haddr_t chk_addr[16]; /* Array of chunk addresses */
+ size_t nchunks; /* Number of chunks in object header */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Safety check */
+ nchunks = oh->nchunks;
+ HDassert(0 < nchunks && nchunks < NELMTS(chk_addr));
+
+ /* Iterate over all the chunks, saving the chunk addresses */
+ for(u = 0; u < oh->nchunks; u++)
+ chk_addr[u] = oh->chunk[u].addr;
+
+ /* Release the object header */
+ if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header")
+
+ /* Iterate over all the saved chunk addresses, evicting them from the cache */
+ /* (in reverse order, so that chunk #0 is unpinned) */
+ for(u = nchunks - 1; u < nchunks; u--)
+ if(H5AC_expunge_entry(loc->file, dxpl_id, (u == 0 ? H5AC_OHDR : H5AC_OHDR_CHK), chk_addr[u], H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTEXPUNGE, FAIL, "unable to expunge object header chunk")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_expunge_chunks_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_get_rc
+ PURPOSE
+ Retrieve the refcount for the object header
+ USAGE
+ herr_t H5O_expunge_chunks_test(loc, dxpl_id, rc)
+ const H5O_loc_t *loc; IN: Object location for object header to query
+ hid_t dxpl_id; IN: DXPL to use for operation
+ unsigned *rc; OUT: Pointer to refcount for object header
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Protects object header, retrieves the object header's refcount, and
+ unprotects object header.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_get_rc(const H5O_loc_t *loc, hid_t dxpl_id, unsigned *rc)
+{
+ H5O_t *oh = NULL; /* Object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(loc);
+ HDassert(rc);
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header")
+
+ /* Save the refcount for the object header */
+ *rc = oh->nlink;
+
+done:
+ /* Release the object header */
+ if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_expunge_chunks_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_msg_get_chunkno_test
+ PURPOSE
+ Retrieve the chunk number for an object header message of a given type.
+ USAGE
+ herr_t H5O_check_msg_marked_test(oid, chunk_num)
+ hid_t oid; IN: Object to check
+ unsigned msg_type; IN: Object header message type to check
+ unsigned *chunk_num; OUT: Object header chunk that the message is in
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the chunk number for the first object header message of a given
+ type found in an object's header.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_msg_get_chunkno_test(hid_t oid, unsigned msg_type, unsigned *chunk_num)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ H5O_mesg_t *idx_msg; /* Pointer to message */
+ unsigned idx; /* Index of message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Locate first message of given type */
+ for(idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
+ if(idx_msg->type->id == msg_type) {
+ /* Set the chunk number for the message */
+ *chunk_num = idx_msg->chunkno;
+
+ /* Break out of loop, to indicate that the message was found */
+ break;
+ } /* end if */
+
+ /* Check for not finding a message of the given type*/
+ if(idx == oh->nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message of type not found")
+
+done:
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_msg_get_chunkno_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5O_msg_move_to_new_chunk_test
+ PURPOSE
+ Move a message into a new chunk
+ USAGE
+ herr_t H5O_msg_move_to_new_chunk_test(oid, msg_type)
+ hid_t oid; IN: Object to check
+ unsigned msg_type; IN: Object header message type to check
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves the first message of the given type to a new object header chunk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5O_msg_move_to_new_chunk_test(hid_t oid, unsigned msg_type)
+{
+ H5O_t *oh = NULL; /* Object header */
+ H5O_loc_t *loc; /* Pointer to object's location */
+ H5O_mesg_t *curr_msg; /* Pointer to current message */
+ unsigned idx; /* Index of message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object location for object */
+ if(NULL == (loc = H5O_get_loc(oid)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found")
+
+ /* Get the object header */
+ if(NULL == (oh = H5O_protect(loc, H5AC_ind_read_dxpl_id, H5AC__NO_FLAGS_SET, FALSE)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
+
+ /* Locate first message of given type */
+ for(idx = 0, curr_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, curr_msg++)
+ if(curr_msg->type->id == msg_type) {
+ H5O_msg_alloc_info_t found_msg; /* Information about message to move */
+ unsigned msg_chunkno = curr_msg->chunkno; /* Chunk that the message is in */
+ uint8_t *end_chunk_data = (oh->chunk[msg_chunkno].image + oh->chunk[msg_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[msg_chunkno].gap); /* End of message data in chunk */
+ uint8_t *end_msg = curr_msg->raw + curr_msg->raw_size; /* End of current message */
+ size_t gap_size = 0; /* Size of gap after current message */
+ size_t null_size = 0; /* Size of NULL message after current message */
+ unsigned null_msgno = 0; /* Index of NULL message after current message */
+ size_t total_size; /* Total size of available space "around" current message */
+ size_t new_idx; /* Index of new null message */
+
+ /* Check if the message is the last one in the chunk */
+ if(end_msg == end_chunk_data)
+ gap_size = oh->chunk[msg_chunkno].gap;
+ else {
+ H5O_mesg_t *tmp_msg; /* Temp. pointer to message to operate on */
+ unsigned v; /* Local index variable */
+
+ /* Check for null message after this message, in same chunk */
+ for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) {
+ if(tmp_msg->type->id == H5O_NULL_ID && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == end_msg) {
+ null_msgno = v;
+ null_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + tmp_msg->raw_size;
+ break;
+ } /* end if */
+
+ /* XXX: Should also check for NULL message in front of current message... */
+
+ } /* end for */
+ } /* end else */
+
+ /* Add up current message's total available space */
+ total_size = curr_msg->raw_size + gap_size + null_size;
+
+ /* Set up "found message" info for moving the message */
+ found_msg.msgno = (int)idx;
+ found_msg.id = curr_msg->type->id;
+ found_msg.chunkno = msg_chunkno;
+ found_msg.gap_size = gap_size;
+ found_msg.null_size = null_size;
+ found_msg.total_size = total_size;
+ found_msg.null_msgno = null_msgno;
+
+ /* Allocate and initialize new chunk in the file, moving the found message */
+ /* (*new_idx returned from this routine is unused here) */
+ if(H5O__alloc_chunk(loc->file, H5AC_ind_read_dxpl_id, oh, 40, oh->nmesgs, &found_msg, &new_idx) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate new object header chunk")
+
+ /* Break out of loop, the message was found */
+ break;
+ } /* end if */
+
+done:
+ if(oh && H5O_unprotect(loc, H5AC_ind_read_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_msg_get_chunkno_test() */
+
diff --git a/src/H5Ounknown.c b/src/H5Ounknown.c
new file mode 100644
index 0000000..1b3a997
--- /dev/null
+++ b/src/H5Ounknown.c
@@ -0,0 +1,88 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Ounknown.c
+ * Apr 19 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Handle unknown message classes in a minimal way.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "H5Omodule.h" /* This source code file is part of the H5O module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5O_unknown_free(void *_mesg);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_UNKNOWN[1] = {{
+ H5O_UNKNOWN_ID, /*message id number */
+ "unknown", /*message name for debugging */
+ 0, /*native message size */
+ 0, /* messages are sharable? */
+ NULL, /*decode message */
+ NULL, /*encode message */
+ NULL, /*copy the native value */
+ NULL, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_unknown_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ NULL, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ NULL /*debug the message */
+}};
+
+/* Declare a free list to manage the H5O_unknown_t struct */
+H5FL_DEFINE(H5O_unknown_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_unknown_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_unknown_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(mesg);
+
+ mesg = H5FL_FREE(H5O_unknown_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_unknown_free() */
+
diff --git a/src/H5P.c b/src/H5P.c
new file mode 100644
index 0000000..49bea0a
--- /dev/null
+++ b/src/H5P.c
@@ -0,0 +1,1657 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Generic Property Functions
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for property iterator callback */
+typedef struct {
+ H5P_iterate_t iter_func; /* Iterator callback */
+ hid_t id; /* Property list or class ID */
+ void *iter_data; /* Iterator callback pointer */
+} H5P_iter_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pcopy
+ PURPOSE
+ Routine to copy a property list or class
+ USAGE
+ hid_t H5Pcopy(id)
+ hid_t id; IN: Property list or class ID to copy
+ RETURNS
+ Success: valid property list ID on success (non-negative)
+ Failure: negative
+ DESCRIPTION
+ Copy a property list or class and return the ID. This routine calls the
+ class 'copy' callback after any property 'copy' callbacks are called
+ (assuming all property 'copy' callbacks return successfully).
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pcopy(hid_t id)
+{
+ void *obj; /* Property object to copy */
+ hid_t ret_value=FALSE; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", id);
+
+ if(H5P_DEFAULT==id)
+ HGOTO_DONE(H5P_DEFAULT);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(id) && H5I_GENPROP_CLS != H5I_get_type(id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property object");
+ if(NULL == (obj = H5I_object(id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property object doesn't exist");
+
+ /* Compare property lists */
+ if(H5I_GENPROP_LST == H5I_get_type(id)) {
+ if((ret_value = H5P_copy_plist((H5P_genplist_t *)obj, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property list");
+ } /* end if */
+ /* Must be property classes */
+ else {
+ H5P_genclass_t *copy_class; /* Copy of class */
+
+ /* Copy the class */
+ if((copy_class = H5P_copy_pclass((H5P_genclass_t *)obj)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property class");
+
+ /* Get an atom for the copied class */
+ if((ret_value = H5I_register(H5I_GENPROP_CLS, copy_class, TRUE)) < 0) {
+ H5P_close_class(copy_class);
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list class");
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pcopy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pcreate_class
+ PURPOSE
+ Create a new property list class.
+ USAGE
+ hid_t H5Pcreate_class(parent, name, cls_create, create_data,
+ cls_close, close_data)
+ hid_t parent; IN: Property list class ID of parent class
+ const char *name; IN: Name of class we are creating
+ H5P_cls_create_func_t cls_create; IN: The callback function to call
+ when each property list in this class is
+ created.
+ void *create_data; IN: Pointer to user data to pass along to class
+ creation callback.
+ H5P_cls_copy_func_t cls_copy; IN: The callback function to call
+ when each property list in this class is
+ copied.
+ void *copy_data; IN: Pointer to user data to pass along to class
+ copy callback.
+ H5P_cls_close_func_t cls_close; IN: The callback function to call
+ when each property list in this class is
+ closed.
+ void *close_data; IN: Pointer to user data to pass along to class
+ close callback.
+ RETURNS
+ Returns a valid property list class ID on success, NULL on failure.
+ DESCRIPTION
+ Allocates memory and attaches a class to the property list class hierarchy.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pcreate_class(hid_t parent, const char *name,
+ H5P_cls_create_func_t cls_create, void *create_data,
+ H5P_cls_copy_func_t cls_copy, void *copy_data,
+ H5P_cls_close_func_t cls_close, void *close_data
+ )
+{
+ H5P_genclass_t *par_class = NULL; /* Pointer to the parent class */
+ H5P_genclass_t *pclass = NULL; /* Property list class created */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("i", "i*sx*xx*xx*x", parent, name, cls_create, create_data, cls_copy,
+ copy_data, cls_close, close_data);
+
+ /* Check arguments. */
+ if(H5P_DEFAULT!=parent && (H5I_GENPROP_CLS!=H5I_get_type(parent)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid class name")
+ if((create_data != NULL && cls_create == NULL)
+ || (copy_data != NULL && cls_copy == NULL)
+ || (close_data != NULL && cls_close == NULL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "data specified, but no callback provided")
+
+ /* Get the pointer to the parent class */
+ if(parent == H5P_DEFAULT)
+ par_class = NULL;
+ else if(NULL == (par_class = (H5P_genclass_t *)H5I_object(parent)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't retrieve parent class")
+
+ /* Create the new property list class */
+ if(NULL == (pclass = H5P_create_class(par_class, name, H5P_TYPE_USER, cls_create, create_data, cls_copy, copy_data, cls_close, close_data)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create property list class")
+
+ /* Get an atom for the class */
+ if((ret_value = H5I_register(H5I_GENPROP_CLS, pclass, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list class")
+
+done:
+ if(ret_value < 0 && pclass)
+ H5P_close_class(pclass);
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pcreate_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pcreate
+ PURPOSE
+ Routine to create a new property list of a property list class.
+ USAGE
+ hid_t H5Pcreate(cls_id)
+ hid_t cls_id; IN: Property list class create list from
+ RETURNS
+ Returns a valid property list ID on success, FAIL on failure.
+ DESCRIPTION
+ Creates a property list of a given class. If a 'create' callback
+ exists for the property list class, it is called before the
+ property list is passed back to the user. If 'create' callbacks exist for
+ any individual properties in the property list, they are called before the
+ class 'create' callback.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pcreate(hid_t cls_id)
+{
+ H5P_genclass_t *pclass; /* Property list class to modify */
+ hid_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", cls_id);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(cls_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class");
+
+ /* Create the new property list */
+ if((ret_value = H5P_create_id(pclass, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create property list");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pcreate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pregister2
+ PURPOSE
+ Routine to register a new property in a property list class.
+ USAGE
+ herr_t H5Pregister2(class, name, size, default, prp_create, prp_set, prp_get, prp_close)
+ hid_t class; IN: Property list class to close
+ const char *name; IN: Name of property to register
+ size_t size; IN: Size of property in bytes
+ void *def_value; IN: Pointer to buffer containing default value
+ for property in newly created property lists
+ H5P_prp_create_func_t prp_create; IN: Function pointer to property
+ creation callback
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Registers a new property with a property list class. The property will
+ exist in all property list objects of that class after this routine is
+ finished. The name of the property must not already exist. The default
+ property value must be provided and all new property lists created with this
+ property will have the property value set to the default provided. Any of
+ the callback routines may be set to NULL if they are not needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'default' pointer for a
+ zero-sized property may be set to NULL. The property 'create' & 'close'
+ callbacks are called for zero-sized properties, but the 'set' and 'get'
+ callbacks are never called.
+
+ The 'create' callback is called when a new property list with this
+ property is being created. H5P_prp_create_func_t is defined as:
+ typedef herr_t (*H5P_prp_create_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *initial_value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being created.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *initial_value; IN/OUT: The initial value for the property being created.
+ (The 'default' value passed to H5Pregister2)
+ The 'create' routine may modify the value to be set and those changes will
+ be stored as the initial value of the property. If the 'create' routine
+ returns a negative value, the new property value is not copied into the
+ property and the property list creation routine returns an error value.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pregister2(hid_t cls_id, const char *name, size_t size, void *def_value,
+ H5P_prp_create_func_t prp_create, H5P_prp_set_func_t prp_set,
+ H5P_prp_get_func_t prp_get, H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close)
+{
+ H5P_genclass_t *pclass; /* Property list class to modify */
+ H5P_genclass_t *orig_pclass; /* Original property class */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE11("e", "i*sz*xxxxxxxx", cls_id, name, size, def_value, prp_create,
+ prp_set, prp_get, prp_delete, prp_copy, prp_cmp, prp_close);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(cls_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid class name")
+ if(size > 0 && def_value == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "properties >0 size must have default")
+
+ /* Create the new property list class */
+ orig_pclass = pclass;
+ if((ret_value = H5P_register(&pclass, name, size, def_value, prp_create, prp_set, prp_get, NULL, NULL, prp_delete, prp_copy, prp_cmp, prp_close)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to register property in class")
+
+ /* Check if the property class changed and needs to be substituted in the ID */
+ if(pclass != orig_pclass) {
+ H5P_genclass_t *old_pclass; /* Old property class */
+
+ /* Substitute the new property class in the ID */
+ if(NULL == (old_pclass = (H5P_genclass_t *)H5I_subst(cls_id, pclass)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to substitute property class in ID")
+ HDassert(old_pclass == orig_pclass);
+
+ /* Close the previous class */
+ if(H5P_close_class(old_pclass) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "unable to close original property class after substitution")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pregister2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pinsert2
+ PURPOSE
+ Routine to insert a new property in a property list.
+ USAGE
+ herr_t H5Pinsert2(plist, name, size, value, prp_set, prp_get, prp_close)
+ hid_t plist; IN: Property list to add property to
+ const char *name; IN: Name of property to add
+ size_t size; IN: Size of property in bytes
+ void *value; IN: Pointer to the value for the property
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Inserts a temporary property into a property list. The property will
+ exist only in this property list object. The name of the property must not
+ already exist. The value must be provided unless the property is zero-
+ sized. Any of the callback routines may be set to NULL if they are not
+ needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'value' pointer for a
+ zero-sized property may be set to NULL. The property 'close' callback is
+ called for zero-sized properties, but the 'set' and 'get' callbacks are
+ never called.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ There is no 'create' callback routine for temporary property list
+ objects, the initial value is assumed to have any necessary setup already
+ performed on it.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pinsert2(hid_t plist_id, const char *name, size_t size, void *value,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close)
+{
+ H5P_genplist_t *plist; /* Property list to modify */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE10("e", "i*sz*xxxxxxx", plist_id, name, size, value, prp_set, prp_get,
+ prp_delete, prp_copy, prp_cmp, prp_close);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name")
+ if(size > 0 && value == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "properties >0 size must have default")
+
+ /* Create the new property list class */
+ if((ret_value = H5P_insert(plist, name, size, value, prp_set, prp_get,
+ NULL, NULL, prp_delete, prp_copy, prp_cmp, prp_close)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to register property in plist")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pinsert2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pset
+ PURPOSE
+ Routine to set a property's value in a property list.
+ USAGE
+ herr_t H5Pset(plist_id, name, value)
+ hid_t plist_id; IN: Property list to find property in
+ const char *name; IN: Name of property to set
+ void *value; IN: Pointer to the value for the property
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Sets a new value for a property in a property list. The property name
+ must exist or this routine will fail. If there is a 'set' callback routine
+ registered for this property, the 'value' will be passed to that routine and
+ any changes to the 'value' will be used when setting the property value.
+ The information pointed at by the 'value' pointer (possibly modified by the
+ 'set' callback) is copied into the property list value and may be changed
+ by the application making the H5Pset call without affecting the property
+ value.
+
+ If the 'set' callback routine returns an error, the property value will
+ not be modified. This routine may not be called for zero-sized properties
+ and will return an error in that case.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pset(hid_t plist_id, const char *name, const void *value)
+{
+ H5P_genplist_t *plist; /* Property list to modify */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*x", plist_id, name, value);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+ if(value == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalied property value");
+
+ /* Go set the value */
+ if(H5P_set(plist, name, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to set value in plist");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pexist
+ PURPOSE
+ Routine to query the existance of a property in a property object.
+ USAGE
+ htri_t H5P_exist(id, name)
+ hid_t id; IN: Property object ID to check
+ const char *name; IN: Name of property to check for
+ RETURNS
+ Success: Positive if the property exists in the property object, zero
+ if the property does not exist.
+ Failure: negative value
+ DESCRIPTION
+ This routine checks if a property exists within a property list or
+ class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5Pexist(hid_t id, const char *name)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ H5P_genclass_t *pclass; /* Property class to query */
+ htri_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "i*s", id, name);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(id) && H5I_GENPROP_CLS != H5I_get_type(id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+
+ /* Check for the existance of the property in the list or class */
+ if(H5I_GENPROP_LST == H5I_get_type(id)) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if((ret_value = H5P_exist_plist(plist, name)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property does not exist in list");
+ } /* end if */
+ else
+ if(H5I_GENPROP_CLS == H5I_get_type(id)) {
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class");
+ if((ret_value = H5P_exist_pclass(pclass, name)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property does not exist in class");
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pexist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget_size
+ PURPOSE
+ Routine to query the size of a property in a property list or class.
+ USAGE
+ herr_t H5Pget_size(id, name)
+ hid_t id; IN: ID of property list or class to check
+ const char *name; IN: Name of property to query
+ size_t *size; OUT: Size of property
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the size of a property's value in bytes. Zero-
+ sized properties are allowed and return a value of 0. This function works
+ for both property lists and classes.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pget_size(hid_t id, const char *name, size_t *size)
+{
+ H5P_genclass_t *pclass; /* Property class to query */
+ H5P_genplist_t *plist; /* Property list to query */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*z", id, name, size);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(id) && H5I_GENPROP_CLS != H5I_get_type(id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+ if(size==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property size");
+
+ if(H5I_GENPROP_LST == H5I_get_type(id)) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+
+ /* Check the property size */
+ if((ret_value = H5P_get_size_plist(plist, name, size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to query size in plist");
+ } /* end if */
+ else
+ if(H5I_GENPROP_CLS == H5I_get_type(id)) {
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+
+ /* Check the property size */
+ if((ret_value = H5P_get_size_pclass(pclass, name, size)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to query size in plist");
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pencode
+ PURPOSE
+ Routine to convert the property values in a property list into a binary buffer
+ USAGE
+ herr_t H5Pencode(plist_id, buf, nalloc)
+ hid_t plist_id; IN: Identifier to property list to encode
+ void *buf: OUT: buffer to gold the encoded plist
+ size_t *nalloc; IN/OUT: size of buffer needed to encode plist
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Encodes a property list into a binary buffer. If the buffer is NULL, then
+ the call will set the size needed to encode the plist in nalloc. Otherwise
+ the routine will encode the plist in buf.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pencode(hid_t plist_id, void *buf, size_t *nalloc)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x*z", plist_id, buf, nalloc);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+
+ /* Call the internal encode routine */
+ if((ret_value = H5P__encode(plist, TRUE, buf, nalloc)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "unable to encode property list");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pencode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pdecode
+ PURPOSE
+ API routine to decode a property list from a binary buffer.
+ USAGE
+ hid_t H5Pdecode(buf)
+ void *buf; IN: buffer that holds the encoded plist
+ RETURNS
+ Returns non-negative ID of new property list object on success, negative
+ on failure.
+ DESCRIPTION
+ Decodes a property list from a binary buffer. The contents of the buffer
+ contain the values for the correponding properties of the plist. The decode
+ callback of a certain property decodes its value from the buffer and sets it
+ in the property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Properties in the property list that are not encoded in the serialized
+ form retain their default value.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pdecode(const void *buf)
+{
+ hid_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "*x", buf);
+
+ /* Call the internal decode routine */
+ if((ret_value = H5P__decode(buf)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "unable to decode property list");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pdecode() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget_class
+ PURPOSE
+ Routine to query the class of a generic property list
+ USAGE
+ hid_t H5Pget_class(plist_id)
+ hid_t plist_id; IN: Property list to query
+ RETURNS
+ Success: ID of class object
+ Failure: negative
+ DESCRIPTION
+ This routine retrieves the class of a property list.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Change the name of this function to H5Pget_class (and remove old H5Pget_class)
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pget_class(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ H5P_genclass_t *pclass=NULL; /* Property list class */
+ hid_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", plist_id);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+
+ /* Retrieve the property list class */
+ if((pclass = H5P_get_class(plist)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "unable to query class of property list");
+
+ /* Increment the outstanding references to the class object */
+ if(H5P_access_class(pclass, H5P_MOD_INC_REF) < 0)
+ HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Can't increment class ID ref count");
+
+ /* Get an atom for the class */
+ if((ret_value = H5I_register(H5I_GENPROP_CLS, pclass, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list class");
+
+done:
+ if(ret_value<0 && pclass)
+ H5P_close_class(pclass);
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget_nprops
+ PURPOSE
+ Routine to query the size of a property in a property list or class.
+ USAGE
+ herr_t H5Pget_nprops(id, nprops)
+ hid_t id; IN: ID of Property list or class to check
+ size_t *nprops; OUT: Number of properties in the property object
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the number of properties in a property list or
+ class. If a property class ID is given, the number of registered properties
+ in the class is returned in NPROPS. If a property list ID is given, the
+ current number of properties in the list is returned in NPROPS.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pget_nprops(hid_t id, size_t *nprops)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ H5P_genclass_t *pclass; /* Property class to query */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*z", id, nprops);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(id) && H5I_GENPROP_CLS != H5I_get_type(id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+ if(nprops==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property nprops pointer");
+
+ if(H5I_GENPROP_LST == H5I_get_type(id)) {
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if(H5P_get_nprops_plist(plist, nprops) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to query # of properties in plist");
+ } /* end if */
+ else
+ if(H5I_GENPROP_CLS == H5I_get_type(id)) {
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class");
+ if(H5P_get_nprops_pclass(pclass, nprops, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to query # of properties in pclass");
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_nprops() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pequal
+ PURPOSE
+ Routine to query whether two property lists or two property classes are equal
+ USAGE
+ htri_t H5Pequal(id1, id2)
+ hid_t id1; IN: Property list or class ID to compare
+ hid_t id2; IN: Property list or class ID to compare
+ RETURNS
+ Success: TRUE if equal, FALSE if unequal
+ Failure: negative
+ DESCRIPTION
+ Determines whether two property lists or two property classes are equal.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5Pequal(hid_t id1, hid_t id2)
+{
+ void *obj1, *obj2; /* Property objects to compare */
+ htri_t ret_value = FALSE; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "ii", id1, id2);
+
+ /* Check arguments. */
+ if((H5I_GENPROP_LST != H5I_get_type(id1) && H5I_GENPROP_CLS != H5I_get_type(id1))
+ || (H5I_GENPROP_LST != H5I_get_type(id2) && H5I_GENPROP_CLS != H5I_get_type(id2)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property objects")
+ if(H5I_get_type(id1) != H5I_get_type(id2))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not the same kind of property objects")
+ if(NULL == (obj1 = H5I_object(id1)) || NULL == (obj2 = H5I_object(id2)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property object doesn't exist")
+
+ /* Compare property lists */
+ if(H5I_GENPROP_LST == H5I_get_type(id1)) {
+ int cmp_ret = 0;
+
+ if(H5P_cmp_plist((const H5P_genplist_t *)obj1, (const H5P_genplist_t *)obj2, &cmp_ret) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOMPARE, FAIL, "can't compare property lists")
+
+ /* Set return value */
+ ret_value = cmp_ret == 0 ? TRUE : FALSE;
+ } /* end if */
+ /* Must be property classes */
+ else {
+ if(H5P_cmp_class((const H5P_genclass_t *)obj1, (const H5P_genclass_t *)obj2) == 0)
+ ret_value = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pequal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pisa_class
+ PURPOSE
+ Routine to query whether a property list is a certain class
+ USAGE
+ hid_t H5Pisa_class(plist_id, pclass_id)
+ hid_t plist_id; IN: Property list to query
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: TRUE (1) or FALSE (0)
+ Failure: negative
+ DESCRIPTION
+ This routine queries whether a property list is a member of the property
+ list class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ What about returning a value indicating that the property class is further
+ up the class hierarchy?
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5Pisa_class(hid_t plist_id, hid_t pclass_id)
+{
+ htri_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "ii", plist_id, pclass_id);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(plist_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if(H5I_GENPROP_CLS != H5I_get_type(pclass_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class");
+
+ /* Compare the property list's class against the other class */
+ if((ret_value = H5P_isa_class(plist_id, pclass_id)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to compare property list classes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pisa_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__iterate_cb
+ PURPOSE
+ Internal callback routine when iterating over properties in property list
+ or class
+ USAGE
+ int H5P__iterate_cb(prop, udata)
+ H5P_genprop_t *prop; IN: Pointer to the property
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC
+ Failure: negative value
+ DESCRIPTION
+ This routine calls the actual callback routine for the property in the
+property list or class.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__iterate_cb(H5P_genprop_t *prop, void *_udata)
+{
+ H5P_iter_ud_t *udata = (H5P_iter_ud_t *)_udata; /* Pointer to user data */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(prop);
+ HDassert(udata);
+
+ /* Call the user's callback routine */
+ ret_value = (*udata->iter_func)(udata->id, prop->name, udata->iter_data);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__iterate_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Piterate
+ PURPOSE
+ Routine to iterate over the properties in a property list or class
+ USAGE
+ int H5Piterate(pclass_id, idx, iter_func, iter_data)
+ hid_t id; IN: ID of property object to iterate over
+ int *idx; IN/OUT: Index of the property to begin with
+ H5P_iterate_t iter_func; IN: Function pointer to function to be
+ called with each property iterated over.
+ void *iter_data; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC if it was
+ non-zero, or zero if all properties have been processed.
+ Failure: negative value
+ DESCRIPTION
+ This routine iterates over the properties in the property object specified
+with ID. The properties in both property lists and classes may be iterated
+over with this function. For each property in the object, the ITER_DATA and
+some additional information, specified below, are passed to the ITER_FUNC
+function. The iteration begins with the IDX property in the object and the
+next element to be processed by the operator is returned in IDX. If IDX is
+NULL, then the iterator starts at the first property; since no stopping point
+is returned in this case, the iterator cannot be restarted if one of the calls
+to its operator returns non-zero. The IDX value is 0-based (ie. to start at
+the "first" property, the IDX value should be 0).
+
+The prototype for H5P_iterate_t is:
+ typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data);
+The operation receives the property list or class identifier for the object
+being iterated over, ID, the name of the current property within the object,
+NAME, and the pointer to the operator data passed in to H5Piterate, ITER_DATA.
+
+The return values from an operator are:
+ Zero causes the iterator to continue, returning zero when all properties
+ have been processed.
+ Positive causes the iterator to immediately return that positive value,
+ indicating short-circuit success. The iterator can be restarted at the
+ index of the next property.
+ Negative causes the iterator to immediately return that value, indicating
+ failure. The iterator can be restarted at the index of the next
+ property.
+
+H5Piterate assumes that the properties in the object identified by ID remains
+unchanged through the iteration. If the membership changes during the
+iteration, the function's behavior is undefined.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_data)
+{
+ H5P_iter_ud_t udata; /* User data for internal iterator callback */
+ int fake_idx = 0; /* Index when user doesn't provide one */
+ void *obj; /* Property object to copy */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Is", "i*Isx*x", id, idx, iter_func, iter_data);
+
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(id) && H5I_GENPROP_CLS != H5I_get_type(id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+ if(NULL == (obj = H5I_object(id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property object doesn't exist");
+ if(iter_func == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration callback");
+
+ /* Set up user data */
+ udata.iter_func = iter_func;
+ udata.id = id;
+ udata.iter_data = iter_data;
+
+ if(H5I_GENPROP_LST == H5I_get_type(id)) {
+ /* Iterate over a property list */
+ if((ret_value = H5P_iterate_plist((H5P_genplist_t *)obj, TRUE, (idx ? idx : &fake_idx), H5P__iterate_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to iterate over list");
+ } /* end if */
+ else
+ if(H5I_GENPROP_CLS == H5I_get_type(id)) {
+ /* Iterate over a property class */
+ if((ret_value = H5P_iterate_pclass((H5P_genclass_t *)obj, (idx ? idx : &fake_idx), H5P__iterate_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to iterate over class");
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property object");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Piterate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget
+ PURPOSE
+ Routine to query the value of a property in a property list.
+ USAGE
+ herr_t H5Pget(plist_id, name, value)
+ hid_t plist_id; IN: Property list to check
+ const char *name; IN: Name of property to query
+ void *value; OUT: Pointer to the buffer for the property value
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Retrieves a copy of the value for a property in a property list. The
+ property name must exist or this routine will fail. If there is a
+ 'get' callback routine registered for this property, the copy of the
+ value of the property will first be passed to that routine and any changes
+ to the copy of the value will be used when returning the property value
+ from this routine.
+ If the 'get' callback routine returns an error, 'value' will not be
+ modified and this routine will return an error. This routine may not be
+ called for zero-sized properties.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pget(hid_t plist_id, const char *name, void *value)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*x", plist_id, name, value);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+ if(value==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalied property value");
+
+ /* Go get the value */
+ if(H5P_get(plist,name,value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Premove
+ PURPOSE
+ Routine to remove a property from a property list.
+ USAGE
+ herr_t H5Premove(plist_id, name)
+ hid_t plist_id; IN: Property list to modify
+ const char *name; IN: Name of property to remove
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Removes a property from a property list. Both properties which were
+ in existance when the property list was created (i.e. properties registered
+ with H5Pregister2) and properties added to the list after it was created
+ (i.e. added with H5Pinsert2) may be removed from a property list.
+ Properties do not need to be removed a property list before the list itself
+ is closed, they will be released automatically when H5Pclose is called.
+ The 'close' callback for this property is called before the property is
+ release, if the callback exists.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Premove(hid_t plist_id, const char *name)
+{
+ H5P_genplist_t *plist; /* Property list to modify */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", plist_id, name);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+
+ /* Create the new property list class */
+ if((ret_value = H5P_remove(plist, name)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Premove() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pcopy_prop
+ PURPOSE
+ Routine to copy a property from one list or class to another
+ USAGE
+ herr_t H5Pcopy_prop(dst_id, src_id, name)
+ hid_t dst_id; IN: ID of destination property list or class
+ hid_t src_id; IN: ID of source property list or class
+ const char *name; IN: Name of property to copy
+ RETURNS
+ Success: non-negative value.
+ Failure: negative value.
+ DESCRIPTION
+ Copies a property from one property list or class to another.
+
+ If a property is copied from one class to another, all the property
+ information will be first deleted from the destination class and then the
+ property information will be copied from the source class into the
+ destination class.
+
+ If a property is copied from one list to another, the property will be
+ first deleted from the destination list (generating a call to the 'close'
+ callback for the property, if one exists) and then the property is copied
+ from the source list to the destination list (generating a call to the
+ 'copy' callback for the property, if one exists).
+
+ If the property does not exist in the destination class or list, this call
+ is equivalent to calling H5Pregister2 or H5Pinsert2 (for a class or list, as
+ appropriate) and the 'create' callback will be called in the case of the
+ property being copied into a list (if such a callback exists for the
+ property).
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pcopy_prop(hid_t dst_id, hid_t src_id, const char *name)
+{
+ H5I_type_t src_id_type, dst_id_type; /* ID types */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii*s", dst_id, src_id, name);
+
+ /* Check arguments. */
+ if((src_id_type = H5I_get_type(src_id)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid source ID")
+ if((dst_id_type = H5I_get_type(dst_id)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid destination ID")
+ if((H5I_GENPROP_LST != src_id_type && H5I_GENPROP_CLS != src_id_type)
+ || (H5I_GENPROP_LST != dst_id_type && H5I_GENPROP_CLS != dst_id_type))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not property objects")
+ if(src_id_type != dst_id_type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not the same kind of property objects")
+ if(!name || !*name)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "no name given")
+
+ /* Compare property lists */
+ if(H5I_GENPROP_LST == src_id_type) {
+ if(H5P_copy_prop_plist(dst_id, src_id, name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property between lists")
+ } /* end if */
+ /* Must be property classes */
+ else {
+ if(H5P_copy_prop_pclass(dst_id, src_id, name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property between classes")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pcopy_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Punregister
+ PURPOSE
+ Routine to remove a property from a property list class.
+ USAGE
+ herr_t H5Punregister(pclass_id, name)
+ hid_t pclass_id; IN: Property list class to modify
+ const char *name; IN: Name of property to remove
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Removes a property from a property list class. Future property lists
+ created of that class will not contain this property. Existing property
+ lists containing this property are not affected.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Punregister(hid_t pclass_id, const char *name)
+{
+ H5P_genclass_t *pclass; /* Property list class to modify */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", pclass_id, name);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(pclass_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name");
+
+ /* Remove the property list from class */
+ if((ret_value = H5P_unregister(pclass, name)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to remove property from class");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Punregister() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pclose
+ PURPOSE
+ Routine to close a property list.
+ USAGE
+ herr_t H5Pclose(plist_id)
+ hid_t plist_id; IN: Property list to close
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Closes a property list. If a 'close' callback exists for the property
+ list class, it is called before the property list is destroyed. If 'close'
+ callbacks exist for any individual properties in the property list, they are
+ called after the class 'close' callback.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pclose(hid_t plist_id)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", plist_id);
+
+ /* Allow default property lists to pass through without throwing an error */
+ if(H5P_DEFAULT != plist_id) {
+ /* Check arguments. */
+ if(H5I_GENPROP_LST != H5I_get_type(plist_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Close the property list */
+ if(H5I_dec_app_ref(plist_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't close")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pclose() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget_class_name
+ PURPOSE
+ Routine to query the name of a generic property list class
+ USAGE
+ char *H5Pget_class_name(pclass_id)
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: Pointer to a malloc'ed string containing the class name
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves the name of a generic property list class.
+ The pointer to the name must be free'd by the user for successful calls.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+char *
+H5Pget_class_name(hid_t pclass_id)
+{
+ H5P_genclass_t *pclass; /* Property class to query */
+ char *ret_value; /* return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE1("*s", "i", pclass_id);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(pclass_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property class");
+
+ /* Get the property list class name */
+ if((ret_value = H5P_get_class_name(pclass)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "unable to query name of class");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_class_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pget_class_parent
+ PURPOSE
+ routine to query the parent class of a generic property class
+ USAGE
+ hid_t H5Pget_class_parent(pclass_id)
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: ID of parent class object
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves an ID for the parent class of a property class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Pget_class_parent(hid_t pclass_id)
+{
+ H5P_genclass_t *pclass; /* Property class to query */
+ H5P_genclass_t *parent = NULL; /* Parent's property class */
+ hid_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", pclass_id);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(pclass_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class")
+
+ /* Retrieve the property class's parent */
+ if(NULL == (parent = H5P_get_class_parent(pclass)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "unable to query class of property list")
+
+ /* Increment the outstanding references to the class object */
+ if(H5P_access_class(parent, H5P_MOD_INC_REF) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL,"Can't increment class ID ref count")
+
+ /* Get an atom for the class */
+ if((ret_value = H5I_register(H5I_GENPROP_CLS, parent, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list class")
+
+done:
+ if(ret_value < 0 && parent)
+ H5P_close_class(parent);
+
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_class_parent() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pclose_class
+ PURPOSE
+ Close a property list class.
+ USAGE
+ herr_t H5Pclose_class(cls_id)
+ hid_t cls_id; IN: Property list class ID to class
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Releases memory and de-attach a class from the property list class hierarchy.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pclose_class(hid_t cls_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", cls_id);
+
+ /* Check arguments */
+ if(H5I_GENPROP_CLS != H5I_get_type(cls_id))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class")
+
+ /* Close the property list class */
+ if(H5I_dec_app_ref(cls_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't close")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pclose_class() */
+
diff --git a/src/H5PB.c b/src/H5PB.c
new file mode 100644
index 0000000..52576f8
--- /dev/null
+++ b/src/H5PB.c
@@ -0,0 +1,1537 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5PB.c
+ *
+ * Purpose: Page Buffer routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5F_FRIEND /*suppress error about including H5Fpkg */
+#include "H5PBmodule.h" /* This source code file is part of the H5PB module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5PBpkg.h" /* File access */
+#include "H5SLprivate.h" /* Skip List */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#define H5PB__PREPEND(page_ptr, head_ptr, tail_ptr, len) { \
+ if((head_ptr) == NULL) { \
+ (head_ptr) = (page_ptr); \
+ (tail_ptr) = (page_ptr); \
+ } /* end if */ \
+ else { \
+ (head_ptr)->prev = (page_ptr); \
+ (page_ptr)->next = (head_ptr); \
+ (head_ptr) = (page_ptr); \
+ } /* end else */ \
+ (len)++; \
+} /* H5PB__PREPEND() */
+
+#define H5PB__REMOVE(page_ptr, head_ptr, tail_ptr, len) { \
+ if((head_ptr) == (page_ptr)) { \
+ (head_ptr) = (page_ptr)->next; \
+ if((head_ptr) != NULL) \
+ (head_ptr)->prev = NULL; \
+ } /* end if */ \
+ else \
+ (page_ptr)->prev->next = (page_ptr)->next; \
+ if((tail_ptr) == (page_ptr)) { \
+ (tail_ptr) = (page_ptr)->prev; \
+ if((tail_ptr) != NULL) \
+ (tail_ptr)->next = NULL; \
+ } /* end if */ \
+ else \
+ (page_ptr)->next->prev = (page_ptr)->prev; \
+ page_ptr->next = NULL; \
+ page_ptr->prev = NULL; \
+ (len)--; \
+}
+
+#define H5PB__INSERT_LRU(page_buf, page_ptr) { \
+ HDassert(page_buf); \
+ HDassert(page_ptr); \
+ /* insert the entry at the head of the list. */ \
+ H5PB__PREPEND((page_ptr), (page_buf)->LRU_head_ptr, \
+ (page_buf)->LRU_tail_ptr, (page_buf)->LRU_list_len) \
+}
+
+#define H5PB__REMOVE_LRU(page_buf, page_ptr) { \
+ HDassert(page_buf); \
+ HDassert(page_ptr); \
+ /* remove the entry from the list. */ \
+ H5PB__REMOVE((page_ptr), (page_buf)->LRU_head_ptr, \
+ (page_buf)->LRU_tail_ptr, (page_buf)->LRU_list_len) \
+}
+
+#define H5PB__MOVE_TO_TOP_LRU(page_buf, page_ptr) { \
+ HDassert(page_buf); \
+ HDassert(page_ptr); \
+ /* Remove entry and insert at the head of the list. */ \
+ H5PB__REMOVE((page_ptr), (page_buf)->LRU_head_ptr, \
+ (page_buf)->LRU_tail_ptr, (page_buf)->LRU_list_len) \
+ H5PB__PREPEND((page_ptr), (page_buf)->LRU_head_ptr, \
+ (page_buf)->LRU_tail_ptr, (page_buf)->LRU_list_len) \
+}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Iteration context for destroying page buffer */
+typedef struct {
+ H5PB_t *page_buf;
+ hbool_t actual_slist;
+} H5PB_ud1_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5PB__insert_entry(H5PB_t *page_buf, H5PB_entry_t *page_entry);
+static htri_t H5PB__make_space(const H5F_io_info2_t *fio_info, H5PB_t *page_buf, H5FD_mem_t inserted_type);
+static herr_t H5PB__write_entry(const H5F_io_info2_t *fio_info, H5PB_entry_t *page_entry);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+/* Declare a free list to manage the H5PB_t struct */
+H5FL_DEFINE_STATIC(H5PB_t);
+
+/* Declare a free list to manage the H5PB_entry_t struct */
+H5FL_DEFINE_STATIC(H5PB_entry_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_reset_stats
+ *
+ * Purpose: This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ * Reset statistics collected for the page buffer layer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_reset_stats(H5PB_t *page_buf)
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(page_buf);
+
+ page_buf->accesses[0] = 0;
+ page_buf->accesses[1] = 0;
+ page_buf->hits[0] = 0;
+ page_buf->hits[1] = 0;
+ page_buf->misses[0] = 0;
+ page_buf->misses[1] = 0;
+ page_buf->evictions[0] = 0;
+ page_buf->evictions[1] = 0;
+ page_buf->bypasses[0] = 0;
+ page_buf->bypasses[1] = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5PB_reset_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_get_stats
+ *
+ * Purpose: This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ * Retrieve statistics collected about page accesses for the page buffer layer.
+ * --accesses: the number of metadata and raw data accesses to the page buffer layer
+ * --hits: the number of metadata and raw data hits in the page buffer layer
+ * --misses: the number of metadata and raw data misses in the page buffer layer
+ * --evictions: the number of metadata and raw data evictions from the page buffer layer
+ * --bypasses: the number of metadata and raw data accesses that bypass the page buffer layer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_get_stats(const H5PB_t *page_buf, unsigned accesses[2], unsigned hits[2],
+ unsigned misses[2], unsigned evictions[2], unsigned bypasses[2])
+{
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(page_buf);
+
+ accesses[0] = page_buf->accesses[0];
+ accesses[1] = page_buf->accesses[1];
+ hits[0] = page_buf->hits[0];
+ hits[1] = page_buf->hits[1];
+ misses[0] = page_buf->misses[0];
+ misses[1] = page_buf->misses[1];
+ evictions[0] = page_buf->evictions[0];
+ evictions[1] = page_buf->evictions[1];
+ bypasses[0] = page_buf->bypasses[0];
+ bypasses[1] = page_buf->bypasses[1];
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5PB_get_stats */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_print_stats()
+ *
+ * Purpose: This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ * Print out statistics collected for the page buffer layer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_print_stats(const H5PB_t *page_buf)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(page_buf);
+
+ printf("PAGE BUFFER STATISTICS:\n");
+
+ printf("******* METADATA\n");
+ printf("\t Total Accesses: %u\n", page_buf->accesses[0]);
+ printf("\t Hits: %u\n", page_buf->hits[0]);
+ printf("\t Misses: %u\n", page_buf->misses[0]);
+ printf("\t Evictions: %u\n", page_buf->evictions[0]);
+ printf("\t Bypasses: %u\n", page_buf->bypasses[0]);
+ printf("\t Hit Rate = %f%%\n", ((double)page_buf->hits[0]/(page_buf->accesses[0] - page_buf->bypasses[0]))*100);
+ printf("*****************\n\n");
+
+ printf("******* RAWDATA\n");
+ printf("\t Total Accesses: %u\n", page_buf->accesses[1]);
+ printf("\t Hits: %u\n", page_buf->hits[1]);
+ printf("\t Misses: %u\n", page_buf->misses[1]);
+ printf("\t Evictions: %u\n", page_buf->evictions[1]);
+ printf("\t Bypasses: %u\n", page_buf->bypasses[1]);
+ printf("\t Hit Rate = %f%%\n", ((double)page_buf->hits[1]/(page_buf->accesses[1]-page_buf->bypasses[0]))*100);
+ printf("*****************\n\n");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5PB_print_stats */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_create
+ *
+ * Purpose: Create and setup the PB on the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_create(H5F_t *f, size_t size, unsigned page_buf_min_meta_perc, unsigned page_buf_min_raw_perc)
+{
+ H5PB_t *page_buf = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Check args */
+ if(f->shared->fs_strategy != H5F_FSPACE_STRATEGY_PAGE)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "Enabling Page Buffering requires PAGE file space strategy")
+ /* round down the size if it is larger than the page size */
+ else if(size > f->shared->fs_page_size) {
+ hsize_t temp_size;
+
+ temp_size = (size / f->shared->fs_page_size) * f->shared->fs_page_size;
+ H5_CHECKED_ASSIGN(size, size_t, temp_size, hsize_t);
+ } /* end if */
+ else if(0 != size % f->shared->fs_page_size)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTINIT, FAIL, "Page Buffer size must be >= to the page size")
+
+ /* Allocate the new page buffering structure */
+ if(NULL == (page_buf = H5FL_CALLOC(H5PB_t)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ page_buf->max_size = size;
+ H5_CHECKED_ASSIGN(page_buf->page_size, size_t, f->shared->fs_page_size, hsize_t);
+ page_buf->min_meta_perc = page_buf_min_meta_perc;
+ page_buf->min_raw_perc = page_buf_min_raw_perc;
+
+ /* Calculate the minimum page count for metadata and raw data
+ * based on the fractions provided
+ */
+ page_buf->min_meta_count = (unsigned)((size * page_buf_min_meta_perc) / (f->shared->fs_page_size * 100));
+ page_buf->min_raw_count = (unsigned)((size * page_buf_min_raw_perc) / (f->shared->fs_page_size * 100));
+
+ if(NULL == (page_buf->slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTCREATE, FAIL, "can't create skip list")
+ if(NULL == (page_buf->mf_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTCREATE, FAIL, "can't create skip list")
+
+ if(NULL == (page_buf->page_fac = H5FL_fac_init(page_buf->page_size)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTINIT, FAIL, "can't create page factory")
+
+ f->shared->page_buf = page_buf;
+
+done:
+ if(ret_value < 0) {
+ if(page_buf != NULL) {
+ if(page_buf->slist_ptr != NULL)
+ H5SL_close(page_buf->slist_ptr);
+ if(page_buf->mf_slist_ptr != NULL)
+ H5SL_close(page_buf->mf_slist_ptr);
+ if(page_buf->page_fac != NULL)
+ H5FL_fac_term(page_buf->page_fac);
+ page_buf = H5FL_FREE(H5PB_t, page_buf);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB_create */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB__flush_cb
+ *
+ * Purpose: Callback to flush PB skiplist entries.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PB__flush_cb(void *item, void H5_ATTR_UNUSED *key, void *_op_data)
+{
+ H5PB_entry_t *page_entry = (H5PB_entry_t *)item; /* Pointer to page entry node */
+ const H5F_io_info2_t *fio_info = (const H5F_io_info2_t *)_op_data;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(page_entry);
+ HDassert(fio_info);
+
+ /* Flush the page if it's dirty */
+ if(page_entry->is_dirty)
+ if(H5PB__write_entry(fio_info, page_entry) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_WRITEERROR, FAIL, "file write failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB__flush_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_flush
+ *
+ * Purpose: Flush/Free all the PB entries to the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_flush(const H5F_io_info2_t *fio_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(fio_info->meta_dxpl);
+ HDassert(fio_info->raw_dxpl);
+
+ /* Flush all the entries in the PB skiplist, if we have write access on the file */
+ if(fio_info->f->shared->page_buf && (H5F_ACC_RDWR & H5F_INTENT(fio_info->f))) {
+ H5PB_t *page_buf = fio_info->f->shared->page_buf;
+
+ /* Iterate over all entries in page buffer skip list */
+ if(H5SL_iterate(page_buf->slist_ptr, H5PB__flush_cb, (void *)fio_info))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_BADITER, FAIL, "can't flush page buffer skip list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB_flush */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB__dest_cb
+ *
+ * Purpose: Callback to free PB skiplist entries.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PB__dest_cb(void *item, void H5_ATTR_UNUSED *key, void *_op_data)
+{
+ H5PB_entry_t *page_entry = (H5PB_entry_t *)item; /* Pointer to page entry node */
+ H5PB_ud1_t *op_data = (H5PB_ud1_t *)_op_data;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checking */
+ HDassert(page_entry);
+ HDassert(op_data);
+ HDassert(op_data->page_buf);
+
+ /* Remove entry from LRU list */
+ if(op_data->actual_slist) {
+ H5PB__REMOVE_LRU(op_data->page_buf, page_entry)
+ page_entry->page_buf_ptr = H5FL_FAC_FREE(op_data->page_buf->page_fac, page_entry->page_buf_ptr);
+ } /* end if */
+
+ /* Free page entry */
+ page_entry = H5FL_FREE(H5PB_entry_t, page_entry);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5PB__dest_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_dest
+ *
+ * Purpose: Flush and destroy the PB on the file if it exists.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_dest(const H5F_io_info2_t *fio_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ H5F_t *f; /* file pointer */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(fio_info);
+ f = fio_info->f;
+ HDassert(f);
+
+ /* flush and destroy the page buffer, if it exists */
+ if(f->shared->page_buf) {
+ H5PB_t *page_buf = f->shared->page_buf;
+ H5PB_ud1_t op_data; /* Iteration context */
+
+ if(H5PB_flush(fio_info)<0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTFLUSH, FAIL, "can't flush page buffer")
+
+ /* Set up context info */
+ op_data.page_buf = page_buf;
+
+ /* Destroy the skip list containing all the entries in the PB */
+ op_data.actual_slist = TRUE;
+ if(H5SL_destroy(page_buf->slist_ptr, H5PB__dest_cb, &op_data))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTCLOSEOBJ, FAIL, "can't destroy page buffer skip list")
+
+ /* Destroy the skip list containing the new entries */
+ op_data.actual_slist = FALSE;
+ if(H5SL_destroy(page_buf->mf_slist_ptr, H5PB__dest_cb, &op_data))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTCLOSEOBJ, FAIL, "can't destroy page buffer skip list")
+
+ /* Destroy the page factory */
+ if(H5FL_fac_term(page_buf->page_fac) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTRELEASE, FAIL, "can't destroy page buffer page factory")
+
+#ifdef QAK
+H5PB_print_stats(page_buf);
+#endif /* QAK */
+
+ f->shared->page_buf = H5FL_FREE(H5PB_t, page_buf);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB_dest */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_add_new_page
+ *
+ * Purpose: Add a new page to the new page skip list. This is called
+ * from the MF layer when a new page is allocated to
+ * indicate to the page buffer layer that a read of the page
+ * from the file is not necessary since it's an empty page.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_add_new_page(H5F_t *f, H5FD_mem_t type, haddr_t page_addr)
+{
+ H5PB_t *page_buf = f->shared->page_buf;
+ H5PB_entry_t *page_entry = NULL; /* pointer to the corresponding page entry */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(page_buf);
+
+ /* If there is an existing page, this means that at some point the
+ * file free space manager freed and re-allocated a page at the same
+ * address. No need to do anything here then...
+ */
+ /* MSC - to be safe, might want to dig in the MF layer and remove
+ * the page when it is freed from this list if it still exists and
+ * remove this check
+ */
+ if(NULL == H5SL_search(page_buf->mf_slist_ptr, &(page_addr))) {
+ /* Create the new PB entry */
+ if(NULL == (page_entry = H5FL_CALLOC(H5PB_entry_t)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Initialize page fields */
+ page_entry->addr = page_addr;
+ page_entry->type = (H5F_mem_page_t)type;
+ page_entry->is_dirty = FALSE;
+
+ /* Insert entry in skip list */
+ if(H5SL_insert(page_buf->mf_slist_ptr, page_entry, &(page_entry->addr)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_BADVALUE, FAIL, "Can't insert entry in skip list")
+ } /* end if */
+
+done:
+ if(ret_value < 0)
+ if(page_entry)
+ page_entry = H5FL_FREE(H5PB_entry_t, page_entry);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB_add_new_page */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_update_entry
+ *
+ * Purpose: In PHDF5, entries that are written by other processes and just
+ * marked clean by this process have to have their corresponding
+ * pages updated if they exist in the page buffer.
+ * This routine checks and update the pages.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_update_entry(H5PB_t *page_buf, haddr_t addr, size_t size, const void *buf)
+{
+ H5PB_entry_t *page_entry; /* Pointer to the corresponding page entry */
+ haddr_t page_addr;
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* Sanity checks */
+ HDassert(page_buf);
+ HDassert(size <= page_buf->page_size);
+ HDassert(buf);
+
+ /* calculate the aligned address of the first page */
+ page_addr = (addr / page_buf->page_size) * page_buf->page_size;
+
+ /* search for the page and update if found */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&page_addr));
+ if(page_entry) {
+ haddr_t offset;
+
+ HDassert(addr + size <= page_addr + page_buf->page_size);
+ offset = addr - page_addr;
+ HDmemcpy((uint8_t *)page_entry->page_buf_ptr + offset, buf, size);
+
+ /* move to top of LRU list */
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5PB_update_entry */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_remove_entry
+ *
+ * Purpose: Remove possible metadata entry with ADDR from the PB cache.
+ * This is in response to the data corruption bug from fheap.c
+ * with page buffering + page strategy.
+ * Note: Large metadata page bypasses the PB cache.
+ * Note: Update of raw data page (large or small sized) is handled by the PB cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Feb 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_remove_entry(const H5F_t *f, haddr_t addr)
+{
+ H5PB_t *page_buf = f->shared->page_buf;
+ H5PB_entry_t *page_entry = NULL; /* pointer to the page entry being searched */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(page_buf);
+
+ /* Search for address in the skip list */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&addr));
+
+ /* If found, remove the entry from the PB cache */
+ if(page_entry) {
+ HDassert(page_entry->type != H5F_MEM_PAGE_DRAW);
+ if(NULL == H5SL_remove(page_buf->slist_ptr, &(page_entry->addr)))
+ HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Page Entry is not in skip list")
+
+ /* Remove from LRU list */
+ H5PB__REMOVE_LRU(page_buf, page_entry)
+ HDassert(H5SL_count(page_buf->slist_ptr) == page_buf->LRU_list_len);
+
+ page_buf->meta_count--;
+
+ page_entry->page_buf_ptr = H5FL_FAC_FREE(page_buf->page_fac, page_entry->page_buf_ptr);
+ page_entry = H5FL_FREE(H5PB_entry_t, page_entry);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5PB_remove_entry */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_read
+ *
+ * Purpose: Reads in the data from the page containing it if it exists
+ * in the PB cache; otherwise reads in the page through the VFD.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_read(const H5F_io_info2_t *fio_info, H5FD_mem_t type, haddr_t addr,
+ size_t size, void *buf/*out*/)
+{
+ H5PB_t *page_buf; /* Page buffering info for this file */
+ H5PB_entry_t *page_entry; /* Pointer to the corresponding page entry */
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ haddr_t first_page_addr, last_page_addr; /* Addresses of the first and last pages covered by I/O */
+ haddr_t offset;
+ haddr_t search_addr; /* Address of current page */
+ hsize_t num_touched_pages; /* Number of pages accessed */
+ size_t access_size;
+ hbool_t bypass_pb = FALSE; /* Whether to bypass page buffering */
+ hsize_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(fio_info);
+
+ /* Get pointer to page buffer info for this file */
+ page_buf = fio_info->f->shared->page_buf;
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(fio_info->f, H5FD_FEAT_HAS_MPI)) {
+#if 1
+ bypass_pb = TRUE;
+#else
+ /* MSC - why this stopped working ? */
+ int mpi_size;
+
+ if((mpi_size = H5F_mpi_get_size(fio_info->f)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "can't retrieve MPI communicator size")
+ if(1 != mpi_size)
+ bypass_pb = TRUE;
+#endif
+ } /* end if */
+#endif
+
+ /* If page buffering is disabled, or the I/O size is larger than that of a
+ * single page, or if this is a parallel raw data access, bypass page
+ * buffering.
+ */
+ if(NULL == page_buf || size >= page_buf->page_size ||
+ (bypass_pb && H5FD_MEM_DRAW == type)) {
+ if(H5F__accum_read(fio_info, type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_READERROR, FAIL, "read through metadata accumulator failed")
+
+ /* Update statistics */
+ if(page_buf) {
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->bypasses[1] ++;
+ else
+ page_buf->bypasses[0] ++;
+ } /* end if */
+
+ /* If page buffering is disabled, or if this is a large metadata access,
+ * or if this is parallel raw data access, we are done here
+ */
+ if(NULL == page_buf || (size >= page_buf->page_size && H5FD_MEM_DRAW != type) ||
+ (bypass_pb && H5FD_MEM_DRAW == type))
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Update statistics */
+ if(page_buf) {
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->accesses[1]++;
+ else
+ page_buf->accesses[0]++;
+ } /* end if */
+
+ /* Calculate the aligned address of the first page */
+ first_page_addr = (addr / page_buf->page_size) * page_buf->page_size;
+
+ /* For Raw data calculate the aligned address of the last page and
+ * the number of pages accessed if more than 1 page is accessed
+ */
+ if(H5FD_MEM_DRAW == type) {
+ last_page_addr = ((addr + size - 1) / page_buf->page_size) * page_buf->page_size;
+
+ /* How many pages does this write span */
+ num_touched_pages = (last_page_addr / page_buf->page_size + 1) -
+ (first_page_addr / page_buf->page_size);
+ if(first_page_addr == last_page_addr) {
+ HDassert(1 == num_touched_pages);
+ last_page_addr = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+ /* Otherwise set last page addr to HADDR_UNDEF */
+ else {
+ num_touched_pages = 1;
+ last_page_addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Copy raw data from dirty pages into the read buffer if the read
+ request spans pages in the page buffer*/
+ if(H5FD_MEM_DRAW == type && size >= page_buf->page_size) {
+ H5SL_node_t *node;
+
+ /* For each touched page in the page buffer, check if it
+ * exists in the page Buffer and is dirty. If it does, we
+ * update the buffer with what's in the page so we get the up
+ * to date data into the buffer after the big read from the file.
+ */
+ node = H5SL_find(page_buf->slist_ptr, (void *)(&first_page_addr));
+ for(i = 0; i < num_touched_pages; i++) {
+ search_addr = i*page_buf->page_size + first_page_addr;
+
+ /* if we still haven't located a starting page, search again */
+ if(!node && i!=0)
+ node = H5SL_find(page_buf->slist_ptr, (void *)(&search_addr));
+
+ /* if the current page is in the Page Buffer, do the updates */
+ if(node) {
+ page_entry = (H5PB_entry_t *)H5SL_item(node);
+
+ HDassert(page_entry);
+
+ /* If the current page address falls out of the access
+ block, then there are no more pages to go over */
+ if(page_entry->addr >= addr + size)
+ break;
+
+ HDassert(page_entry->addr == search_addr);
+
+ if(page_entry->is_dirty) {
+ /* special handling for the first page if it is not a full page access */
+ if(i == 0 && first_page_addr != addr) {
+ offset = addr - first_page_addr;
+ HDassert(page_buf->page_size > offset);
+
+ HDmemcpy(buf, (uint8_t *)page_entry->page_buf_ptr + offset,
+ page_buf->page_size - (size_t)offset);
+
+ /* move to top of LRU list */
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+ } /* end if */
+ /* special handling for the last page if it is not a full page access */
+ else if(num_touched_pages > 1 && i == num_touched_pages-1 && search_addr < addr+size) {
+ offset = (num_touched_pages-2)*page_buf->page_size +
+ (page_buf->page_size - (addr - first_page_addr));
+
+ HDmemcpy((uint8_t *)buf + offset, page_entry->page_buf_ptr,
+ (size_t)((addr + size) - last_page_addr));
+
+ /* move to top of LRU list */
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+ } /* end else-if */
+ /* copy the entire fully accessed pages */
+ else {
+ offset = i*page_buf->page_size;
+
+ HDmemcpy((uint8_t *)buf+(i*page_buf->page_size) , page_entry->page_buf_ptr,
+ page_buf->page_size);
+ } /* end else */
+ } /* end if */
+ node = H5SL_next(node);
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else {
+ /* A raw data access could span 1 or 2 PB entries at this point so
+ we need to handle that */
+ HDassert(1 == num_touched_pages || 2 == num_touched_pages);
+ for(i = 0 ; i < num_touched_pages; i++) {
+ haddr_t buf_offset;
+
+ /* Calculate the aligned address of the page to search for it in the skip list */
+ search_addr = (0==i ? first_page_addr : last_page_addr);
+
+ /* Calculate the access size if the access spans more than 1 page */
+ if(1 == num_touched_pages)
+ access_size = size;
+ else
+ access_size = (0 == i ? (size_t)((first_page_addr + page_buf->page_size) - addr) : (size - access_size));
+
+ /* Lookup the page in the skip list */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&search_addr));
+
+ /* if found */
+ if(page_entry) {
+ offset = (0 == i ? addr - page_entry->addr : 0);
+ buf_offset = (0 == i ? 0 : size - access_size);
+
+ /* copy the requested data from the page into the input buffer */
+ HDmemcpy((uint8_t *)buf + buf_offset, (uint8_t *)page_entry->page_buf_ptr + offset, access_size);
+
+ /* Update LRU */
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+
+ /* Update statistics */
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->hits[1]++;
+ else
+ page_buf->hits[0]++;
+ } /* end if */
+ /* if not found */
+ else {
+ void *new_page_buf = NULL;
+ size_t page_size = page_buf->page_size;
+ haddr_t eoa;
+
+ /* make space for new entry */
+ if((H5SL_count(page_buf->slist_ptr) * page_buf->page_size) >= page_buf->max_size) {
+ htri_t can_make_space;
+
+ /* check if we can make space in page buffer */
+ if((can_make_space = H5PB__make_space(fio_info, page_buf, type)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_NOSPACE, FAIL, "make space in Page buffer Failed")
+
+ /* if make_space returns 0, then we can't use the page
+ buffer for this I/O and we need to bypass */
+ if(0 == can_make_space) {
+ /* make space can't return FALSE on second touched page since the first is of the same type */
+ HDassert(0 == i);
+
+ /* read entire block from VFD and return */
+ if(H5FD_read(&fdio_info, type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_READERROR, FAIL, "driver read request failed")
+
+ /* Break out of loop */
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Read page from VFD */
+ if(NULL == (new_page_buf = H5FL_FAC_MALLOC(page_buf->page_fac)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTALLOC, FAIL, "memory allocation failed for page buffer entry")
+
+ /* Read page through the VFD layer, but make sure we don't read past the EOA. */
+
+ /* Retrieve the 'eoa' for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(fio_info->f, type)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* If the entire page falls outside the EOA, then fail */
+ if(search_addr > eoa)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_BADVALUE, FAIL, "reading an entire page that is outside the file EOA")
+
+ /* Adjust the read size to not go beyond the EOA */
+ if(search_addr + page_size > eoa)
+ page_size = (size_t)(eoa - search_addr);
+
+ /* Read page from VFD */
+ if(H5FD_read(&fdio_info, type, search_addr, page_size, new_page_buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_READERROR, FAIL, "driver read request failed")
+
+ /* Copy the requested data from the page into the input buffer */
+ offset = (0 == i ? addr - search_addr : 0);
+ buf_offset = (0 == i ? 0 : size - access_size);
+ HDmemcpy((uint8_t *)buf + buf_offset, (uint8_t *)new_page_buf + offset, access_size);
+
+ /* Create the new PB entry */
+ if(NULL == (page_entry = H5FL_CALLOC(H5PB_entry_t)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ page_entry->page_buf_ptr = new_page_buf;
+ page_entry->addr = search_addr;
+ page_entry->type = (H5F_mem_page_t)type;
+ page_entry->is_dirty = FALSE;
+
+ /* Insert page into PB */
+ if(H5PB__insert_entry(page_buf, page_entry) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTSET, FAIL, "error inserting new page in page buffer")
+
+ /* Update statistics */
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->misses[1]++;
+ else
+ page_buf->misses[0]++;
+ } /* end else */
+ } /* end for */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB_write
+ *
+ * Purpose: Write data into the Page Buffer. If the page exists in the
+ * cache, update it; otherwise read it from disk, update it, and
+ * insert into cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PB_write(const H5F_io_info2_t *fio_info, H5FD_mem_t type, haddr_t addr,
+ size_t size, const void *buf)
+{
+ H5PB_t *page_buf; /* Page buffering info for this file */
+ H5PB_entry_t *page_entry; /* Pointer to the corresponding page entry */
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ haddr_t first_page_addr, last_page_addr; /* Addresses of the first and last pages covered by I/O */
+ haddr_t offset;
+ haddr_t search_addr; /* Address of current page */
+ hsize_t num_touched_pages; /* Number of pages accessed */
+ size_t access_size;
+ hbool_t bypass_pb = FALSE; /* Whether to bypass page buffering */
+ hsize_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+
+ /* Get pointer to page buffer info for this file */
+ page_buf = fio_info->f->shared->page_buf;
+
+#ifdef H5_HAVE_PARALLEL
+ if(H5F_HAS_FEATURE(fio_info->f, H5FD_FEAT_HAS_MPI)) {
+#if 1
+ bypass_pb = TRUE;
+#else
+ /* MSC - why this stopped working ? */
+ int mpi_size;
+
+ if((mpi_size = H5F_mpi_get_size(fio_info->f)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "can't retrieve MPI communicator size")
+ if(1 != mpi_size)
+ bypass_pb = TRUE;
+#endif
+ } /* end if */
+#endif
+
+ /* If page buffering is disabled, or the I/O size is larger than that of a
+ * single page, or if this is a parallel raw data access, bypass page
+ * buffering.
+ */
+ if(NULL == page_buf || size >= page_buf->page_size || bypass_pb) {
+ if(H5F__accum_write(fio_info, type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_WRITEERROR, FAIL, "write through metadata accumulator failed")
+
+ /* Update statistics */
+ if(page_buf) {
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->bypasses[1]++;
+ else
+ page_buf->bypasses[0]++;
+ } /* end if */
+
+ /* If page buffering is disabled, or if this is a large metadata access,
+ * or if this is a parallel raw data access, we are done here
+ */
+ if(NULL == page_buf || (size >= page_buf->page_size && H5FD_MEM_DRAW != type) ||
+ (bypass_pb && H5FD_MEM_DRAW == type))
+ HGOTO_DONE(SUCCEED)
+
+#ifdef H5_HAVE_PARALLEL
+ if(bypass_pb) {
+ if(H5PB_update_entry(page_buf, addr, size, buf) > 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTUPDATE, FAIL, "failed to update PB with metadata cache")
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+#endif
+ } /* end if */
+
+ /* Update statistics */
+ if(page_buf) {
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->accesses[1]++;
+ else
+ page_buf->accesses[0]++;
+ } /* end if */
+
+ /* Calculate the aligned address of the first page */
+ first_page_addr = (addr / page_buf->page_size) * page_buf->page_size;
+
+ /* For raw data calculate the aligned address of the last page and
+ * the number of pages accessed if more than 1 page is accessed
+ */
+ if(H5FD_MEM_DRAW == type) {
+ last_page_addr = (addr + size - 1) / page_buf->page_size * page_buf->page_size;
+
+ /* how many pages does this write span */
+ num_touched_pages = (last_page_addr/page_buf->page_size + 1) -
+ (first_page_addr / page_buf->page_size);
+ if(first_page_addr == last_page_addr) {
+ HDassert(1 == num_touched_pages);
+ last_page_addr = HADDR_UNDEF;
+ } /* end if */
+ } /* end if */
+ /* Otherwise set last page addr to HADDR_UNDEF */
+ else {
+ num_touched_pages = 1;
+ last_page_addr = HADDR_UNDEF;
+ } /* end else */
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ /* Check if existing pages for raw data need to be updated since raw data access is not atomic */
+ if(H5FD_MEM_DRAW == type && size >= page_buf->page_size) {
+ /* For each touched page, check if it exists in the page buffer, and
+ * update it with the data in the buffer to keep it up to date
+ */
+ for(i = 0; i < num_touched_pages; i++) {
+ search_addr = i * page_buf->page_size + first_page_addr;
+
+ /* Special handling for the first page if it is not a full page update */
+ if(i == 0 && first_page_addr != addr) {
+ /* Lookup the page in the skip list */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&search_addr));
+ if(page_entry) {
+ offset = addr - first_page_addr;
+ HDassert(page_buf->page_size > offset);
+
+ /* Update page's data */
+ HDmemcpy((uint8_t *)page_entry->page_buf_ptr + offset, buf, page_buf->page_size - (size_t)offset);
+
+ /* Mark page dirty and push to top of LRU */
+ page_entry->is_dirty = TRUE;
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+ } /* end if */
+ } /* end if */
+ /* Special handling for the last page if it is not a full page update */
+ else if(num_touched_pages > 1 && i == (num_touched_pages - 1) &&
+ (search_addr + page_buf->page_size) != (addr + size)) {
+ HDassert(search_addr+page_buf->page_size > addr+size);
+
+ /* Lookup the page in the skip list */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&search_addr));
+ if(page_entry) {
+ offset = (num_touched_pages - 2) * page_buf->page_size +
+ (page_buf->page_size - (addr - first_page_addr));
+
+ /* Update page's data */
+ HDmemcpy(page_entry->page_buf_ptr, (const uint8_t *)buf + offset,
+ (size_t)((addr + size) - last_page_addr));
+
+ /* Mark page dirty and push to top of LRU */
+ page_entry->is_dirty = TRUE;
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+ } /* end if */
+ } /* end else-if */
+ /* Discard all fully written pages from the page buffer */
+ else {
+ page_entry = (H5PB_entry_t *)H5SL_remove(page_buf->slist_ptr, (void *)(&search_addr));
+ if(page_entry) {
+ /* Remove from LRU list */
+ H5PB__REMOVE_LRU(page_buf, page_entry)
+
+ /* Decrement page count of appropriate type */
+ if(H5F_MEM_PAGE_DRAW == page_entry->type || H5F_MEM_PAGE_GHEAP == page_entry->type)
+ page_buf->raw_count--;
+ else
+ page_buf->meta_count--;
+
+ /* Free page info */
+ page_entry->page_buf_ptr = H5FL_FAC_FREE(page_buf->page_fac, page_entry->page_buf_ptr);
+ page_entry = H5FL_FREE(H5PB_entry_t, page_entry);
+ } /* end if */
+ } /* end else */
+ } /* end for */
+ } /* end if */
+ else {
+ /* An access could span 1 or 2 PBs at this point so we need to handle that */
+ HDassert(1 == num_touched_pages || 2 == num_touched_pages);
+ for(i = 0; i < num_touched_pages; i++) {
+ haddr_t buf_offset;
+
+ /* Calculate the aligned address of the page to search for it in the skip list */
+ search_addr = (0 == i ? first_page_addr : last_page_addr);
+
+ /* Calculate the access size if the access spans more than 1 page */
+ if(1 == num_touched_pages)
+ access_size = size;
+ else
+ access_size = (0 == i ? (size_t)(first_page_addr + page_buf->page_size - addr) : (size - access_size));
+
+ /* Lookup the page in the skip list */
+ page_entry = (H5PB_entry_t *)H5SL_search(page_buf->slist_ptr, (void *)(&search_addr));
+
+ /* If found */
+ if(page_entry) {
+ offset = (0 == i ? addr - page_entry->addr : 0);
+ buf_offset = (0 == i ? 0 : size - access_size);
+
+ /* Copy the requested data from the input buffer into the page */
+ HDmemcpy((uint8_t *)page_entry->page_buf_ptr + offset, (const uint8_t *)buf + buf_offset, access_size);
+
+ /* Mark page dirty and push to top of LRU */
+ page_entry->is_dirty = TRUE;
+ H5PB__MOVE_TO_TOP_LRU(page_buf, page_entry)
+
+ /* Update statistics */
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->hits[1]++;
+ else
+ page_buf->hits[0]++;
+ } /* end if */
+ /* If not found */
+ else {
+ void *new_page_buf;
+ size_t page_size = page_buf->page_size;
+
+ /* Make space for new entry */
+ if((H5SL_count(page_buf->slist_ptr) * page_buf->page_size) >= page_buf->max_size) {
+ htri_t can_make_space;
+
+ /* Check if we can make space in page buffer */
+ if((can_make_space = H5PB__make_space(fio_info, page_buf, type)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_NOSPACE, FAIL, "make space in Page buffer Failed")
+
+ /* If make_space returns 0, then we can't use the page
+ * buffer for this I/O and we need to bypass
+ */
+ if(0 == can_make_space) {
+ HDassert(0 == i);
+
+ /* Write to VFD and return */
+ if(H5FD_write(&fdio_info, type, addr, size, buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_WRITEERROR, FAIL, "driver write request failed")
+
+ /* Break out of loop */
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Don't bother searching if there is no write access */
+ if(H5F_ACC_RDWR & H5F_INTENT(fio_info->f))
+ /* Lookup & remove the page from the new skip list page if
+ * it exists to see if this is a new page from the MF layer
+ */
+ page_entry = (H5PB_entry_t *)H5SL_remove(page_buf->mf_slist_ptr, (void *)(&search_addr));
+
+ /* Calculate offset into the buffer of the page and the user buffer */
+ offset = (0 == i ? addr - search_addr : 0);
+ buf_offset = (0 == i ? 0 : size - access_size);
+
+ /* If found, then just update the buffer pointer to the newly allocate buffer */
+ if(page_entry) {
+ /* Allocate space for the page buffer */
+ if(NULL == (new_page_buf = H5FL_FAC_MALLOC(page_buf->page_fac)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTALLOC, FAIL, "memory allocation failed for page buffer entry")
+ HDmemset(new_page_buf, 0, (size_t)offset);
+ HDmemset((uint8_t *)new_page_buf + offset + access_size, 0, page_size - ((size_t)offset + access_size));
+
+ page_entry->page_buf_ptr = new_page_buf;
+
+ /* Update statistics */
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->hits[1]++;
+ else
+ page_buf->hits[0]++;
+ } /* end if */
+ /* Otherwise read page through the VFD layer, but make sure we don't read past the EOA. */
+ else {
+ haddr_t eoa, eof = HADDR_UNDEF;
+
+ /* Allocate space for the page buffer */
+ if(NULL == (new_page_buf = H5FL_FAC_CALLOC(page_buf->page_fac)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTALLOC, FAIL, "memory allocation failed for page buffer entry")
+
+ /* Create the new loaded PB entry */
+ if(NULL == (page_entry = H5FL_CALLOC(H5PB_entry_t)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ page_entry->page_buf_ptr = new_page_buf;
+ page_entry->addr = search_addr;
+ page_entry->type = (H5F_mem_page_t)type;
+
+ /* Retrieve the 'eoa' for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(fio_info->f, type)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* If the entire page falls outside the EOA, then fail */
+ if(search_addr > eoa)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_BADVALUE, FAIL, "writing to a page that is outside the file EOA")
+
+ /* Retrieve the 'eof' for the file - The MPI-VFD EOF
+ * returned will most likely be HADDR_UNDEF, so skip
+ * that check.
+ */
+ if(!H5F_HAS_FEATURE(fio_info->f, H5FD_FEAT_HAS_MPI))
+ if(HADDR_UNDEF == (eof = H5FD_get_eof(fio_info->f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "driver get_eof request failed")
+
+ /* Adjust the read size to not go beyond the EOA */
+ if(search_addr + page_size > eoa)
+ page_size = (size_t)(eoa - search_addr);
+
+ if(search_addr < eof) {
+ if(H5FD_read(&fdio_info, type, search_addr, page_size, new_page_buf) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_READERROR, FAIL, "driver read request failed")
+
+ /* Update statistics */
+ if(type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP)
+ page_buf->misses[1]++;
+ else
+ page_buf->misses[0]++;
+ } /* end if */
+ } /* end else */
+
+ /* Copy the requested data from the page into the input buffer */
+ HDmemcpy((uint8_t *)new_page_buf + offset, (const uint8_t *)buf+buf_offset, access_size);
+
+ /* Page is dirty now */
+ page_entry->is_dirty = TRUE;
+
+ /* Insert page into PB, evicting other pages as necessary */
+ if(H5PB__insert_entry(page_buf, page_entry) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTSET, FAIL, "error inserting new page in page buffer")
+ } /* end else */
+ } /* end for */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB__insert_entry()
+ *
+ * Purpose: ???
+ *
+ * This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ * Insert the supplied page into the page buffer, both the
+ * skip list and the LRU.
+ *
+ * As best I can tell, this function imposes no limit on the
+ * number of entries in the page buffer beyond an assertion
+ * failure it the page count exceeds the limit.
+ *
+ * JRM -- 12/22/16
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PB__insert_entry(H5PB_t *page_buf, H5PB_entry_t *page_entry)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Insert entry in skip list */
+ if(H5SL_insert(page_buf->slist_ptr, page_entry, &(page_entry->addr)) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTINSERT, FAIL, "can't insert entry in skip list")
+ HDassert(H5SL_count(page_buf->slist_ptr) * page_buf->page_size <= page_buf->max_size);
+
+ /* Increment appropriate page count */
+ if(H5F_MEM_PAGE_DRAW == page_entry->type || H5F_MEM_PAGE_GHEAP == page_entry->type)
+ page_buf->raw_count++;
+ else
+ page_buf->meta_count++;
+
+ /* Insert entry in LRU */
+ H5PB__INSERT_LRU(page_buf, page_entry)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB__insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB__make_space()
+ *
+ * Purpose: ???
+ *
+ * This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ * If necessary and if possible, evict a page from the page
+ * buffer to make space for the supplied page. Depending on
+ * the page buffer configuration and contents, and the page
+ * supplied this may or may not be possible.
+ *
+ * JRM -- 12/22/16
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5PB__make_space(const H5F_io_info2_t *fio_info, H5PB_t *page_buf,
+ H5FD_mem_t inserted_type)
+{
+ H5PB_entry_t *page_entry; /* Pointer to page eviction candidate */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(fio_info);
+ HDassert(page_buf);
+
+ /* Get oldest entry */
+ page_entry = page_buf->LRU_tail_ptr;
+
+ if(H5FD_MEM_DRAW == inserted_type) {
+ /* If threshould is 100% metadata and page buffer is full of
+ metadata, then we can't make space for raw data */
+ if(0 == page_buf->raw_count && page_buf->min_meta_count == page_buf->meta_count) {
+ HDassert(page_buf->meta_count * page_buf->page_size == page_buf->max_size);
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* check the metadata threshold before evicting metadata items */
+ while(1) {
+ if(page_entry->prev && H5F_MEM_PAGE_META == page_entry->type &&
+ page_buf->min_meta_count >= page_buf->meta_count)
+ page_entry = page_entry->prev;
+ else
+ break;
+ } /* end while */
+ } /* end if */
+ else {
+ /* If threshould is 100% raw data and page buffer is full of
+ raw data, then we can't make space for meta data */
+ if(0 == page_buf->meta_count && page_buf->min_raw_count == page_buf->raw_count) {
+ HDassert(page_buf->raw_count * page_buf->page_size == page_buf->max_size);
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* check the raw data threshold before evicting raw data items */
+ while(1) {
+ if(page_entry->prev && (H5F_MEM_PAGE_DRAW == page_entry->type || H5F_MEM_PAGE_GHEAP == page_entry->type) &&
+ page_buf->min_raw_count >= page_buf->raw_count)
+ page_entry = page_entry->prev;
+ else
+ break;
+ } /* end while */
+ } /* end else */
+
+ /* Remove from page index */
+ if(NULL == H5SL_remove(page_buf->slist_ptr, &(page_entry->addr)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_BADVALUE, FAIL, "Tail Page Entry is not in skip list")
+
+ /* Remove entry from LRU list */
+ H5PB__REMOVE_LRU(page_buf, page_entry)
+ HDassert(H5SL_count(page_buf->slist_ptr) == page_buf->LRU_list_len);
+
+ /* Decrement appropriate page type counter */
+ if(H5F_MEM_PAGE_DRAW == page_entry->type || H5F_MEM_PAGE_GHEAP == page_entry->type)
+ page_buf->raw_count--;
+ else
+ page_buf->meta_count--;
+
+ /* Flush page if dirty */
+ if(page_entry->is_dirty)
+ if(H5PB__write_entry(fio_info, page_entry) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_WRITEERROR, FAIL, "file write failed")
+
+ /* Update statistics */
+ if(page_entry->type == H5F_MEM_PAGE_DRAW || H5F_MEM_PAGE_GHEAP == page_entry->type)
+ page_buf->evictions[1]++;
+ else
+ page_buf->evictions[0]++;
+
+ /* Release page */
+ page_entry->page_buf_ptr = H5FL_FAC_FREE(page_buf->page_fac, page_entry->page_buf_ptr);
+ page_entry = H5FL_FREE(H5PB_entry_t, page_entry);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB__make_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PB__write_entry()
+ *
+ * Purpose: ???
+ *
+ * This function was created without documentation.
+ * What follows is my best understanding of Mohamad's intent.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PB__write_entry(const H5F_io_info2_t *fio_info, H5PB_entry_t *page_entry)
+{
+ haddr_t eoa; /* Current EOA for the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(fio_info);
+ HDassert(fio_info->f);
+ HDassert(page_entry);
+
+ /* Retrieve the 'eoa' for the file */
+ if(HADDR_UNDEF == (eoa = H5F_get_eoa(fio_info->f, page_entry->type)))
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_CANTGET, FAIL, "driver get_eoa request failed")
+
+ /* If the starting address of the page is larger than
+ * the EOA, then the entire page is discarded without writing.
+ */
+ if(page_entry->addr <= eoa) {
+ H5FD_io_info_t fdio_info; /* File driver I/O info */
+ size_t page_size = fio_info->f->shared->page_buf->page_size;
+
+ /* Adjust the page length if it exceeds the EOA */
+ if((page_entry->addr + page_size) > eoa)
+ page_size = (size_t)(eoa - page_entry->addr);
+
+ /* Translate to file driver I/O info object */
+ fdio_info.file = fio_info->f->shared->lf;
+ fdio_info.meta_dxpl = fio_info->meta_dxpl;
+ fdio_info.raw_dxpl = fio_info->raw_dxpl;
+
+ if(H5FD_write(&fdio_info, page_entry->type, page_entry->addr, page_size, page_entry->page_buf_ptr) < 0)
+ HGOTO_ERROR(H5E_PAGEBUF, H5E_WRITEERROR, FAIL, "file write failed")
+ } /* end if */
+
+ page_entry->is_dirty = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PB__write_entry() */
+
diff --git a/src/H5PBmodule.h b/src/H5PBmodule.h
new file mode 100644
index 0000000..c8aabb6
--- /dev/null
+++ b/src/H5PBmodule.h
@@ -0,0 +1,32 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5PB package. Including this header means that the source file
+ * is part of the H5PB package.
+ */
+#ifndef _H5PBmodule_H
+#define _H5PBmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5PB_MODULE
+#define H5_MY_PKG H5PB
+#define H5_MY_PKG_ERR H5E_RESOURCE
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5PBmodule_H */
diff --git a/src/H5PBpkg.h b/src/H5PBpkg.h
new file mode 100644
index 0000000..6b9168b
--- /dev/null
+++ b/src/H5PBpkg.h
@@ -0,0 +1,58 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !(defined H5PB_FRIEND || defined H5PB_MODULE)
+#error "Do not include this file outside the H5PB package!"
+#endif
+
+#ifndef _H5PBpkg_H
+#define _H5PBpkg_H
+
+/* Get package's private header */
+#include "H5PBprivate.h"
+
+/* Other private headers needed by this file */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+typedef struct H5PB_entry_t {
+ void *page_buf_ptr; /* Pointer to the buffer containing the data */
+ haddr_t addr; /* Address of the page in the file */
+ H5F_mem_page_t type; /* Type of the page entry (H5F_MEM_PAGE_RAW/META) */
+ hbool_t is_dirty; /* Flag indicating whether the page has dirty data or not */
+
+ /* Fields supporting replacement policies */
+ struct H5PB_entry_t *next; /* next pointer in the LRU list */
+ struct H5PB_entry_t *prev; /* previous pointer in the LRU list */
+} H5PB_entry_t;
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+
+#endif /* _H5PBpkg_H */
+
diff --git a/src/H5PBprivate.h b/src/H5PBprivate.h
new file mode 100644
index 0000000..e6f2874
--- /dev/null
+++ b/src/H5PBprivate.h
@@ -0,0 +1,106 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5PBprivate.h
+ * June 2014
+ * Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5PBprivate_H
+#define _H5PBprivate_H
+
+/* Include package's public header */
+#ifdef NOT_YET
+#include "H5PBpublic.h"
+#endif /* NOT_YET */
+
+/* Private headers needed by this header */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5SLprivate.h" /* Skip List */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Forward declaration for a page buffer entry */
+struct H5PB_entry_t;
+
+/* Typedef for the main structure for the page buffer */
+typedef struct H5PB_t {
+ size_t max_size; /* The total page buffer size */
+ size_t page_size; /* Size of a single page */
+ unsigned min_meta_perc; /* Minimum ratio of metadata entries required before evicting meta entries */
+ unsigned min_raw_perc; /* Minimum ratio of raw data entries required before evicting raw entries */
+ unsigned meta_count; /* Number of entries for metadata */
+ unsigned raw_count; /* Number of entries for raw data */
+ unsigned min_meta_count; /* Minimum # of entries for metadata */
+ unsigned min_raw_count; /* Minimum # of entries for raw data */
+
+ H5SL_t *slist_ptr; /* Skip list with all the active page entries */
+ H5SL_t *mf_slist_ptr; /* Skip list containing newly allocated page entries inserted from the MF layer */
+
+ size_t LRU_list_len; /* Number of entries in the LRU (identical to slist_ptr count) */
+ struct H5PB_entry_t *LRU_head_ptr; /* Head pointer of the LRU */
+ struct H5PB_entry_t *LRU_tail_ptr; /* Tail pointer of the LRU */
+
+ H5FL_fac_head_t *page_fac; /* Factory for allocating pages */
+
+ /* Statistics */
+ unsigned accesses[2];
+ unsigned hits[2];
+ unsigned misses[2];
+ unsigned evictions[2];
+ unsigned bypasses[2];
+} H5PB_t;
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General routines */
+H5_DLL herr_t H5PB_create(H5F_t *file, size_t page_buffer_size, unsigned page_buf_min_meta_perc, unsigned page_buf_min_raw_perc);
+H5_DLL herr_t H5PB_flush(const H5F_io_info2_t *fio_info);
+H5_DLL herr_t H5PB_dest(const H5F_io_info2_t *fio_info);
+H5_DLL herr_t H5PB_add_new_page(H5F_t *f, H5FD_mem_t type, haddr_t page_addr);
+H5_DLL herr_t H5PB_update_entry(H5PB_t *page_buf, haddr_t addr, size_t size, const void *buf);
+H5_DLL herr_t H5PB_remove_entry(const H5F_t *f, haddr_t addr);
+H5_DLL herr_t H5PB_read(const H5F_io_info2_t *fio_info, H5FD_mem_t type,
+ haddr_t addr, size_t size, void *buf/*out*/);
+H5_DLL herr_t H5PB_write(const H5F_io_info2_t *f, H5FD_mem_t type, haddr_t addr,
+ size_t size, const void *buf);
+
+/* Statistics routines */
+H5_DLL herr_t H5PB_reset_stats(H5PB_t *page_buf);
+H5_DLL herr_t H5PB_get_stats(const H5PB_t *page_buf, unsigned accesses[2],
+ unsigned hits[2], unsigned misses[2], unsigned evictions[2], unsigned bypasses[2]);
+H5_DLL herr_t H5PB_print_stats(const H5PB_t *page_buf);
+
+#endif /* !_H5PBprivate_H */
+
diff --git a/src/H5PL.c b/src/H5PL.c
new file mode 100644
index 0000000..bc69a25
--- /dev/null
+++ b/src/H5PL.c
@@ -0,0 +1,1008 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5PLmodule.h" /* This source code file is part of the H5PL module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5PLpkg.h" /* Plugin */
+#include "H5Zprivate.h" /* Filter pipeline */
+
+
+/****************/
+/* Local Macros */
+/****************/
+#ifdef H5_HAVE_WIN32_API
+#define H5PL_EXPAND_ENV_VAR { \
+ long bufCharCount; \
+ char *tempbuf; \
+ if(NULL == (tempbuf = (char *)H5MM_malloc(H5PL_EXPAND_BUFFER_SIZE))) \
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path") \
+ if((bufCharCount = ExpandEnvironmentStringsA(dl_path, tempbuf, H5PL_EXPAND_BUFFER_SIZE)) > H5PL_EXPAND_BUFFER_SIZE) { \
+ tempbuf = (char *)H5MM_xfree(tempbuf); \
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long") \
+ } \
+ if(bufCharCount == 0) { \
+ tempbuf = (char *)H5MM_xfree(tempbuf); \
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path") \
+ } \
+ dl_path = (char *)H5MM_xfree(dl_path); \
+ dl_path = tempbuf; \
+ }
+#else
+#define H5PL_EXPAND_ENV_VAR
+#endif /* H5_HAVE_WIN32_API */
+
+/****************************/
+/* Macros for supporting
+ * both Windows and Unix */
+/****************************/
+/* Windows support
+ *
+ * SPECIAL WINDOWS NOTE
+ *
+ * Some of the Win32 API functions expand to fooA or fooW depending on
+ * whether UNICODE or _UNICODE are defined. You MUST explicitly use
+ * the A version of the functions to force char * behavior until we
+ * work out a scheme for proper Windows Unicode support.
+ *
+ * If you do not do this, people will be unable to incorporate our
+ * source code into their own CMake builds if they define UNICODE.
+ */
+#ifdef H5_HAVE_WIN32_API
+
+#define H5PL_PATH_SEPARATOR ";"
+
+/* Handle for dynamic library */
+#define H5PL_HANDLE HINSTANCE
+
+/* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */
+#define H5PL_OPEN_DLIB(S) LoadLibraryExA(S, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
+
+/* Get the address of a symbol in dynamic library */
+#define H5PL_GET_LIB_FUNC(H,N) GetProcAddress(H,N)
+
+/* Close dynamic library */
+#define H5PL_CLOSE_LIB(H) FreeLibrary(H)
+
+/* Clear error - nothing to do */
+#define H5PL_CLR_ERROR
+
+/* maximum size for expanding env vars */
+#define H5PL_EXPAND_BUFFER_SIZE 32767
+
+typedef const void *(__cdecl *H5PL_get_plugin_info_t)(void);
+
+/* Unix support */
+#else /* H5_HAVE_WIN32_API */
+
+#define H5PL_PATH_SEPARATOR ":"
+
+/* Handle for dynamic library */
+#define H5PL_HANDLE void *
+
+/* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */
+#define H5PL_OPEN_DLIB(S) dlopen(S, RTLD_LAZY)
+
+/* Get the address of a symbol in dynamic library */
+#define H5PL_GET_LIB_FUNC(H,N) dlsym(H,N)
+
+/* Close dynamic library */
+#define H5PL_CLOSE_LIB(H) dlclose(H)
+
+/* Clear error */
+#define H5PL_CLR_ERROR HERROR(H5E_PLUGIN, H5E_CANTGET, "can't dlopen:%s", dlerror())
+
+typedef const void *(*H5PL_get_plugin_info_t)(void);
+#endif /* H5_HAVE_WIN32_API */
+
+/* Whether to preload pathnames for plugin libraries */
+#define H5PL_DEFAULT_PATH H5_DEFAULT_PLUGINDIR
+
+/* Special symbol to indicate no plugin loading */
+#define H5PL_NO_PLUGIN "::"
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Type for the list of info for opened plugin libraries */
+typedef struct H5PL_table_t {
+ H5PL_type_t pl_type; /* plugin type */
+ int pl_id; /* ID for the plugin */
+ H5PL_HANDLE handle; /* plugin handle */
+} H5PL_table_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5PL__init_path_table(void);
+static htri_t H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info);
+static htri_t H5PL__open(H5PL_type_t pl_type, char *libname, int plugin_id, const void **pl_info);
+static htri_t H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info);
+static herr_t H5PL__close(H5PL_HANDLE handle);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Table for opened plugin libraries */
+static size_t H5PL_table_alloc_g = 0;
+static size_t H5PL_table_used_g = 0;
+static H5PL_table_t *H5PL_table_g = NULL;
+
+/* Table of location paths for plugin libraries */
+static char *H5PL_path_table_g[H5PL_MAX_PATH_NUM];
+static size_t H5PL_num_paths_g = 0;
+static hbool_t H5PL_path_found_g = FALSE;
+
+/* Enable all plugin libraries */
+static unsigned int H5PL_plugin_g = H5PL_ALL_PLUGIN;
+
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5PL__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5PL__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t
+H5PL__init_package(void)
+{
+ char *preload_path;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Retrieve pathnames from HDF5_PLUGIN_PRELOAD if the user sets it
+ * to tell the library to load plugin libraries without search.
+ */
+ if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD")))
+ /* Special symbal "::" means no plugin during data reading. */
+ if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN))
+ H5PL_plugin_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5PL__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL_term_package
+ *
+ * Purpose: Terminate the H5PL interface: release all memory, reset all
+ * global variables to initial values. This only happens if all
+ * types have been destroyed from other interfaces.
+ *
+ * Return: Success: Positive if any action was taken that might
+ * affect some other interface; zero otherwise.
+ * Failure: Negative.
+ *
+ * Programmer: Raymond Lu
+ * 20 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5PL_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ size_t u; /* Local index variable */
+
+ /* Close opened dynamic libraries */
+ if(H5PL_table_g) {
+ for(u = 0; u < H5PL_table_used_g; u++)
+ H5PL__close((H5PL_table_g[u]).handle);
+
+ /* Free the table of dynamic libraries */
+ H5PL_table_g = (H5PL_table_t *)H5MM_xfree(H5PL_table_g);
+ H5PL_table_used_g = H5PL_table_alloc_g = 0;
+
+ n++;
+ } /* end if */
+
+ /* Free the table of search paths */
+ if(H5PL_num_paths_g > 0) {
+ for(u = 0; u < H5PL_num_paths_g; u++)
+ if(H5PL_path_table_g[u])
+ H5PL_path_table_g[u] = (char *)H5MM_xfree(H5PL_path_table_g[u]);
+ H5PL_num_paths_g = 0;
+ H5PL_path_found_g = FALSE;
+
+ n++;
+ } /* end if */
+
+ /* Mark the interface as uninitialized */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5PL_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLset_loading_state
+ *
+ * Purpose: Control the loading of dynamic plugin types.
+ *
+ * This function will not allow plugin types if the pathname from the HDF5_PLUGIN_PRELOAD
+ * environment variable is set to the special "::" string.
+ *
+ * plugin bit = 0, will prevent the use of that dynamic plugin type.
+ * plugin bit = 1, will allow the use of that dynamic plugin type.
+ *
+ * H5PL_TYPE_FILTER changes just dynamic filters
+ * A H5PL_ALL_PLUGIN will enable all dynamic plugin types
+ * A zero value will disable all dynamic plugin types
+ *
+ * Return: Non-negative or success
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLset_loading_state(unsigned int plugin_type)
+{
+ char *preload_path;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "Iu", plugin_type);
+
+ /* change the bit value of the requested plugin type(s) */
+ H5PL_plugin_g = plugin_type;
+
+ /* check if special ENV variable is set and disable all plugin types */
+ if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD")))
+ /* Special symbol "::" means no plugin during data reading. */
+ if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN))
+ H5PL_plugin_g = 0;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLset_loading_state() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLget_loading_state
+ *
+ * Purpose: Query state of the loading of dynamic plugin types.
+ *
+ * This function will return the state of the global flag.
+ *
+ * Return: Zero if all plugin types are disabled, negative if all
+ * plugin types are enabled, positive if one or more of the plugin types are enabled.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLget_loading_state(unsigned int *plugin_type)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*Iu", plugin_type);
+
+ if(plugin_type)
+ *plugin_type = H5PL_plugin_g;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLget_loading_state() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL_load
+ *
+ * Purpose: Given the plugin type and identifier, this function searches
+ * and/or loads a dynamic plugin library first among the already
+ * opened libraries then in the designated location paths.
+ *
+ * Return: Non-NULL on success/NULL on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+const void *
+H5PL_load(H5PL_type_t type, int id)
+{
+ htri_t found; /* Whether the plugin was found */
+ const void *plugin_info = NULL;
+ const void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ switch(type) {
+ case H5PL_TYPE_FILTER:
+ if((H5PL_plugin_g & H5PL_FILTER_PLUGIN) == 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin filter '%d' is not available", id)
+ break;
+
+ case H5PL_TYPE_ERROR:
+ case H5PL_TYPE_NONE:
+ default:
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin '%d' is not valid", id)
+ } /* end switch */
+
+ /* Initialize the location paths for dynamic libraries, if they aren't
+ * already set up.
+ */
+ if(FALSE == H5PL_path_found_g)
+ if(H5PL__init_path_table() < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, NULL, "can't initialize search path table")
+
+ /* Search in the table of already loaded plugin libraries */
+ if((found = H5PL__search_table(type, id, &plugin_info)) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in table failed")
+
+ /* If not found, iterate through the path table to find the right dynamic library */
+ if(!found) {
+ size_t i; /* Local index variable */
+
+ for(i = 0; i < H5PL_num_paths_g; i++) {
+ if((found = H5PL__find(type, id, H5PL_path_table_g[i], &plugin_info)) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in paths failed")
+
+ /* Break out if found */
+ if(found) {
+ HDassert(plugin_info);
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Check if we found the plugin */
+ if(found)
+ ret_value = plugin_info;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL_load() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLappend
+ *
+ * Purpose: Insert a plugin path at the end of the list.
+ *
+ * Return: Non-negative or success.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLappend(const char *plugin_path)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ char *dl_path = NULL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*s", plugin_path);
+ if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
+ if(NULL == plugin_path)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
+ if(NULL == (dl_path = H5MM_strdup(plugin_path)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+
+ H5PL_EXPAND_ENV_VAR
+
+ H5PL_path_table_g[H5PL_num_paths_g] = dl_path;
+ H5PL_num_paths_g++;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLappend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLprepend
+ *
+ * Purpose: Insert a plugin path at the beginning of the list.
+ *
+ * Return: Non-negative or success.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLprepend(const char *plugin_path)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ char *dl_path = NULL;
+ unsigned int plindex;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*s", plugin_path);
+ if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
+ if(NULL == plugin_path)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
+ if(NULL == (dl_path = H5MM_strdup(plugin_path)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+
+ H5PL_EXPAND_ENV_VAR
+
+ for (plindex = (unsigned int)H5PL_num_paths_g; plindex > 0; plindex--)
+ H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1];
+ H5PL_path_table_g[0] = dl_path;
+ H5PL_num_paths_g++;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLprepend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLreplace
+ *
+ * Purpose: Replace the path at the specified index.
+ *
+ * Return: Non-negative or success.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLreplace(const char *plugin_path, unsigned int index)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ char *dl_path = NULL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "*sIu", plugin_path, index);
+ if(NULL == plugin_path)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
+ if(index >= H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
+ if(NULL == (dl_path = H5MM_strdup(plugin_path)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+
+ H5PL_EXPAND_ENV_VAR
+
+ if(H5PL_path_table_g[index])
+ H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]);
+ H5PL_path_table_g[index] = dl_path;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLreplace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLinsert
+ *
+ * Purpose: Insert a plugin path at the specified index, moving other paths after the index.
+ *
+ * Return: Non-negative or success.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLinsert(const char *plugin_path, unsigned int index)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ char *dl_path = NULL;
+ unsigned int plindex;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "*sIu", plugin_path, index);
+ if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
+ if(NULL == plugin_path)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
+ if(index >= H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
+ if(NULL == (dl_path = H5MM_strdup(plugin_path)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+
+ H5PL_EXPAND_ENV_VAR
+
+ for(plindex = (unsigned int)H5PL_num_paths_g; plindex > index; plindex--)
+ H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1];
+ H5PL_path_table_g[index] = dl_path;
+ H5PL_num_paths_g++;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLinsert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLremove
+ *
+ * Purpose: Remove the plugin path at the specifed index and compacting the list.
+ *
+ * Return: Non-negative or success.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLremove(unsigned int index)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ unsigned int plindex;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "Iu", index);
+ if(H5PL_num_paths_g == 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table")
+ if(index >= H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
+ if(NULL == H5PL_path_table_g[index])
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index")
+ H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]);
+
+ H5PL_num_paths_g--;
+ for(plindex = index; plindex < (unsigned int)H5PL_num_paths_g; plindex++)
+ H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex + 1];
+ H5PL_path_table_g[H5PL_num_paths_g] = NULL;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLremove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLget
+ *
+ * Purpose: Query the plugin path at the specified index.
+ *
+ * Return: Success: The length of path.
+ *
+ * If `pathname' is non-NULL then write up to `size' bytes into that
+ * buffer and always return the length of the pathname.
+ * Otherwise `size' is ignored and the function does not store the pathname,
+ * just returning the number of characters required to store the pathname.
+ * If an error occurs then the buffer pointed to by `pathname' (NULL or non-NULL)
+ * is unchanged and the function returns a negative value.
+ * If a zero is returned for the name's length, then there is no pathname
+ * associated with the index.
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5PLget(unsigned int index, char *pathname/*out*/, size_t size)
+{
+ ssize_t ret_value = 0; /* Return value */
+ size_t len = 0; /* Length of pathname */
+ char *dl_path = NULL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "Iuxz", index, pathname, size);
+ if(H5PL_num_paths_g == 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table")
+ if(index >= H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
+ if(NULL == (dl_path = H5PL_path_table_g[index]))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index")
+ len = HDstrlen(dl_path);
+ if(pathname) {
+ HDstrncpy(pathname, dl_path, MIN((size_t)(len + 1), size));
+ if((size_t)len >= size)
+ pathname[size - 1] = '\0';
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (ssize_t)len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLget() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PLsize
+ *
+ * Purpose: Query the size of the current list of plugin paths.
+ *
+ * Return: Plugin path size
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5PLsize(unsigned int *listsize)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*Iu", listsize);
+
+ *listsize = (unsigned int)H5PL_num_paths_g;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5PLsize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL__init_path_table
+ *
+ * Purpose: Initialize the path table.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * 18 March 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PL__init_path_table(void)
+{
+ char *dl_path = NULL;
+ char *origin_dl_path;
+ char *dir;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Retrieve paths from HDF5_PLUGIN_PATH if the user sets it
+ * or from the default paths if it isn't set.
+ */
+ origin_dl_path = HDgetenv("HDF5_PLUGIN_PATH");
+ if(NULL == origin_dl_path)
+ dl_path = H5MM_strdup(H5PL_DEFAULT_PATH);
+ else
+ dl_path = H5MM_strdup(origin_dl_path);
+ if(NULL == dl_path)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+
+ H5PL_EXPAND_ENV_VAR
+
+ /* Put paths in the path table. They are separated by ":" */
+ dir = HDstrtok(dl_path, H5PL_PATH_SEPARATOR);
+ while(dir) {
+ /* Check for too many directories in path */
+ if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
+ if(NULL == (H5PL_path_table_g[H5PL_num_paths_g] = H5MM_strdup(dir)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+ H5PL_num_paths_g++;
+ dir = HDstrtok(NULL, H5PL_PATH_SEPARATOR);
+ } /* end while */
+
+ H5PL_path_found_g = TRUE;
+
+done:
+ if(dl_path)
+ dl_path = (char *)H5MM_xfree(dl_path);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL__init_path_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL__find
+ *
+ * Purpose: Given a path, this function opens the directory and envokes
+ * another function to go through all files to find the right
+ * plugin library. Two function definitions are for Unix and
+ * Windows.
+ *
+ * Return: TRUE on success,
+ * FALSE on not found,
+ * negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef H5_HAVE_WIN32_API
+static htri_t
+H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info)
+{
+ char *pathname = NULL;
+ DIR *dirp = NULL;
+ struct dirent *dp;
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_STATIC
+
+ /* Open the directory */
+ if(!(dirp = HDopendir(dir)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory: %s", dir)
+
+ /* Iterates through all entries in the directory to find the right plugin library */
+ while(NULL != (dp = HDreaddir(dirp))) {
+ /* The library we are looking for should be called libxxx.so... on Unix
+ * or libxxx.xxx.dylib on Mac.
+ */
+#ifndef __CYGWIN__
+ if(!HDstrncmp(dp->d_name, "lib", (size_t)3) &&
+ (HDstrstr(dp->d_name, ".so") || HDstrstr(dp->d_name, ".dylib"))) {
+#else
+ if(!HDstrncmp(dp->d_name, "cyg", (size_t)3) &&
+ HDstrstr(dp->d_name, ".dll") ) {
+
+#endif
+ h5_stat_t my_stat;
+ size_t pathname_len;
+ htri_t found_in_dir;
+
+ /* Allocate & initialize the path name */
+ pathname_len = HDstrlen(dir) + HDstrlen(dp->d_name) + 2;
+ if(NULL == (pathname = (char *)H5MM_malloc(pathname_len)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+ HDsnprintf(pathname, pathname_len, "%s/%s", dir, dp->d_name);
+
+ /* Get info for directory entry */
+ if(HDstat(pathname, &my_stat) == -1)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't stat file: %s", HDstrerror(errno))
+
+ /* If it is a directory, skip it */
+ if(S_ISDIR(my_stat.st_mode))
+ continue;
+
+ /* Attempt to open the dynamic library as a filter library */
+ if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed")
+ if(found_in_dir)
+ HGOTO_DONE(TRUE) /* Indicate success */
+ pathname = (char *)H5MM_xfree(pathname);
+ } /* end if */
+ } /* end while */
+
+done:
+ if(dirp)
+ if(HDclosedir(dirp) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CLOSEERROR, FAIL, "can't close directory: %s", HDstrerror(errno))
+ pathname = (char *)H5MM_xfree(pathname);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL__find() */
+#else /* H5_HAVE_WIN32_API */
+static htri_t
+H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info)
+{
+ WIN32_FIND_DATAA fdFile;
+ HANDLE hFind;
+ char *pathname = NULL;
+ char service[2048];
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_STATIC
+
+ /* Specify a file mask. *.* = We want everything! */
+ sprintf(service, "%s\\*.dll", dir);
+ if((hFind = FindFirstFileA(service, &fdFile)) == INVALID_HANDLE_VALUE)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory")
+
+ do {
+ /* Find first file will always return "."
+ * and ".." as the first two directories.
+ */
+ if(HDstrcmp(fdFile.cFileName, ".") != 0 && HDstrcmp(fdFile.cFileName, "..") != 0) {
+ size_t pathname_len;
+ htri_t found_in_dir;
+
+ /* Allocate & initialize the path name */
+ pathname_len = HDstrlen(dir) + HDstrlen(fdFile.cFileName) + 2;
+ if(NULL == (pathname = (char *)H5MM_malloc(pathname_len)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
+ HDsnprintf(pathname, pathname_len, "%s\\%s", dir, fdFile.cFileName);
+
+ /* Is the entity a File or Folder? */
+ if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+
+ if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed")
+ if(found_in_dir)
+ HGOTO_DONE(TRUE) /* Indicate success */
+ pathname = (char *)H5MM_xfree(pathname);
+ } /* end if */
+ } while(FindNextFileA(hFind, &fdFile)); /* Find the next file. */
+
+done:
+ if(hFind)
+ FindClose(hFind);
+ if(pathname)
+ pathname = (char *)H5MM_xfree(pathname);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL__find() */
+#endif /* H5_HAVE_WIN32_API */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL__open
+ *
+ * Purpose: Iterates through all files to find the right plugin library.
+ * It loads the dynamic plugin library and keeps it on the list
+ * of loaded libraries.
+ *
+ * Return: TRUE on success,
+ * FALSE on not found,
+ * negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5PL__open(H5PL_type_t pl_type, char *libname, int pl_id, const void **pl_info)
+{
+ H5PL_HANDLE handle = NULL;
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_STATIC
+
+ /* There are different reasons why a library can't be open, e.g. wrong architecture.
+ * simply continue if we can't open it.
+ */
+ if(NULL == (handle = H5PL_OPEN_DLIB(libname))) {
+ H5PL_CLR_ERROR; /* clear error */
+ } /* end if */
+ else {
+ H5PL_get_plugin_info_t get_plugin_info = NULL;
+
+ /* Return a handle for the function H5PLget_plugin_info in the dynamic library.
+ * The plugin library is suppose to define this function.
+ */
+ if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_info"))) {
+ if(H5PL__close(handle) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
+ } /* end if */
+ else {
+ const H5Z_class2_t *plugin_info;
+
+ /* Invoke H5PLget_plugin_info to verify this is the right library we are looking for.
+ * Move on if it isn't.
+ */
+ if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)())) {
+ if(H5PL__close(handle) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get plugin info")
+ } /* end if */
+
+ /* Successfully found plugin library, check if it's the right one */
+ if(plugin_info->id == pl_id) {
+ /* Expand the table if it is too small */
+ if(H5PL_table_used_g >= H5PL_table_alloc_g) {
+ size_t n = MAX(H5Z_MAX_NFILTERS, 2 * H5PL_table_alloc_g);
+ H5PL_table_t *table = (H5PL_table_t *)H5MM_realloc(H5PL_table_g, n * sizeof(H5PL_table_t));
+
+ if(!table)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend dynamic library table")
+
+ H5PL_table_g = table;
+ H5PL_table_alloc_g = n;
+ } /* end if */
+
+ (H5PL_table_g[H5PL_table_used_g]).handle = handle;
+ (H5PL_table_g[H5PL_table_used_g]).pl_type = pl_type;
+ (H5PL_table_g[H5PL_table_used_g]).pl_id = plugin_info->id;
+ H5PL_table_used_g++;
+
+ /* Set the plugin info to return */
+ *pl_info = (const void *)plugin_info;
+
+ /* Indicate success */
+ ret_value = TRUE;
+ } /* end if */
+ else
+ if(H5PL__close(handle) < 0)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL__open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL__search_table
+ *
+ * Purpose: Search in the list of already opened dynamic libraries
+ * to see if the one we are looking for is already opened.
+ *
+ * Return: TRUE on success,
+ * FALSE on not found,
+ * Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info)
+{
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_STATIC
+
+ /* Search in the table of already opened dynamic libraries */
+ if(H5PL_table_used_g > 0) {
+ size_t i;
+
+ for(i = 0; i < H5PL_table_used_g; i++) {
+ if((plugin_type == (H5PL_table_g[i]).pl_type) && (type_id == (H5PL_table_g[i]).pl_id)) {
+ H5PL_get_plugin_info_t get_plugin_info;
+ const H5Z_class2_t *plugin_info;
+
+ if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC((H5PL_table_g[i]).handle, "H5PLget_plugin_info")))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get function for H5PLget_plugin_info")
+
+ if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)()))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get plugin info")
+
+ *info = plugin_info;
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5PL__search_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5PL__close
+ *
+ * Purpose: Closes the handle for dynamic library
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5PL__close(H5PL_HANDLE handle)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ H5PL_CLOSE_LIB(handle);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5PL__close() */
+
diff --git a/src/H5PLextern.h b/src/H5PLextern.h
new file mode 100644
index 0000000..7547ad7
--- /dev/null
+++ b/src/H5PLextern.h
@@ -0,0 +1,44 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <songyulu@hdfgroup.org>
+ * 13 February 2013
+ */
+#ifndef _H5PLextern_H
+#define _H5PLextern_H
+
+/* Include HDF5 header */
+#include "hdf5.h"
+
+/* plugins always export */
+#if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5PLUGIN_DLL __declspec(dllexport)
+#elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5PLUGIN_DLL __attribute__ ((visibility("default")))
+#else
+ #define H5PLUGIN_DLL
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5PLUGIN_DLL H5PL_type_t H5PLget_plugin_type(void);
+H5PLUGIN_DLL const void *H5PLget_plugin_info(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5PLextern_H */
+
diff --git a/src/H5PLmodule.h b/src/H5PLmodule.h
new file mode 100644
index 0000000..b441aed
--- /dev/null
+++ b/src/H5PLmodule.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5PL package. Including this header means that the source file
+ * is part of the H5PL package.
+ */
+#ifndef _H5PLmodule_H
+#define _H5PLmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5PL_MODULE
+#define H5_MY_PKG H5PL
+#define H5_MY_PKG_ERR H5E_PLUGIN
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5PLmodule_H */
+
+
diff --git a/src/H5PLpkg.h b/src/H5PLpkg.h
new file mode 100644
index 0000000..e356893
--- /dev/null
+++ b/src/H5PLpkg.h
@@ -0,0 +1,48 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !(defined H5PL_FRIEND || defined H5PL_MODULE)
+#error "Do not include this file outside the H5PL package!"
+#endif
+
+#ifndef _H5PLpkg_H
+#define _H5PLpkg_H
+
+/* Include private header file */
+#include "H5PLprivate.h" /* Filter functions */
+
+/* Other private headers needed by this file */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+#define H5PL_MAX_PATH_NUM 16
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+#endif /* _H5PLpkg_H */
+
diff --git a/src/H5PLprivate.h b/src/H5PLprivate.h
new file mode 100644
index 0000000..0ab8f8c
--- /dev/null
+++ b/src/H5PLprivate.h
@@ -0,0 +1,50 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Raymond Lu <songyulu@hdfgroup.org>
+ * 13 February 2013
+ */
+
+#ifndef _H5PLprivate_H
+#define _H5PLprivate_H
+
+/* Include package's public header */
+#include "H5PLpublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* Internal API routines */
+H5_DLL const void *H5PL_load(H5PL_type_t plugin_type, int type_id);
+
+#endif /* _H5PLprivate_H */
+
diff --git a/src/H5PLpublic.h b/src/H5PLpublic.h
new file mode 100644
index 0000000..9ce1fca
--- /dev/null
+++ b/src/H5PLpublic.h
@@ -0,0 +1,58 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Raymond Lu <songyulu@hdfgroup.org>
+ * 13 February 2013
+ */
+
+#ifndef _H5PLpublic_H
+#define _H5PLpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h" /* Generic Functions */
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+/* Plugin type used by the plugin library */
+typedef enum H5PL_type_t {
+ H5PL_TYPE_ERROR = -1, /*error */
+ H5PL_TYPE_FILTER = 0, /*filter */
+ H5PL_TYPE_NONE = 1 /*this must be last! */
+} H5PL_type_t;
+
+/* Common dynamic plugin type flags used by the set/get_loading_state functions */
+#define H5PL_FILTER_PLUGIN 0x0001
+#define H5PL_ALL_PLUGIN 0xFFFF
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* plugin state */
+H5_DLL herr_t H5PLset_loading_state(unsigned int plugin_type);
+H5_DLL herr_t H5PLget_loading_state(unsigned int *plugin_type/*out*/);
+H5_DLL herr_t H5PLappend(const char *plugin_path);
+H5_DLL herr_t H5PLprepend(const char *plugin_path);
+H5_DLL herr_t H5PLreplace(const char *plugin_path, unsigned int index);
+H5_DLL herr_t H5PLinsert(const char *plugin_path, unsigned int index);
+H5_DLL herr_t H5PLremove(unsigned int index);
+H5_DLL ssize_t H5PLget(unsigned int index, char *pathname/*out*/, size_t size);
+H5_DLL herr_t H5PLsize(unsigned int *listsize/*out*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5PLpublic_H */
+
diff --git a/src/H5Pacpl.c b/src/H5Pacpl.c
new file mode 100644
index 0000000..4368dd6
--- /dev/null
+++ b/src/H5Pacpl.c
@@ -0,0 +1,88 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pacpl.c
+ * January 2 2006
+ * James Laird <jlaird@ncsa.uiuc.edu>
+ *
+ * Purpose: Attribute creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Attribute creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_ACRT[1] = {{
+ "attribute create", /* Class name for debugging */
+ H5P_TYPE_ATTRIBUTE_CREATE, /* Class type */
+
+ &H5P_CLS_STRING_CREATE_g, /* Parent class */
+ &H5P_CLS_ATTRIBUTE_CREATE_g, /* Pointer to class */
+ &H5P_CLS_ATTRIBUTE_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_ATTRIBUTE_CREATE_ID_g, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
diff --git a/src/H5Pdapl.c b/src/H5Pdapl.c
new file mode 100644
index 0000000..3b0a8c5
--- /dev/null
+++ b/src/H5Pdapl.c
@@ -0,0 +1,1294 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pdapl.c
+ * October 27, 2008
+ * Neil Fortner <nfortne2@hdfgroup.org>
+ *
+ * Purpose: Dataset access property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= Dataset Access properties ============ */
+/* Definitions for size of raw data chunk cache(slots) */
+#define H5D_ACS_DATA_CACHE_NUM_SLOTS_SIZE sizeof(size_t)
+#define H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF H5D_CHUNK_CACHE_NSLOTS_DEFAULT
+#define H5D_ACS_DATA_CACHE_NUM_SLOTS_ENC H5P__encode_chunk_cache_nslots
+#define H5D_ACS_DATA_CACHE_NUM_SLOTS_DEC H5P__decode_chunk_cache_nslots
+/* Definition for size of raw data chunk cache(bytes) */
+#define H5D_ACS_DATA_CACHE_BYTE_SIZE_SIZE sizeof(size_t)
+#define H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF H5D_CHUNK_CACHE_NBYTES_DEFAULT
+#define H5D_ACS_DATA_CACHE_BYTE_SIZE_ENC H5P__encode_chunk_cache_nbytes
+#define H5D_ACS_DATA_CACHE_BYTE_SIZE_DEC H5P__decode_chunk_cache_nbytes
+/* Definition for preemption read chunks first */
+#define H5D_ACS_PREEMPT_READ_CHUNKS_SIZE sizeof(double)
+#define H5D_ACS_PREEMPT_READ_CHUNKS_DEF H5D_CHUNK_CACHE_W0_DEFAULT
+#define H5D_ACS_PREEMPT_READ_CHUNKS_ENC H5P__encode_double
+#define H5D_ACS_PREEMPT_READ_CHUNKS_DEC H5P__decode_double
+/* Definitions for VDS view option */
+#define H5D_ACS_VDS_VIEW_SIZE sizeof(H5D_vds_view_t)
+#define H5D_ACS_VDS_VIEW_DEF H5D_VDS_LAST_AVAILABLE
+#define H5D_ACS_VDS_VIEW_ENC H5P__dacc_vds_view_enc
+#define H5D_ACS_VDS_VIEW_DEC H5P__dacc_vds_view_dec
+/* Definitions for VDS printf gap */
+#define H5D_ACS_VDS_PRINTF_GAP_SIZE sizeof(hsize_t)
+#define H5D_ACS_VDS_PRINTF_GAP_DEF (hsize_t)0
+#define H5D_ACS_VDS_PRINTF_GAP_ENC H5P__encode_hsize_t
+#define H5D_ACS_VDS_PRINTF_GAP_DEC H5P__decode_hsize_t
+/* Definition for append flush */
+#define H5D_ACS_APPEND_FLUSH_SIZE sizeof(H5D_append_flush_t)
+#define H5D_ACS_APPEND_FLUSH_DEF {0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},NULL,NULL}
+/* Definitions for external file prefix */
+#define H5D_ACS_EFILE_PREFIX_SIZE sizeof(char *)
+#define H5D_ACS_EFILE_PREFIX_DEF NULL /*default is no prefix */
+#define H5D_ACS_EFILE_PREFIX_SET H5P__dapl_efile_pref_set
+#define H5D_ACS_EFILE_PREFIX_GET H5P__dapl_efile_pref_get
+#define H5D_ACS_EFILE_PREFIX_ENC H5P__dapl_efile_pref_enc
+#define H5D_ACS_EFILE_PREFIX_DEC H5P__dapl_efile_pref_dec
+#define H5D_ACS_EFILE_PREFIX_DEL H5P__dapl_efile_pref_del
+#define H5D_ACS_EFILE_PREFIX_COPY H5P__dapl_efile_pref_copy
+#define H5D_ACS_EFILE_PREFIX_CMP H5P__dapl_efile_pref_cmp
+#define H5D_ACS_EFILE_PREFIX_CLOSE H5P__dapl_efile_pref_close
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__dacc_reg_prop(H5P_genclass_t *pclass);
+static herr_t H5P__encode_chunk_cache_nslots(const void *value, void **_pp,
+ size_t *size);
+static herr_t H5P__decode_chunk_cache_nslots(const void **_pp, void *_value);
+static herr_t H5P__encode_chunk_cache_nbytes(const void *value, void **_pp,
+ size_t *size);
+static herr_t H5P__decode_chunk_cache_nbytes(const void **_pp, void *_value);
+
+/* Property list callbacks */
+static herr_t H5P__dacc_vds_view_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dacc_vds_view_dec(const void **pp, void *value);
+
+/* Property list callbacks */
+static herr_t H5P__dapl_efile_pref_set(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dapl_efile_pref_get(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__dapl_efile_pref_dec(const void **_pp, void *value);
+static herr_t H5P__dapl_efile_pref_del(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dapl_efile_pref_copy(const char* name, size_t size, void* value);
+static int H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__dapl_efile_pref_close(const char* name, size_t size, void* value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Dataset access property list class library initialization object */
+const H5P_libclass_t H5P_CLS_DACC[1] = {{
+ "dataset access", /* Class name for debugging */
+ H5P_TYPE_DATASET_ACCESS, /* Class type */
+
+ &H5P_CLS_LINK_ACCESS_g, /* Parent class */
+ &H5P_CLS_DATASET_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_DATASET_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_DATASET_ACCESS_ID_g, /* Pointer to default property list ID */
+ H5P__dacc_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const H5D_append_flush_t H5D_def_append_flush_g = H5D_ACS_APPEND_FLUSH_DEF; /* Default setting for append flush */
+static const char *H5D_def_efile_prefix_g = H5D_ACS_EFILE_PREFIX_DEF; /* Default external file prefix string */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dacc_reg_prop
+ *
+ * Purpose: Register the dataset access property list class's
+ * properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * October 27, 2008
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dacc_reg_prop(H5P_genclass_t *pclass)
+{
+ size_t rdcc_nslots = H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF; /* Default raw data chunk cache # of slots */
+ size_t rdcc_nbytes = H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF; /* Default raw data chunk cache # of bytes */
+ double rdcc_w0 = H5D_ACS_PREEMPT_READ_CHUNKS_DEF; /* Default raw data chunk cache dirty ratio */
+ H5D_vds_view_t virtual_view = H5D_ACS_VDS_VIEW_DEF; /* Default VDS view option */
+ hsize_t printf_gap = H5D_ACS_VDS_PRINTF_GAP_DEF; /* Default VDS printf gap */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register the size of raw data chunk cache (elements) */
+ if(H5P_register_real(pclass, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, H5D_ACS_DATA_CACHE_NUM_SLOTS_SIZE, &rdcc_nslots,
+ NULL, NULL, NULL, H5D_ACS_DATA_CACHE_NUM_SLOTS_ENC, H5D_ACS_DATA_CACHE_NUM_SLOTS_DEC, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the size of raw data chunk cache(bytes) */
+ if(H5P_register_real(pclass, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, H5D_ACS_DATA_CACHE_BYTE_SIZE_SIZE, &rdcc_nbytes,
+ NULL, NULL, NULL, H5D_ACS_DATA_CACHE_BYTE_SIZE_ENC, H5D_ACS_DATA_CACHE_BYTE_SIZE_DEC, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the preemption for reading chunks */
+ if(H5P_register_real(pclass, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, H5D_ACS_PREEMPT_READ_CHUNKS_SIZE, &rdcc_w0,
+ NULL, NULL, NULL, H5D_ACS_PREEMPT_READ_CHUNKS_ENC, H5D_ACS_PREEMPT_READ_CHUNKS_DEC, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the VDS view option */
+ if(H5P_register_real(pclass, H5D_ACS_VDS_VIEW_NAME, H5D_ACS_VDS_VIEW_SIZE, &virtual_view,
+ NULL, NULL, NULL, H5D_ACS_VDS_VIEW_ENC, H5D_ACS_VDS_VIEW_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the VDS printf gap */
+ if(H5P_register_real(pclass, H5D_ACS_VDS_PRINTF_GAP_NAME, H5D_ACS_VDS_PRINTF_GAP_SIZE, &printf_gap,
+ NULL, NULL, NULL, H5D_ACS_VDS_PRINTF_GAP_ENC, H5D_ACS_VDS_PRINTF_GAP_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register info for append flush */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_ACS_APPEND_FLUSH_NAME, H5D_ACS_APPEND_FLUSH_SIZE, &H5D_def_append_flush_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for external file prefix */
+ if(H5P_register_real(pclass, H5D_ACS_EFILE_PREFIX_NAME, H5D_ACS_EFILE_PREFIX_SIZE, &H5D_def_efile_prefix_g,
+ NULL, H5D_ACS_EFILE_PREFIX_SET, H5D_ACS_EFILE_PREFIX_GET, H5D_ACS_EFILE_PREFIX_ENC, H5D_ACS_EFILE_PREFIX_DEC,
+ H5D_ACS_EFILE_PREFIX_DEL, H5D_ACS_EFILE_PREFIX_COPY, H5D_ACS_EFILE_PREFIX_CMP, H5D_ACS_EFILE_PREFIX_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dacc_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_set
+ *
+ * Purpose: Copies an external file prefix property when it's set
+ * for a property list
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Copy the prefix */
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_get
+ *
+ * Purpose: Copies an external file prefix property when it's retrieved
+ * from a property list
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Copy the prefix */
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_enc
+ *
+ * Purpose: Callback routine which is called whenever the efile flags
+ * property in the dataset access property list is
+ * encoded.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size)
+{
+ const char *efile_pref = *(const char * const *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+ size_t len = 0;
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* calculate prefix length */
+ if(NULL != efile_pref)
+ len = HDstrlen(efile_pref);
+
+ enc_value = (uint64_t)len;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+
+ if(NULL != *pp) {
+ /* encode the length of the prefix */
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode the prefix */
+ if(NULL != efile_pref) {
+ HDmemcpy(*(char **)pp, efile_pref, len);
+ *pp += len;
+ } /* end if */
+ } /* end if */
+
+ *size += (1 + enc_size);
+ if(NULL != efile_pref)
+ *size += len;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_dec
+ *
+ * Purpose: Callback routine which is called whenever the efile prefix
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_dec(const void **_pp, void *_value)
+{
+ char **efile_pref = (char **)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ size_t len;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(efile_pref);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ len = (size_t)enc_value;
+
+ if(0 != len) {
+ /* Make a copy of the user's prefix string */
+ if(NULL == (*efile_pref = (char *)H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for prefix")
+ HDstrncpy(*efile_pref, *(const char **)pp, len);
+ (*efile_pref)[len] = '\0';
+
+ *pp += len;
+ } /* end if */
+ else
+ *efile_pref = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dapl_efile_pref_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_del
+ *
+ * Purpose: Frees memory used to store the external file prefix string
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_copy
+ *
+ * Purpose: Creates a copy of the external file prefix string
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_cmp
+ *
+ * Purpose: Callback routine which is called whenever the efile prefix
+ * property in the dataset creation property list is
+ * compared.
+ *
+ * Return: zero if VALUE1 and VALUE2 are equal, non zero otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size)
+{
+ const char *pref1 = *(const char * const *)value1;
+ const char *pref2 = *(const char * const *)value2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(NULL == pref1 && NULL != pref2)
+ HGOTO_DONE(1);
+ if(NULL != pref1 && NULL == pref2)
+ HGOTO_DONE(-1);
+ if(NULL != pref1 && NULL != pref2)
+ ret_value = HDstrcmp(pref1, pref2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dapl_efile_pref_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dapl_efile_pref_close
+ *
+ * Purpose: Frees memory used to store the external file prefix string
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dapl_efile_pref_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dapl_efile_pref_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_chunk_cache
+ *
+ * Purpose: Set the number of objects in the meta data cache and the
+ * maximum number of chunks and bytes in the raw data chunk cache.
+ * Once set, these values will override the values in the file access
+ * property list. Each of thhese values can be individually unset
+ * (or not set at all) by passing the macros:
+ * H5D_CHUNK_CACHE_NCHUNKS_DEFAULT,
+ * H5D_CHUNK_CACHE_NSLOTS_DEFAULT, and/or
+ * H5D_CHUNK_CACHE_W0_DEFAULT
+ * as appropriate.
+ *
+ * The RDCC_W0 value should be between 0 and 1 inclusive and
+ * indicates how much chunks that have been fully read or fully
+ * written are favored for preemption. A value of zero means
+ * fully read or written chunks are treated no differently than
+ * other chunks (the preemption is strictly LRU) while a value
+ * of one means fully read chunks are always preempted before
+ * other chunks.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Monday, October 27, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_chunk_cache(hid_t dapl_id, size_t rdcc_nslots, size_t rdcc_nbytes, double rdcc_w0)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "izzd", dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);
+
+ /* Check arguments. Note that we allow negative values - they are
+ * considered to "unset" the property. */
+ if(rdcc_w0 > (double)1.0f)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "raw data cache w0 value must be between 0.0 and 1.0 inclusive, or H5D_CHUNK_CACHE_W0_DEFAULT");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dapl_id,H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Set sizes */
+ if(H5P_set(plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &rdcc_nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache number of chunks");
+ if(H5P_set(plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &rdcc_nbytes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache byte size");
+ if(H5P_set(plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &rdcc_w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set preempt read chunks");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_chunk_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_chunk_cache
+ *
+ * Purpose: Retrieves the maximum possible number of elements in the meta
+ * data cache and the maximum possible number of elements and
+ * bytes and the RDCC_W0 value in the raw data chunk cache. Any
+ * (or all) arguments may be null pointers in which case the
+ * corresponding datum is not returned. If these properties have
+ * not been set on this property list, the default values for a
+ * file access property list are returned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Monday, October 27, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_chunk_cache(hid_t dapl_id, size_t *rdcc_nslots, size_t *rdcc_nbytes, double *rdcc_w0)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5P_genplist_t *def_plist; /* Default file access property list */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*z*z*d", dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);
+
+ /* Get the plist structure */
+ if (NULL == (plist = H5P_object_verify(dapl_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Get default file access plist */
+ if (NULL == (def_plist = (H5P_genplist_t *)H5I_object(H5P_FILE_ACCESS_DEFAULT)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for default fapl ID");
+
+ /* Get the properties. If a property is set to the default value, the value
+ * from the default fapl is used. */
+ if (rdcc_nslots) {
+ if (H5P_get(plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, rdcc_nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache number of slots");
+ if (*rdcc_nslots == H5D_CHUNK_CACHE_NSLOTS_DEFAULT)
+ if (H5P_get(def_plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, rdcc_nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default data cache number of slots");
+ } /* end if */
+ if (rdcc_nbytes) {
+ if (H5P_get(plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, rdcc_nbytes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache byte size");
+ if (*rdcc_nbytes == H5D_CHUNK_CACHE_NBYTES_DEFAULT)
+ if (H5P_get(def_plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, rdcc_nbytes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default data cache byte size");
+ } /* end if */
+ if (rdcc_w0) {
+ if (H5P_get(plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, rdcc_w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get preempt read chunks");
+ if (*rdcc_w0 < 0)
+ if (H5P_get(def_plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, rdcc_w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default preempt read chunks");
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_chunk_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_chunk_cache_nslots
+ *
+ * Purpose: Encode the rdcc_nslots parameter to a serialized
+ * property list. Similar to H5P__encode_size_t except
+ * the value of 255 for the enc_size field is reserved to
+ * indicate H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF, in which
+ * nothing further is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, January 23, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__encode_chunk_cache_nslots(const void *value, void **_pp, size_t *size)
+{
+ uint64_t enc_value; /* Property value to encode */
+ uint8_t **pp = (uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(size);
+
+ /* Determine if this is the default value, in which case only encode
+ * enc_size (as 255). Also set size needed for encoding. */
+ if(*(const size_t *)value == H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF) {
+ enc_size = 0;
+ *size += 1;
+ } /* end if */
+ else {
+ enc_value = (uint64_t)*(const size_t *)value;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size > 0);
+ *size += (1 + enc_size);
+ } /* end else */
+
+ HDassert(enc_size < 256);
+
+ if(NULL != *pp) {
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)enc_size;
+
+ /* Encode the value if necessary */
+ if(enc_size != 0) {
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_chunk_cache_nslots() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_chunk_cache_nslots
+ *
+ * Purpose: Decode the rdcc_nslots parameter from a serialized
+ * property list. Similar to H5P__decode_size_t except
+ * the value of 255 for the enc_size field is reserved to
+ * indicate H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF, in which
+ * nothing further needs to be decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, January 23, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__decode_chunk_cache_nslots(const void **_pp, void *_value)
+{
+ size_t *value = (size_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Determine if enc_size indicates that this is the default value, in which
+ * case set value to H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF and return */
+ if(enc_size == 0)
+ *value = H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF;
+ else {
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ H5_CHECKED_ASSIGN(*value, uint64_t, enc_value, size_t);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__decode_chunk_cache_nslots() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_chunk_cache_nbytes
+ *
+ * Purpose: Encode the rdcc_nbytes parameter to a serialized
+ * property list. Similar to H5P__encode_size_t except
+ * the value of 255 for the enc_size field is reserved to
+ * indicate H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF, in which
+ * nothing further is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, January 23, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__encode_chunk_cache_nbytes(const void *value, void **_pp, size_t *size)
+{
+ uint64_t enc_value; /* Property value to encode */
+ uint8_t **pp = (uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(size);
+
+ /* Determine if this is the default value, in which case only encode
+ * enc_size (as 255). Also set size needed for encoding. */
+ if(*(const size_t *)value == H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF) {
+ enc_size = 0;
+ *size += 1;
+ } /* end if */
+ else {
+ enc_value = (uint64_t)*(const size_t *)value;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size > 0);
+ *size += (1 + enc_size);
+ } /* end else */
+
+ HDassert(enc_size < 256);
+
+ if(NULL != *pp) {
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)enc_size;
+
+ /* Encode the value if necessary */
+ if(enc_size != 0) {
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_chunk_cache_nbytes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_chunk_cache_nbytes
+ *
+ * Purpose: Decode the rdcc_nbytes parameter from a serialized
+ * property list. Similar to H5P__decode_size_t except
+ * the value of 255 for the enc_size field is reserved to
+ * indicate H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF, in which
+ * nothing further needs to be decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, January 23, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__decode_chunk_cache_nbytes(const void **_pp, void *_value)
+{
+ size_t *value = (size_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Determine if enc_size indicates that this is the default value, in which
+ * case set value to H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF and return */
+ if(enc_size == 0)
+ *value = H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF;
+ else {
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ H5_CHECKED_ASSIGN(*value, uint64_t, enc_value, size_t);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__decode_chunk_cache_nbytes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_virtual_view
+ *
+ * Purpose: Takes the access property list for the virtual dataset,
+ * dapl_id, and the flag, view, and sets the VDS view
+ * according to the flag value. The view will include all
+ * data before the first missing mapped data found if the
+ * flag is set to H5D_VDS_FIRST_MISSING or to include all
+ * available mapped data if the flag is set to
+ * H5D_VDS_LAST_AVAIALBLE. Missing mapped data will be
+ * filled with the fill value according to the VDS creation
+ * property settings. For VDS with unlimited mappings, the
+ * view defines the extent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 4, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_virtual_view(hid_t plist_id, H5D_vds_view_t view)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDv", plist_id, view);
+
+ /* Check argument */
+ if((view != H5D_VDS_FIRST_MISSING) && (view != H5D_VDS_LAST_AVAILABLE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid bounds option")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_ACS_VDS_VIEW_NAME, &view) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_virtual_view() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_view
+ *
+ * Purpose: Takes the access property list for the virtual dataset,
+ * dapl_id, and gets the flag, view, set by the
+ * H5Pset_virtual_view call. The possible values of view are
+ * H5D_VDS_FIRST_MISSING or H5D_VDS_LAST_AVAIALBLE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 4, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_virtual_view(hid_t plist_id, H5D_vds_view_t *view)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Dv", plist_id, view);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value from property list */
+ if(view)
+ if(H5P_get(plist, H5D_ACS_VDS_VIEW_NAME, view) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_view() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dacc_vds_view_enc
+ *
+ * Purpose: Callback routine which is called whenever the vds view
+ * property in the dataset access property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, May 5, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dacc_vds_view_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5D_vds_view_t *view = (const H5D_vds_view_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(view);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode EDC property */
+ *(*pp)++ = (uint8_t)*view;
+
+ /* Size of EDC property */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dacc_vds_view_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dacc_vds_view_dec
+ *
+ * Purpose: Callback routine which is called whenever the vds view
+ * property in the dataset access property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, May 5, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dacc_vds_view_dec(const void **_pp, void *_value)
+{
+ H5D_vds_view_t *view = (H5D_vds_view_t *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(view);
+
+ /* Decode EDC property */
+ *view = (H5D_vds_view_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dacc_vds_view_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_virtual_printf_gap
+ *
+ * Purpose: Sets the access property list for the virtual dataset,
+ * dapl_id, to instruct the library to stop looking for the
+ * mapped data stored in the files and/or datasets with the
+ * printf-style names after not finding gap_size files and/or
+ * datasets. The found source files and datasets will
+ * determine the extent of the unlimited VDS with the printf
+ * -style mappings.
+ *
+ * For example, if regularly spaced blocks of VDS are mapped
+ * to datasets with the names d-1, d-2, d-3, ..., d-N, ...,
+ * and d-2 dataset is missing and gap_size is set to 0, then
+ * VDS will contain only data found in d-1. If d-2 and d-3
+ * are missing and gap_size is set to 2, then VDS will
+ * contain the data from d-1, d-3, ..., d-N, .... The blocks
+ * that are mapped to d-2 and d-3 will be filled according to
+ * the VDS fill value setting.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_virtual_printf_gap(hid_t plist_id, hsize_t gap_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", plist_id, gap_size);
+
+ /* Check argument */
+ if(gap_size == HSIZE_UNDEF)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid printf gap size")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_ACS_VDS_PRINTF_GAP_NAME, &gap_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_virtual_printf_gap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_printf_gap
+ *
+ * Purpose: Gets the maximum number of missing printf-style files
+ * and/or datasets for determining the extent of the
+ * unlimited VDS, gap_size, using the access property list
+ * for the virtual dataset, dapl_id. The default library
+ * value for gap_size is 0.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * May 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_virtual_printf_gap(hid_t plist_id, hsize_t *gap_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", plist_id, gap_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value from property list */
+ if(gap_size)
+ if(H5P_get(plist, H5D_ACS_VDS_PRINTF_GAP_NAME, gap_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_printf_gap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_append_flush
+ *
+ * Purpose: Sets the boundary, callback function, and user data in the
+ * property list.
+ * "ndims": number of array elements for boundary
+ * "boundary": used to determine whether the current dimension hits
+ * a boundary; if so, invoke the callback function and
+ * flush the dataset.
+ * "func": the callback function to invoke when the boundary is hit
+ * "udata": the user data to pass as parameter with the callback function
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_append_flush(hid_t plist_id, unsigned ndims, const hsize_t *boundary, H5D_append_cb_t func, void *udata)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5D_append_flush_t info; /* Property for append flush parameters */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIu*hx*x", plist_id, ndims, boundary, func, udata);
+
+ /* Check arguments */
+ if(0 == ndims)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality cannot be zero")
+ if(ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality is too large")
+ if(!boundary)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no boundary dimensions specified")
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && udata)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set up values */
+ info.ndims = ndims;
+ info.func = func;
+ info.udata = udata;
+
+ HDmemset(info.boundary, 0, sizeof(info.boundary));
+ /* boundary can be 0 to indicate no boundary is set */
+ for(u = 0; u < ndims; u++) {
+ if(boundary[u] != (boundary[u] & 0xffffffff)) /* negative value (including H5S_UNLIMITED) */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all boundary dimensions must be less than 2^32")
+ info.boundary[u] = boundary[u]; /* Store user's boundary dimensions */
+ } /* end for */
+
+ /* Set values */
+ if(H5P_set(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set append flush")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_append_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_append_flush()
+ *
+ * Purpose: Retrieves the boundary, callback function and user data set in
+ * property list.
+ * Note that the # of boundary sizes to retrieve will not exceed
+ * the parameter "ndims" and the ndims set previously via
+ * H5Pset_append_flush().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_append_flush(hid_t plist_id, unsigned ndims, hsize_t boundary[], H5D_append_cb_t *func, void **udata)
+{
+ H5P_genplist_t *plist; /* property list pointer */
+ H5D_append_flush_t info;
+ unsigned u; /* local index variable */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIu*h*x**x", plist_id, ndims, boundary, func, udata);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve info for append flush */
+ if(H5P_get(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object flush callback")
+
+ /* Assign return values */
+ if(boundary) {
+ HDmemset(boundary, 0, ndims * sizeof(hsize_t));
+ if(info.ndims > 0)
+ for(u = 0; u < info.ndims && u < ndims; u++)
+ boundary[u] = info.boundary[u];
+ } /* end if */
+ if(func)
+ *func = info.func;
+ if(udata)
+ *udata = info.udata;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_append_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_efile_prefix
+ *
+ * Purpose: Set a prefix to be used for any external files.
+ *
+ * If the prefix starts with ${ORIGIN}, this will be replaced by
+ * the absolute path of the directory of the HDF5 file containing
+ * the dataset.
+ *
+ * If the prefix is ".", no prefix will be applied.
+ *
+ * This property can be overwritten by the environment variable
+ * HDF5_EXTFILE_PREFIX.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_efile_prefix(hid_t plist_id, const char *prefix)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", plist_id, prefix);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set prefix */
+ if(H5P_set(plist, H5D_ACS_EFILE_PREFIX_NAME, &prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set prefix info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_efile_prefix() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_efile_prefix
+ *
+ * Purpose: Gets the prefix to be used for any external files.
+ *
+ * If the pointer is not NULL, it points to a user-allocated
+ * buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Pget_efile_prefix(hid_t plist_id, char *prefix, size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ char *my_prefix; /* Library's copy of the prefix */
+ size_t len; /* Length of prefix string */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*sz", plist_id, prefix, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the current prefix */
+ if(H5P_peek(plist, H5D_ACS_EFILE_PREFIX_NAME, &my_prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file prefix")
+
+ /* Check for prefix being set */
+ if(my_prefix) {
+ /* Copy to user's buffer, if given */
+ len = HDstrlen(my_prefix);
+ if(prefix) {
+ HDstrncpy(prefix, my_prefix, MIN(len + 1, size));
+ if(len >= size)
+ prefix[size - 1] = '\0';
+ } /* end if */
+ } /* end if */
+ else
+ len = 0;
+
+ /* Set return value */
+ ret_value = (ssize_t)len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_efile_prefix() */
+
diff --git a/src/H5Pdcpl.c b/src/H5Pdcpl.c
new file mode 100644
index 0000000..3b4c159
--- /dev/null
+++ b/src/H5Pdcpl.c
@@ -0,0 +1,3735 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pdcpl.c
+ * February 26 1998
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Dataset creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+#define H5D_FRIEND /* Suppress error about including H5Dpkg */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Ppkg.h" /* Property lists */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5VMprivate.h" /* Vectors and arrays */
+#include "H5Zprivate.h" /* Data filters */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Define default layout information */
+#define H5D_DEF_STORAGE_COMPACT_INIT {(hbool_t)FALSE, (size_t)0, NULL}
+#define H5D_DEF_STORAGE_CONTIG_INIT {HADDR_UNDEF, (hsize_t)0}
+#define H5D_DEF_STORAGE_CHUNK_INIT {H5D_CHUNK_IDX_BTREE, HADDR_UNDEF, H5D_COPS_BTREE, {{HADDR_UNDEF, NULL}}}
+#define H5D_DEF_LAYOUT_CHUNK_INIT {H5D_CHUNK_IDX_BTREE, (uint8_t)0, (unsigned)0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, (unsigned)0, (uint32_t)0, (hsize_t)0, (hsize_t)0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {{{(uint8_t)0}}}}
+#define H5D_DEF_STORAGE_VIRTUAL_INIT {{HADDR_UNDEF, 0}, 0, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, H5D_VDS_ERROR, HSIZE_UNDEF, -1, -1, FALSE}
+#ifdef H5_HAVE_C99_DESIGNATED_INITIALIZER
+#define H5D_DEF_STORAGE_COMPACT {H5D_COMPACT, { .compact = H5D_DEF_STORAGE_COMPACT_INIT }}
+#define H5D_DEF_STORAGE_CONTIG {H5D_CONTIGUOUS, { .contig = H5D_DEF_STORAGE_CONTIG_INIT }}
+#define H5D_DEF_STORAGE_CHUNK {H5D_CHUNKED, { .chunk = H5D_DEF_STORAGE_CHUNK_INIT }}
+#define H5D_DEF_STORAGE_VIRTUAL {H5D_VIRTUAL, { .virt = H5D_DEF_STORAGE_VIRTUAL_INIT }}
+#define H5D_DEF_LAYOUT_COMPACT {H5D_COMPACT, H5O_LAYOUT_VERSION_DEFAULT, H5D_LOPS_COMPACT, {H5D_DEF_LAYOUT_CHUNK_INIT}, H5D_DEF_STORAGE_COMPACT}
+#define H5D_DEF_LAYOUT_CONTIG {H5D_CONTIGUOUS, H5O_LAYOUT_VERSION_DEFAULT, H5D_LOPS_CONTIG, {H5D_DEF_LAYOUT_CHUNK_INIT}, H5D_DEF_STORAGE_CONTIG}
+#define H5D_DEF_LAYOUT_CHUNK {H5D_CHUNKED, H5O_LAYOUT_VERSION_DEFAULT, H5D_LOPS_CHUNK, {H5D_DEF_LAYOUT_CHUNK_INIT}, H5D_DEF_STORAGE_CHUNK}
+#define H5D_DEF_LAYOUT_VIRTUAL {H5D_VIRTUAL, H5O_LAYOUT_VERSION_4, H5D_LOPS_VIRTUAL, {H5D_DEF_LAYOUT_CHUNK_INIT}, H5D_DEF_STORAGE_VIRTUAL}
+#else /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+/* Note that the compact & chunked layout initialization values are using the
+ * contiguous layout initialization in the union, because the contiguous
+ * layout is first in the union. These values are overridden in the
+ * H5P__init_def_layout() routine. -QAK
+ */
+#define H5D_DEF_LAYOUT_COMPACT {H5D_COMPACT, H5O_LAYOUT_VERSION_DEFAULT, NULL, {H5D_DEF_LAYOUT_CHUNK_INIT}, {H5D_CONTIGUOUS, H5D_DEF_STORAGE_CONTIG_INIT}}
+#define H5D_DEF_LAYOUT_CONTIG {H5D_CONTIGUOUS, H5O_LAYOUT_VERSION_DEFAULT, NULL, {H5D_DEF_LAYOUT_CHUNK_INIT}, {H5D_CONTIGUOUS, H5D_DEF_STORAGE_CONTIG_INIT}}
+#define H5D_DEF_LAYOUT_CHUNK {H5D_CHUNKED, H5O_LAYOUT_VERSION_DEFAULT, NULL, {H5D_DEF_LAYOUT_CHUNK_INIT}, {H5D_CONTIGUOUS, H5D_DEF_STORAGE_CONTIG_INIT}}
+#define H5D_DEF_LAYOUT_VIRTUAL {H5D_VIRTUAL, H5O_LAYOUT_VERSION_4, NULL, {H5D_DEF_LAYOUT_CHUNK_INIT}, {H5D_CONTIGUOUS, H5D_DEF_STORAGE_CONTIG_INIT}}
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+/* ======== Dataset creation properties ======== */
+/* Definitions for storage layout property */
+#define H5D_CRT_LAYOUT_SIZE sizeof(H5O_layout_t)
+#define H5D_CRT_LAYOUT_DEF H5D_DEF_LAYOUT_CONTIG
+#define H5D_CRT_LAYOUT_SET H5P__dcrt_layout_set
+#define H5D_CRT_LAYOUT_GET H5P__dcrt_layout_get
+#define H5D_CRT_LAYOUT_ENC H5P__dcrt_layout_enc
+#define H5D_CRT_LAYOUT_DEC H5P__dcrt_layout_dec
+#define H5D_CRT_LAYOUT_DEL H5P__dcrt_layout_del
+#define H5D_CRT_LAYOUT_COPY H5P__dcrt_layout_copy
+#define H5D_CRT_LAYOUT_CMP H5P__dcrt_layout_cmp
+#define H5D_CRT_LAYOUT_CLOSE H5P__dcrt_layout_close
+/* Definitions for fill value. size=0 means fill value will be 0 as
+ * library default; size=-1 means fill value is undefined. */
+#define H5D_CRT_FILL_VALUE_SIZE sizeof(H5O_fill_t)
+#define H5D_CRT_FILL_VALUE_DEF {{0, NULL, H5O_NULL_ID, {{0, HADDR_UNDEF}}}, H5O_FILL_VERSION_2, NULL, 0, NULL, H5D_ALLOC_TIME_LATE, H5D_FILL_TIME_IFSET, FALSE}
+#define H5D_CRT_FILL_VALUE_SET H5P__dcrt_fill_value_set
+#define H5D_CRT_FILL_VALUE_GET H5P__dcrt_fill_value_get
+#define H5D_CRT_FILL_VALUE_ENC H5P__dcrt_fill_value_enc
+#define H5D_CRT_FILL_VALUE_DEC H5P__dcrt_fill_value_dec
+#define H5D_CRT_FILL_VALUE_DEL H5P__dcrt_fill_value_del
+#define H5D_CRT_FILL_VALUE_COPY H5P__dcrt_fill_value_copy
+#define H5D_CRT_FILL_VALUE_CMP H5P_fill_value_cmp
+#define H5D_CRT_FILL_VALUE_CLOSE H5P__dcrt_fill_value_close
+/* Definitions for space allocation time state */
+#define H5D_CRT_ALLOC_TIME_STATE_SIZE sizeof(unsigned)
+#define H5D_CRT_ALLOC_TIME_STATE_DEF 1
+#define H5D_CRT_ALLOC_TIME_STATE_ENC H5P__encode_unsigned
+#define H5D_CRT_ALLOC_TIME_STATE_DEC H5P__decode_unsigned
+/* Definitions for external file list */
+#define H5D_CRT_EXT_FILE_LIST_SIZE sizeof(H5O_efl_t)
+#define H5D_CRT_EXT_FILE_LIST_DEF {HADDR_UNDEF, 0, 0, NULL}
+#define H5D_CRT_EXT_FILE_LIST_SET H5P__dcrt_ext_file_list_set
+#define H5D_CRT_EXT_FILE_LIST_GET H5P__dcrt_ext_file_list_get
+#define H5D_CRT_EXT_FILE_LIST_ENC H5P__dcrt_ext_file_list_enc
+#define H5D_CRT_EXT_FILE_LIST_DEC H5P__dcrt_ext_file_list_dec
+#define H5D_CRT_EXT_FILE_LIST_DEL H5P__dcrt_ext_file_list_del
+#define H5D_CRT_EXT_FILE_LIST_COPY H5P__dcrt_ext_file_list_copy
+#define H5D_CRT_EXT_FILE_LIST_CMP H5P__dcrt_ext_file_list_cmp
+#define H5D_CRT_EXT_FILE_LIST_CLOSE H5P__dcrt_ext_file_list_close
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* General routines */
+static herr_t H5P__set_layout(H5P_genplist_t *plist, const H5O_layout_t *layout);
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+static herr_t H5P__init_def_layout(void);
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+/* Property class callbacks */
+static herr_t H5P__dcrt_reg_prop(H5P_genclass_t *pclass);
+
+/* Property callbacks */
+static herr_t H5P__dcrt_layout_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_layout_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_layout_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dcrt_layout_dec(const void **pp, void *value);
+static herr_t H5P__dcrt_layout_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_layout_copy(const char *name, size_t size, void *value);
+static int H5P__dcrt_layout_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__dcrt_layout_close(const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_fill_value_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_fill_value_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_fill_value_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dcrt_fill_value_dec(const void **pp, void *value);
+static herr_t H5P__dcrt_fill_value_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_fill_value_copy(const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_fill_value_close(const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_ext_file_list_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_ext_file_list_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_ext_file_list_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dcrt_ext_file_list_dec(const void **pp, void *value);
+static herr_t H5P__dcrt_ext_file_list_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__dcrt_ext_file_list_copy(const char *name, size_t size, void *value);
+static int H5P__dcrt_ext_file_list_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__dcrt_ext_file_list_close(const char *name, size_t size, void *value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Dataset creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_DCRT[1] = {{
+ "dataset create", /* Class name for debugging */
+ H5P_TYPE_DATASET_CREATE, /* Class type */
+
+ &H5P_CLS_OBJECT_CREATE_g, /* Parent class */
+ &H5P_CLS_DATASET_CREATE_g, /* Pointer to class */
+ &H5P_CLS_DATASET_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_DATASET_CREATE_ID_g, /* Pointer to default property list ID */
+ H5P__dcrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Declare extern the free list to manage blocks of type conversion data */
+H5FL_BLK_EXTERN(type_conv);
+
+
+/***************************/
+/* Local Private Variables */
+/***************************/
+
+/* Property value defaults */
+static const H5O_layout_t H5D_def_layout_g = H5D_CRT_LAYOUT_DEF; /* Default storage layout */
+static const H5O_fill_t H5D_def_fill_g = H5D_CRT_FILL_VALUE_DEF; /* Default fill value */
+static const unsigned H5D_def_alloc_time_state_g = H5D_CRT_ALLOC_TIME_STATE_DEF; /* Default allocation time state */
+static const H5O_efl_t H5D_def_efl_g = H5D_CRT_EXT_FILE_LIST_DEF; /* Default external file list */
+
+/* Defaults for each type of layout */
+#ifdef H5_HAVE_C99_DESIGNATED_INITIALIZER
+static const H5O_layout_t H5D_def_layout_compact_g = H5D_DEF_LAYOUT_COMPACT;
+static const H5O_layout_t H5D_def_layout_contig_g = H5D_DEF_LAYOUT_CONTIG;
+static const H5O_layout_t H5D_def_layout_chunk_g = H5D_DEF_LAYOUT_CHUNK;
+static const H5O_layout_t H5D_def_layout_virtual_g = H5D_DEF_LAYOUT_VIRTUAL;
+#else /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+static H5O_layout_t H5D_def_layout_compact_g = H5D_DEF_LAYOUT_COMPACT;
+static H5O_layout_t H5D_def_layout_contig_g = H5D_DEF_LAYOUT_CONTIG;
+static H5O_layout_t H5D_def_layout_chunk_g = H5D_DEF_LAYOUT_CHUNK;
+static H5O_layout_t H5D_def_layout_virtual_g = H5D_DEF_LAYOUT_VIRTUAL;
+static hbool_t H5P_dcrt_def_layout_init_g = FALSE;
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_reg_prop
+ *
+ * Purpose: Register the dataset creation property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register the storage layout property */
+ if(H5P_register_real(pclass, H5D_CRT_LAYOUT_NAME, H5D_CRT_LAYOUT_SIZE, &H5D_def_layout_g,
+ NULL, H5D_CRT_LAYOUT_SET, H5D_CRT_LAYOUT_GET, H5D_CRT_LAYOUT_ENC, H5D_CRT_LAYOUT_DEC,
+ H5D_CRT_LAYOUT_DEL, H5D_CRT_LAYOUT_COPY, H5D_CRT_LAYOUT_CMP, H5D_CRT_LAYOUT_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the fill value property */
+ if(H5P_register_real(pclass, H5D_CRT_FILL_VALUE_NAME, H5D_CRT_FILL_VALUE_SIZE, &H5D_def_fill_g,
+ NULL, H5D_CRT_FILL_VALUE_SET, H5D_CRT_FILL_VALUE_GET, H5D_CRT_FILL_VALUE_ENC, H5D_CRT_FILL_VALUE_DEC,
+ H5D_CRT_FILL_VALUE_DEL, H5D_CRT_FILL_VALUE_COPY, H5D_CRT_FILL_VALUE_CMP, H5D_CRT_FILL_VALUE_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the space allocation time state property */
+ if(H5P_register_real(pclass, H5D_CRT_ALLOC_TIME_STATE_NAME, H5D_CRT_ALLOC_TIME_STATE_SIZE, &H5D_def_alloc_time_state_g,
+ NULL, NULL, NULL, H5D_CRT_ALLOC_TIME_STATE_ENC, H5D_CRT_ALLOC_TIME_STATE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the external file list property */
+ if(H5P_register_real(pclass, H5D_CRT_EXT_FILE_LIST_NAME, H5D_CRT_EXT_FILE_LIST_SIZE, &H5D_def_efl_g,
+ NULL, H5D_CRT_EXT_FILE_LIST_SET, H5D_CRT_EXT_FILE_LIST_GET, H5D_CRT_EXT_FILE_LIST_ENC, H5D_CRT_EXT_FILE_LIST_DEC,
+ H5D_CRT_EXT_FILE_LIST_DEL, H5D_CRT_EXT_FILE_LIST_COPY, H5D_CRT_EXT_FILE_LIST_CMP, H5D_CRT_EXT_FILE_LIST_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_set
+ *
+ * Purpose: Copies a layout property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_layout_t *layout = (H5O_layout_t *)value; /* Create local aliases for values */
+ H5O_layout_t new_layout;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of layout */
+ if(NULL == H5O_msg_copy(H5O_LAYOUT_ID, layout, &new_layout))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy layout")
+
+ /* Copy new layout message over old one */
+ *layout = new_layout;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_get
+ *
+ * Purpose: Copies a layout property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_layout_t *layout = (H5O_layout_t *)value; /* Create local aliases for values */
+ H5O_layout_t new_layout;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of layout */
+ if(NULL == H5O_msg_copy(H5O_LAYOUT_ID, layout, &new_layout))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy layout")
+
+ /* Copy new layout message over old one */
+ *layout = new_layout;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_enc
+ *
+ * Purpose: Callback routine which is called whenever the layout
+ * property in the dataset creation property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_layout_t *layout = (const H5O_layout_t *)value; /* Create local aliases for values */
+ uint8_t **pp = (uint8_t **)_pp;
+ uint8_t *tmp_p;
+ size_t tmp_size;
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(layout);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode layout type */
+ *(*pp)++ = (uint8_t)layout->type;
+ *size += sizeof(uint8_t);
+
+ /* If layout is chunked, encode chunking structure */
+ if(H5D_CHUNKED == layout->type) {
+ /* Encode rank */
+ *(*pp)++ = (uint8_t)layout->u.chunk.ndims;
+ *size += sizeof(uint8_t);
+
+ /* Encode chunk dims */
+ HDcompile_assert(sizeof(uint32_t) == sizeof(layout->u.chunk.dim[0]));
+ for(u = 0; u < (size_t)layout->u.chunk.ndims; u++) {
+ UINT32ENCODE(*pp, layout->u.chunk.dim[u])
+ *size += sizeof(uint32_t);
+ } /* end for */
+ } /* end if */
+ else if(H5D_VIRTUAL == layout->type) {
+ uint64_t nentries = (uint64_t)layout->storage.u.virt.list_nused;
+
+ /* Encode number of entries */
+ UINT64ENCODE(*pp, nentries)
+ *size += (size_t)8;
+
+ /* Iterate over entries */
+ for(u = 0; u < layout->storage.u.virt.list_nused; u++) {
+ /* Source file name */
+ tmp_size = HDstrlen(layout->storage.u.virt.list[u].source_file_name) + (size_t)1;
+ (void)HDmemcpy(*pp, layout->storage.u.virt.list[u].source_file_name, tmp_size);
+ *pp += tmp_size;
+ *size += tmp_size;
+
+ /* Source dataset name */
+ tmp_size = HDstrlen(layout->storage.u.virt.list[u].source_dset_name) + (size_t)1;
+ (void)HDmemcpy(*pp, layout->storage.u.virt.list[u].source_dset_name, tmp_size);
+ *pp += tmp_size;
+ *size += tmp_size;
+
+ /* Source selection. Note that we are not passing the real
+ * allocated size because we do not know it. H5P__encode should
+ * have verified that the buffer is large enough for the entire
+ * list before we get here. */
+ tmp_size = (size_t)-1;
+ tmp_p = *pp;
+ if(H5S_encode(layout->storage.u.virt.list[u].source_select, pp, &tmp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "unable to serialize source selection")
+ *size += (size_t)(*pp - tmp_p);
+
+ /* Virtual dataset selection. Same notes as above apply. */
+ tmp_size = (size_t)-1;
+ tmp_p = *pp;
+ if(H5S_encode(layout->storage.u.virt.list[u].source_dset.virtual_select, pp, &tmp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "unable to serialize virtual selection")
+ *size += (size_t)(*pp - tmp_p);
+ } /* end for */
+ } /* end if */
+ } /* end if */
+ else {
+ /* Size of layout type */
+ *size += sizeof(uint8_t);
+
+ /* If layout is chunked, calculate chunking structure */
+ if(H5D_CHUNKED == layout->type) {
+ *size += sizeof(uint8_t);
+ *size += layout->u.chunk.ndims * sizeof(uint32_t);
+ } /* end if */
+ else if(H5D_VIRTUAL == layout->type) {
+ /* Calculate size of virtual layout info */
+ /* number of entries */
+ *size += (size_t)8;
+
+ /* Iterate over entries */
+ for(u = 0; u < layout->storage.u.virt.list_nused; u++) {
+ /* Source file name */
+ tmp_size = HDstrlen(layout->storage.u.virt.list[u].source_file_name) + (size_t)1;
+ *size += tmp_size;
+
+ /* Source dataset name */
+ tmp_size = HDstrlen(layout->storage.u.virt.list[u].source_dset_name) + (size_t)1;
+ *size += tmp_size;
+
+ /* Source selection */
+ tmp_size = (size_t)0;
+ tmp_p = NULL;
+ if(H5S_encode(layout->storage.u.virt.list[u].source_select, &tmp_p, &tmp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "unable to serialize source selection")
+ *size += tmp_size;
+
+ /* Virtual dataset selection */
+ tmp_size = (size_t)0;
+ tmp_p = NULL;
+ if(H5S_encode(layout->storage.u.virt.list[u].source_dset.virtual_select, &tmp_p, &tmp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "unable to serialize virtual selection")
+ *size += tmp_size;
+ } /* end for */
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_dec
+ *
+ * Purpose: Callback routine which is called whenever the layout
+ * property in the dataset creation property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_dec(const void **_pp, void *value)
+{
+ const H5O_layout_t *layout; /* Storage layout */
+ H5O_layout_t tmp_layout; /* Temporary local layout structure */
+ H5D_layout_t type; /* Layout type */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode layout type */
+ type = (H5D_layout_t)*(*pp)++;
+
+ /* set default layout in case the type is compact or contiguous, otherwise
+ * decode the chunked structure and set chunked layout */
+ switch(type) {
+ case H5D_COMPACT:
+ layout = &H5D_def_layout_compact_g;
+ break;
+
+ case H5D_CONTIGUOUS:
+ layout = &H5D_def_layout_contig_g;
+ break;
+
+ case H5D_CHUNKED:
+ {
+ unsigned ndims; /* Number of chunk dimensions */
+
+ /* Decode the number of chunk dimensions */
+ ndims = *(*pp)++;
+
+ /* default chunk layout */
+ if(0 == ndims)
+ layout = &H5D_def_layout_chunk_g;
+ else { /* chunk layout structure is encoded*/
+ unsigned u; /* Local index variable */
+
+ /* Initialize to default values */
+ tmp_layout = H5D_def_layout_chunk_g;
+
+ /* Set rank & dimensions */
+ tmp_layout.u.chunk.ndims = (unsigned)ndims;
+ for(u = 0; u < ndims; u++)
+ UINT32DECODE(*pp, tmp_layout.u.chunk.dim[u])
+
+ /* Point at the newly set up struct */
+ layout = &tmp_layout;
+ } /* end else */
+ }
+ break;
+
+ case H5D_VIRTUAL:
+ {
+ uint64_t nentries; /* Number of VDS mappings */
+
+ /* Decode number of entries */
+ UINT64DECODE(*pp, nentries)
+
+ if(nentries == (uint64_t)0)
+ /* Just use the default struct */
+ layout = &H5D_def_layout_virtual_g;
+ else {
+ size_t tmp_size;
+ size_t u; /* Local index variable */
+
+ /* Initialize to default values */
+ tmp_layout = H5D_def_layout_virtual_g;
+
+ /* Allocate entry list */
+ if(NULL == (tmp_layout.storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_calloc((size_t)nentries * sizeof(H5O_storage_virtual_ent_t))))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate heap block")
+ tmp_layout.storage.u.virt.list_nalloc = (size_t)nentries;
+ tmp_layout.storage.u.virt.list_nused = (size_t)nentries;
+
+ /* Decode each entry */
+ for(u = 0; u < (size_t)nentries; u++) {
+ /* Source file name */
+ tmp_size = HDstrlen((const char *)*pp) + 1;
+ if(NULL == (tmp_layout.storage.u.virt.list[u].source_file_name = (char *)H5MM_malloc(tmp_size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory for source file name")
+ (void)HDmemcpy(tmp_layout.storage.u.virt.list[u].source_file_name, *pp, tmp_size);
+ *pp += tmp_size;
+
+ /* Source dataset name */
+ tmp_size = HDstrlen((const char *)*pp) + 1;
+ if(NULL == (tmp_layout.storage.u.virt.list[u].source_dset_name = (char *)H5MM_malloc(tmp_size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory for source dataset name")
+ (void)HDmemcpy(tmp_layout.storage.u.virt.list[u].source_dset_name, *pp, tmp_size);
+ *pp += tmp_size;
+
+ /* Source selection */
+ if(NULL == (tmp_layout.storage.u.virt.list[u].source_select = H5S_decode(pp)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "can't decode source space selection")
+ tmp_layout.storage.u.virt.list[u].source_space_status = H5O_VIRTUAL_STATUS_USER;
+
+ /* Virtual selection */
+ if(NULL == (tmp_layout.storage.u.virt.list[u].source_dset.virtual_select = H5S_decode(pp)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "can't decode virtual space selection")
+ tmp_layout.storage.u.virt.list[u].virtual_space_status = H5O_VIRTUAL_STATUS_USER;
+
+ /* Parse source file and dataset names for "printf"
+ * style format specifiers */
+ if(H5D_virtual_parse_source_name(tmp_layout.storage.u.virt.list[u].source_file_name, &tmp_layout.storage.u.virt.list[u].parsed_source_file_name, &tmp_layout.storage.u.virt.list[u].psfn_static_strlen, &tmp_layout.storage.u.virt.list[u].psfn_nsubs) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't parse source file name")
+ if(H5D_virtual_parse_source_name(tmp_layout.storage.u.virt.list[u].source_dset_name, &tmp_layout.storage.u.virt.list[u].parsed_source_dset_name, &tmp_layout.storage.u.virt.list[u].psdn_static_strlen, &tmp_layout.storage.u.virt.list[u].psdn_nsubs) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't parse source dataset name")
+
+ /* Set source names in source_dset struct */
+ if((tmp_layout.storage.u.virt.list[u].psfn_nsubs == 0)
+ && (tmp_layout.storage.u.virt.list[u].psdn_nsubs == 0)) {
+ if(tmp_layout.storage.u.virt.list[u].parsed_source_file_name)
+ tmp_layout.storage.u.virt.list[u].source_dset.file_name = tmp_layout.storage.u.virt.list[u].parsed_source_file_name->name_segment;
+ else
+ tmp_layout.storage.u.virt.list[u].source_dset.file_name = tmp_layout.storage.u.virt.list[u].source_file_name;
+ if(tmp_layout.storage.u.virt.list[u].parsed_source_dset_name)
+ tmp_layout.storage.u.virt.list[u].source_dset.dset_name = tmp_layout.storage.u.virt.list[u].parsed_source_dset_name->name_segment;
+ else
+ tmp_layout.storage.u.virt.list[u].source_dset.dset_name = tmp_layout.storage.u.virt.list[u].source_dset_name;
+ } /* end if */
+
+ /* unlim_dim fields */
+ tmp_layout.storage.u.virt.list[u].unlim_dim_source = H5S_get_select_unlim_dim(tmp_layout.storage.u.virt.list[u].source_select);
+ tmp_layout.storage.u.virt.list[u].unlim_dim_virtual = H5S_get_select_unlim_dim(tmp_layout.storage.u.virt.list[u].source_dset.virtual_select);
+ tmp_layout.storage.u.virt.list[u].unlim_extent_source = HSIZE_UNDEF;
+ tmp_layout.storage.u.virt.list[u].unlim_extent_virtual = HSIZE_UNDEF;
+ tmp_layout.storage.u.virt.list[u].clip_size_source = HSIZE_UNDEF;
+ tmp_layout.storage.u.virt.list[u].clip_size_virtual = HSIZE_UNDEF;
+
+ /* Clipped selections */
+ if(tmp_layout.storage.u.virt.list[u].unlim_dim_virtual < 0) {
+ tmp_layout.storage.u.virt.list[u].source_dset.clipped_source_select = tmp_layout.storage.u.virt.list[u].source_select;
+ tmp_layout.storage.u.virt.list[u].source_dset.clipped_virtual_select = tmp_layout.storage.u.virt.list[u].source_dset.virtual_select;
+ } /* end if */
+
+ /* Update min_dims */
+ if(H5D_virtual_update_min_dims(&tmp_layout, u) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to update virtual dataset minimum dimensions")
+ } /* end for */
+
+ /* Point at the newly set up struct */
+ layout = &tmp_layout;
+ } /* end else */
+ } /* end block */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad layout type")
+ } /* end switch */
+
+ /* Set the value */
+ HDmemcpy(value, layout, sizeof(H5O_layout_t));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_del
+ *
+ * Purpose: Frees memory used to store the layout property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, Feb 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old layout */
+ if(H5O_msg_reset(H5O_LAYOUT_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release layout message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_copy
+ *
+ * Purpose: Copy the layout property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Monday, Feb 9, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ H5O_layout_t *layout = (H5O_layout_t *)value; /* Create local aliases for values */
+ H5O_layout_t new_layout;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(layout);
+
+ /* Make copy of layout */
+ if(NULL == H5O_msg_copy(H5O_LAYOUT_ID, layout, &new_layout))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy layout")
+
+ /* Set new layout message directly into property list */
+ *layout = new_layout;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_cmp
+ *
+ * Purpose: Callback routine which is called whenever the layout
+ * property in the dataset creation property list is
+ * compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 23, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__dcrt_layout_cmp(const void *_layout1, const void *_layout2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5O_layout_t *layout1 = (const H5O_layout_t *)_layout1, /* Create local aliases for values */
+ *layout2 = (const H5O_layout_t *)_layout2;
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(layout1);
+ HDassert(layout2);
+ HDassert(size == sizeof(H5O_layout_t));
+
+ /* Check for different layout type */
+ if(layout1->type < layout2->type)
+ HGOTO_DONE(-1)
+ if(layout1->type > layout2->type)
+ HGOTO_DONE(1)
+
+ /* Compare non-dataset-specific fields in layout info */
+ switch(layout1->type) {
+ case H5D_COMPACT:
+ case H5D_CONTIGUOUS:
+ break;
+
+ case H5D_CHUNKED:
+ {
+ unsigned u; /* Local index variable */
+
+ /* Check the number of dimensions */
+ if(layout1->u.chunk.ndims < layout2->u.chunk.ndims)
+ HGOTO_DONE(-1)
+ if(layout1->u.chunk.ndims > layout2->u.chunk.ndims)
+ HGOTO_DONE(1)
+
+ /* Compare the chunk dims */
+ for(u = 0; u < layout1->u.chunk.ndims - 1; u++) {
+ if(layout1->u.chunk.dim[u] < layout2->u.chunk.dim[u])
+ HGOTO_DONE(-1)
+ if(layout1->u.chunk.dim[u] > layout2->u.chunk.dim[u])
+ HGOTO_DONE(1)
+ } /* end for */
+ } /* end case */
+ break;
+
+ case H5D_VIRTUAL:
+ {
+ htri_t equal;
+ int strcmp_ret;
+ size_t u; /* Local index variable */
+
+ /* Compare number of mappings */
+ if(layout1->storage.u.virt.list_nused < layout2->storage.u.virt.list_nused) HGOTO_DONE(-1)
+ if(layout1->storage.u.virt.list_nused > layout2->storage.u.virt.list_nused) HGOTO_DONE(1)
+
+ /* Iterate over mappings */
+ for(u = 0; u < layout1->storage.u.virt.list_nused; u++) {
+ /* Compare virtual spaces. Note we cannot tell which is
+ * "greater", so just return 1 if different, -1 on failure.
+ */
+ if((equal = H5S_extent_equal(layout1->storage.u.virt.list[u].source_dset.virtual_select, layout2->storage.u.virt.list[u].source_dset.virtual_select)) < 0) HGOTO_DONE(-1)
+ if(!equal)
+ HGOTO_DONE(1)
+ if((equal = H5S_select_shape_same(layout1->storage.u.virt.list[u].source_dset.virtual_select, layout2->storage.u.virt.list[u].source_dset.virtual_select)) < 0) HGOTO_DONE(-1)
+ if(!equal)
+ HGOTO_DONE(1)
+
+ /* Compare source file names */
+ strcmp_ret = HDstrcmp(layout1->storage.u.virt.list[u].source_file_name, layout2->storage.u.virt.list[u].source_file_name);
+ if(strcmp_ret < 0) HGOTO_DONE(-1)
+ if(strcmp_ret > 0) HGOTO_DONE(1)
+
+ /* Compare source dataset names */
+ strcmp_ret = HDstrcmp(layout1->storage.u.virt.list[u].source_dset_name, layout2->storage.u.virt.list[u].source_dset_name);
+ if(strcmp_ret < 0) HGOTO_DONE(-1)
+ if(strcmp_ret > 0) HGOTO_DONE(1)
+
+ /* Compare source spaces. Note we cannot tell which is
+ * "greater", so just return 1 if different, -1 on failure.
+ */
+ if((equal = H5S_extent_equal(layout1->storage.u.virt.list[u].source_select, layout2->storage.u.virt.list[u].source_select)) < 0) HGOTO_DONE(-1)
+ if(!equal)
+ HGOTO_DONE(1)
+ if((equal = H5S_select_shape_same(layout1->storage.u.virt.list[u].source_select, layout2->storage.u.virt.list[u].source_select)) < 0) HGOTO_DONE(-1)
+ if(!equal)
+ HGOTO_DONE(1)
+ } /* end for */
+ } /* end block */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert(0 && "Unknown layout type!");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_layout_close
+ *
+ * Purpose: Frees memory used to store the layout property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, Feb 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_layout_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old layout */
+ if(H5O_msg_reset(H5O_LAYOUT_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release layout message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_layout_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_set
+ *
+ * Purpose: Copies a fill value property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_fill_t *fill = (H5O_fill_t *)value; /* Create local aliases for values */
+ H5O_fill_t new_fill;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of fill value */
+ if(NULL == H5O_msg_copy(H5O_FILL_ID, fill, &new_fill))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy fill value")
+
+ /* Copy new fill value message over old one */
+ *fill = new_fill;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_get
+ *
+ * Purpose: Copies a fill value property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_fill_t *fill = (H5O_fill_t *)value; /* Create local aliases for values */
+ H5O_fill_t new_fill;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of fill value */
+ if(NULL == H5O_msg_copy(H5O_FILL_ID, fill, &new_fill))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy fill value")
+
+ /* Copy new fill value message over old one */
+ *fill = new_fill;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_enc
+ *
+ * Purpose: Callback routine which is called whenever the fill value
+ * property in the dataset creation property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_fill_t *fill = (const H5O_fill_t *)value; /* Create local aliases for values */
+ size_t dt_size = 0; /* Size of encoded datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+ uint8_t **pp = (uint8_t **)_pp;
+ uint64_t enc_value;
+ unsigned enc_size = 0;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(ssize_t) <= sizeof(int64_t));
+ HDassert(fill);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode alloc and fill time */
+ *(*pp)++ = (uint8_t)fill->alloc_time;
+ *(*pp)++ = (uint8_t)fill->fill_time;
+
+ /* Encode size of fill value */
+ INT64ENCODE(*pp, fill->size)
+
+ /* Encode the fill value & datatype */
+ if(fill->size > 0) {
+ /* Encode the fill value itself */
+ HDmemcpy(*pp, (uint8_t *)fill->buf, (size_t)fill->size);
+ *pp += fill->size;
+
+ /* Encode fill value datatype */
+ HDassert(fill->type);
+
+ if(H5T_encode(fill->type, NULL, &dt_size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode datatype")
+
+ /* Encode the size of a size_t */
+ enc_value = (uint64_t)dt_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)enc_size;
+
+ /* Encode the size of the encoded datatype */
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ if(H5T_encode(fill->type, *pp, &dt_size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode datatype")
+ *pp += dt_size;
+ } /* end if */
+ } /* end if */
+
+ /* Calculate size needed for encoding */
+ *size += 2;
+ *size += sizeof(int64_t);
+ if(fill->size > 0) {
+ /* The size of the fill value buffer */
+ *size += (size_t)fill->size;
+
+ /* calculate those if they were not calculated earlier */
+ if(NULL == *pp) {
+ /* Get the size of the encoded datatype */
+ HDassert(fill->type);
+ if(H5T_encode(fill->type, NULL, &dt_size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode datatype")
+ enc_value = (uint64_t)dt_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ }
+ *size += (1 + enc_size);
+ *size += dt_size;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_dec
+ *
+ * Purpose: Callback routine which is called whenever the fill value
+ * property in the dataset creation property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_dec(const void **_pp, void *_value)
+{
+ H5O_fill_t *fill = (H5O_fill_t *)_value; /* Fill value */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(ssize_t) <= sizeof(int64_t));
+
+ /* Set property to default value */
+ *fill = H5D_def_fill_g;
+
+ /* Decode alloc and fill time */
+ fill->alloc_time = (H5D_alloc_time_t)*(*pp)++;
+ fill->fill_time = (H5D_fill_time_t)*(*pp)++;
+
+ /* Decode fill size */
+ INT64DECODE(*pp, fill->size)
+
+ /* Check if there's a fill value */
+ if(fill->size > 0) {
+ size_t dt_size = 0;
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ /* Allocate fill buffer and copy the contents in it */
+ if(NULL == (fill->buf = H5MM_malloc((size_t)fill->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for fill value buffer")
+ HDmemcpy((uint8_t *)fill->buf, *pp, (size_t)fill->size);
+ *pp += fill->size;
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the size of encoded datatype */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ dt_size = (size_t)enc_value;
+
+ /* Decode type */
+ if(NULL == (fill->type = H5T_decode(*pp)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "can't decode fill value datatype")
+ *pp += dt_size;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_del
+ *
+ * Purpose: Frees memory used to store the fill value property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, Feb 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old fill value message */
+ if(H5O_msg_reset(H5O_FILL_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release fill value message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_copy
+ *
+ * Purpose: Copy the fill value property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, Feb 26, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ H5O_fill_t *fill = (H5O_fill_t *)value; /* Create local aliases for values */
+ H5O_fill_t new_fill;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(fill);
+
+ /* Make copy of fill value message */
+ if(NULL == H5O_msg_copy(H5O_FILL_ID, fill, &new_fill))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy fill value")
+
+ /* Set new fill value message directly into property list */
+ *fill = new_fill;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_fill_value_cmp
+ *
+ * Purpose: Callback routine which is called whenever the fill value
+ * property in the dataset creation property list is compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 7, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5P_fill_value_cmp(const void *_fill1, const void *_fill2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5O_fill_t *fill1 = (const H5O_fill_t *)_fill1, /* Create local aliases for values */
+ *fill2 = (const H5O_fill_t *)_fill2;
+ int cmp_value; /* Value from comparison */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(fill1);
+ HDassert(fill2);
+ HDassert(size == sizeof(H5O_fill_t));
+
+ /* Check the size of fill values */
+ if(fill1->size < fill2->size) HGOTO_DONE(-1);
+ if(fill1->size > fill2->size) HGOTO_DONE(1);
+
+ /* Check the types of the fill values */
+ if(fill1->type == NULL && fill2->type != NULL) HGOTO_DONE(-1);
+ if(fill1->type != NULL && fill2->type == NULL) HGOTO_DONE(1);
+ if(fill1->type != NULL)
+ if((cmp_value = H5T_cmp(fill1->type, fill2->type, FALSE)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the fill values in the buffers */
+ if(fill1->buf == NULL && fill2->buf != NULL) HGOTO_DONE(-1);
+ if(fill1->buf != NULL && fill2->buf == NULL) HGOTO_DONE(1);
+ if(fill1->buf != NULL)
+ if((cmp_value = HDmemcmp(fill1->buf, fill2->buf, (size_t)fill1->size)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the allocation time for the fill values */
+ if(fill1->alloc_time < fill2->alloc_time) HGOTO_DONE(-1);
+ if(fill1->alloc_time > fill2->alloc_time) HGOTO_DONE(1);
+
+ /* Check the fill time for the fill values */
+ if(fill1->fill_time < fill2->fill_time) HGOTO_DONE(-1);
+ if(fill1->fill_time > fill2->fill_time) HGOTO_DONE(1);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_fill_value_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_fill_value_close
+ *
+ * Purpose: Frees memory used to store the fill value property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, Feb 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_fill_value_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old fill value message */
+ if(H5O_msg_reset(H5O_FILL_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release fill value message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_fill_value_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_set
+ *
+ * Purpose: Copies an external file list property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_efl_t *efl = (H5O_efl_t *)value; /* Create local aliases for values */
+ H5O_efl_t new_efl;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of external file list */
+ if(NULL == H5O_msg_copy(H5O_EFL_ID, efl, &new_efl))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy external file list")
+
+ /* Copy new external file list message over old one */
+ *efl = new_efl;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_get
+ *
+ * Purpose: Copies an external file lsit property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_efl_t *efl = (H5O_efl_t *)value; /* Create local aliases for values */
+ H5O_efl_t new_efl;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of external file list */
+ if(NULL == H5O_msg_copy(H5O_EFL_ID, efl, &new_efl))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy external file list")
+
+ /* Copy new external file list message over old one */
+ *efl = new_efl;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_enc
+ *
+ * Purpose: Callback routine which is called whenever the efl
+ * property in the dataset creation property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_efl_t *efl = (const H5O_efl_t *)value; /* Create local aliases for values */
+ size_t len = 0; /* String length of slot name */
+ size_t u; /* Local index variable */
+ uint8_t **pp = (uint8_t **)_pp;
+ unsigned enc_size;
+ uint64_t enc_value;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(efl);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(off_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(hsize_t) <= sizeof(uint64_t));
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode number of slots used */
+ enc_value = (uint64_t)efl->nused;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* Encode file list */
+ for(u = 0; u < efl->nused; u++) {
+ /* Calculate length of slot name and encode it */
+ len = HDstrlen(efl->slot[u].name) + 1;
+ enc_value = (uint64_t)len;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* Encode name */
+ HDmemcpy(*pp, (uint8_t *)(efl->slot[u].name), len);
+ *pp += len;
+
+ /* Encode offset */
+ enc_value = (uint64_t)efl->slot[u].offset;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode size */
+ enc_value = (uint64_t)efl->slot[u].size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+ } /* end for */
+ } /* end if */
+
+ /* Calculate size needed for encoding */
+ *size += (1 + H5VM_limit_enc_size((uint64_t)efl->nused));
+ for(u = 0; u < efl->nused; u++) {
+ len = HDstrlen(efl->slot[u].name) + 1;
+ *size += (1 + H5VM_limit_enc_size((uint64_t)len));
+ *size += len;
+ *size += (1 + H5VM_limit_enc_size((uint64_t)efl->slot[u].offset));
+ *size += (1 + H5VM_limit_enc_size((uint64_t)efl->slot[u].size));
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dcrt_ext_file_list_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_dec
+ *
+ * Purpose: Callback routine which is called whenever the efl
+ * property in the dataset creation property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_dec(const void **_pp, void *_value)
+{
+ H5O_efl_t *efl = (H5O_efl_t *)_value; /* External file list */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ size_t u, nused;
+ unsigned enc_size;
+ uint64_t enc_value;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(efl);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(off_t) <= sizeof(uint64_t));
+ HDcompile_assert(sizeof(hsize_t) <= sizeof(uint64_t));
+
+ /* Set property to default value */
+ *efl = H5D_def_efl_g;
+
+ /* Decode number of slots used */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ nused = (size_t)enc_value;
+
+ /* Decode information for each slot */
+ for(u = 0; u < nused; u++) {
+ size_t len;
+ if(efl->nused >= efl->nalloc) {
+ size_t na = efl->nalloc + H5O_EFL_ALLOC;
+ H5O_efl_entry_t *x = (H5O_efl_entry_t *)H5MM_realloc(efl->slot,
+ na * sizeof(H5O_efl_entry_t));
+ if(!x)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ efl->nalloc = na;
+ efl->slot = x;
+ } /* end if */
+
+ /* Decode length of slot name */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ len = (size_t)enc_value;
+
+ /* Allocate name buffer and decode the name into it */
+ efl->slot[u].name = H5MM_xstrdup((const char *)(*pp));
+ *pp += len;
+
+ /* decode offset */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ efl->slot[u].offset = (off_t)enc_value;
+
+ /* decode size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ efl->slot[u].size = (hsize_t)enc_value;
+
+ efl->slot[u].name_offset = 0; /*not entered into heap yet*/
+ efl->nused++;
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_del
+ *
+ * Purpose: Frees memory used to store the efl property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, Feb 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old efl message */
+ if(H5O_msg_reset(H5O_EFL_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release external file list message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_copy
+ *
+ * Purpose: Copy the efl property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thurday, Feb 26, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ H5O_efl_t *efl = (H5O_efl_t *)value; /* Create local aliases for values */
+ H5O_efl_t new_efl;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(efl);
+
+ /* Make copy of efl message */
+ if(NULL == H5O_msg_copy(H5O_EFL_ID, efl, &new_efl))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy external file list")
+
+ /* Set new efl message directly into property list */
+ *efl = new_efl;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_cmp
+ *
+ * Purpose: Callback routine which is called whenever the external file
+ * list property in the dataset creation property list is
+ * compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 7, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__dcrt_ext_file_list_cmp(const void *_efl1, const void *_efl2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5O_efl_t *efl1 = (const H5O_efl_t *)_efl1, /* Create local aliases for values */
+ *efl2 = (const H5O_efl_t *)_efl2;
+ int cmp_value; /* Value from comparison */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(efl1);
+ HDassert(efl2);
+ HDassert(size == sizeof(H5O_efl_t));
+
+ /* Check the number of allocated efl entries */
+ if(efl1->nalloc < efl2->nalloc) HGOTO_DONE(-1);
+ if(efl1->nalloc > efl2->nalloc) HGOTO_DONE(1);
+
+ /* Check the number of used efl entries */
+ if(efl1->nused < efl2->nused) HGOTO_DONE(-1);
+ if(efl1->nused > efl2->nused) HGOTO_DONE(1);
+
+ /* Check the efl entry information */
+ if(efl1->slot == NULL && efl2->slot != NULL) HGOTO_DONE(-1);
+ if(efl1->slot != NULL && efl2->slot == NULL) HGOTO_DONE(1);
+ if(efl1->slot != NULL && efl1->nused > 0) {
+ size_t u; /* Local index variable */
+
+ /* Loop through all entries, comparing them */
+ for(u = 0; u < efl1->nused; u++) {
+ /* Check the name offset of the efl entry */
+ if(efl1->slot[u].name_offset < efl2->slot[u].name_offset) HGOTO_DONE(-1);
+ if(efl1->slot[u].name_offset > efl2->slot[u].name_offset) HGOTO_DONE(1);
+
+ /* Check the name of the efl entry */
+ if(efl1->slot[u].name == NULL && efl2->slot[u].name != NULL) HGOTO_DONE(-1);
+ if(efl1->slot[u].name != NULL && efl2->slot[u].name == NULL) HGOTO_DONE(1);
+ if(efl1->slot[u].name != NULL)
+ if((cmp_value = HDstrcmp(efl1->slot[u].name, efl2->slot[u].name)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the file offset of the efl entry */
+ if(efl1->slot[u].offset < efl2->slot[u].offset) HGOTO_DONE(-1);
+ if(efl1->slot[u].offset > efl2->slot[u].offset) HGOTO_DONE(1);
+
+ /* Check the file size of the efl entry */
+ if(efl1->slot[u].size < efl2->slot[u].size) HGOTO_DONE(-1);
+ if(efl1->slot[u].size > efl2->slot[u].size) HGOTO_DONE(1);
+ } /* end for */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dcrt_ext_file_list_close
+ *
+ * Purpose: Frees memory used to store the efl property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Thursday, Feb 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dcrt_ext_file_list_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old efl message */
+ if(H5O_msg_reset(H5O_EFL_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release external file list message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dcrt_ext_file_list_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__set_layout
+ *
+ * Purpose: Sets the layout of raw data in the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__set_layout(H5P_genplist_t *plist, const H5O_layout_t *layout)
+{
+ unsigned alloc_time_state; /* State of allocation time property */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the allocation time state */
+ if(H5P_get(plist, H5D_CRT_ALLOC_TIME_STATE_NAME, &alloc_time_state) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get space allocation time state")
+
+ /* If we still have the "default" allocation time, change it according to the new layout */
+ if(alloc_time_state) {
+ H5O_fill_t fill; /* Fill value */
+
+ /* Get current fill value info */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Set the default based on layout */
+ switch(layout->type) {
+ case H5D_COMPACT:
+ fill.alloc_time = H5D_ALLOC_TIME_EARLY;
+ break;
+
+ case H5D_CONTIGUOUS:
+ fill.alloc_time = H5D_ALLOC_TIME_LATE;
+ break;
+
+ case H5D_CHUNKED:
+ case H5D_VIRTUAL:
+ fill.alloc_time = H5D_ALLOC_TIME_INCR;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown layout type")
+ } /* end switch */
+
+ /* Set updated fill value info */
+ if(H5P_poke(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set space allocation time")
+ } /* end if */
+
+ /* Set layout value */
+ if(H5P_set(plist, H5D_CRT_LAYOUT_NAME, layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set layout")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__set_layout() */
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__init_def_layout
+ *
+ * Purpose: Set the default layout information for the various types of
+ * dataset layouts
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 13, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__init_def_layout(void)
+{
+ const H5O_layout_chunk_t def_layout_chunk = H5D_DEF_LAYOUT_CHUNK_INIT;
+ const H5O_storage_compact_t def_store_compact = H5D_DEF_STORAGE_COMPACT_INIT;
+ const H5O_storage_chunk_t def_store_chunk = H5D_DEF_STORAGE_CHUNK_INIT;
+ const H5O_storage_virtual_t def_store_virtual = H5D_DEF_STORAGE_VIRTUAL_INIT;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Initialize the default layout info for non-contigous layouts */
+ H5D_def_layout_compact_g.storage.type = H5D_COMPACT;
+ H5D_def_layout_compact_g.storage.u.compact = def_store_compact;
+ H5D_def_layout_chunk_g.u.chunk = def_layout_chunk;
+ H5D_def_layout_chunk_g.storage.type = H5D_CHUNKED;
+ H5D_def_layout_chunk_g.storage.u.chunk = def_store_chunk;
+ H5D_def_layout_virtual_g.storage.type = H5D_VIRTUAL;
+ H5D_def_layout_virtual_g.storage.u.virt = def_store_virtual;
+
+ /* Note that we've initialized the default values */
+ H5P_dcrt_def_layout_init_g = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__init_def_layout() */
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_layout
+ *
+ * Purpose: Sets the layout of raw data in the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_layout(hid_t plist_id, H5D_layout_t layout_type)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ const H5O_layout_t *layout; /* Pointer to default layout information for type specified */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDl", plist_id, layout_type);
+
+ /* Check arguments */
+ if(layout_type < 0 || layout_type >= H5D_NLAYOUTS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "raw data layout method is not valid")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+ /* If the compiler doesn't support C99 designated initializers, check if
+ * the default layout structs have been initialized yet or not. *ick* -QAK
+ */
+ if(!H5P_dcrt_def_layout_init_g)
+ if(H5P__init_def_layout() < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't initialize default layout info")
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+ /* Get pointer to correct default layout */
+ switch(layout_type) {
+ case H5D_COMPACT:
+ layout = &H5D_def_layout_compact_g;
+ break;
+
+ case H5D_CONTIGUOUS:
+ layout = &H5D_def_layout_contig_g;
+ break;
+
+ case H5D_CHUNKED:
+ layout = &H5D_def_layout_chunk_g;
+ break;
+
+ case H5D_VIRTUAL:
+ layout = &H5D_def_layout_virtual_g;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown layout type")
+ } /* end switch */
+
+ /* Set value */
+ if(H5P__set_layout(plist, layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set layout")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_layout() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_layout
+ *
+ * Purpose: Retrieves layout type of a dataset creation property list.
+ *
+ * Return: Success: The layout type
+ *
+ * Failure: H5D_LAYOUT_ERROR (negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and get property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5D_layout_t
+H5Pget_layout(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout property */
+ H5D_layout_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5D_LAYOUT_ERROR)
+ H5TRACE1("Dl", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5D_LAYOUT_ERROR, "can't find object for ID")
+
+ /* Peek at layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5D_LAYOUT_ERROR, "can't get layout")
+
+ /* Set return value */
+ ret_value = layout.type;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* ed H5Pget_layout() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_chunk
+ *
+ * Purpose: Sets the number of dimensions and the size of each chunk to
+ * the values specified. The dimensionality of the chunk should
+ * match the dimensionality of the dataspace.
+ *
+ * As a side effect, the layout method is changed to
+ * H5D_CHUNKED.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_chunk(hid_t plist_id, int ndims, const hsize_t dim[/*ndims*/])
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t chunk_layout; /* Layout information for setting chunk info */
+ uint64_t chunk_nelmts; /* Number of elements in chunk */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIs*[a1]h", plist_id, ndims, dim);
+
+ /* Check arguments */
+ if(ndims <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk dimensionality must be positive")
+ if(ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk dimensionality is too large")
+ if(!dim)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no chunk dimensions specified")
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+ /* If the compiler doesn't support C99 designated initializers, check if
+ * the default layout structs have been initialized yet or not. *ick* -QAK
+ */
+ if(!H5P_dcrt_def_layout_init_g)
+ if(H5P__init_def_layout() < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't initialize default layout info")
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+ /* Verify & initialize property's chunk dims */
+ HDmemcpy(&chunk_layout, &H5D_def_layout_chunk_g, sizeof(H5D_def_layout_chunk_g));
+ HDmemset(&chunk_layout.u.chunk.dim, 0, sizeof(chunk_layout.u.chunk.dim));
+ chunk_nelmts = 1;
+ for(u = 0; u < (unsigned)ndims; u++) {
+ if(dim[u] == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all chunk dimensions must be positive")
+ if(dim[u] != (dim[u] & 0xffffffff))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all chunk dimensions must be less than 2^32")
+ chunk_nelmts *= dim[u];
+ if(chunk_nelmts > (uint64_t)0xffffffff)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "number of elements in chunk must be < 4GB")
+ chunk_layout.u.chunk.dim[u] = (uint32_t)dim[u]; /* Store user's chunk dimensions */
+ } /* end for */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set chunk information in property list */
+ chunk_layout.u.chunk.ndims = (unsigned)ndims;
+ if(H5P__set_layout(plist, &chunk_layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set layout")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_chunk
+ *
+ * Purpose: Retrieves the chunk size of chunked layout. The chunk
+ * dimensionality is returned and the chunk size in each
+ * dimension is returned through the DIM argument. At most
+ * MAX_NDIMS elements of DIM will be initialized.
+ *
+ * Return: Success: Positive Chunk dimensionality.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Pget_chunk(hid_t plist_id, int max_ndims, hsize_t dim[]/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Is", "iIsx", plist_id, max_ndims, dim);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Peek at the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_CHUNKED != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a chunked storage layout")
+
+ if(dim) {
+ unsigned u; /* Local index variable */
+
+ /* Get the dimension sizes */
+ for(u = 0; u < layout.u.chunk.ndims && u < (unsigned)max_ndims; u++)
+ dim[u] = layout.u.chunk.dim[u];
+ } /* end if */
+
+ /* Set the return value */
+ ret_value = (int)layout.u.chunk.ndims;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_chunk() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_virtual
+ *
+ * Purpose: Maps elements of the virtual dataset described by the
+ * virtual dataspace identifier vspace_id to the elements of
+ * the source dataset described by the source dataset
+ * dataspace identifier src_space_id. The source dataset is
+ * identified by the name of the file where it is located,
+ * src_file_name, and the name of the dataset, src_dset_name.
+ *
+ * As a side effect, the layout method is changed to
+ * H5D_VIRTUAL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, February 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_virtual(hid_t dcpl_id, hid_t vspace_id, const char *src_file_name,
+ const char *src_dset_name, hid_t src_space_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t virtual_layout; /* Layout information for setting virtual info */
+ H5S_t *vspace; /* Virtual dataset space selection */
+ H5S_t *src_space; /* Source dataset space selection */
+ H5O_storage_virtual_ent_t *old_list = NULL; /* List pointer previously on property list */
+ H5O_storage_virtual_ent_t *ent = NULL; /* Convenience pointer to new VDS entry */
+ hbool_t retrieved_layout = FALSE; /* Whether the layout has been retrieved */
+ hbool_t free_list = FALSE; /* Whether to free the list of virtual entries */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "ii*s*si", dcpl_id, vspace_id, src_file_name, src_dset_name,
+ src_space_id);
+
+ /* Check arguments */
+ if(!src_file_name)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "source file name not provided")
+ if(!src_dset_name)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADRANGE, FAIL, "source dataset name not provided")
+ if(NULL == (vspace = (H5S_t *)H5I_object_verify(vspace_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(NULL == (src_space = (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Check selections for validity */
+ if(H5D_virtual_check_mapping_pre(vspace, src_space, H5O_VIRTUAL_STATUS_USER) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "invalid mapping selections")
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+ /* If the compiler doesn't support C99 designated initializers, check if
+ * the default layout structs have been initialized yet or not. *ick* -QAK
+ */
+ if(!H5P_dcrt_def_layout_init_g)
+ if(H5P__init_def_layout() < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't initialize default layout info")
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the current layout */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &virtual_layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get layout")
+ retrieved_layout = TRUE;
+
+ /* If the layout was not already virtual, Start with default virtual layout.
+ * Otherwise, add the mapping to the current list. */
+ if(virtual_layout.type == H5D_VIRTUAL)
+ /* Save old list pointer for error recovery */
+ old_list = virtual_layout.storage.u.virt.list;
+ else {
+ /* Reset the old layout */
+ if(H5O_msg_reset(H5O_LAYOUT_ID, &virtual_layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release layout message")
+
+ /* Copy the default virtual layout */
+ HDmemcpy(&virtual_layout, &H5D_def_layout_virtual_g, sizeof(H5D_def_layout_virtual_g));
+
+ /* Sanity check */
+ HDassert(virtual_layout.storage.u.virt.list_nalloc == 0);
+ } /* end else */
+
+ /* Expand list if necessary */
+ if(virtual_layout.storage.u.virt.list_nused == virtual_layout.storage.u.virt.list_nalloc) {
+ H5O_storage_virtual_ent_t *x; /* Pointer to the new list */
+ size_t new_alloc = MAX(H5D_VIRTUAL_DEF_LIST_SIZE, virtual_layout.storage.u.virt.list_nalloc * 2);
+
+ /* Expand size of entry list */
+ if(NULL == (x = (H5O_storage_virtual_ent_t *)H5MM_realloc(virtual_layout.storage.u.virt.list, new_alloc * sizeof(H5O_storage_virtual_ent_t))))
+ HGOTO_ERROR(H5E_PLIST, H5E_RESOURCE, FAIL, "can't reallocate virtual dataset mapping list")
+ virtual_layout.storage.u.virt.list = x;
+ virtual_layout.storage.u.virt.list_nalloc = new_alloc;
+ } /* end if */
+
+ /* Add virtual dataset mapping entry */
+ ent = &virtual_layout.storage.u.virt.list[virtual_layout.storage.u.virt.list_nused];
+ HDmemset(ent, 0, sizeof(H5O_storage_virtual_ent_t)); /* Clear before starting to set up */
+ if(NULL == (ent->source_dset.virtual_select = H5S_copy(vspace, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+ if(NULL == (ent->source_file_name = H5MM_xstrdup(src_file_name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_RESOURCE, FAIL, "can't duplicate source file name")
+ if(NULL == (ent->source_dset_name = H5MM_xstrdup(src_dset_name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_RESOURCE, FAIL, "can't duplicate source file name")
+ if(NULL == (ent->source_select = H5S_copy(src_space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+ if(H5D_virtual_parse_source_name(ent->source_file_name, &ent->parsed_source_file_name, &ent->psfn_static_strlen, &ent->psfn_nsubs) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't parse source file name")
+ if(H5D_virtual_parse_source_name(ent->source_dset_name, &ent->parsed_source_dset_name, &ent->psdn_static_strlen, &ent->psdn_nsubs) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't parse source dataset name")
+ if((ent->psfn_nsubs == 0) && (ent->psdn_nsubs == 0)) {
+ if(ent->parsed_source_file_name)
+ ent->source_dset.file_name = ent->parsed_source_file_name->name_segment;
+ else
+ ent->source_dset.file_name = ent->source_file_name;
+ if(ent->parsed_source_dset_name)
+ ent->source_dset.dset_name = ent->parsed_source_dset_name->name_segment;
+ else
+ ent->source_dset.dset_name = ent->source_dset_name;
+ } /* end if */
+ ent->unlim_dim_source = H5S_get_select_unlim_dim(src_space);
+ ent->unlim_dim_virtual = H5S_get_select_unlim_dim(vspace);
+ if(ent->unlim_dim_virtual < 0) {
+ ent->source_dset.clipped_source_select = ent->source_select;
+ ent->source_dset.clipped_virtual_select = ent->source_dset.virtual_select;
+ } /* end if */
+ ent->unlim_extent_source = HSIZE_UNDEF;
+ ent->unlim_extent_virtual = HSIZE_UNDEF;
+ ent->clip_size_source = HSIZE_UNDEF;
+ ent->clip_size_virtual = HSIZE_UNDEF;
+ ent->source_space_status = H5O_VIRTUAL_STATUS_USER;
+ ent->virtual_space_status = H5O_VIRTUAL_STATUS_USER;
+
+ /* Check entry for validity */
+ if(H5D_virtual_check_mapping_post(ent) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid mapping entry")
+
+ /* Update min_dims */
+ if(H5D_virtual_update_min_dims(&virtual_layout, virtual_layout.storage.u.virt.list_nused) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to update virtual dataset minimum dimensions")
+
+ /* Finish adding entry */
+ virtual_layout.storage.u.virt.list_nused++;
+
+done:
+ /* Set VDS layout information in property list */
+ /* (Even on faliure, so there's not a mangled layout struct in the list) */
+ if(retrieved_layout) {
+ if(H5P_poke(plist, H5D_CRT_LAYOUT_NAME, &virtual_layout) < 0) {
+ HDONE_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set layout")
+ if(old_list != virtual_layout.storage.u.virt.list)
+ free_list = TRUE;
+ } /* end if */
+ } /* end if */
+
+ /* Check if the entry has been partly allocated but not added to the
+ * property list or not included in list_nused */
+ if(ret_value < 0) {
+ /* Free incomplete entry if present */
+ if(ent) {
+ ent->source_file_name = (char *)H5MM_xfree(ent->source_file_name);
+ ent->source_dset_name = (char *)H5MM_xfree(ent->source_dset_name);
+ if(ent->source_dset.virtual_select && H5S_close(ent->source_dset.virtual_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release virtual selection")
+ ent->source_dset.virtual_select = NULL;
+ if(ent->source_select && H5S_close(ent->source_select) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection")
+ ent->source_select = NULL;
+ H5D_virtual_free_parsed_name(ent->parsed_source_file_name);
+ ent->parsed_source_file_name = NULL;
+ H5D_virtual_free_parsed_name(ent->parsed_source_dset_name);
+ ent->parsed_source_dset_name = NULL;
+ } /* end if */
+
+ /* Free list if necessary */
+ if(free_list)
+ virtual_layout.storage.u.virt.list = (H5O_storage_virtual_ent_t *)H5MM_xfree(virtual_layout.storage.u.virt.list);
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_virtual() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_count
+ *
+ * Purpose: Gets the number of mappings for the virtual dataset that
+ * has a creation property list specified by the dcpl_id
+ * parameter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, February 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_virtual_count(hid_t dcpl_id, size_t *count/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", dcpl_id, count);
+
+ if(count) {
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_VIRTUAL != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a virtual storage layout")
+
+ /* Return the number of mappings */
+ *count = layout.storage.u.virt.list_nused;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_vspace
+ *
+ * Purpose: Takes the dataset creation property list for the virtual
+ * dataset, dcpl_id, and the mapping index, index, and
+ * returns a dataspace identifier for the selection within
+ * the virtual dataset used in the mapping.
+ *
+ * Return: Returns a dataspace identifier if successful; otherwise
+ * returns a negative value.
+ *
+ * Programmer: Neil Fortner
+ * Friday, February 13, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Pget_virtual_vspace(hid_t dcpl_id, size_t index)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ H5S_t *space = NULL; /* Dataspace pointer */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "iz", dcpl_id, index);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_VIRTUAL != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a virtual storage layout")
+
+ /* Get the virtual space */
+ if(index >= layout.storage.u.virt.list_nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid index (out of range)")
+ HDassert(layout.storage.u.virt.list_nused <= layout.storage.u.virt.list_nalloc);
+ if(NULL == (space = H5S_copy(layout.storage.u.virt.list[index].source_dset.virtual_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy virtual selection")
+
+ /* Register ID */
+ if((ret_value = H5I_register(H5I_DATASPACE, space, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register data space")
+
+done:
+ /* Free space on failure */
+ if((ret_value < 0) && space)
+ if(H5S_close(space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_vspace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_srcspace
+ *
+ * Purpose: Takes the dataset creation property list for the virtual
+ * dataset, dcpl_id, and the mapping index, index, and
+ * returns a dataspace identifier for the selection within
+ * the source dataset used in the mapping.
+ *
+ * Return: Returns a dataspace identifier if successful; otherwise
+ * returns a negative value.
+ *
+ * Programmer: Neil Fortner
+ * Saturday, February 14, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Pget_virtual_srcspace(hid_t dcpl_id, size_t index)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ H5S_t *space = NULL; /* Dataspace pointer */
+ hid_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "iz", dcpl_id, index);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_VIRTUAL != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a virtual storage layout")
+
+ /* Check index */
+ if(index >= layout.storage.u.virt.list_nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid index (out of range)")
+ HDassert(layout.storage.u.virt.list_nused <= layout.storage.u.virt.list_nalloc);
+
+ /* Attempt to open source dataset and patch extent if extent status is not
+ * H5O_VIRTUAL_STATUS_CORRECT? -NAF */
+ /* If source space status is H5O_VIRTUAL_STATUS_INVALID, patch with bounds
+ * of selection */
+ if((H5O_VIRTUAL_STATUS_INVALID == layout.storage.u.virt.list[index].source_space_status)
+ && (layout.storage.u.virt.list[index].unlim_dim_source < 0)) {
+ hsize_t bounds_start[H5S_MAX_RANK];
+ hsize_t bounds_end[H5S_MAX_RANK];
+ int rank;
+ int i;
+
+ /* Get rank of source space */
+ if((rank = H5S_GET_EXTENT_NDIMS(layout.storage.u.virt.list[index].source_select)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get source space rank")
+
+ /* Get bounds of selection */
+ if(H5S_SELECT_BOUNDS(layout.storage.u.virt.list[index].source_select, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get selection bounds")
+
+ /* Adjust bounds to extent */
+ for(i = 0; i < rank; i++)
+ bounds_end[i]++;
+
+ /* Set extent */
+ if(H5S_set_extent_simple(layout.storage.u.virt.list[index].source_select, (unsigned)rank, bounds_end, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set source space extent")
+
+ /* Update source space status */
+ layout.storage.u.virt.list[index].source_space_status = H5O_VIRTUAL_STATUS_SEL_BOUNDS;
+ } /* end if */
+
+ /* Get the source space */
+ if(NULL == (space = H5S_copy(layout.storage.u.virt.list[index].source_select, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy source selection")
+
+ /* Register ID */
+ if((ret_value = H5I_register(H5I_DATASPACE, space, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register data space")
+
+done:
+ /* Free space on failure */
+ if((ret_value < 0) && space)
+ if(H5S_close(space) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release source selection")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_srcspace() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_filename
+ *
+ * Purpose: Takes the dataset creation property list for the virtual
+ * dataset, dcpl_id, and the mapping index, index, and
+ * retrieves a name of a file for a source dataset used in
+ * the mapping.
+ *
+ * Up to size characters of the filename are returned in
+ * name; additional characters, if any, are not returned to
+ * the user application.
+ *
+ * If the length of the filename, which determines the
+ * required value of size, is unknown, a preliminary call to
+ * H5Pget_virtual_filename with 'name' set to NULL and 'size'
+ * set to zero can be made. The return value of this call will
+ * be the size in bytes of the filename. That value, plus 1
+ * for a NULL terminator, is then assigned to size for a
+ * second H5Pget_virtual_filename call, which will retrieve
+ * the actual filename.
+ *
+ * Return: Returns the length of the name if successful, otherwise
+ * returns a negative value.
+ *
+ * Programmer: Neil Fortner
+ * Saturday, February 14, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Pget_virtual_filename(hid_t dcpl_id, size_t index, char *name/*out*/,
+ size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "izxz", dcpl_id, index, name, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_VIRTUAL != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a virtual storage layout")
+
+ /* Get the virtual filename */
+ if(index >= layout.storage.u.virt.list_nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid index (out of range)")
+ HDassert(layout.storage.u.virt.list_nused <= layout.storage.u.virt.list_nalloc);
+ HDassert(layout.storage.u.virt.list[index].source_file_name);
+ if(name && (size > 0))
+ (void)HDstrncpy(name, layout.storage.u.virt.list[index].source_file_name, size);
+ ret_value = (ssize_t)HDstrlen(layout.storage.u.virt.list[index].source_file_name);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_filename() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_virtual_dsetname
+ *
+ * Purpose: Takes the dataset creation property list for the virtual
+ * dataset, dcpl_id, and the mapping index, index, and
+ * retrieves the name of a source dataset used in the mapping.
+ *
+ * Up to size characters of the name are returned in name;
+ * additional characters, if any, are not returned to the
+ * user application.
+ *
+ * If the length of the dataset name, which determines the
+ * required value of size, is unknown, a preliminary call to
+ * H5Pget_virtual_dsetname with 'name' set to NULL and 'size'
+ * set to zero can be made. The return value of this call will
+ * be the size in bytes of the dataset name. That value, plus 1
+ * for a NULL terminator, is then assigned to size for a
+ * second H5Pget_virtual_dsetname call, which will retrieve
+ * the actual dataset name.
+ *
+ * Return: Returns the length of the name if successful, otherwise
+ * returns a negative value.
+ *
+ * Programmer: Neil Fortner
+ * Saturday, February 14, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Pget_virtual_dsetname(hid_t dcpl_id, size_t index, char *name/*out*/,
+ size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "izxz", dcpl_id, index, name, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_VIRTUAL != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a virtual storage layout")
+
+ /* Get the virtual filename */
+ if(index >= layout.storage.u.virt.list_nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid index (out of range)")
+ HDassert(layout.storage.u.virt.list_nused <= layout.storage.u.virt.list_nalloc);
+ HDassert(layout.storage.u.virt.list[index].source_dset_name);
+ if(name && (size > 0))
+ (void)HDstrncpy(name, layout.storage.u.virt.list[index].source_dset_name, size);
+ ret_value = (ssize_t)HDstrlen(layout.storage.u.virt.list[index].source_dset_name);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_virtual_dsetname() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_chunk_opts
+ *
+ * Purpose: Sets the options related to chunked storage for a dataset.
+ * The storage must already be set to chunked.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Thursday, January 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_chunk_opts(hid_t plist_id, unsigned options)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information for setting chunk info */
+ uint8_t layout_flags = 0; /* "options" translated into layout message flags format */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, options);
+
+ /* Check arguments */
+ if(options & ~(H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "unknown chunk options")
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+ /* If the compiler doesn't support C99 designated initializers, check if
+ * the default layout structs have been initialized yet or not. *ick* -QAK
+ */
+ if(!H5P_dcrt_def_layout_init_g)
+ if(H5P__init_def_layout() < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't initialize default layout info")
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_CHUNKED != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a chunked storage layout")
+
+ /* Translate options into flags that can be used with the layout message */
+ if(options & H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS)
+ layout_flags |= H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS;
+
+ /* Update the layout message, including the version (if necessary) */
+ /* This probably isn't the right way to do this, and should be changed once
+ * this branch gets the "real" way to set the layout version */
+ layout.u.chunk.flags = layout_flags;
+ if(layout.version < H5O_LAYOUT_VERSION_4)
+ layout.version = H5O_LAYOUT_VERSION_4;
+
+ /* Set layout value */
+ if(H5P_poke(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set layout")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_chunk_opts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_chunk_opts
+ *
+ * Purpose: Gets the options related to chunked storage for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, January 22, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_chunk_opts(hid_t plist_id, unsigned *options)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_layout_t layout; /* Layout information for setting chunk info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", plist_id, options);
+
+#ifndef H5_HAVE_C99_DESIGNATED_INITIALIZER
+ /* If the compiler doesn't support C99 designated initializers, check if
+ * the default layout structs have been initialized yet or not. *ick* -QAK
+ */
+ if(!H5P_dcrt_def_layout_init_g)
+ if(H5P__init_def_layout() < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't initialize default layout info")
+#endif /* H5_HAVE_C99_DESIGNATED_INITIALIZER */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the layout property */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
+ if(H5D_CHUNKED != layout.type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a chunked storage layout")
+
+ if(options) {
+ /* Translate options from flags that can be used with the layout message
+ * to those known to the public */
+ *options = 0;
+ if(layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS)
+ *options |= H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_chunk_opts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_external
+ *
+ * Purpose: Adds an external file to the list of external files. PLIST_ID
+ * should be an object ID for a dataset creation property list.
+ * NAME is the name of an external file, OFFSET is the location
+ * where the data starts in that file, and SIZE is the number of
+ * bytes reserved in the file for the data.
+ *
+ * If a dataset is split across multiple files then the files
+ * should be defined in order. The total size of the dataset is
+ * the sum of the SIZE arguments for all the external files. If
+ * the total size is larger than the size of a dataset then the
+ * dataset can be extended (provided the dataspace also allows
+ * the extending).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 3, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_external(hid_t plist_id, const char *name, off_t offset, hsize_t size)
+{
+ size_t idx;
+ hsize_t total, tmp;
+ H5O_efl_t efl;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*soh", plist_id, name, offset, size);
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "no name given")
+ if(offset < 0)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "negative external file offset")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_peek(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
+ if(efl.nused > 0 && H5O_EFL_UNLIMITED == efl.slot[efl.nused - 1].size)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "previous file size is unlimited")
+
+ if(H5O_EFL_UNLIMITED != size) {
+ for(idx = 0, total = size; idx < efl.nused; idx++, total = tmp) {
+ tmp = total + efl.slot[idx].size;
+ if(tmp <= total)
+ HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "total external data size overflowed")
+ } /* end for */
+ } /* end if */
+
+ /* Add to the list */
+ if(efl.nused >= efl.nalloc) {
+ size_t na = efl.nalloc + H5O_EFL_ALLOC;
+ H5O_efl_entry_t *x = (H5O_efl_entry_t *)H5MM_realloc(efl.slot, na * sizeof(H5O_efl_entry_t));
+
+ if(!x)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ efl.nalloc = na;
+ efl.slot = x;
+ } /* end if */
+ idx = efl.nused;
+ efl.slot[idx].name_offset = 0; /*not entered into heap yet*/
+ efl.slot[idx].name = H5MM_xstrdup(name);
+ efl.slot[idx].offset = offset;
+ efl.slot[idx].size = size;
+ efl.nused++;
+
+ if(H5P_poke(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set external file list")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_external() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_external_count
+ *
+ * Purpose: Returns the number of external files for this dataset.
+ *
+ * Return: Success: Number of external files
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 3, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Pget_external_count(hid_t plist_id)
+{
+ H5O_efl_t efl;
+ H5P_genplist_t *plist; /* Property list pointer */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_peek(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
+
+ /* Set return value */
+ ret_value = (int)efl.nused;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_external_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_external
+ *
+ * Purpose: Returns information about an external file. External files
+ * are numbered from zero to N-1 where N is the value returned
+ * by H5Pget_external_count(). At most NAME_SIZE characters are
+ * copied into the NAME array. If the external file name is
+ * longer than NAME_SIZE with the null terminator, then the
+ * return value is not null terminated (similar to strncpy()).
+ *
+ * If NAME_SIZE is zero or NAME is the null pointer then the
+ * external file name is not returned. If OFFSET or SIZE are
+ * null pointers then the corresponding information is not
+ * returned.
+ *
+ * See Also: H5Pset_external()
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 3, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and get property for
+ * generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_external(hid_t plist_id, unsigned idx, size_t name_size, char *name/*out*/,
+ off_t *offset/*out*/, hsize_t *size/*out*/)
+{
+ H5O_efl_t efl;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iIuzxxx", plist_id, idx, name_size, name, offset, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_peek(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
+
+ if(idx >= efl.nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "external file index is out of range")
+
+ /* Return values */
+ if(name_size>0 && name)
+ HDstrncpy(name, efl.slot[idx].name, name_size);
+ if(offset)
+ *offset = efl.slot[idx].offset;
+ if(size)
+ *size = efl.slot[idx].size;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_external() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_szip
+ *
+ * Purpose: Sets the compression method for a permanent or transient
+ * filter pipeline (depending on whether PLIST_ID is a dataset
+ * creation or transfer property list) to H5Z_FILTER_SZIP
+ * Szip is a special compression package that is said to be good
+ * for scientific data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Kent Yang
+ * Tuesday, April 1, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels_per_block)
+{
+ H5O_pline_t pline;
+ H5P_genplist_t *plist; /* Property list pointer */
+ unsigned cd_values[2]; /* Filter parameters */
+ unsigned int config_flags;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, options_mask, pixels_per_block);
+
+ if(H5Z_get_filter_info(H5Z_FILTER_SZIP, &config_flags) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't get filter info")
+
+ if(!(config_flags & H5Z_FILTER_CONFIG_ENCODE_ENABLED))
+ HGOTO_ERROR(H5E_PLINE, H5E_NOENCODER, FAIL, "Filter present but encoding is disabled.")
+
+ /* Check arguments */
+ if((pixels_per_block % 2) == 1)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "pixels_per_block is not even")
+ if(pixels_per_block > H5_SZIP_MAX_PIXELS_PER_BLOCK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "pixels_per_block is too large")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Always set K13 compression (and un-set CHIP compression) */
+ options_mask &= (unsigned)(~H5_SZIP_CHIP_OPTION_MASK);
+ options_mask |= H5_SZIP_ALLOW_K13_OPTION_MASK;
+
+ /* Always set "raw" (no szip header) flag for data */
+ options_mask |= H5_SZIP_RAW_OPTION_MASK;
+
+ /* Mask off the LSB and MSB options, if they were given */
+ /* (The HDF5 library sets them internally, as needed) */
+ options_mask &= (unsigned)(~(H5_SZIP_LSB_OPTION_MASK | H5_SZIP_MSB_OPTION_MASK));
+
+ /* Set the parameters for the filter */
+ cd_values[0]=options_mask;
+ cd_values[1]=pixels_per_block;
+
+ /* Add the filter */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+ if(H5Z_append(&pline, H5Z_FILTER_SZIP, H5Z_FLAG_OPTIONAL, (size_t)2, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add szip filter to pipeline")
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_szip() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_shuffle
+ *
+ * Purpose: Sets the shuffling method for a permanent
+ * filter to H5Z_FILTER_SHUFFLE
+ * and bytes of the datatype of the array to be shuffled
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Kent Yang
+ * Wednesday, November 13, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_shuffle(hid_t plist_id)
+{
+ H5O_pline_t pline;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", plist_id);
+
+ /* Check arguments */
+ if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Add the filter */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+ if(H5Z_append(&pline, H5Z_FILTER_SHUFFLE, H5Z_FLAG_OPTIONAL, (size_t)0, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to shuffle the data")
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_shuffle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_nbit
+ *
+ * Purpose: Sets nbit filter for a dataset creation property list
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Xiaowen Wu
+ * Wednesday, December 22, 2004
+ *
+ * Modifications:
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_nbit(hid_t plist_id)
+{
+ H5O_pline_t pline;
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", plist_id);
+
+ /* Check arguments */
+ if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Add the nbit filter */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+ if(H5Z_append(&pline, H5Z_FILTER_NBIT, H5Z_FLAG_OPTIONAL, (size_t)0, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add nbit filter to pipeline")
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_nbit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_scaleoffset
+ *
+ * Purpose: Sets scaleoffset filter for a dataset creation property list
+ * and user-supplied parameters
+ *
+ * Parameters: scale_factor:
+ for integer datatype,
+ this parameter will be
+ minimum-bits, if this value is set to 0,
+ scaleoffset filter will calculate the minimum-bits.
+
+ For floating-point datatype,
+ For variable-minimum-bits method, this will be
+ the decimal precision of the filter,
+ For fixed-minimum-bits method, this will be
+ the minimum-bit of the filter.
+ scale_type: 0 for floating-point variable-minimum-bits,
+ 1 for floating-point fixed-minimum-bits,
+ other values, for integer datatype
+
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Xiaowen Wu
+ * Thursday, April 14, 2005
+ *
+ * Modifications:
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_scaleoffset(hid_t plist_id, H5Z_SO_scale_type_t scale_type, int scale_factor)
+{
+ H5O_pline_t pline;
+ H5P_genplist_t *plist; /* Property list pointer */
+ unsigned cd_values[2]; /* Filter parameters */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iZaIs", plist_id, scale_type, scale_factor);
+
+ /* Check arguments */
+ if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")
+
+ if(scale_factor < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "scale factor must be >= 0")
+ if(scale_type!=H5Z_SO_FLOAT_DSCALE && scale_type!=H5Z_SO_FLOAT_ESCALE && scale_type!=H5Z_SO_INT)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid scale type")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set parameters for the filter
+ * scale_type = 0: floating-point type, filter uses variable-minimum-bits method,
+ * scale_factor is decimal scale factor
+ * scale_type = 1: floating-point type, filter uses fixed-minimum-bits method,
+ * scale_factor is the fixed minimum number of bits
+ * scale type = other: integer type, scale_factor is minimum number of bits
+ * if scale_factor = 0, then filter calculates minimum number of bits
+ */
+ cd_values[0] = scale_type;
+ cd_values[1] = (unsigned)scale_factor;
+
+ /* Add the scaleoffset filter */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+ if(H5Z_append(&pline, H5Z_FILTER_SCALEOFFSET, H5Z_FLAG_OPTIONAL, (size_t)2, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add scaleoffset filter to pipeline")
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_scaleoffset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fill_value
+ *
+ * Purpose: Set the fill value for a dataset creation property list. The
+ * VALUE is interpreted as being of type TYPE, which need not
+ * be the same type as the dataset but the library must be able
+ * to convert VALUE to the dataset type when the dataset is
+ * created. If VALUE is NULL, it will be interpreted as
+ * undefining fill value.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fill_value(hid_t plist_id, hid_t type_id, const void *value)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_fill_t fill; /* Fill value to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii*x", plist_id, type_id, value);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the current fill value */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Release the dynamic fill value components */
+ H5O_fill_reset_dyn(&fill);
+
+ if(value) {
+ H5T_t *type; /* Datatype for fill value */
+ H5T_path_t *tpath; /* Conversion information */
+
+ /* Retrieve pointer to datatype */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Set the fill value */
+ if(NULL == (fill.type = H5T_copy(type, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy datatype")
+ fill.size = (ssize_t)H5T_get_size(type);
+ if(NULL == (fill.buf = H5MM_malloc((size_t)fill.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for fill value")
+ HDmemcpy(fill.buf, value, (size_t)fill.size);
+
+ /* Set up type conversion function */
+ if(NULL == (tpath = H5T_path_find(type, type, NULL, NULL, H5AC_ind_read_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types")
+
+ /* If necessary, convert fill value datatypes (which copies VL components, etc.) */
+ if(!H5T_path_noop(tpath)) {
+ uint8_t *bkg_buf = NULL; /* Background conversion buffer */
+
+ /* Allocate a background buffer */
+ if(H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (size_t)fill.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Convert the fill value */
+ if(H5T_convert(tpath, type_id, type_id, (size_t)1, (size_t)0, (size_t)0, fill.buf, bkg_buf, H5AC_ind_read_dxpl_id) < 0) {
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
+ } /* end if */
+
+ /* Release the background buffer */
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf);
+ } /* end if */
+ } /* end if */
+ else
+ fill.size = (-1);
+
+ /* Update fill value in property list */
+ if(H5P_poke(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set fill value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fill_value() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_get_fill_value
+ *
+ * Purpose: Queries the fill value property of a dataset creation
+ * property list. The fill value is returned through the VALUE
+ * pointer and the memory is allocated by the caller. The fill
+ * value will be converted from its current datatype to the
+ * specified TYPE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_get_fill_value(H5P_genplist_t *plist, const H5T_t *type, void *value/*out*/,
+ hid_t dxpl_id)
+{
+ H5O_fill_t fill; /* Fill value to retrieve */
+ H5T_path_t *tpath; /*type conversion info */
+ void *buf = NULL; /*conversion buffer */
+ void *bkg = NULL; /*conversion buffer */
+ hid_t src_id = -1; /*source datatype id */
+ hid_t dst_id = -1; /*destination datatype id */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /*
+ * If no fill value is defined then return an error. We can't even
+ * return zero because we don't know the datatype of the dataset and
+ * datatype conversion might not have resulted in zero. If fill value
+ * is undefined, also return error.
+ */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+ if(fill.size == -1)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "fill value is undefined")
+
+ /* Check for "default" fill value */
+ if(fill.size == 0) {
+ HDmemset(value, 0, H5T_get_size(type));
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /*
+ * Can we convert between the source and destination datatypes?
+ */
+ if(NULL == (tpath = H5T_path_find(fill.type, type, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes")
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill.type, H5T_COPY_TRANSIENT), FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy/register datatype")
+
+ /*
+ * Data type conversions are always done in place, so we need a buffer
+ * other than the fill value buffer that is large enough for both source
+ * and destination. The app-supplied buffer might do okay.
+ */
+ if(H5T_get_size(type) >= H5T_get_size(fill.type)) {
+ buf = value;
+ if(H5T_path_bkg(tpath) && NULL == (bkg = H5MM_malloc(H5T_get_size(type))))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for type conversion")
+ } /* end if */
+ else {
+ if(NULL == (buf = H5MM_malloc(H5T_get_size(fill.type))))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for type conversion")
+ if(H5T_path_bkg(tpath) && NULL == (bkg = H5MM_malloc(H5T_get_size(fill.type))))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for type conversion")
+ } /* end else */
+ HDmemcpy(buf, fill.buf, H5T_get_size(fill.type));
+
+ /* Do the conversion */
+ if((dst_id = H5I_register(H5I_DATATYPE, H5T_copy(type, H5T_COPY_TRANSIENT), FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy/register datatype")
+ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ if(buf != value)
+ HDmemcpy(value, buf, H5T_get_size(type));
+
+done:
+ if(buf != value)
+ H5MM_xfree(buf);
+ if(bkg != value)
+ H5MM_xfree(bkg);
+ if(src_id >= 0 && H5I_dec_ref(src_id) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTDEC, FAIL, "can't decrement ref count of temp ID")
+ if(dst_id >= 0 && H5I_dec_ref(dst_id) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTDEC, FAIL, "can't decrement ref count of temp ID")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_get_fill_value() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fill_value
+ *
+ * Purpose: Queries the fill value property of a dataset creation
+ * property list. The fill value is returned through the VALUE
+ * pointer and the memory is allocated by the caller. The fill
+ * value will be converted from its current datatype to the
+ * specified TYPE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, October 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fill_value(hid_t plist_id, hid_t type_id, void *value/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5T_t *type; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iix", plist_id, type_id, value);
+
+ /* Check arguments */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(!value)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,"no fill value output buffer")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the fill value */
+ if(H5P_get_fill_value(plist, type, value, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fill_value() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_is_fill_value_defined
+ *
+ * Purpose: Check if fill value is defined. Internal version of function
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_is_fill_value_defined(const H5O_fill_t *fill, H5D_fill_value_t *status)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(fill);
+ HDassert(status);
+
+ /* Check if the fill value was "unset" */
+ if(fill->size == -1 && !fill->buf)
+ *status = H5D_FILL_VALUE_UNDEFINED;
+ /* Check if the fill value was set to the default fill value by the library */
+ else if(fill->size == 0 && !fill->buf)
+ *status = H5D_FILL_VALUE_DEFAULT;
+ /* Check if the fill value was set by the application */
+ else if(fill->size > 0 && fill->buf)
+ *status = H5D_FILL_VALUE_USER_DEFINED;
+ else {
+ *status = H5D_FILL_VALUE_ERROR;
+ HGOTO_ERROR(H5E_PLIST, H5E_BADRANGE, FAIL, "invalid combination of fill-value info")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_is_fill_value_defined() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_fill_value_defined
+ *
+ * Purpose: Check if fill value is defined.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_fill_value_defined(H5P_genplist_t *plist, H5D_fill_value_t *status)
+{
+ H5O_fill_t fill; /* Fill value to query */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(status);
+
+ /* Get the fill value struct */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Get the fill-value status */
+ if(H5P_is_fill_value_defined(&fill, status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't check fill value status")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_fill_value_defined() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pfill_value_defined
+ *
+ * Purpose: Check if fill value is defined.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pfill_value_defined(hid_t plist_id, H5D_fill_value_t *status)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*DF", plist_id, status);
+
+ HDassert(status);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the fill-value status */
+ if(H5P_fill_value_defined(plist, status) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't check fill value status")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pfill_value_defined() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_alloc_time
+ *
+ * Purpose: Set space allocation time for dataset during creation.
+ * Valid values are H5D_ALLOC_TIME_DEFAULT, H5D_ALLOC_TIME_EARLY,
+ * H5D_ALLOC_TIME_LATE, H5D_ALLOC_TIME_INCR
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ * Modifications:
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_alloc_time(hid_t plist_id, H5D_alloc_time_t alloc_time)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_fill_t fill; /* Fill value property to modify */
+ unsigned alloc_time_state; /* State of allocation time property */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDa", plist_id, alloc_time);
+
+ /* Check arguments */
+ if(alloc_time < H5D_ALLOC_TIME_DEFAULT || alloc_time > H5D_ALLOC_TIME_INCR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid allocation time setting")
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Check for resetting to default for layout type */
+ if(alloc_time == H5D_ALLOC_TIME_DEFAULT) {
+ H5O_layout_t layout; /* Type of storage layout */
+
+ /* Peek at the storage layout */
+ if(H5P_peek(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get layout")
+
+ /* Set the default based on layout */
+ switch(layout.type) {
+ case H5D_COMPACT:
+ alloc_time = H5D_ALLOC_TIME_EARLY;
+ break;
+
+ case H5D_CONTIGUOUS:
+ alloc_time = H5D_ALLOC_TIME_LATE;
+ break;
+
+ case H5D_CHUNKED:
+ alloc_time = H5D_ALLOC_TIME_INCR;
+ break;
+
+ case H5D_VIRTUAL:
+ alloc_time = H5D_ALLOC_TIME_INCR;
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown layout type")
+ } /* end switch */
+
+ /* Reset the "state" of the allocation time property back to the "default" */
+ alloc_time_state = 1;
+ } /* end if */
+ else
+ /* Set the "state" of the allocation time property to indicate the user modified it */
+ alloc_time_state = 0;
+
+ /* Retrieve previous fill value settings */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Update property value */
+ fill.alloc_time = alloc_time;
+
+ /* Set values */
+ if(H5P_poke(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value")
+ if(H5P_set(plist, H5D_CRT_ALLOC_TIME_STATE_NAME, &alloc_time_state) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set space allocation time")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_alloc_time() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_alloc_time
+ *
+ * Purpose: Get space allocation time for dataset creation.
+ * Valid values are H5D_ALLOC_TIME_DEFAULT, H5D_ALLOC_TIME_EARLY,
+ * H5D_ALLOC_TIME_LATE, H5D_ALLOC_TIME_INCR
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_alloc_time(hid_t plist_id, H5D_alloc_time_t *alloc_time/*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, alloc_time);
+
+ /* Get values */
+ if(alloc_time) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_fill_t fill; /* Fill value property to query */
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve fill value settings */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Set user's value */
+ *alloc_time = fill.alloc_time;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_alloc_time() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fill_time
+ *
+ * Purpose: Set fill value writing time for dataset. Valid values are
+ * H5D_FILL_TIME_ALLOC and H5D_FILL_TIME_NEVER.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fill_time(hid_t plist_id, H5D_fill_time_t fill_time)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_fill_t fill; /* Fill value property to modify */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iDf", plist_id, fill_time);
+
+ /* Check arguments */
+ if(fill_time < H5D_FILL_TIME_ALLOC || fill_time > H5D_FILL_TIME_IFSET)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fill time setting")
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve previous fill value settings */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Update property value */
+ fill.fill_time = fill_time;
+
+ /* Set values */
+ if(H5P_poke(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fill_time() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fill_time
+ *
+ * Purpose: Get fill value writing time. Valid values are H5D_NEVER
+ * and H5D_ALLOC.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, January 16, 2002
+ *
+ * Modifications:
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fill_time(hid_t plist_id, H5D_fill_time_t *fill_time/*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, fill_time);
+
+ /* Set values */
+ if(fill_time) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_fill_t fill; /* Fill value property to query */
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve fill value settings */
+ if(H5P_peek(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
+
+ /* Set user's value */
+ *fill_time = fill.fill_time;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fill_time() */
+
diff --git a/src/H5Pdeprec.c b/src/H5Pdeprec.c
new file mode 100644
index 0000000..7f96333
--- /dev/null
+++ b/src/H5Pdeprec.c
@@ -0,0 +1,620 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pdeprec.c
+ * October 11 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5P interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pregister1
+ PURPOSE
+ Routine to register a new property in a property list class.
+ USAGE
+ herr_t H5Pregister1(class, name, size, default, prp_create, prp_set, prp_get, prp_close)
+ hid_t class; IN: Property list class to close
+ const char *name; IN: Name of property to register
+ size_t size; IN: Size of property in bytes
+ void *def_value; IN: Pointer to buffer containing default value
+ for property in newly created property lists
+ H5P_prp_create_func_t prp_create; IN: Function pointer to property
+ creation callback
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Registers a new property with a property list class. The property will
+ exist in all property list objects of that class after this routine is
+ finished. The name of the property must not already exist. The default
+ property value must be provided and all new property lists created with this
+ property will have the property value set to the default provided. Any of
+ the callback routines may be set to NULL if they are not needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'default' pointer for a
+ zero-sized property may be set to NULL. The property 'create' & 'close'
+ callbacks are called for zero-sized properties, but the 'set' and 'get'
+ callbacks are never called.
+
+ The 'create' callback is called when a new property list with this
+ property is being created. H5P_prp_create_func_t is defined as:
+ typedef herr_t (*H5P_prp_create_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *initial_value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being created.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *initial_value; IN/OUT: The initial value for the property being created.
+ (The 'default' value passed to H5Pregister1)
+ The 'create' routine may modify the value to be set and those changes will
+ be stored as the initial value of the property. If the 'create' routine
+ returns a negative value, the new property value is not copied into the
+ property and the property list creation routine returns an error value.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pregister1(hid_t cls_id, const char *name, size_t size, void *def_value,
+ H5P_prp_create_func_t prp_create, H5P_prp_set_func_t prp_set,
+ H5P_prp_get_func_t prp_get, H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_close_func_t prp_close)
+{
+ H5P_genclass_t *pclass; /* Property list class to modify */
+ H5P_genclass_t *orig_pclass; /* Original property class */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE10("e", "i*sz*xxxxxxx", cls_id, name, size, def_value, prp_create,
+ prp_set, prp_get, prp_delete, prp_copy, prp_close);
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(cls_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class");
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid class name");
+ if(size > 0 && def_value == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "properties >0 size must have default");
+
+ /* Create the new property list class */
+ orig_pclass = pclass;
+ if((ret_value = H5P_register(&pclass, name, size, def_value, prp_create, prp_set, prp_get, NULL, NULL, prp_delete, prp_copy, NULL, prp_close)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to register property in class");
+
+ /* Check if the property class changed and needs to be substituted in the ID */
+ if(pclass != orig_pclass) {
+ H5P_genclass_t *old_pclass; /* Old property class */
+
+ /* Substitute the new property class in the ID */
+ if(NULL == (old_pclass = (H5P_genclass_t *)H5I_subst(cls_id, pclass)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to substitute property class in ID")
+ HDassert(old_pclass == orig_pclass);
+
+ /* Close the previous class */
+ if(H5P_close_class(orig_pclass) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "unable to close original property class after substitution")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pregister1() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Pinsert1
+ PURPOSE
+ Routine to insert a new property in a property list.
+ USAGE
+ herr_t H5Pinsert1(plist, name, size, value, prp_set, prp_get, prp_close)
+ hid_t plist; IN: Property list to add property to
+ const char *name; IN: Name of property to add
+ size_t size; IN: Size of property in bytes
+ void *value; IN: Pointer to the value for the property
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Inserts a temporary property into a property list. The property will
+ exist only in this property list object. The name of the property must not
+ already exist. The value must be provided unless the property is zero-
+ sized. Any of the callback routines may be set to NULL if they are not
+ needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'value' pointer for a
+ zero-sized property may be set to NULL. The property 'close' callback is
+ called for zero-sized properties, but the 'set' and 'get' callbacks are
+ never called.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ There is no 'create' callback routine for temporary property list
+ objects, the initial value is assumed to have any necessary setup already
+ performed on it.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Pinsert1(hid_t plist_id, const char *name, size_t size, void *value,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_close_func_t prp_close)
+{
+ H5P_genplist_t *plist; /* Property list to modify */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE9("e", "i*sz*xxxxxx", plist_id, name, size, value, prp_set, prp_get,
+ prp_delete, prp_copy, prp_close);
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid property name")
+ if(size > 0 && value == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "properties >0 size must have default")
+
+ /* Create the new property list class */
+ if((ret_value = H5P_insert(plist, name, size, value, prp_set, prp_get,
+ NULL, NULL, prp_delete, prp_copy, NULL, prp_close)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to register property in plist")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pinsert1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_version
+ *
+ * Purpose: Retrieves version information for various parts of a file.
+ *
+ * SUPER: The file super block.
+ * FREELIST: The global free list.
+ * STAB: The root symbol table entry.
+ * SHHDR: Shared object headers.
+ *
+ * Any (or even all) of the output arguments can be null
+ * pointers.
+ *
+ * Return: Success: Non-negative, version information is returned
+ * through the arguments.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_version(hid_t plist_id, unsigned *super/*out*/, unsigned *freelist/*out*/,
+ unsigned *stab/*out*/, unsigned *shhdr/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "ixxxx", plist_id, super, freelist, stab, shhdr);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(super)
+ if(H5P_get(plist, H5F_CRT_SUPER_VERS_NAME, super) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get superblock version")
+ if(freelist)
+ *freelist = HDF5_FREESPACE_VERSION; /* (hard-wired) */
+ if(stab)
+ *stab = HDF5_OBJECTDIR_VERSION; /* (hard-wired) */
+ if(shhdr)
+ *shhdr = HDF5_SHAREDHEADER_VERSION; /* (hard-wired) */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_version() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_space
+ *
+ * Purpose: It is mapped to H5Pset_file_space_strategy().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Jan 2017
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t threshold)
+{
+
+ H5F_fspace_strategy_t new_strategy; /* File space strategy type */
+ hbool_t new_persist = H5F_FREE_SPACE_PERSIST_DEF; /* Persisting free-space or not */
+ hsize_t new_threshold = H5F_FREE_SPACE_THRESHOLD_DEF; /* Free-space section threshold */
+ H5F_file_space_type_t in_strategy = strategy; /* Input strategy */
+ hsize_t in_threshold = threshold; /* Input threshold */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iFfh", plist_id, strategy, threshold);
+
+ if((unsigned)in_strategy >= H5F_FILE_SPACE_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid strategy")
+ /*
+ * For 1.10.0 H5Pset_file_space:
+ * If strategy is zero, the property is not changed;
+ * the existing strategy is retained.
+ * If threshold is zero, the property is not changed;
+ * the existing threshold is retained.
+ */
+ if(!in_strategy)
+ H5Pget_file_space(plist_id, &in_strategy, NULL);
+ if(!in_threshold)
+ H5Pget_file_space(plist_id, NULL, &in_threshold);
+
+ switch(in_strategy) {
+ case H5F_FILE_SPACE_ALL_PERSIST:
+ new_strategy = H5F_FSPACE_STRATEGY_FSM_AGGR;
+ new_persist = TRUE;
+ new_threshold = in_threshold;
+ break;
+
+ case H5F_FILE_SPACE_ALL:
+ new_strategy = H5F_FSPACE_STRATEGY_FSM_AGGR;
+ new_threshold = in_threshold;
+ break;
+
+ case H5F_FILE_SPACE_AGGR_VFD:
+ new_strategy = H5F_FSPACE_STRATEGY_AGGR;
+ break;
+
+ case H5F_FILE_SPACE_VFD:
+ new_strategy = H5F_FSPACE_STRATEGY_NONE;
+ break;
+
+ case H5F_FILE_SPACE_NTYPES:
+ case H5F_FILE_SPACE_DEFAULT:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file space strategy")
+ }
+
+ if(H5Pset_file_space_strategy(plist_id, new_strategy, new_persist, new_threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_file_space() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_space
+ *
+ * Purpose: It is mapped to H5Pget_file_space_strategy().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Jan 2017
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy, hsize_t *threshold)
+{
+ H5F_fspace_strategy_t new_strategy; /* File space strategy type */
+ hbool_t new_persist; /* Persisting free-space or not */
+ hsize_t new_threshold; /* Free-space section threshold */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*Ff*h", plist_id, strategy, threshold);
+
+ /* Get current file space info */
+ if(H5Pget_file_space_strategy(plist_id, &new_strategy, &new_persist, &new_threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy")
+
+ /* Get value(s) */
+ if(strategy) {
+ switch(new_strategy) {
+
+ case H5F_FSPACE_STRATEGY_FSM_AGGR:
+ if(new_persist)
+ *strategy = H5F_FILE_SPACE_ALL_PERSIST;
+ else
+ *strategy = H5F_FILE_SPACE_ALL;
+ break;
+
+ case H5F_FSPACE_STRATEGY_AGGR:
+ *strategy = H5F_FILE_SPACE_AGGR_VFD;
+ break;
+
+ case H5F_FSPACE_STRATEGY_NONE:
+ *strategy = H5F_FILE_SPACE_VFD;
+ break;
+
+ case H5F_FSPACE_STRATEGY_PAGE:
+ case H5F_FSPACE_STRATEGY_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file space strategy")
+ }
+ }
+
+ if(threshold)
+ *threshold = new_threshold;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_file_space() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Pdxpl.c b/src/H5Pdxpl.c
new file mode 100644
index 0000000..fdb402f
--- /dev/null
+++ b/src/H5Pdxpl.c
@@ -0,0 +1,2242 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pdxpl.c
+ * March 16 1998
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Data transfer property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ======== Data transfer properties ======== */
+/* Definitions for maximum temp buffer size property */
+#define H5D_XFER_MAX_TEMP_BUF_SIZE sizeof(size_t)
+#define H5D_XFER_MAX_TEMP_BUF_DEF H5D_TEMP_BUF_SIZE
+#define H5D_XFER_MAX_TEMP_BUF_ENC H5P__encode_size_t
+#define H5D_XFER_MAX_TEMP_BUF_DEC H5P__decode_size_t
+/* Definitions for type conversion buffer property */
+#define H5D_XFER_TCONV_BUF_SIZE sizeof(void *)
+#define H5D_XFER_TCONV_BUF_DEF NULL
+/* Definitions for background buffer property */
+#define H5D_XFER_BKGR_BUF_SIZE sizeof(void *)
+#define H5D_XFER_BKGR_BUF_DEF NULL
+/* Definitions for background buffer type property */
+#define H5D_XFER_BKGR_BUF_TYPE_SIZE sizeof(H5T_bkg_t)
+#define H5D_XFER_BKGR_BUF_TYPE_DEF H5T_BKG_NO
+#define H5D_XFER_BKGR_BUF_TYPE_ENC H5P__dxfr_bkgr_buf_type_enc
+#define H5D_XFER_BKGR_BUF_TYPE_DEC H5P__dxfr_bkgr_buf_type_dec
+/* Definitions for B-tree node splitting ratio property */
+/* (These default B-tree node splitting ratios are also used for splitting
+ * group's B-trees as well as chunked dataset's B-trees - QAK)
+ */
+#define H5D_XFER_BTREE_SPLIT_RATIO_SIZE sizeof(double[3])
+#define H5D_XFER_BTREE_SPLIT_RATIO_DEF {0.1f, 0.5f, 0.9f}
+#define H5D_XFER_BTREE_SPLIT_RATIO_ENC H5P__dxfr_btree_split_ratio_enc
+#define H5D_XFER_BTREE_SPLIT_RATIO_DEC H5P__dxfr_btree_split_ratio_dec
+/* Definitions for vlen allocation function property */
+#define H5D_XFER_VLEN_ALLOC_SIZE sizeof(H5MM_allocate_t)
+#define H5D_XFER_VLEN_ALLOC_DEF H5D_VLEN_ALLOC
+/* Definitions for vlen allocation info property */
+#define H5D_XFER_VLEN_ALLOC_INFO_SIZE sizeof(void *)
+#define H5D_XFER_VLEN_ALLOC_INFO_DEF H5D_VLEN_ALLOC_INFO
+/* Definitions for vlen free function property */
+#define H5D_XFER_VLEN_FREE_SIZE sizeof(H5MM_free_t)
+#define H5D_XFER_VLEN_FREE_DEF H5D_VLEN_FREE
+/* Definitions for vlen free info property */
+#define H5D_XFER_VLEN_FREE_INFO_SIZE sizeof(void *)
+#define H5D_XFER_VLEN_FREE_INFO_DEF H5D_VLEN_FREE_INFO
+/* Definitions for hyperslab vector size property */
+/* (Be cautious about increasing the default size, there are arrays allocated
+ * on the stack which depend on it - QAK)
+ */
+#define H5D_XFER_HYPER_VECTOR_SIZE_SIZE sizeof(size_t)
+#define H5D_XFER_HYPER_VECTOR_SIZE_DEF H5D_IO_VECTOR_SIZE
+#define H5D_XFER_HYPER_VECTOR_SIZE_ENC H5P__encode_size_t
+#define H5D_XFER_HYPER_VECTOR_SIZE_DEC H5P__decode_size_t
+
+/* Parallel I/O properties */
+/* Note: Some of these are registered with the DXPL class even when parallel
+ * is disabled, so that property list comparisons of encoded property
+ * lists (between parallel & non-parallel builds) work properly. -QAK
+ */
+
+/* Definitions for I/O transfer mode property */
+#define H5D_XFER_IO_XFER_MODE_SIZE sizeof(H5FD_mpio_xfer_t)
+#define H5D_XFER_IO_XFER_MODE_DEF H5FD_MPIO_INDEPENDENT
+#define H5D_XFER_IO_XFER_MODE_ENC H5P__dxfr_io_xfer_mode_enc
+#define H5D_XFER_IO_XFER_MODE_DEC H5P__dxfr_io_xfer_mode_dec
+/* Definitions for optimization of MPI-IO transfer mode property */
+#define H5D_XFER_MPIO_COLLECTIVE_OPT_SIZE sizeof(H5FD_mpio_collective_opt_t)
+#define H5D_XFER_MPIO_COLLECTIVE_OPT_DEF H5FD_MPIO_COLLECTIVE_IO
+#define H5D_XFER_MPIO_COLLECTIVE_OPT_ENC H5P__dxfr_mpio_collective_opt_enc
+#define H5D_XFER_MPIO_COLLECTIVE_OPT_DEC H5P__dxfr_mpio_collective_opt_dec
+#define H5D_XFER_MPIO_CHUNK_OPT_HARD_SIZE sizeof(H5FD_mpio_chunk_opt_t)
+#define H5D_XFER_MPIO_CHUNK_OPT_HARD_DEF H5FD_MPIO_CHUNK_DEFAULT
+#define H5D_XFER_MPIO_CHUNK_OPT_HARD_ENC H5P__dxfr_mpio_chunk_opt_hard_enc
+#define H5D_XFER_MPIO_CHUNK_OPT_HARD_DEC H5P__dxfr_mpio_chunk_opt_hard_dec
+#define H5D_XFER_MPIO_CHUNK_OPT_NUM_SIZE sizeof(unsigned)
+#define H5D_XFER_MPIO_CHUNK_OPT_NUM_DEF H5D_ONE_LINK_CHUNK_IO_THRESHOLD
+#define H5D_XFER_MPIO_CHUNK_OPT_NUM_ENC H5P__encode_unsigned
+#define H5D_XFER_MPIO_CHUNK_OPT_NUM_DEC H5P__decode_unsigned
+#define H5D_XFER_MPIO_CHUNK_OPT_RATIO_SIZE sizeof(unsigned)
+#define H5D_XFER_MPIO_CHUNK_OPT_RATIO_DEF H5D_MULTI_CHUNK_IO_COL_THRESHOLD
+#define H5D_XFER_MPIO_CHUNK_OPT_RATIO_ENC H5P__encode_unsigned
+#define H5D_XFER_MPIO_CHUNK_OPT_RATIO_DEC H5P__decode_unsigned
+/* Definitions for chunk opt mode property. */
+#define H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_SIZE sizeof(H5D_mpio_actual_chunk_opt_mode_t)
+#define H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_DEF H5D_MPIO_NO_CHUNK_OPTIMIZATION
+/* Definitions for chunk io mode property. */
+#define H5D_MPIO_ACTUAL_IO_MODE_SIZE sizeof(H5D_mpio_actual_io_mode_t)
+#define H5D_MPIO_ACTUAL_IO_MODE_DEF H5D_MPIO_NO_COLLECTIVE
+/* Definitions for cause of broken collective io property */
+#define H5D_MPIO_NO_COLLECTIVE_CAUSE_SIZE sizeof(uint32_t)
+#define H5D_MPIO_NO_COLLECTIVE_CAUSE_DEF H5D_MPIO_COLLECTIVE
+#ifdef H5_HAVE_PARALLEL
+/* Definitions for memory MPI type property */
+#define H5FD_MPI_XFER_MEM_MPI_TYPE_SIZE sizeof(MPI_Datatype)
+#define H5FD_MPI_XFER_MEM_MPI_TYPE_DEF MPI_DATATYPE_NULL
+/* Definitions for file MPI type property */
+#define H5FD_MPI_XFER_FILE_MPI_TYPE_SIZE sizeof(MPI_Datatype)
+#define H5FD_MPI_XFER_FILE_MPI_TYPE_DEF MPI_DATATYPE_NULL
+#endif /* H5_HAVE_PARALLEL */
+
+/* Definitions for EDC property */
+#define H5D_XFER_EDC_SIZE sizeof(H5Z_EDC_t)
+#define H5D_XFER_EDC_DEF H5Z_ENABLE_EDC
+#define H5D_XFER_EDC_ENC H5P__dxfr_edc_enc
+#define H5D_XFER_EDC_DEC H5P__dxfr_edc_dec
+/* Definitions for filter callback function property */
+#define H5D_XFER_FILTER_CB_SIZE sizeof(H5Z_cb_t)
+#define H5D_XFER_FILTER_CB_DEF {NULL,NULL}
+/* Definitions for type conversion callback function property */
+#define H5D_XFER_CONV_CB_SIZE sizeof(H5T_conv_cb_t)
+#define H5D_XFER_CONV_CB_DEF {NULL,NULL}
+/* Definitions for data transform property */
+#define H5D_XFER_XFORM_SIZE sizeof(void *)
+#define H5D_XFER_XFORM_DEF NULL
+#define H5D_XFER_XFORM_SET H5P__dxfr_xform_set
+#define H5D_XFER_XFORM_GET H5P__dxfr_xform_get
+#define H5D_XFER_XFORM_ENC H5P__dxfr_xform_enc
+#define H5D_XFER_XFORM_DEC H5P__dxfr_xform_dec
+#define H5D_XFER_XFORM_DEL H5P__dxfr_xform_del
+#define H5D_XFER_XFORM_COPY H5P__dxfr_xform_copy
+#define H5D_XFER_XFORM_CMP H5P__dxfr_xform_cmp
+#define H5D_XFER_XFORM_CLOSE H5P__dxfr_xform_close
+/* Definitions for properties of direct chunk write */
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_SIZE sizeof(hbool_t)
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_DEF FALSE
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_SIZE sizeof(uint32_t)
+#define H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_DEF 0
+#define H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_SIZE sizeof(hsize_t *)
+#define H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_DEF NULL
+#define H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_SIZE sizeof(uint32_t)
+#define H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_DEF 0
+/* Ring type - private property */
+#define H5AC_XFER_RING_SIZE sizeof(unsigned)
+#define H5AC_XFER_RING_DEF H5AC_RING_USER
+#define H5AC_XFER_RING_ENC H5P__encode_unsigned
+#define H5AC_XFER_RING_DEC H5P__decode_unsigned
+#ifdef H5_DEBUG_BUILD
+/* dxpl I/O type - private property */
+#define H5FD_DXPL_TYPE_SIZE sizeof(H5FD_dxpl_type_t)
+#endif /* H5_DEBUG_BUILD */
+#ifdef H5_HAVE_PARALLEL
+/* Definition for reading metadata collectively */
+#define H5D_XFER_COLL_MD_READ_SIZE sizeof(H5P_coll_md_read_flag_t)
+#define H5D_XFER_COLL_MD_READ_DEF H5P_USER_FALSE
+#define H5D_XFER_COLL_MD_READ_ENC H5P__encode_coll_md_read_flag_t
+#define H5D_XFER_COLL_MD_READ_DEC H5P__decode_coll_md_read_flag_t
+#endif /* H5_HAVE_PARALLEL */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__dxfr_reg_prop(H5P_genclass_t *pclass);
+
+/* Property list callbacks */
+static herr_t H5P__dxfr_bkgr_buf_type_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_bkgr_buf_type_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_btree_split_ratio_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_btree_split_ratio_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_io_xfer_mode_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_io_xfer_mode_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_mpio_collective_opt_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_mpio_collective_opt_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_mpio_chunk_opt_hard_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_mpio_chunk_opt_hard_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_edc_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_edc_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_xform_set(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dxfr_xform_get(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dxfr_xform_enc(const void *value, void **pp, size_t *size);
+static herr_t H5P__dxfr_xform_dec(const void **pp, void *value);
+static herr_t H5P__dxfr_xform_del(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__dxfr_xform_copy(const char* name, size_t size, void* value);
+static int H5P__dxfr_xform_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__dxfr_xform_close(const char* name, size_t size, void* value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Data transfer property list class library initialization object */
+const H5P_libclass_t H5P_CLS_DXFR[1] = {{
+ "data transfer", /* Class name for debugging */
+ H5P_TYPE_DATASET_XFER, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_DATASET_XFER_g, /* Pointer to class */
+ &H5P_CLS_DATASET_XFER_ID_g, /* Pointer to class ID */
+ &H5P_LST_DATASET_XFER_ID_g, /* Pointer to default property list ID */
+ H5P__dxfr_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/***************************/
+/* Local Private Variables */
+/***************************/
+
+/* Property value defaults */
+static const size_t H5D_def_max_temp_buf_g = H5D_XFER_MAX_TEMP_BUF_DEF; /* Default value for maximum temp buffer size */
+static const void *H5D_def_tconv_buf_g = H5D_XFER_TCONV_BUF_DEF; /* Default value for type conversion buffer */
+static const void *H5D_def_bkgr_buf_g = H5D_XFER_BKGR_BUF_DEF; /* Default value for background buffer */
+static const H5T_bkg_t H5D_def_bkgr_buf_type_g = H5D_XFER_BKGR_BUF_TYPE_DEF;
+static const double H5D_def_btree_split_ratio_g[3] = H5D_XFER_BTREE_SPLIT_RATIO_DEF; /* Default value for B-tree node split ratios */
+static const H5MM_allocate_t H5D_def_vlen_alloc_g = H5D_XFER_VLEN_ALLOC_DEF; /* Default value for vlen allocation function */
+static const void *H5D_def_vlen_alloc_info_g = H5D_XFER_VLEN_ALLOC_INFO_DEF; /* Default value for vlen allocation information */
+static const H5MM_free_t H5D_def_vlen_free_g = H5D_XFER_VLEN_FREE_DEF; /* Default value for vlen free function */
+static const void *H5D_def_vlen_free_info_g = H5D_XFER_VLEN_FREE_INFO_DEF; /* Default value for vlen free information */
+static const size_t H5D_def_hyp_vec_size_g = H5D_XFER_HYPER_VECTOR_SIZE_DEF; /* Default value for vector size */
+static const haddr_t H5D_def_tag_g = H5AC_TAG_DEF; /* Default value for cache entry tag */
+static const H5FD_mpio_xfer_t H5D_def_io_xfer_mode_g = H5D_XFER_IO_XFER_MODE_DEF; /* Default value for I/O transfer mode */
+static const H5FD_mpio_chunk_opt_t H5D_def_mpio_chunk_opt_mode_g = H5D_XFER_MPIO_CHUNK_OPT_HARD_DEF;
+static const H5FD_mpio_collective_opt_t H5D_def_mpio_collective_opt_mode_g = H5D_XFER_MPIO_COLLECTIVE_OPT_DEF;
+static const unsigned H5D_def_mpio_chunk_opt_num_g = H5D_XFER_MPIO_CHUNK_OPT_NUM_DEF;
+static const unsigned H5D_def_mpio_chunk_opt_ratio_g = H5D_XFER_MPIO_CHUNK_OPT_RATIO_DEF;
+static const H5D_mpio_actual_chunk_opt_mode_t H5D_def_mpio_actual_chunk_opt_mode_g = H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_DEF;
+static const H5D_mpio_actual_io_mode_t H5D_def_mpio_actual_io_mode_g = H5D_MPIO_ACTUAL_IO_MODE_DEF;
+static const H5D_mpio_no_collective_cause_t H5D_def_mpio_no_collective_cause_g = H5D_MPIO_NO_COLLECTIVE_CAUSE_DEF;
+#ifdef H5_HAVE_PARALLEL
+static const MPI_Datatype H5D_def_btype_g = H5FD_MPI_XFER_MEM_MPI_TYPE_DEF; /* Default value for MPI buffer type */
+static const MPI_Datatype H5D_def_ftype_g = H5FD_MPI_XFER_FILE_MPI_TYPE_DEF; /* Default value for MPI file type */
+static const H5P_coll_md_read_flag_t H5D_def_coll_md_read_g = H5D_XFER_COLL_MD_READ_DEF; /* Default setting for the collective metedata read flag */
+#endif /* H5_HAVE_PARALLEL */
+static const H5Z_EDC_t H5D_def_enable_edc_g = H5D_XFER_EDC_DEF; /* Default value for EDC property */
+static const H5Z_cb_t H5D_def_filter_cb_g = H5D_XFER_FILTER_CB_DEF; /* Default value for filter callback */
+static const H5T_conv_cb_t H5D_def_conv_cb_g = H5D_XFER_CONV_CB_DEF; /* Default value for datatype conversion callback */
+static const void *H5D_def_xfer_xform_g = H5D_XFER_XFORM_DEF; /* Default value for data transform */
+static const hbool_t H5D_def_direct_chunk_flag_g = H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_DEF; /* Default value for the flag of direct chunk write */
+static const uint32_t H5D_def_direct_chunk_filters_g = H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_DEF; /* Default value for the filters of direct chunk write */
+static const hsize_t *H5D_def_direct_chunk_offset_g = H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_DEF; /* Default value for the offset of direct chunk write */
+static const uint32_t H5D_def_direct_chunk_datasize_g = H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_DEF; /* Default value for the datasize of direct chunk write */
+static const H5AC_ring_t H5D_ring_g = H5AC_XFER_RING_DEF; /* Default value for the cache entry ring type */
+#ifdef H5_DEBUG_BUILD
+static const H5FD_dxpl_type_t H5D_dxpl_type_g = H5FD_NOIO_DXPL; /* Default value for the dxpl type */
+#endif /* H5_DEBUG_BUILD */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_reg_prop
+ *
+ * Purpose: Register the data transfer property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register the max. temp buffer size property */
+ if(H5P_register_real(pclass, H5D_XFER_MAX_TEMP_BUF_NAME, H5D_XFER_MAX_TEMP_BUF_SIZE, &H5D_def_max_temp_buf_g,
+ NULL, NULL, NULL, H5D_XFER_MAX_TEMP_BUF_ENC, H5D_XFER_MAX_TEMP_BUF_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the cache tag property */
+ if(H5P_register_real(pclass, H5AC_TAG_NAME, H5AC_TAG_SIZE, &H5D_def_tag_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the type conversion buffer property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_TCONV_BUF_NAME, H5D_XFER_TCONV_BUF_SIZE, &H5D_def_tconv_buf_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the background buffer property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_BKGR_BUF_NAME, H5D_XFER_BKGR_BUF_SIZE, &H5D_def_bkgr_buf_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the background buffer type property */
+ if(H5P_register_real(pclass, H5D_XFER_BKGR_BUF_TYPE_NAME, H5D_XFER_BKGR_BUF_TYPE_SIZE, &H5D_def_bkgr_buf_type_g,
+ NULL, NULL, NULL, H5D_XFER_BKGR_BUF_TYPE_ENC, H5D_XFER_BKGR_BUF_TYPE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the B-Tree node splitting ratios property */
+ if(H5P_register_real(pclass, H5D_XFER_BTREE_SPLIT_RATIO_NAME, H5D_XFER_BTREE_SPLIT_RATIO_SIZE, H5D_def_btree_split_ratio_g,
+ NULL, NULL, NULL, H5D_XFER_BTREE_SPLIT_RATIO_ENC, H5D_XFER_BTREE_SPLIT_RATIO_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the vlen allocation function property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_VLEN_ALLOC_NAME, H5D_XFER_VLEN_ALLOC_SIZE, &H5D_def_vlen_alloc_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the vlen allocation information property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_VLEN_ALLOC_INFO_NAME, H5D_XFER_VLEN_ALLOC_INFO_SIZE, &H5D_def_vlen_alloc_info_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the vlen free function property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_VLEN_FREE_NAME, H5D_XFER_VLEN_FREE_SIZE, &H5D_def_vlen_free_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the vlen free information property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_VLEN_FREE_INFO_NAME, H5D_XFER_VLEN_FREE_INFO_SIZE, &H5D_def_vlen_free_info_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the vector size property */
+ if(H5P_register_real(pclass, H5D_XFER_HYPER_VECTOR_SIZE_NAME, H5D_XFER_HYPER_VECTOR_SIZE_SIZE, &H5D_def_hyp_vec_size_g,
+ NULL, NULL, NULL, H5D_XFER_HYPER_VECTOR_SIZE_ENC, H5D_XFER_HYPER_VECTOR_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the I/O transfer mode properties */
+ if(H5P_register_real(pclass, H5D_XFER_IO_XFER_MODE_NAME, H5D_XFER_IO_XFER_MODE_SIZE, &H5D_def_io_xfer_mode_g,
+ NULL, NULL, NULL, H5D_XFER_IO_XFER_MODE_ENC, H5D_XFER_IO_XFER_MODE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, H5D_XFER_MPIO_COLLECTIVE_OPT_SIZE, &H5D_def_mpio_collective_opt_mode_g,
+ NULL, NULL, NULL, H5D_XFER_MPIO_COLLECTIVE_OPT_ENC, H5D_XFER_MPIO_COLLECTIVE_OPT_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME, H5D_XFER_MPIO_CHUNK_OPT_HARD_SIZE, &H5D_def_mpio_chunk_opt_mode_g,
+ NULL, NULL, NULL, H5D_XFER_MPIO_CHUNK_OPT_HARD_ENC, H5D_XFER_MPIO_CHUNK_OPT_HARD_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME, H5D_XFER_MPIO_CHUNK_OPT_NUM_SIZE, &H5D_def_mpio_chunk_opt_num_g,
+ NULL, NULL, NULL, H5D_XFER_MPIO_CHUNK_OPT_NUM_ENC, H5D_XFER_MPIO_CHUNK_OPT_NUM_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5D_XFER_MPIO_CHUNK_OPT_RATIO_NAME, H5D_XFER_MPIO_CHUNK_OPT_RATIO_SIZE, &H5D_def_mpio_chunk_opt_ratio_g,
+ NULL, NULL, NULL, H5D_XFER_MPIO_CHUNK_OPT_RATIO_ENC, H5D_XFER_MPIO_CHUNK_OPT_RATIO_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the chunk optimization mode property. */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_SIZE, &H5D_def_mpio_actual_chunk_opt_mode_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the actual I/O mode property. */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_MPIO_ACTUAL_IO_MODE_NAME, H5D_MPIO_ACTUAL_IO_MODE_SIZE, &H5D_def_mpio_actual_io_mode_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the local cause of broken collective I/O */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_MPIO_LOCAL_NO_COLLECTIVE_CAUSE_NAME, H5D_MPIO_NO_COLLECTIVE_CAUSE_SIZE, &H5D_def_mpio_no_collective_cause_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the global cause of broken collective I/O */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_MPIO_GLOBAL_NO_COLLECTIVE_CAUSE_NAME, H5D_MPIO_NO_COLLECTIVE_CAUSE_SIZE, &H5D_def_mpio_no_collective_cause_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Register the MPI memory type property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5FD_MPI_XFER_MEM_MPI_TYPE_NAME, H5FD_MPI_XFER_MEM_MPI_TYPE_SIZE, &H5D_def_btype_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the MPI file type property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5FD_MPI_XFER_FILE_MPI_TYPE_NAME, H5FD_MPI_XFER_FILE_MPI_TYPE_SIZE, &H5D_def_ftype_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the metadata collective read flag */
+ if(H5P_register_real(pclass, H5_COLL_MD_READ_FLAG_NAME, H5D_XFER_COLL_MD_READ_SIZE,
+ &H5D_def_coll_md_read_g,
+ NULL, NULL, NULL, H5D_XFER_COLL_MD_READ_ENC, H5D_XFER_COLL_MD_READ_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Register the EDC property */
+ if(H5P_register_real(pclass, H5D_XFER_EDC_NAME, H5D_XFER_EDC_SIZE, &H5D_def_enable_edc_g,
+ NULL, NULL, NULL, H5D_XFER_EDC_ENC, H5D_XFER_EDC_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the filter callback property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_FILTER_CB_NAME, H5D_XFER_FILTER_CB_SIZE, &H5D_def_filter_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the type conversion callback property */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_CONV_CB_NAME, H5D_XFER_CONV_CB_SIZE, &H5D_def_conv_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the data transform property */
+ if(H5P_register_real(pclass, H5D_XFER_XFORM_NAME, H5D_XFER_XFORM_SIZE, &H5D_def_xfer_xform_g,
+ NULL, H5D_XFER_XFORM_SET, H5D_XFER_XFORM_GET, H5D_XFER_XFORM_ENC, H5D_XFER_XFORM_DEC,
+ H5D_XFER_XFORM_DEL, H5D_XFER_XFORM_COPY, H5D_XFER_XFORM_CMP, H5D_XFER_XFORM_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the property of flag for direct chunk write */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_NAME, H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_SIZE, &H5D_def_direct_chunk_flag_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the property of filter for direct chunk write */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_NAME, H5D_XFER_DIRECT_CHUNK_WRITE_FILTERS_SIZE, &H5D_def_direct_chunk_filters_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the property of offset for direct chunk write */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_NAME, H5D_XFER_DIRECT_CHUNK_WRITE_OFFSET_SIZE, &H5D_def_direct_chunk_offset_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the property of datasize for direct chunk write */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_NAME, H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_SIZE, &H5D_def_direct_chunk_datasize_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the ring property (private) */
+ if(H5P_register_real(pclass, H5AC_RING_NAME, H5AC_XFER_RING_SIZE, &H5D_ring_g,
+ NULL, NULL, NULL, H5AC_XFER_RING_ENC, H5AC_XFER_RING_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+#ifdef H5_DEBUG_BUILD
+ /* Register the dxpl IO type property */
+ if(H5P_register_real(pclass, H5FD_DXPL_TYPE_NAME, H5FD_DXPL_TYPE_SIZE, &H5D_dxpl_type_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+#endif /* H5_DEBUG_BUILD */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_bkgr_buf_type_enc
+ *
+ * Purpose: Callback routine which is called whenever the background
+ * buffer type property in the dataset transfer property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_bkgr_buf_type_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5T_bkg_t *bkgr_buf_type = (const H5T_bkg_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(bkgr_buf_type);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode background buffer type */
+ *(*pp)++ = (uint8_t)*bkgr_buf_type;
+
+ /* Size of background buffer type */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_bkgr_buf_type_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_bkgr_buf_type_dec
+ *
+ * Purpose: Callback routine which is called whenever the background
+ * buffer type property in the dataset transfer property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_bkgr_buf_type_dec(const void **_pp, void *_value)
+{
+ H5T_bkg_t *bkgr_buf_type = (H5T_bkg_t *)_value; /* Background buffer type */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(bkgr_buf_type);
+
+ /* Decode background buffer type */
+ *bkgr_buf_type = (H5T_bkg_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_bkgr_buf_type_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_btree_split_ratio_enc
+ *
+ * Purpose: Callback routine which is called whenever the B-tree split
+ * ratio property in the dataset transfer property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_btree_split_ratio_enc(const void *value, void **_pp, size_t *size)
+{
+ const double *btree_split_ratio = (const double *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(btree_split_ratio);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the size of a double*/
+ *(*pp)++ = (uint8_t)sizeof(double);
+
+ /* Encode the left split value */
+ H5_ENCODE_DOUBLE(*pp, *(const double *)btree_split_ratio)
+ btree_split_ratio++;
+
+ /* Encode the middle split value */
+ H5_ENCODE_DOUBLE(*pp, *(const double *)btree_split_ratio)
+ btree_split_ratio++;
+
+ /* Encode the right split value */
+ H5_ENCODE_DOUBLE(*pp, *(const double *)btree_split_ratio)
+ } /* end if */
+
+ /* Size of B-tree split ratio values */
+ *size += 1 + (3 * sizeof(double));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_btree_split_ratio_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_btree_split_ratio_dec
+ *
+ * Purpose: Callback routine which is called whenever the B-tree split
+ * ratio property in the dataset transfer property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_btree_split_ratio_dec(const void **_pp, void *_value)
+{
+ double *btree_split_ratio = (double *)_value; /* B-tree split ratio */
+ unsigned enc_size; /* Size of encoded property */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(btree_split_ratio);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(double))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "double value can't be decoded")
+
+ /* Decode the left, middle & left B-tree split ratios */
+ H5_DECODE_DOUBLE(*pp, btree_split_ratio[0])
+ H5_DECODE_DOUBLE(*pp, btree_split_ratio[1])
+ H5_DECODE_DOUBLE(*pp, btree_split_ratio[2])
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_btree_split_ratio_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_set
+ *
+ * Purpose: Copies a data transform property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of data transform */
+ if(H5Z_xform_copy((H5Z_data_xform_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "error copying the data transform info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_get
+ *
+ * Purpose: Copies a data transform property when it's retrieved for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of data transform */
+ if(H5Z_xform_copy((H5Z_data_xform_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "error copying the data transform info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_enc
+ *
+ * Purpose: Callback routine which is called whenever the data transform
+ * property in the dataset transfer property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 6, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5Z_data_xform_t *data_xform_prop = *(const H5Z_data_xform_t * const *)value; /* Create local alias for values */
+ const char *pexp = NULL; /* Pointer to transform expression */
+ size_t len = 0; /* Length of transform expression */
+ uint8_t **pp = (uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(size);
+
+ /* Check for data transform set */
+ if(NULL != data_xform_prop) {
+ /* Get the transform expression */
+ if(NULL == (pexp = H5Z_xform_extract_xform_str(data_xform_prop)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "failed to retrieve transform expression")
+
+ /* Get the transform string expression size */
+ len = HDstrlen(pexp) + 1;
+ } /* end if */
+
+ if(NULL != *pp) {
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ /* encode the length of the prefix */
+ enc_value = (uint64_t)len;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ if(NULL != data_xform_prop) {
+ /* Sanity check */
+ HDassert(pexp);
+
+ /* Copy the expression into the buffer */
+ HDmemcpy(*pp, (const uint8_t *)pexp, len);
+ *pp += len;
+ *pp[0] = '\0';
+ } /* end if */
+ } /* end if */
+
+ /* Size of encoded data transform */
+ *size += (1 + H5VM_limit_enc_size((uint64_t)len));
+ if(NULL != pexp)
+ *size += len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_dec
+ *
+ * Purpose: Callback routine which is called whenever the data transform
+ * property in the dataset transfer property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 6, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_dec(const void **_pp, void *_value)
+{
+ H5Z_data_xform_t **data_xform_prop = (H5Z_data_xform_t **)_value; /* New data xform property */
+ size_t len; /* Length of encoded string */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size;
+ uint64_t enc_value;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(data_xform_prop);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Decode the length of xform expression */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ len = (size_t)enc_value;
+
+ if(0 != len) {
+ if(NULL == (*data_xform_prop = H5Z_xform_create((const char *)*pp)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create data transform info")
+ *pp += len;
+ } /* end if */
+ else
+ *data_xform_prop = H5D_XFER_XFORM_DEF;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_del
+ *
+ * Purpose: Frees memory allocated by H5P_dxfr_xform_set
+ *
+ * Return: Success: SUCCEED, Failure: FAIL
+ *
+ * Programmer: Leon Arber larber@uiuc.edu
+ *
+ * Date: April 9, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(value);
+
+ if(H5Z_xform_destroy(*(H5Z_data_xform_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "error closing the parse tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_copy
+ *
+ * Purpose: Creates a copy of the user's data transform string and its
+ * associated parse tree.
+ *
+ * Return: Success: SUCCEED, Failure: FAIL
+ *
+ * Programmer: Leon Arber larber@uiuc.edu
+ *
+ * Date: April 9, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of data transform */
+ if(H5Z_xform_copy((H5Z_data_xform_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "error copying the data transform info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_cmp
+ *
+ * Purpose: Compare two data transforms.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if VALUE2 is
+ * greater than VALUE1 and zero if VALUE1 and VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__dxfr_xform_cmp(const void *_xform1, const void *_xform2, size_t H5_ATTR_UNUSED size)
+{
+ const H5Z_data_xform_t * const *xform1 = (const H5Z_data_xform_t * const *)_xform1; /* Create local aliases for values */
+ const H5Z_data_xform_t * const *xform2 = (const H5Z_data_xform_t * const *)_xform2; /* Create local aliases for values */
+ const char *pexp1, *pexp2; /* Pointers to transform expressions */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(xform1);
+ HDassert(xform2);
+ HDassert(size == sizeof(H5Z_data_xform_t *));
+
+ /* Check for a property being set */
+ if(*xform1 == NULL && *xform2 != NULL) HGOTO_DONE(-1);
+ if(*xform1 != NULL && *xform2 == NULL) HGOTO_DONE(1);
+
+ if(*xform1) {
+ HDassert(*xform2);
+
+ /* Get the transform expressions */
+ pexp1 = H5Z_xform_extract_xform_str(*xform1);
+ pexp2 = H5Z_xform_extract_xform_str(*xform2);
+
+ /* Check for property expressions */
+ if(pexp1 == NULL && pexp2 != NULL) HGOTO_DONE(-1);
+ if(pexp1 != NULL && pexp2 == NULL) HGOTO_DONE(1);
+
+ if(pexp1) {
+ HDassert(pexp2);
+ ret_value = HDstrcmp(pexp1, pexp2);
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_xform_close
+ *
+ * Purpose: Frees memory allocated by H5P_dxfr_xform_set
+ *
+ * Return: Success: SUCCEED, Failure: FAIL
+ *
+ * Programmer: Leon Arber larber@uiuc.edu
+ *
+ * Date: April 9, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_xform_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(value);
+
+ if(H5Z_xform_destroy(*(H5Z_data_xform_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "error closing the parse tree")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__dxfr_xform_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_data_transform
+ *
+ * Purpose: Sets data transform expression.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Leon Arber
+ * Monday, March 07, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_data_transform(hid_t plist_id, const char *expression)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5Z_data_xform_t *data_xform_prop = NULL; /* New data xform property */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", plist_id, expression);
+
+ /* Check arguments */
+ if(expression == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "expression cannot be NULL")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* See if a data transform is already set, and free it if it is */
+ if(H5P_peek(plist, H5D_XFER_XFORM_NAME, &data_xform_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting data transform expression")
+
+ /* Destroy previous data transform property */
+ if(H5Z_xform_destroy(data_xform_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CLOSEERROR, FAIL, "unable to release data transform expression")
+
+ /* Create data transform info from expression */
+ if(NULL == (data_xform_prop = H5Z_xform_create(expression)))
+ HGOTO_ERROR(H5E_PLINE, H5E_NOSPACE, FAIL, "unable to create data transform info")
+
+ /* Update property list (takes ownership of transform) */
+ if(H5P_poke(plist, H5D_XFER_XFORM_NAME, &data_xform_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "Error setting data transform expression")
+
+done:
+ if(ret_value < 0)
+ if(data_xform_prop && H5Z_xform_destroy(data_xform_prop) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "unable to release data transform expression")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_data_transform() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_data_transform
+ *
+ * Purpose: Gets data transform expression.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Comments:
+ * If `expression' is non-NULL then write up to `size' bytes into that
+ * buffer and always return the length of the transform name.
+ * Otherwise `size' is ignored and the function does not store the expression,
+ * just returning the number of characters required to store the expression.
+ * If an error occurs then the buffer pointed to by `expression' (NULL or non-NULL)
+ * is unchanged and the function returns a negative value.
+ * If a zero is returned for the name's length, then there is no name
+ * associated with the ID.
+ *
+ * Programmer: Leon Arber
+ * August 27, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Pget_data_transform(hid_t plist_id, char *expression /*out*/, size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5Z_data_xform_t *data_xform_prop = NULL; /* New data xform property */
+ size_t len;
+ const char* pexp;
+ ssize_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "ixz", plist_id, expression, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_peek(plist, H5D_XFER_XFORM_NAME, &data_xform_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting data transform expression")
+
+ if(NULL == data_xform_prop)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "data transform has not been set")
+
+ /* Get the data transform string */
+ if(NULL == (pexp = H5Z_xform_extract_xform_str(data_xform_prop)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "failed to retrieve transform expression")
+
+ /* Copy into application buffer */
+ len = HDstrlen(pexp);
+ if(expression) {
+ HDstrncpy(expression, pexp, MIN(len + 1, size));
+ if(len >= size)
+ expression[size - 1] = '\0';
+ } /* end if */
+
+ ret_value = (ssize_t)len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_data_transform() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_buffer
+ *
+ * Purpose: Given a dataset transfer property list, set the maximum size
+ * for the type conversion buffer and background buffer and
+ * optionally supply pointers to application-allocated buffers.
+ * If the buffer size is smaller than the entire amount of data
+ * being transfered between application and file, and a type
+ * conversion buffer or background buffer is required then
+ * strip mining will be used.
+ *
+ * If TCONV and/or BKG are null pointers then buffers will be
+ * allocated and freed during the data transfer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_buffer(hid_t plist_id, size_t size, void *tconv, void *bkg)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iz*x*x", plist_id, size, tconv, bkg);
+
+ /* Check arguments */
+ if(size == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buffer size must not be zero")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_XFER_MAX_TEMP_BUF_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "Can't set transfer buffer size")
+ if(H5P_set(plist, H5D_XFER_TCONV_BUF_NAME, &tconv) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "Can't set transfer type conversion buffer")
+ if(H5P_set(plist, H5D_XFER_BKGR_BUF_NAME, &bkg) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "Can't set background type conversion buffer")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_buffer() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_buffer
+ *
+ * Purpose: Reads values previously set with H5Pset_buffer().
+ *
+ * Return: Success: Buffer size.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Monday, March 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5Pget_buffer(hid_t plist_id, void **tconv/*out*/, void **bkg/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ size_t size; /* Type conversion buffer size */
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE3("z", "ixx", plist_id, tconv, bkg);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, 0, "can't find object for ID")
+
+ /* Return values */
+ if(tconv)
+ if(H5P_get(plist, H5D_XFER_TCONV_BUF_NAME, tconv) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "Can't get transfer type conversion buffer")
+ if(bkg)
+ if(H5P_get(plist, H5D_XFER_BKGR_BUF_NAME, bkg) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "Can't get background type conversion buffer")
+
+ /* Get the size */
+ if(H5P_get(plist, H5D_XFER_MAX_TEMP_BUF_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, 0, "Can't set transfer buffer size")
+
+ /* Set the return value */
+ ret_value = size;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_buffer() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_preserve
+ *
+ * Purpose: When reading or writing compound data types and the
+ * destination is partially initialized and the read/write is
+ * intended to initialize the other members, one must set this
+ * property to TRUE. Otherwise the I/O pipeline treats the
+ * destination datapoints as completely uninitialized.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 17, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_preserve(hid_t plist_id, hbool_t status)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5T_bkg_t need_bkg; /* Value for background buffer type */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", plist_id, status);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ need_bkg = status ? H5T_BKG_YES : H5T_BKG_NO;
+ if(H5P_set(plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_preserve() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_preserve
+ *
+ * Purpose: The inverse of H5Pset_preserve()
+ *
+ * Return: Success: TRUE or FALSE
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, March 17, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Pget_preserve(hid_t plist_id)
+{
+ H5T_bkg_t need_bkg; /* Background value */
+ H5P_genplist_t *plist; /* Property list pointer */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_get(plist, H5D_XFER_BKGR_BUF_TYPE_NAME, &need_bkg) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+ /* Set return value */
+ ret_value = need_bkg ? TRUE : FALSE;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_preserve() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_edc_check
+ *
+ * Purpose: Enable or disable error-detecting for a dataset reading
+ * process. This error-detecting algorithm is whichever
+ * user chooses earlier. This function cannot control
+ * writing process.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Jan 3, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_edc_check(hid_t plist_id, H5Z_EDC_t check)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iZe", plist_id, check);
+
+ /* Check argument */
+ if(check != H5Z_ENABLE_EDC && check != H5Z_DISABLE_EDC)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid value")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_XFER_EDC_NAME, &check) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_edc_check() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_edc_check
+ *
+ * Purpose: Enable or disable error-detecting for a dataset reading
+ * process. This error-detecting algorithm is whichever
+ * user chooses earlier. This function cannot control
+ * writing process.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Jan 3, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_EDC_t
+H5Pget_edc_check(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5Z_EDC_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5Z_ERROR_EDC)
+ H5TRACE1("Ze", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5Z_ERROR_EDC, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_get(plist, H5D_XFER_EDC_NAME, &ret_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, H5Z_ERROR_EDC, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_edc_check() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_filter_callback
+ *
+ * Purpose: Sets user's callback function for dataset transfer property
+ * list. This callback function defines what user wants to do
+ * if certain filter fails.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Jan 14, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_filter_callback(hid_t plist_id, H5Z_filter_func_t func, void *op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+ H5Z_cb_t cb_struct;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", plist_id, func, op_data);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ cb_struct.func = func;
+ cb_struct.op_data = op_data;
+
+ if (H5P_set(plist,H5D_XFER_FILTER_CB_NAME,&cb_struct)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_type_conv_cb
+ *
+ * Purpose: Sets user's callback function for dataset transfer property
+ * list. This callback function defines what user wants to do
+ * if there's exception during datatype conversion.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * April 15, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_type_conv_cb(hid_t plist_id, H5T_conv_except_func_t op, void *operate_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+ H5T_conv_cb_t cb_struct;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", plist_id, op, operate_data);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ cb_struct.func = op;
+ cb_struct.user_data = operate_data;
+
+ if (H5P_set(plist,H5D_XFER_CONV_CB_NAME,&cb_struct)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_type_conv_cb
+ *
+ * Purpose: Gets callback function for dataset transfer property
+ * list. This callback function defines what user wants to do
+ * if there's exception during datatype conversion.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * April 15, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_type_conv_cb(hid_t plist_id, H5T_conv_except_func_t *op, void **operate_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5T_conv_cb_t cb_struct;
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", plist_id, op, operate_data);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get property */
+ if (H5P_get(plist,H5D_XFER_CONV_CB_NAME,&cb_struct)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+ /* Assign return value */
+ *op = cb_struct.func;
+ *operate_data = cb_struct.user_data;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_btree_ratios
+ *
+ * Purpose: Queries B-tree split ratios. See H5Pset_btree_ratios().
+ *
+ * Return: Success: Non-negative with split ratios returned through
+ * the non-null arguments.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, September 28, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_btree_ratios(hid_t plist_id, double *left/*out*/, double *middle/*out*/,
+ double *right/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ double btree_split_ratio[3]; /* B-tree node split ratios */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "ixxx", plist_id, left, middle, right);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the split ratios */
+ if(H5P_get(plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &btree_split_ratio) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+ /* Get values */
+ if(left)
+ *left = btree_split_ratio[0];
+ if(middle)
+ *middle = btree_split_ratio[1];
+ if(right)
+ *right = btree_split_ratio[2];
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_btree_ratios() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_btree_ratios
+ *
+ * Purpose: Sets B-tree split ratios for a dataset transfer property
+ * list. The split ratios determine what percent of children go
+ * in the first node when a node splits. The LEFT ratio is
+ * used when the splitting node is the left-most node at its
+ * level in the tree; the RIGHT ratio is when the splitting node
+ * is the right-most node at its level; and the MIDDLE ratio for
+ * all other cases. A node which is the only node at its level
+ * in the tree uses the RIGHT ratio when it splits. All ratios
+ * are real numbers between 0 and 1, inclusive.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, September 28, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_btree_ratios(hid_t plist_id, double left, double middle,
+ double right)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ double split_ratio[3]; /* B-tree node split ratios */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iddd", plist_id, left, middle, right);
+
+ /* Check arguments */
+ if(left < (double)0.0f || left > (double)1.0f
+ || middle < (double)0.0f || middle > (double)1.0f
+ || right < (double)0.0f || right > (double)1.0f)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "split ratio must satisfy 0.0<=X<=1.0")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ split_ratio[0] = left;
+ split_ratio[1] = middle;
+ split_ratio[2] = right;
+
+ /* Set the split ratios */
+ if(H5P_set(plist, H5D_XFER_BTREE_SPLIT_RATIO_NAME, &split_ratio) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_btree_ratios() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_set_vlen_mem_manager
+ *
+ * Purpose: Sets the memory allocate/free pair for VL datatypes. The
+ * allocation routine is called when data is read into a new
+ * array and the free routine is called when H5Dvlen_reclaim is
+ * called. The alloc_info and free_info are user parameters
+ * which are passed to the allocation and freeing functions
+ * respectively. To reset the allocate/free functions to the
+ * default setting of using the system's malloc/free functions,
+ * call this routine with alloc_func and free_func set to NULL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 1, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_set_vlen_mem_manager(H5P_genplist_t *plist, H5MM_allocate_t alloc_func,
+ void *alloc_info, H5MM_free_t free_func, void *free_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(plist);
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_XFER_VLEN_ALLOC_NAME, &alloc_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+ if(H5P_set(plist, H5D_XFER_VLEN_ALLOC_INFO_NAME, &alloc_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+ if(H5P_set(plist, H5D_XFER_VLEN_FREE_NAME, &free_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+ if(H5P_set(plist, H5D_XFER_VLEN_FREE_INFO_NAME, &free_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_set_vlen_mem_manager() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_vlen_mem_manager
+ *
+ * Purpose: Sets the memory allocate/free pair for VL datatypes. The
+ * allocation routine is called when data is read into a new
+ * array and the free routine is called when H5Dvlen_reclaim is
+ * called. The alloc_info and free_info are user parameters
+ * which are passed to the allocation and freeing functions
+ * respectively. To reset the allocate/free functions to the
+ * default setting of using the system's malloc/free functions,
+ * call this routine with alloc_func and free_func set to NULL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 1, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_vlen_mem_manager(hid_t plist_id, H5MM_allocate_t alloc_func,
+ void *alloc_info, H5MM_free_t free_func, void *free_info)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "ix*xx*x", plist_id, alloc_func, alloc_info, free_func,
+ free_info);
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Update property list */
+ if(H5P_set_vlen_mem_manager(plist, alloc_func, alloc_info, free_func, free_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set values")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_vlen_mem_manager() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_vlen_mem_manager
+ *
+ * Purpose: The inverse of H5Pset_vlen_mem_manager()
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 1, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_vlen_mem_manager(hid_t plist_id, H5MM_allocate_t *alloc_func/*out*/,
+ void **alloc_info/*out*/, H5MM_free_t *free_func/*out*/, void **free_info/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "ixxxx", plist_id, alloc_func, alloc_info, free_func, free_info);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(alloc_func)
+ if(H5P_get(plist, H5D_XFER_VLEN_ALLOC_NAME, alloc_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if(alloc_info)
+ if(H5P_get(plist, H5D_XFER_VLEN_ALLOC_INFO_NAME, alloc_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if(free_func)
+ if(H5P_get(plist, H5D_XFER_VLEN_FREE_NAME, free_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if(free_info)
+ if(H5P_get(plist, H5D_XFER_VLEN_FREE_INFO_NAME, free_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_vlen_mem_manager() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_hyper_vector_size
+ *
+ * Purpose: Given a dataset transfer property list, set the number of
+ * "I/O vectors" (offset and length pairs) which are to be
+ * accumulated in memory before being issued to the lower levels
+ * of the library for reading or writing the actual data.
+ * Increasing the number should give better performance, but use
+ * more memory during hyperslab I/O. The vector size must be
+ * greater than 1.
+ *
+ * The default is to use 1024 vectors for I/O during hyperslab
+ * reading/writing.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 9, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_hyper_vector_size(hid_t plist_id, size_t vector_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", plist_id, vector_size);
+
+ /* Check arguments */
+ if(vector_size < 1)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "vector size too small")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ if(H5P_set(plist, H5D_XFER_HYPER_VECTOR_SIZE_NAME, &vector_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_hyper_vector_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_hyper_vector_size
+ *
+ * Purpose: Reads values previously set with H5Pset_hyper_vector_size().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 9, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_hyper_vector_size(hid_t plist_id, size_t *vector_size/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, vector_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Return values */
+ if(vector_size)
+ if(H5P_get(plist, H5D_XFER_HYPER_VECTOR_SIZE_NAME, vector_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_hyper_vector_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_io_xfer_mode_enc
+ *
+ * Purpose: Callback routine which is called whenever the I/O transfer
+ * mode property in the dataset transfer property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_io_xfer_mode_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5FD_mpio_xfer_t *xfer_mode = (const H5FD_mpio_xfer_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(xfer_mode);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode I/O transfer mode */
+ *(*pp)++ = (uint8_t)*xfer_mode;
+
+ /* Size of I/O transfer mode */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_io_xfer_mode_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_io_xfer_mode_dec
+ *
+ * Purpose: Callback routine which is called whenever the I/O transfer
+ * mode property in the dataset transfer property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_io_xfer_mode_dec(const void **_pp, void *_value)
+{
+ H5FD_mpio_xfer_t *xfer_mode = (H5FD_mpio_xfer_t *)_value; /* I/O transfer mode */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(xfer_mode);
+
+ /* Decode I/O transfer mode */
+ *xfer_mode = (H5FD_mpio_xfer_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_io_xfer_mode_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_mpio_collective_opt_enc
+ *
+ * Purpose: Callback routine which is called whenever the MPI-I/O
+ * collective optimization property in the dataset transfer
+ * property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_mpio_collective_opt_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5FD_mpio_collective_opt_t *coll_opt = (const H5FD_mpio_collective_opt_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(coll_opt);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode MPI-I/O collective optimization property */
+ *(*pp)++ = (uint8_t)*coll_opt;
+
+ /* Size of MPI-I/O collective optimization property */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_mpio_collective_opt_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_mpio_collective_opt_dec
+ *
+ * Purpose: Callback routine which is called whenever the MPI-I/O
+ * collective optimization property in the dataset transfer
+ * property list is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_mpio_collective_opt_dec(const void **_pp, void *_value)
+{
+ H5FD_mpio_collective_opt_t *coll_opt = (H5FD_mpio_collective_opt_t *)_value; /* MPI-I/O collective optimization mode */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(coll_opt);
+
+ /* Decode MPI-I/O collective optimization mode */
+ *coll_opt = (H5FD_mpio_collective_opt_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_mpio_collective_opt_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_mpio_chunk_opt_hard_enc
+ *
+ * Purpose: Callback routine which is called whenever the MPI-I/O
+ * chunk optimization property in the dataset transfer
+ * property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_mpio_chunk_opt_hard_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5FD_mpio_chunk_opt_t *chunk_opt = (const H5FD_mpio_chunk_opt_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(chunk_opt);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode MPI-I/O chunk optimization property */
+ *(*pp)++ = (uint8_t)*chunk_opt;
+
+ /* Size of MPI-I/O chunk optimization property */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_mpio_chunk_opt_hard_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_mpio_chunk_opt_hard_enc
+ *
+ * Purpose: Callback routine which is called whenever the MPI-I/O
+ * chunk collective optimization property in the dataset transfer
+ * property list is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_mpio_chunk_opt_hard_dec(const void **_pp, void *_value)
+{
+ H5FD_mpio_chunk_opt_t *chunk_opt = (H5FD_mpio_chunk_opt_t *)_value; /* MPI-I/O chunk optimization mode */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(chunk_opt);
+
+ /* Decode MPI-I/O chunk optimization mode */
+ *chunk_opt = (H5FD_mpio_chunk_opt_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_mpio_chunk_opt_hard_dec() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mpio_actual_chunk_opt_mode
+ *
+ * Purpose: Retrieves the chunked io optimization scheme that library chose
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Wednesday, May 4, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mpio_actual_chunk_opt_mode(hid_t plist_id, H5D_mpio_actual_chunk_opt_mode_t *actual_chunk_opt_mode)
+{
+ H5P_genplist_t *plist;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Do", plist_id, actual_chunk_opt_mode);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Return values */
+ if(actual_chunk_opt_mode)
+ if(H5P_get(plist, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, actual_chunk_opt_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_mpio_actual_chunk_opt_mode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mpio_actual_io_mode
+ *
+ * Purpose: Retrieves the type of I/O actually preformed when collective I/O
+ * is requested.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Wednesday, May 4, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mpio_actual_io_mode(hid_t plist_id, H5D_mpio_actual_io_mode_t *actual_io_mode)
+{
+ H5P_genplist_t *plist;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Di", plist_id, actual_io_mode);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Return values */
+ if(actual_io_mode)
+ if(H5P_get(plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, actual_io_mode) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_mpio_actual_io_mode() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mpio_no_collective_cause
+ *
+ * Purpose: Retrieves cause for the broke collective I/O
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jonathan Kim
+ * Aug 3, 2012
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mpio_no_collective_cause(hid_t plist_id, uint32_t *local_no_collective_cause, uint32_t *global_no_collective_cause)
+{
+ H5P_genplist_t *plist;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*Iu*Iu", plist_id, local_no_collective_cause,
+ global_no_collective_cause);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Return values */
+ if(local_no_collective_cause)
+ if(H5P_get(plist, H5D_MPIO_LOCAL_NO_COLLECTIVE_CAUSE_NAME, local_no_collective_cause) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get local value")
+ if(global_no_collective_cause)
+ if(H5P_get(plist, H5D_MPIO_GLOBAL_NO_COLLECTIVE_CAUSE_NAME, global_no_collective_cause) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get global value")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_mpio_no_collective_cause() */
+
+
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_edc_enc
+ *
+ * Purpose: Callback routine which is called whenever the error detect
+ * property in the dataset transfer property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_edc_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5Z_EDC_t *check = (const H5Z_EDC_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(check);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode EDC property */
+ *(*pp)++ = (uint8_t)*check;
+
+ /* Size of EDC property */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_edc_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__dxfr_edc_dec
+ *
+ * Purpose: Callback routine which is called whenever the error detect
+ * property in the dataset transfer property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 3, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__dxfr_edc_dec(const void **_pp, void *_value)
+{
+ H5Z_EDC_t *check = (H5Z_EDC_t *)_value; /* EDC property */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(check);
+
+ /* Decode EDC property */
+ *check = (H5Z_EDC_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__dxfr_edc_dec() */
+
diff --git a/src/H5Pencdec.c b/src/H5Pencdec.c
new file mode 100644
index 0000000..73c48d7
--- /dev/null
+++ b/src/H5Pencdec.c
@@ -0,0 +1,789 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Generic Property Functions
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppkg.h" /* Property lists */
+#include "H5VMprivate.h" /* Vector functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Version # of encoded property lists */
+#define H5P_ENCODE_VERS 0
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for iterator when encoding a property list */
+typedef struct {
+ hbool_t encode; /* Whether the property list should be encoded */
+ size_t *enc_size_ptr; /* Pointer to size of encoded buffer */
+ void **pp; /* Pointer to encoding buffer pointer */
+} H5P_enc_iter_ud_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_size_t
+ *
+ * Purpose: Generic encoding callback routine for 'size_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 29, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_size_t(const void *value, void **_pp, size_t *size)
+{
+ uint64_t enc_value = (uint64_t)*(const size_t *)value; /* Property value to encode */
+ uint8_t **pp = (uint8_t **)_pp;
+ unsigned enc_size = H5VM_limit_enc_size(enc_value); /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(enc_size < 256);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)enc_size;
+
+ /* Encode the value */
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += (1 + enc_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_size_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_hsize_t
+ *
+ * Purpose: Generic encoding callback routine for 'hsize_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 07, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_hsize_t(const void *value, void **_pp, size_t *size)
+{
+ uint64_t enc_value = (uint64_t)*(const hsize_t *)value; /* Property value to encode */
+ unsigned enc_size = H5VM_limit_enc_size(enc_value); /* Size of encoded property */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDcompile_assert(sizeof(hsize_t) <= sizeof(uint64_t));
+ HDassert(enc_size < 256);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ *(*pp)++ = (uint8_t)enc_size;
+
+ /* Encode the value */
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += (1 + enc_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_hsize_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_unsigned
+ *
+ * Purpose: Generic encoding callback routine for 'unsigned' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 29, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_unsigned(const void *value, void **_pp, size_t *size)
+{
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(value);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* Encode the value */
+ H5_ENCODE_UNSIGNED(*pp, *(const unsigned *)value)
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += (1 + sizeof(unsigned));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_unsigned() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_uint8_t
+ *
+ * Purpose: Generic encoding callback routine for 'uint8_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 07, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_uint8_t(const void *value, void **_pp, size_t *size)
+{
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(value);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the value */
+ *(*pp)++ = *(const uint8_t *)value;
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_uint8_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_hbool_t
+ *
+ * Purpose: Generic encoding callback routine for 'hbool_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_hbool_t(const void *value, void **_pp, size_t *size)
+{
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(value);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode the value */
+ *(*pp)++ = (uint8_t)*(const hbool_t *)value;
+
+ /* Set size needed for encoding */
+ *size += 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_hbool_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_double
+ *
+ * Purpose: Generic encoding callback routine for 'double' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 29, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_double(const void *value, void **_pp, size_t *size)
+{
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(value);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the size */
+ *(*pp)++ = (uint8_t)sizeof(double);
+
+ /* Encode the value */
+ H5_ENCODE_DOUBLE(*pp, *(const double *)value)
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += (1 + sizeof(double));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_double() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__encode_cb
+ PURPOSE
+ Internal callback routine when iterating over properties while encoding
+ a property list.
+ USAGE
+ int H5P__encode_cb(item, key, udata)
+ H5P_genprop_t *prop; IN: Pointer to the property
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: H5_ITER_CONT
+ Fail: H5_ITER_ERROR
+ DESCRIPTION
+ This routine encodes a property in a property list
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__encode_cb(H5P_genprop_t *prop, void *_udata)
+{
+ H5P_enc_iter_ud_t *udata = (H5P_enc_iter_ud_t *)_udata; /* Pointer to user data */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(prop);
+ HDassert(udata);
+
+ /* Check if this property can be encoded */
+ if(prop->encode) {
+ size_t prop_name_len; /* Length of property's name */
+ size_t prop_value_len; /* Encoded size of property's value */
+
+ /* Encode (or not, if the 'encode' flag is off) the property's name */
+ prop_name_len = HDstrlen(prop->name) + 1;
+ if(udata->encode) {
+ HDstrncpy((char *)*(udata->pp), prop->name, prop_name_len);
+ *(uint8_t **)(udata->pp) += prop_name_len;
+ } /* end if */
+ *(udata->enc_size_ptr) += prop_name_len;
+
+ /* Encode (or not, if *(udata->pp) is NULL) the property value */
+ prop_value_len = 0;
+ if((prop->encode)(prop->value, udata->pp, &prop_value_len) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, H5_ITER_ERROR, "property encoding routine failed")
+ *(udata->enc_size_ptr) += prop_value_len;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__encode_cb() */
+
+
+/*-------------------------------------------------------------------------
+ NAME
+ H5P__encode
+ PURPOSE
+ Internal routine to encode a property list into a binary buffer.
+ USAGE
+ herr_t H5P__encode(plist, enc_all_prop, buf, nalloc)
+ const H5P_genplist_t *plist; IN: Property list to encode
+ hbool_t enc_all_prop; IN: Whether to encode all properties (TRUE),
+ or just non-default (i.e. changed) properties (FALSE).
+ uint8_t *buf; OUT: buffer to hold the encoded plist
+ size_t *nalloc; IN/OUT: size of buffer needed to encode plist
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Encodes a property list into a binary buffer. If the buffer is NULL, then
+ the call will set the size needed to encode the plist in nalloc. Otherwise
+ the routine will encode the plist in buf.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P__encode(const H5P_genplist_t *plist, hbool_t enc_all_prop, void *buf,
+ size_t *nalloc)
+{
+ H5P_enc_iter_ud_t udata; /* User data for property iteration callback */
+ uint8_t *p = (uint8_t *)buf; /* Temporary pointer to encoding buffer */
+ int idx; /* Index of property to start at */
+ size_t encode_size = 0; /* Size of buffer needed to encode properties */
+ hbool_t encode = TRUE; /* Whether the property list should be encoded */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ if(NULL == nalloc)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad allocation size pointer")
+
+ /* If the buffer is NULL, then this call to H5P__encode will return how much
+ * space is needed to encode a property.
+ */
+ if(NULL == p)
+ encode = FALSE;
+
+ /* Encode property list description info */
+ if(encode) {
+ /* Version # of property list encoding */
+ *p++ = (uint8_t)H5P_ENCODE_VERS;
+
+ /* Type of property list */
+ *p++ = (uint8_t)plist->pclass->type;
+ } /* end if */
+ encode_size += 2;
+
+ /* Initialize user data for iteration callback */
+ udata.encode = encode;
+ udata.enc_size_ptr = &encode_size;
+ udata.pp = (void **)&p;
+
+ /* Iterate over all properties in property list, encoding them */
+ idx = 0;
+ if(H5P_iterate_plist(plist, enc_all_prop, &idx, H5P__encode_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADITER, FAIL, "can't iterate over properties")
+
+ /* Encode a terminator for list of properties */
+ if(encode)
+ *p++ = 0;
+ encode_size++;
+
+ /* Set the size of the buffer needed/used to encode the property list */
+ *nalloc = encode_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_size_t
+ *
+ * Purpose: Generic decoding callback routine for 'size_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 2, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_size_t(const void **_pp, void *_value)
+{
+ size_t *value = (size_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ H5_CHECKED_ASSIGN(*value, size_t, enc_value, uint64_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__decode_size_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_hsize_t
+ *
+ * Purpose: Generic decoding callback routine for 'hsize_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 07, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_hsize_t(const void **_pp, void *_value)
+{
+ hsize_t *value = (hsize_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDcompile_assert(sizeof(hsize_t) <= sizeof(uint64_t));
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ H5_CHECKED_ASSIGN(*value, hsize_t, enc_value, uint64_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__decode_hsize_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_unsigned
+ *
+ * Purpose: Generic decoding callback routine for 'unsigned' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 2, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_unsigned(const void **_pp, void *_value)
+{
+ unsigned *value = (unsigned *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ H5_DECODE_UNSIGNED(*pp, *value)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__decode_unsigned() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_uint8_t
+ *
+ * Purpose: Generic decoding callback routine for 'uint8_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 2, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_uint8_t(const void **_pp, void *_value)
+{
+ uint8_t *value = (uint8_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the value */
+ *value = *(*pp)++;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__decode_uint8_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_hbool_t
+ *
+ * Purpose: Generic decoding callback routine for 'hbool_t' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_hbool_t(const void **_pp, void *_value)
+{
+ hbool_t *value = (hbool_t *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the value */
+ *value = (hbool_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__decode_hbool_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_double
+ *
+ * Purpose: Generic decoding callback routine for 'double' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 2, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_double(const void **_pp, void *_value)
+{
+ double *value = (double *)_value; /* Property value to return */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(value);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(double))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "double value can't be decoded")
+
+ H5_DECODE_DOUBLE(*pp, *value)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__decode_double() */
+
+
+/*-------------------------------------------------------------------------
+ NAME
+ H5P__decode
+ PURPOSE
+ Internal routine to decode a property list from a binary buffer.
+ USAGE
+ H5P_genplist_t *H5P__decode(buf)
+ const void *buf; IN: buffer that holds the encoded plist
+ RETURNS
+ Returns non-negative ID of new property list object on success, negative
+ on failure.
+ DESCRIPTION
+ Decodes a property list from a binary buffer. The contents of the buffer
+ contain the values for the correponding properties of the plist. The decode
+ callback of a certain property decodes its value from the buffer and sets it
+ in the property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Properties in the property list that are not encoded in the serialized
+ form retain their default value.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5P__decode(const void *buf)
+{
+ H5P_genplist_t *plist; /* Property list to decode into */
+ void *value_buf = NULL; /* Pointer to buffer to use when decoding values */
+ const uint8_t *p = (const uint8_t *)buf; /* Current pointer into buffer */
+ H5P_plist_type_t type; /* Type of encoded property list */
+ hid_t plist_id = -1; /* ID of new property list */
+ size_t value_buf_size = 0; /* Size of current value buffer */
+ uint8_t vers; /* Version of encoded property list */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ if(NULL == p)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "decode buffer is NULL")
+
+ /* Get the version number of the encoded property list */
+ vers = (uint8_t)*p++;
+ if((uint8_t)H5P_ENCODE_VERS != vers)
+ HGOTO_ERROR(H5E_PLIST, H5E_VERSION, FAIL, "bad version # of encoded information, expected %u, got %u", (unsigned)H5P_ENCODE_VERS, (unsigned)vers)
+
+ /* Get the type of the property list */
+ type = (H5P_plist_type_t)*p++;
+ if(type <= H5P_TYPE_USER || type > H5P_TYPE_LINK_ACCESS)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADRANGE, FAIL, "bad type of encoded information: %u", (unsigned)type)
+
+ /* Create new property list of the specified type */
+ if((plist_id = H5P__new_plist_of_type(type)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_VERSION, FAIL, "can't create property list of type: %u\n", (unsigned)type);
+
+ /* Get the property list object */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property class")
+
+ /* Loop over encoded properties, deserializing their values */
+ while(p) {
+ H5P_genprop_t *prop; /* Pointer to property with same name */
+ const char *name; /* Pointer to property list name */
+
+ /* Check for end of serialized list of properties */
+ if(0 == *p)
+ break;
+
+ /* Get property list name */
+ name = (const char *)p;
+ p += HDstrlen(name) + 1;
+
+ /* Find property with name */
+ if(NULL == (prop = H5P__find_prop_plist(plist, name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist: '%s'", name)
+
+ /* Check if we should increase the size of the value buffer */
+ if(prop->size > value_buf_size) {
+ if(NULL == (value_buf = H5MM_realloc(value_buf, prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "decoding buffer allocation failed")
+ value_buf_size = prop->size;
+ } /* end if */
+
+ /* Decode serialized value */
+ if(prop->decode) {
+ if((prop->decode)((const void **)&p, value_buf) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "property decoding routine failed, property: '%s'", name)
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "no decode callback for property: '%s'", name)
+
+ /* Set the value for the property */
+ if(H5P_poke(plist, name, value_buf) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value for property: '%s'", name)
+ } /* end while */
+
+ /* Set return value */
+ ret_value = plist_id;
+
+done:
+ /* Release resources */
+ if(value_buf)
+ value_buf = H5MM_xfree(value_buf);
+
+ /* Cleanup on error */
+ if(ret_value < 0) {
+ if(plist_id > 0 && H5I_dec_ref(plist_id) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "unable to close partially initialized property list")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__decode() */
+
diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c
new file mode 100644
index 0000000..1b0a4b9
--- /dev/null
+++ b/src/H5Pfapl.c
@@ -0,0 +1,4809 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pfapl.c
+ * February 26 1998
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: File access property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory Management */
+#include "H5Ppkg.h" /* Property lists */
+
+/* Includes needed to set as default file driver */
+#include "H5FDsec2.h" /* Posix unbuffered I/O file driver */
+#include "H5FDstdio.h" /* Standard C buffered I/O */
+#ifdef H5_HAVE_WINDOWS
+#include "H5FDwindows.h" /* Windows buffered I/O */
+#endif
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= File Access properties ============ */
+/* Definitions for the initial metadata cache resize configuration */
+#define H5F_ACS_META_CACHE_INIT_CONFIG_SIZE sizeof(H5AC_cache_config_t)
+#define H5F_ACS_META_CACHE_INIT_CONFIG_DEF H5AC__DEFAULT_CACHE_CONFIG
+#define H5F_ACS_META_CACHE_INIT_CONFIG_ENC H5P__facc_cache_config_enc
+#define H5F_ACS_META_CACHE_INIT_CONFIG_DEC H5P__facc_cache_config_dec
+#define H5F_ACS_META_CACHE_INIT_CONFIG_CMP H5P__facc_cache_config_cmp
+/* Definitions for size of raw data chunk cache(slots) */
+#define H5F_ACS_DATA_CACHE_NUM_SLOTS_SIZE sizeof(size_t)
+#define H5F_ACS_DATA_CACHE_NUM_SLOTS_DEF 521
+#define H5F_ACS_DATA_CACHE_NUM_SLOTS_ENC H5P__encode_size_t
+#define H5F_ACS_DATA_CACHE_NUM_SLOTS_DEC H5P__decode_size_t
+/* Definition for size of raw data chunk cache(bytes) */
+#define H5F_ACS_DATA_CACHE_BYTE_SIZE_SIZE sizeof(size_t)
+#define H5F_ACS_DATA_CACHE_BYTE_SIZE_DEF (1024*1024)
+#define H5F_ACS_DATA_CACHE_BYTE_SIZE_ENC H5P__encode_size_t
+#define H5F_ACS_DATA_CACHE_BYTE_SIZE_DEC H5P__decode_size_t
+/* Definition for preemption read chunks first */
+#define H5F_ACS_PREEMPT_READ_CHUNKS_SIZE sizeof(double)
+#define H5F_ACS_PREEMPT_READ_CHUNKS_DEF 0.75f
+#define H5F_ACS_PREEMPT_READ_CHUNKS_ENC H5P__encode_double
+#define H5F_ACS_PREEMPT_READ_CHUNKS_DEC H5P__decode_double
+/* Definition for threshold for alignment */
+#define H5F_ACS_ALIGN_THRHD_SIZE sizeof(hsize_t)
+#define H5F_ACS_ALIGN_THRHD_DEF H5F_ALIGN_THRHD_DEF
+#define H5F_ACS_ALIGN_THRHD_ENC H5P__encode_hsize_t
+#define H5F_ACS_ALIGN_THRHD_DEC H5P__decode_hsize_t
+/* Definition for alignment */
+#define H5F_ACS_ALIGN_SIZE sizeof(hsize_t)
+#define H5F_ACS_ALIGN_DEF H5F_ALIGN_DEF
+#define H5F_ACS_ALIGN_ENC H5P__encode_hsize_t
+#define H5F_ACS_ALIGN_DEC H5P__decode_hsize_t
+/* Definition for minimum metadata allocation block size (when
+ aggregating metadata allocations. */
+#define H5F_ACS_META_BLOCK_SIZE_SIZE sizeof(hsize_t)
+#define H5F_ACS_META_BLOCK_SIZE_DEF H5F_META_BLOCK_SIZE_DEF
+#define H5F_ACS_META_BLOCK_SIZE_ENC H5P__encode_hsize_t
+#define H5F_ACS_META_BLOCK_SIZE_DEC H5P__decode_hsize_t
+/* Definition for maximum sieve buffer size (when data sieving
+ is allowed by file driver */
+#define H5F_ACS_SIEVE_BUF_SIZE_SIZE sizeof(size_t)
+#define H5F_ACS_SIEVE_BUF_SIZE_DEF (64*1024)
+#define H5F_ACS_SIEVE_BUF_SIZE_ENC H5P__encode_size_t
+#define H5F_ACS_SIEVE_BUF_SIZE_DEC H5P__decode_size_t
+/* Definition for minimum "small data" allocation block size (when
+ aggregating "small" raw data allocations. */
+#define H5F_ACS_SDATA_BLOCK_SIZE_SIZE sizeof(hsize_t)
+#define H5F_ACS_SDATA_BLOCK_SIZE_DEF H5F_SDATA_BLOCK_SIZE_DEF
+#define H5F_ACS_SDATA_BLOCK_SIZE_ENC H5P__encode_hsize_t
+#define H5F_ACS_SDATA_BLOCK_SIZE_DEC H5P__decode_hsize_t
+/* Definition for garbage-collect references */
+#define H5F_ACS_GARBG_COLCT_REF_SIZE sizeof(unsigned)
+#define H5F_ACS_GARBG_COLCT_REF_DEF 0
+#define H5F_ACS_GARBG_COLCT_REF_ENC H5P__encode_unsigned
+#define H5F_ACS_GARBG_COLCT_REF_DEC H5P__decode_unsigned
+/* Definition for file driver ID & info*/
+#define H5F_ACS_FILE_DRV_SIZE sizeof(H5FD_driver_prop_t)
+#define H5F_ACS_FILE_DRV_DEF {H5_DEFAULT_VFD, NULL}
+#define H5F_ACS_FILE_DRV_CRT H5P__facc_file_driver_create
+#define H5F_ACS_FILE_DRV_SET H5P__facc_file_driver_set
+#define H5F_ACS_FILE_DRV_GET H5P__facc_file_driver_get
+#define H5F_ACS_FILE_DRV_DEL H5P__facc_file_driver_del
+#define H5F_ACS_FILE_DRV_COPY H5P__facc_file_driver_copy
+#define H5F_ACS_FILE_DRV_CMP H5P__facc_file_driver_cmp
+#define H5F_ACS_FILE_DRV_CLOSE H5P__facc_file_driver_close
+/* Definition for file close degree */
+#define H5F_CLOSE_DEGREE_SIZE sizeof(H5F_close_degree_t)
+#define H5F_CLOSE_DEGREE_DEF H5F_CLOSE_DEFAULT
+#define H5F_CLOSE_DEGREE_ENC H5P__facc_fclose_degree_enc
+#define H5F_CLOSE_DEGREE_DEC H5P__facc_fclose_degree_dec
+/* Definition for offset position in file for family file driver */
+#define H5F_ACS_FAMILY_OFFSET_SIZE sizeof(hsize_t)
+#define H5F_ACS_FAMILY_OFFSET_DEF 0
+#define H5F_ACS_FAMILY_OFFSET_ENC H5P__encode_hsize_t
+#define H5F_ACS_FAMILY_OFFSET_DEC H5P__decode_hsize_t
+/* Definition for new member size of family driver. It's private
+ * property only used by h5repart */
+#define H5F_ACS_FAMILY_NEWSIZE_SIZE sizeof(hsize_t)
+#define H5F_ACS_FAMILY_NEWSIZE_DEF 0
+/* Definition for whether to convert family to sec2 driver. It's private
+ * property only used by h5repart */
+#define H5F_ACS_FAMILY_TO_SEC2_SIZE sizeof(hbool_t)
+#define H5F_ACS_FAMILY_TO_SEC2_DEF FALSE
+/* Definition for data type in multi file driver */
+#define H5F_ACS_MULTI_TYPE_SIZE sizeof(H5FD_mem_t)
+#define H5F_ACS_MULTI_TYPE_DEF H5FD_MEM_DEFAULT
+#define H5F_ACS_MULTI_TYPE_ENC H5P__facc_multi_type_enc
+#define H5F_ACS_MULTI_TYPE_DEC H5P__facc_multi_type_dec
+/* Definition for 'use latest format version' flag */
+#define H5F_ACS_LATEST_FORMAT_SIZE sizeof(hbool_t)
+#define H5F_ACS_LATEST_FORMAT_DEF FALSE
+#define H5F_ACS_LATEST_FORMAT_ENC H5P__encode_hbool_t
+#define H5F_ACS_LATEST_FORMAT_DEC H5P__decode_hbool_t
+/* Definition for whether to query the file descriptor from the core VFD
+ * instead of the memory address. (Private to library)
+ */
+#define H5F_ACS_WANT_POSIX_FD_SIZE sizeof(hbool_t)
+#define H5F_ACS_WANT_POSIX_FD_DEF FALSE
+/* Definition for external file cache size */
+#define H5F_ACS_EFC_SIZE_SIZE sizeof(unsigned)
+#define H5F_ACS_EFC_SIZE_DEF 0
+#define H5F_ACS_EFC_SIZE_ENC H5P__encode_unsigned
+#define H5F_ACS_EFC_SIZE_DEC H5P__decode_unsigned
+/* Definition of pointer to initial file image info */
+#define H5F_ACS_FILE_IMAGE_INFO_SIZE sizeof(H5FD_file_image_info_t)
+#define H5F_ACS_FILE_IMAGE_INFO_DEF H5FD_DEFAULT_FILE_IMAGE_INFO
+#define H5F_ACS_FILE_IMAGE_INFO_SET H5P__facc_file_image_info_set
+#define H5F_ACS_FILE_IMAGE_INFO_GET H5P__facc_file_image_info_get
+#define H5F_ACS_FILE_IMAGE_INFO_DEL H5P__facc_file_image_info_del
+#define H5F_ACS_FILE_IMAGE_INFO_COPY H5P__facc_file_image_info_copy
+#define H5F_ACS_FILE_IMAGE_INFO_CMP H5P__facc_file_image_info_cmp
+#define H5F_ACS_FILE_IMAGE_INFO_CLOSE H5P__facc_file_image_info_close
+/* Definition of core VFD write tracking flag */
+#define H5F_ACS_CORE_WRITE_TRACKING_FLAG_SIZE sizeof(hbool_t)
+#define H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEF FALSE
+#define H5F_ACS_CORE_WRITE_TRACKING_FLAG_ENC H5P__encode_hbool_t
+#define H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEC H5P__decode_hbool_t
+/* Definition of core VFD write tracking page size */
+#define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_SIZE sizeof(size_t)
+#define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEF 524288
+#define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_ENC H5P__encode_size_t
+#define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEC H5P__decode_size_t
+/* Definition for # of metadata read attempts */
+#define H5F_ACS_METADATA_READ_ATTEMPTS_SIZE sizeof(unsigned)
+#define H5F_ACS_METADATA_READ_ATTEMPTS_DEF 0
+#define H5F_ACS_METADATA_READ_ATTEMPTS_ENC H5P__encode_unsigned
+#define H5F_ACS_METADATA_READ_ATTEMPTS_DEC H5P__decode_unsigned
+/* Definition for object flush callback */
+#define H5F_ACS_OBJECT_FLUSH_CB_SIZE sizeof(H5F_object_flush_t)
+#define H5F_ACS_OBJECT_FLUSH_CB_DEF {NULL, NULL}
+/* Definition for status_flags in the superblock */
+#define H5F_ACS_CLEAR_STATUS_FLAGS_SIZE sizeof(hbool_t)
+#define H5F_ACS_CLEAR_STATUS_FLAGS_DEF FALSE
+/* Definition for 'use metadata cache logging' flag */
+#define H5F_ACS_USE_MDC_LOGGING_SIZE sizeof(hbool_t)
+#define H5F_ACS_USE_MDC_LOGGING_DEF FALSE
+#define H5F_ACS_USE_MDC_LOGGING_ENC H5P__encode_hbool_t
+#define H5F_ACS_USE_MDC_LOGGING_DEC H5P__decode_hbool_t
+/* Definition for 'mdc log location' flag */
+#define H5F_ACS_MDC_LOG_LOCATION_SIZE sizeof(char *)
+#define H5F_ACS_MDC_LOG_LOCATION_DEF NULL /* default is no log location */
+#define H5F_ACS_MDC_LOG_LOCATION_ENC H5P_facc_mdc_log_location_enc
+#define H5F_ACS_MDC_LOG_LOCATION_DEC H5P_facc_mdc_log_location_dec
+#define H5F_ACS_MDC_LOG_LOCATION_DEL H5P_facc_mdc_log_location_del
+#define H5F_ACS_MDC_LOG_LOCATION_COPY H5P_facc_mdc_log_location_copy
+#define H5F_ACS_MDC_LOG_LOCATION_CMP H5P_facc_mdc_log_location_cmp
+#define H5F_ACS_MDC_LOG_LOCATION_CLOSE H5P_facc_mdc_log_location_close
+/* Definition for 'start metadata cache logging on access' flag */
+#define H5F_ACS_START_MDC_LOG_ON_ACCESS_SIZE sizeof(hbool_t)
+#define H5F_ACS_START_MDC_LOG_ON_ACCESS_DEF FALSE
+#define H5F_ACS_START_MDC_LOG_ON_ACCESS_ENC H5P__encode_hbool_t
+#define H5F_ACS_START_MDC_LOG_ON_ACCESS_DEC H5P__decode_hbool_t
+/* Definition for evict on close property */
+#define H5F_ACS_EVICT_ON_CLOSE_FLAG_SIZE sizeof(hbool_t)
+#define H5F_ACS_EVICT_ON_CLOSE_FLAG_DEF FALSE
+#define H5F_ACS_EVICT_ON_CLOSE_FLAG_ENC H5P__encode_hbool_t
+#define H5F_ACS_EVICT_ON_CLOSE_FLAG_DEC H5P__decode_hbool_t
+#ifdef H5_HAVE_PARALLEL
+/* Definition of collective metadata read mode flag */
+#define H5F_ACS_COLL_MD_READ_FLAG_SIZE sizeof(H5P_coll_md_read_flag_t)
+#define H5F_ACS_COLL_MD_READ_FLAG_DEF H5P_USER_FALSE
+#define H5F_ACS_COLL_MD_READ_FLAG_ENC H5P__encode_coll_md_read_flag_t
+#define H5F_ACS_COLL_MD_READ_FLAG_DEC H5P__decode_coll_md_read_flag_t
+/* Definition of collective metadata write mode flag */
+#define H5F_ACS_COLL_MD_WRITE_FLAG_SIZE sizeof(hbool_t)
+#define H5F_ACS_COLL_MD_WRITE_FLAG_DEF FALSE
+#define H5F_ACS_COLL_MD_WRITE_FLAG_ENC H5P__encode_hbool_t
+#define H5F_ACS_COLL_MD_WRITE_FLAG_DEC H5P__decode_hbool_t
+#endif /* H5_HAVE_PARALLEL */
+/* Definitions for the initial metadata cache image configuration */
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_SIZE sizeof(H5AC_cache_image_config_t)
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_DEF H5AC__DEFAULT_CACHE_IMAGE_CONFIG
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_ENC H5P__facc_cache_image_config_enc
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_DEC H5P__facc_cache_image_config_dec
+#define H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_CMP H5P__facc_cache_image_config_cmp
+/* Definition for total size of page buffer(bytes) */
+#define H5F_ACS_PAGE_BUFFER_SIZE_SIZE sizeof(size_t)
+#define H5F_ACS_PAGE_BUFFER_SIZE_DEF 0
+#define H5F_ACS_PAGE_BUFFER_SIZE_ENC H5P__encode_size_t
+#define H5F_ACS_PAGE_BUFFER_SIZE_DEC H5P__decode_size_t
+/* Definition for minimum metadata size of page buffer(bytes) */
+#define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_SIZE sizeof(unsigned)
+#define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_DEF 0
+#define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_ENC H5P__encode_unsigned
+#define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_DEC H5P__decode_unsigned
+/* Definition for minimum raw data size of page buffer(bytes) */
+#define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_SIZE sizeof(unsigned)
+#define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEF 0
+#define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_ENC H5P__encode_unsigned
+#define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEC H5P__decode_unsigned
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__facc_reg_prop(H5P_genclass_t *pclass);
+
+/* File driver ID & info property callbacks */
+static herr_t H5P__facc_file_driver_create(const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_driver_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_driver_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_driver_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_driver_copy(const char *name, size_t size, void *value);
+static int H5P__facc_file_driver_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__facc_file_driver_close(const char *name, size_t size, void *value);
+
+/* File image info property callbacks */
+static herr_t H5P__file_image_info_copy(void *value);
+static herr_t H5P__file_image_info_free(void *value);
+static herr_t H5P__facc_file_image_info_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_image_info_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_image_info_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__facc_file_image_info_copy(const char *name, size_t size, void *value);
+static int H5P__facc_file_image_info_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__facc_file_image_info_close(const char *name, size_t size, void *value);
+
+/* encode & decode callbacks */
+static herr_t H5P__facc_cache_config_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__facc_cache_config_dec(const void **_pp, void *value);
+static int H5P__facc_cache_config_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__facc_fclose_degree_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__facc_fclose_degree_dec(const void **pp, void *value);
+static herr_t H5P__facc_multi_type_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__facc_multi_type_dec(const void **_pp, void *value);
+
+/* Metadata cache log location property callbacks */
+static herr_t H5P_facc_mdc_log_location_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P_facc_mdc_log_location_dec(const void **_pp, void *value);
+static herr_t H5P_facc_mdc_log_location_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P_facc_mdc_log_location_copy(const char *name, size_t size, void *value);
+static int H5P_facc_mdc_log_location_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P_facc_mdc_log_location_close(const char *name, size_t size, void *value);
+
+/* Metadata cache image property callbacks */
+static int H5P__facc_cache_image_config_cmp(const void *_config1, const void *_config2, size_t H5_ATTR_UNUSED size);
+static herr_t H5P__facc_cache_image_config_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__facc_cache_image_config_dec(const void **_pp, void *_value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* File access property list class library initialization object */
+const H5P_libclass_t H5P_CLS_FACC[1] = {{
+ "file access", /* Class name for debugging */
+ H5P_TYPE_FILE_ACCESS, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_FILE_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_FILE_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_FILE_ACCESS_ID_g, /* Pointer to default property list ID */
+ H5P__facc_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const H5AC_cache_config_t H5F_def_mdc_initCacheCfg_g = H5F_ACS_META_CACHE_INIT_CONFIG_DEF; /* Default metadata cache settings */
+static const size_t H5F_def_rdcc_nslots_g = H5F_ACS_DATA_CACHE_NUM_SLOTS_DEF; /* Default raw data chunk cache # of slots */
+static const size_t H5F_def_rdcc_nbytes_g = H5F_ACS_DATA_CACHE_BYTE_SIZE_DEF; /* Default raw data chunk cache # of bytes */
+static const double H5F_def_rdcc_w0_g = H5F_ACS_PREEMPT_READ_CHUNKS_DEF; /* Default raw data chunk cache dirty ratio */
+static const hsize_t H5F_def_threshold_g = H5F_ACS_ALIGN_THRHD_DEF; /* Default allocation alignment threshold */
+static const hsize_t H5F_def_alignment_g = H5F_ACS_ALIGN_DEF; /* Default allocation alignment value */
+static const hsize_t H5F_def_meta_block_size_g = H5F_ACS_META_BLOCK_SIZE_DEF; /* Default metadata allocation block size */
+static const size_t H5F_def_sieve_buf_size_g = H5F_ACS_SIEVE_BUF_SIZE_DEF; /* Default raw data I/O sieve buffer size */
+static const hsize_t H5F_def_sdata_block_size_g = H5F_ACS_SDATA_BLOCK_SIZE_DEF; /* Default small data allocation block size */
+static const unsigned H5F_def_gc_ref_g = H5F_ACS_GARBG_COLCT_REF_DEF; /* Default garbage collection for references setting */
+static const H5F_close_degree_t H5F_def_close_degree_g = H5F_CLOSE_DEGREE_DEF; /* Default file close degree */
+static const hsize_t H5F_def_family_offset_g = H5F_ACS_FAMILY_OFFSET_DEF; /* Default offset for family VFD */
+static const hsize_t H5F_def_family_newsize_g = H5F_ACS_FAMILY_NEWSIZE_DEF; /* Default size of new files for family VFD */
+static const hbool_t H5F_def_family_to_sec2_g = H5F_ACS_FAMILY_TO_SEC2_DEF; /* Default ?? for family VFD */
+static const H5FD_mem_t H5F_def_mem_type_g = H5F_ACS_MULTI_TYPE_DEF; /* Default file space type for multi VFD */
+static const hbool_t H5F_def_latest_format_g = H5F_ACS_LATEST_FORMAT_DEF; /* Default setting for "use the latest version of the format" flag */
+static const hbool_t H5F_def_want_posix_fd_g = H5F_ACS_WANT_POSIX_FD_DEF; /* Default setting for retrieving 'handle' from core VFD */
+static const unsigned H5F_def_efc_size_g = H5F_ACS_EFC_SIZE_DEF; /* Default external file cache size */
+static const H5FD_file_image_info_t H5F_def_file_image_info_g = H5F_ACS_FILE_IMAGE_INFO_DEF; /* Default file image info and callbacks */
+static const hbool_t H5F_def_core_write_tracking_flag_g = H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEF; /* Default setting for core VFD write tracking */
+static const size_t H5F_def_core_write_tracking_page_size_g = H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEF; /* Default core VFD write tracking page size */
+static const unsigned H5F_def_metadata_read_attempts_g = H5F_ACS_METADATA_READ_ATTEMPTS_DEF; /* Default setting for the # of metadata read attempts */
+static const H5F_object_flush_t H5F_def_object_flush_cb_g = H5F_ACS_OBJECT_FLUSH_CB_DEF; /* Default setting for object flush callback */
+static const hbool_t H5F_def_clear_status_flags_g = H5F_ACS_CLEAR_STATUS_FLAGS_DEF; /* Default to clear the superblock status_flags */
+static const hbool_t H5F_def_use_mdc_logging_g = H5F_ACS_USE_MDC_LOGGING_DEF; /* Default metadata cache logging flag */
+static const char *H5F_def_mdc_log_location_g = H5F_ACS_MDC_LOG_LOCATION_DEF; /* Default mdc log location */
+static const hbool_t H5F_def_start_mdc_log_on_access_g = H5F_ACS_START_MDC_LOG_ON_ACCESS_DEF; /* Default mdc log start on access flag */
+static const hbool_t H5F_def_evict_on_close_flag_g = H5F_ACS_EVICT_ON_CLOSE_FLAG_DEF; /* Default setting for evict on close property */
+#ifdef H5_HAVE_PARALLEL
+static const H5P_coll_md_read_flag_t H5F_def_coll_md_read_flag_g = H5F_ACS_COLL_MD_READ_FLAG_DEF; /* Default setting for the collective metedata read flag */
+static const hbool_t H5F_def_coll_md_write_flag_g = H5F_ACS_COLL_MD_WRITE_FLAG_DEF; /* Default setting for the collective metedata write flag */
+#endif /* H5_HAVE_PARALLEL */
+static const H5AC_cache_image_config_t H5F_def_mdc_initCacheImageCfg_g = H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_DEF; /* Default metadata cache image settings */
+static const size_t H5F_def_page_buf_size_g = H5F_ACS_PAGE_BUFFER_SIZE_DEF; /* Default page buffer size */
+static const unsigned H5F_def_page_buf_min_meta_perc_g = H5F_ACS_PAGE_BUFFER_MIN_META_PERC_DEF; /* Default page buffer minimum metadata size */
+static const unsigned H5F_def_page_buf_min_raw_perc_g = H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEF; /* Default page buffer minumum raw data size */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_reg_prop
+ *
+ * Purpose: Register the file access property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_reg_prop(H5P_genclass_t *pclass)
+{
+ const H5FD_driver_prop_t def_driver_prop = H5F_ACS_FILE_DRV_DEF; /* Default VFL driver ID & info (initialized from a variable) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register the initial metadata cache resize configuration */
+ if(H5P_register_real(pclass, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, H5F_ACS_META_CACHE_INIT_CONFIG_SIZE, &H5F_def_mdc_initCacheCfg_g,
+ NULL, NULL, NULL, H5F_ACS_META_CACHE_INIT_CONFIG_ENC, H5F_ACS_META_CACHE_INIT_CONFIG_DEC,
+ NULL, NULL, H5F_ACS_META_CACHE_INIT_CONFIG_CMP, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the size of raw data chunk cache (elements) */
+ if(H5P_register_real(pclass, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, H5F_ACS_DATA_CACHE_NUM_SLOTS_SIZE, &H5F_def_rdcc_nslots_g,
+ NULL, NULL, NULL, H5F_ACS_DATA_CACHE_NUM_SLOTS_ENC, H5F_ACS_DATA_CACHE_NUM_SLOTS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the size of raw data chunk cache(bytes) */
+ if(H5P_register_real(pclass, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, H5F_ACS_DATA_CACHE_BYTE_SIZE_SIZE, &H5F_def_rdcc_nbytes_g,
+ NULL, NULL, NULL, H5F_ACS_DATA_CACHE_BYTE_SIZE_ENC, H5F_ACS_DATA_CACHE_BYTE_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the preemption for reading chunks */
+ if(H5P_register_real(pclass, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, H5F_ACS_PREEMPT_READ_CHUNKS_SIZE, &H5F_def_rdcc_w0_g,
+ NULL, NULL, NULL, H5F_ACS_PREEMPT_READ_CHUNKS_ENC, H5F_ACS_PREEMPT_READ_CHUNKS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the threshold for alignment */
+ if(H5P_register_real(pclass, H5F_ACS_ALIGN_THRHD_NAME, H5F_ACS_ALIGN_THRHD_SIZE, &H5F_def_threshold_g,
+ NULL, NULL, NULL, H5F_ACS_ALIGN_THRHD_ENC, H5F_ACS_ALIGN_THRHD_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the alignment */
+ if(H5P_register_real(pclass, H5F_ACS_ALIGN_NAME, H5F_ACS_ALIGN_SIZE, &H5F_def_alignment_g,
+ NULL, NULL, NULL, H5F_ACS_ALIGN_ENC, H5F_ACS_ALIGN_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the minimum metadata allocation block size */
+ if(H5P_register_real(pclass, H5F_ACS_META_BLOCK_SIZE_NAME, H5F_ACS_META_BLOCK_SIZE_SIZE, &H5F_def_meta_block_size_g,
+ NULL, NULL, NULL, H5F_ACS_META_BLOCK_SIZE_ENC, H5F_ACS_META_BLOCK_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the maximum sieve buffer size */
+ if(H5P_register_real(pclass, H5F_ACS_SIEVE_BUF_SIZE_NAME, H5F_ACS_SIEVE_BUF_SIZE_SIZE, &H5F_def_sieve_buf_size_g,
+ NULL, NULL, NULL, H5F_ACS_SIEVE_BUF_SIZE_ENC, H5F_ACS_SIEVE_BUF_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the minimum "small data" allocation block size */
+ if(H5P_register_real(pclass, H5F_ACS_SDATA_BLOCK_SIZE_NAME, H5F_ACS_SDATA_BLOCK_SIZE_SIZE, &H5F_def_sdata_block_size_g,
+ NULL, NULL, NULL, H5F_ACS_SDATA_BLOCK_SIZE_ENC, H5F_ACS_SDATA_BLOCK_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the garbage collection reference */
+ if(H5P_register_real(pclass, H5F_ACS_GARBG_COLCT_REF_NAME, H5F_ACS_GARBG_COLCT_REF_SIZE, &H5F_def_gc_ref_g,
+ NULL, NULL, NULL, H5F_ACS_GARBG_COLCT_REF_ENC, H5F_ACS_GARBG_COLCT_REF_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the file driver ID & info */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_FILE_DRV_NAME, H5F_ACS_FILE_DRV_SIZE, &def_driver_prop,
+ H5F_ACS_FILE_DRV_CRT, H5F_ACS_FILE_DRV_SET, H5F_ACS_FILE_DRV_GET, NULL, NULL,
+ H5F_ACS_FILE_DRV_DEL, H5F_ACS_FILE_DRV_COPY, H5F_ACS_FILE_DRV_CMP, H5F_ACS_FILE_DRV_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the file close degree */
+ if(H5P_register_real(pclass, H5F_ACS_CLOSE_DEGREE_NAME, H5F_CLOSE_DEGREE_SIZE, &H5F_def_close_degree_g,
+ NULL, NULL, NULL, H5F_CLOSE_DEGREE_ENC, H5F_CLOSE_DEGREE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the offset of family driver info */
+ if(H5P_register_real(pclass, H5F_ACS_FAMILY_OFFSET_NAME, H5F_ACS_FAMILY_OFFSET_SIZE, &H5F_def_family_offset_g,
+ NULL, NULL, NULL, H5F_ACS_FAMILY_OFFSET_ENC, H5F_ACS_FAMILY_OFFSET_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the private property of new family file size. It's used by h5repart only. */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_FAMILY_NEWSIZE_NAME, H5F_ACS_FAMILY_NEWSIZE_SIZE, &H5F_def_family_newsize_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the private property of whether convert family to sec2 driver. It's used by h5repart only. */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_FAMILY_TO_SEC2_NAME, H5F_ACS_FAMILY_TO_SEC2_SIZE, &H5F_def_family_to_sec2_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the data type of multi driver info */
+ if(H5P_register_real(pclass, H5F_ACS_MULTI_TYPE_NAME, H5F_ACS_MULTI_TYPE_SIZE, &H5F_def_mem_type_g,
+ NULL, NULL, NULL, H5F_ACS_MULTI_TYPE_ENC, H5F_ACS_MULTI_TYPE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the 'use the latest version of the format' flag */
+ if(H5P_register_real(pclass, H5F_ACS_LATEST_FORMAT_NAME, H5F_ACS_LATEST_FORMAT_SIZE, &H5F_def_latest_format_g,
+ NULL, NULL, NULL, H5F_ACS_LATEST_FORMAT_ENC, H5F_ACS_LATEST_FORMAT_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the private property of whether to retrieve the file descriptor from the core VFD */
+ /* (used internally to the library only) */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_WANT_POSIX_FD_NAME, H5F_ACS_WANT_POSIX_FD_SIZE, &H5F_def_want_posix_fd_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the external file cache size */
+ if(H5P_register_real(pclass, H5F_ACS_EFC_SIZE_NAME, H5F_ACS_EFC_SIZE_SIZE, &H5F_def_efc_size_g,
+ NULL, NULL, NULL, H5F_ACS_EFC_SIZE_ENC, H5F_ACS_EFC_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the initial file image info */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_FILE_IMAGE_INFO_NAME, H5F_ACS_FILE_IMAGE_INFO_SIZE, &H5F_def_file_image_info_g,
+ NULL, H5F_ACS_FILE_IMAGE_INFO_SET, H5F_ACS_FILE_IMAGE_INFO_GET, NULL, NULL,
+ H5F_ACS_FILE_IMAGE_INFO_DEL, H5F_ACS_FILE_IMAGE_INFO_COPY, H5F_ACS_FILE_IMAGE_INFO_CMP, H5F_ACS_FILE_IMAGE_INFO_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the core VFD backing store write tracking flag */
+ if(H5P_register_real(pclass, H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME, H5F_ACS_CORE_WRITE_TRACKING_FLAG_SIZE, &H5F_def_core_write_tracking_flag_g,
+ NULL, NULL, NULL, H5F_ACS_CORE_WRITE_TRACKING_FLAG_ENC, H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the size of the core VFD backing store page size */
+ if(H5P_register_real(pclass, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_SIZE, &H5F_def_core_write_tracking_page_size_g,
+ NULL, NULL, NULL, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_ENC, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the # of read attempts */
+ if(H5P_register_real(pclass, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, H5F_ACS_METADATA_READ_ATTEMPTS_SIZE, &H5F_def_metadata_read_attempts_g,
+ NULL, NULL, NULL, H5F_ACS_METADATA_READ_ATTEMPTS_ENC, H5F_ACS_METADATA_READ_ATTEMPTS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register object flush callback */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_ACS_OBJECT_FLUSH_CB_NAME, H5F_ACS_OBJECT_FLUSH_CB_SIZE, &H5F_def_object_flush_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the private property of whether to clear the superblock status_flags. It's used by h5clear only. */
+ if(H5P_register_real(pclass, H5F_ACS_CLEAR_STATUS_FLAGS_NAME, H5F_ACS_CLEAR_STATUS_FLAGS_SIZE, &H5F_def_clear_status_flags_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the metadata cache logging flag. */
+ if(H5P_register_real(pclass, H5F_ACS_USE_MDC_LOGGING_NAME, H5F_ACS_USE_MDC_LOGGING_SIZE, &H5F_def_use_mdc_logging_g,
+ NULL, NULL, NULL, H5F_ACS_USE_MDC_LOGGING_ENC, H5F_ACS_USE_MDC_LOGGING_DEC, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the metadata cache log location. */
+ if(H5P_register_real(pclass, H5F_ACS_MDC_LOG_LOCATION_NAME, H5F_ACS_MDC_LOG_LOCATION_SIZE, &H5F_def_mdc_log_location_g,
+ NULL, NULL, NULL, H5F_ACS_MDC_LOG_LOCATION_ENC, H5F_ACS_MDC_LOG_LOCATION_DEC,
+ H5F_ACS_MDC_LOG_LOCATION_DEL, H5F_ACS_MDC_LOG_LOCATION_COPY, H5F_ACS_MDC_LOG_LOCATION_CMP, H5F_ACS_MDC_LOG_LOCATION_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the flag that indicates whether mdc logging starts on file access. */
+ if(H5P_register_real(pclass, H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME, H5F_ACS_START_MDC_LOG_ON_ACCESS_SIZE, &H5F_def_start_mdc_log_on_access_g,
+ NULL, NULL, NULL, H5F_ACS_START_MDC_LOG_ON_ACCESS_ENC, H5F_ACS_START_MDC_LOG_ON_ACCESS_DEC, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the evict on close flag */
+ if(H5P_register_real(pclass, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, H5F_ACS_EVICT_ON_CLOSE_FLAG_SIZE, &H5F_def_evict_on_close_flag_g,
+ NULL, NULL, NULL, H5F_ACS_EVICT_ON_CLOSE_FLAG_ENC, H5F_ACS_EVICT_ON_CLOSE_FLAG_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Register the metadata collective read flag */
+ if(H5P_register_real(pclass, H5_COLL_MD_READ_FLAG_NAME, H5F_ACS_COLL_MD_READ_FLAG_SIZE, &H5F_def_coll_md_read_flag_g,
+ NULL, NULL, NULL, H5F_ACS_COLL_MD_READ_FLAG_ENC, H5F_ACS_COLL_MD_READ_FLAG_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the metadata collective write flag */
+ if(H5P_register_real(pclass, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, H5F_ACS_COLL_MD_WRITE_FLAG_SIZE, &H5F_def_coll_md_write_flag_g,
+ NULL, NULL, NULL, H5F_ACS_COLL_MD_WRITE_FLAG_ENC, H5F_ACS_COLL_MD_WRITE_FLAG_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Register the initial metadata cache image configuration */
+ if(H5P_register_real(pclass, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_SIZE, &H5F_def_mdc_initCacheImageCfg_g,
+ NULL, NULL, NULL, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_ENC, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_DEC,
+ NULL, NULL, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_CMP, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the size of the page buffer size */
+ if(H5P_register_real(pclass, H5F_ACS_PAGE_BUFFER_SIZE_NAME, H5F_ACS_PAGE_BUFFER_SIZE_SIZE, &H5F_def_page_buf_size_g,
+ NULL, NULL, NULL, H5F_ACS_PAGE_BUFFER_SIZE_ENC, H5F_ACS_PAGE_BUFFER_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register the size of the page buffer minimum metadata size */
+ if(H5P_register_real(pclass, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_SIZE, &H5F_def_page_buf_min_meta_perc_g,
+ NULL, NULL, NULL, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_ENC, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register the size of the page buffer minimum raw data size */
+ if(H5P_register_real(pclass, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_SIZE, &H5F_def_page_buf_min_raw_perc_g,
+ NULL, NULL, NULL, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_ENC, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_alignment
+ *
+ * Purpose: Sets the alignment properties of a file access property list
+ * so that any file object >= THRESHOLD bytes will be aligned on
+ * an address which is a multiple of ALIGNMENT. The addresses
+ * are relative to the end of the user block; the alignment is
+ * calculated by subtracting the user block size from the
+ * absolute file address and then adjusting the address to be a
+ * multiple of ALIGNMENT.
+ *
+ * Default values for THRESHOLD and ALIGNMENT are one, implying
+ * no alignment. Generally the default values will result in
+ * the best performance for single-process access to the file.
+ * For MPI-IO and other parallel systems, choose an alignment
+ * which is a multiple of the disk block size.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 9, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed file access property list mechanism to the new
+ * generic property list.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_alignment(hid_t fapl_id, hsize_t threshold, hsize_t alignment)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ihh", fapl_id, threshold, alignment);
+
+ /* Check args */
+ if(alignment < 1)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "alignment must be positive")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_ALIGN_THRHD_NAME, &threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set threshold")
+ if(H5P_set(plist, H5F_ACS_ALIGN_NAME, &alignment) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set alignment")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_alignment
+ *
+ * Purpose: Returns the current settings for alignment properties from a
+ * file access property list. The THRESHOLD and/or ALIGNMENT
+ * pointers may be null pointers.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 9, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_alignment(hid_t fapl_id, hsize_t *threshold/*out*/,
+ hsize_t *alignment/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", fapl_id, threshold, alignment);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(threshold)
+ if(H5P_get(plist, H5F_ACS_ALIGN_THRHD_NAME, threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get threshold")
+ if(alignment)
+ if(H5P_get(plist, H5F_ACS_ALIGN_NAME, alignment) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get alignment")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_alignment() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_set_driver
+ *
+ * Purpose: Set the file driver (DRIVER_ID) for a file access
+ * property list (PLIST_ID) and supply an optional
+ * struct containing the driver-specific properites
+ * (DRIVER_INFO). The driver properties will be copied into the
+ * property list and the reference count on the driver will be
+ * incremented, allowing the caller to close the driver ID but
+ * still use the property list.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 3, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_set_driver(H5P_genplist_t *plist, hid_t new_driver_id, const void *new_driver_info)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(NULL == H5I_object_verify(new_driver_id, H5I_VFL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file driver ID")
+
+ if(TRUE == H5P_isa_class(plist->plist_id, H5P_FILE_ACCESS)) {
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+
+ /* Prepare the driver property */
+ driver_prop.driver_id = new_driver_id;
+ driver_prop.driver_info = new_driver_info;
+
+ /* Set the driver ID & info property */
+ if(H5P_set(plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set driver ID & info")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_set_driver() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_driver
+ *
+ * Purpose: Set the file driver (DRIVER_ID) for a file access
+ * property list (PLIST_ID) and supply an optional
+ * struct containing the driver-specific properites
+ * (DRIVER_INFO). The driver properties will be copied into the
+ * property list and the reference count on the driver will be
+ * incremented, allowing the caller to close the driver ID but
+ * still use the property list.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 3, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_driver(hid_t plist_id, hid_t new_driver_id, const void *new_driver_info)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ii*x", plist_id, new_driver_id, new_driver_info);
+
+ /* Check arguments */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if(NULL == H5I_object_verify(new_driver_id, H5I_VFL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file driver ID")
+
+ /* Set the driver */
+ if(H5P_set_driver(plist, new_driver_id, new_driver_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set driver info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_driver() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_peek_driver
+ *
+ * Purpose: Return the ID of the low-level file driver. PLIST_ID should
+ * be a file access property list.
+ *
+ * Return: Success: A low-level driver ID which is the same ID
+ * used when the driver was set for the property
+ * list. The driver ID is only valid as long as
+ * the file driver remains registered.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 26, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5P_peek_driver(H5P_genplist_t *plist)
+{
+ hid_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the current driver ID */
+ if(TRUE == H5P_isa_class(plist->plist_id, H5P_FILE_ACCESS)) {
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+
+ if(H5P_peek(plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get driver ID")
+ ret_value = driver_prop.driver_id;
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a file access property list")
+
+ if(H5FD_VFD_DEFAULT == ret_value)
+ ret_value = H5_DEFAULT_VFD;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_peek_driver() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_driver
+ *
+ * Purpose: Return the ID of the low-level file driver. PLIST_ID should
+ * be a file access property list.
+ *
+ * Note: The ID returned should not be closed.
+ *
+ * Return: Success: A low-level driver ID which is the same ID
+ * used when the driver was set for the property
+ * list. The driver ID is only valid as long as
+ * the file driver remains registered.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, February 26, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Pget_driver(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", plist_id);
+
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+
+ /* Get the driver */
+ if((ret_value = H5P_peek_driver(plist)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get driver")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_driver() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_peek_driver_info
+ *
+ * Purpose: Returns a pointer directly to the file driver-specific
+ * information of a file access.
+ *
+ * Return: Success: Ptr to *uncopied* driver specific data
+ * structure if any.
+ *
+ * Failure: NULL. Null is also returned if the driver has
+ * not registered any driver-specific properties
+ * although no error is pushed on the stack in
+ * this case.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+const void *
+H5P_peek_driver_info(H5P_genplist_t *plist)
+{
+ const void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Get the current driver info */
+ if(TRUE == H5P_isa_class(plist->plist_id, H5P_FILE_ACCESS)) {
+ H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
+
+ if(H5P_peek(plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get driver info")
+ ret_value = driver_prop.driver_info;
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, NULL, "not a file access property list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_peek_driver_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_driver_info
+ *
+ * Purpose: Returns a pointer directly to the file driver-specific
+ * information of a file access.
+ *
+ * Return: Success: Ptr to *uncopied* driver specific data
+ * structure if any.
+ *
+ * Failure: NULL. Null is also returned if the driver has
+ * not registered any driver-specific properties
+ * although no error is pushed on the stack in
+ * this case.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+const void *
+H5Pget_driver_info(hid_t plist_id)
+{
+ H5P_genplist_t *plist = NULL; /* Property list pointer */
+ const void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE1("*x", "i", plist_id);
+
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property list")
+
+ /* Get the driver info */
+ if(NULL == (ret_value = (const void *)H5P_peek_driver_info(plist)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get driver info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_driver_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__file_driver_copy
+ *
+ * Purpose: Copy file driver ID & info.
+ *
+ * Note: This is an "in-place" copy, since this routine gets called
+ * after the top-level copy has been performed and this routine
+ * finishes the "deep" part of the copy.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, Sept 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__file_driver_copy(void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(value) {
+ H5FD_driver_prop_t *info = (H5FD_driver_prop_t *)value; /* Driver ID & info struct */
+
+ /* Copy the driver & info, if there is one */
+ if(info->driver_id > 0) {
+ /* Increment the reference count on driver and copy driver info */
+ if(H5I_inc_ref(info->driver_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINC, FAIL, "unable to increment ref count on VFL driver")
+
+ /* Copy driver info, if it exists */
+ if(info->driver_info) {
+ H5FD_class_t *driver; /* Pointer to driver */
+ void *new_pl; /* Copy of driver info */
+
+ /* Retrieve the driver for the ID */
+ if(NULL == (driver = (H5FD_class_t *)H5I_object(info->driver_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a driver ID")
+
+ /* Allow the driver to copy or do it ourselves */
+ if(driver->fapl_copy) {
+ if(NULL == (new_pl = (driver->fapl_copy)(info->driver_info)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "driver info copy failed")
+ } /* end if */
+ else if(driver->fapl_size > 0) {
+ if(NULL == (new_pl = H5MM_malloc(driver->fapl_size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "driver info allocation failed")
+ HDmemcpy(new_pl, info->driver_info, driver->fapl_size);
+ } /* end else-if */
+ else
+ HGOTO_ERROR(H5E_PLIST, H5E_UNSUPPORTED, FAIL, "no way to copy driver info")
+
+ /* Set the driver info for the copy */
+ info->driver_info = new_pl;
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__file_driver_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__file_driver_free
+ *
+ * Purpose: Free file driver ID & info.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, Sept 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__file_driver_free(void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(value) {
+ H5FD_driver_prop_t *info = (H5FD_driver_prop_t *)value; /* Driver ID & info struct */
+
+ /* Copy the driver & info, if there is one */
+ if(info->driver_id > 0) {
+ if(info->driver_info) {
+ H5FD_class_t *driver; /* Pointer to driver */
+
+ /* Retrieve the driver for the ID */
+ if(NULL == (driver = (H5FD_class_t *)H5I_object(info->driver_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a driver ID")
+
+ /* Allow driver to free info or do it ourselves */
+ if(driver->fapl_free) {
+ if((driver->fapl_free)((void *)info->driver_info) < 0) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "driver info free request failed")
+ } /* end if */
+ else
+ H5MM_xfree((void *)info->driver_info); /* Casting away const OK -QAK */
+ } /* end if */
+
+ /* Decrement reference count for driver */
+ if(H5I_dec_ref(info->driver_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDEC, FAIL, "can't decrement reference count for driver ID")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__file_driver_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_create
+ *
+ * Purpose: Create callback for the file driver ID & info property.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_create(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Make copy of file driver */
+ if(H5P__file_driver_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_set
+ *
+ * Purpose: Copies a file driver property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, Sept 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of file driver ID & info */
+ if(H5P__file_driver_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_get
+ *
+ * Purpose: Copies a file driver property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, Sept 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of file driver */
+ if(H5P__file_driver_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_del
+ *
+ * Purpose: Frees memory used to store the driver ID & info property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Free the file driver ID & info */
+ if(H5P__file_driver_free(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "can't release file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_copy
+ *
+ * Purpose: Copy callback for the file driver ID & info property.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Make copy of file driver */
+ if(H5P__file_driver_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_cmp
+ *
+ * Purpose: Callback routine which is called whenever the file driver ID & info
+ * property in the file access property list is compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__facc_file_driver_cmp(const void *_info1, const void *_info2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5FD_driver_prop_t *info1 = (const H5FD_driver_prop_t *)_info1, /* Create local aliases for values */
+ *info2 = (const H5FD_driver_prop_t *)_info2;
+ H5FD_class_t *cls1, *cls2; /* Driver class for each property */
+ int cmp_value; /* Value from comparison */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(info1);
+ HDassert(info2);
+ HDassert(size == sizeof(H5FD_driver_prop_t));
+
+ /* Compare drivers */
+ if(NULL == (cls1 = H5FD_get_class(info1->driver_id)))
+ HGOTO_DONE(-1)
+ if(NULL == (cls2 = H5FD_get_class(info2->driver_id)))
+ HGOTO_DONE(1)
+ if(cls1->name == NULL && cls2->name != NULL) HGOTO_DONE(-1);
+ if(cls1->name != NULL && cls2->name == NULL) HGOTO_DONE(1);
+ if(0 != (cmp_value = HDstrcmp(cls1->name, cls2->name)))
+ HGOTO_DONE(cmp_value);
+
+ /* Compare driver infos */
+ if(cls1->fapl_size < cls2->fapl_size) HGOTO_DONE(-1)
+ if(cls1->fapl_size > cls2->fapl_size) HGOTO_DONE(1)
+ HDassert(cls1->fapl_size == cls2->fapl_size);
+ if(info1->driver_info == NULL && info2->driver_info != NULL) HGOTO_DONE(-1);
+ if(info1->driver_info != NULL && info2->driver_info == NULL) HGOTO_DONE(1);
+ if(info1->driver_info) {
+ HDassert(cls1->fapl_size > 0);
+ if(0 != (cmp_value = HDmemcmp(info1->driver_info, info2->driver_info, cls1->fapl_size)))
+ HGOTO_DONE(cmp_value);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_driver_close
+ *
+ * Purpose: Close callback for the file driver ID & info property.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 8, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_driver_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Free the file driver */
+ if(H5P__file_driver_free(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "can't release file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_driver_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_family_offset
+ *
+ * Purpose: Set offset for family driver. This file access property
+ * list will be passed to H5Fget_vfd_handle or H5FDget_vfd_handle
+ * to retrieve VFD file handle.
+ *
+ * Return: Success: Non-negative value.
+ * Failure: Negative value.
+ *
+ * Programmer: Raymond Lu
+ * Sep 17, 2002
+ *
+ *-------------------------------------------------------------------------
+*/
+herr_t
+H5Pset_family_offset(hid_t fapl_id, hsize_t offset)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", fapl_id, offset);
+
+ /* Get the plist structure */
+ if(H5P_DEFAULT == fapl_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't modify default property list")
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(H5P_set(plist, H5F_ACS_FAMILY_OFFSET_NAME, &offset) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set offset for family file")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_family_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_family_offset
+ *
+ * Purpose: Get offset for family driver. This file access property
+ * list will be passed to H5Fget_vfd_handle or H5FDget_vfd_handle
+ * to retrieve VFD file handle.
+ *
+ * Return: Success: Non-negative value.
+ * Failure: Negative value.
+ *
+ * Programmer: Raymond Lu
+ * Sep 17, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_family_offset(hid_t fapl_id, hsize_t *offset)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", fapl_id, offset);
+
+ /* Get the plist structure */
+ if(H5P_DEFAULT == fapl_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't modify default property list")
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(offset) {
+ if(H5P_get(plist, H5F_ACS_FAMILY_OFFSET_NAME, offset) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set offset for family file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_family_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_multi_type
+ *
+ * Purpose: Set data type for multi driver. This file access property
+ * list will be passed to H5Fget_vfd_handle or H5FDget_vfd_handle
+ * to retrieve VFD file handle.
+ *
+ * Return: Success: Non-negative value.
+ * Failure: Negative value.
+ *
+ * Programmer: Raymond Lu
+ * Sep 17, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_multi_type(hid_t fapl_id, H5FD_mem_t type)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iMt", fapl_id, type);
+
+ /* Get the plist structure */
+ if(H5P_DEFAULT == fapl_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't modify default property list")
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(H5P_set(plist, H5F_ACS_MULTI_TYPE_NAME, &type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set type for multi driver")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_multi_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_multi_type
+ *
+ * Purpose: Get data type for multi driver. This file access property
+ * list will be passed to H5Fget_vfd_handle or H5FDget_vfd_handle
+ * to retrieve VFD file handle.
+ *
+ * Return: Success: Non-negative value.
+ * Failure: Negative value.
+ *
+ * Programmer: Raymond Lu
+ * Sep 17, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_multi_type(hid_t fapl_id, H5FD_mem_t *type)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Mt", fapl_id, type);
+
+ /* Get the plist structure */
+ if(H5P_DEFAULT == fapl_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't modify default property list")
+ if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(type) {
+ if(H5P_get(plist, H5F_ACS_MULTI_TYPE_NAME, type) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get type for multi driver")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_multi_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_cache
+ *
+ * Purpose: Set the number of objects in the meta data cache and the
+ * maximum number of chunks and bytes in the raw data chunk
+ * cache.
+ *
+ * The RDCC_W0 value should be between 0 and 1 inclusive and
+ * indicates how much chunks that have been fully read or fully
+ * written are favored for preemption. A value of zero means
+ * fully read or written chunks are treated no differently than
+ * other chunks (the preemption is strictly LRU) while a value
+ * of one means fully read chunks are always preempted before
+ * other chunks.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, May 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_cache(hid_t plist_id, int H5_ATTR_UNUSED mdc_nelmts,
+ size_t rdcc_nslots, size_t rdcc_nbytes, double rdcc_w0)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIszzd", plist_id, mdc_nelmts, rdcc_nslots, rdcc_nbytes,
+ rdcc_w0);
+
+ /* Check arguments */
+ if(rdcc_w0 < (double)0.0f || rdcc_w0 > (double)1.0f)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "raw data cache w0 value must be between 0.0 and 1.0 inclusive")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set sizes */
+ if(H5P_set(plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, &rdcc_nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache number of slots")
+ if(H5P_set(plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, &rdcc_nbytes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache byte size")
+ if(H5P_set(plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, &rdcc_w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set preempt read chunks")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_cache
+ *
+ * Purpose: Retrieves the maximum possible number of elements in the meta
+ * data cache and the maximum possible number of elements and
+ * bytes and the RDCC_W0 value in the raw data chunk cache. Any
+ * (or all) arguments may be null pointers in which case the
+ * corresponding datum is not returned.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, May 19, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_cache(hid_t plist_id, int *mdc_nelmts,
+ size_t *rdcc_nslots, size_t *rdcc_nbytes, double *rdcc_w0)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*Is*z*z*d", plist_id, mdc_nelmts, rdcc_nslots, rdcc_nbytes,
+ rdcc_w0);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get sizes */
+
+ /* the mdc_nelmts FAPL entry no longer exists, so just return a constant */
+ if(mdc_nelmts)
+ *mdc_nelmts = 0;
+
+ if(rdcc_nslots)
+ if(H5P_get(plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, rdcc_nslots) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache number of slots")
+ if(rdcc_nbytes)
+ if(H5P_get(plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, rdcc_nbytes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache byte size")
+ if(rdcc_w0)
+ if(H5P_get(plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, rdcc_w0) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get preempt read chunks")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_mdc_image_config
+ *
+ * Purpose: Set the initial metadata cache image configuration in the
+ * target FAPL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: J. Mainzer
+ * Thursday, June 25, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t *config_ptr)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", plist_id, config_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* validate the new configuration */
+ if(H5AC_validate_cache_image_config(config_ptr) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid metadata cache image configuration")
+
+ /* set the modified metadata cache image config */
+
+ /* If we ever support multiple versions of H5AC_cache_image_config_t, we
+ * will have to test the version and do translation here.
+ */
+
+ if(H5P_set(plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, config_ptr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set metadata cache image initial config")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_mdc_image_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mdc_image_config
+ *
+ * Purpose: Retrieve the metadata cache initial image configuration
+ * from the target FAPL.
+ *
+ * Observe that the function will fail if config_ptr is
+ * NULL, or if config_ptr->version specifies an unknown
+ * version of H5AC_cache_image_config_t.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: J. Mainzer
+ * Friday, June 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t *config_ptr)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", plist_id, config_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* validate the config_ptr */
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL config_ptr on entry.")
+
+ if(config_ptr->version != H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unknown image config version.")
+
+ /* If we ever support multiple versions of H5AC_cache_config_t, we
+ * will have to get the cannonical version here, and then translate
+ * to the version of the structure supplied.
+ */
+
+ /* Get the current initial metadata cache resize configuration */
+ if(H5P_get(plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, config_ptr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get metadata cache initial image config")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_mdc_image_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_mdc_config
+ *
+ * Purpose: Set the initial metadata cache resize configuration in the
+ * target FAPL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: J. Mainzer
+ * Thursday, April 7, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_mdc_config(hid_t plist_id, H5AC_cache_config_t *config_ptr)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", plist_id, config_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* validate the new configuration */
+ if(H5AC_validate_config(config_ptr) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid metadata cache configuration")
+
+ /* set the modified config */
+
+ /* If we ever support multiple versions of H5AC_cache_config_t, we
+ * will have to test the version and do translation here.
+ */
+
+ if(H5P_set(plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, config_ptr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set metadata cache initial config")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_mdc_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mdc_config
+ *
+ * Purpose: Retrieve the metadata cache initial resize configuration
+ * from the target FAPL.
+ *
+ * Observe that the function will fail if config_ptr is
+ * NULL, or if config_ptr->version specifies an unknown
+ * version of H5AC_cache_config_t.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: J. Mainzer
+ * Thursday, April 7, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mdc_config(hid_t plist_id, H5AC_cache_config_t *config_ptr)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", plist_id, config_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* validate the config_ptr */
+ if(config_ptr == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL config_ptr on entry.")
+
+ if(config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unknown config version.")
+
+ /* If we ever support multiple versions of H5AC_cache_config_t, we
+ * will have to get the cannonical version here, and then translate
+ * to the version of the structure supplied.
+ */
+
+ /* Get the current initial metadata cache resize configuration */
+ if(H5P_get(plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, config_ptr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get metadata cache initial resize config")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_mdc_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_gc_references
+ *
+ * Purpose: Sets the flag for garbage collecting references for the file.
+ * Dataset region references (and other reference types
+ * probably) use space in the file heap. If garbage collection
+ * is on and the user passes in an uninitialized value in a
+ * reference structure, the heap might get corrupted. When
+ * garbage collection is off however and the user re-uses a
+ * reference, the previous heap block will be orphaned and not
+ * returned to the free heap space. When garbage collection is
+ * on, the user must initialize the reference structures to 0 or
+ * risk heap corruption.
+ *
+ * Default value for garbage collecting references is off, just
+ * to be on the safe side.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June, 1999
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_gc_references(hid_t plist_id, unsigned gc_ref)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, gc_ref);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_GARBG_COLCT_REF_NAME, &gc_ref) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set garbage collect reference")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_gc_references
+ *
+ * Purpose: Returns the current setting for the garbage collection
+ * references property from a file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * June, 1999
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_gc_references(hid_t plist_id, unsigned *gc_ref/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, gc_ref);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(gc_ref)
+ if(H5P_get(plist, H5F_ACS_GARBG_COLCT_REF_NAME, gc_ref) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get garbage collect reference")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fclose_degree
+ *
+ * Purpose: Sets the degree for the file close behavior.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * November, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fclose_degree(hid_t plist_id, H5F_close_degree_t degree)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iFd", plist_id, degree);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_CLOSE_DEGREE_NAME, &degree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fclose_degree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fclose_degree
+ *
+ * Purpose: Returns the degree for the file close behavior.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * November, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fclose_degree(hid_t plist_id, H5F_close_degree_t *degree)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Fd", plist_id, degree);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(degree && H5P_get(plist, H5F_ACS_CLOSE_DEGREE_NAME, degree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file close degree")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fclose_degree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_meta_block_size
+ *
+ * Purpose: Sets the minimum size of metadata block allocations when
+ * the H5FD_FEAT_AGGREGATE_METADATA is set by a VFL driver.
+ * Each "raw" metadata block is allocated to be this size and then
+ * specific pieces of metadata (object headers, local heaps, B-trees, etc)
+ * are sub-allocated from this block.
+ *
+ * The default value is set to 2048 (bytes), indicating that metadata
+ * will be attempted to be bunched together in (at least) 2K blocks in
+ * the file. Setting the value to 0 with this API function will
+ * turn off the metadata aggregation, even if the VFL driver attempts to
+ * use that strategy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_meta_block_size(hid_t plist_id, hsize_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_META_BLOCK_SIZE_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set meta data block size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_meta_block_size
+ *
+ * Purpose: Returns the current settings for the metadata block allocation
+ * property from a file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 29, 2000
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_meta_block_size(hid_t plist_id, hsize_t *size/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(size) {
+ if(H5P_get(plist, H5F_ACS_META_BLOCK_SIZE_NAME, size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get meta data block size")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_sieve_buf_size
+ *
+ * Purpose: Sets the maximum size of the data seive buffer used for file
+ * drivers which are capable of using data sieving. The data sieve
+ * buffer is used when performing I/O on datasets in the file. Using a
+ * buffer which is large anough to hold several pieces of the dataset
+ * being read in for hyperslab selections boosts performance by quite a
+ * bit.
+ *
+ * The default value is set to 64KB, indicating that file I/O for raw data
+ * reads and writes will occur in at least 64KB blocks.
+ * Setting the value to 0 with this API function will turn off the
+ * data sieving, even if the VFL driver attempts to use that strategy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 21, 2000
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_sieve_buf_size(hid_t plist_id, size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set sieve buffer size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_sieve_buf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_sieve_buf_size
+ *
+ * Purpose: Returns the current settings for the data sieve buffer size
+ * property from a file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 21, 2000
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, Oct 23, 2001
+ * Changed the file access list to the new generic property
+ * list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_sieve_buf_size(hid_t plist_id, size_t *size/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(size)
+ if(H5P_get(plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get sieve buffer size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_sieve_buf_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_small_data_block_size
+ *
+ * Purpose: Sets the minimum size of "small" raw data block allocations
+ * when the H5FD_FEAT_AGGREGATE_SMALLDATA is set by a VFL driver.
+ * Each "small" raw data block is allocated to be this size and then
+ * pieces of raw data which are small enough to fit are sub-allocated from
+ * this block.
+ *
+ * The default value is set to 2048 (bytes), indicating that raw data
+ * smaller than this value will be attempted to be bunched together in (at
+ * least) 2K blocks in the file. Setting the value to 0 with this API
+ * function will turn off the "small" raw data aggregation, even if the
+ * VFL driver attempts to use that strategy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 5, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_small_data_block_size(hid_t plist_id, hsize_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'small data' block size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_small_data_block_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_small_data_block_size
+ *
+ * Purpose: Returns the current settings for the "small" raw data block
+ * allocation property from a file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 5, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_small_data_block_size(hid_t plist_id, hsize_t *size/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(size) {
+ if(H5P_get(plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get 'small data' block size")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_small_data_block_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_libver_bounds
+ *
+ * Purpose: Indicates which versions of the file format the library should
+ * use when creating objects. LOW is the earliest version of the HDF5
+ * library that is guaranteed to be able to access the objects created
+ * (the format of some objects in an HDF5 file may not have changed between
+ * versions of the HDF5 library, possibly allowing earlier versions of the
+ * HDF5 library to access those objects) and HIGH is the latest version
+ * of the library required to access the objects created (later versions
+ * of the HDF5 library will also be able to access those objects).
+ *
+ * LOW is used to require that objects use a more modern format and HIGH
+ * is used to restrict objects from using a more modern format.
+ *
+ * The special values of H5F_FORMAT_EARLIEST and H5F_FORMAT_LATEST can be
+ * used in the following manner: Setting LOW and HIGH to H5F_FORMAT_LATEST
+ * will produce files whose objects use the latest version of the file
+ * format available in the current HDF5 library for each object created.
+ * Setting LOW and HIGH to H5F_FORMAT_EARLIEST will produce files that that
+ * always require the use of the earliest version of the file format for
+ * each object created. [NOTE! LOW=HIGH=H5F_FORMAT_EARLIEST is not
+ * implemented as of version 1.8.0 and setting LOW and HIGH to
+ * H5F_FORMAT_EARLIEST will produce an error currently].
+ *
+ * Currently, the only two valid combinations for this routine are:
+ * LOW = H5F_FORMAT_EARLIEST and HIGH = H5F_FORMAT_LATEST (the default
+ * setting, which creates objects with the ealiest version possible for
+ * each object, but no upper limit on the version allowed to be created if
+ * a newer version of an object's format is required to support a feature
+ * requested with an HDF5 library API routine), and LOW = H5F_FORMAT_LATEST
+ * and HIGH = H5F_FORMAT_LATEST (which is described above).
+ *
+ * The LOW and HIGH values set with this routine at imposed with each
+ * HDF5 library API call that creates objects in the file. API calls that
+ * would violate the LOW or HIGH format bound will fail.
+ *
+ * Setting the LOW and HIGH values will not affect reading/writing existing
+ * objects, only the creation of new objects.
+ *
+ * Note: Eventually we want to add more values to the H5F_libver_t
+ * enumerated type that indicate library release values where the file
+ * format was changed (like "H5F_FORMAT_1_2_0" for the file format changes
+ * in the 1.2.x release branch and possily even "H5F_FORMAT_1_4_2" for
+ * a change mid-way through the 1.4.x release branch, etc).
+ *
+ * Adding more values will allow applications to make settings like the
+ * following:
+ * LOW = H5F_FORMAT_EARLIEST, HIGH = H5F_FORMAT_1_2_0 => Create objects
+ * with the earliest possible format and don't allow any objects
+ * to be created that require a library version greater than 1.2.x
+ * (This is the "make certain that <application> linked with v1.2.x
+ * of the library can read the file produced" use case)
+ *
+ * LOW = H5F_FORMAT_1_4_2, HIGH = H5F_FORMAT_LATEST => create objects
+ * with at least the version of their format that the 1.4.2 library
+ * uses and allow any later version of the object's format
+ * necessary to represent features used.
+ * (This is the "make certain to take advantage of <new feature>
+ * in the file format" use case (maybe <new feature> is smaller
+ * or scales better than an ealier version, which would otherwise
+ * be used))
+ *
+ * LOW = H5F_FORMAT_1_2_0, HIGH = H5F_FORMAT_1_6_0 => creates objects
+ * with at least the version of their format that the 1.2.x library
+ * uses and don't allow any objects to be created that require a
+ * library version greater than 1.6.x.
+ * (Not certain of a particular use case for these settings,
+ * although its probably just the logical combination of the
+ * previous two; it just falls out as possible/logical (if it turns
+ * out to be hard to implement in some way, we can always disallow
+ * it))
+ *
+ * Note #2: We talked about whether to include enum values for only library
+ * versions where the format changed and decided it would be less confusing
+ * for application developers if we include enum values for _all_ library
+ * releases and then map down to the previous actual library release which
+ * had a format change.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, December 30, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_libver_bounds(hid_t plist_id, H5F_libver_t low,
+ H5F_libver_t high)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ hbool_t latest; /* Whether to use the latest version or not */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iFvFv", plist_id, low, high);
+
+ /* Check args */
+ /* (Note that this is _really_ restricted right now, we'll want to loosen
+ * this up more as we add features - QAK)
+ */
+ if(high != H5F_LIBVER_LATEST)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid high library version bound")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ latest = (hbool_t)((low == H5F_LIBVER_LATEST) ? TRUE : FALSE);
+ if(H5P_set(plist, H5F_ACS_LATEST_FORMAT_NAME, &latest) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set library version bounds")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_libver_bounds() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_libver_bounds
+ *
+ * Purpose: Returns the current settings for the library version format bounds
+ * from a file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, January 3, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_libver_bounds(hid_t plist_id, H5F_libver_t *low/*out*/,
+ H5F_libver_t *high/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ hbool_t latest; /* Whether to use the latest version or not */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", plist_id, low, high);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_get(plist, H5F_ACS_LATEST_FORMAT_NAME, &latest) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get library version bounds")
+
+ /* Check for setting values to return */
+ /* (Again, this is restricted now, we'll need to open it up later -QAK) */
+ if(low)
+ *low = latest ? H5F_LIBVER_LATEST : H5F_LIBVER_EARLIEST;
+ if(high)
+ *high = H5F_LIBVER_LATEST;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_libver_bounds() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_file_cache_size
+ *
+ * Purpose: Sets the number of files opened through external links
+ * from the file associated with this fapl to be held open
+ * in that file's external file cache. When the maximum
+ * number of files is reached, the least recently used file
+ * is closed (unless it is opened from somewhere else).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 17, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_file_cache_size(hid_t plist_id, unsigned efc_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, efc_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(H5P_set(plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set elink file cache size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_file_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_file_cache_size
+ *
+ * Purpose: Gets the number of files opened through external links
+ * from the file associated with this fapl to be held open
+ * in that file's external file cache. When the maximum
+ * number of files is reached, the least recently used file
+ * is closed (unless it is opened from somewhere else).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 17, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_elink_file_cache_size(hid_t plist_id, unsigned *efc_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", plist_id, efc_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(efc_size)
+ if(H5P_get(plist, H5F_ACS_EFC_SIZE_NAME, efc_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get elink file cache size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_file_cache_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_image
+ *
+ * Purpose: Sets the initial file image. Some file drivers can initialize
+ * the starting data in a file from a buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t image_info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*xz", fapl_id, buf_ptr, buf_len);
+
+ /* validate parameters */
+ if(!(((buf_ptr == NULL) && (buf_len == 0)) || ((buf_ptr != NULL) && (buf_len > 0))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "inconsistant buf_ptr and buf_len")
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old image info */
+ if(H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image pointer")
+
+ /* Release previous buffer, if it exists */
+ if(image_info.buffer != NULL) {
+ if(image_info.callbacks.image_free) {
+ if(SUCCEED != image_info.callbacks.image_free(image_info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(image_info.buffer);
+ } /* end if */
+
+ /* Update struct */
+ if(buf_ptr) {
+ /* Allocate memory */
+ if(image_info.callbacks.image_malloc) {
+ if(NULL == (image_info.buffer = image_info.callbacks.image_malloc(buf_len,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed")
+ } /* end if */
+ else
+ if(NULL == (image_info.buffer = H5MM_malloc(buf_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block")
+
+ /* Copy data */
+ if(image_info.callbacks.image_memcpy) {
+ if(image_info.buffer != image_info.callbacks.image_memcpy(image_info.buffer,
+ buf_ptr, buf_len, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET,
+ image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(image_info.buffer, buf_ptr, buf_len);
+ } /* end if */
+ else
+ image_info.buffer = NULL;
+
+ image_info.size = buf_len;
+
+ /* Set values */
+ if(H5P_poke(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_file_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_image
+ *
+ * Purpose: If the file image exists and buf_ptr_ptr is not NULL,
+ * allocate a buffer of the correct size, copy the image into
+ * the new buffer, and return the buffer to the caller in
+ * *buf_ptr_ptr. Do this using the file image callbacks
+ * if defined.
+ *
+ * NB: It is the responsibility of the caller to free the
+ * buffer whose address is returned in *buf_ptr_ptr. Do
+ * this using free if the file image callbacks are not
+ * defined, or with whatever method is appropriate if
+ * the callbacks are defined.
+ *
+ * If buf_ptr_ptr is not NULL, and no image exists, set
+ * *buf_ptr_ptr to NULL.
+ *
+ * If buf_len_ptr is not NULL, set *buf_len_ptr equal
+ * to the length of the file image if it exists, and
+ * to 0 if it does not.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t image_info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i**x*z", fapl_id, buf_ptr_ptr, buf_len_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((image_info.buffer != NULL) && (image_info.size > 0)) ||
+ ((image_info.buffer == NULL) && (image_info.size == 0)));
+
+ /* Set output size */
+ if(buf_len_ptr != NULL)
+ *buf_len_ptr = image_info.size;
+
+ /* Duplicate the image if desired, using callbacks if available */
+ if(buf_ptr_ptr != NULL) {
+ void * copy_ptr = NULL; /* Copy of memory image */
+
+ if(image_info.buffer != NULL) {
+ /* Allocate memory */
+ if(image_info.callbacks.image_malloc) {
+ if(NULL == (copy_ptr = image_info.callbacks.image_malloc(image_info.size,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, image_info.callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed")
+ } /* end if */
+ else
+ if(NULL == (copy_ptr = H5MM_malloc(image_info.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate copy")
+
+ /* Copy data */
+ if(image_info.callbacks.image_memcpy) {
+ if(copy_ptr != image_info.callbacks.image_memcpy(copy_ptr, image_info.buffer,
+ image_info.size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET,
+ image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(copy_ptr, image_info.buffer, image_info.size);
+ } /* end if */
+
+ *buf_ptr_ptr = copy_ptr;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_file_image */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_image_callbacks
+ *
+ * Purpose: Sets the callbacks for file images. Some file drivers allow
+ * the use of user-defined callbacks for allocating, freeing and
+ * copying the drivers internal buffer, potentially allowing a
+ * clever user to do optimizations such as avoiding large mallocs
+ * and memcpys or to perform detailed logging.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, callbacks_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old info */
+ if(H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((info.buffer != NULL) && (info.size > 0)) ||
+ ((info.buffer == NULL) && (info.size == 0)));
+
+ /* Make sure a file image hasn't already been set */
+ if(info.buffer != NULL || info.size > 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "setting callbacks when an image is already set is forbidden. It could cause memory leaks.")
+
+ /* verify that callbacks_ptr is not NULL */
+ if(NULL == callbacks_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr")
+
+ /* Make sure udata callbacks are going to be set if udata is going to be set */
+ if(callbacks_ptr->udata)
+ if(callbacks_ptr->udata_copy == NULL || callbacks_ptr->udata_free == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "udata callbacks must be set if udata is set")
+
+ /* Release old udata if it exists */
+ if(info.callbacks.udata != NULL) {
+ HDassert(info.callbacks.udata_free);
+ if(info.callbacks.udata_free(info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed")
+ } /* end if */
+
+ /* Update struct */
+ info.callbacks = *callbacks_ptr;
+
+ if(callbacks_ptr->udata) {
+ HDassert(callbacks_ptr->udata_copy);
+ HDassert(callbacks_ptr->udata_free);
+ if((info.callbacks.udata = callbacks_ptr->udata_copy(callbacks_ptr->udata)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy the suppplied udata")
+ } /* end if */
+
+ /* Set values */
+ if(H5P_poke(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_file_image_callbacks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_image_callbacks
+ *
+ * Purpose: Sets the callbacks for file images. Some file drivers allow
+ * the use of user-defined callbacks for allocating, freeing and
+ * copying the drivers internal buffer, potentially allowing a
+ * clever user to do optimizations such as avoiding large mallocs
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, callbacks_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old info */
+ if(H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((info.buffer != NULL) && (info.size > 0)) ||
+ ((info.buffer == NULL) && (info.size == 0)));
+
+ /* verify that callbacks_ptr is not NULL */
+ if(NULL == callbacks_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr")
+
+ /* Transfer values to parameters */
+ *callbacks_ptr = info.callbacks;
+
+ /* Copy udata if it exists */
+ if(info.callbacks.udata != NULL) {
+ HDassert(info.callbacks.udata_copy);
+ if((callbacks_ptr->udata = info.callbacks.udata_copy(info.callbacks.udata)) == 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy udata")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_file_image_callbacks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__file_image_info_copy
+ *
+ * Purpose: Copy file image info. The buffer
+ * and udata may need to be copied, possibly using their
+ * respective callbacks so the default copy won't work.
+ *
+ * Note: This is an "in-place" copy, since this routine gets called
+ * after the top-level copy has been performed and this routine
+ * finishes the "deep" part of the copy.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__file_image_info_copy(void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(value) {
+ H5FD_file_image_info_t *info; /* Image info struct */
+
+ info = (H5FD_file_image_info_t *)value;
+
+ /* verify file image field consistancy */
+ HDassert(((info->buffer != NULL) && (info->size > 0)) ||
+ ((info->buffer == NULL) && (info->size == 0)));
+
+ if(info->buffer && info->size > 0) {
+ void *old_buffer; /* Pointer to old image buffer */
+
+ /* Store the old buffer */
+ old_buffer = info->buffer;
+
+ /* Allocate new buffer */
+ if(info->callbacks.image_malloc) {
+ if(NULL == (info->buffer = info->callbacks.image_malloc(info->size,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "image malloc callback failed")
+ } /* end if */
+ else {
+ if(NULL == (info->buffer = H5MM_malloc(info->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory block")
+ } /* end else */
+
+ /* Copy data to new buffer */
+ if(info->callbacks.image_memcpy) {
+ if(info->buffer != info->callbacks.image_memcpy(info->buffer, old_buffer,
+ info->size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(info->buffer, old_buffer, info->size);
+ } /* end if */
+
+ /* Copy udata if it exists */
+ if(info->callbacks.udata) {
+ void *old_udata = info->callbacks.udata;
+
+ if(NULL == info->callbacks.udata_copy)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "udata_copy not defined")
+
+ info->callbacks.udata = info->callbacks.udata_copy(old_udata);
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__file_image_info_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__file_image_info_free
+ *
+ * Purpose: Free file image info. The buffer and udata may need to be
+ * freed, possibly using their respective callbacks, so the
+ * default free won't work.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__file_image_info_free(void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ if(value) {
+ H5FD_file_image_info_t *info; /* Image info struct */
+
+ info = (H5FD_file_image_info_t *)value;
+
+ /* Verify file image field consistancy */
+ HDassert(((info->buffer != NULL) && (info->size > 0)) ||
+ ((info->buffer == NULL) && (info->size == 0)));
+
+ /* Free buffer */
+ if(info->buffer != NULL && info->size > 0) {
+ if(info->callbacks.image_free) {
+ if((*info->callbacks.image_free)(info->buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, info->callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(info->buffer);
+ } /* end if */
+
+ /* Free udata if it exists */
+ if(info->callbacks.udata) {
+ if(NULL == info->callbacks.udata_free)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "udata_free not defined")
+ if((*info->callbacks.udata_free)(info->callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "udata_free callback failed")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__file_image_info_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_image_config_cmp
+ *
+ * Purpose: Compare two cache image configurations.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if VALUE2 is
+ * greater than VALUE1 and zero if VALUE1 and VALUE2 are equal.
+ *
+ * Programmer: John Mainzer
+ * June 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__facc_cache_image_config_cmp(const void *_config1, const void *_config2, size_t H5_ATTR_UNUSED size)
+{
+ const H5AC_cache_image_config_t *config1 = (const H5AC_cache_image_config_t *)_config1; /* Create local aliases for values */
+ const H5AC_cache_image_config_t *config2 = (const H5AC_cache_image_config_t *)_config2; /* Create local aliases for values */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check for a property being set */
+ if(config1 == NULL && config2 != NULL) HGOTO_DONE(-1);
+ if(config1 != NULL && config2 == NULL) HGOTO_DONE(1);
+
+ if(config1->version < config2->version) HGOTO_DONE(-1);
+ if(config1->version > config2->version) HGOTO_DONE(1);
+
+ if(config1->generate_image < config2->generate_image) HGOTO_DONE(-1);
+ if(config1->generate_image > config2->generate_image) HGOTO_DONE(1);
+
+ if(config1->save_resize_status < config2->save_resize_status) HGOTO_DONE(-1);
+ if(config1->save_resize_status > config2->save_resize_status) HGOTO_DONE(1);
+
+ if(config1->entry_ageout < config2->entry_ageout) HGOTO_DONE(-1);
+ if(config1->entry_ageout > config2->entry_ageout) HGOTO_DONE(1);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_cache_image_config_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_image_config_enc
+ *
+ * Purpose: Callback routine which is called whenever the default
+ * cache image config property in the file creation
+ * property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: John Mainzer
+ * June 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_cache_image_config_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5AC_cache_image_config_t *config = (const H5AC_cache_image_config_t *)value; /* Create local aliases for value */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ if(NULL != *pp) {
+ /* Encode type sizes (as a safety check) */
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ INT32ENCODE(*pp, (int32_t)config->version);
+
+ H5_ENCODE_UNSIGNED(*pp, config->generate_image);
+
+ H5_ENCODE_UNSIGNED(*pp, config->save_resize_status);
+
+ INT32ENCODE(*pp, (int32_t)config->entry_ageout);
+ } /* end if */
+
+ /* Compute encoded size of fixed-size values */
+ *size += (1 + (2 * sizeof(unsigned)) + (2 * sizeof(int32_t)));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_cache_image_config_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_image_config_dec
+ *
+ * Purpose: Callback routine which is called whenever the default
+ * cache image config property in the file creation property
+ * list is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: John Mainzer
+ * June 26, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_cache_image_config_dec(const void **_pp, void *_value)
+{
+ H5AC_cache_image_config_t *config = (H5AC_cache_image_config_t *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(config);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Set property to default value */
+ HDmemcpy(config, &H5F_def_mdc_initCacheImageCfg_g, sizeof(H5AC_cache_image_config_t));
+
+ /* Decode type sizes */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ INT32DECODE(*pp, config->version);
+
+ H5_DECODE_UNSIGNED(*pp, config->generate_image);
+
+ H5_DECODE_UNSIGNED(*pp, config->save_resize_status);
+
+ INT32DECODE(*pp, config->entry_ageout);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_cache_image_config_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_set
+ *
+ * Purpose: Copies a file image property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_image_info_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of file image info */
+ if(H5P__file_image_info_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_get
+ *
+ * Purpose: Copies a file image property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_image_info_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of file image info */
+ if(H5P__file_image_info_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_del
+ *
+ * Purpose: Delete callback for the file image info property, called
+ * when the property is deleted from the plist. The buffer
+ * and udata may need to be freed, possibly using their
+ * respective callbacks so the default free won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_image_info_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Free the file image info */
+ if(H5P__file_image_info_free(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "can't release file image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_copy
+ *
+ * Purpose: Copy callback for the file image info property. The buffer
+ * and udata may need to be copied, possibly using their
+ * respective callbacks so the default copy won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_image_info_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Make copy of file image info */
+ if(H5P__file_image_info_copy(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy file image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_cmp
+ *
+ * Purpose: Callback routine which is called whenever the file image info
+ * property in the file access property list is compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__facc_file_image_info_cmp(const void *_info1, const void *_info2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5FD_file_image_info_t *info1 = (const H5FD_file_image_info_t *)_info1, /* Create local aliases for values */
+ *info2 = (const H5FD_file_image_info_t *)_info2;
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(info1);
+ HDassert(info2);
+ HDassert(size == sizeof(H5FD_file_image_info_t));
+
+ /* Check for different buffer sizes */
+ if(info1->size < info2->size) HGOTO_DONE(-1)
+ if(info1->size > info2->size) HGOTO_DONE(1)
+
+ /* Check for different callbacks */
+ /* (Order in memory is fairly meaningless, so just check for equality) */
+ if(info1->callbacks.image_malloc != info2->callbacks.image_malloc) HGOTO_DONE(1)
+ if(info1->callbacks.image_memcpy != info2->callbacks.image_memcpy) HGOTO_DONE(-1)
+ if(info1->callbacks.image_realloc != info2->callbacks.image_realloc) HGOTO_DONE(1)
+ if(info1->callbacks.image_free != info2->callbacks.image_free) HGOTO_DONE(-1)
+ if(info1->callbacks.udata_copy != info2->callbacks.udata_copy) HGOTO_DONE(1)
+ if(info1->callbacks.udata_free != info2->callbacks.udata_free) HGOTO_DONE(-1)
+
+ /* Check for different udata */
+ /* (Don't know how big it is, so can't check contents) */
+ if(info1->callbacks.udata < info2->callbacks.udata) HGOTO_DONE(-1)
+ if(info1->callbacks.udata > info2->callbacks.udata) HGOTO_DONE(1)
+
+ /* Check buffer contents (instead of buffer pointers) */
+ if(info1->buffer != NULL && info2->buffer == NULL) HGOTO_DONE(-1)
+ if(info1->buffer == NULL && info2->buffer != NULL) HGOTO_DONE(1)
+ if(info1->buffer != NULL && info2->buffer != NULL)
+ ret_value = HDmemcmp(info1->buffer, info2->buffer, size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_file_image_info_close
+ *
+ * Purpose: Close callback for the file image info property. The buffer
+ * and udata may need to be freed, possibly using their
+ * respective callbacks so the standard free won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_file_image_info_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Free the file image info */
+ if(H5P__file_image_info_free(value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "can't release file image info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_file_image_info_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_config_cmp
+ *
+ * Purpose: Compare two cache configurations.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if VALUE2 is
+ * greater than VALUE1 and zero if VALUE1 and VALUE2 are equal.
+ *
+ * Programmer: Mohamad Chaarawi
+ * September 24, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__facc_cache_config_cmp(const void *_config1, const void *_config2, size_t H5_ATTR_UNUSED size)
+{
+ const H5AC_cache_config_t *config1 = (const H5AC_cache_config_t *)_config1; /* Create local aliases for values */
+ const H5AC_cache_config_t *config2 = (const H5AC_cache_config_t *)_config2; /* Create local aliases for values */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check for a property being set */
+ if(config1 == NULL && config2 != NULL) HGOTO_DONE(-1);
+ if(config1 != NULL && config2 == NULL) HGOTO_DONE(1);
+
+ if(config1->version < config2->version) HGOTO_DONE(-1);
+ if(config1->version > config2->version) HGOTO_DONE(1);
+
+ if(config1->rpt_fcn_enabled < config2->rpt_fcn_enabled) HGOTO_DONE(-1);
+ if(config1->rpt_fcn_enabled > config2->rpt_fcn_enabled) HGOTO_DONE(1);
+
+ if(config1->evictions_enabled < config2->evictions_enabled) HGOTO_DONE(-1);
+ if(config1->evictions_enabled > config2->evictions_enabled) HGOTO_DONE(1);
+
+ if(config1->set_initial_size < config2->set_initial_size) HGOTO_DONE(-1);
+ if(config1->set_initial_size > config2->set_initial_size) HGOTO_DONE(1);
+
+ if(config1->initial_size < config2->initial_size) HGOTO_DONE(-1);
+ if(config1->initial_size > config2->initial_size) HGOTO_DONE(1);
+
+ if(config1->min_clean_fraction < config2->min_clean_fraction) HGOTO_DONE(-1);
+ if(config1->min_clean_fraction > config2->min_clean_fraction) HGOTO_DONE(1);
+
+ if(config1->max_size < config2->max_size) HGOTO_DONE(-1);
+ if(config1->max_size > config2->max_size) HGOTO_DONE(1);
+
+ if(config1->min_size < config2->min_size) HGOTO_DONE(-1);
+ if(config1->min_size > config2->min_size) HGOTO_DONE(1);
+
+ if(config1->epoch_length < config2->epoch_length) HGOTO_DONE(-1);
+ if(config1->epoch_length > config2->epoch_length) HGOTO_DONE(1);
+
+ if(config1->incr_mode < config2->incr_mode) HGOTO_DONE(-1);
+ if(config1->incr_mode > config2->incr_mode) HGOTO_DONE(1);
+
+ if(config1->lower_hr_threshold < config2->lower_hr_threshold) HGOTO_DONE(-1);
+ if(config1->lower_hr_threshold > config2->lower_hr_threshold) HGOTO_DONE(1);
+
+ if(config1->increment < config2->increment) HGOTO_DONE(-1);
+ if(config1->increment > config2->increment) HGOTO_DONE(1);
+
+ if(config1->apply_max_increment < config2->apply_max_increment) HGOTO_DONE(-1);
+ if(config1->apply_max_increment > config2->apply_max_increment) HGOTO_DONE(1);
+
+ if(config1->max_increment < config2->max_increment) HGOTO_DONE(-1);
+ if(config1->max_increment > config2->max_increment) HGOTO_DONE(1);
+
+ if(config1->flash_incr_mode < config2->flash_incr_mode) HGOTO_DONE(-1);
+ if(config1->flash_incr_mode > config2->flash_incr_mode) HGOTO_DONE(1);
+
+ if(config1->flash_multiple < config2->flash_multiple) HGOTO_DONE(-1);
+ if(config1->flash_multiple > config2->flash_multiple) HGOTO_DONE(1);
+
+ if(config1->flash_threshold < config2->flash_threshold) HGOTO_DONE(-1);
+ if(config1->flash_threshold > config2->flash_threshold) HGOTO_DONE(1);
+
+ if(config1->decr_mode < config2->decr_mode) HGOTO_DONE(-1);
+ if(config1->decr_mode > config2->decr_mode) HGOTO_DONE(1);
+
+ if(config1->upper_hr_threshold < config2->upper_hr_threshold) HGOTO_DONE(-1);
+ if(config1->upper_hr_threshold > config2->upper_hr_threshold) HGOTO_DONE(1);
+
+ if(config1->decrement < config2->decrement) HGOTO_DONE(-1);
+ if(config1->decrement > config2->decrement) HGOTO_DONE(1);
+
+ if(config1->apply_max_decrement < config2->apply_max_decrement) HGOTO_DONE(-1);
+ if(config1->apply_max_decrement > config2->apply_max_decrement) HGOTO_DONE(1);
+
+ if(config1->max_decrement < config2->max_decrement) HGOTO_DONE(-1);
+ if(config1->max_decrement > config2->max_decrement) HGOTO_DONE(1);
+
+ if(config1->epochs_before_eviction < config2->epochs_before_eviction) HGOTO_DONE(-1);
+ if(config1->epochs_before_eviction > config2->epochs_before_eviction) HGOTO_DONE(1);
+
+ if(config1->apply_empty_reserve < config2->apply_empty_reserve) HGOTO_DONE(-1);
+ if(config1->apply_empty_reserve > config2->apply_empty_reserve) HGOTO_DONE(1);
+
+ if(config1->empty_reserve < config2->empty_reserve) HGOTO_DONE(-1);
+ if(config1->empty_reserve > config2->empty_reserve) HGOTO_DONE(1);
+
+ if(config1->dirty_bytes_threshold < config2->dirty_bytes_threshold) HGOTO_DONE(-1);
+ if(config1->dirty_bytes_threshold > config2->dirty_bytes_threshold) HGOTO_DONE(1);
+
+ if(config1->metadata_write_strategy < config2->metadata_write_strategy) HGOTO_DONE(-1);
+ if(config1->metadata_write_strategy > config2->metadata_write_strategy) HGOTO_DONE(1);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_cache_config_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_config_enc
+ *
+ * Purpose: Callback routine which is called whenever the default
+ * cache config property in the file creation property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 09, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_cache_config_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5AC_cache_config_t *config = (const H5AC_cache_config_t *)value; /* Create local aliases for values */
+ uint8_t **pp = (uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ uint64_t enc_value; /* Property to encode */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ if(NULL != *pp) {
+ /* Encode type sizes (as a safety check) */
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+ *(*pp)++ = (uint8_t)sizeof(double);
+
+ /* int */
+ INT32ENCODE(*pp, (int32_t)config->version);
+
+ H5_ENCODE_UNSIGNED(*pp, config->rpt_fcn_enabled);
+
+ H5_ENCODE_UNSIGNED(*pp, config->open_trace_file);
+
+ H5_ENCODE_UNSIGNED(*pp, config->close_trace_file);
+
+ HDmemcpy(*pp, (const uint8_t *)(config->trace_file_name), (size_t)(H5AC__MAX_TRACE_FILE_NAME_LEN + 1));
+ *pp += H5AC__MAX_TRACE_FILE_NAME_LEN + 1;
+
+ H5_ENCODE_UNSIGNED(*pp, config->evictions_enabled);
+
+ H5_ENCODE_UNSIGNED(*pp, config->set_initial_size);
+
+ enc_value = (uint64_t)config->initial_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ H5_ENCODE_DOUBLE(*pp, config->min_clean_fraction);
+
+ enc_value = (uint64_t)config->max_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ enc_value = (uint64_t)config->min_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* long int */
+ INT64ENCODE(*pp, (int64_t)config->epoch_length);
+
+ /* enum */
+ *(*pp)++ = (uint8_t)config->incr_mode;
+
+ H5_ENCODE_DOUBLE(*pp, config->lower_hr_threshold);
+
+ H5_ENCODE_DOUBLE(*pp, config->increment);
+
+ H5_ENCODE_UNSIGNED(*pp, config->apply_max_increment);
+
+ enc_value = (uint64_t)config->max_increment;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* enum */
+ *(*pp)++ = (uint8_t)config->flash_incr_mode;
+
+ H5_ENCODE_DOUBLE(*pp, config->flash_multiple);
+
+ H5_ENCODE_DOUBLE(*pp, config->flash_threshold);
+
+ /* enum */
+ *(*pp)++ = (uint8_t)config->decr_mode;
+
+ H5_ENCODE_DOUBLE(*pp, config->upper_hr_threshold);
+
+ H5_ENCODE_DOUBLE(*pp, config->decrement);
+
+ H5_ENCODE_UNSIGNED(*pp, config->apply_max_decrement);
+
+ enc_value = (uint64_t)config->max_decrement;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* int */
+ INT32ENCODE(*pp, (int32_t)config->epochs_before_eviction);
+
+ H5_ENCODE_UNSIGNED(*pp, config->apply_empty_reserve);
+
+ H5_ENCODE_DOUBLE(*pp, config->empty_reserve);
+
+ /* unsigned */
+ UINT32ENCODE(*pp, (uint32_t)config->dirty_bytes_threshold);
+
+ /* int */
+ INT32ENCODE(*pp, (int32_t)config->metadata_write_strategy);
+ } /* end if */
+
+ /* Compute encoded size of variably-encoded values */
+ enc_value = (uint64_t)config->initial_size;
+ *size += 1 + H5VM_limit_enc_size(enc_value);
+ enc_value = (uint64_t)config->max_size;
+ *size += 1 + H5VM_limit_enc_size(enc_value);
+ enc_value = (uint64_t)config->min_size;
+ *size += 1 + H5VM_limit_enc_size(enc_value);
+ enc_value = (uint64_t)config->max_increment;
+ *size += 1 + H5VM_limit_enc_size(enc_value);
+ enc_value = (uint64_t)config->max_decrement;
+ *size += 1 + H5VM_limit_enc_size(enc_value);
+
+ /* Compute encoded size of fixed-size values */
+ *size += (5 + (sizeof(unsigned) * 8) + (sizeof(double) * 8) +
+ (sizeof(int32_t) * 4) + sizeof(int64_t) +
+ H5AC__MAX_TRACE_FILE_NAME_LEN + 1);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_cache_config_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_cache_config_dec
+ *
+ * Purpose: Callback routine which is called whenever the default
+ * cache config property in the file creation property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 09, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_cache_config_dec(const void **_pp, void *_value)
+{
+ H5AC_cache_config_t *config = (H5AC_cache_config_t *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size;
+ uint64_t enc_value;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(config);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Set property to default value */
+ HDmemcpy(config, &H5F_def_mdc_initCacheCfg_g, sizeof(H5AC_cache_config_t));
+
+ /* Decode type sizes */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(double))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "double value can't be decoded")
+
+ /* int */
+ INT32DECODE(*pp, config->version);
+
+ H5_DECODE_UNSIGNED(*pp, config->rpt_fcn_enabled);
+
+ H5_DECODE_UNSIGNED(*pp, config->open_trace_file);
+
+ H5_DECODE_UNSIGNED(*pp, config->close_trace_file);
+
+ HDstrcpy(config->trace_file_name, (const char *)(*pp));
+ *pp += H5AC__MAX_TRACE_FILE_NAME_LEN + 1;
+
+ H5_DECODE_UNSIGNED(*pp, config->evictions_enabled);
+
+ H5_DECODE_UNSIGNED(*pp, config->set_initial_size);
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ config->initial_size = (size_t)enc_value;
+
+ H5_DECODE_DOUBLE(*pp, config->min_clean_fraction);
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ config->max_size = (size_t)enc_value;
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ config->min_size = (size_t)enc_value;
+
+ /* long int */
+ {
+ int64_t temp;
+ INT64DECODE(*pp, temp);
+ config->epoch_length = (long int)temp;
+ }
+ /* enum */
+ config->incr_mode = (enum H5C_cache_incr_mode)*(*pp)++;
+
+ H5_DECODE_DOUBLE(*pp, config->lower_hr_threshold);
+
+ H5_DECODE_DOUBLE(*pp, config->increment);
+
+ H5_DECODE_UNSIGNED(*pp, config->apply_max_increment);
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ config->max_increment = (size_t)enc_value;
+
+ /* enum */
+ config->flash_incr_mode = (enum H5C_cache_flash_incr_mode)*(*pp)++;
+
+ H5_DECODE_DOUBLE(*pp, config->flash_multiple);
+
+ H5_DECODE_DOUBLE(*pp, config->flash_threshold);
+
+ /* enum */
+ config->decr_mode = (enum H5C_cache_decr_mode)*(*pp)++;
+
+ H5_DECODE_DOUBLE(*pp, config->upper_hr_threshold);
+
+ H5_DECODE_DOUBLE(*pp, config->decrement);
+
+ H5_DECODE_UNSIGNED(*pp, config->apply_max_decrement);
+
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ config->max_decrement = (size_t)enc_value;
+
+ /* int */
+ INT32DECODE(*pp, config->epochs_before_eviction);
+
+ H5_DECODE_UNSIGNED(*pp, config->apply_empty_reserve);
+
+ H5_DECODE_DOUBLE(*pp, config->empty_reserve);
+
+ /* unsigned */
+ UINT32DECODE(*pp, config->dirty_bytes_threshold);
+
+ /* int */
+ INT32DECODE(*pp, config->metadata_write_strategy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__facc_cache_config_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_fclose_degree_enc
+ *
+ * Purpose: Callback routine which is called whenever the file close
+ * degree property in the file access property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_fclose_degree_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5F_close_degree_t *fclose_degree = (const H5F_close_degree_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(fclose_degree);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode file close degree */
+ *(*pp)++ = (uint8_t)*fclose_degree;
+
+ /* Size of file close degree */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_fclose_degree_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_fclose_degree_dec
+ *
+ * Purpose: Callback routine which is called whenever the file close
+ * degree property in the file access property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_fclose_degree_dec(const void **_pp, void *_value)
+{
+ H5F_close_degree_t *fclose_degree = (H5F_close_degree_t *)_value; /* File close degree */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(fclose_degree);
+
+ /* Decode file close degree */
+ *fclose_degree = (H5F_close_degree_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_fclose_degree_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_multi_type_enc
+ *
+ * Purpose: Callback routine which is called whenever the multi VFD
+ * memory type property in the file access property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_multi_type_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5FD_mem_t *type = (const H5FD_mem_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(type);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode file close degree */
+ *(*pp)++ = (uint8_t)*type;
+
+ /* Size of multi VFD memory type */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_multi_type_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__facc_multi_type_dec
+ *
+ * Purpose: Callback routine which is called whenever the multi VFD
+ * memory type property in the file access property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__facc_multi_type_dec(const void **_pp, void *_value)
+{
+ H5FD_mem_t *type = (H5FD_mem_t *)_value; /* File close degree */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(type);
+
+ /* Decode multi VFD memory type */
+ *type = (H5FD_mem_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__facc_multi_type_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_core_write_tracking
+ *
+ * Purpose: Enables/disables core VFD write tracking and page
+ * aggregation size.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Tuesday, April 8, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_core_write_tracking(hid_t plist_id, hbool_t is_enabled, size_t page_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ibz", plist_id, is_enabled, page_size);
+
+ /* The page size cannot be zero */
+ if(page_size == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "page_size cannot be zero")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME, &is_enabled) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set core VFD write tracking flag")
+ if(H5P_set(plist, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME, &page_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set core VFD write tracking page size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_core_write_tracking() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_core_write_tracking
+ *
+ * Purpose: Gets information about core VFD write tracking and page
+ * aggregation size.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * Tuesday, April 8, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_core_write_tracking(hid_t plist_id, hbool_t *is_enabled, size_t *page_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*b*z", plist_id, is_enabled, page_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(is_enabled) {
+ if(H5P_get(plist, H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME, is_enabled) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get core VFD write tracking flag")
+ } /* end if */
+
+ if(page_size) {
+ if(H5P_get(plist, H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME, page_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get core VFD write tracking page size")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_core_write_tracking() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_metadata_read_attempts
+ *
+ * Purpose: Sets the # of read attempts in the file access property list
+ * when reading metadata with checksum.
+ * The # of read attempts set via this routine will only apply
+ * when opening a file with SWMR access.
+ * The # of read attempts set via this routine does not have
+ * any effect when opening a file with non-SWMR access; for this
+ * case, the # of read attempts will be always be 1.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, attempts);
+
+ /* Cannot set the # of attempts to 0 */
+ if(attempts == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "number of metadatata read attempts must be greater than 0");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &attempts) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set # of metadata read attempts")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_metadata_read_attempts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_metadata_read_attempts
+ *
+ * Purpose: Returns the # of metadata read attempts set in the file access property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Sept 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_metadata_read_attempts(hid_t plist_id, unsigned *attempts/*out*/)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, attempts);
+
+ /* Get values */
+ if(attempts) {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the # of read attempts set */
+ if(H5P_get(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, attempts) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get the number of metadata read attempts")
+
+ /* If not set, return the default value */
+ if(*attempts == H5F_ACS_METADATA_READ_ATTEMPTS_DEF) /* 0 */
+ *attempts = H5F_METADATA_READ_ATTEMPTS;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_metadata_read_attempts() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_obj_flush_cb
+ *
+ * Purpose: Sets the callback function to invoke and the user data when an
+ * object flush occurs in the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5F_object_flush_t flush_info;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", plist_id, func, udata);
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && udata)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ flush_info.func = func;
+ flush_info.udata = udata;
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &flush_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_obj_flush_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_obj_flush_cb
+ *
+ * Purpose: Retrieves the callback function and user data set in the
+ * property list for an object flush.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5F_object_flush_t flush_info;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", plist_id, func, udata);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the callback function and user data */
+ if(H5P_get(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &flush_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object flush callback")
+
+ /* Assign return value */
+ if(func)
+ *func = flush_info.func;
+ if(udata)
+ *udata = flush_info.udata;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_obj_flush_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_mdc_log_options
+ *
+ * Purpose: Set metadata cache log options.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_mdc_log_options(hid_t plist_id, hbool_t is_enabled, const char *location,
+ hbool_t start_on_access)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ char * tmp_location; /* Working location pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "ib*sb", plist_id, is_enabled, location, start_on_access);
+
+ /* Check arguments */
+ if(H5P_DEFAULT == plist_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't modify default property list")
+ if(!location)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "location cannot be NULL")
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plist_id is not a file access property list")
+
+ /* Get the current location string and free it */
+ if(H5P_get(plist, H5F_ACS_MDC_LOG_LOCATION_NAME, &tmp_location) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get current log location")
+ H5MM_xfree(tmp_location);
+
+ /* Make a copy of the passed-in location */
+ if(NULL == (tmp_location = H5MM_xstrdup(location)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy passed-in log location")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_USE_MDC_LOGGING_NAME, &is_enabled) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set is_enabled flag")
+ if(H5P_set(plist, H5F_ACS_MDC_LOG_LOCATION_NAME, &tmp_location) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set log location")
+ if(H5P_set(plist, H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME, &start_on_access) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set start_on_access flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_mdc_log_options() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mdc_log_options
+ *
+ * Purpose: Get metadata cache log options.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mdc_log_options(hid_t plist_id, hbool_t *is_enabled, char *location,
+ size_t *location_size, hbool_t *start_on_access)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ char *location_ptr; /* Pointer to location string */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*b*s*z*b", plist_id, is_enabled, location, location_size,
+ start_on_access);
+
+ /* Get the property list structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plist_id is not a file access property list")
+
+ /* Get simple values */
+ if(is_enabled)
+ if(H5P_get(plist, H5F_ACS_USE_MDC_LOGGING_NAME, is_enabled) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get log location")
+ if(start_on_access)
+ if(H5P_get(plist, H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME, start_on_access) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get start_on_access flag")
+
+ /* Get the location */
+ if(location || location_size)
+ if(H5P_get(plist, H5F_ACS_MDC_LOG_LOCATION_NAME, &location_ptr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get log location")
+
+ /* Copy log location to output buffer */
+ if(location_ptr && location)
+ HDmemcpy(location, location_ptr, *location_size);
+
+ /* Get location size, including terminating NULL */
+ if(location_size) {
+ if(location_ptr)
+ *location_size = HDstrlen(location_ptr) + 1;
+ else
+ *location_size = 0;
+ }
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_mdc_log_options() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_enc
+ *
+ * Purpose: Callback routine which is called whenever the metadata
+ * cache log location property in the file access property
+ * list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_facc_mdc_log_location_enc(const void *value, void **_pp, size_t *size)
+{
+ const char *log_location = *(const char * const *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+ size_t len = 0;
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* calculate prefix length */
+ if(NULL != log_location)
+ len = HDstrlen(log_location);
+
+ enc_value = (uint64_t)len;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+
+ if(NULL != *pp) {
+ /* encode the length of the prefix */
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode the prefix */
+ if(NULL != log_location) {
+ HDmemcpy(*(char **)pp, log_location, len);
+ *pp += len;
+ } /* end if */
+ } /* end if */
+
+ *size += (1 + enc_size);
+ if(NULL != log_location)
+ *size += len;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P_facc_mdc_log_location_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_dec
+ *
+ * Purpose: Callback routine which is called whenever the metadata
+ * cache log location property in the file access property
+ * list is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_facc_mdc_log_location_dec(const void **_pp, void *_value)
+{
+ char **log_location = (char **)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ size_t len;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(log_location);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ len = enc_value;
+
+ if(0 != len) {
+ /* Make a copy of the user's prefix string */
+ if(NULL == (*log_location = (char *)H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for prefix")
+ HDstrncpy(*log_location, *(const char **)pp, len);
+ (*log_location)[len] = '\0';
+
+ *pp += len;
+ } /* end if */
+ else
+ *log_location = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_facc_mdc_log_location_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_del
+ *
+ * Purpose: Frees memory used to store the metadata cache log location.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_facc_mdc_log_location_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P_facc_mdc_log_location_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_copy
+ *
+ * Purpose: Creates a copy of the metadata cache log location string.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_facc_mdc_log_location_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P_facc_mdc_log_location_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_cmp
+ *
+ * Purpose: Callback routine which is called whenever the metadata
+ * cache log location property in the file creation property
+ * list is compared.
+ *
+ * Return: zero if VALUE1 and VALUE2 are equal, non zero otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P_facc_mdc_log_location_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size)
+{
+ const char *pref1 = *(const char * const *)value1;
+ const char *pref2 = *(const char * const *)value2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(NULL == pref1 && NULL != pref2)
+ HGOTO_DONE(1);
+ if(NULL != pref1 && NULL == pref2)
+ HGOTO_DONE(-1);
+ if(NULL != pref1 && NULL != pref2)
+ ret_value = HDstrcmp(pref1, pref2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_facc_mdc_log_location_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_facc_mdc_log_location_close
+ *
+ * Purpose: Frees memory used to store the metadata cache log location
+ * string
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_facc_mdc_log_location_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P_facc_mdc_log_location_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_evict_on_close
+ *
+ * Purpose: Sets the evict_on_close property value.
+ *
+ * When this property is set, closing an HDF5 object will
+ * cause the object's metadata cache entries to be flushed
+ * and evicted from the cache.
+ *
+ * Currently only implemented for datasets.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Spring 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_evict_on_close(hid_t fapl_id, hbool_t evict_on_close)
+{
+ H5P_genplist_t *plist; /* property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", fapl_id, evict_on_close);
+
+ /* Compare the property list's class against the other class */
+ if(TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not a file access plist")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+#ifndef H5_HAVE_PARALLEL
+ /* Set value */
+ if(H5P_set(plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, &evict_on_close) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set evict on close property")
+#else
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "evict on close is currently not supported in parallel HDF5")
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_evict_on_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_evict_on_close
+ *
+ * Purpose: Gets the evict_on_close property value.
+ *
+ * When this property is set, closing an HDF5 object will
+ * cause the object's metadata cache entries to be flushed
+ * and evicted from the cache.
+ *
+ * Currently only implemented for datasets.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Spring 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_evict_on_close(hid_t fapl_id, hbool_t *evict_on_close)
+{
+ H5P_genplist_t *plist; /* property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", fapl_id, evict_on_close);
+
+ /* Compare the property list's class against the other class */
+ if(TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not an access plist")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_get(plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, evict_on_close) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get evict on close property")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_evict_on_close() */
+
+#ifdef H5_HAVE_PARALLEL
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__encode_coll_md_read_flag_t
+ *
+ * Purpose: Generic encoding callback routine for 'coll_md_read_flag' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__encode_coll_md_read_flag_t(const void *value, void **_pp, size_t *size)
+{
+ const H5P_coll_md_read_flag_t *coll_md_read_flag = (const H5P_coll_md_read_flag_t *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(coll_md_read_flag);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ /* Encode the value */
+ HDmemcpy(*pp, coll_md_read_flag, sizeof(H5P_coll_md_read_flag_t));
+ *pp += sizeof(H5P_coll_md_read_flag_t);
+ } /* end if */
+
+ /* Set size needed for encoding */
+ *size += sizeof(H5P_coll_md_read_flag_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__encode_coll_md_read_flag_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__decode_coll_md_read_flag_t
+ *
+ * Purpose: Generic decoding callback routine for 'coll_md_read_flag' properties.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P__decode_coll_md_read_flag_t(const void **_pp, void *_value)
+{
+ H5P_coll_md_read_flag_t *coll_md_read_flag = (H5P_coll_md_read_flag_t *)_value; /* File close degree */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(coll_md_read_flag);
+
+ /* Decode file close degree */
+ *coll_md_read_flag = (H5P_coll_md_read_flag_t)*(*pp);
+ *pp += sizeof(H5P_coll_md_read_flag_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__decode_coll_md_read_flag_t() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_all_coll_metadata_ops
+ *
+ * Purpose: Tell the library whether the metadata read operations will
+ * be done collectively (1) or not (0). Default is independent.
+ * With collective mode, the library will optimize access to
+ * metadata operations on the file.
+ *
+ * Note: This routine accepts file access property lists, link
+ * access property lists, attribute access property lists,
+ * dataset access property lists, group access property lists,
+ * named datatype access property lists,
+ * and dataset transfer property lists.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_all_coll_metadata_ops(hid_t plist_id, hbool_t is_collective)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5P_coll_md_read_flag_t coll_meta_read; /* Property value */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", plist_id, is_collective);
+
+ /* Compare the property list's class against the other class */
+ /* (Dataset, group, attribute, and named datype access property lists
+ * are sub-classes of link access property lists -QAK)
+ */
+ if(TRUE != H5P_isa_class(plist_id, H5P_LINK_ACCESS) &&
+ TRUE != H5P_isa_class(plist_id, H5P_FILE_ACCESS) &&
+ TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not an access plist")
+
+ /* set property to either TRUE if > 0, or FALSE otherwise */
+ if(is_collective)
+ coll_meta_read = H5P_USER_TRUE;
+ else
+ coll_meta_read = H5P_USER_FALSE;
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5_COLL_MD_READ_FLAG_NAME, &coll_meta_read) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set collective metadata read flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_all_coll_metadata_ops() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_all_coll_metadata_ops
+ *
+ * Purpose: Gets information about collective metadata read mode.
+ *
+ * Note: This routine accepts file access property lists, link
+ * access property lists, attribute access property lists,
+ * dataset access property lists, group access property lists,
+ * named datatype access property lists,
+ * and dataset transfer property lists.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_all_coll_metadata_ops(hid_t plist_id, hbool_t *is_collective)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", plist_id, is_collective);
+
+ /* Compare the property list's class against the other class */
+ /* (Dataset, group, attribute, and named datype access property lists
+ * are sub-classes of link access property lists -QAK)
+ */
+ if(TRUE != H5P_isa_class(plist_id, H5P_LINK_ACCESS) &&
+ TRUE != H5P_isa_class(plist_id, H5P_FILE_ACCESS) &&
+ TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not an access plist")
+
+ /* Get value */
+ if(is_collective) {
+ H5P_coll_md_read_flag_t internal_flag; /* property setting. we need to convert to either TRUE or FALSE */
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_get(plist, H5_COLL_MD_READ_FLAG_NAME, &internal_flag) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get core collective metadata read flag")
+
+ if(internal_flag < 0)
+ *is_collective = FALSE;
+ else
+ *is_collective = (hbool_t)internal_flag;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_all_coll_metadata_ops */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_coll_metadata_write
+ *
+ * Purpose: Tell the library whether the metadata write operations will
+ * be done collectively (1) or not (0). Default is collective.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_coll_metadata_write(hid_t plist_id, hbool_t is_collective)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", plist_id, is_collective);
+
+ /* Compare the property list's class against the other class */
+ if(TRUE != H5P_isa_class(plist_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not a file access plist")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, &is_collective) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set collective metadata write flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_coll_metadata_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_coll_metadata_write
+ *
+ * Purpose: Gets information about collective metadata write mode.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_coll_metadata_write(hid_t plist_id, hbool_t *is_collective)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", plist_id, is_collective);
+
+ /* Compare the property list's class against the other class */
+ if(TRUE != H5P_isa_class(plist_id, H5P_FILE_ACCESS))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not an access plist")
+
+ /* Get the plist structure */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_get(plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, is_collective) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get collective metadata write flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_coll_metadata_write() */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_page_buffer_size
+ *
+ * Purpose: Set the maximum page buffering size. This has to be a
+ * multiple of the page allocation size which must be enabled;
+ * otherwise file create/open will fail.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * June 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_page_buffer_size(hid_t plist_id, size_t buf_size, unsigned min_meta_perc, unsigned min_raw_perc)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "izIuIu", plist_id, buf_size, min_meta_perc, min_raw_perc);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(min_meta_perc > 100)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Minimum metadata fractions must be between 0 and 100 inclusive")
+ if(min_raw_perc > 100)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Minimum rawdata fractions must be between 0 and 100 inclusive")
+
+ if(min_meta_perc + min_raw_perc > 100)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Sum of minimum metadata and raw data fractions can't be bigger than 100");
+
+ /* Set size */
+ if(H5P_set(plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, &buf_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set page buffer size")
+ if(H5P_set(plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, &min_meta_perc) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set percentage of min metadata entries")
+ if(H5P_set(plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &min_raw_perc) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set percentage of min rawdata entries")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_page_buffer_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_page_buffer_size
+ *
+ * Purpose: Retrieves the maximum page buffer size.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * June 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_page_buffer_size(hid_t plist_id, size_t *buf_size, unsigned *min_meta_perc, unsigned *min_raw_perc)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*z*Iu*Iu", plist_id, buf_size, min_meta_perc, min_raw_perc);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get size */
+
+ if(buf_size)
+ if(H5P_get(plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, buf_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get page buffer size")
+ if(min_meta_perc)
+ if(H5P_get(plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, min_meta_perc) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get page buffer minimum metadata percent")
+ if(min_raw_perc)
+ if(H5P_get(plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, min_raw_perc) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get page buffer minimum raw data percent")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_page_buffer_size() */
+
diff --git a/src/H5Pfcpl.c b/src/H5Pfcpl.c
new file mode 100644
index 0000000..5383aae
--- /dev/null
+++ b/src/H5Pfcpl.c
@@ -0,0 +1,1517 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pfcpl.c
+ * January 6 1998
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: File creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Bprivate.h" /* B-tree subclass names */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5SMprivate.h" /* Shared object header messages */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= File Creation properties ============ */
+/* Definitions for the size of the file user block in bytes */
+#define H5F_CRT_USER_BLOCK_SIZE sizeof(hsize_t)
+#define H5F_CRT_USER_BLOCK_DEF 0
+#define H5F_CRT_USER_BLOCK_ENC H5P__encode_hsize_t
+#define H5F_CRT_USER_BLOCK_DEC H5P__decode_hsize_t
+/* Definitions for the 1/2 rank for symbol table leaf nodes */
+#define H5F_CRT_SYM_LEAF_SIZE sizeof(unsigned)
+#define H5F_CRT_SYM_LEAF_ENC H5P__encode_unsigned
+#define H5F_CRT_SYM_LEAF_DEC H5P__decode_unsigned
+/* Definitions for the 1/2 rank for btree internal nodes */
+#define H5F_CRT_BTREE_RANK_SIZE sizeof(unsigned[H5B_NUM_BTREE_ID])
+#define H5F_CRT_BTREE_RANK_DEF {HDF5_BTREE_SNODE_IK_DEF,HDF5_BTREE_CHUNK_IK_DEF}
+#define H5F_CRT_BTREE_RANK_ENC H5P__fcrt_btree_rank_enc
+#define H5F_CRT_BTREE_RANK_DEC H5P__fcrt_btree_rank_dec
+/* Definitions for byte number in an address */
+#define H5F_CRT_ADDR_BYTE_NUM_SIZE sizeof(uint8_t)
+#define H5F_CRT_ADDR_BYTE_NUM_DEF H5F_OBJ_ADDR_SIZE
+#define H5F_CRT_ADDR_BYTE_NUM_ENC H5P__encode_uint8_t
+#define H5F_CRT_ADDR_BYTE_NUM_DEC H5P__decode_uint8_t
+/* Definitions for byte number for object size */
+#define H5F_CRT_OBJ_BYTE_NUM_SIZE sizeof(uint8_t)
+#define H5F_CRT_OBJ_BYTE_NUM_DEF H5F_OBJ_SIZE_SIZE
+#define H5F_CRT_OBJ_BYTE_NUM_ENC H5P__encode_uint8_t
+#define H5F_CRT_OBJ_BYTE_NUM_DEC H5P__decode_uint8_t
+/* Definitions for version number of the superblock */
+#define H5F_CRT_SUPER_VERS_SIZE sizeof(unsigned)
+#define H5F_CRT_SUPER_VERS_DEF HDF5_SUPERBLOCK_VERSION_DEF
+/* Definitions for shared object header messages */
+#define H5F_CRT_SHMSG_NINDEXES_SIZE sizeof(unsigned)
+#define H5F_CRT_SHMSG_NINDEXES_DEF (0)
+#define H5F_CRT_SHMSG_NINDEXES_ENC H5P__encode_unsigned
+#define H5F_CRT_SHMSG_NINDEXES_DEC H5P__decode_unsigned
+#define H5F_CRT_SHMSG_INDEX_TYPES_SIZE sizeof(unsigned[H5O_SHMESG_MAX_NINDEXES])
+#define H5F_CRT_SHMSG_INDEX_TYPES_DEF {0,0,0,0,0,0}
+#define H5F_CRT_SHMSG_INDEX_TYPES_ENC H5P__fcrt_shmsg_index_types_enc
+#define H5F_CRT_SHMSG_INDEX_TYPES_DEC H5P__fcrt_shmsg_index_types_dec
+#define H5F_CRT_SHMSG_INDEX_MINSIZE_SIZE sizeof(unsigned[H5O_SHMESG_MAX_NINDEXES])
+#define H5F_CRT_SHMSG_INDEX_MINSIZE_DEF {250,250,250,250,250,250}
+#define H5F_CRT_SHMSG_INDEX_MINSIZE_ENC H5P__fcrt_shmsg_index_minsize_enc
+#define H5F_CRT_SHMSG_INDEX_MINSIZE_DEC H5P__fcrt_shmsg_index_minsize_dec
+/* Definitions for shared object header list/btree phase change cutoffs */
+#define H5F_CRT_SHMSG_LIST_MAX_SIZE sizeof(unsigned)
+#define H5F_CRT_SHMSG_LIST_MAX_DEF (50)
+#define H5F_CRT_SHMSG_LIST_MAX_ENC H5P__encode_unsigned
+#define H5F_CRT_SHMSG_LIST_MAX_DEC H5P__decode_unsigned
+#define H5F_CRT_SHMSG_BTREE_MIN_SIZE sizeof(unsigned)
+#define H5F_CRT_SHMSG_BTREE_MIN_DEF (40)
+#define H5F_CRT_SHMSG_BTREE_MIN_ENC H5P__encode_unsigned
+#define H5F_CRT_SHMSG_BTREE_MIN_DEC H5P__decode_unsigned
+/* Definitions for file space handling strategy */
+#define H5F_CRT_FILE_SPACE_STRATEGY_SIZE sizeof(H5F_fspace_strategy_t)
+#define H5F_CRT_FILE_SPACE_STRATEGY_DEF H5F_FILE_SPACE_STRATEGY_DEF
+#define H5F_CRT_FILE_SPACE_STRATEGY_ENC H5P__fcrt_fspace_strategy_enc
+#define H5F_CRT_FILE_SPACE_STRATEGY_DEC H5P__fcrt_fspace_strategy_dec
+#define H5F_CRT_FREE_SPACE_PERSIST_SIZE sizeof(hbool_t)
+#define H5F_CRT_FREE_SPACE_PERSIST_DEF H5F_FREE_SPACE_PERSIST_DEF
+#define H5F_CRT_FREE_SPACE_PERSIST_ENC H5P__encode_hbool_t
+#define H5F_CRT_FREE_SPACE_PERSIST_DEC H5P__decode_hbool_t
+#define H5F_CRT_FREE_SPACE_THRESHOLD_SIZE sizeof(hsize_t)
+#define H5F_CRT_FREE_SPACE_THRESHOLD_DEF H5F_FREE_SPACE_THRESHOLD_DEF
+#define H5F_CRT_FREE_SPACE_THRESHOLD_ENC H5P__encode_hsize_t
+#define H5F_CRT_FREE_SPACE_THRESHOLD_DEC H5P__decode_hsize_t
+/* Definitions for file space page size in support of level-2 page caching */
+#define H5F_CRT_FILE_SPACE_PAGE_SIZE_SIZE sizeof(hsize_t)
+#define H5F_CRT_FILE_SPACE_PAGE_SIZE_DEF H5F_FILE_SPACE_PAGE_SIZE_DEF
+#define H5F_CRT_FILE_SPACE_PAGE_SIZE_ENC H5P__encode_hsize_t
+#define H5F_CRT_FILE_SPACE_PAGE_SIZE_DEC H5P__decode_hsize_t
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P_fcrt_reg_prop(H5P_genclass_t *pclass);
+
+/* property callbacks */
+static herr_t H5P__fcrt_btree_rank_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__fcrt_btree_rank_dec(const void **_pp, void *value);
+static herr_t H5P__fcrt_shmsg_index_types_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__fcrt_shmsg_index_types_dec(const void **_pp, void *value);
+static herr_t H5P__fcrt_shmsg_index_minsize_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__fcrt_shmsg_index_minsize_dec(const void **_pp, void *value);
+static herr_t H5P__fcrt_fspace_strategy_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__fcrt_fspace_strategy_dec(const void **_pp, void *_value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* File creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_FCRT[1] = {{
+ "file create", /* Class name for debugging */
+ H5P_TYPE_FILE_CREATE, /* Class type */
+
+ &H5P_CLS_GROUP_CREATE_g, /* Parent class */
+ &H5P_CLS_FILE_CREATE_g, /* Pointer to class */
+ &H5P_CLS_FILE_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_FILE_CREATE_ID_g, /* Pointer to default property list ID */
+ H5P_fcrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const hsize_t H5F_def_userblock_size_g = H5F_CRT_USER_BLOCK_DEF; /* Default userblock size */
+static const unsigned H5F_def_sym_leaf_k_g = H5F_CRT_SYM_LEAF_DEF; /* Default size for symbol table leaf nodes */
+static const unsigned H5F_def_btree_k_g[H5B_NUM_BTREE_ID] = H5F_CRT_BTREE_RANK_DEF; /* Default 'K' values for B-trees in file */
+static const uint8_t H5F_def_sizeof_addr_g = H5F_CRT_ADDR_BYTE_NUM_DEF; /* Default size of addresses in the file */
+static const uint8_t H5F_def_sizeof_size_g = H5F_CRT_OBJ_BYTE_NUM_DEF; /* Default size of sizes in the file */
+static const unsigned H5F_def_superblock_ver_g = H5F_CRT_SUPER_VERS_DEF; /* Default superblock version # */
+static const unsigned H5F_def_num_sohm_indexes_g = H5F_CRT_SHMSG_NINDEXES_DEF;
+static const unsigned H5F_def_sohm_index_flags_g[H5O_SHMESG_MAX_NINDEXES] = H5F_CRT_SHMSG_INDEX_TYPES_DEF;
+static const unsigned H5F_def_sohm_index_minsizes_g[H5O_SHMESG_MAX_NINDEXES] = H5F_CRT_SHMSG_INDEX_MINSIZE_DEF;
+static const unsigned H5F_def_sohm_list_max_g = H5F_CRT_SHMSG_LIST_MAX_DEF;
+static const unsigned H5F_def_sohm_btree_min_g = H5F_CRT_SHMSG_BTREE_MIN_DEF;
+static const H5F_fspace_strategy_t H5F_def_file_space_strategy_g = H5F_CRT_FILE_SPACE_STRATEGY_DEF;
+static const hbool_t H5F_def_free_space_persist_g = H5F_CRT_FREE_SPACE_PERSIST_DEF;
+static const hsize_t H5F_def_free_space_threshold_g = H5F_CRT_FREE_SPACE_THRESHOLD_DEF;
+static const hsize_t H5F_def_file_space_page_size_g = H5F_CRT_FILE_SPACE_PAGE_SIZE_DEF;
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_fcrt_reg_prop
+ *
+ * Purpose: Register the file creation property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_fcrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Register the user block size */
+ if(H5P_register_real(pclass, H5F_CRT_USER_BLOCK_NAME, H5F_CRT_USER_BLOCK_SIZE, &H5F_def_userblock_size_g,
+ NULL, NULL, NULL, H5F_CRT_USER_BLOCK_ENC, H5F_CRT_USER_BLOCK_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the 1/2 rank for symbol table leaf nodes */
+ if(H5P_register_real(pclass, H5F_CRT_SYM_LEAF_NAME, H5F_CRT_SYM_LEAF_SIZE, &H5F_def_sym_leaf_k_g,
+ NULL, NULL, NULL, H5F_CRT_SYM_LEAF_ENC, H5F_CRT_SYM_LEAF_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the 1/2 rank for btree internal nodes */
+ if(H5P_register_real(pclass, H5F_CRT_BTREE_RANK_NAME, H5F_CRT_BTREE_RANK_SIZE, H5F_def_btree_k_g,
+ NULL, NULL, NULL, H5F_CRT_BTREE_RANK_ENC, H5F_CRT_BTREE_RANK_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the byte number for an address */
+ if(H5P_register_real(pclass, H5F_CRT_ADDR_BYTE_NUM_NAME, H5F_CRT_ADDR_BYTE_NUM_SIZE, &H5F_def_sizeof_addr_g,
+ NULL, NULL, NULL, H5F_CRT_ADDR_BYTE_NUM_ENC, H5F_CRT_ADDR_BYTE_NUM_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the byte number for object size */
+ if(H5P_register_real(pclass, H5F_CRT_OBJ_BYTE_NUM_NAME, H5F_CRT_OBJ_BYTE_NUM_SIZE, &H5F_def_sizeof_size_g,
+ NULL, NULL, NULL, H5F_CRT_OBJ_BYTE_NUM_ENC, H5F_CRT_OBJ_BYTE_NUM_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the superblock version number */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5F_CRT_SUPER_VERS_NAME, H5F_CRT_SUPER_VERS_SIZE, &H5F_def_superblock_ver_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the shared OH message information */
+ if(H5P_register_real(pclass, H5F_CRT_SHMSG_NINDEXES_NAME, H5F_CRT_SHMSG_NINDEXES_SIZE, &H5F_def_num_sohm_indexes_g,
+ NULL, NULL, NULL, H5F_CRT_SHMSG_NINDEXES_ENC, H5F_CRT_SHMSG_NINDEXES_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5F_CRT_SHMSG_INDEX_TYPES_NAME, H5F_CRT_SHMSG_INDEX_TYPES_SIZE, &H5F_def_sohm_index_flags_g,
+ NULL, NULL, NULL, H5F_CRT_SHMSG_INDEX_TYPES_ENC, H5F_CRT_SHMSG_INDEX_TYPES_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, H5F_CRT_SHMSG_INDEX_MINSIZE_SIZE, &H5F_def_sohm_index_minsizes_g,
+ NULL, NULL, NULL, H5F_CRT_SHMSG_INDEX_MINSIZE_ENC, H5F_CRT_SHMSG_INDEX_MINSIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the shared OH cutoff size information */
+ if(H5P_register_real(pclass, H5F_CRT_SHMSG_LIST_MAX_NAME, H5F_CRT_SHMSG_LIST_MAX_SIZE, &H5F_def_sohm_list_max_g,
+ NULL, NULL, NULL, H5F_CRT_SHMSG_LIST_MAX_ENC, H5F_CRT_SHMSG_LIST_MAX_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ if(H5P_register_real(pclass, H5F_CRT_SHMSG_BTREE_MIN_NAME, H5F_CRT_SHMSG_BTREE_MIN_SIZE, &H5F_def_sohm_btree_min_g,
+ NULL, NULL, NULL, H5F_CRT_SHMSG_BTREE_MIN_ENC, H5F_CRT_SHMSG_BTREE_MIN_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the file space handling strategy */
+ if(H5P_register_real(pclass, H5F_CRT_FILE_SPACE_STRATEGY_NAME, H5F_CRT_FILE_SPACE_STRATEGY_SIZE, &H5F_def_file_space_strategy_g,
+ NULL, NULL, NULL, H5F_CRT_FILE_SPACE_STRATEGY_ENC, H5F_CRT_FILE_SPACE_STRATEGY_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the free-space persist flag */
+ if(H5P_register_real(pclass, H5F_CRT_FREE_SPACE_PERSIST_NAME, H5F_CRT_FREE_SPACE_PERSIST_SIZE, &H5F_def_free_space_persist_g,
+ NULL, NULL, NULL, H5F_CRT_FREE_SPACE_PERSIST_ENC, H5F_CRT_FREE_SPACE_PERSIST_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the free space section threshold */
+ if(H5P_register_real(pclass, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, H5F_CRT_FREE_SPACE_THRESHOLD_SIZE, &H5F_def_free_space_threshold_g,
+ NULL, NULL, NULL, H5F_CRT_FREE_SPACE_THRESHOLD_ENC, H5F_CRT_FREE_SPACE_THRESHOLD_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the file space page size */
+ if(H5P_register_real(pclass, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, H5F_CRT_FILE_SPACE_PAGE_SIZE_SIZE, &H5F_def_file_space_page_size_g,
+ NULL, NULL, NULL, H5F_CRT_FILE_SPACE_PAGE_SIZE_ENC, H5F_CRT_FILE_SPACE_PAGE_SIZE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_fcrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_userblock
+ *
+ * Purpose: Sets the userblock size field of a file creation property
+ * list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_userblock(hid_t plist_id, hsize_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", plist_id, size);
+
+ /* Sanity check non-zero userblock sizes */
+ if(size > 0) {
+ /* Check that the userblock size is >=512 */
+ if(size < 512)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "userblock size is non-zero and less than 512")
+
+ /* Check that the userblock size is a power of two */
+ if(!POWER_OF_TWO(size))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "userblock size is non-zero and not a power of two")
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(H5P_set(plist, H5F_CRT_USER_BLOCK_NAME, &size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set user block")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_userblock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_userblock
+ *
+ * Purpose: Queries the size of a user block in a file creation property
+ * list.
+ *
+ * Return: Success: Non-negative, size returned through SIZE argument.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu, Oct 14, 2001
+ * Changed to the new generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_userblock(hid_t plist_id, hsize_t *size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", plist_id, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Get value */
+ if (size)
+ if(H5P_get(plist, H5F_CRT_USER_BLOCK_NAME, size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL,"can't get user block");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_sizes
+ *
+ * Purpose: Sets file size-of addresses and sizes. PLIST_ID should be a
+ * file creation property list. A value of zero causes the
+ * property to not change.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_sizes(hid_t plist_id, size_t sizeof_addr, size_t sizeof_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "izz", plist_id, sizeof_addr, sizeof_size);
+
+ /* Check arguments */
+ if(sizeof_addr) {
+ if(sizeof_addr != 2 && sizeof_addr != 4 && sizeof_addr != 8 && sizeof_addr != 16)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file haddr_t size is not valid")
+ } /* end if */
+ if(sizeof_size) {
+ if(sizeof_size != 2 && sizeof_size != 4 && sizeof_size != 8 && sizeof_size != 16)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file size_t size is not valid")
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(sizeof_addr) {
+ uint8_t tmp_sizeof_addr = (uint8_t)sizeof_addr;
+
+ if(H5P_set(plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &tmp_sizeof_addr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set byte number for an address")
+ } /* end if */
+ if(sizeof_size) {
+ uint8_t tmp_sizeof_size = (uint8_t)sizeof_size;
+
+ if(H5P_set(plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &tmp_sizeof_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set byte number for object ")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_sizes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_sizes
+ *
+ * Purpose: Returns the size of address and size quantities stored in a
+ * file according to a file creation property list. Either (or
+ * even both) SIZEOF_ADDR and SIZEOF_SIZE may be null pointers.
+ *
+ * Return: Success: Non-negative, sizes returned through arguments.
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_sizes(hid_t plist_id, size_t *sizeof_addr, size_t *sizeof_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*z*z", plist_id, sizeof_addr, sizeof_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(sizeof_addr) {
+ uint8_t tmp_sizeof_addr;
+
+ if(H5P_get(plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &tmp_sizeof_addr) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get byte number for an address")
+ *sizeof_addr = tmp_sizeof_addr;
+ } /* end if */
+ if(sizeof_size) {
+ uint8_t tmp_sizeof_size;
+
+ if(H5P_get(plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &tmp_sizeof_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get byte number for object ")
+ *sizeof_size = tmp_sizeof_size;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_sizes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_sym_k
+ *
+ * Purpose: IK is one half the rank of a tree that stores a symbol
+ * table for a group. Internal nodes of the symbol table are on
+ * average 75% full. That is, the average rank of the tree is
+ * 1.5 times the value of IK.
+ *
+ * LK is one half of the number of symbols that can be stored in
+ * a symbol table node. A symbol table node is the leaf of a
+ * symbol table tree which is used to store a group. When
+ * symbols are inserted randomly into a group, the group's
+ * symbol table nodes are 75% full on average. That is, they
+ * contain 1.5 times the number of symbols specified by LK.
+ *
+ * Either (or even both) of IK and LK can be zero in which case
+ * that value is left unchanged.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu, Oct 14, 2001
+ * Changed to the new generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_sym_k(hid_t plist_id, unsigned ik, unsigned lk)
+{
+ unsigned btree_k[H5B_NUM_BTREE_ID];
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, ik, lk);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Set values */
+ if (ik > 0) {
+ if((ik * 2) >= HDF5_BTREE_IK_MAX_ENTRIES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "istore IK value exceeds maximum B-tree entries");
+
+ if(H5P_get(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get rank for btree interanl nodes");
+ btree_k[H5B_SNODE_ID] = ik;
+ if(H5P_set(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set rank for btree nodes");
+ }
+ if (lk > 0)
+ if(H5P_set(plist, H5F_CRT_SYM_LEAF_NAME, &lk) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set rank for symbol table leaf nodes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_sym_k
+ *
+ * Purpose: Retrieves the symbol table B-tree 1/2 rank (IK) and the
+ * symbol table leaf node 1/2 size (LK). See H5Pset_sym_k() for
+ * details. Either (or even both) IK and LK may be null
+ * pointers.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Changed to the new generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_sym_k(hid_t plist_id, unsigned *ik /*out */ , unsigned *lk /*out */ )
+{
+ unsigned btree_k[H5B_NUM_BTREE_ID];
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", plist_id, ik, lk);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Get values */
+ if (ik) {
+ if(H5P_get(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get rank for btree nodes");
+ *ik = btree_k[H5B_SNODE_ID];
+ }
+ if (lk)
+ if(H5P_get(plist, H5F_CRT_SYM_LEAF_NAME, lk) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get rank for symbol table leaf nodes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_istore_k
+ *
+ * Purpose: IK is one half the rank of a tree that stores chunked raw
+ * data. On average, such a tree will be 75% full, or have an
+ * average rank of 1.5 times the value of IK.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 6, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu, Oct 14, 2001
+ * Changed to the new generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_istore_k(hid_t plist_id, unsigned ik)
+{
+ unsigned btree_k[H5B_NUM_BTREE_ID];
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, ik);
+
+ /* Check arguments */
+ if (ik == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "istore IK value must be positive");
+
+ if((ik * 2) >= HDF5_BTREE_IK_MAX_ENTRIES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "istore IK value exceeds maximum B-tree entries");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Set value */
+ if(H5P_get(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get rank for btree interanl nodes");
+ btree_k[H5B_CHUNK_ID] = ik;
+ if(H5P_set(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set rank for btree interanl nodes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_istore_k
+ *
+ * Purpose: Queries the 1/2 rank of an indexed storage B-tree. See
+ * H5Pset_istore_k() for details. The argument IK may be the
+ * null pointer.
+ *
+ * Return: Success: Non-negative, size returned through IK
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu, Oct 14, 2001
+ * Changed to the new generic property list.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_istore_k(hid_t plist_id, unsigned *ik /*out */ )
+{
+ unsigned btree_k[H5B_NUM_BTREE_ID];
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, ik);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Get value */
+ if(ik) {
+ if(H5P_get(plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get rank for btree interanl nodes");
+ *ik = btree_k[H5B_CHUNK_ID];
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_istore_k() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_btree_rank_enc
+ *
+ * Purpose: Callback routine which is called whenever the index storage
+ * btree in file creation property list is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_btree_rank_enc(const void *value, void **_pp, size_t *size)
+{
+ const unsigned *btree_k = (const unsigned *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(btree_k);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ unsigned u; /* Local index variable */
+
+ /* Encode the size of an unsigned*/
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* Encode all the btree */
+ for(u = 0 ; u < H5B_NUM_BTREE_ID; u++) {
+ /* Encode the left split value */
+ H5_ENCODE_UNSIGNED(*pp, *(const unsigned *)btree_k)
+ btree_k++;
+ } /* end for */
+ } /* end if */
+
+ /* Size of type flags values */
+ *size += 1 + (H5B_NUM_BTREE_ID * sizeof(unsigned));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__fcrt_btree_rank_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_btree_rank_dec
+ *
+ * Purpose: Callback routine which is called whenever the index storage
+ * btree in file creation property list is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_btree_rank_dec(const void **_pp, void *_value)
+{
+ unsigned *btree_k = (unsigned *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(btree_k);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ /* Decode all the type flags */
+ for(u = 0 ; u < H5B_NUM_BTREE_ID; u++)
+ H5_DECODE_UNSIGNED(*pp, btree_k[u])
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__fcrt_btree_rank_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_shared_mesg_nindexes
+ *
+ * Purpose: Set the number of Shared Object Header Message (SOHM)
+ * indexes specified in this property list. If this is
+ * zero then shared object header messages are disabled
+ * for this file.
+ *
+ * These indexes can then be configured with
+ * H5Pset_shared_mesg_index. H5Pset_shared_mesg_phase_chage
+ * also controls settings for all indexes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, October 9, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_shared_mesg_nindexes(hid_t plist_id, unsigned nindexes)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, nindexes);
+
+ /* Check argument */
+ if (nindexes > H5O_SHMESG_MAX_NINDEXES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "number of indexes is greater than H5O_SHMESG_MAX_NINDEXES");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ if(H5P_set(plist, H5F_CRT_SHMSG_NINDEXES_NAME, &nindexes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set number of indexes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_shared_mesg_nindexes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_shared_mesg_nindexes
+ *
+ * Purpose: Get the number of Shared Object Header Message (SOHM)
+ * indexes specified in this property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, October 9, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_shared_mesg_nindexes(hid_t plist_id, unsigned *nindexes)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", plist_id, nindexes);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ if(H5P_get(plist, H5F_CRT_SHMSG_NINDEXES_NAME, nindexes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of indexes");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_shared_mesg_nindexes() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_shared_mesg_index
+ *
+ * Purpose: Configure a given shared message index. Sets the types of
+ * message that should be stored in this index and the minimum
+ * size of a message in the index.
+ *
+ * INDEX_NUM is zero-indexed (in a file with three indexes,
+ * they are numbered 0, 1, and 2).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, April 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_shared_mesg_index(hid_t plist_id, unsigned index_num, unsigned mesg_type_flags, unsigned min_mesg_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ unsigned nindexes; /* Number of SOHM indexes */
+ unsigned type_flags[H5O_SHMESG_MAX_NINDEXES]; /* Array of mesg_type_flags*/
+ unsigned minsizes[H5O_SHMESG_MAX_NINDEXES]; /* Array of min_mesg_sizes*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iIuIuIu", plist_id, index_num, mesg_type_flags, min_mesg_size);
+
+ /* Check arguments */
+ if(mesg_type_flags > H5O_SHMESG_ALL_FLAG)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "unrecognized flags in mesg_type_flags")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Read the current number of indexes */
+ if(H5P_get(plist, H5F_CRT_SHMSG_NINDEXES_NAME, &nindexes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of indexes")
+
+ /* Range check */
+ if(index_num >= nindexes)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index_num is too large; no such index");
+
+ /* Get arrays of type flags and message sizes */
+ if(H5P_get(plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, type_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get current index type flags")
+ if(H5P_get(plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, minsizes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get current min sizes")
+
+ /* Set values in arrays */
+ type_flags[index_num] = mesg_type_flags;
+ minsizes[index_num] = min_mesg_size;
+
+ /* Write arrays back to plist */
+ if(H5P_set(plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, type_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set index type flags")
+ if(H5P_set(plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, minsizes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set min mesg sizes")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_shared_mesg_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_shared_mesg_index
+ *
+ * Purpose: Get information about a given shared message index. Gets
+ * the types of message that are stored in the index and the
+ * minimum size of a message in the index.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, April 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_shared_mesg_index(hid_t plist_id, unsigned index_num, unsigned *mesg_type_flags, unsigned *min_mesg_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ unsigned nindexes; /* Number of SOHM indexes */
+ unsigned type_flags[H5O_SHMESG_MAX_NINDEXES]; /* Array of mesg_type_flags*/
+ unsigned minsizes[H5O_SHMESG_MAX_NINDEXES]; /* Array of min_mesg_sizes*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iIu*Iu*Iu", plist_id, index_num, mesg_type_flags,
+ min_mesg_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Read the current number of indexes */
+ if(H5P_get(plist, H5F_CRT_SHMSG_NINDEXES_NAME, &nindexes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of indexes")
+
+ if(index_num >= nindexes)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index_num is greater than number of indexes in property list")
+
+ /* Get arrays of type flags and message sizes */
+ if(H5P_get(plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, type_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get current index type flags")
+ if(H5P_get(plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, minsizes) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get current min sizes")
+
+ /* Get values from arrays */
+ if(mesg_type_flags)
+ *mesg_type_flags = type_flags[index_num];
+ if(min_mesg_size)
+ *min_mesg_size = minsizes[index_num];
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_shared_mesg_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_shmsg_index_types_enc
+ *
+ * Purpose: Callback routine which is called whenever the shared
+ * message indec types in file creation property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_shmsg_index_types_enc(const void *value, void **_pp, size_t *size)
+{
+ const unsigned *type_flags = (const unsigned *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(type_flags);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ unsigned u; /* Local index variable */
+
+ /* Encode the size of a double*/
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* Encode all the type flags */
+ for(u = 0; u < H5O_SHMESG_MAX_NINDEXES; u++) {
+ /* Encode the left split value */
+ H5_ENCODE_UNSIGNED(*pp, *(const unsigned *)type_flags)
+ type_flags++;
+ } /* end for */
+ } /* end if */
+
+ /* Size of type flags values */
+ *size += 1 + (H5O_SHMESG_MAX_NINDEXES * sizeof(unsigned));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__fcrt_shmsg_index_types_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_shmsg_index_types_dec
+ *
+ * Purpose: Callback routine which is called whenever the shared
+ * message indec types in file creation property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_shmsg_index_types_dec(const void **_pp, void *_value)
+{
+ unsigned *type_flags = (unsigned *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(type_flags);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ /* Decode all the type flags */
+ for(u = 0; u < H5O_SHMESG_MAX_NINDEXES; u++)
+ H5_DECODE_UNSIGNED(*pp, type_flags[u])
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__fcrt_shmsg_index_types_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_shmsg_index_minsize_enc
+ *
+ * Purpose: Callback routine which is called whenever the shared
+ * message index minsize in file creation property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_shmsg_index_minsize_enc(const void *value, void **_pp, size_t *size)
+{
+ const unsigned *minsizes = (const unsigned *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(minsizes);
+ HDassert(size);
+
+ if(NULL != *pp) {
+ unsigned u; /* Local index variable */
+
+ /* Encode the size of a double*/
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* Encode all the minsize values */
+ for(u = 0 ; u < H5O_SHMESG_MAX_NINDEXES; u++) {
+ /* Encode the left split value */
+ H5_ENCODE_UNSIGNED(*pp, *(const unsigned *)minsizes)
+ minsizes++;
+ } /* end for */
+ } /* end if */
+
+ /* Size of type flags values */
+ *size += 1 + (H5O_SHMESG_MAX_NINDEXES * sizeof(unsigned));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__fcrt_shmsg_index_minsize_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_shmsg_index_minsize_dec
+ *
+ * Purpose: Callback routine which is called whenever the shared
+ * message indec minsize in file creation property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * August 7, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_shmsg_index_minsize_dec(const void **_pp, void *_value)
+{
+ unsigned *minsizes = (unsigned *)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned enc_size; /* Size of encoded property */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(minsizes);
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ /* Decode all the minsize values */
+ for(u = 0 ; u < H5O_SHMESG_MAX_NINDEXES; u++)
+ H5_DECODE_UNSIGNED(*pp, minsizes[u])
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__fcrt_shmsg_index_minsize_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_shared_mesg_phase_change
+ *
+ * Purpose: Sets the cutoff values for indexes storing shared object
+ * header messages in this file. If more than max_list
+ * messages are in an index, that index will become a B-tree.
+ * Likewise, a B-tree index containing fewer than min_btree
+ * messages will be converted to a list.
+ *
+ * If the max_list is zero then SOHM indexes in this file will
+ * never be lists but will be created as B-trees.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, April 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_shared_mesg_phase_change(hid_t plist_id, unsigned max_list, unsigned min_btree)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, max_list, min_btree);
+
+ /* Check that values are sensible. The min_btree value must be no greater
+ * than the max list plus one.
+ *
+ * Range check to make certain they will fit into encoded form.
+ */
+ if(max_list + 1 < min_btree)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "minimum B-tree value is greater than maximum list value")
+ if(max_list > H5O_SHMESG_MAX_LIST_SIZE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "max list value is larger than H5O_SHMESG_MAX_LIST_SIZE")
+ if(min_btree > H5O_SHMESG_MAX_LIST_SIZE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "min btree value is larger than H5O_SHMESG_MAX_LIST_SIZE")
+
+ /* Avoid the strange case where max_list == 0 and min_btree == 1, so deleting the
+ * last message in a B-tree makes it become an empty list.
+ */
+ if(max_list == 0)
+ min_btree = 0;
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ if(H5P_set(plist, H5F_CRT_SHMSG_LIST_MAX_NAME, &max_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set list maximum in property list");
+ if(H5P_set(plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, &min_btree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set B-tree minimum in property list");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_shared_mesg_phase_change() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_shared_mesg_phase_change
+ *
+ * Purpose: Gets the maximum size of a SOHM list index before it becomes
+ * a B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, April 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_shared_mesg_phase_change(hid_t plist_id, unsigned *max_list, unsigned *min_btree)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*Iu*Iu", plist_id, max_list, min_btree);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");
+
+ /* Get value(s) */
+ if(max_list)
+ if(H5P_get(plist, H5F_CRT_SHMSG_LIST_MAX_NAME, max_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get list maximum");
+ if(min_btree)
+ if(H5P_get(plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, min_btree) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get SOHM information");
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_shared_mesg_phase_change() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_space_strategy
+ *
+ * Purpose: Sets the "strategy" that the library employs in managing file space
+ * Sets the "persist" value as to persist free-space or not
+ * Sets the "threshold" value that the free space manager(s) will use to track free space sections.
+ * Ignore "persist" and "threshold" for strategies that do not use free-space managers
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 10, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t strategy, hbool_t persist, hsize_t threshold)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iFfbh", plist_id, strategy, persist, threshold);
+
+ /* Check arguments */
+ if(strategy >= H5F_FSPACE_STRATEGY_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid strategy")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value(s), if non-zero */
+ if(H5P_set(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &strategy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy")
+
+ /* Ignore persist and threshold settings for strategies that do not use FSM */
+ if(strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || strategy == H5F_FSPACE_STRATEGY_PAGE) {
+ if(H5P_set(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &persist) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space persisting status")
+
+ if(H5P_set(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space threshold")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_file_space_strategy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_space_strategy
+ *
+ * Purpose: Retrieves the strategy, persist, and threshold that the library
+ * uses in managing file space.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; June 10, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t *strategy, hbool_t *persist, hsize_t *threshold)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*Ff*b*h", plist_id, strategy, persist, threshold);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value(s) */
+ if(strategy)
+ if(H5P_get(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, strategy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy")
+ if(persist)
+ if(H5P_get(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, persist) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space persisting status")
+ if(threshold)
+ if(H5P_get(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, threshold) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space threshold")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_file_space_strategy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_fspace_strategy_enc
+ *
+ * Purpose: Callback routine which is called whenever the free-space
+ * strategy property in the file creation property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 27, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_fspace_strategy_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5F_fspace_strategy_t *strategy = (const H5F_fspace_strategy_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(strategy);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode free-space strategy */
+ *(*pp)++ = (uint8_t)*strategy;
+
+ /* Size of free-space strategy */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__fcrt_fspace_strategy_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__fcrt_fspace_strategy_dec
+ *
+ * Purpose: Callback routine which is called whenever the free-space
+ * strategy property in the file creation property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, December 27, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__fcrt_fspace_strategy_dec(const void **_pp, void *_value)
+{
+ H5F_fspace_strategy_t *strategy = (H5F_fspace_strategy_t *)_value; /* Free-space strategy */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(strategy);
+
+ /* Decode free-space strategy */
+ *strategy = (H5F_fspace_strategy_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__fcrt_fspace_strategy_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_space_page_size
+ *
+ * Purpose: Sets the file space page size for paged aggregation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; August 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_space_page_size(hid_t plist_id, hsize_t fsp_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ih", plist_id, fsp_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(fsp_size < H5F_FILE_SPACE_PAGE_SIZE_MIN)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "cannot set file space page size to less than 512")
+
+ /* Set the value*/
+ if(H5P_set(plist, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, &fsp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set file space page size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_file_space_page_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_space_page_size
+ *
+ * Purpose: Retrieves the file space page size for aggregating small metadata
+ * or raw data in the parameter "fsp_size".
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; August 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_space_page_size(hid_t plist_id, hsize_t *fsp_size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*h", plist_id, fsp_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id,H5P_FILE_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(fsp_size)
+ if(H5P_get(plist, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, fsp_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space page size")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_file_space_page_size() */
+
diff --git a/src/H5Pfmpl.c b/src/H5Pfmpl.c
new file mode 100644
index 0000000..e858a79
--- /dev/null
+++ b/src/H5Pfmpl.c
@@ -0,0 +1,134 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pmtpl.c
+ * November 1 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: File mount property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ======================== File Mount properties ====================*/
+/* Definition for whether absolute symlinks local to file. */
+#define H5F_MNT_SYM_LOCAL_SIZE sizeof(hbool_t)
+#define H5F_MNT_SYM_LOCAL_DEF FALSE
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P_fmnt_reg_prop(H5P_genclass_t *pclass);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* File mount property list class library initialization object */
+const H5P_libclass_t H5P_CLS_FMNT[1] = {{
+ "file mount", /* Class name for debugging */
+ H5P_TYPE_FILE_MOUNT, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_FILE_MOUNT_g, /* Pointer to class */
+ &H5P_CLS_FILE_MOUNT_ID_g, /* Pointer to class ID */
+ &H5P_LST_FILE_MOUNT_ID_g, /* Pointer to default property list ID */
+ H5P_fmnt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const hbool_t H5F_def_local_g = H5F_MNT_SYM_LOCAL_DEF; /* Whether symlinks are local to file */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_fmnt_reg_prop
+ *
+ * Purpose: Register the file mount property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P_fmnt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Register property of whether symlinks is local to file */
+ if(H5P_register_real(pclass, H5F_MNT_SYM_LOCAL_NAME, H5F_MNT_SYM_LOCAL_SIZE, &H5F_def_local_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_fmnt_reg_prop() */
+
diff --git a/src/H5Pgcpl.c b/src/H5Pgcpl.c
new file mode 100644
index 0000000..6f1fab1
--- /dev/null
+++ b/src/H5Pgcpl.c
@@ -0,0 +1,706 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pgcpl.c
+ * August 29 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Group creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= Group Creation properties ============ */
+#define H5G_CRT_GROUP_INFO_ENC H5P__gcrt_group_info_enc
+#define H5G_CRT_GROUP_INFO_DEC H5P__gcrt_group_info_dec
+#define H5G_CRT_LINK_INFO_ENC H5P__gcrt_link_info_enc
+#define H5G_CRT_LINK_INFO_DEC H5P__gcrt_link_info_dec
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__gcrt_reg_prop(H5P_genclass_t *pclass);
+
+/* Property callbacks */
+static herr_t H5P__gcrt_group_info_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__gcrt_group_info_dec(const void **_pp, void *value);
+static herr_t H5P__gcrt_link_info_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__gcrt_link_info_dec(const void **_pp, void *value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Group creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_GCRT[1] = {{
+ "group create", /* Class name for debugging */
+ H5P_TYPE_GROUP_CREATE, /* Class type */
+
+ &H5P_CLS_OBJECT_CREATE_g, /* Parent class */
+ &H5P_CLS_GROUP_CREATE_g, /* Pointer to class */
+ &H5P_CLS_GROUP_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_GROUP_CREATE_ID_g, /* Pointer to default property list ID */
+ H5P__gcrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const H5O_ginfo_t H5G_def_ginfo_g = H5G_CRT_GROUP_INFO_DEF; /* Default group info settings */
+static const H5O_linfo_t H5G_def_linfo_g = H5G_CRT_LINK_INFO_DEF; /* Default link info settings */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__gcrt_reg_prop
+ *
+ * Purpose: Initialize the group creation property list class
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__gcrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register group info property */
+ if(H5P_register_real(pclass, H5G_CRT_GROUP_INFO_NAME, H5G_CRT_GROUP_INFO_SIZE, &H5G_def_ginfo_g,
+ NULL, NULL, NULL, H5G_CRT_GROUP_INFO_ENC, H5G_CRT_GROUP_INFO_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register link info property */
+ if(H5P_register_real(pclass, H5G_CRT_LINK_INFO_NAME, H5G_CRT_LINK_INFO_SIZE, &H5G_def_linfo_g,
+ NULL, NULL, NULL, H5G_CRT_LINK_INFO_ENC, H5G_CRT_LINK_INFO_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__gcrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_local_heap_size_hint
+ *
+ * Purpose: Set the "size hint" for creating local heaps for a group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 29, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_local_heap_size_hint(hid_t plist_id, size_t size_hint)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", plist_id, size_hint);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Update field */
+ H5_CHECKED_ASSIGN(ginfo.lheap_size_hint, uint32_t, size_hint, size_t);
+
+ /* Set value */
+ if(H5P_set(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set group info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_local_heap_size_hint() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_local_heap_size_hint
+ *
+ * Purpose: Returns the local heap size hint, which is used for creating
+ * groups
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 29, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_local_heap_size_hint(hid_t plist_id, size_t *size_hint /*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, size_hint);
+
+ if(size_hint) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Update field */
+ *size_hint = ginfo.lheap_size_hint;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_local_heap_size_hint() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_link_phase_change
+ *
+ * Purpose: Set the maximum # of links to store "compactly" and the
+ * minimum # of links to store "densely". (These should
+ * overlap).
+ *
+ * Note: Currently both of these must be updated at the same time.
+ *
+ * Note: Come up with better name & description! -QAK
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 29, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_link_phase_change(hid_t plist_id, unsigned max_compact, unsigned min_dense)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, max_compact, min_dense);
+
+ /* Range check values */
+ if(max_compact < min_dense)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "max compact value must be >= min dense value")
+ if(max_compact > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "max compact value must be < 65536")
+ if(min_dense > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "min dense value must be < 65536")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get group info */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Update fields */
+ if(max_compact != H5G_CRT_GINFO_MAX_COMPACT || min_dense != H5G_CRT_GINFO_MIN_DENSE)
+ ginfo.store_link_phase_change = TRUE;
+ else
+ ginfo.store_link_phase_change = FALSE;
+ ginfo.max_compact = (uint16_t)max_compact;
+ ginfo.min_dense = (uint16_t)min_dense;
+
+ /* Set group info */
+ if(H5P_set(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set group info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_link_phase_change() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_link_phase_change
+ *
+ * Purpose: Returns the max. # of compact links & the min. # of dense
+ * links, which are used for storing groups
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * August 29, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_link_phase_change(hid_t plist_id, unsigned *max_compact /*out*/, unsigned *min_dense /*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", plist_id, max_compact, min_dense);
+
+ /* Get values */
+ if(max_compact || min_dense) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get group info */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ if(max_compact)
+ *max_compact = ginfo.max_compact;
+ if(min_dense)
+ *min_dense = ginfo.min_dense;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_link_phase_change() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_est_link_info
+ *
+ * Purpose: Set the estimates for the number of entries and length of each
+ * entry name in a group.
+ *
+ * Note: Currently both of these must be updated at the same time.
+ *
+ * Note: EST_NUM_ENTRIES applies only when the number of entries is less
+ * than the MAX_COMPACT # of entries (from H5Pset_link_phase_change).
+ *
+ * Note: Come up with better name & description? -QAK
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 6, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_est_link_info(hid_t plist_id, unsigned est_num_entries, unsigned est_name_len)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, est_num_entries, est_name_len);
+
+ /* Range check values */
+ if(est_num_entries > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "est. number of entries must be < 65536")
+ if(est_name_len > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "est. name length must be < 65536")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get group info */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ /* Update fields */
+ if(est_num_entries != H5G_CRT_GINFO_EST_NUM_ENTRIES || est_name_len != H5G_CRT_GINFO_EST_NAME_LEN)
+ ginfo.store_est_entry_info = TRUE;
+ else
+ ginfo.store_est_entry_info = FALSE;
+ ginfo.est_num_entries = (uint16_t)est_num_entries;
+ ginfo.est_name_len = (uint16_t)est_name_len;
+
+ /* Set group info */
+ if(H5P_set(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set group info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_est_link_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_est_link_info
+ *
+ * Purpose: Returns the est. # of links in a group & the est. length of
+ * the name of each link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 6, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_est_link_info(hid_t plist_id, unsigned *est_num_entries /*out*/, unsigned *est_name_len /*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", plist_id, est_num_entries, est_name_len);
+
+ /* Get values */
+ if(est_num_entries || est_name_len) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_ginfo_t ginfo; /* Group information structure */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get group info */
+ if(H5P_get(plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info")
+
+ if(est_num_entries)
+ *est_num_entries = ginfo.est_num_entries;
+ if(est_name_len)
+ *est_name_len = ginfo.est_name_len;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_est_link_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_link_creation_order
+ *
+ * Purpose: Set the flags for creation order of links in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 12, 2006
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_link_creation_order(hid_t plist_id, unsigned crt_order_flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_linfo_t linfo; /* Link information structure */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, crt_order_flags);
+
+ /* Check for bad combination of flags */
+ if(!(crt_order_flags & H5P_CRT_ORDER_TRACKED) && (crt_order_flags & H5P_CRT_ORDER_INDEXED))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "tracking creation order is required for index")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get link info */
+ if(H5P_get(plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get link info")
+
+ /* Update fields */
+ linfo.track_corder = (hbool_t)((crt_order_flags & H5P_CRT_ORDER_TRACKED) ? TRUE : FALSE);
+ linfo.index_corder = (hbool_t)((crt_order_flags & H5P_CRT_ORDER_INDEXED) ? TRUE : FALSE);
+
+ /* Set link info */
+ if(H5P_set(plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set link info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_link_creation_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_link_creation_order
+ *
+ * Purpose: Returns the flag indicating that creation order is tracked
+ * for links in a group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * September 12, 2006
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_link_creation_order(hid_t plist_id, unsigned *crt_order_flags /*out*/)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, crt_order_flags);
+
+ /* Get values */
+ if(crt_order_flags) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_linfo_t linfo; /* Link information structure */
+
+ /* Reset the value to return */
+ *crt_order_flags = 0;
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_GROUP_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get link info */
+ if(H5P_get(plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get link info")
+
+ *crt_order_flags |= linfo.track_corder ? H5P_CRT_ORDER_TRACKED : 0;
+ *crt_order_flags |= linfo.index_corder ? H5P_CRT_ORDER_INDEXED : 0;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_link_creation_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__gcrt_group_info_enc
+ *
+ * Purpose: Callback routine which is called whenever the group
+ * property in the dataset access property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__gcrt_group_info_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_ginfo_t *ginfo = (const H5O_ginfo_t *)value; /* Create local aliases for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(NULL != *pp) {
+ UINT32ENCODE(*pp, ginfo->lheap_size_hint)
+ UINT16ENCODE(*pp, ginfo->max_compact)
+ UINT16ENCODE(*pp, ginfo->min_dense)
+ UINT16ENCODE(*pp, ginfo->est_num_entries)
+ UINT16ENCODE(*pp, ginfo->est_name_len)
+ } /* end if */
+
+ *size += sizeof(uint16_t) * 4 + sizeof(uint32_t);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__gcrt_group_info_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__gcrt_group_info_dec
+ *
+ * Purpose: Callback routine which is called whenever the group info
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__gcrt_group_info_dec(const void **_pp, void *_value)
+{
+ H5O_ginfo_t *ginfo = (H5O_ginfo_t *)_value; /* Group info settings */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Set property to default value */
+ HDmemset(ginfo, 0, sizeof(H5O_ginfo_t));
+ *ginfo = H5G_def_ginfo_g;
+
+ UINT32DECODE(*pp, ginfo->lheap_size_hint)
+ UINT16DECODE(*pp, ginfo->max_compact)
+ UINT16DECODE(*pp, ginfo->min_dense)
+ UINT16DECODE(*pp, ginfo->est_num_entries)
+ UINT16DECODE(*pp, ginfo->est_name_len)
+
+ /* Update fields */
+ if(ginfo->max_compact != H5G_CRT_GINFO_MAX_COMPACT ||
+ ginfo->min_dense != H5G_CRT_GINFO_MIN_DENSE)
+ ginfo->store_link_phase_change = TRUE;
+ else
+ ginfo->store_link_phase_change = FALSE;
+
+ if(ginfo->est_num_entries != H5G_CRT_GINFO_EST_NUM_ENTRIES ||
+ ginfo->est_name_len != H5G_CRT_GINFO_EST_NAME_LEN)
+ ginfo->store_est_entry_info = TRUE;
+ else
+ ginfo->store_est_entry_info = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__gcrt_group_info_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__gcrt_link_info_enc
+ *
+ * Purpose: Callback routine which is called whenever the link
+ * property in the dataset access property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__gcrt_link_info_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_linfo_t *linfo = (const H5O_linfo_t *)value; /* Create local aliases for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(NULL != *pp) {
+ unsigned crt_order_flags = 0;
+
+ crt_order_flags |= linfo->track_corder ? H5P_CRT_ORDER_TRACKED : 0;
+ crt_order_flags |= linfo->index_corder ? H5P_CRT_ORDER_INDEXED : 0;
+
+ /* Encode the size of unsigned*/
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* Encode the value */
+ H5_ENCODE_UNSIGNED(*pp, crt_order_flags)
+ } /* end if */
+
+ *size += (1 + sizeof(unsigned));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__gcrt_link_info_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__gcrt_link_info_dec
+ *
+ * Purpose: Callback routine which is called whenever the link info
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__gcrt_link_info_dec(const void **_pp, void *_value)
+{
+ H5O_linfo_t *linfo = (H5O_linfo_t *)_value; /* Link info settings */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ unsigned crt_order_flags;
+ unsigned enc_size;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ /* Set property to default value */
+ HDmemset(linfo, 0, sizeof(H5O_linfo_t));
+ *linfo = H5G_def_linfo_g;
+
+ H5_DECODE_UNSIGNED(*pp, crt_order_flags)
+
+ /* Update fields */
+ linfo->track_corder = (hbool_t)((crt_order_flags & H5P_CRT_ORDER_TRACKED) ? TRUE : FALSE);
+ linfo->index_corder = (hbool_t)((crt_order_flags & H5P_CRT_ORDER_INDEXED) ? TRUE : FALSE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__gcrt_link_info_dec() */
+
diff --git a/src/H5Pint.c b/src/H5Pint.c
new file mode 100644
index 0000000..fe17a19
--- /dev/null
+++ b/src/H5Pint.c
@@ -0,0 +1,5524 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Generic Property Functions
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#ifdef H5_HAVE_PARALLEL
+#include "H5ACprivate.h" /* Metadata cache */
+#endif /* H5_HAVE_PARALLEL */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Typedef for checking for duplicate class names in parent class */
+typedef struct {
+ const H5P_genclass_t *parent; /* Pointer to parent class */
+ const char *name; /* Pointer to name to check */
+ H5P_genclass_t *new_class; /* Pointer to class during path traversal */
+} H5P_check_class_t;
+
+/* Typedef for property list iterator callback */
+typedef struct {
+ H5P_iterate_int_t cb_func; /* Iterator callback */
+ void *udata; /* Iterator callback pointer */
+ const H5P_genplist_t *plist; /* Property list pointer */
+ H5SL_t *seen; /* Skip list to hold names of properties already seen */
+ int *curr_idx_ptr; /* Pointer to current iteration index */
+ int prev_idx; /* Previous iteration index */
+} H5P_iter_plist_ud_t;
+
+/* Typedef for property list class iterator callback */
+typedef struct {
+ H5P_iterate_int_t cb_func; /* Iterator callback */
+ void *udata; /* Iterator callback pointer */
+ int *curr_idx_ptr; /* Pointer to current iteration index */
+ int prev_idx; /* Previous iteration index */
+} H5P_iter_pclass_ud_t;
+
+/* Typedef for property list comparison callback */
+typedef struct {
+ const H5P_genplist_t *plist2; /* Pointer to second property list */
+ int cmp_value; /* Value from property comparison */
+} H5P_plist_cmp_ud_t;
+
+/* Typedef for property list set/poke callbacks */
+typedef struct {
+ const void *value; /* Pointer to value to set */
+} H5P_prop_set_ud_t;
+
+/* Typedef for property list get/peek callbacks */
+typedef struct {
+ void *value; /* Pointer for retrieved value */
+} H5P_prop_get_ud_t;
+
+/* Typedef for H5P__do_prop() callbacks */
+typedef herr_t (*H5P_do_plist_op_t)(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *udata);
+typedef herr_t (*H5P_do_pclass_op_t)(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *udata);
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* General helper routines */
+static H5P_genprop_t *H5P_dup_prop(H5P_genprop_t *oprop, H5P_prop_within_t type);
+static herr_t H5P_free_prop(H5P_genprop_t *prop);
+static int H5P_cmp_prop(const H5P_genprop_t *prop1, const H5P_genprop_t *prop2);
+static herr_t H5P__do_prop(H5P_genplist_t *plist, const char *name, H5P_do_plist_op_t plist_op,
+ H5P_do_pclass_op_t pclass_op, void *udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/*
+ * Predefined property list classes. These are initialized at runtime by
+ * H5P__init_package() in this source file.
+ */
+hid_t H5P_CLS_ROOT_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_ROOT_g = NULL;
+hid_t H5P_CLS_OBJECT_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_OBJECT_CREATE_g = NULL;
+hid_t H5P_CLS_FILE_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_FILE_CREATE_g = NULL;
+hid_t H5P_CLS_FILE_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_FILE_ACCESS_g = NULL;
+hid_t H5P_CLS_DATASET_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_DATASET_CREATE_g = NULL;
+hid_t H5P_CLS_DATASET_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_DATASET_ACCESS_g = NULL;
+hid_t H5P_CLS_DATASET_XFER_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_DATASET_XFER_g = NULL;
+hid_t H5P_CLS_FILE_MOUNT_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_FILE_MOUNT_g = NULL;
+hid_t H5P_CLS_GROUP_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_GROUP_CREATE_g = NULL;
+hid_t H5P_CLS_GROUP_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_GROUP_ACCESS_g = NULL;
+hid_t H5P_CLS_DATATYPE_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_DATATYPE_CREATE_g = NULL;
+hid_t H5P_CLS_DATATYPE_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_DATATYPE_ACCESS_g = NULL;
+hid_t H5P_CLS_ATTRIBUTE_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_ATTRIBUTE_CREATE_g = NULL;
+hid_t H5P_CLS_ATTRIBUTE_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_ATTRIBUTE_ACCESS_g = NULL;
+hid_t H5P_CLS_OBJECT_COPY_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_OBJECT_COPY_g = NULL;
+hid_t H5P_CLS_LINK_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_LINK_CREATE_g = NULL;
+hid_t H5P_CLS_LINK_ACCESS_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_LINK_ACCESS_g = NULL;
+hid_t H5P_CLS_STRING_CREATE_ID_g = FAIL;
+H5P_genclass_t *H5P_CLS_STRING_CREATE_g = NULL;
+
+/*
+ * Predefined property lists for each predefined class. These are initialized
+ * at runtime by H5P__init_package() in this source file.
+ */
+hid_t H5P_LST_FILE_CREATE_ID_g = FAIL;
+hid_t H5P_LST_FILE_ACCESS_ID_g = FAIL;
+hid_t H5P_LST_DATASET_CREATE_ID_g = FAIL;
+hid_t H5P_LST_DATASET_ACCESS_ID_g = FAIL;
+hid_t H5P_LST_DATASET_XFER_ID_g = FAIL;
+hid_t H5P_LST_FILE_MOUNT_ID_g = FAIL;
+hid_t H5P_LST_GROUP_CREATE_ID_g = FAIL;
+hid_t H5P_LST_GROUP_ACCESS_ID_g = FAIL;
+hid_t H5P_LST_DATATYPE_CREATE_ID_g = FAIL;
+hid_t H5P_LST_DATATYPE_ACCESS_ID_g = FAIL;
+hid_t H5P_LST_ATTRIBUTE_CREATE_ID_g = FAIL;
+hid_t H5P_LST_ATTRIBUTE_ACCESS_ID_g = FAIL;
+hid_t H5P_LST_OBJECT_COPY_ID_g = FAIL;
+hid_t H5P_LST_LINK_CREATE_ID_g = FAIL;
+hid_t H5P_LST_LINK_ACCESS_ID_g = FAIL;
+
+/* Root property list class library initialization object */
+const H5P_libclass_t H5P_CLS_ROOT[1] = {{
+ "root", /* Class name for debugging */
+ H5P_TYPE_ROOT, /* Class type */
+
+ NULL, /* Parent class */
+ &H5P_CLS_ROOT_g, /* Pointer to class */
+ &H5P_CLS_ROOT_ID_g, /* Pointer to class ID */
+ NULL, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+/* Attribute access property list class library initialization object */
+/* (move to proper source code file when used for real) */
+const H5P_libclass_t H5P_CLS_AACC[1] = {{
+ "attribute access", /* Class name for debugging */
+ H5P_TYPE_ATTRIBUTE_ACCESS, /* Class type */
+
+ &H5P_CLS_LINK_ACCESS_g, /* Parent class */
+ &H5P_CLS_ATTRIBUTE_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_ATTRIBUTE_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_ATTRIBUTE_ACCESS_ID_g, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+/* Group access property list class library initialization object */
+/* (move to proper source code file when used for real) */
+const H5P_libclass_t H5P_CLS_GACC[1] = {{
+ "group access", /* Class name for debugging */
+ H5P_TYPE_GROUP_ACCESS, /* Class type */
+
+ &H5P_CLS_LINK_ACCESS_g, /* Parent class */
+ &H5P_CLS_GROUP_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_GROUP_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_GROUP_ACCESS_ID_g, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+/* Datatype creation property list class library initialization object */
+/* (move to proper source code file when used for real) */
+const H5P_libclass_t H5P_CLS_TCRT[1] = {{
+ "datatype create", /* Class name for debugging */
+ H5P_TYPE_DATATYPE_CREATE, /* Class type */
+
+ &H5P_CLS_OBJECT_CREATE_g, /* Parent class */
+ &H5P_CLS_DATATYPE_CREATE_g, /* Pointer to class */
+ &H5P_CLS_DATATYPE_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_DATATYPE_CREATE_ID_g, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+/* Datatype access property list class library initialization object */
+/* (move to proper source code file when used for real) */
+const H5P_libclass_t H5P_CLS_TACC[1] = {{
+ "datatype access", /* Class name for debugging */
+ H5P_TYPE_DATATYPE_ACCESS, /* Class type */
+
+ &H5P_CLS_LINK_ACCESS_g, /* Parent class */
+ &H5P_CLS_DATATYPE_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_DATATYPE_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_DATATYPE_ACCESS_ID_g, /* Pointer to default property list ID */
+ NULL, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/* Library property list classes defined in other code modules */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_OCRT[1]; /* Object creation */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_STRCRT[1]; /* String create */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_GCRT[1]; /* Group create */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_OCPY[1]; /* Object copy */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_FCRT[1]; /* File creation */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_DCRT[1]; /* Dataset creation */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_DXFR[1]; /* Data transfer */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_FMNT[1]; /* File mount */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_ACRT[1]; /* Attribute creation */
+H5_DLLVAR const H5P_libclass_t H5P_CLS_LCRT[1]; /* Link creation */
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Track the revision count of a class, to make comparisons faster */
+static unsigned H5P_next_rev = 0;
+#define H5P_GET_NEXT_REV (H5P_next_rev++)
+
+/* List of all property list classes in the library */
+/* (order here is not important, they will be initialized in the proper
+ * order according to their parent class dependencies)
+ */
+static H5P_libclass_t const * const init_class[] = {
+ H5P_CLS_ROOT, /* Root */
+ H5P_CLS_OCRT, /* Object create */
+ H5P_CLS_STRCRT, /* String create */
+ H5P_CLS_LACC, /* Link access */
+ H5P_CLS_GCRT, /* Group create */
+ H5P_CLS_OCPY, /* Object copy */
+ H5P_CLS_GACC, /* Group access */
+ H5P_CLS_FCRT, /* File creation */
+ H5P_CLS_FACC, /* File access */
+ H5P_CLS_DCRT, /* Dataset creation */
+ H5P_CLS_DACC, /* Dataset access */
+ H5P_CLS_DXFR, /* Data transfer */
+ H5P_CLS_FMNT, /* File mount */
+ H5P_CLS_TCRT, /* Datatype creation */
+ H5P_CLS_TACC, /* Datatype access */
+ H5P_CLS_ACRT, /* Attribute creation */
+ H5P_CLS_AACC, /* Attribute access */
+ H5P_CLS_LCRT /* Link creation */
+};
+
+/* Declare a free list to manage the H5P_genclass_t struct */
+H5FL_DEFINE_STATIC(H5P_genclass_t);
+
+/* Declare a free list to manage the H5P_genprop_t struct */
+H5FL_DEFINE_STATIC(H5P_genprop_t);
+
+/* Declare a free list to manage the H5P_genplist_t struct */
+H5FL_DEFINE_STATIC(H5P_genplist_t);
+
+/* Generic Property Class ID class */
+static const H5I_class_t H5I_GENPROPCLS_CLS[1] = {{
+ H5I_GENPROP_CLS, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5P_close_class /* Callback routine for closing objects of this class */
+}};
+
+/* Generic Property List ID class */
+static const H5I_class_t H5I_GENPROPLST_CLS[1] = {{
+ H5I_GENPROP_LST, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ (H5I_free_t)H5P_close /* Callback routine for closing objects of this class */
+}};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_init
+ *
+ * Purpose: Initialize the interface from some other layer.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 4, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_init() */
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5P__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5P__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+--------------------------------------------------------------------------*/
+herr_t
+H5P__init_package(void)
+{
+ size_t tot_init; /* Total # of classes initialized */
+ size_t pass_init; /* # of classes initialized in each pass */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /*
+ * Initialize the Generic Property class & object groups.
+ */
+ if(H5I_register_type(H5I_GENPROPCLS_CLS) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group")
+ if(H5I_register_type(H5I_GENPROPLST_CLS) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group")
+
+ /* Repeatedly pass over the list of property list classes for the library,
+ * initializing each class if it's parent class is initialized, until no
+ * more progress is made.
+ */
+ tot_init = 0;
+ do {
+ size_t u; /* Local index variable */
+
+ /* Reset pass initialization counter */
+ pass_init = 0;
+
+ /* Make a pass over all the library's property list classes */
+ for(u = 0; u < NELMTS(init_class); u++) {
+ H5P_libclass_t const *lib_class = init_class[u]; /* Current class to operate on */
+
+ /* Check if the current class hasn't been initialized and can be now */
+ HDassert(lib_class->class_id);
+ if(*lib_class->class_id == (-1) && (lib_class->par_pclass == NULL
+ || *lib_class->par_pclass != NULL)) {
+ /* Sanity check - only the root class is not allowed to have a parent class */
+ HDassert(lib_class->par_pclass || lib_class == H5P_CLS_ROOT);
+
+ /* Allocate the new class */
+ if(NULL == (*lib_class->pclass = H5P_create_class(lib_class->par_pclass ? *lib_class->par_pclass : NULL, lib_class->name, lib_class->type, lib_class->create_func, lib_class->create_data, lib_class->copy_func, lib_class->copy_data, lib_class->close_func, lib_class->close_data)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "class initialization failed")
+
+ /* Call routine to register properties for class */
+ if(lib_class->reg_prop_func && (*lib_class->reg_prop_func)(*lib_class->pclass) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register properties")
+
+ /* Register the new class */
+ if((*lib_class->class_id = H5I_register(H5I_GENPROP_CLS, *lib_class->pclass, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register property list class")
+
+ /* Only register the default property list if it hasn't been created yet */
+ if(lib_class->def_plist_id && *lib_class->def_plist_id == (-1)) {
+ /* Register the default property list for the new class*/
+ if((*lib_class->def_plist_id = H5P_create_id(*lib_class->pclass, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register default property list for class")
+ } /* end if */
+
+ /* Increment class initialization counters */
+ pass_init++;
+ tot_init++;
+ } /* end if */
+ } /* end for */
+ } while(pass_init > 0);
+
+ /* Verify that all classes were initialized */
+ HDassert(tot_init == NELMTS(init_class));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__init_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_term_package
+ PURPOSE
+ Terminate various H5P objects
+ USAGE
+ void H5P_term_package()
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Release the atom group and any other resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5P_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ int64_t nlist, nclass;
+
+ /* Destroy HDF5 library property classes & lists */
+
+ /* Check if there are any open property list classes or lists */
+ nclass = H5I_nmembers(H5I_GENPROP_CLS);
+ nlist = H5I_nmembers(H5I_GENPROP_LST);
+
+ /* If there are any open classes or groups, attempt to get rid of them. */
+ if((nclass + nlist) > 0) {
+ /* Clear the lists */
+ if(nlist > 0) {
+ (void)H5I_clear_type(H5I_GENPROP_LST, FALSE, FALSE);
+
+ /* Reset the default property lists, if they've been closed */
+ if(H5I_nmembers(H5I_GENPROP_LST) == 0) {
+ H5P_LST_FILE_CREATE_ID_g =
+ H5P_LST_FILE_ACCESS_ID_g =
+ H5P_LST_DATASET_CREATE_ID_g =
+ H5P_LST_DATASET_ACCESS_ID_g =
+ H5P_LST_DATASET_XFER_ID_g =
+ H5P_LST_GROUP_CREATE_ID_g =
+ H5P_LST_GROUP_ACCESS_ID_g =
+ H5P_LST_DATATYPE_CREATE_ID_g =
+ H5P_LST_DATATYPE_ACCESS_ID_g =
+ H5P_LST_ATTRIBUTE_CREATE_ID_g =
+ H5P_LST_ATTRIBUTE_ACCESS_ID_g =
+ H5P_LST_OBJECT_COPY_ID_g =
+ H5P_LST_LINK_CREATE_ID_g =
+ H5P_LST_LINK_ACCESS_ID_g =
+ H5P_LST_FILE_MOUNT_ID_g = (-1);
+ } /* end if */
+ } /* end if */
+
+ /* Only attempt to close the classes after all the lists are closed */
+ if(nlist == 0 && nclass > 0) {
+ (void)H5I_clear_type(H5I_GENPROP_CLS, FALSE, FALSE);
+
+ /* Reset the default property classes, if they've been closed */
+ if(H5I_nmembers(H5I_GENPROP_CLS) == 0) {
+ H5P_CLS_ROOT_g =
+ H5P_CLS_OBJECT_CREATE_g =
+ H5P_CLS_FILE_CREATE_g =
+ H5P_CLS_FILE_ACCESS_g =
+ H5P_CLS_DATASET_CREATE_g =
+ H5P_CLS_DATASET_ACCESS_g =
+ H5P_CLS_DATASET_XFER_g =
+ H5P_CLS_GROUP_CREATE_g =
+ H5P_CLS_GROUP_ACCESS_g =
+ H5P_CLS_DATATYPE_CREATE_g =
+ H5P_CLS_DATATYPE_ACCESS_g =
+ H5P_CLS_STRING_CREATE_g =
+ H5P_CLS_ATTRIBUTE_CREATE_g =
+ H5P_CLS_ATTRIBUTE_ACCESS_g =
+ H5P_CLS_OBJECT_COPY_g =
+ H5P_CLS_LINK_CREATE_g =
+ H5P_CLS_LINK_ACCESS_g =
+ H5P_CLS_FILE_MOUNT_g = NULL;
+
+ H5P_CLS_ROOT_ID_g =
+ H5P_CLS_OBJECT_CREATE_ID_g =
+ H5P_CLS_FILE_CREATE_ID_g =
+ H5P_CLS_FILE_ACCESS_ID_g =
+ H5P_CLS_DATASET_CREATE_ID_g =
+ H5P_CLS_DATASET_ACCESS_ID_g =
+ H5P_CLS_DATASET_XFER_ID_g =
+ H5P_CLS_GROUP_CREATE_ID_g =
+ H5P_CLS_GROUP_ACCESS_ID_g =
+ H5P_CLS_DATATYPE_CREATE_ID_g =
+ H5P_CLS_DATATYPE_ACCESS_ID_g =
+ H5P_CLS_STRING_CREATE_ID_g =
+ H5P_CLS_ATTRIBUTE_CREATE_ID_g =
+ H5P_CLS_ATTRIBUTE_ACCESS_ID_g =
+ H5P_CLS_OBJECT_COPY_ID_g =
+ H5P_CLS_LINK_CREATE_ID_g =
+ H5P_CLS_LINK_ACCESS_ID_g =
+ H5P_CLS_FILE_MOUNT_ID_g = (-1);
+ } /* end if */
+ } /* end if */
+
+ n++; /*H5I*/
+ } else {
+ /* Destroy the property list and class id groups */
+ n += (H5I_dec_type_ref(H5I_GENPROP_LST) > 0);
+ n += (H5I_dec_type_ref(H5I_GENPROP_CLS) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5P_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__do_prop_cb1
+ PURPOSE
+ Internal routine to call a property list callback routine and update
+ the property list accordingly.
+ USAGE
+ herr_t H5P__do_prop_cb1(slist,prop,cb)
+ H5SL_t *slist; IN/OUT: Skip list to hold changed properties
+ H5P_genprop_t *prop; IN: Property to call callback for
+ H5P_prp_cb1_t *cb; IN: Callback routine to call
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Calls the callback routine passed in. If the callback routine changes
+ the property value, then the property is duplicated and added to skip list.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__do_prop_cb1(H5SL_t *slist, H5P_genprop_t *prop, H5P_prp_cb1_t cb)
+{
+ void *tmp_value = NULL; /* Temporary value buffer */
+ H5P_genprop_t *pcopy = NULL; /* Copy of property to insert into skip list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(slist);
+ HDassert(prop);
+ HDassert(prop->cmp);
+ HDassert(cb);
+
+ /* Allocate space for a temporary copy of the property value */
+ if(NULL == (tmp_value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary property value")
+ HDmemcpy(tmp_value, prop->value, prop->size);
+
+ /* Call "type 1" callback ('create', 'copy' or 'close') */
+ if(cb(prop->name, prop->size, tmp_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL,"Property callback failed")
+
+ /* Make a copy of the class's property */
+ if(NULL == (pcopy = H5P_dup_prop(prop, H5P_PROP_WITHIN_LIST)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "Can't copy property")
+
+ /* Copy the changed value into the new property */
+ HDmemcpy(pcopy->value, tmp_value, prop->size);
+
+ /* Insert the changed property into the property list */
+ if(H5P_add_prop(slist, pcopy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "Can't insert property into skip list")
+
+done:
+ /* Release the temporary value buffer */
+ if(tmp_value)
+ H5MM_xfree(tmp_value);
+
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(pcopy)
+ H5P_free_prop(pcopy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__do_prop_cb1() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_copy_pclass
+ PURPOSE
+ Internal routine to copy a generic property class
+ USAGE
+ hid_t H5P_copy_pclass(pclass)
+ H5P_genclass_t *pclass; IN: Property class to copy
+ RETURNS
+ Success: valid property class ID on success (non-negative)
+ Failure: negative
+ DESCRIPTION
+ Copy a property class and return the ID. This routine does not make
+ any callbacks. (They are only make when operating on property lists).
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genclass_t *
+H5P_copy_pclass(H5P_genclass_t *pclass)
+{
+ H5P_genclass_t *new_pclass = NULL; /* Property list class copied */
+ H5P_genprop_t *pcopy; /* Copy of property to insert into class */
+ H5P_genclass_t *ret_value=NULL; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+
+ /*
+ * Create new property class object
+ */
+
+ /* Create the new property list class */
+ if(NULL == (new_pclass = H5P_create_class(pclass->parent, pclass->name, pclass->type, pclass->create_func, pclass->create_data, pclass->copy_func, pclass->copy_data, pclass->close_func, pclass->close_data)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, NULL, "unable to create property list class")
+
+ /* Copy the properties registered for this class */
+ if(pclass->nprops > 0) {
+ H5SL_node_t *curr_node; /* Current node in skip list */
+
+ /* Walk through the properties in the old class */
+ curr_node=H5SL_first(pclass->props);
+ while(curr_node!=NULL) {
+ /* Make a copy of the class's property */
+ if(NULL == (pcopy = H5P_dup_prop((H5P_genprop_t *)H5SL_item(curr_node), H5P_PROP_WITHIN_CLASS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL,"Can't copy property")
+
+ /* Insert the initialized property into the property list */
+ if(H5P_add_prop(new_pclass->props,pcopy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, NULL,"Can't insert property into class")
+
+ /* Increment property count for class */
+ new_pclass->nprops++;
+
+ /* Get the next property node in the list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Set the return value */
+ ret_value=new_pclass;
+
+done:
+ if(ret_value==NULL && new_pclass)
+ H5P_close_class(new_pclass);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_copy_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_copy_plist
+ PURPOSE
+ Internal routine to copy a generic property list
+ USAGE
+ hid_t H5P_copy_plist(old_plist_id)
+ hid_t old_plist_id; IN: Property list ID to copy
+ RETURNS
+ Success: valid property list ID on success (non-negative)
+ Failure: negative
+ DESCRIPTION
+ Copy a property list and return the ID. This routine calls the
+ class 'copy' callback after any property 'copy' callbacks are called
+ (assuming all property 'copy' callbacks return successfully).
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5P_copy_plist(const H5P_genplist_t *old_plist, hbool_t app_ref)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_genplist_t *new_plist=NULL; /* New property list generated from copy */
+ H5P_genprop_t *tmp; /* Temporary pointer to properties */
+ H5P_genprop_t *new_prop; /* New property created for copy */
+ hid_t new_plist_id; /* Property list ID of new list created */
+ H5SL_node_t *curr_node; /* Current node in skip list */
+ H5SL_t *seen=NULL; /* Skip list containing properties already seen */
+ size_t nseen; /* Number of items 'seen' */
+ hbool_t has_parent_class; /* Flag to indicate that this property list's class has a parent */
+ hid_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(old_plist);
+
+ /*
+ * Create new property list object
+ */
+
+ /* Allocate room for the property list */
+ if(NULL==(new_plist = H5FL_CALLOC(H5P_genplist_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,"memory allocation failed")
+
+ /* Set class state */
+ new_plist->pclass = old_plist->pclass;
+ new_plist->nprops = 0; /* Initially the plist has the same number of properties as the class */
+ new_plist->class_init = FALSE; /* Initially, wait until the class callback finishes to set */
+
+ /* Initialize the skip list to hold the changed properties */
+ if((new_plist->props = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for changed properties")
+
+ /* Create the skip list for deleted properties */
+ if((new_plist->del = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for deleted properties")
+
+ /* Create the skip list to hold names of properties already seen
+ * (This prevents a property in the class hierarchy from having it's
+ * 'create' callback called, if a property in the class hierarchy has
+ * already been seen)
+ */
+ if((seen = H5SL_create(H5SL_TYPE_STR, NULL))== NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties")
+ nseen = 0;
+
+ /* Cycle through the deleted properties & copy them into the new list's deleted section */
+ if(H5SL_count(old_plist->del)>0) {
+ curr_node=H5SL_first(old_plist->del);
+ while(curr_node) {
+ char *new_name; /* Pointer to new name */
+
+ /* Duplicate string for insertion into new deleted property skip list */
+ if((new_name=H5MM_xstrdup((char *)H5SL_item(curr_node))) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE,H5E_NOSPACE,FAIL,"memory allocation failed")
+
+ /* Insert property name into deleted list */
+ if(H5SL_insert(new_plist->del,new_name,new_name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into deleted skip list")
+
+ /* Add property name to "seen" list */
+ if(H5SL_insert(seen,new_name,new_name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list")
+ nseen++;
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Cycle through the properties and copy them also */
+ if(H5SL_count(old_plist->props)>0) {
+ curr_node=H5SL_first(old_plist->props);
+ while(curr_node) {
+ /* Get a pointer to the node's property */
+ tmp = (H5P_genprop_t *)H5SL_item(curr_node);
+
+ /* Make a copy of the list's property */
+ if(NULL == (new_prop = H5P_dup_prop(tmp, H5P_PROP_WITHIN_LIST)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property")
+
+ /* Call property copy callback, if it exists */
+ if(new_prop->copy) {
+ if((new_prop->copy)(new_prop->name,new_prop->size,new_prop->value) < 0) {
+ H5P_free_prop(new_prop);
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property")
+ } /* end if */
+ } /* end if */
+
+ /* Insert the initialized property into the property list */
+ if(H5P_add_prop(new_plist->props,new_prop) < 0) {
+ H5P_free_prop(new_prop);
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into list")
+ } /* end if */
+
+ /* Add property name to "seen" list */
+ if(H5SL_insert(seen,new_prop->name,new_prop->name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list")
+ nseen++;
+
+ /* Increment the number of properties in list */
+ new_plist->nprops++;
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /*
+ * Check for copying class properties (up through list of parent classes also),
+ * initialize each with default value & make property 'copy' callback.
+ */
+ tclass=old_plist->pclass;
+ has_parent_class = (hbool_t)(tclass != NULL && tclass->parent != NULL && tclass->parent->nprops > 0);
+ while(tclass!=NULL) {
+ if(tclass->nprops>0) {
+ /* Walk through the properties in the old class */
+ curr_node=H5SL_first(tclass->props);
+ while(curr_node!=NULL) {
+ /* Get pointer to property from node */
+ tmp = (H5P_genprop_t *)H5SL_item(curr_node);
+
+ /* Only "copy" properties we haven't seen before */
+ if(nseen==0 || H5SL_search(seen,tmp->name) == NULL) {
+ /* Call property copy callback, if it exists */
+ if(tmp->copy) {
+ /* Call the callback & insert changed value into skip list (if necessary) */
+ if(H5P__do_prop_cb1(new_plist->props, tmp, tmp->copy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't create property")
+ } /* end if */
+
+ /* Add property name to "seen" list, if we have other classes to work on */
+ if(has_parent_class) {
+ if(H5SL_insert(seen,tmp->name,tmp->name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list")
+ nseen++;
+ } /* end if */
+
+ /* Increment the number of properties in list */
+ new_plist->nprops++;
+ } /* end if */
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass=tclass->parent;
+ } /* end while */
+
+ /* Increment the number of property lists derived from class */
+ if(H5P_access_class(new_plist->pclass, H5P_MOD_INC_LST) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "Can't increment class ref count")
+
+ /* Get an atom for the property list */
+ if((new_plist_id = H5I_register(H5I_GENPROP_LST, new_plist, app_ref)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list")
+
+ /* Save the property list ID in the property list struct, for use in the property class's 'close' callback */
+ new_plist->plist_id=new_plist_id;
+
+ /* Call the class callback (if it exists) now that we have the property list ID
+ * (up through chain of parent classes also)
+ */
+ tclass = new_plist->pclass;
+ while(NULL != tclass) {
+ if(NULL != tclass->copy_func) {
+ if((tclass->copy_func)(new_plist_id, old_plist->plist_id, old_plist->pclass->copy_data) < 0) {
+ /* Delete ID, ignore return value */
+ H5I_remove(new_plist_id);
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property")
+ } /* end if */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* Set the class initialization flag */
+ new_plist->class_init = TRUE;
+
+ /* Set the return value */
+ ret_value=new_plist_id;
+
+done:
+ /* Release the list of 'seen' properties */
+ if(seen!=NULL)
+ H5SL_close(seen);
+
+ if(ret_value<0 && new_plist)
+ H5P_close(new_plist);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_copy_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_dup_prop
+ PURPOSE
+ Internal routine to duplicate a property
+ USAGE
+ H5P_genprop_t *H5P_dup_prop(oprop)
+ H5P_genprop_t *oprop; IN: Pointer to property to copy
+ H5P_prop_within_t type; IN: Type of object the property will be inserted into
+ RETURNS
+ Returns a pointer to the newly created duplicate of a property on success,
+ NULL on failure.
+ DESCRIPTION
+ Allocates memory and copies property information into a new property object.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5P_genprop_t *
+H5P_dup_prop(H5P_genprop_t *oprop, H5P_prop_within_t type)
+{
+ H5P_genprop_t *prop = NULL; /* Pointer to new property copied */
+ H5P_genprop_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(oprop);
+ HDassert(type != H5P_PROP_WITHIN_UNKNOWN);
+
+ /* Allocate the new property */
+ if(NULL == (prop = H5FL_MALLOC(H5P_genprop_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy basic property information */
+ HDmemcpy(prop, oprop, sizeof(H5P_genprop_t));
+
+ /* Check if we should duplicate the name or share it */
+
+ /* Duplicating property for a class */
+ if(type == H5P_PROP_WITHIN_CLASS) {
+ HDassert(oprop->type == H5P_PROP_WITHIN_CLASS);
+ HDassert(oprop->shared_name == FALSE);
+
+ /* Duplicate name */
+ prop->name = H5MM_xstrdup(oprop->name);
+ } /* end if */
+ /* Duplicating property for a list */
+ else {
+ /* Check if we are duplicating a property from a list or a class */
+
+ /* Duplicating a property from a list */
+ if(oprop->type == H5P_PROP_WITHIN_LIST) {
+ /* If the old property's name wasn't shared, we have to copy it here also */
+ if(!oprop->shared_name)
+ prop->name = H5MM_xstrdup(oprop->name);
+ } /* end if */
+ /* Duplicating a property from a class */
+ else {
+ HDassert(oprop->type == H5P_PROP_WITHIN_CLASS);
+ HDassert(oprop->shared_name == FALSE);
+
+ /* Share the name */
+ prop->shared_name = TRUE;
+
+ /* Set the type */
+ prop->type = type;
+ } /* end else */
+ } /* end else */
+
+ /* Duplicate current value, if it exists */
+ if(oprop->value != NULL) {
+ HDassert(prop->size > 0);
+ if(NULL == (prop->value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(prop->value, oprop->value, prop->size);
+ } /* end if */
+
+ /* Set return value */
+ ret_value = prop;
+
+done:
+ /* Free any resources allocated */
+ if(ret_value == NULL) {
+ if(prop != NULL) {
+ if(prop->name != NULL)
+ H5MM_xfree(prop->name);
+ if(prop->value != NULL)
+ H5MM_xfree(prop->value);
+ prop = H5FL_FREE(H5P_genprop_t, prop);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_dup_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_create_prop
+ PURPOSE
+ Internal routine to create a new property
+ USAGE
+ H5P_genprop_t *H5P_create_prop(name,size,type,value,prp_create,prp_set,
+ prp_get,prp_delete,prp_close, prp_encode, prp_decode)
+ const char *name; IN: Name of property to register
+ size_t size; IN: Size of property in bytes
+ H5P_prop_within_t type; IN: Type of object the property will be inserted into
+ void *value; IN: Pointer to buffer containing value for property
+ H5P_prp_create_func_t prp_create; IN: Function pointer to property
+ creation callback
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_encode_func_t prp_encode; IN: Function pointer to property encode
+ H5P_prp_decode_func_t prp_decode; IN: Function pointer to property decode
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns a pointer to the newly created property on success,
+ NULL on failure.
+ DESCRIPTION
+ Allocates memory and copies property information into a new property object.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5P_genprop_t *
+H5P_create_prop(const char *name, size_t size, H5P_prop_within_t type,
+ const void *value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close)
+{
+ H5P_genprop_t *prop = NULL; /* Pointer to new property copied */
+ H5P_genprop_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(name);
+ HDassert((size > 0 && value != NULL) || (size == 0));
+ HDassert(type != H5P_PROP_WITHIN_UNKNOWN);
+
+ /* Allocate the new property */
+ if(NULL == (prop = H5FL_MALLOC(H5P_genprop_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the property initial values */
+ prop->name = H5MM_xstrdup(name); /* Duplicate name */
+ prop->shared_name = FALSE;
+ prop->size = size;
+ prop->type = type;
+
+ /* Duplicate value, if it exists */
+ if(value != NULL) {
+ if(NULL == (prop->value = H5MM_malloc (prop->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemcpy(prop->value, value, prop->size);
+ } /* end if */
+ else
+ prop->value = NULL;
+
+ /* Set the function pointers */
+ prop->create = prp_create;
+ prop->set = prp_set;
+ prop->get = prp_get;
+ prop->encode = prp_encode;
+ prop->decode = prp_decode;
+ prop->del = prp_delete;
+ prop->copy = prp_copy;
+ /* Use custom comparison routine if available, otherwise default to memcmp() */
+ if(prp_cmp != NULL)
+ prop->cmp = prp_cmp;
+ else
+ prop->cmp = &memcmp;
+ prop->close = prp_close;
+
+ /* Set return value */
+ ret_value = prop;
+
+done:
+ /* Free any resources allocated */
+ if(ret_value == NULL) {
+ if(prop != NULL) {
+ if(prop->name != NULL)
+ H5MM_xfree(prop->name);
+ if(prop->value != NULL)
+ H5MM_xfree(prop->value);
+ prop = H5FL_FREE(H5P_genprop_t, prop);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_create_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_add_prop
+ PURPOSE
+ Internal routine to insert a property into a property skip list
+ USAGE
+ herr_t H5P_add_prop(slist, prop)
+ H5SL_t *slist; IN/OUT: Pointer to skip list of properties
+ H5P_genprop_t *prop; IN: Pointer to property to insert
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Inserts a property into a skip list of properties.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_add_prop(H5SL_t *slist, H5P_genprop_t *prop)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(slist);
+ HDassert(prop);
+ HDassert(prop->type != H5P_PROP_WITHIN_UNKNOWN);
+
+ /* Insert property into skip list */
+ if(H5SL_insert(slist, prop, prop->name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into skip list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_add_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__find_prop_plist
+ PURPOSE
+ Internal routine to check for a property in a property list's skip list
+ USAGE
+ H5P_genprop_t *H5P_find_prop(plist, name)
+ const H5P_genplist_t *plist; IN: Pointer to property list to check
+ const char *name; IN: Name of property to check for
+ RETURNS
+ Returns pointer to property on success, NULL on failure.
+ DESCRIPTION
+ Checks for a property in a property list's skip list of properties.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genprop_t *
+H5P__find_prop_plist(const H5P_genplist_t *plist, const char *name)
+{
+ H5P_genprop_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(plist);
+ HDassert(name);
+
+ /* Check if the property has been deleted from list */
+ if(H5SL_search(plist->del,name) != NULL) {
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "property deleted from skip list")
+ } /* end if */
+ else {
+ /* Get the property data from the skip list */
+ if(NULL == (ret_value = (H5P_genprop_t *)H5SL_search(plist->props, name))) {
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+
+ /* Couldn't find property in list itself, start searching through class info */
+ tclass = plist->pclass;
+ while(tclass != NULL) {
+ /* Find the property in the class */
+ if(NULL != (ret_value = (H5P_genprop_t *)H5SL_search(tclass->props, name)))
+ /* Got pointer to property - leave now */
+ break;
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* Check if we haven't found the property */
+ if(ret_value == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,NULL,"can't find property in skip list")
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__find_prop_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_find_prop_pclass
+ PURPOSE
+ Internal routine to check for a property in a class skip list
+ USAGE
+ H5P_genprop_t *H5P_find_prop_class(pclass, name)
+ H5P_genclass *pclass; IN: Pointer generic property class to check
+ const char *name; IN: Name of property to check for
+ RETURNS
+ Returns pointer to property on success, NULL on failure.
+ DESCRIPTION
+ Checks for a property in a class's skip list of properties.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5P_genprop_t *
+H5P_find_prop_pclass(H5P_genclass_t *pclass, const char *name)
+{
+ H5P_genprop_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+ HDassert(name);
+
+ /* Get the property from the skip list */
+ if(NULL == (ret_value = (H5P_genprop_t *)H5SL_search(pclass->props, name)))
+ HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,NULL,"can't find property in skip list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_find_prop_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_free_prop
+ PURPOSE
+ Internal routine to destroy a property node
+ USAGE
+ herr_t H5P_free_prop(prop)
+ H5P_genprop_t *prop; IN: Pointer to property to destroy
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Releases all the memory for a property list. Does _not_ call the
+ properties 'close' callback, that should already have been done.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P_free_prop(H5P_genprop_t *prop)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(prop);
+
+ /* Release the property value if it exists */
+ if(prop->value)
+ H5MM_xfree(prop->value);
+
+ /* Only free the name if we own it */
+ if(!prop->shared_name)
+ H5MM_xfree(prop->name);
+
+ prop = H5FL_FREE(H5P_genprop_t, prop);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5P_free_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_free_prop_cb
+ PURPOSE
+ Internal routine to properties from a property skip list
+ USAGE
+ herr_t H5P_free_prop_cb(item, key, op_data)
+ void *item; IN/OUT: Pointer to property
+ void *key; IN/OUT: Pointer to property key
+ void *_make_cb; IN: Whether to make property callbacks or not
+ RETURNS
+ Returns zero on success, negative on failure.
+ DESCRIPTION
+ Calls the property 'close' callback for a property & frees property
+ info.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P_free_prop_cb(void *item, void H5_ATTR_UNUSED *key, void *op_data)
+{
+ H5P_genprop_t *tprop=(H5P_genprop_t *)item; /* Temporary pointer to property */
+ hbool_t make_cb = *(hbool_t *)op_data; /* Whether to make property 'close' callback */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(tprop);
+
+ /* Call the close callback and ignore the return value, there's nothing we can do about it */
+ if(make_cb && tprop->close != NULL)
+ (tprop->close)(tprop->name, tprop->size, tprop->value);
+
+ /* Free the property, ignoring return value, nothing we can do */
+ H5P_free_prop(tprop);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5P_free_prop_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_free_del_name_cb
+ PURPOSE
+ Internal routine to free 'deleted' property name
+ USAGE
+ herr_t H5P_free_del_name_cb(item, key, op_data)
+ void *item; IN/OUT: Pointer to deleted name
+ void *key; IN/OUT: Pointer to key
+ void *op_data; IN: Operator callback data (unused)
+ RETURNS
+ Returns zero on success, negative on failure.
+ DESCRIPTION
+ Frees the deleted property name
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P_free_del_name_cb(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *op_data)
+{
+ char *del_name=(char *)item; /* Temporary pointer to deleted name */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(del_name);
+
+ /* Free the name */
+ H5MM_xfree(del_name);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5P_free_del_name_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_access_class
+ PURPOSE
+ Internal routine to increment or decrement list & class dependancies on a
+ property list class
+ USAGE
+ herr_t H5P_access_class(pclass,mod)
+ H5P_genclass_t *pclass; IN: Pointer to class to modify
+ H5P_class_mod_t mod; IN: Type of modification to class
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Increment/Decrement the class or list dependancies for a given class.
+ This routine is the final arbiter on decisions about actually releasing a
+ class in memory, such action is only taken when the reference counts for
+ both dependent classes & lists reach zero.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(pclass);
+ HDassert(mod > H5P_MOD_ERR && mod < H5P_MOD_MAX);
+
+ switch(mod) {
+ case H5P_MOD_INC_CLS: /* Increment the dependant class count*/
+ pclass->classes++;
+ break;
+
+ case H5P_MOD_DEC_CLS: /* Decrement the dependant class count*/
+ pclass->classes--;
+ break;
+
+ case H5P_MOD_INC_LST: /* Increment the dependant list count*/
+ pclass->plists++;
+ break;
+
+ case H5P_MOD_DEC_LST: /* Decrement the dependant list count*/
+ pclass->plists--;
+ break;
+
+ case H5P_MOD_INC_REF: /* Increment the ID reference count*/
+ /* Reset the deleted flag if incrementing the reference count */
+ if(pclass->deleted)
+ pclass->deleted = FALSE;
+ pclass->ref_count++;
+ break;
+
+ case H5P_MOD_DEC_REF: /* Decrement the ID reference count*/
+ pclass->ref_count--;
+
+ /* Mark the class object as deleted if reference count drops to zero */
+ if(pclass->ref_count == 0)
+ pclass->deleted = TRUE;
+ break;
+
+ case H5P_MOD_ERR:
+ case H5P_MOD_MAX:
+ default:
+ HDassert(0 && "Invalid H5P class modification");
+ } /* end switch */
+
+ /* Check if we can release the class information now */
+ if(pclass->deleted && pclass->plists == 0 && pclass->classes == 0) {
+ H5P_genclass_t *par_class = pclass->parent; /* Pointer to class's parent */
+
+ HDassert(pclass->name);
+ H5MM_xfree(pclass->name);
+
+ /* Free the class properties without making callbacks */
+ if(pclass->props) {
+ hbool_t make_cb = FALSE;
+
+ H5SL_destroy(pclass->props, H5P_free_prop_cb, &make_cb);
+ } /* end if */
+
+ pclass = H5FL_FREE(H5P_genclass_t, pclass);
+
+ /* Reduce the number of dependent classes on parent class also */
+ if(par_class != NULL)
+ H5P_access_class(par_class, H5P_MOD_DEC_CLS);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5P_access_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_open_class_path_cb
+ PURPOSE
+ Internal callback routine to check for duplicated names in parent class.
+ USAGE
+ int H5P_open_class_path_cb(obj, id, key)
+ H5P_genclass_t *obj; IN: Pointer to class
+ hid_t id; IN: ID of object being looked at
+ const void *key; IN: Pointer to information used to compare
+ classes.
+ RETURNS
+ Returns >0 on match, 0 on no match and <0 on failure.
+ DESCRIPTION
+ Checks whether a property list class has the same parent and name as a
+ new class being created. This is a callback routine for H5I_search()
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P_open_class_path_cb(void *_obj, hid_t H5_ATTR_UNUSED id, void *_key)
+{
+ H5P_genclass_t *obj = (H5P_genclass_t *)_obj; /* Pointer to the class for this ID */
+ H5P_check_class_t *key = (H5P_check_class_t *)_key; /* Pointer to key information for comparison */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(obj);
+ HDassert(H5I_GENPROP_CLS == H5I_get_type(id));
+ HDassert(key);
+
+ /* Check if the class object has the same parent as the new class */
+ if(obj->parent == key->parent) {
+ /* Check if they have the same name */
+ if(HDstrcmp(obj->name, key->name) == 0) {
+ key->new_class = obj;
+ ret_value = 1; /* Indicate a match */
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_open_class_path_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_create_class
+ PURPOSE
+ Internal routine to create a new property list class.
+ USAGE
+ H5P_genclass_t H5P_create_class(par_class, name, type,
+ cls_create, create_data, cls_close, close_data)
+ H5P_genclass_t *par_class; IN: Pointer to parent class
+ const char *name; IN: Name of class we are creating
+ H5P_plist_type_t type; IN: Type of class we are creating
+ H5P_cls_create_func_t; IN: The callback function to call when each
+ property list in this class is created.
+ void *create_data; IN: Pointer to user data to pass along to class
+ creation callback.
+ H5P_cls_copy_func_t; IN: The callback function to call when each
+ property list in this class is copied.
+ void *copy_data; IN: Pointer to user data to pass along to class
+ copy callback.
+ H5P_cls_close_func_t; IN: The callback function to call when each
+ property list in this class is closed.
+ void *close_data; IN: Pointer to user data to pass along to class
+ close callback.
+ RETURNS
+ Returns a pointer to the newly created property list class on success,
+ NULL on failure.
+ DESCRIPTION
+ Allocates memory and attaches a class to the property list class hierarchy.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genclass_t *
+H5P_create_class(H5P_genclass_t *par_class, const char *name, H5P_plist_type_t type,
+ H5P_cls_create_func_t cls_create, void *create_data,
+ H5P_cls_copy_func_t cls_copy, void *copy_data,
+ H5P_cls_close_func_t cls_close, void *close_data)
+{
+ H5P_genclass_t *pclass = NULL; /* Property list class created */
+ H5P_genclass_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(name);
+ /* Allow internal classes to break some rules */
+ /* (This allows the root of the tree to be created with this routine -QAK) */
+ if(type == H5P_TYPE_USER)
+ HDassert(par_class);
+
+ /* Allocate room for the class */
+ if(NULL == (pclass = H5FL_CALLOC(H5P_genclass_t)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, NULL, "propery list class allocation failed")
+
+ /* Set class state */
+ pclass->parent = par_class;
+ if(NULL == (pclass->name = H5MM_xstrdup(name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, NULL, "propery list class name allocation failed")
+ pclass->type = type;
+ pclass->nprops = 0; /* Classes are created without properties initially */
+ pclass->plists = 0; /* No properties lists of this class yet */
+ pclass->classes = 0; /* No classes derived from this class yet */
+ pclass->ref_count = 1; /* This is the first reference to the new class */
+ pclass->deleted = FALSE; /* Not deleted yet... :-) */
+ pclass->revision = H5P_GET_NEXT_REV; /* Get a revision number for the class */
+
+ /* Create the skip list for properties */
+ if(NULL == (pclass->props = H5SL_create(H5SL_TYPE_STR, NULL)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, NULL, "can't create skip list for properties")
+
+ /* Set callback functions and pass-along data */
+ pclass->create_func = cls_create;
+ pclass->create_data = create_data;
+ pclass->copy_func = cls_copy;
+ pclass->copy_data = copy_data;
+ pclass->close_func = cls_close;
+ pclass->close_data = close_data;
+
+ /* Increment parent class's derived class value */
+ if(par_class != NULL) {
+ if(H5P_access_class(par_class, H5P_MOD_INC_CLS) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, NULL, "Can't increment parent class ref count")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = pclass;
+
+done:
+ /* Free any resources allocated */
+ if(ret_value == NULL)
+ if(pclass) {
+ if(pclass->name)
+ H5MM_xfree(pclass->name);
+ if(pclass->props) {
+ hbool_t make_cb = FALSE;
+
+ H5SL_destroy(pclass->props, H5P_free_prop_cb, &make_cb);
+ } /* end if */
+ pclass = H5FL_FREE(H5P_genclass_t, pclass);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_create_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_create
+ PURPOSE
+ Internal routine to create a new property list of a property list class.
+ USAGE
+ H5P_genplist_t *H5P_create(class)
+ H5P_genclass_t *class; IN: Property list class create list from
+ RETURNS
+ Returns a pointer to the newly created property list on success,
+ NULL on failure.
+ DESCRIPTION
+ Creates a property list of a given class. If a 'create' callback
+ exists for the property list class, it is called before the
+ property list is passed back to the user.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ If this routine is called from a library routine other than
+ H5P_c, the calling routine is responsible for getting an ID for
+ the property list and calling the class 'create' callback (if one exists)
+ and also setting the "class_init" flag.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5P_genplist_t *
+H5P_create(H5P_genclass_t *pclass)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_genplist_t *plist = NULL; /* New property list created */
+ H5P_genprop_t *tmp; /* Temporary pointer to parent class properties */
+ H5SL_t *seen = NULL; /* Skip list to hold names of properties already seen */
+ H5P_genplist_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+
+ /*
+ * Create new property list object
+ */
+
+ /* Allocate room for the property list */
+ if(NULL==(plist = H5FL_CALLOC(H5P_genplist_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,"memory allocation failed")
+
+ /* Set class state */
+ plist->pclass = pclass;
+ plist->nprops = 0; /* Initially the plist has the same number of properties as the class */
+ plist->class_init = FALSE; /* Initially, wait until the class callback finishes to set */
+
+ /* Create the skip list for changed properties */
+ if((plist->props = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for changed properties")
+
+ /* Create the skip list for deleted properties */
+ if((plist->del = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for deleted properties")
+
+ /* Create the skip list to hold names of properties already seen
+ * (This prevents a property in the class hierarchy from having it's
+ * 'create' callback called, if a property in the class hierarchy has
+ * already been seen)
+ */
+ if((seen = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for seen properties")
+
+ /*
+ * Check if we should copy class properties (up through list of parent classes also),
+ * initialize each with default value & make property 'create' callback.
+ */
+ tclass=pclass;
+ while(tclass!=NULL) {
+ if(tclass->nprops>0) {
+ H5SL_node_t *curr_node; /* Current node in skip list */
+
+ /* Walk through the properties in the old class */
+ curr_node=H5SL_first(tclass->props);
+ while(curr_node!=NULL) {
+ /* Get pointer to property from node */
+ tmp = (H5P_genprop_t *)H5SL_item(curr_node);
+
+ /* Only "create" properties we haven't seen before */
+ if(H5SL_search(seen,tmp->name) == NULL) {
+ /* Call property creation callback, if it exists */
+ if(tmp->create) {
+ /* Call the callback & insert changed value into skip list (if necessary) */
+ if(H5P__do_prop_cb1(plist->props, tmp, tmp->create) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL,"Can't create property")
+ } /* end if */
+
+ /* Add property name to "seen" list */
+ if(H5SL_insert(seen,tmp->name,tmp->name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,NULL,"can't insert property into seen skip list")
+
+ /* Increment the number of properties in list */
+ plist->nprops++;
+ } /* end if */
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass=tclass->parent;
+ } /* end while */
+
+ /* Increment the number of property lists derived from class */
+ if(H5P_access_class(plist->pclass,H5P_MOD_INC_LST) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, NULL,"Can't increment class ref count")
+
+ /* Set return value */
+ ret_value=plist;
+
+done:
+ /* Release the skip list of 'seen' properties */
+ if(seen!=NULL)
+ H5SL_close(seen);
+
+ /* Release resources allocated on failure */
+ if(ret_value==NULL) {
+ if(plist!=NULL) {
+ /* Close & free any changed properties */
+ if(plist->props) {
+ unsigned make_cb=1;
+
+ H5SL_destroy(plist->props,H5P_free_prop_cb,&make_cb);
+ } /* end if */
+
+ /* Close the deleted property skip list */
+ if(plist->del)
+ H5SL_close(plist->del);
+
+ /* Release the property list itself */
+ plist = H5FL_FREE(H5P_genplist_t, plist);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_create_id
+ PURPOSE
+ Internal routine to create a new property list of a property list class.
+ USAGE
+ hid_t H5P_create_id(pclass)
+ H5P_genclass_t *pclass; IN: Property list class create list from
+ RETURNS
+ Returns a valid property list ID on success, FAIL on failure.
+ DESCRIPTION
+ Creates a property list of a given class. If a 'create' callback
+ exists for the property list class, it is called before the
+ property list is passed back to the user. If 'create' callbacks exist for
+ any individual properties in the property list, they are called before the
+ class 'create' callback.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5P_create_id(H5P_genclass_t *pclass, hbool_t app_ref)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_genplist_t *plist = NULL; /* Property list created */
+ hid_t plist_id = FAIL; /* Property list ID */
+ hid_t ret_value = H5I_INVALID_HID; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pclass);
+
+ /* Create the new property list */
+ if((plist=H5P_create(pclass)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create property list")
+
+ /* Get an atom for the property list */
+ if((plist_id = H5I_register(H5I_GENPROP_LST, plist, app_ref)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list")
+
+ /* Save the property list ID in the property list struct, for use in the property class's 'close' callback */
+ plist->plist_id=plist_id;
+
+ /* Call the class callback (if it exists) now that we have the property list ID
+ * (up through chain of parent classes also)
+ */
+ tclass = plist->pclass;
+ while(NULL != tclass) {
+ if(NULL != tclass->create_func) {
+ if((tclass->create_func)(plist_id, tclass->create_data) < 0) {
+ /* Delete ID, ignore return value */
+ H5I_remove(plist_id);
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property")
+ } /* end if */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* Set the class initialization flag */
+ plist->class_init = TRUE;
+
+ /* Set the return value */
+ ret_value=plist_id;
+
+done:
+ if(ret_value<0 && plist)
+ H5P_close(plist);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_create_id() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_register_real
+ PURPOSE
+ Internal routine to register a new property in a property list class.
+ USAGE
+ herr_t H5P_register_real(class, name, size, default, prp_create, prp_set,
+ prp_get, prp_close, prp_encode, prp_decode)
+ H5P_genclass_t *class; IN: Property list class to modify
+ const char *name; IN: Name of property to register
+ size_t size; IN: Size of property in bytes
+ void *def_value; IN: Pointer to buffer containing default value
+ for property in newly created property lists
+ H5P_prp_create_func_t prp_create; IN: Function pointer to property
+ creation callback
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_encode_func_t prp_encode; IN: Function pointer to property encode
+ H5P_prp_decode_func_t prp_decode; IN: Function pointer to property decode
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Registers a new property with a property list class. The property will
+ exist in all property list objects of that class after this routine is
+ finished. The name of the property must not already exist. The default
+ property value must be provided and all new property lists created with this
+ property will have the property value set to the default provided. Any of
+ the callback routines may be set to NULL if they are not needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'default' pointer for a
+ zero-sized property may be set to NULL. The property 'create' & 'close'
+ callbacks are called for zero-sized properties, but the 'set' and 'get'
+ callbacks are never called.
+
+ The 'create' callback is called when a new property list with this
+ property is being created. H5P_prp_create_func_t is defined as:
+ typedef herr_t (*H5P_prp_create_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *initial_value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being created.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *initial_value; IN/OUT: The initial value for the property being created.
+ (The 'default' value passed to H5Pregister2)
+ The 'create' routine may modify the value to be set and those changes will
+ be stored as the initial value of the property. If the 'create' routine
+ returns a negative value, the new property value is not copied into the
+ property and the property list creation routine returns an error value.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ The 'encode' callback is called when a property list with this
+ property is being encoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to encode.
+ size_t *size; IN/OUT: The size of the buffer to encode the property.
+ void *value; IN: The value of the property being encoded.
+ void *plist; IN: The property list structure.
+ uint8_t **buf; OUT: The buffer that holds the encoded property;
+ The 'encode' routine returns the size needed to encode the property value
+ if the buffer passed in is NULL or the size is zero. Otherwise it encodes
+ the property value into binary in buf.
+
+ The 'decode' callback is called when a property list with this
+ property is being decoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to decode.
+ size_t *size; IN: H5_ATTR_UNUSED
+ void *value; IN: H5_ATTR_UNUSED
+ void *plist; IN: The property list structure.
+ uint8_t **buf; IN: The buffer that holds the binary encoded property;
+ The 'decode' routine decodes the binary buffer passed in and transforms it into
+ corresponding property values that are set in the property list passed in.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_register_real(H5P_genclass_t *pclass, const char *name, size_t size,
+ const void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close)
+{
+ H5P_genprop_t *new_prop = NULL; /* Temporary property pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pclass);
+ HDassert(0 == pclass->plists);
+ HDassert(0 == pclass->classes);
+ HDassert(name);
+ HDassert((size > 0 && def_value != NULL) || (size == 0));
+
+ /* Check for duplicate named properties */
+ if(NULL != H5SL_search(pclass->props, name))
+ HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists")
+
+ /* Create property object from parameters */
+ if(NULL == (new_prop = H5P_create_prop(name, size, H5P_PROP_WITHIN_CLASS,
+ def_value, prp_create, prp_set, prp_get, prp_encode, prp_decode,
+ prp_delete, prp_copy, prp_cmp, prp_close)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL,"Can't create property")
+
+ /* Insert property into property list class */
+ if(H5P_add_prop(pclass->props, new_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class")
+
+ /* Increment property count for class */
+ pclass->nprops++;
+
+ /* Update the revision for the class */
+ pclass->revision = H5P_GET_NEXT_REV;
+
+done:
+ if(ret_value < 0)
+ if(new_prop && H5P_free_prop(new_prop) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "unable to close property")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_register_real() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_register
+ PURPOSE
+ Internal routine to register a new property in a property list class.
+ USAGE
+ herr_t H5P_register(class, name, size, default, prp_create, prp_set, prp_get, prp_close)
+ H5P_genclass_t **class; IN: Property list class to modify
+ const char *name; IN: Name of property to register
+ size_t size; IN: Size of property in bytes
+ void *def_value; IN: Pointer to buffer containing default value
+ for property in newly created property lists
+ H5P_prp_create_func_t prp_create; IN: Function pointer to property
+ creation callback
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_encode_func_t prp_encode; IN: Function pointer to property encode
+ H5P_prp_decode_func_t prp_decode; IN: Function pointer to property decode
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Registers a new property with a property list class. The property will
+ exist in all property list objects of that class after this routine is
+ finished. The name of the property must not already exist. The default
+ property value must be provided and all new property lists created with this
+ property will have the property value set to the default provided. Any of
+ the callback routines may be set to NULL if they are not needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'default' pointer for a
+ zero-sized property may be set to NULL. The property 'create' & 'close'
+ callbacks are called for zero-sized properties, but the 'set' and 'get'
+ callbacks are never called.
+
+ The 'create' callback is called when a new property list with this
+ property is being created. H5P_prp_create_func_t is defined as:
+ typedef herr_t (*H5P_prp_create_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *initial_value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being created.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *initial_value; IN/OUT: The initial value for the property being created.
+ (The 'default' value passed to H5Pregister2)
+ The 'create' routine may modify the value to be set and those changes will
+ be stored as the initial value of the property. If the 'create' routine
+ returns a negative value, the new property value is not copied into the
+ property and the property list creation routine returns an error value.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'encode' callback is called when a property list with this
+ property is being encoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to encode.
+ size_t *size; IN/OUT: The size of the buffer to encode the property.
+ void *value; IN: The value of the property being encoded.
+ void *plist; IN: The property list structure.
+ uint8_t **buf; OUT: The buffer that holds the encoded property;
+ The 'encode' routine returns the size needed to encode the property value
+ if the buffer passed in is NULL or the size is zero. Otherwise it encodes
+ the property value into binary in buf.
+
+ The 'decode' callback is called when a property list with this
+ property is being decoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to decode.
+ size_t *size; IN: H5_ATTR_UNUSED
+ void *value; IN: H5_ATTR_UNUSED
+ void *plist; IN: The property list structure.
+ uint8_t **buf; IN: The buffer that holds the binary encoded property;
+ The 'decode' routine decodes the binary buffer passed in and transforms it into
+ corresponding property values that are set in the property list passed in.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_register(H5P_genclass_t **ppclass, const char *name, size_t size,
+ const void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close)
+{
+ H5P_genclass_t *pclass = *ppclass; /* Pointer to class to modify */
+ H5P_genclass_t *new_class = NULL; /* New class pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(ppclass);
+ HDassert(pclass);
+
+ /* Check if class needs to be split because property lists or classes have
+ * been created since the last modification was made to the class.
+ */
+ if(pclass->plists > 0 || pclass->classes > 0) {
+ if(NULL == (new_class = H5P_create_class(pclass->parent, pclass->name,
+ pclass->type, pclass->create_func, pclass->create_data,
+ pclass->copy_func, pclass->copy_data,
+ pclass->close_func, pclass->close_data)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy class")
+
+ /* Walk through the skip list of the old class and copy properties */
+ if(pclass->nprops > 0) {
+ H5SL_node_t *curr_node; /* Current node in skip list */
+
+ /* Walk through the properties in the old class */
+ curr_node = H5SL_first(pclass->props);
+ while(curr_node != NULL) {
+ H5P_genprop_t *pcopy; /* Property copy */
+
+ /* Make a copy of the class's property */
+ if(NULL == (pcopy = H5P_dup_prop((H5P_genprop_t *)H5SL_item(curr_node), H5P_PROP_WITHIN_CLASS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "Can't copy property")
+
+ /* Insert the initialized property into the property class */
+ if(H5P_add_prop(new_class->props, pcopy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class")
+
+ /* Increment property count for class */
+ new_class->nprops++;
+
+ /* Get the next property node in the skip list */
+ curr_node = H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Use the new class instead of the old one */
+ pclass = new_class;
+ } /* end if */
+
+ /* Really register the property in the class */
+ if(H5P_register_real(pclass, name, size, def_value, prp_create, prp_set, prp_get,
+ prp_encode, prp_decode, prp_delete, prp_copy, prp_cmp, prp_close) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "can't register property")
+
+ /* Update pointer to pointer to class, if a new one was generated */
+ if(new_class)
+ *ppclass = pclass;
+
+done:
+ if(ret_value < 0)
+ if(new_class && H5P_close_class(new_class) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "unable to close new property class")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_register() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_insert
+ PURPOSE
+ Internal routine to insert a new property in a property list.
+ USAGE
+ herr_t H5P_insert(plist, name, size, value, prp_set, prp_get, prp_close,
+ prp_encode, prp_decode)
+ H5P_genplist_t *plist; IN: Property list to add property to
+ const char *name; IN: Name of property to add
+ size_t size; IN: Size of property in bytes
+ void *value; IN: Pointer to the value for the property
+ H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback
+ H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback
+ H5P_prp_encode_func_t prp_encode; IN: Function pointer to property encode
+ H5P_prp_decode_func_t prp_decode; IN: Function pointer to property decode
+ H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback
+ H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback
+ H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback
+ H5P_prp_close_func_t prp_close; IN: Function pointer to property close
+ callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Inserts a temporary property into a property list. The property will
+ exist only in this property list object. The name of the property must not
+ already exist. The value must be provided unless the property is zero-
+ sized. Any of the callback routines may be set to NULL if they are not
+ needed.
+
+ Zero-sized properties are allowed and do not store any data in the
+ property list. These may be used as flags to indicate the presence or
+ absence of a particular piece of information. The 'value' pointer for a
+ zero-sized property may be set to NULL. The property 'close' callback is
+ called for zero-sized properties, but the 'set' and 'get' callbacks are
+ never called.
+
+ The 'set' callback is called before a new value is copied into the
+ property. H5P_prp_set_func_t is defined as:
+ typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being modified.
+ const char *name; IN: The name of the property being modified.
+ size_t size; IN: The size of the property value
+ void *new_value; IN/OUT: The value being set for the property.
+ The 'set' routine may modify the value to be set and those changes will be
+ stored as the value of the property. If the 'set' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list set routine returns an error value.
+
+ The 'get' callback is called before a value is retrieved from the
+ property. H5P_prp_get_func_t is defined as:
+ typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list being queried.
+ const char *name; IN: The name of the property being queried.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value being retrieved for the property.
+ The 'get' routine may modify the value to be retrieved and those changes
+ will be returned to the calling function. If the 'get' routine returns a
+ negative value, the property value is returned and the property list get
+ routine returns an error value.
+
+ The 'encode' callback is called when a property list with this
+ property is being encoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to encode.
+ size_t *size; IN/OUT: The size of the buffer to encode the property.
+ void *value; IN: The value of the property being encoded.
+ void *plist; IN: The property list structure.
+ uint8_t **buf; OUT: The buffer that holds the encoded property;
+ The 'encode' routine returns the size needed to encode the property value
+ if the buffer passed in is NULL or the size is zero. Otherwise it encodes
+ the property value into binary in buf.
+
+ The 'decode' callback is called when a property list with this
+ property is being decoded. H5P_prp_encode_func_t is defined as:
+ typedef herr_t (*H5P_prp_encode_func_t)(void *f, size_t *size,
+ void *value, void *plist, uint8_t **buf);
+ where the parameters to the callback function are:
+ void *f; IN: A fake file structure used to decode.
+ size_t *size; IN: H5_ATTR_UNUSED
+ void *value; IN: H5_ATTR_UNUSED
+ void *plist; IN: The property list structure.
+ uint8_t **buf; IN: The buffer that holds the binary encoded property;
+ The 'decode' routine decodes the binary buffer passed in and transforms it into
+ corresponding property values that are set in the property list passed in.
+
+ The 'delete' callback is called when a property is deleted from a
+ property list. H5P_prp_del_func_t is defined as:
+ typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name,
+ size_t size, void *value);
+ where the parameters to the callback function are:
+ hid_t prop_id; IN: The ID of the property list the property is deleted from.
+ const char *name; IN: The name of the property being deleted.
+ size_t size; IN: The size of the property value
+ void *value; IN/OUT: The value of the property being deleted.
+ The 'delete' routine may modify the value passed in, but the value is not
+ used by the library when the 'delete' routine returns. If the
+ 'delete' routine returns a negative value, the property list deletion
+ routine returns an error value but the property is still deleted.
+
+ The 'copy' callback is called when a property list with this
+ property is copied. H5P_prp_copy_func_t is defined as:
+ typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being copied.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being copied.
+ The 'copy' routine may modify the value to be copied and those changes will be
+ stored as the value of the property. If the 'copy' routine returns a
+ negative value, the new property value is not copied into the property and
+ the property list copy routine returns an error value.
+
+ The 'compare' callback is called when a property list with this
+ property is compared to another property list. H5P_prp_compare_func_t is
+ defined as:
+ typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2,
+ size_t size);
+ where the parameters to the callback function are:
+ const void *value1; IN: The value of the first property being compared.
+ const void *value2; IN: The value of the second property being compared.
+ size_t size; IN: The size of the property value
+ The 'compare' routine may not modify the values to be compared. The
+ 'compare' routine should return a positive value if VALUE1 is greater than
+ VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1
+ and VALUE2 are equal.
+
+ The 'close' callback is called when a property list with this
+ property is being destroyed. H5P_prp_close_func_t is defined as:
+ typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size,
+ void *value);
+ where the parameters to the callback function are:
+ const char *name; IN: The name of the property being closed.
+ size_t size; IN: The size of the property value
+ void *value; IN: The value of the property being closed.
+ The 'close' routine may modify the value passed in, but the value is not
+ used by the library when the 'close' routine returns. If the
+ 'close' routine returns a negative value, the property list close
+ routine returns an error value but the property list is still closed.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The 'set' callback function may be useful to range check the value being
+ set for the property or may perform some tranformation/translation of the
+ value set. The 'get' callback would then [probably] reverse the
+ transformation, etc. A single 'get' or 'set' callback could handle
+ multiple properties by performing different actions based on the property
+ name or other properties in the property list.
+
+ There is no 'create' callback routine for temporary property list
+ objects, the initial value is assumed to have any necessary setup already
+ performed on it.
+
+ I would like to say "the property list is not closed" when a 'close'
+ routine fails, but I don't think that's possible due to other properties in
+ the list being successfully closed & removed from the property list. I
+ suppose that it would be possible to just remove the properties which have
+ successful 'close' callbacks, but I'm not happy with the ramifications
+ of a mangled, un-closable property list hanging around... Any comments? -QAK
+
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_insert(H5P_genplist_t *plist, const char *name, size_t size,
+ void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close)
+{
+ H5P_genprop_t *new_prop = NULL; /* Temporary property pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(plist);
+ HDassert(name);
+ HDassert((size > 0 && value != NULL) || (size == 0));
+
+ /* Check for duplicate named properties */
+ if(NULL != H5SL_search(plist->props, name))
+ HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists")
+
+ /* Check if the property has been deleted */
+ if(NULL != H5SL_search(plist->del, name)) {
+ char *temp_name = NULL;
+
+ /* Remove the property name from the deleted property skip list */
+ if(NULL == (temp_name = (char *)H5SL_remove(plist->del, name)))
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTDELETE,FAIL,"can't remove property from deleted skip list")
+
+ /* free the name of the removed property */
+ H5MM_xfree(temp_name);
+ } /* end if */
+ else {
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+
+ /* Check if the property is already in the class hierarchy */
+ tclass = plist->pclass;
+ while(tclass) {
+ if(tclass->nprops > 0) {
+ /* Find the property in the class */
+ if(NULL != H5SL_search(tclass->props, name))
+ HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists")
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+ } /* end else */
+
+ /* Ok to add to property list */
+
+ /* Create property object from parameters */
+ if(NULL == (new_prop = H5P_create_prop(name, size, H5P_PROP_WITHIN_LIST, value, NULL,
+ prp_set, prp_get, prp_encode, prp_decode, prp_delete, prp_copy,
+ prp_cmp, prp_close)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "Can't create property")
+
+ /* Insert property into property list class */
+ if(H5P_add_prop(plist->props, new_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "Can't insert property into class")
+
+ /* Increment property count for class */
+ plist->nprops++;
+
+done:
+ if(ret_value < 0)
+ if(new_prop && H5P_free_prop(new_prop) < 0)
+ HDONE_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "unable to close property")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_insert() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__do_prop
+ PURPOSE
+ Internal routine to perform an operation on a property in a property list
+ USAGE
+ herr_t H5P__do_prop(plist, name, cb, udata)
+ H5P_genplist_t *plist; IN: Property list to find property in
+ const char *name; IN: Name of property to set
+ H5P_do_plist_op_t plist_op; IN: Pointer to the callback to invoke when the
+ property is found in the property list
+ H5P_do_pclass_op_t pclass_op; IN: Pointer to the callback to invoke when the
+ property is found in the property class
+ void *udata; IN: Pointer to the user data for the callback
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Finds a property in a property list and calls the callback with it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__do_prop(H5P_genplist_t *plist, const char *name, H5P_do_plist_op_t plist_op,
+ H5P_do_pclass_op_t pclass_op, void *udata)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(plist_op);
+ HDassert(pclass_op);
+
+ /* Check if the property has been deleted */
+ if(NULL != H5SL_search(plist->del, name))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist")
+
+ /* Find property in changed list */
+ if(NULL != (prop = (H5P_genprop_t *)H5SL_search(plist->props, name))) {
+ /* Call the 'found in propery list' callback */
+ if((*plist_op)(plist, name, prop, udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on property")
+ } /* end if */
+ else {
+ /*
+ * Check if we should set class properties (up through list of parent classes also),
+ * & make property 'set' callback.
+ */
+ tclass = plist->pclass;
+ while(NULL != tclass) {
+ if(tclass->nprops > 0) {
+ /* Find the property in the class */
+ if(NULL != (prop = (H5P_genprop_t *)H5SL_search(tclass->props, name))) {
+ /* Call the 'found in class' callback */
+ if((*pclass_op)(plist, name, prop, udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on property")
+
+ /* Leave */
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* If we get this far, then it wasn't in the list of changed properties,
+ * nor in the properties in the class hierarchy, indicate an error
+ */
+ if(NULL == tclass)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "can't find property in skip list")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__do_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__poke_plist_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to overwrite a property's value in a property list.
+ USAGE
+ herr_t H5P__poke_plist_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to overwrite property in
+ const char *name; IN: Name of property to overwrite
+ H5P_genprop_t *prop; IN: Property to overwrite
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Overwrite a value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property list.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__poke_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_set_ud_t *udata = (H5P_prop_set_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Overwrite value in property */
+ HDmemcpy(prop->value, udata->value, prop->size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__poke_plist_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__poke_pclass_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to overwrite a property's value in a property list.
+ USAGE
+ herr_t H5P__poke_pclass_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to overwrite property in
+ const char *name; IN: Name of property to overwrite
+ H5P_genprop_t *prop; IN: Property to overwrite
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Overwrite a value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property class.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__poke_pclass_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_set_ud_t *udata = (H5P_prop_set_ud_t *)_udata; /* User data for callback */
+ H5P_genprop_t *pcopy = NULL; /* Copy of property to insert into skip list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+ HDassert(prop->cmp);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Make a copy of the class's property */
+ if(NULL == (pcopy = H5P_dup_prop(prop, H5P_PROP_WITHIN_LIST)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "Can't copy property")
+
+ HDmemcpy(pcopy->value, udata->value, pcopy->size);
+
+ /* Insert the changed property into the property list */
+ if(H5P_add_prop(plist->props, pcopy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert changed property into skip list")
+
+done:
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(pcopy)
+ H5P_free_prop(pcopy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__poke_pclass_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_poke
+ PURPOSE
+ Internal routine to overwrite a property's value in a property list.
+ USAGE
+ herr_t H5P_poke(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to find property in
+ const char *name; IN: Name of property to overwrite
+ void *value; IN: Pointer to the value for the property
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Overwrites a property in a property list (i.e. a "shallow" copy over
+ the property value). The property name must exist or this routine will
+ fail. If there is a setget' callback routine registered for this property,
+ it is _NOT_ called.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine may not be called for zero-sized properties and will
+ return an error in that case.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_poke(H5P_genplist_t *plist, const char *name, const void *value)
+{
+ H5P_prop_set_ud_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(value);
+
+ /* Find the property and set the value */
+ udata.value = value;
+ if(H5P__do_prop(plist, name, H5P__poke_plist_cb, H5P__poke_pclass_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on plist to overwrite value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_poke() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__set_plist_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to set a property's value in a property list.
+ USAGE
+ herr_t H5P__set_plist_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to set property in
+ const char *name; IN: Name of property to set
+ H5P_genprop_t *prop; IN: Property to set
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Sets a new value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property list.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__set_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_set_ud_t *udata = (H5P_prop_set_ud_t *)_udata; /* User data for callback */
+ void *tmp_value = NULL; /* Temporary value for property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Make a copy of the value and pass to 'set' callback */
+ if(NULL != prop->set) {
+ /* Make a copy of the current value, in case the callback fails */
+ if(NULL == (tmp_value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value")
+ HDmemcpy(tmp_value, udata->value, prop->size);
+
+ /* Call user's callback */
+ if((*(prop->set))(plist->plist_id, name, prop->size, tmp_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value")
+ } /* end if */
+ /* No 'set' callback, just copy value */
+ else
+ tmp_value = (void *)udata->value; /* Casting away const OK -QAK */
+
+ /* Free any previous value for the property */
+ if(NULL != prop->del) {
+ /* Call user's 'delete' callback */
+ if((*(prop->del))(plist->plist_id, name, prop->size, prop->value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't release property value")
+ } /* end if */
+
+ /* Copy new [possibly unchanged] value into property value */
+ HDmemcpy(prop->value, tmp_value, prop->size);
+
+done:
+ /* Free the temporary value buffer */
+ if(tmp_value != NULL && tmp_value != udata->value)
+ H5MM_xfree(tmp_value);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__set_plist_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__set_pclass_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to set a property's value in a property list.
+ USAGE
+ herr_t H5P__set_pclass_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to set property in
+ const char *name; IN: Name of property to set
+ H5P_genprop_t *prop; IN: Property to set
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Sets a new value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property class.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__set_pclass_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_set_ud_t *udata = (H5P_prop_set_ud_t *)_udata; /* User data for callback */
+ H5P_genprop_t *pcopy = NULL; /* Copy of property to insert into skip list */
+ void *tmp_value = NULL; /* Temporary value for property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+ HDassert(prop->cmp);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Make a copy of the value and pass to 'set' callback */
+ if(NULL != prop->set) {
+ /* Make a copy of the current value, in case the callback fails */
+ if(NULL == (tmp_value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value")
+ HDmemcpy(tmp_value, udata->value, prop->size);
+
+ /* Call user's callback */
+ if((*(prop->set))(plist->plist_id, name, prop->size, tmp_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value")
+ } /* end if */
+ /* No 'set' callback, just copy value */
+ else
+ tmp_value = (void *)udata->value; /* Casting away const OK -QAK */
+
+ /* Make a copy of the class's property */
+ if(NULL == (pcopy = H5P_dup_prop(prop, H5P_PROP_WITHIN_LIST)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "Can't copy property")
+
+ HDmemcpy(pcopy->value, tmp_value, pcopy->size);
+
+ /* Insert the changed property into the property list */
+ if(H5P_add_prop(plist->props, pcopy) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert changed property into skip list")
+
+done:
+ /* Free the temporary value buffer */
+ if(tmp_value != NULL && tmp_value != udata->value)
+ H5MM_xfree(tmp_value);
+
+ /* Cleanup on failure */
+ if(ret_value < 0)
+ if(pcopy)
+ H5P_free_prop(pcopy);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__set_pclass_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_set
+ PURPOSE
+ Internal routine to set a property's value in a property list.
+ USAGE
+ herr_t H5P_set(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to find property in
+ const char *name; IN: Name of property to set
+ const void *value; IN: Pointer to the value for the property
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Sets a new value for a property in a property list. The property name
+ must exist or this routine will fail. If there is a 'set' callback routine
+ registered for this property, the 'value' will be passed to that routine and
+ any changes to the 'value' will be used when setting the property value.
+ The information pointed at by the 'value' pointer (possibly modified by the
+ 'set' callback) is copied into the property list value and may be changed
+ by the application making the H5Pset call without affecting the property
+ value.
+
+ If the 'set' callback routine returns an error, the property value will
+ not be modified. This routine may not be called for zero-sized properties
+ and will return an error in that case.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_set(H5P_genplist_t *plist, const char *name, const void *value)
+{
+ H5P_prop_set_ud_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(value);
+
+ /* Find the property and set the value */
+ udata.value = value;
+ if(H5P__do_prop(plist, name, H5P__set_plist_cb, H5P__set_pclass_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on plist to set value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_set() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_exist_plist
+ PURPOSE
+ Internal routine to query the existance of a property in a property list.
+ USAGE
+ htri_t H5P_exist_plist(plist, name)
+ const H5P_genplist_t *plist; IN: Property list to check
+ const char *name; IN: Name of property to check for
+ RETURNS
+ Success: Positive if the property exists in the property list, zero
+ if the property does not exist.
+ Failure: negative value
+ DESCRIPTION
+ This routine checks if a property exists within a property list.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5P_exist_plist(const H5P_genplist_t *plist, const char *name)
+{
+ htri_t ret_value = FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(plist);
+ HDassert(name);
+
+ /* Check for property in deleted property list */
+ if(H5SL_search(plist->del, name) != NULL)
+ ret_value = FALSE;
+ else {
+ /* Check for property in changed property list */
+ if(H5SL_search(plist->props, name) != NULL)
+ ret_value = TRUE;
+ else {
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+
+ tclass = plist->pclass;
+ while(tclass != NULL) {
+ if(H5SL_search(tclass->props, name) != NULL)
+ HGOTO_DONE(TRUE)
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* If we've reached here, we couldn't find the property */
+ ret_value = FALSE;
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_exist_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_exist_pclass
+ PURPOSE
+ Internal routine to query the existance of a property in a property class.
+ USAGE
+ herr_t H5P_exist_pclass(pclass, name)
+ H5P_genclass_t *pclass; IN: Property class to check
+ const char *name; IN: Name of property to check for
+ RETURNS
+ Success: Positive if the property exists in the property class, zero
+ if the property does not exist.
+ Failure: negative value
+ DESCRIPTION
+ This routine checks if a property exists within a property class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5P_exist_pclass(H5P_genclass_t *pclass, const char *name)
+{
+ htri_t ret_value = FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(pclass);
+ HDassert(name);
+
+ /* Check for property in property list */
+ if(H5SL_search(pclass->props, name) != NULL)
+ ret_value = TRUE;
+ else {
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+
+ tclass = pclass->parent;
+ while(tclass != NULL) {
+ if(H5SL_search(tclass->props, name) != NULL)
+ HGOTO_DONE(TRUE)
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+
+ /* If we've reached here, we couldn't find the property */
+ ret_value = FALSE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_exist_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_size_plist
+ PURPOSE
+ Internal routine to query the size of a property in a property list.
+ USAGE
+ herr_t H5P_get_size_plist(plist, name)
+ const H5P_genplist_t *plist; IN: Property list to check
+ const char *name; IN: Name of property to query
+ size_t *size; OUT: Size of property
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the size of a property's value in bytes. Zero-
+ sized properties are allowed and return a value of 0.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_get_size_plist(const H5P_genplist_t *plist, const char *name, size_t *size)
+{
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(plist);
+ HDassert(name);
+ HDassert(size);
+
+ /* Find property */
+ if(NULL == (prop = H5P__find_prop_plist(plist, name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist")
+
+ /* Get property size */
+ *size = prop->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_size_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_size_pclass
+ PURPOSE
+ Internal routine to query the size of a property in a property class.
+ USAGE
+ herr_t H5P_get_size_pclass(pclass, name)
+ H5P_genclass_t *pclass; IN: Property class to check
+ const char *name; IN: Name of property to query
+ size_t *size; OUT: Size of property
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the size of a property's value in bytes. Zero-
+ sized properties are allowed and return a value of 0.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_get_size_pclass(H5P_genclass_t *pclass, const char *name, size_t *size)
+{
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+ HDassert(name);
+ HDassert(size);
+
+ /* Find property */
+ if((prop=H5P_find_prop_pclass(pclass,name)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist")
+
+ /* Get property size */
+ *size=prop->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_size_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_nprops_plist
+ PURPOSE
+ Internal routine to query the number of properties in a property list
+ USAGE
+ herr_t H5P_get_nprops_plist(plist, nprops)
+ H5P_genplist_t *plist; IN: Property list to check
+ size_t *nprops; OUT: Number of properties in the property list
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the number of a properties in a property list.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_get_nprops_plist(const H5P_genplist_t *plist, size_t *nprops)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(plist);
+ HDassert(nprops);
+
+ /* Get property size */
+ *nprops = plist->nprops;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5P_get_nprops_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_nprops_pclass
+ PURPOSE
+ Internal routine to query the number of properties in a property class
+ USAGE
+ herr_t H5P_get_nprops_pclass(pclass, nprops)
+ H5P_genclass_t *pclass; IN: Property class to check
+ size_t *nprops; OUT: Number of properties in the property list
+ hbool_t recurse; IN: Include properties in parent class(es) also
+ RETURNS
+ Success: non-negative value (can't fail)
+ Failure: negative value
+ DESCRIPTION
+ This routine retrieves the number of a properties in a property class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_get_nprops_pclass(const H5P_genclass_t *pclass, size_t *nprops, hbool_t recurse)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pclass);
+ HDassert(nprops);
+
+ /* Get number of properties */
+ *nprops = pclass->nprops;
+
+ /* Check if the class is derived, and walk up the chain, if so */
+ if(recurse)
+ while(pclass->parent != NULL) {
+ pclass = pclass->parent;
+ *nprops += pclass->nprops;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_nprops_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_cmp_prop
+ PURPOSE
+ Internal routine to compare two generic properties
+ USAGE
+ int H5P_cmp_prop(prop1, prop2)
+ H5P_genprop_t *prop1; IN: 1st property to compare
+ H5P_genprop_t *prop1; IN: 2nd property to compare
+ RETURNS
+ Success: negative if prop1 "less" than prop2, positive if prop1 "greater"
+ than prop2, zero if prop1 is "equal" to prop2
+ Failure: can't fail
+ DESCRIPTION
+ This function compares two generic properties together to see if
+ they are the same property.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P_cmp_prop(const H5P_genprop_t *prop1, const H5P_genprop_t *prop2)
+{
+ int cmp_value; /* Value from comparison */
+ int ret_value = 0; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(prop1);
+ HDassert(prop2);
+
+ /* Check the name */
+ if((cmp_value = HDstrcmp(prop1->name, prop2->name)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the size of properties */
+ if(prop1->size < prop2->size) HGOTO_DONE(-1);
+ if(prop1->size > prop2->size) HGOTO_DONE(1);
+
+ /* Check if they both have the same 'create' callback */
+ if(prop1->create == NULL && prop2->create != NULL) HGOTO_DONE(-1);
+ if(prop1->create != NULL && prop2->create == NULL) HGOTO_DONE(1);
+ if(prop1->create != prop2->create) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'set' callback */
+ if(prop1->set == NULL && prop2->set != NULL) HGOTO_DONE(-1);
+ if(prop1->set != NULL && prop2->set == NULL) HGOTO_DONE(1);
+ if(prop1->set != prop2->set) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'get' callback */
+ if(prop1->get == NULL && prop2->get != NULL) HGOTO_DONE(-1);
+ if(prop1->get != NULL && prop2->get == NULL) HGOTO_DONE(1);
+ if(prop1->get != prop2->get) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'encode' callback */
+ if(prop1->encode == NULL && prop2->encode != NULL) HGOTO_DONE(-1);
+ if(prop1->encode != NULL && prop2->encode == NULL) HGOTO_DONE(1);
+ if(prop1->encode != prop2->encode) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'decode' callback */
+ if(prop1->decode == NULL && prop2->decode != NULL) HGOTO_DONE(-1);
+ if(prop1->decode != NULL && prop2->decode == NULL) HGOTO_DONE(1);
+ if(prop1->decode != prop2->decode) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'delete' callback */
+ if(prop1->del == NULL && prop2->del != NULL) HGOTO_DONE(-1);
+ if(prop1->del != NULL && prop2->del == NULL) HGOTO_DONE(1);
+ if(prop1->del != prop2->del) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'copy' callback */
+ if(prop1->copy == NULL && prop2->copy != NULL) HGOTO_DONE(-1);
+ if(prop1->copy != NULL && prop2->copy == NULL) HGOTO_DONE(1);
+ if(prop1->copy != prop2->copy) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'compare' callback */
+ if(prop1->cmp == NULL && prop2->cmp != NULL) HGOTO_DONE(-1);
+ if(prop1->cmp != NULL && prop2->cmp == NULL) HGOTO_DONE(1);
+ if(prop1->cmp != prop2->cmp) HGOTO_DONE(-1);
+
+ /* Check if they both have the same 'close' callback */
+ if(prop1->close == NULL && prop2->close != NULL) HGOTO_DONE(-1);
+ if(prop1->close != NULL && prop2->close == NULL) HGOTO_DONE(1);
+ if(prop1->close != prop2->close) HGOTO_DONE(-1);
+
+ /* Check if they both have values allocated (or not allocated) */
+ if(prop1->value == NULL && prop2->value != NULL) HGOTO_DONE(-1);
+ if(prop1->value != NULL && prop2->value == NULL) HGOTO_DONE(1);
+ if(prop1->value != NULL) {
+ /* Call comparison routine */
+ if((cmp_value = prop1->cmp(prop1->value, prop2->value, prop1->size)) != 0)
+ HGOTO_DONE(cmp_value);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_cmp_prop() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_cmp_class
+ PURPOSE
+ Internal routine to compare two generic property classes
+ USAGE
+ int H5P_cmp_class(pclass1, pclass2)
+ H5P_genclass_t *pclass1; IN: 1st property class to compare
+ H5P_genclass_t *pclass2; IN: 2nd property class to compare
+ RETURNS
+ Success: negative if class1 "less" than class2, positive if class1 "greater"
+ than class2, zero if class1 is "equal" to class2
+ Failure: can't fail
+ DESCRIPTION
+ This function compares two generic property classes together to see if
+ they are the same class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5P_cmp_class(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2)
+{
+ H5SL_node_t *tnode1, *tnode2; /* Temporary pointer to property nodes */
+ int cmp_value; /* Value from comparison */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(pclass1);
+ HDassert(pclass2);
+
+ /* Use the revision number to quickly check for identical classes */
+ if(pclass1->revision == pclass2->revision)
+ HGOTO_DONE(0);
+
+ /* Check the name */
+ if((cmp_value = HDstrcmp(pclass1->name, pclass2->name)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the number of properties */
+ if(pclass1->nprops < pclass2->nprops) HGOTO_DONE(-1);
+ if(pclass1->nprops > pclass2->nprops) HGOTO_DONE(1);
+
+ /* Check the number of property lists created from the class */
+ if(pclass1->plists < pclass2->plists) HGOTO_DONE(-1);
+ if(pclass1->plists > pclass2->plists) HGOTO_DONE(1);
+
+ /* Check the number of classes derived from the class */
+ if(pclass1->classes < pclass2->classes) HGOTO_DONE(-1);
+ if(pclass1->classes > pclass2->classes) HGOTO_DONE(1);
+
+ /* Check the number of ID references open on the class */
+ if(pclass1->ref_count < pclass2->ref_count) HGOTO_DONE(-1);
+ if(pclass1->ref_count > pclass2->ref_count) HGOTO_DONE(1);
+
+ /* Check the property list types */
+ if(pclass1->type < pclass2->type) HGOTO_DONE(-1);
+ if(pclass1->type > pclass2->type) HGOTO_DONE(1);
+
+ /* Check whether they are deleted or not */
+ if(pclass1->deleted < pclass2->deleted) HGOTO_DONE(-1);
+ if(pclass1->deleted > pclass2->deleted) HGOTO_DONE(1);
+
+ /* Check whether they have creation callback functions & data */
+ if(pclass1->create_func == NULL && pclass2->create_func != NULL) HGOTO_DONE(-1);
+ if(pclass1->create_func != NULL && pclass2->create_func == NULL) HGOTO_DONE(1);
+ if(pclass1->create_func != pclass2->create_func) HGOTO_DONE(-1);
+ if(pclass1->create_data < pclass2->create_data) HGOTO_DONE(-1);
+ if(pclass1->create_data > pclass2->create_data) HGOTO_DONE(1);
+
+ /* Check whether they have close callback functions & data */
+ if(pclass1->close_func == NULL && pclass2->close_func != NULL) HGOTO_DONE(-1);
+ if(pclass1->close_func != NULL && pclass2->close_func == NULL) HGOTO_DONE(1);
+ if(pclass1->close_func != pclass2->close_func) HGOTO_DONE(-1);
+ if(pclass1->close_data < pclass2->close_data) HGOTO_DONE(-1);
+ if(pclass1->close_data > pclass2->close_data) HGOTO_DONE(1);
+
+ /* Cycle through the properties and compare them also */
+ tnode1 = H5SL_first(pclass1->props);
+ tnode2 = H5SL_first(pclass2->props);
+ while(tnode1 || tnode2) {
+ H5P_genprop_t *prop1, *prop2; /* Property for node */
+
+ /* Check if they both have properties in this skip list node */
+ if(tnode1 == NULL && tnode2 != NULL) HGOTO_DONE(-1);
+ if(tnode1 != NULL && tnode2 == NULL) HGOTO_DONE(1);
+
+ /* Compare the two properties */
+ prop1 = (H5P_genprop_t *)H5SL_item(tnode1);
+ prop2 = (H5P_genprop_t *)H5SL_item(tnode2);
+ if((cmp_value = H5P_cmp_prop(prop1, prop2)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Advance the pointers */
+ tnode1 = H5SL_next(tnode1);
+ tnode2 = H5SL_next(tnode2);
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_cmp_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__cmp_plist_cb
+ PURPOSE
+ Internal callback routine when iterating over properties in property list
+ to compare them for equality
+ USAGE
+ int H5P__cmp_plist_cb(prop, udata)
+ H5P_genprop_t *prop; IN: Pointer to the property
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns whether to continue (H5_ITER_CONT) or stop (H5_ITER_STOP)
+ iterating over the property lists.
+ Failure: Negative value (H5_ITER_ERROR)
+ DESCRIPTION
+ This routine compares a property from one property list (the one being
+ iterated over, to a property from the second property list (which is
+ looked up). Iteration is stopped if the comparison is non-equal.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__cmp_plist_cb(H5P_genprop_t *prop, void *_udata)
+{
+ H5P_plist_cmp_ud_t *udata = (H5P_plist_cmp_ud_t *)_udata; /* Pointer to user data */
+ htri_t prop2_exist; /* Whether the property exists in the second property list */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(prop);
+ HDassert(udata);
+
+ /* Check if the property exists in the second property list */
+ if((prop2_exist = H5P_exist_plist(udata->plist2, prop->name)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, H5_ITER_ERROR, "can't lookup existance of property?")
+ if(prop2_exist) {
+ const H5P_genprop_t *prop2; /* Pointer to property in second plist */
+
+ /* Look up same property in second property list */
+ if(NULL == (prop2 = H5P__find_prop_plist(udata->plist2, prop->name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, H5_ITER_ERROR, "property doesn't exist")
+
+ /* Compare the two properties */
+ if((udata->cmp_value = H5P_cmp_prop(prop, prop2)) != 0)
+ HGOTO_DONE(H5_ITER_STOP);
+ } /* end if */
+ else {
+ /* Property exists in first list, but not second */
+ udata->cmp_value = 1;
+ HGOTO_DONE(H5_ITER_STOP);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__cmp_plist_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_cmp_plist
+ PURPOSE
+ Internal routine to compare two generic property lists
+ USAGE
+ herr_t H5P_cmp_plist(plist1, plist2, cmp_ret)
+ H5P_genplist_t *plist1; IN: 1st property list to compare
+ H5P_genplist_t *plist2; IN: 2nd property list to compare
+ int *cmp_ret; OUT: Comparison value for two property lists
+ Negative if list1 "less" than list2,
+ positive if list1 "greater" than list2,
+ zero if list1 is "equal" to list2
+ RETURNS
+ Success: non-negative value
+ Failure: negative value
+ DESCRIPTION
+ This function compares two generic property lists together to see if
+ they are equal.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_cmp_plist(const H5P_genplist_t *plist1, const H5P_genplist_t *plist2,
+ int *cmp_ret)
+{
+ H5P_plist_cmp_ud_t udata; /* User data for callback */
+ int idx = 0; /* Index of property to begin with */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(plist1);
+ HDassert(plist2);
+ HDassert(cmp_ret);
+
+ /* Check the number of properties */
+ if(plist1->nprops < plist2->nprops) {
+ *cmp_ret = -1;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+ if(plist1->nprops > plist2->nprops) {
+ *cmp_ret = 1;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /* Check whether they've been initialized */
+ if(plist1->class_init < plist2->class_init) {
+ *cmp_ret = -1;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+ if(plist1->class_init > plist2->class_init) {
+ *cmp_ret = 1;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /* Set up iterator callback info */
+ udata.cmp_value = 0;
+ udata.plist2 = plist2;
+
+ /* Iterate over properties in first property list */
+ if((ret_value = H5P_iterate_plist(plist1, TRUE, &idx, H5P__cmp_plist_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to iterate over list")
+ if(ret_value != 0) {
+ *cmp_ret = udata.cmp_value;
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+
+ /* Check the parent classes */
+ if((*cmp_ret = H5P_cmp_class(plist1->pclass, plist2->pclass)) != 0)
+ HGOTO_DONE(SUCCEED);
+
+ /* Property lists must be equal, set comparison value to 0 */
+ *cmp_ret = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_cmp_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_class_isa
+ PURPOSE
+ Internal routine to query whether a property class is the same as another
+ class.
+ USAGE
+ htri_t H5P_class_isa(pclass1, pclass2)
+ H5P_genclass_t *pclass1; IN: Property class to check
+ H5P_genclass_t *pclass2; IN: Property class to compare with
+ RETURNS
+ Success: TRUE (1) or FALSE (0)
+ Failure: negative value
+ DESCRIPTION
+ This routine queries whether a property class is the same as another class,
+ and walks up the hierarchy of derived classes, checking if the first class
+ is derived from the second class also.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5P_class_isa(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pclass1);
+ HDassert(pclass2);
+
+ /* Compare property classes */
+ if(H5P_cmp_class(pclass1, pclass2) == 0) {
+ HGOTO_DONE(TRUE);
+ } else {
+ /* Check if the class is derived, and walk up the chain, if so */
+ if(pclass1->parent != NULL)
+ ret_value = H5P_class_isa(pclass1->parent, pclass2);
+ else
+ HGOTO_DONE(FALSE);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_class_isa() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_isa_class
+ PURPOSE
+ Internal routine to query whether a property list is a certain class
+ USAGE
+ hid_t H5P_isa_class(plist_id, pclass_id)
+ hid_t plist_id; IN: Property list to query
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: TRUE (1) or FALSE (0)
+ Failure: negative
+ DESCRIPTION
+ This routine queries whether a property list is a member of the property
+ list class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This function is special in that it is an internal library function, but
+ accepts hid_t's as parameters. Since it is used in basically the same way
+ as the H5I functions, this should be OK. Don't make more library functions
+ which accept hid_t's without thorough discussion. -QAK
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5P_isa_class(hid_t plist_id, hid_t pclass_id)
+{
+ H5P_genplist_t *plist; /* Property list to query */
+ H5P_genclass_t *pclass; /* Property list class */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object_verify(plist_id, H5I_GENPROP_LST)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(pclass_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class")
+
+ /* Compare the property list's class against the other class */
+ if((ret_value = H5P_class_isa(plist->pclass, pclass)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to compare property list classes")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_isa_class() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_object_verify
+ PURPOSE
+ Internal routine to query whether a property list is a certain class and
+ retrieve the property list object associated with it.
+ USAGE
+ void *H5P_object_verify(plist_id, pclass_id)
+ hid_t plist_id; IN: Property list to query
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: valid pointer to a property list object
+ Failure: NULL
+ DESCRIPTION
+ This routine queries whether a property list is member of a certain class
+ and retrieves the property list object associated with it.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This function is special in that it is an internal library function, but
+ accepts hid_t's as parameters. Since it is used in basically the same way
+ as the H5I functions, this should be OK. Don't make more library functions
+ which accept hid_t's without thorough discussion. -QAK
+
+ This function is similar (in spirit) to H5I_object_verify()
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genplist_t *
+H5P_object_verify(hid_t plist_id, hid_t pclass_id)
+{
+ H5P_genplist_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Compare the property list's class against the other class */
+ if(H5P_isa_class(plist_id, pclass_id) != TRUE)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, NULL, "property list is not a member of the class")
+
+ /* Get the plist structure */
+ if(NULL == (ret_value = (H5P_genplist_t *)H5I_object(plist_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "can't find object for ID")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_object_verify() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__iterate_plist_cb
+ PURPOSE
+ Internal callback routine when iterating over properties in property list
+ USAGE
+ int H5P__iterate_plist_cb(item, key, udata)
+ void *item; IN: Pointer to the property
+ void *key; IN: Pointer to the property's name
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC
+ DESCRIPTION
+ This routine calls the actual callback routine for the property in the
+property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__iterate_plist_cb(void *_item, void *_key, void *_udata)
+{
+ H5P_genprop_t *item = (H5P_genprop_t *)_item; /* Pointer to the property */
+ char *key = (char *)_key; /* Pointer to the property's name */
+ H5P_iter_plist_ud_t *udata = (H5P_iter_plist_ud_t *)_udata; /* Pointer to user data */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(item);
+ HDassert(key);
+
+ /* Check if we've found the correctly indexed property */
+ if(*udata->curr_idx_ptr >= udata->prev_idx) {
+ /* Call the callback function */
+ ret_value = (*udata->cb_func)(item, udata->udata);
+ if(ret_value != 0)
+ HGOTO_DONE(ret_value);
+ } /* end if */
+
+ /* Increment the current index */
+ (*udata->curr_idx_ptr)++;
+
+ /* Add property name to 'seen' list */
+ if(H5SL_insert(udata->seen, key, key) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert property into 'seen' skip list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__iterate_plist_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__iterate_plist_pclass_cb
+ PURPOSE
+ Internal callback routine when iterating over properties in property class
+ USAGE
+ int H5P__iterate_plist_pclass_cb(item, key, udata)
+ void *item; IN: Pointer to the property
+ void *key; IN: Pointer to the property's name
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC
+ DESCRIPTION
+ This routine verifies that the property hasn't already been seen or was
+deleted, and then chains to the property list callback.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__iterate_plist_pclass_cb(void *_item, void *_key, void *_udata)
+{
+ H5P_genprop_t *item = (H5P_genprop_t *)_item; /* Pointer to the property */
+ char *key = (char *)_key; /* Pointer to the property's name */
+ H5P_iter_plist_ud_t *udata = (H5P_iter_plist_ud_t *)_udata; /* Pointer to user data */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(item);
+ HDassert(key);
+
+ /* Only call iterator callback for properties we haven't seen
+ * before and that haven't been deleted.
+ */
+ if(NULL == H5SL_search(udata->seen, key) &&
+ NULL == H5SL_search(udata->plist->del, key))
+ ret_value = H5P__iterate_plist_cb(item, key, udata);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__iterate_plist_pclass_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_iterate_plist
+ PURPOSE
+ Internal routine to iterate over the properties in a property list
+ USAGE
+ int H5P_iterate_plist(plist, iter_all_prop, idx, cb_func, iter_data)
+ const H5P_genplist_t *plist; IN: Property list to iterate over
+ hbool_t iter_all_prop; IN: Whether to iterate over all properties
+ (TRUE), or just non-default (i.e. changed)
+ properties (FALSE).
+ int *idx; IN/OUT: Index of the property to begin with
+ H5P_iterate_t cb_func; IN: Function pointer to function to be
+ called with each property iterated over.
+ void *iter_data; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC if it was
+ non-zero, or zero if all properties have been processed.
+ Failure: negative value
+ DESCRIPTION
+ This routine iterates over the properties in the property object specified
+with PLIST_ID. For each property in the object, the ITER_DATA and some
+additional information, specified below, are passed to the ITER_FUNC function.
+The iteration begins with the IDX property in the object and the next element
+to be processed by the operator is returned in IDX. If IDX is NULL, then the
+iterator starts at the first property; since no stopping point is returned in
+this case, the iterator cannot be restarted if one of the calls to its operator
+returns non-zero.
+
+The prototype for H5P_iterate_t is:
+ typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data);
+The operation receives the property list or class identifier for the object
+being iterated over, ID, the name of the current property within the object,
+NAME, and the pointer to the operator data passed in to H5Piterate, ITER_DATA.
+
+The return values from an operator are:
+ Zero causes the iterator to continue, returning zero when all properties
+ have been processed.
+ Positive causes the iterator to immediately return that positive value,
+ indicating short-circuit success. The iterator can be restarted at the
+ index of the next property.
+ Negative causes the iterator to immediately return that value, indicating
+ failure. The iterator can be restarted at the index of the next
+ property.
+
+H5Piterate assumes that the properties in the object identified by ID remains
+unchanged through the iteration. If the membership changes during the
+iteration, the function's behavior is undefined.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5P_iterate_plist(const H5P_genplist_t *plist, hbool_t iter_all_prop, int *idx,
+ H5P_iterate_int_t cb_func, void *udata)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_iter_plist_ud_t udata_int; /* User data for skip list iterator */
+ H5SL_t *seen = NULL; /* Skip list to hold names of properties already seen */
+ int curr_idx = 0; /* Current iteration index */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(idx);
+ HDassert(cb_func);
+
+ /* Create the skip list to hold names of properties already seen */
+ if(NULL == (seen = H5SL_create(H5SL_TYPE_STR, NULL)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "can't create skip list for seen properties")
+
+ /* Set up iterator callback info */
+ udata_int.plist = plist;
+ udata_int.cb_func = cb_func;
+ udata_int.udata = udata;
+ udata_int.seen = seen;
+ udata_int.curr_idx_ptr = &curr_idx;
+ udata_int.prev_idx = *idx;
+
+ /* Iterate over properties in property list proper */
+ /* (Will be only the non-default (i.e. changed) properties) */
+ ret_value = H5SL_iterate(plist->props, H5P__iterate_plist_cb, &udata_int);
+ if(ret_value != 0)
+ HGOTO_DONE(ret_value);
+
+ /* Check for iterating over all properties, or just non-default ones */
+ if(iter_all_prop) {
+ /* Walk up the class hiearchy */
+ tclass = plist->pclass;
+ while(tclass != NULL) {
+ /* Iterate over properties in property list class */
+ ret_value = H5SL_iterate(tclass->props, H5P__iterate_plist_pclass_cb, &udata_int);
+ if(ret_value != 0)
+ HGOTO_DONE(ret_value);
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+ } /* end if */
+
+done:
+ /* Set the index we stopped at */
+ *idx = curr_idx;
+
+ /* Release the skip list of 'seen' properties */
+ if(seen != NULL)
+ H5SL_close(seen);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_iterate_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__iterate_pclass_cb
+ PURPOSE
+ Internal callback routine when iterating over properties in property list
+ class
+ USAGE
+ int H5P__iterate_pclass_cb(item, key, udata)
+ void *item; IN: Pointer to the property
+ void *key; IN: Pointer to the property's name
+ void *udata; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC
+ DESCRIPTION
+ This routine calls the actual callback routine for the property in the
+property list class.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5P__iterate_pclass_cb(void *_item, void *_key, void *_udata)
+{
+ H5P_genprop_t *item = (H5P_genprop_t *)_item; /* Pointer to the property */
+ char *key = (char *)_key; /* Pointer to the property's name */
+ H5P_iter_pclass_ud_t *udata = (H5P_iter_pclass_ud_t *)_udata; /* Pointer to user data */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(item);
+ HDassert(key);
+
+ /* Check if we've found the correctly indexed property */
+ if(*udata->curr_idx_ptr >= udata->prev_idx) {
+ /* Call the callback function */
+ ret_value = (*udata->cb_func)(item, udata->udata);
+ if(ret_value != 0)
+ HGOTO_DONE(ret_value);
+ } /* end if */
+
+ /* Increment the current index */
+ (*udata->curr_idx_ptr)++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__iterate_pclass_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_iterate_pclass
+ PURPOSE
+ Internal routine to iterate over the properties in a property class
+ USAGE
+ herr_t H5P_iterate_pclass(pclass, idx, cb_func, iter_data)
+ const H5P_genpclass_t *pclass; IN: Property list class to iterate over
+ int *idx; IN/OUT: Index of the property to begin with
+ H5P_iterate_t cb_func; IN: Function pointer to function to be
+ called with each property iterated over.
+ void *iter_data; IN/OUT: Pointer to iteration data from user
+ RETURNS
+ Success: Returns the return value of the last call to ITER_FUNC if it was
+ non-zero, or zero if all properties have been processed.
+ Failure: negative value
+ DESCRIPTION
+ This routine iterates over the properties in the property object specified
+with PCLASS_ID. For each property in the object, the ITER_DATA and some
+additional information, specified below, are passed to the ITER_FUNC function.
+The iteration begins with the IDX property in the object and the next element
+to be processed by the operator is returned in IDX. If IDX is NULL, then the
+iterator starts at the first property; since no stopping point is returned in
+this case, the iterator cannot be restarted if one of the calls to its operator
+returns non-zero.
+
+The prototype for H5P_iterate_t is:
+ typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data);
+The operation receives the property list or class identifier for the object
+being iterated over, ID, the name of the current property within the object,
+NAME, and the pointer to the operator data passed in to H5Piterate, ITER_DATA.
+
+The return values from an operator are:
+ Zero causes the iterator to continue, returning zero when all properties
+ have been processed.
+ Positive causes the iterator to immediately return that positive value,
+ indicating short-circuit success. The iterator can be restarted at the
+ index of the next property.
+ Negative causes the iterator to immediately return that value, indicating
+ failure. The iterator can be restarted at the index of the next
+ property.
+
+H5Piterate assumes that the properties in the object identified by ID remains
+unchanged through the iteration. If the membership changes during the
+iteration, the function's behavior is undefined.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5P_iterate_pclass(const H5P_genclass_t *pclass, int *idx,
+ H5P_iterate_int_t cb_func, void *udata)
+{
+ H5P_iter_pclass_ud_t udata_int; /* User data for skip list iterator */
+ int curr_idx = 0; /* Current iteration index */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(pclass);
+ HDassert(idx);
+ HDassert(cb_func);
+
+ /* Set up iterator callback info */
+ udata_int.cb_func = cb_func;
+ udata_int.udata = udata;
+ udata_int.curr_idx_ptr = &curr_idx;
+ udata_int.prev_idx = *idx;
+
+ /* Iterate over properties in property list class proper */
+ ret_value = H5SL_iterate(pclass->props, H5P__iterate_pclass_cb, &udata_int);
+ if(ret_value != 0)
+ HGOTO_DONE(ret_value);
+
+done:
+ /* Set the index we stopped at */
+ *idx = curr_idx;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_iterate_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__peek_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to peek at a property's value in a property list.
+ USAGE
+ herr_t H5P__peek_plist_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to peek property in
+ const char *name; IN: Name of property to peek
+ H5P_genprop_t *prop; IN: Property to peek
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Peeks at a new value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property list and when it's found
+ for the property class.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__peek_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_get_ud_t *udata = (H5P_prop_get_ud_t *)_udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Make a (shallow) copy of the value */
+ HDmemcpy(udata->value, prop->value, prop->size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__peek_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_peek
+ PURPOSE
+ Internal routine to look at the value of a property in a property list.
+ USAGE
+ herr_t H5P_peek(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to check
+ const char *name; IN: Name of property to query
+ void *value; OUT: Pointer to the buffer for the property value
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Retrieves a "shallow" copy of the value for a property in a property
+ list. The property name must exist or this routine will fail. If there
+ is a 'get' callback routine registered for this property, it is _NOT_
+ called.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine may not be called for zero-sized properties and will
+ return an error in that case.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_peek(H5P_genplist_t *plist, const char *name, void *value)
+{
+ H5P_prop_get_ud_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(value);
+
+ /* Find the property and peek at the value */
+ udata.value = value;
+ if(H5P__do_prop(plist, name, H5P__peek_cb, H5P__peek_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on plist to peek at value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_peek() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__get_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to get a property's value in a property list.
+ USAGE
+ herr_t H5P__get_plist_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to get property in
+ const char *name; IN: Name of property to get
+ H5P_genprop_t *prop; IN: Property to get
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Gets a new value for a property in a property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Called when the property is found in the property list and when it's found
+ for the property class.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__get_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void *_udata)
+{
+ H5P_prop_get_ud_t *udata = (H5P_prop_get_ud_t *)_udata; /* User data for callback */
+ void *tmp_value = NULL; /* Temporary value for property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Check for property size >0 */
+ if(0 == prop->size)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size")
+
+ /* Call the 'get' callback, if there is one */
+ if(NULL != prop->get) {
+ /* Make a copy of the current value, in case the callback fails */
+ if(NULL == (tmp_value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value")
+ HDmemcpy(tmp_value, prop->value, prop->size);
+
+ /* Call user's callback */
+ if((*(prop->get))(plist->plist_id, name, prop->size, tmp_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value")
+
+ /* Copy new [possibly unchanged] value into return value */
+ HDmemcpy(udata->value, tmp_value, prop->size);
+ } /* end if */
+ /* No 'get' callback, just copy value */
+ else
+ HDmemcpy(udata->value, prop->value, prop->size);
+
+done:
+ /* Free the temporary value buffer */
+ if(tmp_value)
+ H5MM_xfree(tmp_value);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__get_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get
+ PURPOSE
+ Internal routine to query the value of a property in a property list.
+ USAGE
+ herr_t H5P_get(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to check
+ const char *name; IN: Name of property to query
+ void *value; OUT: Pointer to the buffer for the property value
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Retrieves a copy of the value for a property in a property list. The
+ property name must exist or this routine will fail. If there is a
+ 'get' callback routine registered for this property, the copy of the
+ value of the property will first be passed to that routine and any changes
+ to the copy of the value will be used when returning the property value
+ from this routine.
+ If the 'get' callback routine returns an error, 'value' will not be
+ modified and this routine will return an error. This routine may not be
+ called for zero-sized properties.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_get(H5P_genplist_t *plist, const char *name, void *value)
+{
+ H5P_prop_get_ud_t udata; /* User data for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(value);
+
+ /* Find the property and get the value */
+ udata.value = value;
+ if(H5P__do_prop(plist, name, H5P__get_cb, H5P__get_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on plist to get value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__del_plist_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to remove a property's value in a property list.
+ USAGE
+ herr_t H5P__del_plist_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to remove property from
+ const char *name; IN: Name of property to remove
+ H5P_genprop_t *prop; IN: Property to remove
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Remove a property in a property list. Called when the
+ property is found in the property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__del_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void H5_ATTR_UNUSED *_udata)
+{
+ char *del_name = NULL; /* Pointer to deleted name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Pass value to 'close' callback, if it exists */
+ if(NULL != prop->del) {
+ /* Call user's callback */
+ if((*(prop->del))(plist->plist_id, name, prop->size, prop->value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't release property value")
+ } /* end if */
+
+ /* Duplicate string for insertion into new deleted property skip list */
+ if(NULL == (del_name = H5MM_xstrdup(name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Insert property name into deleted list */
+ if(H5SL_insert(plist->del, del_name, del_name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into deleted skip list")
+
+ /* Remove the property from the skip list */
+ if(NULL == H5SL_remove(plist->props, prop->name))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "can't remove property from skip list")
+
+ /* Free the property, ignoring return value, nothing we can do */
+ H5P_free_prop(prop);
+
+ /* Decrement the number of properties in list */
+ plist->nprops--;
+
+done:
+ /* Error cleanup */
+ if(ret_value < 0)
+ if(del_name)
+ H5MM_xfree(del_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__del_plist_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P__del_pclass_cb
+ PURPOSE
+ Internal callback for H5P__do_prop, to remove a property's value in a property list.
+ USAGE
+ herr_t H5P__del_pclass_cb(plist, name, value)
+ H5P_genplist_t *plist; IN: Property list to remove property from
+ const char *name; IN: Name of property to remove
+ H5P_genprop_t *prop; IN: Property to remove
+ void *udata; IN: User data for operation
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Remove a property in a property list. Called when the
+ property is found in the property class.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5P__del_pclass_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop,
+ void H5_ATTR_UNUSED *_udata)
+{
+ char *del_name = NULL; /* Pointer to deleted name */
+ void *tmp_value = NULL; /* Temporary value for property */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+ HDassert(prop);
+
+ /* Pass value to 'del' callback, if it exists */
+ if(NULL != prop->del) {
+ /* Allocate space for a temporary copy of the property value */
+ if(NULL == (tmp_value = H5MM_malloc(prop->size)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary property value")
+ HDmemcpy(tmp_value, prop->value, prop->size);
+
+ /* Call user's callback */
+ if((*(prop->del))(plist->plist_id, name, prop->size, tmp_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't close property value")
+ } /* end if */
+
+ /* Duplicate string for insertion into new deleted property skip list */
+ if(NULL == (del_name = H5MM_xstrdup(name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Insert property name into deleted list */
+ if(H5SL_insert(plist->del, del_name, del_name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into deleted skip list")
+
+ /* Decrement the number of properties in list */
+ plist->nprops--;
+
+done:
+ /* Free the temporary value buffer */
+ if(tmp_value)
+ H5MM_xfree(tmp_value);
+
+ /* Error cleanup */
+ if(ret_value < 0)
+ if(del_name)
+ H5MM_xfree(del_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__del_pclass_cb() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_remove
+ PURPOSE
+ Internal routine to remove a property from a property list.
+ USAGE
+ herr_t H5P_remove(plist, name)
+ H5P_genplist_t *plist; IN: Property list to modify
+ const char *name; IN: Name of property to remove
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Removes a property from a property list. Both properties which were
+ in existance when the property list was created (i.e. properties registered
+ with H5Pregister2) and properties added to the list after it was created
+ (i.e. added with H5Pinsert2) may be removed from a property list.
+ Properties do not need to be removed a property list before the list itself
+ is closed, they will be released automatically when H5Pclose is called.
+ The 'close' callback for this property is called before the property is
+ release, if the callback exists.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_remove(H5P_genplist_t *plist, const char *name)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(plist);
+ HDassert(name);
+
+ /* Find the property and get the value */
+ if(H5P__do_prop(plist, name, H5P__del_plist_cb, H5P__del_pclass_cb, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTOPERATE, FAIL, "can't operate on plist to remove value")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_remove() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_copy_prop_plist
+ PURPOSE
+ Internal routine to copy a property from one list to another
+ USAGE
+ herr_t H5P_copy_prop_plist(dst_plist, src_plist, name)
+ hid_t dst_id; IN: ID of destination property list or class
+ hid_t src_id; IN: ID of source property list or class
+ const char *name; IN: Name of property to copy
+ RETURNS
+ Success: non-negative value.
+ Failure: negative value.
+ DESCRIPTION
+ Copies a property from one property list to another.
+
+ If a property is copied from one list to another, the property will be
+ first deleted from the destination list (generating a call to the 'close'
+ callback for the property, if one exists) and then the property is copied
+ from the source list to the destination list (generating a call to the
+ 'copy' callback for the property, if one exists).
+
+ If the property does not exist in the destination list, this call is
+ equivalent to calling H5Pinsert2 and the 'create' callback will be called
+ (if such a callback exists for the property).
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_copy_prop_plist(hid_t dst_id, hid_t src_id, const char *name)
+{
+ H5P_genplist_t *dst_plist; /* Pointer to destination property list */
+ H5P_genplist_t *src_plist; /* Pointer to source property list */
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ H5P_genprop_t *new_prop=NULL; /* Pointer to new property */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(name);
+
+ /* Get the objects to operate on */
+ if(NULL == (src_plist = (H5P_genplist_t *)H5I_object(src_id)) || NULL == (dst_plist = (H5P_genplist_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property object doesn't exist")
+
+ /* If the property exists in the destination alread */
+ if(NULL != H5P__find_prop_plist(dst_plist, name)) {
+ /* Delete the property from the destination list, calling the 'close' callback if necessary */
+ if(H5P_remove(dst_plist, name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property")
+
+ /* Get the pointer to the source property */
+ prop = H5P__find_prop_plist(src_plist, name);
+
+ /* Make a copy of the source property */
+ if((new_prop=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property")
+
+ /* Call property copy callback, if it exists */
+ if(new_prop->copy) {
+ if((new_prop->copy)(new_prop->name,new_prop->size,new_prop->value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property")
+ } /* end if */
+
+ /* Insert the initialized property into the property list */
+ if(H5P_add_prop(dst_plist->props,new_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into list")
+
+ /* Increment the number of properties in list */
+ dst_plist->nprops++;
+ } /* end if */
+ /* If not, get the information required to do an H5Pinsert2 with the property into the destination list */
+ else {
+ /* Get the pointer to the source property */
+ prop = H5P__find_prop_plist(src_plist, name);
+
+ /* Create property object from parameters */
+ if(NULL == (new_prop = H5P_create_prop(prop->name, prop->size, H5P_PROP_WITHIN_LIST, prop->value,
+ prop->create, prop->set, prop->get, prop->encode, prop->decode,
+ prop->del, prop->copy, prop->cmp, prop->close)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL,"Can't create property")
+
+ /* Call property creation callback, if it exists */
+ if(new_prop->create) {
+ if((new_prop->create)(new_prop->name, new_prop->size, new_prop->value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property")
+ } /* end if */
+
+ /* Insert property into property list class */
+ if(H5P_add_prop(dst_plist->props, new_prop) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class")
+
+ /* Increment property count for class */
+ dst_plist->nprops++;
+ } /* end else */
+
+done:
+ /* Cleanup, if necessary */
+ if(ret_value<0) {
+ if(new_prop!=NULL)
+ H5P_free_prop(new_prop);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_copy_prop_plist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_copy_prop_pclass
+ PURPOSE
+ Internal routine to copy a property from one class to another
+ USAGE
+ herr_t H5P_copy_prop_pclass(dst_pclass, src_pclass, name)
+ H5P_genclass_t *dst_pclass; IN: Pointer to destination class
+ H5P_genclass_t *src_pclass; IN: Pointer to source class
+ const char *name; IN: Name of property to copy
+ RETURNS
+ Success: non-negative value.
+ Failure: negative value.
+ DESCRIPTION
+ Copies a property from one property class to another.
+
+ If a property is copied from one class to another, all the property
+ information will be first deleted from the destination class and then the
+ property information will be copied from the source class into the
+ destination class.
+
+ If the property does not exist in the destination class or list, this call
+ is equivalent to calling H5Pregister2.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_copy_prop_pclass(hid_t dst_id, hid_t src_id, const char *name)
+{
+ H5P_genclass_t *src_pclass; /* Source property class, containing property to copy */
+ H5P_genclass_t *dst_pclass; /* Destination property class */
+ H5P_genclass_t *orig_dst_pclass; /* Original destination property class */
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(name);
+
+ /* Get propery list classes */
+ if(NULL == (src_pclass = (H5P_genclass_t *)H5I_object(src_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "source property class object doesn't exist")
+ if(NULL == (dst_pclass = (H5P_genclass_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "destination property class object doesn't exist")
+
+ /* Get the property from the source */
+ if(NULL == (prop = H5P_find_prop_pclass(src_pclass, name)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "unable to locate property")
+
+ /* If the property exists in the destination already */
+ if(H5P_exist_pclass(dst_pclass, name)) {
+ /* Delete the old property from the destination class */
+ if(H5P_unregister(dst_pclass, name) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property")
+ } /* end if */
+
+ /* Register the property into the destination */
+ orig_dst_pclass = dst_pclass;
+ if(H5P_register(&dst_pclass, name, prop->size, prop->value, prop->create, prop->set, prop->get,
+ prop->encode, prop->decode, prop->del, prop->copy, prop->cmp, prop->close) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property")
+
+ /* Check if the property class changed and needs to be substituted in the ID */
+ if(dst_pclass != orig_dst_pclass) {
+ H5P_genclass_t *old_dst_pclass; /* Old destination property class */
+
+ /* Substitute the new destination property class in the ID */
+ if(NULL == (old_dst_pclass = (H5P_genclass_t *)H5I_subst(dst_id, dst_pclass)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to substitute property class in ID")
+ HDassert(old_dst_pclass == orig_dst_pclass);
+
+ /* Close the previous class */
+ if(H5P_close_class(old_dst_pclass) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, FAIL, "unable to close original property class after substitution")
+ } /* end if */
+
+done:
+ /* Cleanup, if necessary */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_copy_prop_pclass() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_unregister
+ PURPOSE
+ Internal routine to remove a property from a property list class.
+ USAGE
+ herr_t H5P_unregister(pclass, name)
+ H5P_genclass_t *pclass; IN: Property list class to modify
+ const char *name; IN: Name of property to remove
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Removes a property from a property list class. Future property lists
+ created of that class will not contain this property. Existing property
+ lists containing this property are not affected.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_unregister(H5P_genclass_t *pclass, const char *name)
+{
+ H5P_genprop_t *prop; /* Temporary property pointer */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+ HDassert(name);
+
+ /* Get the property node from the skip list */
+ if((prop = (H5P_genprop_t *)H5SL_search(pclass->props,name)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list")
+
+ /* Remove the property from the skip list */
+ if(H5SL_remove(pclass->props,prop->name) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTDELETE,FAIL,"can't remove property from skip list")
+
+ /* Free the property, ignoring return value, nothing we can do */
+ H5P_free_prop(prop);
+
+ /* Decrement the number of registered properties in class */
+ pclass->nprops--;
+
+ /* Update the revision for the class */
+ pclass->revision = H5P_GET_NEXT_REV;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_unregister() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_close
+ PURPOSE
+ Internal routine to close a property list.
+ USAGE
+ herr_t H5P_close(plist)
+ H5P_genplist_t *plist; IN: Property list to close
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Closes a property list. If a 'close' callback exists for the property
+ list class, it is called before the property list is destroyed. If 'close'
+ callbacks exist for any individual properties in the property list, they are
+ called after the class 'close' callback.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The property list class 'close' callback routine is not called from
+ here, it must have been check for and called properly prior to this routine
+ being called
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_close(void *_plist)
+{
+ H5P_genclass_t *tclass; /* Temporary class pointer */
+ H5P_genplist_t *plist=(H5P_genplist_t *)_plist;
+ H5SL_t *seen=NULL; /* Skip list to hold names of properties already seen */
+ size_t nseen; /* Number of items 'seen' */
+ hbool_t has_parent_class; /* Flag to indicate that this property list's class has a parent */
+ size_t ndel; /* Number of items deleted */
+ H5SL_node_t *curr_node; /* Current node in skip list */
+ H5P_genprop_t *tmp; /* Temporary pointer to properties */
+ unsigned make_cb=0; /* Operator data for property free callback */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(plist);
+
+ /* Make call to property list class close callback, if needed
+ * (up through chain of parent classes also)
+ */
+ if(plist->class_init) {
+ tclass = plist->pclass;
+ while(NULL != tclass) {
+ if(NULL != tclass->close_func) {
+ /* Call user's "close" callback function, ignoring return value */
+ (tclass->close_func)(plist->plist_id, tclass->close_data);
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass = tclass->parent;
+ } /* end while */
+ } /* end if */
+
+ /* Create the skip list to hold names of properties already seen
+ * (This prevents a property in the class hierarchy from having it's
+ * 'close' callback called, if a property in the class hierarchy has
+ * already been seen)
+ */
+ if((seen = H5SL_create(H5SL_TYPE_STR, NULL)) == NULL)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties")
+ nseen = 0;
+
+ /* Walk through the changed properties in the list */
+ if(H5SL_count(plist->props)>0) {
+ curr_node=H5SL_first(plist->props);
+ while(curr_node!=NULL) {
+ /* Get pointer to property from node */
+ tmp = (H5P_genprop_t *)H5SL_item(curr_node);
+
+ /* Call property close callback, if it exists */
+ if(tmp->close) {
+ /* Call the 'close' callback */
+ (tmp->close)(tmp->name,tmp->size,tmp->value);
+ } /* end if */
+
+ /* Add property name to "seen" list */
+ if(H5SL_insert(seen,tmp->name,tmp->name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list")
+ nseen++;
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Determine number of deleted items from property list */
+ ndel=H5SL_count(plist->del);
+
+ /*
+ * Check if we should remove class properties (up through list of parent classes also),
+ * initialize each with default value & make property 'remove' callback.
+ */
+ tclass=plist->pclass;
+ has_parent_class = (hbool_t)(tclass != NULL && tclass->parent != NULL && tclass->parent->nprops > 0);
+ while(tclass!=NULL) {
+ if(tclass->nprops>0) {
+ /* Walk through the properties in the class */
+ curr_node=H5SL_first(tclass->props);
+ while(curr_node!=NULL) {
+ /* Get pointer to property from node */
+ tmp = (H5P_genprop_t *)H5SL_item(curr_node);
+
+ /* Only "delete" properties we haven't seen before
+ * and that haven't already been deleted
+ */
+ if((nseen==0 || H5SL_search(seen,tmp->name) == NULL) &&
+ (ndel==0 || H5SL_search(plist->del,tmp->name) == NULL)) {
+
+ /* Call property close callback, if it exists */
+ if(tmp->close) {
+ void *tmp_value; /* Temporary value buffer */
+
+ /* Allocate space for a temporary copy of the property value */
+ if(NULL==(tmp_value=H5MM_malloc(tmp->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for temporary property value")
+ HDmemcpy(tmp_value,tmp->value,tmp->size);
+
+ /* Call the 'close' callback */
+ (tmp->close)(tmp->name,tmp->size,tmp_value);
+
+ /* Release the temporary value buffer */
+ H5MM_xfree(tmp_value);
+ } /* end if */
+
+ /* Add property name to "seen" list, if we have other classes to work on */
+ if(has_parent_class) {
+ if(H5SL_insert(seen,tmp->name,tmp->name) < 0)
+ HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list")
+ nseen++;
+ } /* end if */
+ } /* end if */
+
+ /* Get the next property node in the skip list */
+ curr_node=H5SL_next(curr_node);
+ } /* end while */
+ } /* end if */
+
+ /* Go up to parent class */
+ tclass=tclass->parent;
+ } /* end while */
+
+ /* Decrement class's dependant property list value! */
+ if(H5P_access_class(plist->pclass,H5P_MOD_DEC_LST) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "Can't decrement class ref count")
+
+ /* Free the list of 'seen' properties */
+ H5SL_close(seen);
+ seen=NULL;
+
+ /* Free the list of deleted property names */
+ H5SL_destroy(plist->del,H5P_free_del_name_cb,NULL);
+
+ /* Free the properties */
+ H5SL_destroy(plist->props,H5P_free_prop_cb,&make_cb);
+
+ /* Destroy property list object */
+ plist = H5FL_FREE(H5P_genplist_t, plist);
+
+done:
+ /* Release the skip list of 'seen' properties */
+ if(seen != NULL)
+ H5SL_close(seen);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_close() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_class_name
+ PURPOSE
+ Internal routine to query the name of a generic property list class
+ USAGE
+ char *H5P_get_class_name(pclass)
+ H5P_genclass_t *pclass; IN: Property list class to check
+ RETURNS
+ Success: Pointer to a malloc'ed string containing the class name
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves the name of a generic property list class.
+ The pointer to the name must be free'd by the user for successful calls.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+char *
+H5P_get_class_name(H5P_genclass_t *pclass)
+{
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(pclass);
+
+ /* Get class name */
+ ret_value=H5MM_xstrdup(pclass->name);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_class_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_class_path
+ PURPOSE
+ Internal routine to query the full path of a generic property list class
+ USAGE
+ char *H5P_get_class_name(pclass)
+ H5P_genclass_t *pclass; IN: Property list class to check
+ RETURNS
+ Success: Pointer to a malloc'ed string containing the full path of class
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves the full path name of a generic property list
+ class, starting with the root of the class hierarchy.
+ The pointer to the name must be free'd by the user for successful calls.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+char *
+H5P_get_class_path(H5P_genclass_t *pclass)
+{
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+
+ /* Recursively build the full path */
+ if(pclass->parent != NULL) {
+ char *par_path; /* Parent class's full path */
+
+ /* Get the parent class's path */
+ par_path = H5P_get_class_path(pclass->parent);
+ if(par_path != NULL) {
+ size_t ret_str_len;
+
+ /* Allocate enough space for the parent class's path, plus the '/'
+ * separator, this class's name and the string terminator
+ */
+ ret_str_len = HDstrlen(par_path) + 1 + HDstrlen(pclass->name) + 1;
+ if(NULL == (ret_value = (char *)H5MM_malloc(ret_str_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for class name")
+
+ /* Build the full path for this class */
+ HDsnprintf(ret_value, ret_str_len, "%s/%s", par_path, pclass->name);
+
+ /* Free the parent class's path */
+ H5MM_xfree(par_path);
+ } /* end if */
+ else
+ ret_value = H5MM_xstrdup(pclass->name);
+ } /* end if */
+ else
+ ret_value = H5MM_xstrdup(pclass->name);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_class_path() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_open_class_path
+ PURPOSE
+ Internal routine to open [a copy of] a class with its full path name
+ USAGE
+ H5P_genclass_t *H5P_open_class_path(path)
+ const char *path; IN: Full path name of class to open [copy of]
+ RETURNS
+ Success: Pointer to a generic property class object
+ Failure: NULL
+ DESCRIPTION
+ This routine opens [a copy] of the class indicated by the full path.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genclass_t *
+H5P_open_class_path(const char *path)
+{
+ char *tmp_path = NULL; /* Temporary copy of the path */
+ char *curr_name; /* Pointer to current component of path name */
+ char *delimit; /* Pointer to path delimiter during traversal */
+ H5P_genclass_t *curr_class; /* Pointer to class during path traversal */
+ H5P_check_class_t check_info; /* Structure to hold the information for checking duplicate names */
+ H5P_genclass_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(path);
+
+ /* Duplicate the path to use */
+ tmp_path = H5MM_xstrdup(path);
+ HDassert(tmp_path);
+
+ /* Find the generic property class with this full path */
+ curr_name = tmp_path;
+ curr_class = NULL;
+ while(NULL != (delimit = HDstrchr(curr_name, '/'))) {
+ /* Change the delimiter to terminate the string */
+ *delimit = '\0';
+
+ /* Set up the search structure */
+ check_info.parent = curr_class;
+ check_info.name = curr_name;
+ check_info.new_class = NULL;
+
+ /* Find the class with this name & parent by iterating over the open classes */
+ if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes")
+ else if(NULL == check_info.new_class)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class")
+
+ /* Advance the pointer in the path to the start of the next component */
+ curr_class = check_info.new_class;
+ curr_name = delimit + 1;
+ } /* end while */
+
+ /* Should be pointing to the last component in the path name now... */
+
+ /* Set up the search structure */
+ check_info.parent = curr_class;
+ check_info.name = curr_name;
+ check_info.new_class = NULL;
+
+ /* Find the class with this name & parent by iterating over the open classes */
+ if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes")
+ else if(NULL == check_info.new_class)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class")
+
+ /* Copy it */
+ if(NULL == (ret_value = H5P_copy_pclass(check_info.new_class)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL, "can't copy property class")
+
+done:
+ /* Free the duplicated path */
+ H5MM_xfree(tmp_path);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_open_class_path() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_class_parent
+ PURPOSE
+ Internal routine to query the parent class of a generic property class
+ USAGE
+ H5P_genclass_t *H5P_get_class_parent(pclass)
+ H5P_genclass_t *pclass; IN: Property class to check
+ RETURNS
+ Success: Pointer to the parent class of a property class
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves a pointer to the parent class for a property class.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5P_genclass_t *
+H5P_get_class_parent(const H5P_genclass_t *pclass)
+{
+ H5P_genclass_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(pclass);
+
+ /* Get property size */
+ ret_value = pclass->parent;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_class_parent() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_close_class
+ PURPOSE
+ Internal routine to close a property list class.
+ USAGE
+ herr_t H5P_close_class(class)
+ H5P_genclass_t *class; IN: Property list class to close
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Releases memory and de-attach a class from the property list class hierarchy.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5P_close_class(void *_pclass)
+{
+ H5P_genclass_t *pclass = (H5P_genclass_t *)_pclass;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pclass);
+
+ /* Decrement the reference count & check if the object should go away */
+ if(H5P_access_class(pclass, H5P_MOD_DEC_REF) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "can't decrement ID ref count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_close_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__new_plist_of_type
+ *
+ * Purpose: Create a new property list, of a given type
+ *
+ * Return: Success: ID of new property list
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, August 2, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5P__new_plist_of_type(H5P_plist_type_t type)
+{
+ H5P_genclass_t *pclass; /* Class of property list to create */
+ hid_t class_id; /* ID of class to create */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDcompile_assert(H5P_TYPE_ATTRIBUTE_ACCESS == (H5P_TYPE_MAX_TYPE - 1));
+ HDassert(type >= H5P_TYPE_USER && type <= H5P_TYPE_LINK_ACCESS);
+
+ /* Check arguments */
+ if(type == H5P_TYPE_USER)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't create user property list");
+ if(type == H5P_TYPE_ROOT)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "shouldn't be creating root class property list");
+
+ /* Instantiate a property list of the proper type */
+ switch(type) {
+ case H5P_TYPE_OBJECT_CREATE:
+ class_id = H5P_CLS_OBJECT_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_FILE_CREATE:
+ class_id = H5P_CLS_FILE_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_FILE_ACCESS:
+ class_id = H5P_CLS_FILE_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_DATASET_CREATE:
+ class_id = H5P_CLS_DATASET_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_DATASET_ACCESS:
+ class_id = H5P_CLS_DATASET_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_DATASET_XFER:
+ class_id = H5P_CLS_DATASET_XFER_ID_g;
+ break;
+
+ case H5P_TYPE_FILE_MOUNT:
+ class_id = H5P_CLS_FILE_MOUNT_ID_g;
+ break;
+
+ case H5P_TYPE_GROUP_CREATE:
+ class_id = H5P_CLS_GROUP_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_GROUP_ACCESS:
+ class_id = H5P_CLS_GROUP_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_DATATYPE_CREATE:
+ class_id = H5P_CLS_DATATYPE_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_DATATYPE_ACCESS:
+ class_id = H5P_CLS_DATATYPE_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_STRING_CREATE:
+ class_id = H5P_CLS_STRING_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_ATTRIBUTE_CREATE:
+ class_id = H5P_CLS_ATTRIBUTE_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_ATTRIBUTE_ACCESS:
+ class_id = H5P_CLS_ATTRIBUTE_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_OBJECT_COPY:
+ class_id = H5P_CLS_OBJECT_COPY_ID_g;
+ break;
+
+ case H5P_TYPE_LINK_CREATE:
+ class_id = H5P_CLS_LINK_CREATE_ID_g;
+ break;
+
+ case H5P_TYPE_LINK_ACCESS:
+ class_id = H5P_CLS_LINK_ACCESS_ID_g;
+ break;
+
+ case H5P_TYPE_USER: /* shut compiler warnings up */
+ case H5P_TYPE_ROOT:
+ case H5P_TYPE_MAX_TYPE:
+ default:
+ HGOTO_ERROR(H5E_PLIST, H5E_BADRANGE, FAIL, "invalid property list type: %u\n", (unsigned)type);
+ } /* end switch */
+
+ /* Get the class object */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object(class_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property class")
+
+ /* Create the new property list */
+ if((ret_value = H5P_create_id(pclass, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create property list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__new_plist_of_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_get_plist_id
+ *
+ * Purpose: Quick and dirty routine to retrieve property list ID from
+ * property list structure.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5P_genplist_t data structure)
+ *
+ * Return: Success: Non-negative ID of property list.
+ * Failure: negative.
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * April 22, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5P_get_plist_id(const H5P_genplist_t *plist)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(plist);
+
+ FUNC_LEAVE_NOAPI(plist->plist_id)
+} /* end H5P_get_plist_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_get_class
+ *
+ * Purpose: Quick and dirty routine to retrieve property list class from
+ * property list structure.
+ * (Mainly added to stop non-file routines from poking about in the
+ * H5P_genplist_t data structure)
+ *
+ * Return: Success: Non-NULL class of property list.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * April 22, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+H5P_genclass_t *
+H5P_get_class(const H5P_genplist_t *plist)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(plist);
+
+ FUNC_LEAVE_NOAPI(plist->pclass)
+} /* end H5P_get_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_verify_apl_and_dxpl
+ *
+ * Purpose: Validate access property list and/or switch from generic
+ * property list to default of correct type.
+ *
+ * Also, if using internal DXPL and collective flag is set,
+ * switch to internal collective DXPL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mohamad Chaarawi
+ * Sunday, June 21, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_verify_apl_and_dxpl(hid_t *acspl_id, const H5P_libclass_t *libclass, hid_t *dxpl_id,
+ hid_t
+#ifndef H5_HAVE_PARALLEL
+ H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ loc_id, hbool_t
+#ifndef H5_HAVE_PARALLEL
+ H5_ATTR_UNUSED
+#endif /* H5_HAVE_PARALLEL */
+ is_collective)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(acspl_id);
+ HDassert(libclass);
+ HDassert(dxpl_id);
+
+#ifdef H5_HAVE_PARALLEL
+ /* If parallel is enabled and the file driver used in the MPI-IO
+ VFD, issue an MPI barrier for easier debugging if the API function
+ calling this is supposed to be called collectively. Note that this
+ happens only when the environment variable H5_COLL_BARRIER is set
+ to non 0. */
+ if(is_collective && H5_coll_api_sanity_check_g) {
+ MPI_Comm mpi_comm; /* file communicator */
+
+ /* retrieve the MPI communicator from the loc_id or the fapl_id */
+ if(H5F_mpi_retrieve_comm(loc_id, *acspl_id, &mpi_comm) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator")
+
+ /* issue the barrier */
+ if(mpi_comm != MPI_COMM_NULL)
+ MPI_Barrier(mpi_comm);
+ }
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Set access plist to the default property list of the appropriate class if it's the generic default */
+ if(H5P_DEFAULT == *acspl_id)
+ *acspl_id = *libclass->def_plist_id;
+ else {
+#ifdef H5_HAVE_PARALLEL
+ H5P_coll_md_read_flag_t md_coll_read; /* Collective metadata read flag */
+ H5P_genplist_t *plist; /* Property list pointer */
+#endif /* H5_HAVE_PARALLEL */
+
+ /* Sanity check the access property list class */
+ if(TRUE != H5P_isa_class(*acspl_id, *libclass->class_id))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not the required access property list")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Get the plist structure for the access property list */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(*acspl_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the collective metadata read flag */
+ if(H5P_peek(plist, H5_COLL_MD_READ_FLAG_NAME, &md_coll_read) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get core collective metadata read flag")
+
+ /* If collective metadata read requested and using internal DXPL, switch to internal collective DXPL */
+ if(H5P_USER_TRUE == md_coll_read)
+ *dxpl_id = H5AC_coll_read_dxpl_id;
+#endif /* H5_HAVE_PARALLEL */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_verify_apl_and_dxpl() */
+
diff --git a/src/H5Plapl.c b/src/H5Plapl.c
new file mode 100644
index 0000000..18b81ac
--- /dev/null
+++ b/src/H5Plapl.c
@@ -0,0 +1,1308 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Plapl.c
+ * July 14 2006
+ * James Laird <jlaird@ncsa.uiuc.edu>
+ *
+ * Purpose: Link access property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ======== Link access properties ======== */
+/* Definitions for number of soft links to traverse */
+#define H5L_ACS_NLINKS_SIZE sizeof(size_t)
+#define H5L_ACS_NLINKS_DEF H5L_NUM_LINKS /*max symlinks to follow per lookup */
+#define H5L_ACS_NLINKS_ENC H5P__encode_size_t
+#define H5L_ACS_NLINKS_DEC H5P__decode_size_t
+
+
+/* Definitions for external link prefix */
+#define H5L_ACS_ELINK_PREFIX_SIZE sizeof(char *)
+#define H5L_ACS_ELINK_PREFIX_DEF NULL /*default is no prefix */
+#define H5L_ACS_ELINK_PREFIX_SET H5P__lacc_elink_pref_set
+#define H5L_ACS_ELINK_PREFIX_GET H5P__lacc_elink_pref_get
+#define H5L_ACS_ELINK_PREFIX_ENC H5P__lacc_elink_pref_enc
+#define H5L_ACS_ELINK_PREFIX_DEC H5P__lacc_elink_pref_dec
+#define H5L_ACS_ELINK_PREFIX_DEL H5P__lacc_elink_pref_del
+#define H5L_ACS_ELINK_PREFIX_COPY H5P__lacc_elink_pref_copy
+#define H5L_ACS_ELINK_PREFIX_CMP H5P__lacc_elink_pref_cmp
+#define H5L_ACS_ELINK_PREFIX_CLOSE H5P__lacc_elink_pref_close
+
+/* Definitions for setting fapl of external link access */
+#define H5L_ACS_ELINK_FAPL_SIZE sizeof(hid_t)
+#define H5L_ACS_ELINK_FAPL_DEF H5P_DEFAULT
+#define H5L_ACS_ELINK_FAPL_SET H5P__lacc_elink_fapl_set
+#define H5L_ACS_ELINK_FAPL_GET H5P__lacc_elink_fapl_get
+#define H5L_ACS_ELINK_FAPL_ENC H5P__lacc_elink_fapl_enc
+#define H5L_ACS_ELINK_FAPL_DEC H5P__lacc_elink_fapl_dec
+#define H5L_ACS_ELINK_FAPL_DEL H5P__lacc_elink_fapl_del
+#define H5L_ACS_ELINK_FAPL_COPY H5P__lacc_elink_fapl_copy
+#define H5L_ACS_ELINK_FAPL_CMP H5P__lacc_elink_fapl_cmp
+#define H5L_ACS_ELINK_FAPL_CLOSE H5P__lacc_elink_fapl_close
+
+/* Definitions for file access flags for external link traversal */
+#define H5L_ACS_ELINK_FLAGS_SIZE sizeof(unsigned)
+#define H5L_ACS_ELINK_FLAGS_DEF H5F_ACC_DEFAULT
+#define H5L_ACS_ELINK_FLAGS_ENC H5P__encode_unsigned
+#define H5L_ACS_ELINK_FLAGS_DEC H5P__decode_unsigned
+
+/* Definitions for callback function for external link traversal */
+#define H5L_ACS_ELINK_CB_SIZE sizeof(H5L_elink_cb_t)
+#define H5L_ACS_ELINK_CB_DEF {NULL,NULL}
+
+#ifdef H5_HAVE_PARALLEL
+/* Definition for reading metadata collectively */
+#define H5L_ACS_COLL_MD_READ_SIZE sizeof(H5P_coll_md_read_flag_t)
+#define H5L_ACS_COLL_MD_READ_DEF H5P_USER_FALSE
+#define H5L_ACS_COLL_MD_READ_ENC H5P__encode_coll_md_read_flag_t
+#define H5L_ACS_COLL_MD_READ_DEC H5P__decode_coll_md_read_flag_t
+#endif /* H5_HAVE_PARALLEL */
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__lacc_reg_prop(H5P_genclass_t *pclass);
+
+/* Property list callbacks */
+static herr_t H5P__lacc_elink_pref_set(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_pref_get(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_pref_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__lacc_elink_pref_dec(const void **_pp, void *value);
+static herr_t H5P__lacc_elink_pref_del(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_pref_copy(const char* name, size_t size, void* value);
+static int H5P__lacc_elink_pref_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__lacc_elink_pref_close(const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_fapl_set(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_fapl_get(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_fapl_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__lacc_elink_fapl_dec(const void **_pp, void *value);
+static herr_t H5P__lacc_elink_fapl_del(hid_t prop_id, const char* name, size_t size, void* value);
+static herr_t H5P__lacc_elink_fapl_copy(const char* name, size_t size, void* value);
+static int H5P__lacc_elink_fapl_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__lacc_elink_fapl_close(const char* name, size_t size, void* value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Dataset creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_LACC[1] = {{
+ "link access", /* Class name for debugging */
+ H5P_TYPE_LINK_ACCESS, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_LINK_ACCESS_g, /* Pointer to class */
+ &H5P_CLS_LINK_ACCESS_ID_g, /* Pointer to class ID */
+ &H5P_LST_LINK_ACCESS_ID_g, /* Pointer to default property list ID */
+ H5P__lacc_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const size_t H5L_def_nlinks_g = H5L_ACS_NLINKS_DEF; /* Default number of soft links to traverse */
+static const char *H5L_def_elink_prefix_g = H5L_ACS_ELINK_PREFIX_DEF; /* Default external link prefix string */
+static const hid_t H5L_def_fapl_id_g = H5L_ACS_ELINK_FAPL_DEF; /* Default fapl for external link access */
+static const unsigned H5L_def_elink_flags_g = H5L_ACS_ELINK_FLAGS_DEF; /* Default file access flags for external link traversal */
+static const H5L_elink_cb_t H5L_def_elink_cb_g = H5L_ACS_ELINK_CB_DEF; /* Default external link traversal callback */
+#ifdef H5_HAVE_PARALLEL
+static const H5P_coll_md_read_flag_t H5L_def_coll_md_read_g = H5L_ACS_COLL_MD_READ_DEF; /* Default setting for the collective metedata read flag */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_reg_prop
+ *
+ * Purpose: Register the dataset creation property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register property for number of links traversed */
+ if(H5P_register_real(pclass, H5L_ACS_NLINKS_NAME, H5L_ACS_NLINKS_SIZE, &H5L_def_nlinks_g,
+ NULL, NULL, NULL, H5L_ACS_NLINKS_ENC, H5L_ACS_NLINKS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for external link prefix */
+ if(H5P_register_real(pclass, H5L_ACS_ELINK_PREFIX_NAME, H5L_ACS_ELINK_PREFIX_SIZE, &H5L_def_elink_prefix_g,
+ NULL, H5L_ACS_ELINK_PREFIX_SET, H5L_ACS_ELINK_PREFIX_GET, H5L_ACS_ELINK_PREFIX_ENC, H5L_ACS_ELINK_PREFIX_DEC,
+ H5L_ACS_ELINK_PREFIX_DEL, H5L_ACS_ELINK_PREFIX_COPY, H5L_ACS_ELINK_PREFIX_CMP, H5L_ACS_ELINK_PREFIX_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register fapl for link access */
+ if(H5P_register_real(pclass, H5L_ACS_ELINK_FAPL_NAME, H5L_ACS_ELINK_FAPL_SIZE, &H5L_def_fapl_id_g,
+ NULL, H5L_ACS_ELINK_FAPL_SET, H5L_ACS_ELINK_FAPL_GET, H5L_ACS_ELINK_FAPL_ENC, H5L_ACS_ELINK_FAPL_DEC,
+ H5L_ACS_ELINK_FAPL_DEL, H5L_ACS_ELINK_FAPL_COPY, H5L_ACS_ELINK_FAPL_CMP, H5L_ACS_ELINK_FAPL_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for external link file access flags */
+ if(H5P_register_real(pclass, H5L_ACS_ELINK_FLAGS_NAME, H5L_ACS_ELINK_FLAGS_SIZE, &H5L_def_elink_flags_g,
+ NULL, NULL, NULL, H5L_ACS_ELINK_FLAGS_ENC, H5L_ACS_ELINK_FLAGS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for external link file traversal callback */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5L_ACS_ELINK_CB_NAME, H5L_ACS_ELINK_CB_SIZE, &H5L_def_elink_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+#ifdef H5_HAVE_PARALLEL
+ /* Register the metadata collective read flag */
+ if(H5P_register_real(pclass, H5_COLL_MD_READ_FLAG_NAME, H5L_ACS_COLL_MD_READ_SIZE, &H5L_def_coll_md_read_g,
+ NULL, NULL, NULL, H5L_ACS_COLL_MD_READ_ENC, H5L_ACS_COLL_MD_READ_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+#endif /* H5_HAVE_PARALLEL */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_set
+ *
+ * Purpose: Copies an external link FAPL property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ hid_t l_fapl_id;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Get the FAPL ID */
+ l_fapl_id = *(const hid_t *)value;
+
+ /* Duplicate the FAPL, if it's non-default */
+ if(l_fapl_id != H5P_DEFAULT) {
+ H5P_genplist_t *l_fapl_plist;
+
+ if(NULL == (l_fapl_plist = (H5P_genplist_t *)H5P_object_verify(l_fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get property list")
+ if(((*(hid_t *)value) = H5P_copy_plist(l_fapl_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy file access property list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_get
+ *
+ * Purpose: Copies an external link FAPL property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ hid_t l_fapl_id;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Get the FAPL ID */
+ l_fapl_id = *(const hid_t *)value;
+
+ /* Duplicate the FAPL, if it's non-default */
+ if(l_fapl_id != H5P_DEFAULT) {
+ H5P_genplist_t *l_fapl_plist;
+
+ if(NULL == (l_fapl_plist = (H5P_genplist_t *)H5P_object_verify(l_fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get property list")
+ if(((*(hid_t *)value) = H5P_copy_plist(l_fapl_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy file access property list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_enc
+ *
+ * Purpose: Callback routine which is called whenever the elink FAPL
+ * property in the dataset access property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_enc(const void *value, void **_pp, size_t *size)
+{
+ const hid_t *elink_fapl = (const hid_t *)value; /* Property to encode */
+ uint8_t **pp = (uint8_t **)_pp;
+ H5P_genplist_t *fapl_plist; /* Pointer to property list */
+ hbool_t non_default_fapl = FALSE; /* Whether the FAPL is non-default */
+ size_t fapl_size = 0; /* FAPL's encoded size */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check for non-default FAPL */
+ if(*elink_fapl != H5P_DEFAULT) {
+ if(NULL == (fapl_plist = (H5P_genplist_t *)H5P_object_verify(*elink_fapl, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property list")
+ non_default_fapl = TRUE;
+ } /* end if */
+
+ if(NULL != *pp) {
+ /* Store whether the FAPL is non-default */
+ *(*pp)++ = (uint8_t)non_default_fapl;
+ } /* end if */
+
+ /* Encode the property list, if non-default */
+ /* (if *pp == NULL, will only compute the size) */
+ if(non_default_fapl) {
+ if(H5P__encode(fapl_plist, TRUE, NULL, &fapl_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "can't encode property list")
+
+ if(*pp) {
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ /* encode the length of the plist */
+ enc_value = (uint64_t)fapl_size;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode the plist */
+ if(H5P__encode(fapl_plist, TRUE, *pp, &fapl_size) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, FAIL, "can't encode property list")
+
+ *pp += fapl_size;
+ }
+ fapl_size += (1 + H5VM_limit_enc_size((uint64_t)fapl_size));
+ } /* end if */
+
+ *size += (1 + fapl_size); /* Non-default flag, plus encoded property list size */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_dec
+ *
+ * Purpose: Callback routine which is called whenever the elink FAPL
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_dec(const void **_pp, void *_value)
+{
+ hid_t *elink_fapl = (hid_t *)_value; /* The elink FAPL value */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ hbool_t non_default_fapl; /* Whether the FAPL is non-default */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(elink_fapl);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Determine if the FAPL is non-default */
+ non_default_fapl = (hbool_t)*(*pp)++;
+
+ if(non_default_fapl) {
+ size_t fapl_size = 0; /* Encoded size of property list */
+ unsigned enc_size;
+ uint64_t enc_value;
+
+ /* Decode the plist length */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ fapl_size = (size_t)enc_value;
+
+ /* Decode the property list */
+ if((*elink_fapl = H5P__decode(*pp)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "can't decode property")
+
+ *pp += fapl_size;
+ } /* end if */
+ else
+ *elink_fapl = H5P_DEFAULT;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_dec() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_del
+ *
+ * Purpose: Close the FAPL for link access
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Tuesday, Sept 23, 2008
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ hid_t l_fapl_id;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Get the FAPL ID */
+ l_fapl_id = (*(const hid_t *)value);
+
+ /* Close the FAPL */
+ if(l_fapl_id != H5P_DEFAULT && H5I_dec_ref(l_fapl_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_copy
+ *
+ * Purpose: Copy the FAPL for link access
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Tuesday, Sept 23, 2008
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ hid_t l_fapl_id;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Get the FAPL ID */
+ l_fapl_id = (*(const hid_t *)value);
+
+ /* Duplicate the FAPL, if it's non-default */
+ if(l_fapl_id != H5P_DEFAULT) {
+ H5P_genplist_t *l_fapl_plist;
+
+ if(NULL == (l_fapl_plist = (H5P_genplist_t *)H5P_object_verify(l_fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get property list")
+ if(((*(hid_t *)value) = H5P_copy_plist(l_fapl_plist, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "unable to copy file access property list")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_cmp
+ *
+ * Purpose: Callback routine which is called whenever the elink FAPL
+ * property in the link access property list is
+ * compared.
+ *
+ * Return: zero if VALUE1 and VALUE2 are equal, non zero otherwise.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, August 15, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__lacc_elink_fapl_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size)
+{
+ const hid_t *fapl1 = (const hid_t *)value1;
+ const hid_t *fapl2 = (const hid_t *)value2;
+ H5P_genplist_t *obj1, *obj2; /* Property lists to compare */
+ int ret_value = 0;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check for comparison with default value */
+ if(*fapl1 == 0 && *fapl2 > 0) HGOTO_DONE(1);
+ if(*fapl1 > 0 && *fapl2 == 0) HGOTO_DONE(-1);
+
+ /* Get the property list objects */
+ obj1 = (H5P_genplist_t *)H5I_object(*fapl1);
+ obj2 = (H5P_genplist_t *)H5I_object(*fapl2);
+
+ /* Check for NULL property lists */
+ if(obj1 == NULL && obj2 != NULL) HGOTO_DONE(1);
+ if(obj1 != NULL && obj2 == NULL) HGOTO_DONE(-1);
+ if(obj1 && obj2) {
+ herr_t status;
+
+ status = H5P_cmp_plist(obj1, obj2, &ret_value);
+ HDassert(status >= 0);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_cmp() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_fapl_close
+ *
+ * Purpose: Close the FAPL for link access
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi
+ * Tuesday, Sept 23, 2008
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_fapl_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ hid_t l_fapl_id;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Get the FAPL ID */
+ l_fapl_id = (*(const hid_t *)value);
+
+ /* Close the FAPL */
+ if((l_fapl_id > H5P_DEFAULT) && (H5I_dec_ref(l_fapl_id) < 0))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_fapl_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_set
+ *
+ * Purpose: Copies an external link prefix property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Copy the prefix */
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_get
+ *
+ * Purpose: Copies an external link prefix property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Copy the prefix */
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_enc
+ *
+ * Purpose: Callback routine which is called whenever the elink flags
+ * property in the dataset access property list is
+ * encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_enc(const void *value, void **_pp, size_t *size)
+{
+ const char *elink_pref = *(const char * const *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+ size_t len = 0;
+ uint64_t enc_value;
+ unsigned enc_size;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* calculate prefix length */
+ if(NULL != elink_pref)
+ len = HDstrlen(elink_pref);
+
+ enc_value = (uint64_t)len;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+
+ if(NULL != *pp) {
+ /* encode the length of the prefix */
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode the prefix */
+ if(NULL != elink_pref) {
+ HDmemcpy(*(char **)pp, elink_pref, len);
+ *pp += len;
+ } /* end if */
+ } /* end if */
+
+ *size += (1 + enc_size);
+ if(NULL != elink_pref)
+ *size += len;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_dec
+ *
+ * Purpose: Callback routine which is called whenever the elink prefix
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_dec(const void **_pp, void *_value)
+{
+ char **elink_pref = (char **)_value;
+ const uint8_t **pp = (const uint8_t **)_pp;
+ size_t len;
+ uint64_t enc_value; /* Decoded property value */
+ unsigned enc_size; /* Size of encoded property */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(elink_pref);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Decode the size */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+
+ /* Decode the value */
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ len = (size_t)enc_value;
+
+ if(0 != len) {
+ /* Make a copy of the user's prefix string */
+ if(NULL == (*elink_pref = (char *)H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for prefix")
+ HDstrncpy(*elink_pref, *(const char **)pp, len);
+ (*elink_pref)[len] = '\0';
+
+ *pp += len;
+ } /* end if */
+ else
+ *elink_pref = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_pref_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_del
+ *
+ * Purpose: Frees memory used to store the external link prefix string
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_copy
+ *
+ * Purpose: Creates a copy of the external link prefix string
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(value);
+
+ *(char **)value = H5MM_xstrdup(*(const char **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_cmp
+ *
+ * Purpose: Callback routine which is called whenever the elink prefix
+ * property in the dataset creation property list is
+ * compared.
+ *
+ * Return: zero if VALUE1 and VALUE2 are equal, non zero otherwise.
+ *
+ * Programmer: Mohamad Chaarawi
+ * Thursday, November 3, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__lacc_elink_pref_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size)
+{
+ const char *pref1 = *(const char * const *)value1;
+ const char *pref2 = *(const char * const *)value2;
+ int ret_value = 0;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(NULL == pref1 && NULL != pref2)
+ HGOTO_DONE(1);
+ if(NULL != pref1 && NULL == pref2)
+ HGOTO_DONE(-1);
+ if(NULL != pref1 && NULL != pref2)
+ ret_value = HDstrcmp(pref1, pref2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__lacc_elink_pref_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__lacc_elink_pref_close
+ *
+ * Purpose: Frees memory used to store the external link prefix string
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__lacc_elink_pref_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(value);
+
+ H5MM_xfree(*(void **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__lacc_elink_pref_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_nlinks
+ *
+ * Purpose: Set the number of soft or UD link traversals allowed before
+ * the library assumes it has found a cycle and aborts the
+ * traversal.
+ *
+ * The limit on soft or UD link traversals is designed to
+ * terminate link traversal if one or more links form a cycle.
+ * However, users may have a file with a legitimate path
+ * formed of a large number of soft or user-defined links.
+ * This property can be used to allow traversal of as many
+ * links as desired.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Friday, July 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_nlinks(hid_t plist_id, size_t nlinks)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", plist_id, nlinks);
+
+ if(nlinks <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "number of links must be positive");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set number of links */
+ if(H5P_set(plist, H5L_ACS_NLINKS_NAME, &nlinks) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set nlink info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_nlinks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_nlinks
+ *
+ * Purpose: Gets the number of soft or user-defined links that can be
+ * traversed before a failure occurs.
+ *
+ * Retrieves the current setting for the nlinks property on
+ * the given property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Friday, July 14, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_nlinks(hid_t plist_id, size_t *nlinks)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*z", plist_id, nlinks);
+
+ if(!nlinks)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer passed in");
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the current number of links */
+ if(H5P_get(plist, H5L_ACS_NLINKS_NAME, nlinks) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of links")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_prefix
+ *
+ * Purpose: Set a prefix to be applied to the path of any external links
+ * traversed. The prefix is appended to the filename stored
+ * in the external link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, August 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_prefix(hid_t plist_id, const char *prefix)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", plist_id, prefix);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set prefix */
+ if(H5P_set(plist, H5L_ACS_ELINK_PREFIX_NAME, &prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set prefix info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_prefix() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_prefix
+ *
+ * Purpose: Gets the prefix to be applied to any external link
+ * traversals made using this property list.
+ *
+ * If the pointer is not NULL, it points to a user-allocated
+ * buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, August 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Pget_elink_prefix(hid_t plist_id, char *prefix, size_t size)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ char *my_prefix; /* Library's copy of the prefix */
+ size_t len; /* Length of prefix string */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*sz", plist_id, prefix, size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the current prefix */
+ if(H5P_peek(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix")
+
+ /* Check for prefix being set */
+ if(my_prefix) {
+ /* Copy to user's buffer, if given */
+ len = HDstrlen(my_prefix);
+ if(prefix) {
+ HDstrncpy(prefix, my_prefix, MIN(len + 1, size));
+ if(len >= size)
+ prefix[size - 1] = '\0';
+ } /* end if */
+ } /* end if */
+ else
+ len = 0;
+
+ /* Set return value */
+ ret_value = (ssize_t)len;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_prefix() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_fapl
+ *
+ * Purpose: Sets the file access property list for link access
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer:
+ * Vailin Choi; Tuesday, September 12th, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_fapl(hid_t lapl_id, hid_t fapl_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ii", lapl_id, fapl_id);
+
+ /* Check arguments */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link access property list");
+
+ /* Set the file access property list for the link access */
+ if(H5P_set(plist, H5L_ACS_ELINK_FAPL_NAME, &fapl_id) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fapl for link")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_fapl() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_fapl
+ *
+ * Purpose: Gets the file access property list identifier that is
+ * set for link access property.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer:
+ * Vailin Choi; Tuesday, September 12th, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Pget_elink_fapl(hid_t lapl_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", lapl_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ if(H5P_get(plist, H5L_ACS_ELINK_FAPL_NAME, &ret_value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fapl for links")
+
+done:
+ FUNC_LEAVE_API(ret_value);
+} /* end H5Pget_elink_fapl() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_acc_flags
+ *
+ * Purpose: Sets the file access flags to be used when traversing an
+ * external link. This should be either H5F_ACC_RDONLY or
+ * H5F_ACC_RDWR, or H5F_ACC_DEFAULT to unset the value.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 9, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_acc_flags(hid_t lapl_id, unsigned flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", lapl_id, flags);
+
+ /* Check that flags are valid */
+ if(( flags != H5F_ACC_RDWR) && (flags != (H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE))
+ && (flags != H5F_ACC_RDONLY) && (flags != (H5F_ACC_RDONLY | H5F_ACC_SWMR_READ))
+ && (flags != H5F_ACC_DEFAULT))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set flags */
+ if(H5P_set(plist, H5L_ACS_ELINK_FLAGS_NAME, &flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set access flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_acc_flags
+ *
+ * Purpose: Gets the file access flags to be used when traversing an
+ * external link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 9, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_elink_acc_flags(hid_t lapl_id, unsigned *flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", lapl_id, flags);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get flags */
+ if(flags)
+ if(H5P_get(plist, H5L_ACS_ELINK_FLAGS_NAME, flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "can't get access flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_cb
+ *
+ * Purpose: Sets the file access flags to be used when traversing an
+ * external link. This should be either H5F_ACC_RDONLY or
+ * H5F_ACC_RDWR.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 15, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_cb(hid_t lapl_id, H5L_elink_traverse_t func, void *op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", lapl_id, func, op_data);
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && op_data)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Populate the callback info struct */
+ cb_info.func = func;
+ cb_info.user_data = op_data;
+
+ /* Set callback info */
+ if(H5P_set(plist, H5L_ACS_ELINK_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set callback info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_cb
+ *
+ * Purpose: Gets the file access flags to be used when traversing an
+ * external link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 15, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_elink_cb(hid_t lapl_id, H5L_elink_traverse_t *func, void **op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", lapl_id, func, op_data);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get callback_info */
+ if(H5P_get(plist, H5L_ACS_ELINK_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info")
+
+ if(func)
+ *func = cb_info.func;
+ if(op_data)
+ *op_data = cb_info.user_data;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_cb() */
+
diff --git a/src/H5Plcpl.c b/src/H5Plcpl.c
new file mode 100644
index 0000000..6508a82
--- /dev/null
+++ b/src/H5Plcpl.c
@@ -0,0 +1,208 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Plcpl.c
+ * May 8 2006
+ * Peter Cao <xcao@ncsa.uiuc.edu>
+ *
+ * Purpose: Link creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ======== Link creation properties ======== */
+/* Definitions for create intermediate groups flag */
+#define H5L_CRT_INTERMEDIATE_GROUP_SIZE sizeof(unsigned)
+#define H5L_CRT_INTERMEDIATE_GROUP_DEF 0
+#define H5L_CRT_INTERMEDIATE_GROUP_ENC H5P__encode_unsigned
+#define H5L_CRT_INTERMEDIATE_GROUP_DEC H5P__decode_unsigned
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P_lcrt_reg_prop(H5P_genclass_t *pclass);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Link creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_LCRT[1] = {{
+ "link create", /* Class name for debugging */
+ H5P_TYPE_LINK_CREATE, /* Class type */
+
+ &H5P_CLS_STRING_CREATE_g, /* Parent class */
+ &H5P_CLS_LINK_CREATE_g, /* Pointer to class */
+ &H5P_CLS_LINK_CREATE_ID_g, /* Pointer to class ID */
+ &H5P_LST_LINK_CREATE_ID_g, /* Pointer to default property list ID */
+ H5P_lcrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const unsigned H5L_def_intmd_group_g = H5L_CRT_INTERMEDIATE_GROUP_DEF; /* Default setting for creating intermediate groups */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_lcrt_reg_prop
+ *
+ * Purpose: Register the dataset creation property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_lcrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Register create intermediate groups property */
+ if(H5P_register_real(pclass, H5L_CRT_INTERMEDIATE_GROUP_NAME, H5L_CRT_INTERMEDIATE_GROUP_SIZE, &H5L_def_intmd_group_g,
+ NULL, NULL, NULL, H5L_CRT_INTERMEDIATE_GROUP_ENC, H5L_CRT_INTERMEDIATE_GROUP_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_lcrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_create_intermediate_group
+ *
+ * Purpose: set crt_intmd_group so that H5Lcreate_*, H5Olink, etc.
+ * will create missing groups along the given path "name"
+ *
+ * Note: XXX: This property should really be an access property. -QAK
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * May 08, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_create_intermediate_group(hid_t plist_id, unsigned crt_intmd_group)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, crt_intmd_group);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ crt_intmd_group = (unsigned)(crt_intmd_group > 0 ? 1 : 0);
+ if(H5P_set(plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set intermediate group creation flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_create_intermediate_group() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_create_intermediate_group
+ *
+ * Purpose: Returns the crt_intmd_group, which is set to create missing
+ * groups during H5Olink, etc.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * May 08, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_create_intermediate_group(hid_t plist_id, unsigned *crt_intmd_group /*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, crt_intmd_group);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_LINK_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(crt_intmd_group)
+ if(H5P_get(plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, crt_intmd_group) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get intermediate group creation flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_create_intermediate_group() */
+
diff --git a/src/H5Pmodule.h b/src/H5Pmodule.h
new file mode 100644
index 0000000..d5c471a
--- /dev/null
+++ b/src/H5Pmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5P package. Including this header means that the source file
+ * is part of the H5P package.
+ */
+#ifndef _H5Pmodule_H
+#define _H5Pmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5P_MODULE
+#define H5_MY_PKG H5P
+#define H5_MY_PKG_ERR H5E_PLIST
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Pmodule_H */
+
diff --git a/src/H5Pocpl.c b/src/H5Pocpl.c
new file mode 100644
index 0000000..0393f7f
--- /dev/null
+++ b/src/H5Pocpl.c
@@ -0,0 +1,1983 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pocpl.c
+ * Nov 28 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Ppkg.h" /* Property lists */
+#include "H5PLprivate.h" /* Dynamic plugin */
+#include "H5Zprivate.h" /* Filter pipeline */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= Object Creation properties ============ */
+/* Definitions for the max. # of attributes to store compactly */
+#define H5O_CRT_ATTR_MAX_COMPACT_SIZE sizeof(unsigned)
+#define H5O_CRT_ATTR_MAX_COMPACT_ENC H5P__encode_unsigned
+#define H5O_CRT_ATTR_MAX_COMPACT_DEC H5P__decode_unsigned
+/* Definitions for the min. # of attributes to store densely */
+#define H5O_CRT_ATTR_MIN_DENSE_SIZE sizeof(unsigned)
+#define H5O_CRT_ATTR_MIN_DENSE_ENC H5P__encode_unsigned
+#define H5O_CRT_ATTR_MIN_DENSE_DEC H5P__decode_unsigned
+/* Definitions for object header flags */
+#define H5O_CRT_OHDR_FLAGS_SIZE sizeof(uint8_t)
+#define H5O_CRT_OHDR_FLAGS_ENC H5P__encode_uint8_t
+#define H5O_CRT_OHDR_FLAGS_DEC H5P__decode_uint8_t
+/* Definitions for filter pipeline */
+#define H5O_CRT_PIPELINE_SIZE sizeof(H5O_pline_t)
+#define H5O_CRT_PIPELINE_SET H5P__ocrt_pipeline_set
+#define H5O_CRT_PIPELINE_GET H5P__ocrt_pipeline_get
+#define H5O_CRT_PIPELINE_ENC H5P__ocrt_pipeline_enc
+#define H5O_CRT_PIPELINE_DEC H5P__ocrt_pipeline_dec
+#define H5O_CRT_PIPELINE_DEL H5P__ocrt_pipeline_del
+#define H5O_CRT_PIPELINE_COPY H5P__ocrt_pipeline_copy
+#define H5O_CRT_PIPELINE_CMP H5P__ocrt_pipeline_cmp
+#define H5O_CRT_PIPELINE_CLOSE H5P__ocrt_pipeline_close
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__ocrt_reg_prop(H5P_genclass_t *pclass);
+
+/* Property callbacks */
+static herr_t H5P__ocrt_pipeline_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__ocrt_pipeline_dec(const void **_pp, void *value);
+static herr_t H5P__ocrt_pipeline_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocrt_pipeline_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocrt_pipeline_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocrt_pipeline_copy(const char *name, size_t size, void *value);
+static int H5P__ocrt_pipeline_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__ocrt_pipeline_close(const char *name, size_t size, void *value);
+
+/* Local routines */
+static herr_t H5P__set_filter(H5P_genplist_t *plist, H5Z_filter_t filter,
+ unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/]);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Object creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_OCRT[1] = {{
+ "object create", /* Class name for debugging */
+ H5P_TYPE_OBJECT_CREATE, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_OBJECT_CREATE_g, /* Pointer to class */
+ &H5P_CLS_OBJECT_CREATE_ID_g, /* Pointer to class ID */
+ NULL, /* Pointer to default property list ID */
+ H5P__ocrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const unsigned H5O_def_attr_max_compact_g = H5O_CRT_ATTR_MAX_COMPACT_DEF; /* Default max. compact attribute storage settings */
+static const unsigned H5O_def_attr_min_dense_g = H5O_CRT_ATTR_MIN_DENSE_DEF; /* Default min. dense attribute storage settings */
+static const uint8_t H5O_def_ohdr_flags_g = H5O_CRT_OHDR_FLAGS_DEF; /* Default object header flag settings */
+static const H5O_pline_t H5O_def_pline_g = H5O_CRT_PIPELINE_DEF; /* Default I/O pipeline setting */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_reg_prop
+ *
+ * Purpose: Initialize the object creation property list class
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register max. compact attribute storage property */
+ if(H5P_register_real(pclass, H5O_CRT_ATTR_MAX_COMPACT_NAME, H5O_CRT_ATTR_MAX_COMPACT_SIZE, &H5O_def_attr_max_compact_g,
+ NULL, NULL, NULL, H5O_CRT_ATTR_MAX_COMPACT_ENC, H5O_CRT_ATTR_MAX_COMPACT_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register min. dense attribute storage property */
+ if(H5P_register_real(pclass, H5O_CRT_ATTR_MIN_DENSE_NAME, H5O_CRT_ATTR_MIN_DENSE_SIZE, &H5O_def_attr_min_dense_g,
+ NULL, NULL, NULL, H5O_CRT_ATTR_MIN_DENSE_ENC, H5O_CRT_ATTR_MIN_DENSE_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register object header flags property */
+ if(H5P_register_real(pclass, H5O_CRT_OHDR_FLAGS_NAME, H5O_CRT_OHDR_FLAGS_SIZE, &H5O_def_ohdr_flags_g,
+ NULL, NULL, NULL, H5O_CRT_OHDR_FLAGS_ENC, H5O_CRT_OHDR_FLAGS_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the pipeline property */
+ if(H5P_register_real(pclass, H5O_CRT_PIPELINE_NAME, H5O_CRT_PIPELINE_SIZE, &H5O_def_pline_g,
+ NULL, H5O_CRT_PIPELINE_SET, H5O_CRT_PIPELINE_GET, H5O_CRT_PIPELINE_ENC, H5O_CRT_PIPELINE_DEC,
+ H5O_CRT_PIPELINE_DEL, H5O_CRT_PIPELINE_COPY, H5O_CRT_PIPELINE_CMP, H5O_CRT_PIPELINE_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_attr_phase_change
+ *
+ * Purpose: Sets the cutoff values for indexes storing attributes
+ * in object headers for this file. If more than max_compact
+ * attributes are in an object header, the attributes will be
+ * moved to a heap and indexed with a B-tree.
+ * Likewise, an object header containing fewer than min_dense
+ * attributes will be converted back to storing the attributes
+ * directly in the object header.
+ *
+ * If the max_compact is zero then attributes for this object will
+ * never be stored in the object header but will be always be
+ * stored in a heap.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_attr_phase_change(hid_t plist_id, unsigned max_compact, unsigned min_dense)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIuIu", plist_id, max_compact, min_dense);
+
+ /* Range check values */
+ if(max_compact < min_dense)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "max compact value must be >= min dense value")
+ if(max_compact > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "max compact value must be < 65536")
+ if(min_dense > 65535)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "min dense value must be < 65536")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set property values */
+ if(H5P_set(plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &max_compact) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set max. # of compact attributes in property list")
+ if(H5P_set(plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &min_dense) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set min. # of dense attributes in property list")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_attr_phase_change */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_attr_phase_change
+ *
+ * Purpose: Gets the phase change values for attribute storage
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_attr_phase_change(hid_t plist_id, unsigned *max_compact, unsigned *min_dense)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*Iu*Iu", plist_id, max_compact, min_dense);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(max_compact) {
+ if(H5P_get(plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, max_compact) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get max. # of compact attributes")
+ } /* end if */
+ if(min_dense) {
+ if(H5P_get(plist, H5O_CRT_ATTR_MIN_DENSE_NAME, min_dense) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get min. # of dense attributes")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_attr_phase_change() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_attr_creation_order
+ *
+ * Purpose: Set the flags for creation order of attributes on an object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_attr_creation_order(hid_t plist_id, unsigned crt_order_flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ uint8_t ohdr_flags; /* Object header flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, crt_order_flags);
+
+ /* Check for bad combination of flags */
+ if(!(crt_order_flags & H5P_CRT_ORDER_TRACKED) && (crt_order_flags & H5P_CRT_ORDER_INDEXED))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "tracking creation order is required for index")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get object header flags */
+ if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags")
+
+ /* Mask off previous attribute creation order flag settings */
+ ohdr_flags &= (uint8_t)~(H5O_HDR_ATTR_CRT_ORDER_TRACKED | H5O_HDR_ATTR_CRT_ORDER_INDEXED);
+
+ /* Update with new attribute creation order flags */
+ ohdr_flags = (uint8_t)(ohdr_flags | ((crt_order_flags & H5P_CRT_ORDER_TRACKED) ? H5O_HDR_ATTR_CRT_ORDER_TRACKED : 0));
+ ohdr_flags = (uint8_t)(ohdr_flags | ((crt_order_flags & H5P_CRT_ORDER_INDEXED) ? H5O_HDR_ATTR_CRT_ORDER_INDEXED : 0));
+
+ /* Set object header flags */
+ if(H5P_set(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object header flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_attr_creation_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_attr_creation_order
+ *
+ * Purpose: Returns the flags indicating creation order is tracked/indexed
+ * for attributes on an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * February 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_attr_creation_order(hid_t plist_id, unsigned *crt_order_flags)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Iu", plist_id, crt_order_flags);
+
+ /* Get values */
+ if(crt_order_flags) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ uint8_t ohdr_flags; /* Object header flags */
+
+ /* Reset the value to return */
+ *crt_order_flags = 0;
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get object header flags */
+ if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags")
+
+ /* Set creation order flags to return */
+ *crt_order_flags |= (ohdr_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? H5P_CRT_ORDER_TRACKED : 0;
+ *crt_order_flags |= (ohdr_flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? H5P_CRT_ORDER_INDEXED : 0;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_attr_creation_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_obj_track_times
+ *
+ * Purpose: Set whether the birth, access, modification & change times for
+ * an object are stored.
+ *
+ * Birth time is the time the object was created. Access time is
+ * the last time that metadata or raw data was read from this
+ * object. Modification time is the last time the data for
+ * this object was changed (either writing raw data to a dataset
+ * or inserting/modifying/deleting a link in a group). Change
+ * time is the last time the metadata for this object was written
+ * (adding/modifying/deleting an attribute on an object, extending
+ * the size of a dataset, etc).
+ *
+ * If these times are not tracked, they will be reported as
+ * 12:00 AM UDT, Jan. 1, 1970 (i.e. 0 seconds past the UNIX
+ * epoch) when queried.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * March 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_obj_track_times(hid_t plist_id, hbool_t track_times)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ uint8_t ohdr_flags; /* Object header flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ib", plist_id, track_times);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get object header flags */
+ if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags")
+
+ /* Mask off previous time tracking flag settings */
+ ohdr_flags &= (uint8_t)~H5O_HDR_STORE_TIMES;
+
+ /* Update with new time tracking flag */
+ ohdr_flags = (uint8_t)(ohdr_flags | (track_times ? H5O_HDR_STORE_TIMES : 0));
+
+ /* Set object header flags */
+ if(H5P_set(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object header flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_obj_track_times() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_obj_track_times
+ *
+ * Purpose: Returns whether times are tracked for an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * March 1, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_obj_track_times(hid_t plist_id, hbool_t *track_times)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*b", plist_id, track_times);
+
+ /* Get values */
+ if(track_times) {
+ H5P_genplist_t *plist; /* Property list pointer */
+ uint8_t ohdr_flags; /* Object header flags */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get object header flags */
+ if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags")
+
+ /* Set track times flag to return */
+ *track_times = (hbool_t)((ohdr_flags & H5O_HDR_STORE_TIMES) ? TRUE : FALSE);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_obj_track_times() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_modify_filter
+ *
+ * Purpose: Modifies the specified FILTER in the
+ * transient or permanent output filter pipeline
+ * depending on whether PLIST is a dataset creation or dataset
+ * transfer property list. The FLAGS argument specifies certain
+ * general properties of the filter and is documented below.
+ * The CD_VALUES is an array of CD_NELMTS integers which are
+ * auxiliary data for the filter. The integer vlues will be
+ * stored in the dataset object header as part of the filter
+ * information.
+ *
+ * The FLAGS argument is a bit vector of the following fields:
+ *
+ * H5Z_FLAG_OPTIONAL(0x0001)
+ * If this bit is set then the filter is optional. If the
+ * filter fails during an H5Dwrite() operation then the filter
+ * is just excluded from the pipeline for the chunk for which it
+ * failed; the filter will not participate in the pipeline
+ * during an H5Dread() of the chunk. If this bit is clear and
+ * the filter fails then the entire I/O operation fails.
+ * If this bit is set but encoding is disabled for a filter,
+ * attempting to write will generate an error.
+ *
+ * Note: This function currently supports only the permanent filter
+ * pipeline. That is, PLIST_ID must be a dataset creation
+ * property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_modify_filter(H5P_genplist_t *plist, H5Z_filter_t filter, unsigned flags,
+ size_t cd_nelmts, const unsigned cd_values[/*cd_nelmts*/])
+{
+ H5O_pline_t pline;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the pipeline property to modify */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Modify the filter parameters of the I/O pipeline */
+ if(H5Z_modify(&pline, filter, flags, cd_nelmts, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add filter to pipeline")
+
+ /* Put the I/O pipeline information back into the property list */
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_modify_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pmodify_filter
+ *
+ * Purpose: Modifies the specified FILTER in the
+ * transient or permanent output filter pipeline
+ * depending on whether PLIST is a dataset creation or dataset
+ * transfer property list. The FLAGS argument specifies certain
+ * general properties of the filter and is documented below.
+ * The CD_VALUES is an array of CD_NELMTS integers which are
+ * auxiliary data for the filter. The integer vlues will be
+ * stored in the dataset object header as part of the filter
+ * information.
+ *
+ * The FLAGS argument is a bit vector of the following fields:
+ *
+ * H5Z_FLAG_OPTIONAL(0x0001)
+ * If this bit is set then the filter is optional. If the
+ * filter fails during an H5Dwrite() operation then the filter
+ * is just excluded from the pipeline for the chunk for which it
+ * failed; the filter will not participate in the pipeline
+ * during an H5Dread() of the chunk. If this bit is clear and
+ * the filter fails then the entire I/O operation fails.
+ * If this bit is set but encoding is disabled for a filter,
+ * attempting to write will generate an error.
+ *
+ * Note: This function currently supports only the permanent filter
+ * pipeline. That is, PLIST_ID must be a dataset creation
+ * property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Thursday, March 26, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pmodify_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int flags,
+ size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
+{
+ H5P_genplist_t *plist; /* Property list */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iZfIuz*[a3]Iu", plist_id, filter, flags, cd_nelmts, cd_values);
+
+ /* Check args */
+ if (filter<0 || filter>H5Z_FILTER_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identifier")
+ if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
+ if (cd_nelmts>0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no client data values supplied")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+
+ /* Modify the filter parameters of the I/O pipeline */
+ if(H5P_modify_filter(plist, filter, flags, cd_nelmts, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't modify filter")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pmodify_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_filter
+ *
+ * Purpose: Adds the specified FILTER and corresponding properties to the
+ * end of the data or link output filter pipeline
+ * depending on whether PLIST is a dataset creation or group
+ * creation property list. The FLAGS argument specifies certain
+ * general properties of the filter and is documented below.
+ * The CD_VALUES is an array of CD_NELMTS integers which are
+ * auxiliary data for the filter. The integer vlues will be
+ * stored in the dataset object header as part of the filter
+ * information.
+ *
+ * The FLAGS argument is a bit vector of the following fields:
+ *
+ * H5Z_FLAG_OPTIONAL(0x0001)
+ * If this bit is set then the filter is optional. If the
+ * filter fails during an H5Dwrite() operation then the filter
+ * is just excluded from the pipeline for the chunk for which it
+ * failed; the filter will not participate in the pipeline
+ * during an H5Dread() of the chunk. If this bit is clear and
+ * the filter fails then the entire I/O operation fails.
+ * If this bit is set but encoding is disabled for a filter,
+ * attempting to write will generate an error.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ * Neil Fortner
+ * Wednesday, May 20, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int flags,
+ size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
+{
+ H5P_genplist_t *plist; /* Property list */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iZfIuz*[a3]Iu", plist_id, filter, flags, cd_nelmts, cd_values);
+
+ /* Check args */
+ if (filter<0 || filter>H5Z_FILTER_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identifier")
+ if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
+ if (cd_nelmts>0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no client data values supplied")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Call the private function */
+ if(H5P__set_filter(plist, filter, flags, cd_nelmts, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "failed to call private function")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__set_filter
+ *
+ * Purpose: Adds the specified FILTER and corresponding properties to the
+ * end of the data or link output filter pipeline
+ * depending on whether PLIST is a dataset creation or group
+ * creation property list. The FLAGS argument specifies certain
+ * general properties of the filter and is documented below.
+ * The CD_VALUES is an array of CD_NELMTS integers which are
+ * auxiliary data for the filter. The integer vlues will be
+ * stored in the dataset object header as part of the filter
+ * information.
+ *
+ * The FLAGS argument is a bit vector of the following fields:
+ *
+ * H5Z_FLAG_OPTIONAL(0x0001)
+ * If this bit is set then the filter is optional. If the
+ * filter fails during an H5Dwrite() operation then the filter
+ * is just excluded from the pipeline for the chunk for which it
+ * failed; the filter will not participate in the pipeline
+ * during an H5Dread() of the chunk. If this bit is clear and
+ * the filter fails then the entire I/O operation fails.
+ * If this bit is set but encoding is disabled for a filter,
+ * attempting to write will generate an error.
+ *
+ * If the filter is not registered, this function tries to load
+ * it dynamically during run time.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__set_filter(H5P_genplist_t *plist, H5Z_filter_t filter, unsigned int flags,
+ size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
+{
+ H5O_pline_t pline; /* Filter pipeline */
+ htri_t filter_avail; /* Filter availability */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check if filter is already available */
+ if((filter_avail = H5Z_filter_avail(filter)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't check filter availability")
+
+ /* If filter is not available, try to dynamically load it */
+ if(!filter_avail) {
+ const H5Z_class2_t *filter_info;
+
+ if(NULL == (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, (int)filter)))
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, FAIL, "failed to load dynamically loaded plugin")
+ if(H5Z_register(filter_info) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter")
+ } /* end if */
+
+ /* Get the pipeline property to append to */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Add the filter to the I/O pipeline */
+ if(H5Z_append(&pline, filter, flags, cd_nelmts, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add filter to pipeline")
+
+ /* Put the I/O pipeline information back into the property list */
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__set_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_nfilters
+ *
+ * Purpose: Returns the number of filters in the data or link
+ * pipeline depending on whether PLIST_ID is a dataset creation
+ * or group creation property list. In each pipeline the
+ * filters are numbered from zero through N-1 where N is the
+ * value returned by this function. During output to the file
+ * the filters of a pipeline are applied in increasing order
+ * (the inverse is true for input).
+ *
+ * Return: Success: Number of filters or zero if there are none.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 4, 1998
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Wednesday, May 20, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Pget_nfilters(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the pipeline property to query */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Set return value */
+ ret_value=(int)(pline.nused);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_nfilters */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_filter2
+ *
+ * Purpose: This is the query counterpart of H5Pset_filter() and returns
+ * information about a particular filter number in a permanent
+ * or transient pipeline depending on whether PLIST_ID is a
+ * dataset creation or transfer property list. On input,
+ * CD_NELMTS indicates the number of entries in the CD_VALUES
+ * array allocated by the caller while on exit it contains the
+ * number of values defined by the filter. FILTER_CONFIG is a bit
+ * field contaning encode/decode flags from H5Zpublic.h. The IDX
+ * should be a value between zero and N-1 as described for
+ * H5Pget_nfilters() and the function will return failure if the
+ * filter number is out of range.
+ *
+ * Return: Success: Filter identification number.
+ *
+ * Failure: H5Z_FILTER_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Wednesday, May 20, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_filter_t
+H5Pget_filter2(hid_t plist_id, unsigned idx, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/,
+ unsigned *filter_config /*out*/)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ const H5Z_filter_info_t *filter; /* Pointer to filter information */
+ H5Z_filter_t ret_value; /* return value */
+
+ FUNC_ENTER_API(H5Z_FILTER_ERROR)
+ H5TRACE8("Zf", "iIux*zxzxx", plist_id, idx, flags, cd_nelmts, cd_values,
+ namelen, name, filter_config);
+
+ /* Check args */
+ if(cd_nelmts || cd_values) {
+ /*
+ * It's likely that users forget to initialize this on input, so
+ * we'll check that it has a reasonable value. The actual number
+ * is unimportant because the H5O layer will detect when a message
+ * is too large.
+ */
+ if(cd_nelmts && *cd_nelmts > 256)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "probable uninitialized *cd_nelmts argument")
+ if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "client data values not supplied")
+
+ /*
+ * If cd_nelmts is null but cd_values is non-null then just ignore
+ * cd_values
+ */
+ if(!cd_nelmts)
+ cd_values = NULL;
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5Z_FILTER_ERROR, "can't find object for ID")
+
+ /* Get the pipeline property to query */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get pipeline")
+
+ /* Check index */
+ if(idx >= pline.nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "filter number is invalid")
+
+ /* Set pointer to particular filter to query */
+ filter = &pline.filter[idx];
+
+ /* Get filter information */
+ if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, filter_config) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")
+
+ /* Set return value */
+ ret_value = filter->id;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_filter2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_get_filter_by_id
+ *
+ * Purpose: This is an additional query counterpart of H5Pset_filter() and
+ * returns information about a particular filter in a permanent
+ * or transient pipeline depending on whether PLIST_ID is a
+ * dataset creation or transfer property list. On input,
+ * CD_NELMTS indicates the number of entries in the CD_VALUES
+ * array allocated by the caller while on exit it contains the
+ * number of values defined by the filter. FILTER_CONFIG is a bit
+ * field contaning encode/decode flags from H5Zpublic.h. The ID
+ * should be the filter ID to retrieve the parameters for. If the
+ * filter is not set for the property list, an error will be returned.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_get_filter_by_id(H5P_genplist_t *plist, H5Z_filter_t id, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/, unsigned *filter_config)
+{
+ H5O_pline_t pline; /* Filter pipeline */
+ H5Z_filter_info_t *filter; /* Pointer to filter information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get pipeline info */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Get pointer to filter in pipeline */
+ if(NULL == (filter = H5Z_filter_info(&pline, id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "filter ID is invalid")
+
+ /* Get filter information */
+ if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, filter_config) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get filter info")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_get_filter_by_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_filter_by_id2
+ *
+ * Purpose: This is an additional query counterpart of H5Pset_filter() and
+ * returns information about a particular filter in a permanent
+ * or transient pipeline depending on whether PLIST_ID is a
+ * dataset creation or transfer property list. On input,
+ * CD_NELMTS indicates the number of entries in the CD_VALUES
+ * array allocated by the caller while on exit it contains the
+ * number of values defined by the filter. FILTER_CONFIG is a bit
+ * field contaning encode/decode flags from H5Zpublic.h. The ID
+ * should be the filter ID to retrieve the parameters for. If the
+ * filter is not set for the property list, an error will be returned.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Thursday, May 21, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_filter_by_id2(hid_t plist_id, H5Z_filter_t id, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/, unsigned *filter_config)
+{
+ H5P_genplist_t *plist; /* Property list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("e", "iZfx*zxzx*Iu", plist_id, id, flags, cd_nelmts, cd_values,
+ namelen, name, filter_config);
+
+ /* Check args */
+ if(cd_nelmts || cd_values) {
+ /*
+ * It's likely that users forget to initialize this on input, so
+ * we'll check that it has a reasonable value. The actual number
+ * is unimportant because the H5O layer will detect when a message
+ * is too large.
+ */
+ if(cd_nelmts && *cd_nelmts > 256)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "probable uninitialized *cd_nelmts argument")
+ if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "client data values not supplied")
+
+ /*
+ * If cd_nelmts is null but cd_values is non-null then just ignore
+ * cd_values
+ */
+ if(!cd_nelmts)
+ cd_values = NULL;
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get filter information */
+ if(H5P_get_filter_by_id(plist, id, flags, cd_nelmts, cd_values, namelen,
+ name, filter_config) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get filter info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_filter_by_id2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pall_filters_avail
+ *
+ * Purpose: This is a query routine to verify that all the filters set
+ * in the dataset creation property list are available currently.
+ *
+ * Return: Success: TRUE if all filters available, FALSE if one or
+ * more filters not currently available.
+ * Failure: FAIL on error
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 8, 2003
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Thursday, May 21, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Pall_filters_avail(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the pipeline property to query */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Check if all filters are available */
+ if((ret_value = H5Z_all_filters_avail(&pline)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "can't check pipeline information")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pall_filters_avail() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_filter_in_pline
+ *
+ * Purpose: Check whether the filter is in the pipeline of the object
+ * creation property list.
+ *
+ * Return: TRUE: found
+ * FALSE: not found
+ * FAIL: error
+ *
+ * Programmer: Raymond Lu
+ * 26 April 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5P_filter_in_pline(H5P_genplist_t *plist, H5Z_filter_t id)
+{
+ H5O_pline_t pline; /* Filter pipeline */
+ htri_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get pipeline info */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Check if the file is in the pipeline */
+ if((ret_value = H5Z_filter_in_pline(&pline, id)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTCOMPARE, FAIL, "can't find filter")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_get_filter_by_id() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Premove_filter
+ *
+ * Purpose: Deletes a filter from the dataset creation property list;
+ * deletes all filters if FILTER is H5Z_FILTER_NONE
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Pedro Vicente
+ * January 26, 2004
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Thursday, May 21, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Premove_filter(hid_t plist_id, H5Z_filter_t filter)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iZf", plist_id, filter);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the pipeline property to modify */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Check if there are any filters */
+ if (pline.filter) {
+ /* Delete filter */
+ if(H5Z_delete(&pline, filter) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't delete filter")
+
+ /* Put the I/O pipeline information back into the property list */
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Premove_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_deflate
+ *
+ * Purpose: Sets the compression method for a dataset or group link
+ * filter pipeline (depending on whether PLIST_ID is a dataset
+ * creation or group creation property list) to H5Z_FILTER_DEFLATE
+ * and the compression level to LEVEL which should be a value
+ * between zero and nine, inclusive. Lower compression levels
+ * are faster but result in less compression. This is the same
+ * algorithm as used by the GNU gzip program.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Tuesday, October 2, 2001
+ * Changed the way to check parameter and set property for
+ * generic property list.
+ *
+ * Neil Fortner
+ * Thursday, March 26, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_deflate(hid_t plist_id, unsigned level)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, level);
+
+ /* Check arguments */
+ if(level > 9)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid deflate level")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the pipeline property to append to */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Add the filter */
+ if(H5Z_append(&pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &level) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add deflate filter to pipeline")
+
+ /* Put the I/O pipeline information back into the property list */
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_deflate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fletcher32
+ *
+ * Purpose: Sets Fletcher32 checksum of EDC for a dataset creation
+ * property list or group creation property list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Dec 19, 2002
+ *
+ * Modifications:
+ *
+ * Neil Fortner
+ * Wednesday, May 6, 2009
+ * Overloaded to accept gcpl's as well as dcpl's and moved to
+ * H5Pocpl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fletcher32(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list */
+ H5O_pline_t pline; /* Filter pipeline */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the pipeline property to append to */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
+
+ /* Add the Fletcher32 checksum as a filter */
+ if(H5Z_append(&pline, H5Z_FILTER_FLETCHER32, H5Z_FLAG_MANDATORY, (size_t)0, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add fletcher32 filter to pipeline")
+
+ /* Put the I/O pipeline information back into the property list */
+ if(H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fletcher32() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_get_filter
+ *
+ * Purpose: Internal component of H5Pget_filter & H5Pget_filter_id
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 23, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_get_filter(const H5Z_filter_info_t *filter, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/,
+ unsigned *filter_config /*out*/)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check arguments */
+ HDassert(filter);
+
+ /* Filter flags */
+ if(flags)
+ *flags = filter->flags;
+
+ /* Filter parameters */
+ if(cd_values) {
+ size_t i; /* Local index variable */
+
+ for(i = 0; i < filter->cd_nelmts && i < *cd_nelmts; i++)
+ cd_values[i] = filter->cd_values[i];
+ } /* end if */
+
+ /* Number of filter parameters */
+ if(cd_nelmts)
+ *cd_nelmts = filter->cd_nelmts;
+
+ /* Filter name */
+ if(namelen > 0 && name) {
+ const char *s = filter->name;
+
+ /* If there's no name on the filter, use the class's filter name */
+ if(!s) {
+ H5Z_class2_t *cls = H5Z_find(filter->id);
+
+ if(cls)
+ s = cls->name;
+ } /* end if */
+
+ /* Check for actual name */
+ if(s) {
+ HDstrncpy(name, s, namelen);
+ name[namelen - 1] = '\0';
+ } /* end if */
+ else {
+ /* Check for unknown library filter */
+ /* (probably from a future version of the library) */
+ if(filter->id < 256) {
+ HDstrncpy(name, "Unknown library filter", namelen);
+ name[namelen - 1] = '\0';
+ } /* end if */
+ else
+ name[0] = '\0';
+ } /* end if */
+ } /* end if */
+
+ /* Filter configuration (assume filter ID has already been checked) */
+ if(filter_config)
+ H5Z_get_filter_info(filter->id, filter_config);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P_get_filter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_set
+ *
+ * Purpose: Copies an I/O pipeline property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_pline_t *pline = (H5O_pline_t *)value; /* Create local aliases for values */
+ H5O_pline_t new_pline;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of I/O pipeline */
+ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &new_pline))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy I/O pipeline")
+
+ /* Copy new I/O pipeline message over old one */
+ *pline = new_pline;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_get
+ *
+ * Purpose: Copies a layout property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, Sept 1, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ H5O_pline_t *pline = (H5O_pline_t *)value; /* Create local aliases for values */
+ H5O_pline_t new_pline;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of I/O pipeline */
+ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &new_pline))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy I/O pipeline")
+
+ /* Copy new I/O pipeline message over old one */
+ *pline = new_pline;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_enc
+ *
+ * Purpose: Callback routine which is called whenever the pipeline
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_pline_t *pline = (const H5O_pline_t *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+ size_t u; /* Local index variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(pline);
+ HDassert(size);
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ if(NULL != *pp) {
+ unsigned enc_size;
+ uint64_t enc_value;
+
+ /* Encode size of unsigned */
+ *(*pp)++ = (uint8_t)sizeof(unsigned);
+
+ /* encode nused value */
+ enc_value = (uint64_t)pline->nused;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode each pipeline */
+ for(u = 0; u < pline->nused; u++) {
+ unsigned v; /* Local index variable */
+
+ /* encode filter ID */
+ INT32ENCODE(*pp, pline->filter[u].id)
+
+ /* encode filter flags */
+ H5_ENCODE_UNSIGNED(*pp, pline->filter[u].flags)
+
+ /* encode filter name if it exists */
+ if(NULL != pline->filter[u].name) {
+ /* encode TRUE indicating that it exits */
+ *(*pp)++ = (uint8_t)TRUE;
+
+ /* encode filter name */
+ HDmemcpy(*pp, (uint8_t *)(pline->filter[u].name), H5Z_COMMON_NAME_LEN);
+ *pp += H5Z_COMMON_NAME_LEN;
+ } /* end if */
+ else
+ /* encode FALSE indicating that it does not exist */
+ *(*pp)++ = (uint8_t)FALSE;
+
+ /* encode cd_nelmts */
+ enc_value = (uint64_t)pline->filter[u].cd_nelmts;
+ enc_size = H5VM_limit_enc_size(enc_value);
+ HDassert(enc_size < 256);
+ *(*pp)++ = (uint8_t)enc_size;
+ UINT64ENCODE_VAR(*pp, enc_value, enc_size);
+
+ /* encode all values */
+ for(v = 0; v < pline->filter[u].cd_nelmts; v++)
+ H5_ENCODE_UNSIGNED(*pp, pline->filter[u].cd_values[v])
+ } /* end for */
+ } /* end if */
+
+ /* calculate size required for encoding */
+ *size += 1;
+ *size += (1 + H5VM_limit_enc_size((uint64_t)pline->nused));
+ for(u = 0; u < pline->nused; u++) {
+ *size += (sizeof(int32_t) + sizeof(unsigned) + 1);
+ if(NULL != pline->filter[u].name)
+ *size += H5Z_COMMON_NAME_LEN;
+ *size += (1 + H5VM_limit_enc_size((uint64_t)pline->filter[u].cd_nelmts));
+ *size += pline->filter[u].cd_nelmts * sizeof(unsigned);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__ocrt_pipeline_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_dec
+ *
+ * Purpose: Callback routine which is called whenever the pipeline
+ * property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mohamad Chaarawi
+ * Monday, October 10, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_dec(const void **_pp, void *_value)
+{
+ H5O_pline_t *pline = (H5O_pline_t *)_value; /* Property to set */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ size_t nused; /* Number of filters used for pipeline */
+ unsigned enc_size; /* Size of encoded value (in bytes) */
+ uint64_t enc_value; /* Value to encode */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
+
+ /* Decode the size of size_t */
+ enc_size = *(*pp)++;
+ if(enc_size != sizeof(unsigned))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded")
+
+ /* decode nused */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ nused = (size_t)enc_value;
+
+ /* Set property default value */
+ HDmemset(pline, 0, sizeof(H5O_pline_t));
+ *pline = H5O_def_pline_g;
+
+ for(u = 0; u < nused; u++) {
+ H5Z_filter_info_t filter; /* Filter info, for pipeline */
+ uint8_t has_name; /* Flag to indicate whether filter has a name */
+ unsigned v; /* Local index variable */
+
+ /* decode filter id */
+ INT32DECODE(*pp, filter.id)
+
+ /* decode filter flags */
+ H5_DECODE_UNSIGNED(*pp, filter.flags)
+
+ /* decode value indicating if the name is encoded */
+ has_name = *(*pp)++;
+ if(has_name) {
+ /* decode name */
+ filter.name = H5MM_xstrdup((const char *)(*pp));
+ *pp += H5Z_COMMON_NAME_LEN;
+ } /* end if */
+ else
+ filter.name = NULL;
+
+ /* decode num elements */
+ enc_size = *(*pp)++;
+ HDassert(enc_size < 256);
+ UINT64DECODE_VAR(*pp, enc_value, enc_size);
+ filter.cd_nelmts = (size_t)enc_value;
+
+ if(filter.cd_nelmts) {
+ if(NULL == (filter.cd_values = (unsigned *)H5MM_malloc(sizeof(unsigned) * filter.cd_nelmts)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for cd_values")
+ } /* end if */
+ else
+ filter.cd_values = NULL;
+
+ /* decode values */
+ for(v = 0; v < filter.cd_nelmts; v++)
+ H5_DECODE_UNSIGNED(*pp, filter.cd_values[v])
+
+ /* Add the filter to the I/O pipeline */
+ if(H5Z_append(pline, filter.id, filter.flags, filter.cd_nelmts, filter.cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add filter to pipeline")
+
+ /* Free cd_values, if it was allocated */
+ filter.cd_values = (unsigned *)H5MM_xfree(filter.cd_values);
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__ocrt_pipeline_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_del
+ *
+ * Purpose: Frees memory used to store the I/O pipeline property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old I/O pipeline */
+ if(H5O_msg_reset(H5O_PLINE_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release I/O pipeline message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_copy
+ *
+ * Purpose: Copy the I/O pipeline property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 3, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ H5O_pline_t *pline = (H5O_pline_t *)value; /* Create local aliases for values */
+ H5O_pline_t new_pline;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(pline);
+
+ /* Make copy of I/O pipeline */
+ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &new_pline))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy I/O pipeline")
+
+ /* Copy new I/O pipeline message over old one */
+ *pline = new_pline;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_cmp
+ *
+ * Purpose: Callback routine which is called whenever a filter pipeline
+ * property in a property list is compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 7, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__ocrt_pipeline_cmp(const void *_pline1, const void *_pline2, size_t H5_ATTR_UNUSED size)
+{
+ const H5O_pline_t *pline1 = (const H5O_pline_t *)_pline1, /* Create local aliases for values */
+ *pline2 = (const H5O_pline_t *)_pline2;
+ int cmp_value; /* Value from comparison */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(pline1);
+ HDassert(pline2);
+ HDassert(size == sizeof(H5O_pline_t));
+
+ /* Check the number of used pipeline entries */
+ if(pline1->nused < pline2->nused) HGOTO_DONE(-1);
+ if(pline1->nused > pline2->nused) HGOTO_DONE(1);
+
+ /* Check the filter entry information */
+ if(pline1->filter == NULL && pline2->filter != NULL) HGOTO_DONE(-1);
+ if(pline1->filter != NULL && pline2->filter == NULL) HGOTO_DONE(1);
+ if(pline1->filter != NULL && pline1->nused > 0) {
+ size_t u; /* Local index variable */
+
+ /* Loop through all filters, comparing them */
+ for(u = 0; u < pline1->nused; u++) {
+ /* Check the ID of the filter */
+ if(pline1->filter[u].id < pline2->filter[u].id) HGOTO_DONE(-1);
+ if(pline1->filter[u].id > pline2->filter[u].id) HGOTO_DONE(1);
+
+ /* Check the flags for the filter */
+ if(pline1->filter[u].flags < pline2->filter[u].flags) HGOTO_DONE(-1);
+ if(pline1->filter[u].flags > pline2->filter[u].flags) HGOTO_DONE(1);
+
+ /* Check the name of the filter */
+ if(pline1->filter[u].name == NULL && pline2->filter[u].name != NULL) HGOTO_DONE(-1);
+ if(pline1->filter[u].name != NULL && pline2->filter[u].name == NULL) HGOTO_DONE(1);
+ if(pline1->filter[u].name != NULL)
+ if((cmp_value = HDstrcmp(pline1->filter[u].name, pline2->filter[u].name)) != 0)
+ HGOTO_DONE(cmp_value);
+
+ /* Check the number of parameters for the filter */
+ if(pline1->filter[u].cd_nelmts < pline2->filter[u].cd_nelmts) HGOTO_DONE(-1);
+ if(pline1->filter[u].cd_nelmts > pline2->filter[u].cd_nelmts) HGOTO_DONE(1);
+
+ /* Check the filter parameter information */
+ if(pline1->filter[u].cd_values == NULL && pline2->filter[u].cd_values != NULL) HGOTO_DONE(-1);
+ if(pline1->filter[u].cd_values != NULL && pline2->filter[u].cd_values == NULL) HGOTO_DONE(1);
+ if(pline1->filter[u].cd_values != NULL && pline1->filter[u].cd_nelmts > 0) {
+ size_t v; /* Local index variable */
+
+ /* Loop through all parameters, comparing them */
+ for(v = 0; v < pline1->filter[u].cd_nelmts; v++) {
+ /* Check each parameter for the filter */
+ if(pline1->filter[u].cd_values[v] < pline2->filter[u].cd_values[v]) HGOTO_DONE(-1);
+ if(pline1->filter[u].cd_values[v] > pline2->filter[u].cd_values[v]) HGOTO_DONE(1);
+ } /* end for */
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocrt_pipeline_close
+ *
+ * Purpose: Frees memory used to store the I/O pipeline property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Sept 3, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocrt_pipeline_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Reset the old I/O pipeline */
+ if(H5O_msg_reset(H5O_PLINE_ID, value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTRESET, FAIL, "can't release I/O pipeline message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocrt_pipeline_close() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_filter1
+ *
+ * Purpose: This is the query counterpart of H5Pset_filter() and returns
+ * information about a particular filter number in a permanent
+ * or transient pipeline depending on whether PLIST_ID is a
+ * dataset creation or transfer property list. On input,
+ * CD_NELMTS indicates the number of entries in the CD_VALUES
+ * array allocated by the caller while on exit it contains the
+ * number of values defined by the filter. The IDX
+ * should be a value between zero and N-1 as described for
+ * H5Pget_nfilters() and the function will return failure if the
+ * filter number is out of range.
+ *
+ * Return: Success: Filter identification number.
+ *
+ * Failure: H5Z_FILTER_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 15, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_filter_t
+H5Pget_filter1(hid_t plist_id, unsigned idx, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/)
+{
+ H5O_pline_t pline; /* Filter pipeline */
+ const H5Z_filter_info_t *filter; /* Pointer to filter information */
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5Z_filter_t ret_value; /* return value */
+
+ FUNC_ENTER_API(H5Z_FILTER_ERROR)
+ H5TRACE7("Zf", "iIux*zxzx", plist_id, idx, flags, cd_nelmts, cd_values, namelen,
+ name);
+
+ /* Check args */
+ if(cd_nelmts || cd_values) {
+ /*
+ * It's likely that users forget to initialize this on input, so
+ * we'll check that it has a reasonable value. The actual number
+ * is unimportant because the H5O layer will detect when a message
+ * is too large.
+ */
+ if(cd_nelmts && *cd_nelmts > 256)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "probable uninitialized *cd_nelmts argument")
+ if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "client data values not supplied")
+
+ /*
+ * If cd_nelmts is null but cd_values is non-null then just ignore
+ * cd_values
+ */
+ if(!cd_nelmts)
+ cd_values = NULL;
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5Z_FILTER_ERROR, "can't find object for ID")
+
+ /* Get pipeline info */
+ if(H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get pipeline")
+
+ /* Check more args */
+ if(idx >= pline.nused)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "filter number is invalid")
+
+ /* Set pointer to particular filter to query */
+ filter = &pline.filter[idx];
+
+ /* Get filter information */
+ if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")
+
+ /* Set return value */
+ ret_value = filter->id;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_filter1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_filter_by_id1
+ *
+ * Purpose: This is an additional query counterpart of H5Pset_filter() and
+ * returns information about a particular filter in a permanent
+ * or transient pipeline depending on whether PLIST_ID is a
+ * dataset creation or transfer property list. On input,
+ * CD_NELMTS indicates the number of entries in the CD_VALUES
+ * array allocated by the caller while on exit it contains the
+ * number of values defined by the filter. The ID
+ * should be the filter ID to retrieve the parameters for. If the
+ * filter is not set for the property list, an error will be returned.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_filter_by_id1(hid_t plist_id, H5Z_filter_t id, unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
+ size_t namelen, char name[]/*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE7("e", "iZfx*zxzx", plist_id, id, flags, cd_nelmts, cd_values, namelen,
+ name);
+
+ /* Check args */
+ if(cd_nelmts || cd_values) {
+ /*
+ * It's likely that users forget to initialize this on input, so
+ * we'll check that it has a reasonable value. The actual number
+ * is unimportant because the H5O layer will detect when a message
+ * is too large.
+ */
+ if(cd_nelmts && *cd_nelmts > 256)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "probable uninitialized *cd_nelmts argument")
+ if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "client data values not supplied")
+
+ /*
+ * If cd_nelmts is null but cd_values is non-null then just ignore
+ * cd_values
+ */
+ if(!cd_nelmts)
+ cd_values = NULL;
+ } /* end if */
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get filter info */
+ if(H5P_get_filter_by_id(plist, id, flags, cd_nelmts, cd_values, namelen, name, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get filter info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_filter_by_id1() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Pocpypl.c b/src/H5Pocpypl.c
new file mode 100644
index 0000000..47bba05
--- /dev/null
+++ b/src/H5Pocpypl.c
@@ -0,0 +1,918 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pocpypl.c
+ * Mar 13 2006
+ * Peter Cao <xcao@ncsa.uiuc.edu>
+ *
+ * Purpose: Object copying property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ========= Object Copy properties ============ */
+/* Definitions for copy options */
+#define H5O_CPY_OPTION_SIZE sizeof(unsigned)
+#define H5O_CPY_OPTION_DEF 0
+#define H5O_CPY_OPTION_ENC H5P__encode_unsigned
+#define H5O_CPY_OPTION_DEC H5P__decode_unsigned
+/* Definitions for merge committed dtype list */
+#define H5O_CPY_MERGE_COMM_DT_LIST_SIZE sizeof(H5O_copy_dtype_merge_list_t *)
+#define H5O_CPY_MERGE_COMM_DT_LIST_DEF NULL
+#define H5O_CPY_MERGE_COMM_DT_LIST_SET H5P__ocpy_merge_comm_dt_list_set
+#define H5O_CPY_MERGE_COMM_DT_LIST_GET H5P__ocpy_merge_comm_dt_list_get
+#define H5O_CPY_MERGE_COMM_DT_LIST_ENC H5P__ocpy_merge_comm_dt_list_enc
+#define H5O_CPY_MERGE_COMM_DT_LIST_DEC H5P__ocpy_merge_comm_dt_list_dec
+#define H5O_CPY_MERGE_COMM_DT_LIST_DEL H5P__ocpy_merge_comm_dt_list_del
+#define H5O_CPY_MERGE_COMM_DT_LIST_COPY H5P__ocpy_merge_comm_dt_list_copy
+#define H5O_CPY_MERGE_COMM_DT_LIST_CMP H5P__ocpy_merge_comm_dt_list_cmp
+#define H5O_CPY_MERGE_COMM_DT_LIST_CLOSE H5P__ocpy_merge_comm_dt_list_close
+/* Definitions for callback function when completing the search for a matching committed datatype from the committed dtype list */
+#define H5O_CPY_MCDT_SEARCH_CB_SIZE sizeof(H5O_mcdt_cb_info_t)
+#define H5O_CPY_MCDT_SEARCH_CB_DEF {NULL,NULL}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* General routines */
+static H5O_copy_dtype_merge_list_t *H5P__free_merge_comm_dtype_list(H5O_copy_dtype_merge_list_t *dt_list);
+static herr_t H5P__copy_merge_comm_dt_list(H5O_copy_dtype_merge_list_t **value);
+
+/* Property class callbacks */
+static herr_t H5P__ocpy_reg_prop(H5P_genclass_t *pclass);
+
+/* Property callbacks */
+static herr_t H5P__ocpy_merge_comm_dt_list_set(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocpy_merge_comm_dt_list_get(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocpy_merge_comm_dt_list_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__ocpy_merge_comm_dt_list_dec(const void **_pp, void *value);
+static herr_t H5P__ocpy_merge_comm_dt_list_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P__ocpy_merge_comm_dt_list_copy(const char* name, size_t size, void* value);
+static int H5P__ocpy_merge_comm_dt_list_cmp(const void *value1, const void *value2, size_t size);
+static herr_t H5P__ocpy_merge_comm_dt_list_close(const char* name, size_t size, void* value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Object copy property list class library initialization object */
+const H5P_libclass_t H5P_CLS_OCPY[1] = {{
+ "object copy", /* Class name for debugging */
+ H5P_TYPE_OBJECT_COPY, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_OBJECT_COPY_g, /* Pointer to class */
+ &H5P_CLS_OBJECT_COPY_ID_g, /* Pointer to class ID */
+ &H5P_LST_OBJECT_COPY_ID_g, /* Pointer to default property list ID */
+ H5P__ocpy_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const unsigned H5O_def_ocpy_option_g = H5O_CPY_OPTION_DEF; /* Default object copy flags */
+static const H5O_copy_dtype_merge_list_t *H5O_def_merge_comm_dtype_list_g = H5O_CPY_MERGE_COMM_DT_LIST_DEF; /* Default merge committed dtype list */
+static const H5O_mcdt_cb_info_t H5O_def_mcdt_cb_g = H5O_CPY_MCDT_SEARCH_CB_DEF; /* Default callback before searching the global list of committed datatypes at destination */
+
+/* Declare a free list to manage the H5O_copy_dtype_merge_list_t struct */
+H5FL_DEFINE(H5O_copy_dtype_merge_list_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_reg_prop
+ *
+ * Purpose: Initialize the object copy property list class
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register copy options property */
+ if(H5P_register_real(pclass, H5O_CPY_OPTION_NAME, H5O_CPY_OPTION_SIZE, &H5O_def_ocpy_option_g,
+ NULL, NULL, NULL, H5O_CPY_OPTION_ENC, H5O_CPY_OPTION_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register merge named dtype list property */
+ if(H5P_register_real(pclass, H5O_CPY_MERGE_COMM_DT_LIST_NAME, H5O_CPY_MERGE_COMM_DT_LIST_SIZE, &H5O_def_merge_comm_dtype_list_g,
+ NULL, H5O_CPY_MERGE_COMM_DT_LIST_SET, H5O_CPY_MERGE_COMM_DT_LIST_GET, H5O_CPY_MERGE_COMM_DT_LIST_ENC, H5O_CPY_MERGE_COMM_DT_LIST_DEC,
+ H5O_CPY_MERGE_COMM_DT_LIST_DEL, H5O_CPY_MERGE_COMM_DT_LIST_COPY, H5O_CPY_MERGE_COMM_DT_LIST_CMP, H5O_CPY_MERGE_COMM_DT_LIST_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for callback when completing the search for a matching named datatype from the named dtype list */
+ /* (Note: this property should not have an encode/decode callback -QAK) */
+ if(H5P_register_real(pclass, H5O_CPY_MCDT_SEARCH_CB_NAME, H5O_CPY_MCDT_SEARCH_CB_SIZE, &H5O_def_mcdt_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocpy_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__free_merge_comm_dtype_list
+ *
+ * Purpose: Frees the provided merge named dtype list
+ *
+ * Return: NULL
+ *
+ * Programmer: Neil Fortner
+ * October 27, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_copy_dtype_merge_list_t *
+H5P__free_merge_comm_dtype_list(H5O_copy_dtype_merge_list_t *dt_list)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Free the list */
+ while(dt_list) {
+ H5O_copy_dtype_merge_list_t *tmp_node;
+
+ tmp_node = dt_list->next;
+
+ (void)H5MM_xfree(dt_list->path);
+ (void)H5FL_FREE(H5O_copy_dtype_merge_list_t, dt_list);
+
+ dt_list = tmp_node;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(NULL);
+} /* H5P__free_merge_comm_dtype_list */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__copy_merge_comm_dt_list
+ *
+ * Purpose: Copy a merge committed datatype list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 2, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__copy_merge_comm_dt_list(H5O_copy_dtype_merge_list_t **value)
+{
+ const H5O_copy_dtype_merge_list_t *src_dt_list; /* Source merge named datatype lists */
+ H5O_copy_dtype_merge_list_t *dst_dt_list = NULL; /* Destination merge named datatype lists */
+ H5O_copy_dtype_merge_list_t *dst_dt_list_tail = NULL, *tmp_dt_list = NULL; /* temporary merge named datatype lists */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of merge committed dtype list */
+ src_dt_list = *value;
+ while(src_dt_list) {
+ /* Copy src_dt_list */
+ if(NULL == (tmp_dt_list = H5FL_CALLOC(H5O_copy_dtype_merge_list_t)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ if(NULL == (tmp_dt_list->path = H5MM_strdup(src_dt_list->path)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Add copied node to dest dtype list */
+ if(dst_dt_list_tail) {
+ dst_dt_list_tail->next = tmp_dt_list;
+ dst_dt_list_tail = tmp_dt_list;
+ } /* end if */
+ else {
+ dst_dt_list = tmp_dt_list;
+ dst_dt_list_tail = tmp_dt_list;
+ } /* end else */
+ tmp_dt_list = NULL;
+
+ /* Advance src_dt_list pointer */
+ src_dt_list = src_dt_list->next;
+ } /* end while */
+
+ /* Set the merge named dtype list property for the destination property list */
+ *value = dst_dt_list;
+
+done:
+ if(ret_value < 0) {
+ dst_dt_list = H5P__free_merge_comm_dtype_list(dst_dt_list);
+ if(tmp_dt_list) {
+ tmp_dt_list->path = (char *)H5MM_xfree(tmp_dt_list->path);
+ tmp_dt_list = H5FL_FREE(H5O_copy_dtype_merge_list_t, tmp_dt_list);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__copy_merge_comm_dt_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_set
+ *
+ * Purpose: Copies a merge committed datatype list property when it's set for a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of merge committed dtype list */
+ if(H5P__copy_merge_comm_dt_list((H5O_copy_dtype_merge_list_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy merge committed dtype list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocpy_merge_comm_dt_list_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_get
+ *
+ * Purpose: Copies a merge committed datatype list property when it's retrieved from a property list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, Sept 2, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of merge committed dtype list */
+ if(H5P__copy_merge_comm_dt_list((H5O_copy_dtype_merge_list_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy merge committed dtype list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocpy_merge_comm_dt_list_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_enc
+ *
+ * Purpose: Callback routine which is called whenever the common
+ * datatype property in the object copy property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5O_copy_dtype_merge_list_t * const *dt_list_ptr = (const H5O_copy_dtype_merge_list_t * const *)value;
+ uint8_t **pp = (uint8_t **)_pp;
+ const H5O_copy_dtype_merge_list_t *dt_list; /* Pointer to merge named datatype list */
+ size_t len; /* Length of path component */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(dt_list_ptr);
+ HDassert(size);
+
+ /* Iterate over merge committed dtype list */
+ dt_list = *dt_list_ptr;
+ while(dt_list) {
+ /* Get length of encoded path */
+ len = HDstrlen(dt_list->path) + 1;
+
+ /* Encode merge committed dtype list */
+ if(*pp) {
+ HDmemcpy(*(char **)pp, dt_list->path, len);
+ *pp += len;
+ } /* end if */
+
+ /* Increment the size of the buffer */
+ *size += len;
+
+ /* Advance to the next node */
+ dt_list = dt_list->next;
+ } /* end while */
+
+ /* Encode the terminator for the string sequence */
+ if(*pp)
+ *(*pp)++ = (uint8_t)'\0';
+
+ /* Account for the string sequence terminator */
+ *size += 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__ocpy_merge_comm_dt_list_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_dec
+ *
+ * Purpose: Callback routine which is called whenever the common
+ * datatype property in the dataset access property list is
+ * decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_dec(const void **_pp, void *_value)
+{
+ H5O_copy_dtype_merge_list_t **dt_list = (H5O_copy_dtype_merge_list_t **)_value; /* Pointer to merge named datatype list */
+ const uint8_t **pp = (const uint8_t **)_pp;
+ H5O_copy_dtype_merge_list_t *dt_list_tail = NULL, *tmp_dt_list = NULL; /* temporary merge named datatype lists */
+ size_t len; /* Length of path component */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(dt_list);
+
+ /* Start off with NULL (default value) */
+ *dt_list = NULL;
+
+ /* Decode the string sequence */
+ len = HDstrlen(*(const char **)pp);
+ while(len > 0) {
+ /* Create new node & duplicate string */
+ if(NULL == (tmp_dt_list = H5FL_CALLOC(H5O_copy_dtype_merge_list_t)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ if(NULL == (tmp_dt_list->path = H5MM_strdup(*(const char **)pp)))
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ *pp += len + 1;
+ HDassert(len == HDstrlen(tmp_dt_list->path));
+
+ /* Add copied node to dtype list */
+ if(dt_list_tail) {
+ dt_list_tail->next = tmp_dt_list;
+ dt_list_tail = tmp_dt_list;
+ } /* end if */
+ else {
+ *dt_list = tmp_dt_list;
+ dt_list_tail = tmp_dt_list;
+ } /* end else */
+ tmp_dt_list = NULL;
+
+ /* Compute length of next string */
+ len = HDstrlen(*(const char **)pp);
+ } /* end while */
+
+ /* Advance past terminator for string sequence */
+ *pp += 1;
+
+done:
+ if(ret_value < 0) {
+ *dt_list = H5P__free_merge_comm_dtype_list(*dt_list);
+ if(tmp_dt_list) {
+ tmp_dt_list->path = (char *)H5MM_xfree(tmp_dt_list->path);
+ tmp_dt_list = H5FL_FREE(H5O_copy_dtype_merge_list_t, tmp_dt_list);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P__ocpy_merge_comm_dt_list_dec() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_del
+ *
+ * Purpose: Frees memory used to store the merge committed datatype list property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 2, 2015
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
+ size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Free the merge named dtype list */
+ H5P__free_merge_comm_dtype_list(*(H5O_copy_dtype_merge_list_t **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__ocpy_merge_comm_dt_list_del() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_copy
+ *
+ * Purpose: Copy the merge committed datatype list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size,
+ void *value)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(value);
+
+ /* Make copy of merge committed dtype list */
+ if(H5P__copy_merge_comm_dt_list((H5O_copy_dtype_merge_list_t **)value) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy merge committed dtype list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocpy_merge_comm_dt_list_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_cmp
+ *
+ * Purpose: Callback routine which is called whenever the merge
+ * named dtype property in the object copy property list
+ * is compared.
+ *
+ * Return: positive if VALUE1 is greater than VALUE2, negative if
+ * VALUE2 is greater than VALUE1 and zero if VALUE1 and
+ * VALUE2 are equal.
+ *
+ * Programmer: Neil Fortner
+ * Friday, October 28, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5P__ocpy_merge_comm_dt_list_cmp(const void *_dt_list1, const void *_dt_list2,
+ size_t H5_ATTR_UNUSED size)
+{
+ const H5O_copy_dtype_merge_list_t *dt_list1 = *(H5O_copy_dtype_merge_list_t * const *)_dt_list1, /* Create local aliases for values */
+ *dt_list2 = *(H5O_copy_dtype_merge_list_t * const *)_dt_list2;
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(_dt_list1);
+ HDassert(_dt_list2);
+ HDassert(size == sizeof(H5O_copy_dtype_merge_list_t *));
+
+ /* Walk through the lists, comparing each path. For the lists to be the
+ * same, the paths must be in the same order. */
+ while(dt_list1 && dt_list2) {
+ HDassert(dt_list1->path);
+ HDassert(dt_list2->path);
+
+ /* Compare paths */
+ ret_value = HDstrcmp(dt_list1->path, dt_list2->path);
+ if(ret_value != 0) HGOTO_DONE(ret_value)
+
+ /* Advance to next node */
+ dt_list1 = dt_list1->next;
+ dt_list2 = dt_list2->next;
+ } /* end while */
+
+ /* Check if one list is longer than the other */
+ if(dt_list1) HGOTO_DONE(1)
+ if(dt_list2) HGOTO_DONE(-1)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__ocpy_merge_comm_dt_list_cmp() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5P__ocpy_merge_comm_dt_list_close
+ *
+ * Purpose: Close the merge common datatype list property
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5P__ocpy_merge_comm_dt_list_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(value);
+
+ /* Free the merge named dtype list */
+ H5P__free_merge_comm_dtype_list(*(H5O_copy_dtype_merge_list_t **)value);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__ocpy_merge_comm_dt_list_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_copy_object
+ *
+ * Purpose: Set properties when copying an object (group, dataset, and datatype)
+ * from one location to another
+ *
+ * Usage: H5Pset_copy_group(plist_id, cpy_option)
+ * hid_t plist_id; IN: Property list to copy object
+ * unsigned cpy_option; IN: Options to copy object such as
+ * H5O_COPY_SHALLOW_HIERARCHY_FLAG -- Copy only immediate members
+ * H5O_COPY_EXPAND_SOFT_LINK_FLAG -- Expand soft links into new objects/
+ * H5O_COPY_EXPAND_EXT_LINK_FLAG -- Expand external links into new objects
+ * H5O_COPY_EXPAND_REFERENCE_FLAG -- Copy objects that are pointed by references
+ * H5O_COPY_WITHOUT_ATTR_FLAG -- Copy object without copying attributes
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * March 13, 2006
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_copy_object(hid_t plist_id, unsigned cpy_option)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iIu", plist_id, cpy_option);
+
+ /* Check parameters */
+ if(cpy_option & ~H5O_COPY_ALL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown option specified")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set value */
+ if(H5P_set(plist, H5O_CPY_OPTION_NAME, &cpy_option) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set copy object flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_copy_object() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_copy_object
+ *
+ * Purpose: Returns the cpy_option, which is set for H5Ocopy(hid_t loc_id,
+ * const char* name, ... ) for copying objects
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * March 13, 2006
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_copy_object(hid_t plist_id, unsigned *cpy_option /*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, cpy_option);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(cpy_option)
+ if(H5P_get(plist, H5O_CPY_OPTION_NAME, cpy_option) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object copy flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_copy_object() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Padd_merge_committed_dtype_path
+ *
+ * Purpose: Adds path to the list of paths to search first in the
+ * target file when merging committed datatypes during H5Ocopy
+ * (i.e. when using the H5O_COPY_MERGE_COMMITTED_DTYPE_FLAG flag
+ * as set by H5Pset_copy_object). If the source named
+ * dataype is not found in the list of paths created by this
+ * function, the entire file will be searched.
+ *
+ * Usage: H5Padd_merge_committed_dtype_path(plist_id, path)
+ * hid_t plist_id; IN: Property list to copy object
+ * const char *path; IN: Path to add to list
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * October 27, 2011
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Padd_merge_committed_dtype_path(hid_t plist_id, const char *path)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_copy_dtype_merge_list_t *old_list; /* Merge committed dtype list currently present */
+ H5O_copy_dtype_merge_list_t *new_obj = NULL; /* New object to add to list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", plist_id, path);
+
+ /* Check parameters */
+ if(!path)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no path specified")
+ if(path[0] == '\0')
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "path is empty string")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get dtype list */
+ if(H5P_peek(plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &old_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get merge named dtype list")
+
+ /* Add the new path to the list */
+ if(NULL == (new_obj = H5FL_CALLOC(H5O_copy_dtype_merge_list_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (new_obj->path = H5MM_strdup(path)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ new_obj->next = old_list;
+
+ /* Update the list stored in the property list */
+ if(H5P_poke(plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &new_obj) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set merge named dtype list")
+
+done:
+ if(ret_value < 0)
+ if(new_obj) {
+ new_obj->path = (char *)H5MM_xfree(new_obj->path);
+ new_obj = H5FL_FREE(H5O_copy_dtype_merge_list_t, new_obj);
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Padd_merge_committed_dtype_path() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pfree_merge_committed_dtype_paths
+ *
+ * Purpose: Frees and clears the list of paths created by
+ * H5Padd_merge_committed_dtype_path. A new list may then be
+ * created by calling H5Padd_merge_committed_dtype_path again.
+ *
+ * Usage: H5Pfree_merge_committed_dtype_paths(plist_id)
+ * hid_t plist_id; IN: Property list to copy object
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * October 27, 2011
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pfree_merge_committed_dtype_paths(hid_t plist_id)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_copy_dtype_merge_list_t *dt_list; /* Merge committed dtype list currently present */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", plist_id);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get dtype list */
+ if(H5P_peek(plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &dt_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get merge committed dtype list")
+
+ /* Free dtype list */
+ dt_list = H5P__free_merge_comm_dtype_list(dt_list);
+
+ /* Update the list stored in the property list (to NULL) */
+ if(H5P_poke(plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &dt_list) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set merge committed dtype list")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pfree_merge_committed_dtype_paths() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_mcdt_search_cb
+ *
+ * Purpose: Set the callback function when a matching committed datatype is not found
+ * from the list of paths stored in the object copy property list.
+ * H5Ocopy will invoke this callback before searching all committed datatypes
+ * at destination.
+ *
+ * Usage: H5Pset_mcdt_search_cb(plist_id, H5O_mcdt_search_cb_t func, void *op_data)
+ * hid_t plist_id; IN: Property list to copy object
+ * H5O_mcdt_search_cb_t func; IN: The callback function
+ * void *op_data; IN: The user data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; November 28, 2011
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_mcdt_search_cb(hid_t plist_id, H5O_mcdt_search_cb_t func, void *op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_mcdt_cb_info_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", plist_id, func, op_data);
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && op_data)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Populate the callback info struct */
+ cb_info.func = func;
+ cb_info.user_data = op_data;
+
+ /* Set callback info */
+ if(H5P_set(plist, H5O_CPY_MCDT_SEARCH_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set callback info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_mcdt_search_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_mcdt_search_cb
+ *
+ * Purpose: Retrieves the callback function and user data from the specified
+ * object copy property list.
+ *
+ * Usage: H5Pget_mcdt_search_cb(plist_id, H5O_mcdt_search_cb_t *func, void **op_data)
+ * hid_t plist_id; IN: Property list to copy object
+ * H5O_mcdt_search_cb_t *func; OUT: The callback function
+ * void **op_data; OUT: The user data
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; November 29, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_mcdt_search_cb(hid_t plist_id, H5O_mcdt_search_cb_t *func, void **op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5O_mcdt_cb_info_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", plist_id, func, op_data);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get callback info */
+ if(H5P_get(plist, H5O_CPY_MCDT_SEARCH_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info")
+
+ if(func)
+ *func = cb_info.func;
+
+ if(op_data)
+ *op_data = cb_info.user_data;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_mcdt_search_cb() */
+
diff --git a/src/H5Ppkg.h b/src/H5Ppkg.h
new file mode 100644
index 0000000..13463ae
--- /dev/null
+++ b/src/H5Ppkg.h
@@ -0,0 +1,208 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Friday, November 16, 2001
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5P package. Source files outside the H5P package should
+ * include H5Pprivate.h instead.
+ */
+#if !(defined H5P_FRIEND || defined H5P_MODULE)
+#error "Do not include this file outside the H5P package!"
+#endif
+
+#ifndef _H5Ppkg_H
+#define _H5Ppkg_H
+
+/* Get package's private header */
+#include "H5Pprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5SLprivate.h" /* Skip lists */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+/* Define enum for type of object that property is within */
+typedef enum {
+ H5P_PROP_WITHIN_UNKNOWN=0, /* Property container is unknown */
+ H5P_PROP_WITHIN_LIST, /* Property is within a list */
+ H5P_PROP_WITHIN_CLASS /* Property is within a class */
+} H5P_prop_within_t;
+
+/* Define enum for modifications to class */
+typedef enum {
+ H5P_MOD_ERR=(-1), /* Indicate an error */
+ H5P_MOD_INC_CLS, /* Increment the dependant class count*/
+ H5P_MOD_DEC_CLS, /* Decrement the dependant class count*/
+ H5P_MOD_INC_LST, /* Increment the dependant list count*/
+ H5P_MOD_DEC_LST, /* Decrement the dependant list count*/
+ H5P_MOD_INC_REF, /* Increment the ID reference count*/
+ H5P_MOD_DEC_REF, /* Decrement the ID reference count*/
+ H5P_MOD_MAX /* Upper limit on class modifications */
+} H5P_class_mod_t;
+
+/* Define structure to hold property information */
+typedef struct H5P_genprop_t {
+ /* Values for this property */
+ char *name; /* Name of property */
+ size_t size; /* Size of property value */
+ void *value; /* Pointer to property value */
+ H5P_prop_within_t type; /* Type of object the property is within */
+ hbool_t shared_name; /* Whether the name is shared or not */
+
+ /* Callback function pointers & info */
+ H5P_prp_create_func_t create; /* Function to call when a property is created */
+ H5P_prp_set_func_t set; /* Function to call when a property value is set */
+ H5P_prp_get_func_t get; /* Function to call when a property value is retrieved */
+ H5P_prp_encode_func_t encode; /* Function to call when a property is encoded */
+ H5P_prp_decode_func_t decode; /* Function to call when a property is decoded */
+ H5P_prp_delete_func_t del; /* Function to call when a property is deleted */
+ H5P_prp_copy_func_t copy; /* Function to call when a property is copied */
+ H5P_prp_compare_func_t cmp; /* Function to call when a property is compared */
+ H5P_prp_close_func_t close; /* Function to call when a property is closed */
+} H5P_genprop_t;
+
+/* Define structure to hold class information */
+struct H5P_genclass_t {
+ struct H5P_genclass_t *parent; /* Pointer to parent class */
+ char *name; /* Name of property list class */
+ H5P_plist_type_t type; /* Type of property */
+ size_t nprops; /* Number of properties in class */
+ unsigned plists; /* Number of property lists that have been created since the last modification to the class */
+ unsigned classes; /* Number of classes that have been derived since the last modification to the class */
+ unsigned ref_count; /* Number of oustanding ID's open on this class object */
+ hbool_t deleted; /* Whether this class has been deleted and is waiting for dependent classes & proplists to close */
+ unsigned revision; /* Revision number of a particular class (global) */
+ H5SL_t *props; /* Skip list containing properties */
+
+ /* Callback function pointers & info */
+ H5P_cls_create_func_t create_func; /* Function to call when a property list is created */
+ void *create_data; /* Pointer to user data to pass along to create callback */
+ H5P_cls_copy_func_t copy_func; /* Function to call when a property list is copied */
+ void *copy_data; /* Pointer to user data to pass along to copy callback */
+ H5P_cls_close_func_t close_func; /* Function to call when a property list is closed */
+ void *close_data; /* Pointer to user data to pass along to close callback */
+};
+
+/* Define structure to hold property list information */
+struct H5P_genplist_t {
+ H5P_genclass_t *pclass; /* Pointer to class info */
+ hid_t plist_id; /* Copy of the property list ID (for use in close callback) */
+ size_t nprops; /* Number of properties in class */
+ hbool_t class_init; /* Whether the class initialization callback finished successfully */
+ H5SL_t *del; /* Skip list containing names of deleted properties */
+ H5SL_t *props; /* Skip list containing properties */
+};
+
+/* Property list/class iterator callback function pointer */
+typedef int (*H5P_iterate_int_t)(H5P_genprop_t *prop, void *udata);
+
+/* Forward declarations (for prototypes & struct definitions) */
+struct H5Z_filter_info_t;
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* Private functions, not part of the publicly documented API */
+H5_DLL H5P_genclass_t *H5P_create_class(H5P_genclass_t *par_class,
+ const char *name, H5P_plist_type_t type,
+ H5P_cls_create_func_t cls_create, void *create_data,
+ H5P_cls_copy_func_t cls_copy, void *copy_data,
+ H5P_cls_close_func_t cls_close, void *close_data);
+H5_DLL H5P_genclass_t *H5P_copy_pclass(H5P_genclass_t *pclass);
+H5_DLL herr_t H5P_register_real(H5P_genclass_t *pclass, const char *name, size_t size,
+ const void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5P_register(H5P_genclass_t **pclass, const char *name, size_t size,
+ const void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete,
+ H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp,
+ H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5P_add_prop(H5SL_t *props, H5P_genprop_t *prop);
+H5_DLL herr_t H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod);
+H5_DLL htri_t H5P_exist_pclass(H5P_genclass_t *pclass, const char *name);
+H5_DLL herr_t H5P_get_size_plist(const H5P_genplist_t *plist, const char *name,
+ size_t *size);
+H5_DLL herr_t H5P_get_size_pclass(H5P_genclass_t *pclass, const char *name,
+ size_t *size);
+H5_DLL herr_t H5P_get_nprops_plist(const H5P_genplist_t *plist, size_t *nprops);
+H5_DLL int H5P_cmp_class(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2);
+H5_DLL herr_t H5P_cmp_plist(const H5P_genplist_t *plist1, const H5P_genplist_t *plist2,
+ int *cmp_ret);
+H5_DLL int H5P_iterate_plist(const H5P_genplist_t *plist, hbool_t iter_all_prop,
+ int *idx, H5P_iterate_int_t iter_func, void *iter_data);
+H5_DLL int H5P_iterate_pclass(const H5P_genclass_t *pclass, int *idx,
+ H5P_iterate_int_t iter_func, void *iter_data);
+H5_DLL herr_t H5P_copy_prop_plist(hid_t dst_id, hid_t src_id, const char *name);
+H5_DLL herr_t H5P_copy_prop_pclass(hid_t dst_id, hid_t src_id, const char *name);
+H5_DLL herr_t H5P_unregister(H5P_genclass_t *pclass, const char *name);
+H5_DLL char *H5P_get_class_path(H5P_genclass_t *pclass);
+H5_DLL H5P_genclass_t *H5P_open_class_path(const char *path);
+H5_DLL H5P_genclass_t *H5P_get_class_parent(const H5P_genclass_t *pclass);
+H5_DLL herr_t H5P_close_class(void *_pclass);
+H5_DLL H5P_genprop_t *H5P__find_prop_plist(const H5P_genplist_t *plist, const char *name);
+H5_DLL hid_t H5P__new_plist_of_type(H5P_plist_type_t type);
+
+/* Encode/decode routines */
+H5_DLL herr_t H5P__encode(const H5P_genplist_t *plist, hbool_t enc_all_prop,
+ void *buf, size_t *nalloc);
+H5_DLL hid_t H5P__decode(const void *buf);
+H5_DLL herr_t H5P__encode_hsize_t(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__encode_size_t(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__encode_unsigned(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__encode_uint8_t(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__encode_hbool_t(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__encode_double(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__decode_hsize_t(const void **_pp, void *value);
+H5_DLL herr_t H5P__decode_size_t(const void **_pp, void *value);
+H5_DLL herr_t H5P__decode_unsigned(const void **_pp, void *value);
+H5_DLL herr_t H5P__decode_uint8_t(const void **_pp, void *value);
+H5_DLL herr_t H5P__decode_hbool_t(const void **_pp, void *value);
+H5_DLL herr_t H5P__decode_double(const void **_pp, void *value);
+H5_DLL herr_t H5P__encode_coll_md_read_flag_t(const void *value, void **_pp, size_t *size);
+H5_DLL herr_t H5P__decode_coll_md_read_flag_t(const void **_pp, void *value);
+
+/* Private OCPL routines */
+H5_DLL herr_t H5P_get_filter(const struct H5Z_filter_info_t *filter,
+ unsigned int *flags, size_t *cd_nelmts, unsigned cd_values[],
+ size_t namelen, char name[], unsigned *filter_config);
+
+/* Testing functions */
+#ifdef H5P_TESTING
+H5_DLL char *H5P_get_class_path_test(hid_t pclass_id);
+H5_DLL hid_t H5P_open_class_path_test(const char *path);
+#endif /* H5P_TESTING */
+
+#endif /* _H5Ppkg_H */
+
diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h
new file mode 100644
index 0000000..a468464
--- /dev/null
+++ b/src/H5Pprivate.h
@@ -0,0 +1,207 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5P module
+ */
+#ifndef _H5Pprivate_H
+#define _H5Pprivate_H
+
+/* Include package's public header */
+#include "H5Ppublic.h"
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* ======== String creation property names ======== */
+#define H5P_STRCRT_CHAR_ENCODING_NAME "character_encoding" /* Character set encoding for string */
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5P_MODULE
+#define H5P_PLIST_ID(P) ((P)->plist_id)
+#define H5P_CLASS(P) ((P)->pclass)
+#else /* H5P_MODULE */
+#define H5P_PLIST_ID(P) (H5P_get_plist_id(P))
+#define H5P_CLASS(P) (H5P_get_class(P))
+#endif /* H5P_MODULE */
+
+#define H5_COLL_MD_READ_FLAG_NAME "collective_metadata_read"
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+typedef enum H5P_coll_md_read_flag_t {
+ H5P_FORCE_FALSE = -1,
+ H5P_USER_FALSE = 0,
+ H5P_USER_TRUE = 1
+} H5P_coll_md_read_flag_t;
+
+/* Forward declarations (for prototypes & type definitions) */
+struct H5O_fill_t;
+struct H5T_t;
+
+/* Forward declarations for anonymous H5P objects */
+typedef struct H5P_genplist_t H5P_genplist_t;
+typedef struct H5P_genclass_t H5P_genclass_t;
+
+typedef enum H5P_plist_type_t {
+ H5P_TYPE_USER = 0,
+ H5P_TYPE_ROOT = 1,
+ H5P_TYPE_OBJECT_CREATE = 2,
+ H5P_TYPE_FILE_CREATE = 3,
+ H5P_TYPE_FILE_ACCESS = 4,
+ H5P_TYPE_DATASET_CREATE = 5,
+ H5P_TYPE_DATASET_ACCESS = 6,
+ H5P_TYPE_DATASET_XFER = 7,
+ H5P_TYPE_FILE_MOUNT = 8,
+ H5P_TYPE_GROUP_CREATE = 9,
+ H5P_TYPE_GROUP_ACCESS = 10,
+ H5P_TYPE_DATATYPE_CREATE = 11,
+ H5P_TYPE_DATATYPE_ACCESS = 12,
+ H5P_TYPE_STRING_CREATE = 13,
+ H5P_TYPE_ATTRIBUTE_CREATE = 14,
+ H5P_TYPE_OBJECT_COPY = 15,
+ H5P_TYPE_LINK_CREATE = 16,
+ H5P_TYPE_LINK_ACCESS = 17,
+ H5P_TYPE_ATTRIBUTE_ACCESS = 18,
+ H5P_TYPE_MAX_TYPE
+} H5P_plist_type_t;
+
+/* Function pointer for library classes with properties to register */
+typedef herr_t (*H5P_reg_prop_func_t)(H5P_genclass_t *pclass);
+
+/*
+ * Each library property list class has a variable of this type that contains
+ * class variables and methods used to initialize the class.
+ */
+typedef struct H5P_libclass_t {
+ const char *name; /* Class name */
+ H5P_plist_type_t type; /* Class type */
+
+ H5P_genclass_t * * par_pclass; /* Pointer to global parent class property list class */
+ H5P_genclass_t * * pclass; /* Pointer to global property list class */
+ hid_t * const class_id; /* Pointer to global property list class ID */
+ hid_t * const def_plist_id; /* Pointer to global default property list ID */
+ H5P_reg_prop_func_t reg_prop_func; /* Register class's properties */
+
+ /* Class callback function pointers & info */
+ H5P_cls_create_func_t create_func; /* Function to call when a property list is created */
+ void *create_data; /* Pointer to user data to pass along to create callback */
+ H5P_cls_copy_func_t copy_func; /* Function to call when a property list is copied */
+ void *copy_data; /* Pointer to user data to pass along to copy callback */
+ H5P_cls_close_func_t close_func; /* Function to call when a property list is closed */
+ void *close_data; /* Pointer to user data to pass along to close callback */
+} H5P_libclass_t;
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* Predefined property list classes. */
+H5_DLLVAR H5P_genclass_t *H5P_CLS_ROOT_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_OBJECT_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_FILE_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_FILE_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_DATASET_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_DATASET_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_DATASET_XFER_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_FILE_MOUNT_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_GROUP_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_GROUP_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_DATATYPE_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_DATATYPE_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_ATTRIBUTE_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_ATTRIBUTE_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_OBJECT_COPY_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_LINK_CREATE_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_LINK_ACCESS_g;
+H5_DLLVAR H5P_genclass_t *H5P_CLS_STRING_CREATE_g;
+
+/* Internal property list classes */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_LACC[1]; /* Link access */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_AACC[1]; /* Attribute access */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_DACC[1]; /* Dataset access */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_GACC[1]; /* Group access */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_TACC[1]; /* Named datatype access */
+H5_DLLVAR const struct H5P_libclass_t H5P_CLS_FACC[1]; /* File access */
+
+/******************************/
+/* Library Private Prototypes */
+/******************************/
+
+/* Package initialization routine */
+H5_DLL herr_t H5P_init(void);
+
+/* Internal versions of API routines */
+H5_DLL herr_t H5P_close(void *_plist);
+H5_DLL hid_t H5P_create_id(H5P_genclass_t *pclass, hbool_t app_ref);
+H5_DLL hid_t H5P_copy_plist(const H5P_genplist_t *old_plist, hbool_t app_ref);
+H5_DLL herr_t H5P_get(H5P_genplist_t *plist, const char *name, void *value);
+H5_DLL herr_t H5P_set(H5P_genplist_t *plist, const char *name, const void *value);
+H5_DLL herr_t H5P_peek(H5P_genplist_t *plist, const char *name, void *value);
+H5_DLL herr_t H5P_poke(H5P_genplist_t *plist, const char *name, const void *value);
+H5_DLL herr_t H5P_insert(H5P_genplist_t *plist, const char *name, size_t size,
+ void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_encode_func_t prp_encode, H5P_prp_decode_func_t prp_decode,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5P_remove(H5P_genplist_t *plist, const char *name);
+H5_DLL htri_t H5P_exist_plist(const H5P_genplist_t *plist, const char *name);
+H5_DLL htri_t H5P_class_isa(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2);
+H5_DLL char *H5P_get_class_name(H5P_genclass_t *pclass);
+
+/* Internal helper routines */
+H5_DLL herr_t H5P_get_nprops_pclass(const H5P_genclass_t *pclass, size_t *nprops,
+ hbool_t recurse);
+H5_DLL hid_t H5P_peek_driver(H5P_genplist_t *plist);
+H5_DLL const void *H5P_peek_driver_info(H5P_genplist_t *plist);
+H5_DLL herr_t H5P_set_driver(H5P_genplist_t *plist, hid_t new_driver_id,
+ const void *new_driver_info);
+H5_DLL herr_t H5P_set_vlen_mem_manager(H5P_genplist_t *plist,
+ H5MM_allocate_t alloc_func, void *alloc_info, H5MM_free_t free_func,
+ void *free_info);
+H5_DLL herr_t H5P_is_fill_value_defined(const struct H5O_fill_t *fill,
+ H5D_fill_value_t *status);
+H5_DLL int H5P_fill_value_cmp(const void *value1, const void *value2,
+ size_t size);
+H5_DLL herr_t H5P_modify_filter(H5P_genplist_t *plist, H5Z_filter_t filter,
+ unsigned flags, size_t cd_nelmts, const unsigned cd_values[]);
+H5_DLL herr_t H5P_get_filter_by_id(H5P_genplist_t *plist, H5Z_filter_t id,
+ unsigned int *flags, size_t *cd_nelmts, unsigned cd_values[],
+ size_t namelen, char name[], unsigned *filter_config);
+H5_DLL htri_t H5P_filter_in_pline(H5P_genplist_t *plist, H5Z_filter_t id);
+H5_DLL herr_t H5P_verify_apl_and_dxpl(hid_t *acspl_id, const H5P_libclass_t *libclass,
+ hid_t *dxpl_id, hid_t loc_id, hbool_t is_collective);
+
+/* Query internal fields of the property list struct */
+H5_DLL hid_t H5P_get_plist_id(const H5P_genplist_t *plist);
+H5_DLL H5P_genclass_t *H5P_get_class(const H5P_genplist_t *plist);
+
+/* *SPECIAL* Don't make more of these! -QAK */
+H5_DLL htri_t H5P_isa_class(hid_t plist_id, hid_t pclass_id);
+H5_DLL H5P_genplist_t *H5P_object_verify(hid_t plist_id, hid_t pclass_id);
+
+/* Private DCPL routines */
+H5_DLL herr_t H5P_fill_value_defined(H5P_genplist_t *plist,
+ H5D_fill_value_t *status);
+H5_DLL herr_t H5P_get_fill_value(H5P_genplist_t *plist, const struct H5T_t *type,
+ void *value, hid_t dxpl_id);
+
+#endif /* _H5Pprivate_H */
+
diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h
new file mode 100644
index 0000000..55b3877
--- /dev/null
+++ b/src/H5Ppublic.h
@@ -0,0 +1,547 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains function prototypes for each exported function in the
+ * H5P module.
+ */
+#ifndef _H5Ppublic_H
+#define _H5Ppublic_H
+
+/* System headers needed by this file */
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5ACpublic.h"
+#include "H5Dpublic.h"
+#include "H5Fpublic.h"
+#include "H5FDpublic.h"
+#include "H5Ipublic.h"
+#include "H5Lpublic.h"
+#include "H5Opublic.h"
+#include "H5MMpublic.h"
+#include "H5Tpublic.h"
+#include "H5Zpublic.h"
+
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* When this header is included from a private HDF5 header, don't make calls to H5open() */
+#undef H5OPEN
+#ifndef _H5private_H
+#define H5OPEN H5open(),
+#else /* _H5private_H */
+#define H5OPEN
+#endif /* _H5private_H */
+
+/*
+ * The library's property list classes
+ */
+
+#define H5P_ROOT (H5OPEN H5P_CLS_ROOT_ID_g)
+#define H5P_OBJECT_CREATE (H5OPEN H5P_CLS_OBJECT_CREATE_ID_g)
+#define H5P_FILE_CREATE (H5OPEN H5P_CLS_FILE_CREATE_ID_g)
+#define H5P_FILE_ACCESS (H5OPEN H5P_CLS_FILE_ACCESS_ID_g)
+#define H5P_DATASET_CREATE (H5OPEN H5P_CLS_DATASET_CREATE_ID_g)
+#define H5P_DATASET_ACCESS (H5OPEN H5P_CLS_DATASET_ACCESS_ID_g)
+#define H5P_DATASET_XFER (H5OPEN H5P_CLS_DATASET_XFER_ID_g)
+#define H5P_FILE_MOUNT (H5OPEN H5P_CLS_FILE_MOUNT_ID_g)
+#define H5P_GROUP_CREATE (H5OPEN H5P_CLS_GROUP_CREATE_ID_g)
+#define H5P_GROUP_ACCESS (H5OPEN H5P_CLS_GROUP_ACCESS_ID_g)
+#define H5P_DATATYPE_CREATE (H5OPEN H5P_CLS_DATATYPE_CREATE_ID_g)
+#define H5P_DATATYPE_ACCESS (H5OPEN H5P_CLS_DATATYPE_ACCESS_ID_g)
+#define H5P_STRING_CREATE (H5OPEN H5P_CLS_STRING_CREATE_ID_g)
+#define H5P_ATTRIBUTE_CREATE (H5OPEN H5P_CLS_ATTRIBUTE_CREATE_ID_g)
+#define H5P_ATTRIBUTE_ACCESS (H5OPEN H5P_CLS_ATTRIBUTE_ACCESS_ID_g)
+#define H5P_OBJECT_COPY (H5OPEN H5P_CLS_OBJECT_COPY_ID_g)
+#define H5P_LINK_CREATE (H5OPEN H5P_CLS_LINK_CREATE_ID_g)
+#define H5P_LINK_ACCESS (H5OPEN H5P_CLS_LINK_ACCESS_ID_g)
+
+/*
+ * The library's default property lists
+ */
+#define H5P_FILE_CREATE_DEFAULT (H5OPEN H5P_LST_FILE_CREATE_ID_g)
+#define H5P_FILE_ACCESS_DEFAULT (H5OPEN H5P_LST_FILE_ACCESS_ID_g)
+#define H5P_DATASET_CREATE_DEFAULT (H5OPEN H5P_LST_DATASET_CREATE_ID_g)
+#define H5P_DATASET_ACCESS_DEFAULT (H5OPEN H5P_LST_DATASET_ACCESS_ID_g)
+#define H5P_DATASET_XFER_DEFAULT (H5OPEN H5P_LST_DATASET_XFER_ID_g)
+#define H5P_FILE_MOUNT_DEFAULT (H5OPEN H5P_LST_FILE_MOUNT_ID_g)
+#define H5P_GROUP_CREATE_DEFAULT (H5OPEN H5P_LST_GROUP_CREATE_ID_g)
+#define H5P_GROUP_ACCESS_DEFAULT (H5OPEN H5P_LST_GROUP_ACCESS_ID_g)
+#define H5P_DATATYPE_CREATE_DEFAULT (H5OPEN H5P_LST_DATATYPE_CREATE_ID_g)
+#define H5P_DATATYPE_ACCESS_DEFAULT (H5OPEN H5P_LST_DATATYPE_ACCESS_ID_g)
+#define H5P_ATTRIBUTE_CREATE_DEFAULT (H5OPEN H5P_LST_ATTRIBUTE_CREATE_ID_g)
+#define H5P_ATTRIBUTE_ACCESS_DEFAULT (H5OPEN H5P_LST_ATTRIBUTE_ACCESS_ID_g)
+#define H5P_OBJECT_COPY_DEFAULT (H5OPEN H5P_LST_OBJECT_COPY_ID_g)
+#define H5P_LINK_CREATE_DEFAULT (H5OPEN H5P_LST_LINK_CREATE_ID_g)
+#define H5P_LINK_ACCESS_DEFAULT (H5OPEN H5P_LST_LINK_ACCESS_ID_g)
+
+/* Common creation order flags (for links in groups and attributes on objects) */
+#define H5P_CRT_ORDER_TRACKED 0x0001
+#define H5P_CRT_ORDER_INDEXED 0x0002
+
+/* Default value for all property list classes */
+#define H5P_DEFAULT (hid_t)0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************/
+/* Public Typedefs */
+/*******************/
+
+
+/* Define property list class callback function pointer types */
+typedef herr_t (*H5P_cls_create_func_t)(hid_t prop_id, void *create_data);
+typedef herr_t (*H5P_cls_copy_func_t)(hid_t new_prop_id, hid_t old_prop_id,
+ void *copy_data);
+typedef herr_t (*H5P_cls_close_func_t)(hid_t prop_id, void *close_data);
+
+/* Define property list callback function pointer types */
+typedef herr_t (*H5P_prp_cb1_t)(const char *name, size_t size, void *value);
+typedef herr_t (*H5P_prp_cb2_t)(hid_t prop_id, const char *name, size_t size, void *value);
+typedef H5P_prp_cb1_t H5P_prp_create_func_t;
+typedef H5P_prp_cb2_t H5P_prp_set_func_t;
+typedef H5P_prp_cb2_t H5P_prp_get_func_t;
+typedef herr_t (*H5P_prp_encode_func_t)(const void *value, void **buf, size_t *size);
+typedef herr_t (*H5P_prp_decode_func_t)(const void **buf, void *value);
+typedef H5P_prp_cb2_t H5P_prp_delete_func_t;
+typedef H5P_prp_cb1_t H5P_prp_copy_func_t;
+typedef int (*H5P_prp_compare_func_t)(const void *value1, const void *value2, size_t size);
+typedef H5P_prp_cb1_t H5P_prp_close_func_t;
+
+/* Define property list iteration function type */
+typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data);
+
+/* Actual IO mode property */
+typedef enum H5D_mpio_actual_chunk_opt_mode_t {
+ /* The default value, H5D_MPIO_NO_CHUNK_OPTIMIZATION, is used for all I/O
+ * operations that do not use chunk optimizations, including non-collective
+ * I/O and contiguous collective I/O.
+ */
+ H5D_MPIO_NO_CHUNK_OPTIMIZATION = 0,
+ H5D_MPIO_LINK_CHUNK,
+ H5D_MPIO_MULTI_CHUNK
+} H5D_mpio_actual_chunk_opt_mode_t;
+
+typedef enum H5D_mpio_actual_io_mode_t {
+ /* The following four values are conveniently defined as a bit field so that
+ * we can switch from the default to indpendent or collective and then to
+ * mixed without having to check the original value.
+ *
+ * NO_COLLECTIVE means that either collective I/O wasn't requested or that
+ * no I/O took place.
+ *
+ * CHUNK_INDEPENDENT means that collective I/O was requested, but the
+ * chunk optimization scheme chose independent I/O for each chunk.
+ */
+ H5D_MPIO_NO_COLLECTIVE = 0x0,
+ H5D_MPIO_CHUNK_INDEPENDENT = 0x1,
+ H5D_MPIO_CHUNK_COLLECTIVE = 0x2,
+ H5D_MPIO_CHUNK_MIXED = 0x1 | 0x2,
+
+ /* The contiguous case is separate from the bit field. */
+ H5D_MPIO_CONTIGUOUS_COLLECTIVE = 0x4
+} H5D_mpio_actual_io_mode_t;
+
+/* Broken collective IO property */
+typedef enum H5D_mpio_no_collective_cause_t {
+ H5D_MPIO_COLLECTIVE = 0x00,
+ H5D_MPIO_SET_INDEPENDENT = 0x01,
+ H5D_MPIO_DATATYPE_CONVERSION = 0x02,
+ H5D_MPIO_DATA_TRANSFORMS = 0x04,
+ H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED = 0x08,
+ H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES = 0x10,
+ H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET = 0x20,
+ H5D_MPIO_FILTERS = 0x40
+} H5D_mpio_no_collective_cause_t;
+
+/********************/
+/* Public Variables */
+/********************/
+
+/* Property list class IDs */
+/* (Internal to library, do not use! Use macros above) */
+H5_DLLVAR hid_t H5P_CLS_ROOT_ID_g;
+H5_DLLVAR hid_t H5P_CLS_OBJECT_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_FILE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_FILE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_CLS_DATASET_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_DATASET_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_CLS_DATASET_XFER_ID_g;
+H5_DLLVAR hid_t H5P_CLS_FILE_MOUNT_ID_g;
+H5_DLLVAR hid_t H5P_CLS_GROUP_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_GROUP_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_CLS_DATATYPE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_DATATYPE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_CLS_STRING_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_ATTRIBUTE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_ATTRIBUTE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_CLS_OBJECT_COPY_ID_g;
+H5_DLLVAR hid_t H5P_CLS_LINK_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_CLS_LINK_ACCESS_ID_g;
+
+/* Default roperty list IDs */
+/* (Internal to library, do not use! Use macros above) */
+H5_DLLVAR hid_t H5P_LST_FILE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_FILE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_LST_DATASET_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_DATASET_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_LST_DATASET_XFER_ID_g;
+H5_DLLVAR hid_t H5P_LST_FILE_MOUNT_ID_g;
+H5_DLLVAR hid_t H5P_LST_GROUP_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_GROUP_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_LST_DATATYPE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_DATATYPE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_LST_ATTRIBUTE_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_ATTRIBUTE_ACCESS_ID_g;
+H5_DLLVAR hid_t H5P_LST_OBJECT_COPY_ID_g;
+H5_DLLVAR hid_t H5P_LST_LINK_CREATE_ID_g;
+H5_DLLVAR hid_t H5P_LST_LINK_ACCESS_ID_g;
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+/* Generic property list routines */
+H5_DLL hid_t H5Pcreate_class(hid_t parent, const char *name,
+ H5P_cls_create_func_t cls_create, void *create_data,
+ H5P_cls_copy_func_t cls_copy, void *copy_data,
+ H5P_cls_close_func_t cls_close, void *close_data);
+H5_DLL char *H5Pget_class_name(hid_t pclass_id);
+H5_DLL hid_t H5Pcreate(hid_t cls_id);
+H5_DLL herr_t H5Pregister2(hid_t cls_id, const char *name, size_t size,
+ void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_del, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5Pinsert2(hid_t plist_id, const char *name, size_t size,
+ void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5Pset(hid_t plist_id, const char *name, const void *value);
+H5_DLL htri_t H5Pexist(hid_t plist_id, const char *name);
+H5_DLL herr_t H5Pencode(hid_t plist_id, void *buf, size_t *nalloc);
+H5_DLL hid_t H5Pdecode(const void *buf);
+H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size);
+H5_DLL herr_t H5Pget_nprops(hid_t id, size_t *nprops);
+H5_DLL hid_t H5Pget_class(hid_t plist_id);
+H5_DLL hid_t H5Pget_class_parent(hid_t pclass_id);
+H5_DLL herr_t H5Pget(hid_t plist_id, const char *name, void * value);
+H5_DLL htri_t H5Pequal(hid_t id1, hid_t id2);
+H5_DLL htri_t H5Pisa_class(hid_t plist_id, hid_t pclass_id);
+H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func,
+ void *iter_data);
+H5_DLL herr_t H5Pcopy_prop(hid_t dst_id, hid_t src_id, const char *name);
+H5_DLL herr_t H5Premove(hid_t plist_id, const char *name);
+H5_DLL herr_t H5Punregister(hid_t pclass_id, const char *name);
+H5_DLL herr_t H5Pclose_class(hid_t plist_id);
+H5_DLL herr_t H5Pclose(hid_t plist_id);
+H5_DLL hid_t H5Pcopy(hid_t plist_id);
+
+/* Object creation property list (OCPL) routines */
+H5_DLL herr_t H5Pset_attr_phase_change(hid_t plist_id, unsigned max_compact, unsigned min_dense);
+H5_DLL herr_t H5Pget_attr_phase_change(hid_t plist_id, unsigned *max_compact, unsigned *min_dense);
+H5_DLL herr_t H5Pset_attr_creation_order(hid_t plist_id, unsigned crt_order_flags);
+H5_DLL herr_t H5Pget_attr_creation_order(hid_t plist_id, unsigned *crt_order_flags);
+H5_DLL herr_t H5Pset_obj_track_times(hid_t plist_id, hbool_t track_times);
+H5_DLL herr_t H5Pget_obj_track_times(hid_t plist_id, hbool_t *track_times);
+H5_DLL herr_t H5Pmodify_filter(hid_t plist_id, H5Z_filter_t filter,
+ unsigned int flags, size_t cd_nelmts,
+ const unsigned int cd_values[/*cd_nelmts*/]);
+H5_DLL herr_t H5Pset_filter(hid_t plist_id, H5Z_filter_t filter,
+ unsigned int flags, size_t cd_nelmts,
+ const unsigned int c_values[]);
+H5_DLL int H5Pget_nfilters(hid_t plist_id);
+H5_DLL H5Z_filter_t H5Pget_filter2(hid_t plist_id, unsigned filter,
+ unsigned int *flags/*out*/,
+ size_t *cd_nelmts/*out*/,
+ unsigned cd_values[]/*out*/,
+ size_t namelen, char name[],
+ unsigned *filter_config /*out*/);
+H5_DLL herr_t H5Pget_filter_by_id2(hid_t plist_id, H5Z_filter_t id,
+ unsigned int *flags/*out*/, size_t *cd_nelmts/*out*/,
+ unsigned cd_values[]/*out*/, size_t namelen, char name[]/*out*/,
+ unsigned *filter_config/*out*/);
+H5_DLL htri_t H5Pall_filters_avail(hid_t plist_id);
+H5_DLL herr_t H5Premove_filter(hid_t plist_id, H5Z_filter_t filter);
+H5_DLL herr_t H5Pset_deflate(hid_t plist_id, unsigned aggression);
+H5_DLL herr_t H5Pset_fletcher32(hid_t plist_id);
+
+/* File creation property list (FCPL) routines */
+H5_DLL herr_t H5Pset_userblock(hid_t plist_id, hsize_t size);
+H5_DLL herr_t H5Pget_userblock(hid_t plist_id, hsize_t *size);
+H5_DLL herr_t H5Pset_sizes(hid_t plist_id, size_t sizeof_addr,
+ size_t sizeof_size);
+H5_DLL herr_t H5Pget_sizes(hid_t plist_id, size_t *sizeof_addr/*out*/,
+ size_t *sizeof_size/*out*/);
+H5_DLL herr_t H5Pset_sym_k(hid_t plist_id, unsigned ik, unsigned lk);
+H5_DLL herr_t H5Pget_sym_k(hid_t plist_id, unsigned *ik/*out*/, unsigned *lk/*out*/);
+H5_DLL herr_t H5Pset_istore_k(hid_t plist_id, unsigned ik);
+H5_DLL herr_t H5Pget_istore_k(hid_t plist_id, unsigned *ik/*out*/);
+H5_DLL herr_t H5Pset_shared_mesg_nindexes(hid_t plist_id, unsigned nindexes);
+H5_DLL herr_t H5Pget_shared_mesg_nindexes(hid_t plist_id, unsigned *nindexes);
+H5_DLL herr_t H5Pset_shared_mesg_index(hid_t plist_id, unsigned index_num, unsigned mesg_type_flags, unsigned min_mesg_size);
+H5_DLL herr_t H5Pget_shared_mesg_index(hid_t plist_id, unsigned index_num, unsigned *mesg_type_flags, unsigned *min_mesg_size);
+H5_DLL herr_t H5Pset_shared_mesg_phase_change(hid_t plist_id, unsigned max_list, unsigned min_btree);
+H5_DLL herr_t H5Pget_shared_mesg_phase_change(hid_t plist_id, unsigned *max_list, unsigned *min_btree);
+H5_DLL herr_t H5Pset_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t strategy, hbool_t persist, hsize_t threshold);
+H5_DLL herr_t H5Pget_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t *strategy, hbool_t *persist, hsize_t *threshold);
+H5_DLL herr_t H5Pset_file_space_page_size(hid_t plist_id, hsize_t fsp_size);
+H5_DLL herr_t H5Pget_file_space_page_size(hid_t plist_id, hsize_t *fsp_size);
+
+/* File access property list (FAPL) routines */
+H5_DLL herr_t H5Pset_alignment(hid_t fapl_id, hsize_t threshold,
+ hsize_t alignment);
+H5_DLL herr_t H5Pget_alignment(hid_t fapl_id, hsize_t *threshold/*out*/,
+ hsize_t *alignment/*out*/);
+H5_DLL herr_t H5Pset_driver(hid_t plist_id, hid_t driver_id,
+ const void *driver_info);
+H5_DLL hid_t H5Pget_driver(hid_t plist_id);
+H5_DLL const void *H5Pget_driver_info(hid_t plist_id);
+H5_DLL herr_t H5Pset_family_offset(hid_t fapl_id, hsize_t offset);
+H5_DLL herr_t H5Pget_family_offset(hid_t fapl_id, hsize_t *offset);
+H5_DLL herr_t H5Pset_multi_type(hid_t fapl_id, H5FD_mem_t type);
+H5_DLL herr_t H5Pget_multi_type(hid_t fapl_id, H5FD_mem_t *type);
+H5_DLL herr_t H5Pset_cache(hid_t plist_id, int mdc_nelmts,
+ size_t rdcc_nslots, size_t rdcc_nbytes,
+ double rdcc_w0);
+H5_DLL herr_t H5Pget_cache(hid_t plist_id,
+ int *mdc_nelmts, /* out */
+ size_t *rdcc_nslots/*out*/,
+ size_t *rdcc_nbytes/*out*/, double *rdcc_w0);
+H5_DLL herr_t H5Pset_mdc_config(hid_t plist_id,
+ H5AC_cache_config_t * config_ptr);
+H5_DLL herr_t H5Pget_mdc_config(hid_t plist_id,
+ H5AC_cache_config_t * config_ptr); /* out */
+H5_DLL herr_t H5Pset_gc_references(hid_t fapl_id, unsigned gc_ref);
+H5_DLL herr_t H5Pget_gc_references(hid_t fapl_id, unsigned *gc_ref/*out*/);
+H5_DLL herr_t H5Pset_fclose_degree(hid_t fapl_id, H5F_close_degree_t degree);
+H5_DLL herr_t H5Pget_fclose_degree(hid_t fapl_id, H5F_close_degree_t *degree);
+H5_DLL herr_t H5Pset_meta_block_size(hid_t fapl_id, hsize_t size);
+H5_DLL herr_t H5Pget_meta_block_size(hid_t fapl_id, hsize_t *size/*out*/);
+H5_DLL herr_t H5Pset_sieve_buf_size(hid_t fapl_id, size_t size);
+H5_DLL herr_t H5Pget_sieve_buf_size(hid_t fapl_id, size_t *size/*out*/);
+H5_DLL herr_t H5Pset_small_data_block_size(hid_t fapl_id, hsize_t size);
+H5_DLL herr_t H5Pget_small_data_block_size(hid_t fapl_id, hsize_t *size/*out*/);
+H5_DLL herr_t H5Pset_libver_bounds(hid_t plist_id, H5F_libver_t low,
+ H5F_libver_t high);
+H5_DLL herr_t H5Pget_libver_bounds(hid_t plist_id, H5F_libver_t *low,
+ H5F_libver_t *high);
+H5_DLL herr_t H5Pset_elink_file_cache_size(hid_t plist_id, unsigned efc_size);
+H5_DLL herr_t H5Pget_elink_file_cache_size(hid_t plist_id, unsigned *efc_size);
+H5_DLL herr_t H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len);
+H5_DLL herr_t H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr);
+H5_DLL herr_t H5Pset_file_image_callbacks(hid_t fapl_id,
+ H5FD_file_image_callbacks_t *callbacks_ptr);
+H5_DLL herr_t H5Pget_file_image_callbacks(hid_t fapl_id,
+ H5FD_file_image_callbacks_t *callbacks_ptr);
+H5_DLL herr_t H5Pset_core_write_tracking(hid_t fapl_id, hbool_t is_enabled, size_t page_size);
+H5_DLL herr_t H5Pget_core_write_tracking(hid_t fapl_id, hbool_t *is_enabled, size_t *page_size);
+H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts);
+H5_DLL herr_t H5Pget_metadata_read_attempts(hid_t plist_id, unsigned *attempts);
+H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata);
+H5_DLL herr_t H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata);
+H5_DLL herr_t H5Pset_mdc_log_options(hid_t plist_id, hbool_t is_enabled, const char *location, hbool_t start_on_access);
+H5_DLL herr_t H5Pget_mdc_log_options(hid_t plist_id, hbool_t *is_enabled, char *location, size_t *location_size, hbool_t *start_on_access);
+H5_DLL herr_t H5Pset_evict_on_close(hid_t fapl_id, hbool_t evict_on_close);
+H5_DLL herr_t H5Pget_evict_on_close(hid_t fapl_id, hbool_t *evict_on_close);
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5Pset_all_coll_metadata_ops(hid_t plist_id, hbool_t is_collective);
+H5_DLL herr_t H5Pget_all_coll_metadata_ops(hid_t plist_id, hbool_t *is_collective);
+H5_DLL herr_t H5Pset_coll_metadata_write(hid_t plist_id, hbool_t is_collective);
+H5_DLL herr_t H5Pget_coll_metadata_write(hid_t plist_id, hbool_t *is_collective);
+#endif /* H5_HAVE_PARALLEL */
+H5_DLL herr_t H5Pset_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t *config_ptr);
+H5_DLL herr_t H5Pget_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t *config_ptr /*out*/);
+H5_DLL herr_t H5Pset_page_buffer_size(hid_t plist_id, size_t buf_size, unsigned min_meta_per, unsigned min_raw_per);
+H5_DLL herr_t H5Pget_page_buffer_size(hid_t plist_id, size_t *buf_size, unsigned *min_meta_per, unsigned *min_raw_per);
+
+/* Dataset creation property list (DCPL) routines */
+H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout);
+H5_DLL H5D_layout_t H5Pget_layout(hid_t plist_id);
+H5_DLL herr_t H5Pset_chunk(hid_t plist_id, int ndims, const hsize_t dim[/*ndims*/]);
+H5_DLL int H5Pget_chunk(hid_t plist_id, int max_ndims, hsize_t dim[]/*out*/);
+H5_DLL herr_t H5Pset_virtual(hid_t dcpl_id, hid_t vspace_id,
+ const char *src_file_name, const char *src_dset_name, hid_t src_space_id);
+H5_DLL herr_t H5Pget_virtual_count(hid_t dcpl_id, size_t *count/*out*/);
+H5_DLL hid_t H5Pget_virtual_vspace(hid_t dcpl_id, size_t index);
+H5_DLL hid_t H5Pget_virtual_srcspace(hid_t dcpl_id, size_t index);
+H5_DLL ssize_t H5Pget_virtual_filename(hid_t dcpl_id, size_t index,
+ char *name/*out*/, size_t size);
+H5_DLL ssize_t H5Pget_virtual_dsetname(hid_t dcpl_id, size_t index,
+ char *name/*out*/, size_t size);
+H5_DLL herr_t H5Pset_external(hid_t plist_id, const char *name, off_t offset,
+ hsize_t size);
+H5_DLL herr_t H5Pset_chunk_opts(hid_t plist_id, unsigned opts);
+H5_DLL herr_t H5Pget_chunk_opts(hid_t plist_id, unsigned *opts);
+H5_DLL int H5Pget_external_count(hid_t plist_id);
+H5_DLL herr_t H5Pget_external(hid_t plist_id, unsigned idx, size_t name_size,
+ char *name/*out*/, off_t *offset/*out*/,
+ hsize_t *size/*out*/);
+H5_DLL herr_t H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels_per_block);
+H5_DLL herr_t H5Pset_shuffle(hid_t plist_id);
+H5_DLL herr_t H5Pset_nbit(hid_t plist_id);
+H5_DLL herr_t H5Pset_scaleoffset(hid_t plist_id, H5Z_SO_scale_type_t scale_type, int scale_factor);
+H5_DLL herr_t H5Pset_fill_value(hid_t plist_id, hid_t type_id,
+ const void *value);
+H5_DLL herr_t H5Pget_fill_value(hid_t plist_id, hid_t type_id,
+ void *value/*out*/);
+H5_DLL herr_t H5Pfill_value_defined(hid_t plist, H5D_fill_value_t *status);
+H5_DLL herr_t H5Pset_alloc_time(hid_t plist_id, H5D_alloc_time_t
+ alloc_time);
+H5_DLL herr_t H5Pget_alloc_time(hid_t plist_id, H5D_alloc_time_t
+ *alloc_time/*out*/);
+H5_DLL herr_t H5Pset_fill_time(hid_t plist_id, H5D_fill_time_t fill_time);
+H5_DLL herr_t H5Pget_fill_time(hid_t plist_id, H5D_fill_time_t
+ *fill_time/*out*/);
+
+/* Dataset access property list (DAPL) routines */
+H5_DLL herr_t H5Pset_chunk_cache(hid_t dapl_id, size_t rdcc_nslots,
+ size_t rdcc_nbytes, double rdcc_w0);
+H5_DLL herr_t H5Pget_chunk_cache(hid_t dapl_id,
+ size_t *rdcc_nslots/*out*/,
+ size_t *rdcc_nbytes/*out*/,
+ double *rdcc_w0/*out*/);
+H5_DLL herr_t H5Pset_virtual_view(hid_t plist_id, H5D_vds_view_t view);
+H5_DLL herr_t H5Pget_virtual_view(hid_t plist_id, H5D_vds_view_t *view);
+H5_DLL herr_t H5Pset_virtual_printf_gap(hid_t plist_id, hsize_t gap_size);
+H5_DLL herr_t H5Pget_virtual_printf_gap(hid_t plist_id, hsize_t *gap_size);
+H5_DLL herr_t H5Pset_append_flush(hid_t plist_id, unsigned ndims,
+ const hsize_t boundary[], H5D_append_cb_t func, void *udata);
+H5_DLL herr_t H5Pget_append_flush(hid_t plist_id, unsigned dims,
+ hsize_t boundary[], H5D_append_cb_t *func, void **udata);
+H5_DLL herr_t H5Pset_efile_prefix(hid_t dapl_id, const char* prefix);
+H5_DLL ssize_t H5Pget_efile_prefix(hid_t dapl_id, char* prefix /*out*/, size_t size);
+
+/* Dataset xfer property list (DXPL) routines */
+H5_DLL herr_t H5Pset_data_transform(hid_t plist_id, const char* expression);
+H5_DLL ssize_t H5Pget_data_transform(hid_t plist_id, char* expression /*out*/, size_t size);
+H5_DLL herr_t H5Pset_buffer(hid_t plist_id, size_t size, void *tconv,
+ void *bkg);
+H5_DLL size_t H5Pget_buffer(hid_t plist_id, void **tconv/*out*/,
+ void **bkg/*out*/);
+H5_DLL herr_t H5Pset_preserve(hid_t plist_id, hbool_t status);
+H5_DLL int H5Pget_preserve(hid_t plist_id);
+H5_DLL herr_t H5Pset_edc_check(hid_t plist_id, H5Z_EDC_t check);
+H5_DLL H5Z_EDC_t H5Pget_edc_check(hid_t plist_id);
+H5_DLL herr_t H5Pset_filter_callback(hid_t plist_id, H5Z_filter_func_t func,
+ void* op_data);
+H5_DLL herr_t H5Pset_btree_ratios(hid_t plist_id, double left, double middle,
+ double right);
+H5_DLL herr_t H5Pget_btree_ratios(hid_t plist_id, double *left/*out*/,
+ double *middle/*out*/,
+ double *right/*out*/);
+H5_DLL herr_t H5Pset_vlen_mem_manager(hid_t plist_id,
+ H5MM_allocate_t alloc_func,
+ void *alloc_info, H5MM_free_t free_func,
+ void *free_info);
+H5_DLL herr_t H5Pget_vlen_mem_manager(hid_t plist_id,
+ H5MM_allocate_t *alloc_func,
+ void **alloc_info,
+ H5MM_free_t *free_func,
+ void **free_info);
+H5_DLL herr_t H5Pset_hyper_vector_size(hid_t fapl_id, size_t size);
+H5_DLL herr_t H5Pget_hyper_vector_size(hid_t fapl_id, size_t *size/*out*/);
+H5_DLL herr_t H5Pset_type_conv_cb(hid_t dxpl_id, H5T_conv_except_func_t op, void* operate_data);
+H5_DLL herr_t H5Pget_type_conv_cb(hid_t dxpl_id, H5T_conv_except_func_t *op, void** operate_data);
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5Pget_mpio_actual_chunk_opt_mode(hid_t plist_id, H5D_mpio_actual_chunk_opt_mode_t *actual_chunk_opt_mode);
+H5_DLL herr_t H5Pget_mpio_actual_io_mode(hid_t plist_id, H5D_mpio_actual_io_mode_t *actual_io_mode);
+H5_DLL herr_t H5Pget_mpio_no_collective_cause(hid_t plist_id, uint32_t *local_no_collective_cause, uint32_t *global_no_collective_cause);
+#endif /* H5_HAVE_PARALLEL */
+
+/* Link creation property list (LCPL) routines */
+H5_DLL herr_t H5Pset_create_intermediate_group(hid_t plist_id, unsigned crt_intmd);
+H5_DLL herr_t H5Pget_create_intermediate_group(hid_t plist_id, unsigned *crt_intmd /*out*/);
+
+/* Group creation property list (GCPL) routines */
+H5_DLL herr_t H5Pset_local_heap_size_hint(hid_t plist_id, size_t size_hint);
+H5_DLL herr_t H5Pget_local_heap_size_hint(hid_t plist_id, size_t *size_hint /*out*/);
+H5_DLL herr_t H5Pset_link_phase_change(hid_t plist_id, unsigned max_compact, unsigned min_dense);
+H5_DLL herr_t H5Pget_link_phase_change(hid_t plist_id, unsigned *max_compact /*out*/, unsigned *min_dense /*out*/);
+H5_DLL herr_t H5Pset_est_link_info(hid_t plist_id, unsigned est_num_entries, unsigned est_name_len);
+H5_DLL herr_t H5Pget_est_link_info(hid_t plist_id, unsigned *est_num_entries /* out */, unsigned *est_name_len /* out */);
+H5_DLL herr_t H5Pset_link_creation_order(hid_t plist_id, unsigned crt_order_flags);
+H5_DLL herr_t H5Pget_link_creation_order(hid_t plist_id, unsigned *crt_order_flags /* out */);
+
+/* String creation property list (STRCPL) routines */
+H5_DLL herr_t H5Pset_char_encoding(hid_t plist_id, H5T_cset_t encoding);
+H5_DLL herr_t H5Pget_char_encoding(hid_t plist_id, H5T_cset_t *encoding /*out*/);
+
+/* Link access property list (LAPL) routines */
+H5_DLL herr_t H5Pset_nlinks(hid_t plist_id, size_t nlinks);
+H5_DLL herr_t H5Pget_nlinks(hid_t plist_id, size_t *nlinks);
+H5_DLL herr_t H5Pset_elink_prefix(hid_t plist_id, const char *prefix);
+H5_DLL ssize_t H5Pget_elink_prefix(hid_t plist_id, char *prefix, size_t size);
+H5_DLL hid_t H5Pget_elink_fapl(hid_t lapl_id);
+H5_DLL herr_t H5Pset_elink_fapl(hid_t lapl_id, hid_t fapl_id);
+H5_DLL herr_t H5Pset_elink_acc_flags(hid_t lapl_id, unsigned flags);
+H5_DLL herr_t H5Pget_elink_acc_flags(hid_t lapl_id, unsigned *flags);
+H5_DLL herr_t H5Pset_elink_cb(hid_t lapl_id, H5L_elink_traverse_t func, void *op_data);
+H5_DLL herr_t H5Pget_elink_cb(hid_t lapl_id, H5L_elink_traverse_t *func, void **op_data);
+
+/* Object copy property list (OCPYPL) routines */
+H5_DLL herr_t H5Pset_copy_object(hid_t plist_id, unsigned crt_intmd);
+H5_DLL herr_t H5Pget_copy_object(hid_t plist_id, unsigned *crt_intmd /*out*/);
+H5_DLL herr_t H5Padd_merge_committed_dtype_path(hid_t plist_id, const char *path);
+H5_DLL herr_t H5Pfree_merge_committed_dtype_paths(hid_t plist_id);
+H5_DLL herr_t H5Pset_mcdt_search_cb(hid_t plist_id, H5O_mcdt_search_cb_t func, void *op_data);
+H5_DLL herr_t H5Pget_mcdt_search_cb(hid_t plist_id, H5O_mcdt_search_cb_t *func, void **op_data);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+/* We renamed the "root" of the property list class hierarchy */
+#define H5P_NO_CLASS H5P_ROOT
+
+
+/* Typedefs */
+
+
+/* Function prototypes */
+H5_DLL herr_t H5Pregister1(hid_t cls_id, const char *name, size_t size,
+ void *def_value, H5P_prp_create_func_t prp_create,
+ H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_del, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_close_func_t prp_close);
+H5_DLL herr_t H5Pinsert1(hid_t plist_id, const char *name, size_t size,
+ void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get,
+ H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy,
+ H5P_prp_close_func_t prp_close);
+H5_DLL H5Z_filter_t H5Pget_filter1(hid_t plist_id, unsigned filter,
+ unsigned int *flags/*out*/, size_t *cd_nelmts/*out*/,
+ unsigned cd_values[]/*out*/, size_t namelen, char name[]);
+H5_DLL herr_t H5Pget_filter_by_id1(hid_t plist_id, H5Z_filter_t id,
+ unsigned int *flags/*out*/, size_t *cd_nelmts/*out*/,
+ unsigned cd_values[]/*out*/, size_t namelen, char name[]/*out*/);
+H5_DLL herr_t H5Pget_version(hid_t plist_id, unsigned *boot/*out*/,
+ unsigned *freelist/*out*/, unsigned *stab/*out*/,
+ unsigned *shhdr/*out*/);
+H5_DLL herr_t H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t threshold);
+H5_DLL herr_t H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy, hsize_t *threshold);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Ppublic_H */
+
diff --git a/src/H5Pstrcpl.c b/src/H5Pstrcpl.c
new file mode 100644
index 0000000..fb91356
--- /dev/null
+++ b/src/H5Pstrcpl.c
@@ -0,0 +1,285 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Pstrcpl.c
+ * October 26 2005
+ * James Laird <jlaird@ncsa.uiuc.edu>
+ *
+ * Purpose: String creation property list class routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* ======== String creation properties ======== */
+/* Definitions for character set encoding property */
+#define H5P_STRCRT_CHAR_ENCODING_SIZE sizeof(H5T_cset_t)
+#define H5P_STRCRT_CHAR_ENCODING_DEF H5F_DEFAULT_CSET
+#define H5P_STRCRT_CHAR_ENCODING_ENC H5P__strcrt_char_encoding_enc
+#define H5P_STRCRT_CHAR_ENCODING_DEC H5P__strcrt_char_encoding_dec
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Property class callbacks */
+static herr_t H5P__strcrt_reg_prop(H5P_genclass_t *pclass);
+
+/* encode & decode callbacks */
+static herr_t H5P__strcrt_char_encoding_enc(const void *value, void **_pp, size_t *size);
+static herr_t H5P__strcrt_char_encoding_dec(const void **_pp, void *value);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* String creation property list class library initialization object */
+const H5P_libclass_t H5P_CLS_STRCRT[1] = {{
+ "string create", /* Class name for debugging */
+ H5P_TYPE_STRING_CREATE, /* Class type */
+
+ &H5P_CLS_ROOT_g, /* Parent class */
+ &H5P_CLS_STRING_CREATE_g, /* Pointer to class */
+ &H5P_CLS_STRING_CREATE_ID_g, /* Pointer to class ID */
+ NULL, /* Pointer to default property list ID */
+ H5P__strcrt_reg_prop, /* Default property registration routine */
+
+ NULL, /* Class creation callback */
+ NULL, /* Class creation callback info */
+ NULL, /* Class copy callback */
+ NULL, /* Class copy callback info */
+ NULL, /* Class close callback */
+ NULL /* Class close callback info */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Property value defaults */
+static const H5T_cset_t H5P_def_char_encoding_g = H5P_STRCRT_CHAR_ENCODING_DEF; /* Default character set encoding */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__strcrt_reg_prop
+ *
+ * Purpose: Register the string creation property list class's properties
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 31, 2006
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__strcrt_reg_prop(H5P_genclass_t *pclass)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Register character encoding */
+ if(H5P_register_real(pclass, H5P_STRCRT_CHAR_ENCODING_NAME, H5P_STRCRT_CHAR_ENCODING_SIZE, &H5P_def_char_encoding_g,
+ NULL, NULL, NULL, H5P_STRCRT_CHAR_ENCODING_ENC, H5P_STRCRT_CHAR_ENCODING_DEC,
+ NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P__strcrt_reg_prop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_char_encoding
+ *
+ * Purpose: Sets the character encoding of the string.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Wednesday, October 26, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_char_encoding(hid_t plist_id, H5T_cset_t encoding)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTc", plist_id, encoding);
+
+ /* Check arguments */
+ if (encoding <= H5T_CSET_ERROR || encoding >= H5T_NCSET)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "character encoding is not valid")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_STRING_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set the character encoding */
+ if(H5P_set(plist, H5P_STRCRT_CHAR_ENCODING_NAME, &encoding) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set character encoding")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5P_set_char_encoding() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_char_encoding
+ *
+ * Purpose: Gets the character encoding of the string.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * November 1, 2005
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_char_encoding(hid_t plist_id, H5T_cset_t *encoding /*out*/)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ix", plist_id, encoding);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_STRING_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get value */
+ if(encoding)
+ if(H5P_get(plist, H5P_STRCRT_CHAR_ENCODING_NAME, encoding) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get character encoding flag")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_char_encoding() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__strcrt_char_encoding_enc
+ *
+ * Purpose: Callback routine which is called whenever the character
+ * set encoding property in the string create property list
+ * is encoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__strcrt_char_encoding_enc(const void *value, void **_pp, size_t *size)
+{
+ const H5T_cset_t *encoding = (const H5T_cset_t *)value; /* Create local alias for values */
+ uint8_t **pp = (uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(encoding);
+ HDassert(size);
+
+ if(NULL != *pp)
+ /* Encode character set encoding */
+ *(*pp)++ = (uint8_t)*encoding;
+
+ /* Size of character set encoding */
+ (*size)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__strcrt_char_encoding_enc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P__strcrt_char_encoding_dec
+ *
+ * Purpose: Callback routine which is called whenever the character
+ * set encoding property in the string create property list
+ * is decoded.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 31, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5P__strcrt_char_encoding_dec(const void **_pp, void *_value)
+{
+ H5T_cset_t *encoding = (H5T_cset_t *)_value; /* Character set encoding */
+ const uint8_t **pp = (const uint8_t **)_pp;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(pp);
+ HDassert(*pp);
+ HDassert(encoding);
+
+ /* Decode character set encoding */
+ *encoding = (H5T_cset_t)*(*pp)++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5P__strcrt_char_encoding_dec() */
+
diff --git a/src/H5Ptest.c b/src/H5Ptest.c
new file mode 100644
index 0000000..475a164
--- /dev/null
+++ b/src/H5Ptest.c
@@ -0,0 +1,125 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Saturday May 31, 2003
+ *
+ * Purpose: Generic Property Testing Functions
+ */
+
+#include "H5Pmodule.h" /* This source code file is part of the H5P module */
+#define H5P_TESTING /*suppress warning about H5P testing funcs*/
+
+
+/* Private header files */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppkg.h" /* Property lists */
+#include "H5Dprivate.h" /* Dataset */
+
+/* Local variables */
+
+/* Local typedefs */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_get_class_path_test
+ PURPOSE
+ Routine to query the full path of a generic property list class
+ USAGE
+ char *H5P_get_class_name_test(pclass_id)
+ hid_t pclass_id; IN: Property class to query
+ RETURNS
+ Success: Pointer to a malloc'ed string containing the full path of class
+ Failure: NULL
+ DESCRIPTION
+ This routine retrieves the full path name of a generic property list
+ class, starting with the root of the class hierarchy.
+ The pointer to the name must be free'd by the user for successful calls.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING H5P_get_class_path()
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+char *
+H5P_get_class_path_test(hid_t pclass_id)
+{
+ H5P_genclass_t *pclass; /* Property class to query */
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check arguments. */
+ if(NULL == (pclass = (H5P_genclass_t *)H5I_object_verify(pclass_id, H5I_GENPROP_CLS)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property class");
+
+ /* Get the property list class path */
+ if(NULL == (ret_value = H5P_get_class_path(pclass)))
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "unable to query full path of class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_get_class_path_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5P_open_class_path_test
+ PURPOSE
+ Routine to open a [copy of] a class with its full path name
+ USAGE
+ hid_t H5P_open_class_name_test(path)
+ const char *path; IN: Full path name of class to open [copy of]
+ RETURNS
+ Success: ID of generic property class
+ Failure: NULL
+ DESCRIPTION
+ This routine opens [a copy] of the class indicated by the full path.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING H5P_open_class_path()
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5P_open_class_path_test(const char *path)
+{
+ H5P_genclass_t *pclass = NULL; /* Property class to query */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments. */
+ if (NULL == path || *path=='\0')
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid class path");
+
+ /* Open the property list class */
+ if ((pclass=H5P_open_class_path(path))==NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "unable to find class with full path");
+
+ /* Get an atom for the class */
+ if ((ret_value=H5I_register(H5I_GENPROP_CLS, pclass, TRUE))<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list class");
+
+done:
+ if(ret_value<0 && pclass)
+ H5P_close_class(pclass);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5P_open_class_path_test() */
+
diff --git a/src/H5R.c b/src/H5R.c
new file mode 100644
index 0000000..73c1d55
--- /dev/null
+++ b/src/H5R.c
@@ -0,0 +1,1050 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Rmodule.h" /* This source code file is part of the H5R module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gprivate.h" /* Groups */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Rpkg.h" /* References */
+#include "H5Sprivate.h" /* Dataspaces */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5R_create(void *ref, H5G_loc_t *loc, const char *name,
+ H5R_type_t ref_type, H5S_t *space, hid_t dxpl_id);
+static H5S_t * H5R_get_region(H5F_t *file, hid_t dxpl_id, const void *_ref);
+static ssize_t H5R_get_name(H5F_t *file, hid_t lapl_id, hid_t dxpl_id, hid_t id,
+ H5R_type_t ref_type, const void *_ref, char *name, size_t size);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Reference ID class */
+static const H5I_class_t H5I_REFERENCE_CLS[1] = {{
+ H5I_REFERENCE, /* ID class value */
+ 0, /* Class flags */
+ 0, /* # of reserved IDs for class */
+ NULL /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5R_top_package_initialize_s = FALSE;
+
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5R__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5R__init_package()
+
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t
+H5R__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Initialize the atom group for the file IDs */
+ if(H5I_register_type(H5I_REFERENCE_CLS) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Mark "top" of interface as initialized, too */
+ H5R_top_package_initialize_s = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R__init_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_top_term_package
+ PURPOSE
+ Terminate various H5R objects
+ USAGE
+ void H5R_top_term_package()
+ RETURNS
+ void
+ DESCRIPTION
+ Release IDs for the atom group, deferring full interface shutdown
+ until later (in H5R_term_package).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5R_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5R_top_package_initialize_s) {
+ if(H5I_nmembers(H5I_REFERENCE) > 0) {
+ (void)H5I_clear_type(H5I_REFERENCE, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Mark closed */
+ if(0 == n)
+ H5R_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5R_top_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_term_package
+ PURPOSE
+ Terminate various H5R objects
+ USAGE
+ void H5R_term_package()
+ RETURNS
+ void
+ DESCRIPTION
+ Release the atom group and any other resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+
+ Finishes shutting down the interface, after H5R_top_term_package()
+ is called
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5R_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity checks */
+ HDassert(0 == H5I_nmembers(H5I_REFERENCE));
+ HDassert(FALSE == H5R_top_package_initialize_s);
+
+ /* Destroy the reference id group */
+ n += (H5I_dec_type_ref(H5I_REFERENCE) > 0);
+
+ /* Mark closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5R_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_create
+ PURPOSE
+ Creates a particular kind of reference for the user
+ USAGE
+ herr_t H5R_create(ref, loc, name, ref_type, space)
+ void *ref; OUT: Reference created
+ H5G_loc_t *loc; IN: File location used to locate object pointed to
+ const char *name; IN: Name of object at location LOC_ID of object
+ pointed to
+ H5R_type_t ref_type; IN: Type of reference to create
+ H5S_t *space; IN: Dataspace ID with selection, used for Dataset
+ Region references.
+
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Creates a particular type of reference specified with REF_TYPE, in the
+ space pointed to by REF. The LOC_ID and NAME are used to locate the object
+ pointed to and the SPACE_ID is used to choose the region pointed to (for
+ Dataset Region references).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5R_create(void *_ref, H5G_loc_t *loc, const char *name, H5R_type_t ref_type, H5S_t *space, hid_t dxpl_id)
+{
+ H5G_loc_t obj_loc; /* Group hier. location of object */
+ H5G_name_t path; /* Object group hier. path */
+ H5O_loc_t oloc; /* Object object location */
+ hbool_t obj_found = FALSE; /* Object location found */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(_ref);
+ HDassert(loc);
+ HDassert(name);
+ HDassert(ref_type > H5R_BADTYPE && ref_type < H5R_MAXTYPE);
+
+ /* Set up object location to fill in */
+ obj_loc.oloc = &oloc;
+ obj_loc.path = &path;
+ H5G_loc_reset(&obj_loc);
+
+ /* Find the object */
+ if(H5G_loc_find(loc, name, &obj_loc, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_NOTFOUND, FAIL, "object not found")
+ obj_found = TRUE;
+
+ switch(ref_type) {
+ case H5R_OBJECT:
+ {
+ hobj_ref_t *ref = (hobj_ref_t *)_ref; /* Get pointer to correct type of reference struct */
+
+ *ref = obj_loc.oloc->addr;
+ break;
+ }
+
+ case H5R_DATASET_REGION:
+ {
+ H5HG_t hobjid; /* Heap object ID */
+ hdset_reg_ref_t *ref = (hdset_reg_ref_t *)_ref; /* Get pointer to correct type of reference struct */
+ hssize_t buf_size; /* Size of buffer needed to serialize selection */
+ uint8_t *p; /* Pointer to OID to store */
+ uint8_t *buf; /* Buffer to store serialized selection in */
+ unsigned heapid_found; /* Flag for non-zero heap ID found */
+ unsigned u; /* local index */
+
+ /* Set up information for dataset region */
+
+ /* Return any previous heap block to the free list if we are garbage collecting */
+ if(H5F_GC_REF(loc->oloc->file)) {
+ /* Check for an existing heap ID in the reference */
+ for(u = 0, heapid_found = 0, p = (uint8_t *)ref; u < H5R_DSET_REG_REF_BUF_SIZE; u++)
+ if(p[u] != 0) {
+ heapid_found = 1;
+ break;
+ } /* end if */
+
+ if(heapid_found != 0) {
+/* Return heap block to free list */
+ } /* end if */
+ } /* end if */
+
+ /* Zero the heap ID out, may leak heap space if user is re-using reference and doesn't have garbage collection on */
+ HDmemset(ref, 0, H5R_DSET_REG_REF_BUF_SIZE);
+
+ /* Get the amount of space required to serialize the selection */
+ if((buf_size = H5S_SELECT_SERIAL_SIZE(space)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "Invalid amount of space for serializing selection")
+
+ /* Increase buffer size to allow for the dataset OID */
+ buf_size += (hssize_t)sizeof(haddr_t);
+
+ /* Allocate the space to store the serialized information */
+ H5_CHECK_OVERFLOW(buf_size, hssize_t, size_t);
+ if(NULL == (buf = (uint8_t *)H5MM_malloc((size_t)buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Serialize information for dataset OID into heap buffer */
+ p = (uint8_t *)buf;
+ H5F_addr_encode(loc->oloc->file, &p, obj_loc.oloc->addr);
+
+ /* Serialize the selection into heap buffer */
+ if(H5S_SELECT_SERIALIZE(space, &p) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTCOPY, FAIL, "Unable to serialize selection")
+
+ /* Save the serialized buffer for later */
+ H5_CHECK_OVERFLOW(buf_size, hssize_t, size_t);
+ if(H5HG_insert(loc->oloc->file, dxpl_id, (size_t)buf_size, buf, &hobjid) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_WRITEERROR, FAIL, "Unable to serialize selection")
+
+ /* Serialize the heap ID and index for storage in the file */
+ p = (uint8_t *)ref;
+ H5F_addr_encode(loc->oloc->file, &p, hobjid.addr);
+ UINT32ENCODE(p, hobjid.idx);
+
+ /* Free the buffer we serialized data in */
+ H5MM_xfree(buf);
+ break;
+ }
+
+ case H5R_BADTYPE:
+ case H5R_MAXTYPE:
+ default:
+ HDassert("unknown reference type" && 0);
+ HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)")
+ } /* end switch */
+
+done:
+ if(obj_found)
+ H5G_loc_free(&obj_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rcreate
+ PURPOSE
+ Creates a particular kind of reference for the user
+ USAGE
+ herr_t H5Rcreate(ref, loc_id, name, ref_type, space_id)
+ void *ref; OUT: Reference created
+ hid_t loc_id; IN: Location ID used to locate object pointed to
+ const char *name; IN: Name of object at location LOC_ID of object
+ pointed to
+ H5R_type_t ref_type; IN: Type of reference to create
+ hid_t space_id; IN: Dataspace ID with selection, used for Dataset
+ Region references.
+
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Creates a particular type of reference specified with REF_TYPE, in the
+ space pointed to by REF. The LOC_ID and NAME are used to locate the object
+ pointed to and the SPACE_ID is used to choose the region pointed to (for
+ Dataset Region references).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Rcreate(void *ref, hid_t loc_id, const char *name, H5R_type_t ref_type, hid_t space_id)
+{
+ H5G_loc_t loc; /* File location */
+ H5S_t *space = NULL; /* Pointer to dataspace containing region */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "*xi*sRti", ref, loc_id, name, ref_type, space_id);
+
+ /* Check args */
+ if(ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name given")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(ref_type != H5R_OBJECT && ref_type != H5R_DATASET_REGION)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "reference type not supported")
+ if(space_id == (-1) && ref_type == H5R_DATASET_REGION)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "reference region dataspace id must be valid")
+ if(space_id != (-1) && (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Create reference */
+ if((ret_value = H5R_create(ref, &loc, name, ref_type, space, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable to create reference")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rcreate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_dereference
+ PURPOSE
+ Opens the HDF5 object referenced.
+ USAGE
+ hid_t H5R_dereference(ref)
+ H5F_t *file; IN: File the object being dereferenced is within
+ H5R_type_t ref_type; IN: Type of reference
+ void *ref; IN: Reference to open.
+
+ RETURNS
+ Valid ID on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, open that object and return an ID for
+ that object.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Currently only set up to work with references to datasets
+ EXAMPLES
+ REVISION LOG
+ Raymond Lu
+ 13 July 2011
+ I added the OAPL_ID parameter for the object being referenced. It only
+ supports dataset access property list currently.
+
+ M. Scot Breitenfeld
+ 3 March 2015
+ Added a check for undefined reference pointer.
+--------------------------------------------------------------------------*/
+hid_t
+H5R_dereference(H5F_t *file, hid_t oapl_id, hid_t dxpl_id, H5R_type_t ref_type, const void *_ref, hbool_t app_ref)
+{
+ H5O_loc_t oloc; /* Object location */
+ H5G_name_t path; /* Path of object */
+ H5G_loc_t loc; /* Group location */
+ unsigned rc; /* Reference count of object */
+ H5O_type_t obj_type; /* Type of object */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(_ref);
+ HDassert(ref_type > H5R_BADTYPE && ref_type < H5R_MAXTYPE);
+ HDassert(file);
+
+ /* Initialize the object location */
+ H5O_loc_reset(&oloc);
+ oloc.file = file;
+
+ switch(ref_type) {
+ case H5R_OBJECT:
+ oloc.addr = *(const hobj_ref_t *)_ref; /* Only object references currently supported */
+ if(!H5F_addr_defined(oloc.addr) || oloc.addr == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Undefined reference pointer")
+ break;
+
+ case H5R_DATASET_REGION:
+ {
+ H5HG_t hobjid; /* Heap object ID */
+ uint8_t *buf; /* Buffer to store serialized selection in */
+ const uint8_t *p; /* Pointer to OID to store */
+
+ /* Get the heap ID for the dataset region */
+ p = (const uint8_t *)_ref;
+ H5F_addr_decode(oloc.file, &p, &(hobjid.addr));
+ UINT32DECODE(p, hobjid.idx);
+
+ if(!H5F_addr_defined(hobjid.addr) || hobjid.addr == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Undefined reference pointer")
+
+ /* Get the dataset region from the heap (allocate inside routine) */
+ if(NULL == (buf = (uint8_t *)H5HG_read(oloc.file, dxpl_id, &hobjid, NULL, NULL)))
+ HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information")
+
+ /* Get the object oid for the dataset */
+ p = buf;
+ H5F_addr_decode(oloc.file, &p, &(oloc.addr));
+
+ /* Free the buffer allocated in H5HG_read() */
+ H5MM_xfree(buf);
+ } /* end case */
+ break;
+
+ case H5R_BADTYPE:
+ case H5R_MAXTYPE:
+ default:
+ HDassert("unknown reference type" && 0);
+ HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)")
+ } /* end switch */
+
+ /* Get the # of links for object, and its type */
+ /* (To check to make certain that this object hasn't been deleted since the reference was created) */
+ if(H5O_get_rc_and_type(&oloc, dxpl_id, &rc, &obj_type) < 0 || 0 == rc)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_LINKCOUNT, FAIL, "dereferencing deleted object")
+
+ /* Construct a group location for opening the object */
+ H5G_name_reset(&path);
+ loc.oloc = &oloc;
+ loc.path = &path;
+
+ /* Open the object */
+ switch(obj_type) {
+ case H5O_TYPE_GROUP:
+ {
+ H5G_t *group; /* Pointer to group to open */
+
+ if(NULL == (group = H5G_open(&loc, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found")
+
+ /* Create an atom for the group */
+ if((ret_value = H5I_register(H5I_GROUP, group, app_ref)) < 0) {
+ H5G_close(group);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREGISTER, FAIL, "can't register group")
+ } /* end if */
+ } /* end case */
+ break;
+
+ case H5O_TYPE_NAMED_DATATYPE:
+ {
+ H5T_t *type; /* Pointer to datatype to open */
+
+ if(NULL == (type = H5T_open(&loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "not found")
+
+ /* Create an atom for the datatype */
+ if((ret_value = H5I_register(H5I_DATATYPE, type, app_ref)) < 0) {
+ H5T_close(type);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "can't register datatype")
+ } /* end if */
+ } /* end case */
+ break;
+
+ case H5O_TYPE_DATASET:
+ {
+ H5D_t *dset; /* Pointer to dataset to open */
+
+ /* Open the dataset */
+ if(NULL == (dset = H5D_open(&loc, oapl_id, dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, FAIL, "not found")
+
+ /* Create an atom for the dataset */
+ if((ret_value = H5I_register(H5I_DATASET, dset, app_ref)) < 0) {
+ H5D_close(dset);
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "can't register dataset")
+ } /* end if */
+ } /* end case */
+ break;
+
+ case H5O_TYPE_UNKNOWN:
+ case H5O_TYPE_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_REFERENCE, H5E_BADTYPE, FAIL, "can't identify type of object referenced")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R_dereference() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rdereference2
+ PURPOSE
+ Opens the HDF5 object referenced.
+ USAGE
+ hid_t H5Rdereference2(ref)
+ hid_t id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ hid_t oapl_id; IN: Property list of the object being referenced.
+ H5R_type_t ref_type; IN: Type of reference to create
+ void *ref; IN: Reference to open.
+
+ RETURNS
+ Valid ID on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, open that object and return an ID for
+ that object.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+ Raymond Lu
+ 13 July 2011
+ I added the OAPL_ID parameter for the object being referenced. It only
+ supports dataset access property list currently.
+--------------------------------------------------------------------------*/
+hid_t
+H5Rdereference2(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, const void *_ref)
+{
+ H5G_loc_t loc; /* Group location */
+ H5F_t *file = NULL; /* File object */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("i", "iiRt*x", obj_id, oapl_id, ref_type, _ref);
+
+ /* Check args */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(oapl_id < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(_ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&oapl_id, H5P_CLS_DACC, &dxpl_id, obj_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Get the file pointer from the entry */
+ file = loc.oloc->file;
+
+ /* Create reference */
+ if((ret_value = H5R_dereference(file, oapl_id, dxpl_id, ref_type, _ref, TRUE)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable to dereference object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rdereference2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_get_region
+ PURPOSE
+ Retrieves a dataspace with the region pointed to selected.
+ USAGE
+ H5S_t *H5R_get_region(file, ref_type, ref)
+ H5F_t *file; IN: File the object being dereferenced is within
+ void *ref; IN: Reference to open.
+
+ RETURNS
+ Pointer to the dataspace on success, NULL on failure
+ DESCRIPTION
+ Given a reference to some object, creates a copy of the dataset pointed
+ to's dataspace and defines a selection in the copy which is the region
+ pointed to.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_t *
+H5R_get_region(H5F_t *file, hid_t dxpl_id, const void *_ref)
+{
+ H5O_loc_t oloc; /* Object location */
+ const uint8_t *p; /* Pointer to OID to store */
+ H5HG_t hobjid; /* Heap object ID */
+ uint8_t *buf = NULL; /* Buffer to store serialized selection in */
+ H5S_t *ret_value;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(_ref);
+ HDassert(file);
+
+ /* Initialize the object location */
+ H5O_loc_reset(&oloc);
+ oloc.file = file;
+
+ /* Get the heap ID for the dataset region */
+ p = (const uint8_t *)_ref;
+ H5F_addr_decode(oloc.file, &p, &(hobjid.addr));
+ UINT32DECODE(p, hobjid.idx);
+
+ /* Get the dataset region from the heap (allocate inside routine) */
+ if((buf = (uint8_t *)H5HG_read(oloc.file, dxpl_id, &hobjid, NULL, NULL)) == NULL)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, NULL, "Unable to read dataset region information")
+
+ /* Get the object oid for the dataset */
+ p = buf;
+ H5F_addr_decode(oloc.file, &p, &(oloc.addr));
+
+ /* Open and copy the dataset's dataspace */
+ if((ret_value = H5S_read(&oloc, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, NULL, "not found")
+
+ /* Unserialize the selection */
+ if(H5S_SELECT_DESERIALIZE(&ret_value, &p) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTDECODE, NULL, "can't deserialize selection")
+
+done:
+ /* Free the buffer allocated in H5HG_read() */
+ if(buf)
+ H5MM_xfree(buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R_get_region() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rget_region
+ PURPOSE
+ Retrieves a dataspace with the region pointed to selected.
+ USAGE
+ hid_t H5Rget_region(id, ref_type, ref)
+ hid_t id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ H5R_type_t ref_type; IN: Type of reference to get region of
+ void *ref; IN: Reference to open.
+
+ RETURNS
+ Valid ID on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, creates a copy of the dataset pointed
+ to's dataspace and defines a selection in the copy which is the region
+ pointed to.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Rget_region(hid_t id, H5R_type_t ref_type, const void *ref)
+{
+ H5G_loc_t loc; /* Object's group location */
+ H5S_t *space = NULL; /* Dataspace object */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iRt*x", id, ref_type, ref);
+
+ /* Check args */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(ref_type != H5R_DATASET_REGION)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+
+ /* Get the dataspace with the correct region selected */
+ if((space = H5R_get_region(loc.oloc->file, H5AC_ind_read_dxpl_id, ref)) == NULL)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTCREATE, FAIL, "unable to create dataspace")
+
+ /* Atomize */
+ if((ret_value = H5I_register (H5I_DATASPACE, space, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rget_region() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_get_obj_type
+ PURPOSE
+ Retrieves the type of object that an object reference points to
+ USAGE
+ H5O_type_t H5R_get_obj_type(file, ref_type, ref)
+ H5F_t *file; IN: File the object being dereferenced is within
+ H5R_type_t ref_type; IN: Type of reference to query
+ void *ref; IN: Reference to query.
+
+ RETURNS
+ Success: An object type defined in H5Gpublic.h
+ Failure: H5G_UNKNOWN
+ DESCRIPTION
+ Given a reference to some object, this function returns the type of object
+ pointed to.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5R_get_obj_type(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type,
+ const void *_ref, H5O_type_t *obj_type)
+{
+ H5O_loc_t oloc; /* Object location */
+ unsigned rc; /* Reference count of object */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+ HDassert(_ref);
+
+ /* Initialize the symbol table entry */
+ H5O_loc_reset(&oloc);
+ oloc.file = file;
+
+ switch(ref_type) {
+ case H5R_OBJECT:
+ /* Get the object oid */
+ oloc.addr = *(const hobj_ref_t *)_ref; /* Only object references currently supported */
+ break;
+
+ case H5R_DATASET_REGION:
+ {
+ H5HG_t hobjid; /* Heap object ID */
+ const uint8_t *p; /* Pointer to reference to decode */
+ uint8_t *buf; /* Buffer to store serialized selection in */
+
+ /* Get the heap ID for the dataset region */
+ p = (const uint8_t *)_ref;
+ H5F_addr_decode(oloc.file, &p, &(hobjid.addr));
+ UINT32DECODE(p, hobjid.idx);
+
+ /* Get the dataset region from the heap (allocate inside routine) */
+ if((buf = (uint8_t *)H5HG_read(oloc.file, dxpl_id, &hobjid, NULL, NULL)) == NULL)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information")
+
+ /* Get the object oid for the dataset */
+ p = buf;
+ H5F_addr_decode(oloc.file, &p, &(oloc.addr));
+
+ /* Free the buffer allocated in H5HG_read() */
+ H5MM_xfree(buf);
+ } /* end case */
+ break;
+
+ case H5R_BADTYPE:
+ case H5R_MAXTYPE:
+ default:
+ HDassert("unknown reference type" && 0);
+ HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)")
+ } /* end switch */
+
+ /* Get the # of links for object, and its type */
+ /* (To check to make certain that this object hasn't been deleted since the reference was created) */
+ if(H5O_get_rc_and_type(&oloc, dxpl_id, &rc, obj_type) < 0 || 0 == rc)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_LINKCOUNT, FAIL, "dereferencing deleted object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R_get_obj_type() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rget_obj_type2
+ PURPOSE
+ Retrieves the type of object that an object reference points to
+ USAGE
+ herr_t H5Rget_obj_type2(id, ref_type, ref, obj_type)
+ hid_t id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ H5R_type_t ref_type; IN: Type of reference to query
+ void *ref; IN: Reference to query.
+ H5O_type_t *obj_type; OUT: Type of object reference points to
+
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Given a reference to some object, this function retrieves the type of
+ object pointed to.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Rget_obj_type2(hid_t id, H5R_type_t ref_type, const void *ref,
+ H5O_type_t *obj_type)
+{
+ H5G_loc_t loc; /* Object location */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iRt*x*Ot", id, ref_type, ref, obj_type);
+
+ /* Check args */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+
+ /* Get the object information */
+ if(H5R_get_obj_type(loc.oloc->file, H5AC_ind_read_dxpl_id, ref_type, ref, obj_type) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rget_obj_type2() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5R_get_name
+ PURPOSE
+ Internal routine to determine a name for the object referenced
+ USAGE
+ ssize_t H5R_get_name(f, dxpl_id, ref_type, ref, name, size)
+ H5F_t *f; IN: Pointer to the file that the reference is pointing
+ into
+ hid_t lapl_id; IN: LAPL to use for operation
+ hid_t dxpl_id; IN: DXPL to use for operation
+ hid_t id; IN: Location ID given for reference
+ H5R_type_t ref_type; IN: Type of reference
+ void *ref; IN: Reference to query.
+ char *name; OUT: Buffer to place name of object referenced
+ size_t size; IN: Size of name buffer
+
+ RETURNS
+ Non-negative length of the path on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, determine a path to the object
+ referenced in the file.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This may not be the only path to that object.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static ssize_t
+H5R_get_name(H5F_t *f, hid_t lapl_id, hid_t dxpl_id, hid_t id, H5R_type_t ref_type,
+ const void *_ref, char *name, size_t size)
+{
+ hid_t file_id = H5I_INVALID_HID; /* ID for file that the reference is in */
+ H5O_loc_t oloc; /* Object location describing object for reference */
+ ssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(f);
+ HDassert(_ref);
+
+ /* Initialize the object location */
+ H5O_loc_reset(&oloc);
+ oloc.file = f;
+
+ /* Get address for reference */
+ switch(ref_type) {
+ case H5R_OBJECT:
+ oloc.addr = *(const hobj_ref_t *)_ref;
+ break;
+
+ case H5R_DATASET_REGION:
+ {
+ H5HG_t hobjid; /* Heap object ID */
+ uint8_t *buf; /* Buffer to store serialized selection in */
+ const uint8_t *p; /* Pointer to OID to store */
+
+ /* Get the heap ID for the dataset region */
+ p = (const uint8_t *)_ref;
+ H5F_addr_decode(oloc.file, &p, &(hobjid.addr));
+ UINT32DECODE(p, hobjid.idx);
+
+ /* Get the dataset region from the heap (allocate inside routine) */
+ if((buf = (uint8_t *)H5HG_read(oloc.file, dxpl_id, &hobjid, NULL, NULL)) == NULL)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information")
+
+ /* Get the object oid for the dataset */
+ p = buf;
+ H5F_addr_decode(oloc.file, &p, &(oloc.addr));
+
+ /* Free the buffer allocated in H5HG_read() */
+ H5MM_xfree(buf);
+ } /* end case */
+ break;
+
+ case H5R_BADTYPE:
+ case H5R_MAXTYPE:
+ default:
+ HDassert("unknown reference type" && 0);
+ HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)")
+ } /* end switch */
+
+ /* Retrieve file ID for name search */
+ if((file_id = H5I_get_file_id(id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "can't retrieve file ID")
+
+ /* Get name, length, etc. */
+ if((ret_value = H5G_get_name_by_addr(file_id, lapl_id, dxpl_id, &oloc, name, size)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "can't determine name")
+
+done:
+ /* Close file ID used for search */
+ if(file_id > 0 && H5I_dec_ref(file_id) < 0)
+ HDONE_ERROR(H5E_REFERENCE, H5E_CANTDEC, FAIL, "can't decrement ref count of temp ID")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5R_get_name() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rget_name
+ PURPOSE
+ Determines a name for the object referenced
+ USAGE
+ ssize_t H5Rget_name(loc_id, ref_type, ref, name, size)
+ hid_t loc_id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ H5R_type_t ref_type; IN: Type of reference
+ void *ref; IN: Reference to query.
+ char *name; OUT: Buffer to place name of object referenced. If NULL
+ then this call will return the size in bytes of name.
+ size_t size; IN: Size of name buffer (user needs to include NULL terminator
+ when passing in the size)
+
+ RETURNS
+ Non-negative length of the path on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, determine a path to the object
+ referenced in the file.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This may not be the only path to that object.
+ EXAMPLES
+ REVISION LOG
+ M. Scot Breitenfeld
+ 22 January 2014
+ Changed the behavior for the returned value of the function when name is NULL.
+ If name is NULL then size is ignored and the function returns the size
+ of the name buffer (not including the NULL terminator), it still returns
+ negative on failure.
+--------------------------------------------------------------------------*/
+ssize_t
+H5Rget_name(hid_t id, H5R_type_t ref_type, const void *_ref, char *name,
+ size_t size)
+{
+ H5G_loc_t loc; /* Group location */
+ H5F_t *file; /* File object */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("Zs", "iRt*x*sz", id, ref_type, _ref, name, size);
+
+ /* Check args */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(_ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+
+ /* Get the file pointer from the entry */
+ file = loc.oloc->file;
+
+ /* Get name */
+ if((ret_value = H5R_get_name(file, H5P_DEFAULT, H5AC_ind_read_dxpl_id, id, ref_type, _ref, name, size)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable to determine object path")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rget_name() */
+
diff --git a/src/H5RS.c b/src/H5RS.c
new file mode 100644
index 0000000..0a3fff0
--- /dev/null
+++ b/src/H5RS.c
@@ -0,0 +1,497 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Reference counted string algorithms.
+ *
+ * These are used for various internal strings which get copied multiple times.
+ *
+ */
+
+
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5RSprivate.h" /* Reference-counted strings */
+
+/* Private typedefs & structs */
+struct H5RS_str_t {
+ char *s; /* String to be reference counted */
+ unsigned wrapped; /* Indicates that the string to be ref-counted is not copied */
+ unsigned n; /* Reference count of number of pointers sharing string */
+};
+
+/* Declare a free list to manage the H5RS_str_t struct */
+H5FL_DEFINE_STATIC(H5RS_str_t);
+
+/* Declare the PQ free list for the wrapped strings */
+H5FL_BLK_DEFINE(str_buf);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_xstrdup
+ PURPOSE
+ Duplicate the string being reference counted
+ USAGE
+ char *H5RS_xstrdup(s)
+ const char *s; IN: String to duplicate
+
+ RETURNS
+ Returns a pointer to a new string on success, NULL on failure.
+ DESCRIPTION
+ Duplicate a string buffer being reference counted. Use this instead of
+ [H5MM_][x]strdup, in order to use the free-list memory routines.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static char *
+H5RS_xstrdup(const char *s)
+{
+ char *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(s) {
+ size_t len = HDstrlen(s) + 1;
+
+ ret_value = (char *)H5FL_BLK_MALLOC(str_buf, len);
+ HDassert(ret_value);
+ HDstrncpy(ret_value, s, len);
+ } /* end if */
+ else
+ ret_value = NULL;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_xstrdup() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_create
+ PURPOSE
+ Create a reference counted string
+ USAGE
+ H5RS_str_t *H5RS_create(s)
+ const char *s; IN: String to initialize ref-counted string with
+
+ RETURNS
+ Returns a pointer to a new ref-counted string on success, NULL on failure.
+ DESCRIPTION
+ Create a reference counted string. The string passed in is copied into an
+ internal buffer.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5RS_str_t *
+H5RS_create(const char *s)
+{
+ H5RS_str_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate ref-counted string structure */
+ if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
+ HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the internal fields */
+ ret_value->s = H5RS_xstrdup(s);
+ ret_value->wrapped = 0;
+ ret_value->n = 1;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_wrap
+ PURPOSE
+ "Wrap" a reference counted string around an existing string
+ USAGE
+ H5RS_str_t *H5RS_wrap(s)
+ const char *s; IN: String to wrap ref-counted string around
+
+ RETURNS
+ Returns a pointer to a new ref-counted string on success, NULL on failure.
+ DESCRIPTION
+ Wrap a reference counted string around an existing string, which is not
+ duplicated, unless its reference count gets incremented.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5RS_str_t *
+H5RS_wrap(char *s)
+{
+ H5RS_str_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate ref-counted string structure */
+ if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
+ HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the internal fields */
+ ret_value->s = s;
+ ret_value->wrapped = 1;
+ ret_value->n = 1;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_wrap() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_own
+ PURPOSE
+ Transfer ownership of a regular string to a reference counted string
+ USAGE
+ H5RS_str_t *H5RS_own(s)
+ const char *s; IN: String to transfer ownership of
+
+ RETURNS
+ Returns a pointer to a new ref-counted string on success, NULL on failure.
+ DESCRIPTION
+ Transfer ownership of a dynamically allocated string to a reference counted
+ string. The routine which passed in the string should not attempt to free
+ it, the reference counting string routines will do that when the reference
+ count drops to zero.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5RS_str_t *
+H5RS_own(char *s)
+{
+ H5RS_str_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate ref-counted string structure */
+ if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
+ HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the internal fields */
+ ret_value->s = s;
+ ret_value->wrapped = 0;
+ ret_value->n = 1;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_own() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_decr
+ PURPOSE
+ Decrement the reference count for a ref-counted string
+ USAGE
+ herr_t H5RS_decr(rs)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to decrement count of
+
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Decrement the reference count for a reference counted string. If the
+ reference count drops to zero, the reference counted string is deleted.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5RS_decr(H5RS_str_t *rs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs);
+ HDassert(rs->n > 0);
+
+ /* Decrement reference count for string */
+ if((--rs->n) == 0) {
+ if(!rs->wrapped)
+ rs->s = (char *)H5FL_BLK_FREE(str_buf, rs->s);
+ rs = H5FL_FREE(H5RS_str_t, rs);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5RS_decr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_incr
+ PURPOSE
+ Increment the reference count for a ref-counted string
+ USAGE
+ herr_t H5RS_incr(rs)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to increment count of
+
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Increment the reference count for a reference counted string.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5RS_incr(H5RS_str_t *rs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs);
+ HDassert(rs->n > 0);
+
+ /* If the ref-counted string started life as a wrapper around an existing
+ * string, duplicate the string now, so that the wrapped string can go out
+ * scope appropriately.
+ */
+ if(rs->wrapped) {
+ rs->s = H5RS_xstrdup(rs->s);
+ rs->wrapped = 0;
+ } /* end if */
+
+ /* Increment reference count for string */
+ rs->n++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5RS_incr() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_dup
+ PURPOSE
+ "Duplicate" a ref-counted string
+ USAGE
+ H5RS_str_t H5RS_dup(rs)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to "duplicate"
+
+ RETURNS
+ Returns a pointer to ref-counted string on success, NULL on failure.
+ DESCRIPTION
+ Increment the reference count for the reference counted string and return
+ a pointer to it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5RS_str_t *
+H5RS_dup(H5RS_str_t *ret_value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check for valid reference counted string */
+ if(ret_value != NULL)
+ /* Increment reference count for string */
+ ret_value->n++;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_dup() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_dup_str
+ PURPOSE
+ "Duplicate" a regular string into a ref-counted string
+ USAGE
+ H5RS_str_t H5RS_dup_str(s)
+ const char *s; IN: Regular string to duplicate
+
+ RETURNS
+ Returns a pointer to ref-counted string on success, NULL on failure.
+ DESCRIPTION
+ Duplicate a regular string into a ref-counted string.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5RS_str_t *
+H5RS_dup_str(const char *s)
+{
+ char *new_str; /* Duplicate of string */
+ size_t path_len; /* Length of the path */
+ H5RS_str_t *ret_value;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(s);
+
+ /* Get the length of the string */
+ path_len = HDstrlen(s);
+
+ /* Allocate space for the string */
+ if(NULL == (new_str = (char *)H5FL_BLK_MALLOC(str_buf, path_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy name for full path */
+ HDstrncpy(new_str, s, (path_len + 1));
+
+ /* Create reference counted string for path */
+ ret_value = H5RS_own(new_str);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_dup_str() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_cmp
+ PURPOSE
+ Compare two ref-counted strings
+ USAGE
+ int H5RS_cmp(rs1,rs2)
+ const H5RS_str_t *rs1; IN: First Ref-counted string to compare
+ const H5RS_str_t *rs2; IN: Second Ref-counted string to compare
+
+ RETURNS
+ Returns positive, negative or 0 for comparison of two r-strings [same as
+ strcmp()]
+ DESCRIPTION
+ Compare two ref-counted strings and return a value indicating their sort
+ order [same as strcmp()]
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5RS_cmp(const H5RS_str_t *rs1, const H5RS_str_t *rs2)
+{
+ /* Can't return invalid value from this function */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs1);
+ HDassert(rs1->s);
+ HDassert(rs2);
+ HDassert(rs2->s);
+
+ FUNC_LEAVE_NOAPI(HDstrcmp(rs1->s, rs2->s))
+} /* end H5RS_cmp() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_len
+ PURPOSE
+ Compute the length of a ref-counted string
+ USAGE
+ ssize_t H5RS_cmp(rs)
+ const H5RS_str_t *rs; IN: Ref-counted string to compute length of
+
+ RETURNS
+ Returns non-negative value on success, negative value on failure
+ DESCRIPTION
+ Compute the length of a ref-counted string. [same as strlen()]
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+ssize_t
+H5RS_len(const H5RS_str_t *rs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs);
+ HDassert(rs->s);
+
+ FUNC_LEAVE_NOAPI((ssize_t)HDstrlen(rs->s))
+} /* end H5RS_len() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_get_str
+ PURPOSE
+ Get a pointer to the internal string contained in a ref-counted string
+ USAGE
+ char *H5RS_get_str(rs)
+ const H5RS_str_t *rs; IN: Ref-counted string to get internal string from
+
+ RETURNS
+ Returns a pointer to the internal string being ref-counted on success,
+ NULL on failure.
+ DESCRIPTION
+ Gets a pointer to the internal string being reference counted. This
+ pointer is volatile and might be invalid is further calls to the H5RS
+ API are made.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+char *
+H5RS_get_str(const H5RS_str_t *rs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs);
+ HDassert(rs->s);
+
+ FUNC_LEAVE_NOAPI(rs->s)
+} /* end H5RS_get_str() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS_get_count
+ PURPOSE
+ Get the reference count for a ref-counted string
+ USAGE
+ unsigned H5RS_get_count(rs)
+ const H5RS_str_t *rs; IN: Ref-counted string to get internal count from
+
+ RETURNS
+ Returns the number of references to the internal string being ref-counted on success,
+ 0 on failure.
+ DESCRIPTION
+ Gets the count of references to the reference counted string.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+unsigned
+H5RS_get_count(const H5RS_str_t *rs)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(rs);
+ HDassert(rs->n > 0);
+
+ FUNC_LEAVE_NOAPI(rs->n)
+} /* end H5RS_get_count() */
+
diff --git a/src/H5RSprivate.h b/src/H5RSprivate.h
new file mode 100644
index 0000000..f69624a
--- /dev/null
+++ b/src/H5RSprivate.h
@@ -0,0 +1,59 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5RS module
+ */
+#ifndef _H5RSprivate_H
+#define _H5RSprivate_H
+
+/**************************************/
+/* Public headers needed by this file */
+/**************************************/
+#ifdef LATER
+#include "H5RSpublic.h"
+#endif /* LATER */
+
+/***************************************/
+/* Private headers needed by this file */
+/***************************************/
+#include "H5private.h"
+
+/************/
+/* Typedefs */
+/************/
+
+/* Typedef for reference counted string (defined in H5RS.c) */
+typedef struct H5RS_str_t H5RS_str_t;
+
+/**********/
+/* Macros */
+/**********/
+
+/********************/
+/* Private routines */
+/********************/
+H5_DLL H5RS_str_t *H5RS_create(const char *s);
+H5_DLL H5RS_str_t *H5RS_wrap(char *s);
+H5_DLL H5RS_str_t *H5RS_own(char *s);
+H5_DLL herr_t H5RS_decr(H5RS_str_t *rs);
+H5_DLL herr_t H5RS_incr(H5RS_str_t *rs);
+H5_DLL H5RS_str_t *H5RS_dup(H5RS_str_t *s);
+H5_DLL H5RS_str_t *H5RS_dup_str(const char *s);
+H5_DLL int H5RS_cmp(const H5RS_str_t *rs1, const H5RS_str_t *rs2);
+H5_DLL ssize_t H5RS_len(const H5RS_str_t *rs);
+H5_DLL char *H5RS_get_str(const H5RS_str_t *rs);
+H5_DLL unsigned H5RS_get_count(const H5RS_str_t *rs);
+
+#endif /* _H5RSprivate_H */
+
diff --git a/src/H5Rdeprec.c b/src/H5Rdeprec.c
new file mode 100644
index 0000000..109bbb4
--- /dev/null
+++ b/src/H5Rdeprec.c
@@ -0,0 +1,189 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Rdeprec.c
+ * September 13 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5R interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Rmodule.h" /* This source code file is part of the H5R module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Rpkg.h" /* References */
+#include "H5Ppublic.h" /* for using H5P_DATASET_ACCESS_DEFAULT */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rget_obj_type1
+ PURPOSE
+ Retrieves the type of object that an object reference points to
+ USAGE
+ H5G_obj_t H5Rget_obj_type1(id, ref_type, ref)
+ hid_t id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ H5R_type_t ref_type; IN: Type of reference to query
+ void *ref; IN: Reference to query.
+
+ RETURNS
+ Success: An object type defined in H5Gpublic.h
+ Failure: H5G_UNKNOWN
+ DESCRIPTION
+ Given a reference to some object, this function returns the type of object
+ pointed to.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5G_obj_t
+H5Rget_obj_type1(hid_t id, H5R_type_t ref_type, const void *ref)
+{
+ H5G_loc_t loc; /* Object location */
+ H5O_type_t obj_type; /* Object type */
+ H5G_obj_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5G_UNKNOWN)
+ H5TRACE3("Go", "iRt*x", id, ref_type, ref);
+
+ /* Check args */
+ if(H5G_loc(id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "not a location")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5G_UNKNOWN, "invalid reference type")
+ if(ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5G_UNKNOWN, "invalid reference pointer")
+
+ /* Get the object information */
+ if(H5R_get_obj_type(loc.oloc->file, H5AC_ind_read_dxpl_id, ref_type, ref, &obj_type) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, H5G_UNKNOWN, "unable to determine object type")
+
+ /* Set return value */
+ ret_value = H5G_map_obj_type(obj_type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rget_obj_type1() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Rdereference1
+ PURPOSE
+ Opens the HDF5 object referenced.
+ USAGE
+ hid_t H5Rdereference1(ref)
+ hid_t id; IN: Dataset reference object is in or location ID of
+ object that the dataset is located within.
+ H5R_type_t ref_type; IN: Type of reference to create
+ void *ref; IN: Reference to open.
+
+ RETURNS
+ Valid ID on success, Negative on failure
+ DESCRIPTION
+ Given a reference to some object, open that object and return an ID for
+ that object.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Rdereference1(hid_t obj_id, H5R_type_t ref_type, const void *_ref)
+{
+ H5G_loc_t loc; /* Group location */
+ H5F_t *file = NULL; /* File object */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iRt*x", obj_id, ref_type, _ref);
+
+ /* Check args */
+ if(H5G_loc(obj_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(ref_type <= H5R_BADTYPE || ref_type >= H5R_MAXTYPE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
+ if(_ref == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference pointer")
+
+ /* Get the file pointer from the entry */
+ file = loc.oloc->file;
+
+ /* Create reference */
+ if((ret_value = H5R_dereference(file, H5P_DATASET_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id, ref_type, _ref, TRUE)) < 0)
+ HGOTO_ERROR(H5E_REFERENCE, H5E_CANTINIT, FAIL, "unable dereference object")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Rdereference1() */
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Rmodule.h b/src/H5Rmodule.h
new file mode 100644
index 0000000..2eaf050
--- /dev/null
+++ b/src/H5Rmodule.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5R package. Including this header means that the source file
+ * is part of the H5R package.
+ */
+#ifndef _H5Rmodule_H
+#define _H5Rmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5R_MODULE
+#define H5_MY_PKG H5R
+#define H5_MY_PKG_ERR H5E_REFERENCE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Rmodule_H */
+
+
diff --git a/src/H5Rpkg.h b/src/H5Rpkg.h
new file mode 100644
index 0000000..6d5036b
--- /dev/null
+++ b/src/H5Rpkg.h
@@ -0,0 +1,62 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Thursday, September 13, 2007
+ *
+ * Purpose: This file contains declarations which are visible
+ * only within the H5R package. Source files outside the
+ * H5R package should include H5Rprivate.h instead.
+ */
+#if !(defined H5R_FRIEND || defined H5R_MODULE)
+#error "Do not include this file outside the H5R package!"
+#endif
+
+#ifndef _H5Rpkg_H
+#define _H5Rpkg_H
+
+/* Get package's private header */
+#include "H5Rprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5Fprivate.h" /* File access */
+
+/**************************/
+/* Package Private Macros */
+/**************************/
+
+
+/****************************/
+/* Package Private Typedefs */
+/****************************/
+
+
+/*****************************/
+/* Package Private Variables */
+/*****************************/
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
+
+/* General functions */
+H5_DLL herr_t H5R_get_obj_type(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type,
+ const void *_ref, H5O_type_t *obj_type);
+H5_DLL hid_t H5R_dereference(H5F_t *file, hid_t dapl_id, hid_t dxpl_id, H5R_type_t ref_type,
+ const void *_ref, hbool_t app_ref);
+
+
+#endif /* _H5Rpkg_H */
+
diff --git a/src/H5Rprivate.h b/src/H5Rprivate.h
new file mode 100644
index 0000000..7efa225
--- /dev/null
+++ b/src/H5Rprivate.h
@@ -0,0 +1,29 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5R module
+ */
+#ifndef _H5Rprivate_H
+#define _H5Rprivate_H
+
+#include "H5Rpublic.h"
+
+/* Private headers needed by this file */
+
+/* Internal data structures */
+
+/* Private functions */
+
+#endif /* _H5Rprivate_H */
+
diff --git a/src/H5Rpublic.h b/src/H5Rpublic.h
new file mode 100644
index 0000000..446b7cd
--- /dev/null
+++ b/src/H5Rpublic.h
@@ -0,0 +1,91 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5R module.
+ */
+#ifndef _H5Rpublic_H
+#define _H5Rpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Gpublic.h"
+#include "H5Ipublic.h"
+
+/*
+ * Reference types allowed.
+ */
+typedef enum {
+ H5R_BADTYPE = (-1), /*invalid Reference Type */
+ H5R_OBJECT, /*Object reference */
+ H5R_DATASET_REGION, /*Dataset Region Reference */
+ H5R_MAXTYPE /*highest type (Invalid as true type) */
+} H5R_type_t;
+
+/* Note! Be careful with the sizes of the references because they should really
+ * depend on the run-time values in the file. Unfortunately, the arrays need
+ * to be defined at compile-time, so we have to go with the worst case sizes for
+ * them. -QAK
+ */
+#define H5R_OBJ_REF_BUF_SIZE sizeof(haddr_t)
+/* Object reference structure for user's code */
+typedef haddr_t hobj_ref_t; /* Needs to be large enough to store largest haddr_t in a worst case machine (ie. 8 bytes currently) */
+
+#define H5R_DSET_REG_REF_BUF_SIZE (sizeof(haddr_t)+4)
+/* 4 is used instead of sizeof(int) to permit portability between
+ the Crays and other machines (the heap ID is always encoded as an int32 anyway)
+*/
+/* Dataset Region reference structure for user's code */
+typedef unsigned char hdset_reg_ref_t[H5R_DSET_REG_REF_BUF_SIZE];/* Buffer to store heap ID and index */
+/* Needs to be large enough to store largest haddr_t in a worst case machine (ie. 8 bytes currently) plus an int */
+
+/* Publicly visible data structures */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions in H5R.c */
+H5_DLL herr_t H5Rcreate(void *ref, hid_t loc_id, const char *name,
+ H5R_type_t ref_type, hid_t space_id);
+H5_DLL hid_t H5Rdereference2(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, const void *ref);
+H5_DLL hid_t H5Rget_region(hid_t dataset, H5R_type_t ref_type, const void *ref);
+H5_DLL herr_t H5Rget_obj_type2(hid_t id, H5R_type_t ref_type, const void *_ref,
+ H5O_type_t *obj_type);
+H5_DLL ssize_t H5Rget_name(hid_t loc_id, H5R_type_t ref_type, const void *ref,
+ char *name/*out*/, size_t size);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+
+/* Typedefs */
+
+
+/* Function prototypes */
+H5_DLL H5G_obj_t H5Rget_obj_type1(hid_t id, H5R_type_t ref_type, const void *_ref);
+H5_DLL hid_t H5Rdereference1(hid_t obj_id, H5R_type_t ref_type, const void *ref);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H5Rpublic_H */
+
diff --git a/src/H5S.c b/src/H5S.c
new file mode 100644
index 0000000..dd390d9
--- /dev/null
+++ b/src/H5S.c
@@ -0,0 +1,2259 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Spkg.h" /* Dataspaces */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Version of dataspace encoding */
+#define H5S_ENCODE_VERSION 0
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static htri_t H5S_is_simple(const H5S_t *sdim);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5S_extent_t struct */
+H5FL_DEFINE(H5S_extent_t);
+
+/* Declare a free list to manage the H5S_t struct */
+H5FL_DEFINE(H5S_t);
+
+/* Declare a free list to manage the array's of hsize_t's */
+H5FL_ARR_DEFINE(hsize_t, H5S_MAX_RANK);
+
+/* Dataspace ID class */
+static const H5I_class_t H5I_DATASPACE_CLS[1] = {{
+ H5I_DATASPACE, /* ID class value */
+ 0, /* Class flags */
+ 2, /* # of reserved IDs for class */
+ (H5I_free_t)H5S_close /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5S_top_package_initialize_s = FALSE;
+
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5S__init_package -- Initialize interface-specific information
+USAGE
+ herr_t H5S__init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+--------------------------------------------------------------------------*/
+herr_t
+H5S__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Initialize the atom group for the file IDs */
+ if(H5I_register_type(H5I_DATASPACE_CLS) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Mark "top" of interface as initialized, too */
+ H5S_top_package_initialize_s = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__init_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_top_term_package
+ PURPOSE
+ Terminate various H5S objects
+ USAGE
+ void H5S_top_term_package()
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Release IDs for the atom group, deferring full interface shutdown
+ until later (in H5S_term_package).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5S_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5S_top_package_initialize_s) {
+ if(H5I_nmembers(H5I_DATASPACE) > 0) {
+ (void)H5I_clear_type(H5I_DATASPACE, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Mark "top" of interface as closed */
+ if(0 == n)
+ H5S_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5S_top_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_term_package
+ PURPOSE
+ Terminate various H5S objects
+ USAGE
+ void H5S_term_package()
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Release the atom group and any other resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+
+ Finishes shutting down the interface, after H5S_top_term_package()
+ is called
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5S_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity checks */
+ HDassert(0 == H5I_nmembers(H5I_DATASPACE));
+ HDassert(FALSE == H5S_top_package_initialize_s);
+
+ /* Destroy the dataspace object id group */
+ n += (H5I_dec_type_ref(H5I_DATASPACE) > 0);
+
+ /* Mark interface as closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5S_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_create
+ PURPOSE
+ Create empty, typed dataspace
+ USAGE
+ H5S_t *H5S_create(type)
+ H5S_type_t type; IN: Dataspace type to create
+ RETURNS
+ Pointer to dataspace on success, NULL on failure
+ DESCRIPTION
+ Creates a new dataspace of a given type. The extent is undefined and the
+ selection is set to the "all" selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5S_t *
+H5S_create(H5S_class_t type)
+{
+ H5S_t *new_ds = NULL; /* New dataspace created */
+ H5S_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Create a new dataspace */
+ if(NULL == (new_ds = H5FL_CALLOC(H5S_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Initialize default dataspace state */
+ new_ds->extent.type = type;
+ if(type == H5S_NULL)
+ new_ds->extent.version = H5O_SDSPACE_VERSION_2;
+ else
+ new_ds->extent.version = H5O_SDSPACE_VERSION_1;
+ new_ds->extent.rank = 0;
+ new_ds->extent.size = new_ds->extent.max = NULL;
+
+ switch(type) {
+ case H5S_SCALAR:
+ new_ds->extent.nelem = 1;
+ break;
+
+ case H5S_SIMPLE:
+ case H5S_NULL:
+ new_ds->extent.nelem = 0;
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown dataspace (extent) type" && 0);
+ break;
+ } /* end switch */
+
+ /* Start with "all" selection */
+ if(H5S_select_all(new_ds, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, NULL, "unable to set all selection")
+
+ /* Reset common selection info pointer */
+ new_ds->select.sel_info.hslab = NULL;
+
+ /* Reset "shared" info on extent */
+ if(H5O_msg_reset_share(H5O_SDSPACE_ID, &(new_ds->extent.sh_loc)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRESET, NULL, "unable to reset shared component info")
+
+ /* Set return value */
+ ret_value = new_ds;
+
+done:
+ if(ret_value == NULL) {
+ if(new_ds && H5S_close(new_ds) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Screate
+ PURPOSE
+ Create empty, typed dataspace
+ USAGE
+ hid_t H5Screate(type)
+ H5S_type_t type; IN: Dataspace type to create
+ RETURNS
+ Valid dataspace ID on success, negative on failure
+ DESCRIPTION
+ Creates a new dataspace of a given type. The extent & selection are
+ undefined
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Screate(H5S_class_t type)
+{
+ H5S_t *new_ds=NULL; /* New dataspace structure */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "Sc", type);
+
+ /* Check args */
+ if(type <= H5S_NO_CLASS || type > H5S_NULL) /* don't allow complex dataspace yet */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid dataspace type")
+
+ if(NULL == (new_ds = H5S_create(type)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace")
+
+ /* Atomize */
+ if((ret_value = H5I_register (H5I_DATASPACE, new_ds, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ if(ret_value < 0) {
+ if(new_ds && H5S_close(new_ds) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Screate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extent_release
+ *
+ * Purpose: Releases all memory associated with a dataspace extent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_extent_release(H5S_extent_t *extent)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(extent);
+
+ /* Release extent */
+ if(extent->type == H5S_SIMPLE) {
+ if(extent->size)
+ extent->size = H5FL_ARR_FREE(hsize_t, extent->size);
+ if(extent->max)
+ extent->max = H5FL_ARR_FREE(hsize_t, extent->max);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extent_release() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_close
+ *
+ * Purpose: Releases all memory associated with a dataspace.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_close(H5S_t *ds)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(ds);
+
+ /* Release selection (this should come before the extent release) */
+ if(H5S_SELECT_RELEASE(ds) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace selection")
+
+ /* Release extent */
+ if(H5S_extent_release(&ds->extent) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace extent")
+
+ /* Release the main structure */
+ ds = H5FL_FREE(H5S_t, ds);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sclose
+ *
+ * Purpose: Release access to a dataspace object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Errors:
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Sclose(hid_t space_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", space_id);
+
+ /* Check args */
+ if (NULL == H5I_object_verify(space_id,H5I_DATASPACE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* When the reference count reaches zero the resources are freed */
+ if(H5I_dec_app_ref(space_id) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDEC, FAIL, "problem freeing id")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Scopy
+ *
+ * Purpose: Copies a dataspace.
+ *
+ * Return: Success: ID of the new dataspace
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Scopy(hid_t space_id)
+{
+ H5S_t *src;
+ H5S_t *dst = NULL;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", space_id);
+
+ /* Check args */
+ if(NULL == (src = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Copy */
+ if(NULL == (dst = H5S_copy(src, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace")
+
+ /* Atomize */
+ if((ret_value = H5I_register (H5I_DATASPACE, dst, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ if(ret_value < 0) {
+ if(dst && H5S_close(dst) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Scopy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sextent_copy
+ *
+ * Purpose: Copies a dataspace extent.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Sextent_copy(hid_t dst_id,hid_t src_id)
+{
+ H5S_t *src;
+ H5S_t *dst;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "ii", dst_id, src_id);
+
+ /* Check args */
+ if(NULL == (src = (H5S_t *)H5I_object_verify(src_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(NULL == (dst = (H5S_t *)H5I_object_verify(dst_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Copy */
+ if(H5S_extent_copy(dst, src) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy extent")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sextent_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extent_copy
+ *
+ * Purpose: Copies a dataspace extent
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Monday, February 23, 2015
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_extent_copy(H5S_t *dst, const H5S_t *src)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dst);
+ HDassert(src);
+
+ /* Copy extent */
+ if(H5S_extent_copy_real(&(dst->extent), &(src->extent), TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy extent")
+
+ /* If the selection is 'all', update the number of elements selected in the
+ * destination space */
+ if(H5S_SEL_ALL == H5S_GET_SELECT_TYPE(dst))
+ if(H5S_select_all(dst, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extent_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extent_copy_real
+ *
+ * Purpose: Copies a dataspace extent
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 3, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_extent_copy_real(H5S_extent_t *dst, const H5S_extent_t *src, hbool_t copy_max)
+{
+ unsigned u;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Release destination extent before we copy over it */
+ if(H5S_extent_release(dst) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace extent")
+
+ /* Copy the regular fields */
+ dst->type = src->type;
+ dst->version = src->version;
+ dst->nelem = src->nelem;
+ dst->rank = src->rank;
+
+ switch (src->type) {
+ case H5S_NULL:
+ case H5S_SCALAR:
+ dst->size = NULL;
+ dst->max = NULL;
+ break;
+
+ case H5S_SIMPLE:
+ if(src->size) {
+ dst->size = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)src->rank);
+ for(u = 0; u < src->rank; u++)
+ dst->size[u] = src->size[u];
+ } /* end if */
+ else
+ dst->size = NULL;
+ if(copy_max && src->max) {
+ dst->max = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)src->rank);
+ for(u = 0; u < src->rank; u++)
+ dst->max[u] = src->max[u];
+ } /* end if */
+ else
+ dst->max = NULL;
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown dataspace type" && 0);
+ break;
+ } /* end switch */
+
+ /* Copy the shared object info */
+ if(H5O_set_shared(&(dst->sh_loc), &(src->sh_loc)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy shared information")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extent_copy_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_copy
+ *
+ * Purpose: Copies a dataspace, by copying the extent and selection through
+ * H5S_extent_copy and H5S_select_copy. If the SHARE_SELECTION flag
+ * is set, then the selection can be shared between the source and
+ * destination dataspaces. (This should only occur in situations
+ * where the destination dataspace will immediately change to a new
+ * selection)
+ *
+ * Return: Success: A pointer to a new copy of SRC
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_t *
+H5S_copy(const H5S_t *src, hbool_t share_selection, hbool_t copy_max)
+{
+ H5S_t *dst = NULL;
+ H5S_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(NULL == (dst = H5FL_CALLOC(H5S_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Copy the source dataspace's extent */
+ if(H5S_extent_copy_real(&(dst->extent), &(src->extent), copy_max) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy extent")
+
+ /* Copy the source dataspace's selection */
+ if(H5S_select_copy(dst, src, share_selection) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy select")
+
+ /* Set the return value */
+ ret_value = dst;
+
+done:
+ if(NULL == ret_value)
+ if(dst)
+ dst = H5FL_FREE(H5S_t, dst);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_get_simple_extent_npoints
+ *
+ * Purpose: Determines how many data points a dataset extent has.
+ *
+ * Return: Success: Number of data points in the dataset extent.
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ * Changed Name - QAK 7/7/98
+ *
+ *-------------------------------------------------------------------------
+ */
+hssize_t
+H5S_get_simple_extent_npoints(const H5S_t *ds)
+{
+ hssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(-1)
+
+ /* check args */
+ HDassert(ds);
+
+ /* Get the number of elements in extent */
+ ret_value = (hssize_t)ds->extent.nelem;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_get_simple_extent_npoints() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sget_simple_extent_npoints
+ *
+ * Purpose: Determines how many data points a dataset extent has.
+ *
+ * Return: Success: Number of data points in the dataset.
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ * Changed Name - QAK 7/7/98
+ *
+ *-------------------------------------------------------------------------
+ */
+hssize_t
+H5Sget_simple_extent_npoints(hid_t space_id)
+{
+ H5S_t *ds;
+ hssize_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Hs", "i", space_id);
+
+ /* Check args */
+ if(NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = (hssize_t)H5S_GET_EXTENT_NPOINTS(ds);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sget_simple_extent_npoints() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_get_npoints_max
+ *
+ * Purpose: Determines the maximum number of data points a dataspace may
+ * have. If the `max' array is null then the maximum number of
+ * data points is the same as the current number of data points
+ * without regard to the hyperslab. If any element of the `max'
+ * array is zero then the maximum possible size is returned.
+ *
+ * Return: Success: Maximum number of data points the dataspace
+ * may have.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5S_get_npoints_max(const H5S_t *ds)
+{
+ unsigned u;
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* check args */
+ HDassert(ds);
+
+ switch (H5S_GET_EXTENT_TYPE(ds)) {
+ case H5S_NULL:
+ ret_value = 0;
+ break;
+
+ case H5S_SCALAR:
+ ret_value = 1;
+ break;
+
+ case H5S_SIMPLE:
+ if (ds->extent.max) {
+ for (ret_value=1, u=0; u<ds->extent.rank; u++) {
+ if (H5S_UNLIMITED==ds->extent.max[u]) {
+ ret_value = HSIZET_MAX;
+ break;
+ }
+ else
+ ret_value *= ds->extent.max[u];
+ }
+ }
+ else {
+ for (ret_value=1, u=0; u<ds->extent.rank; u++)
+ ret_value *= ds->extent.size[u];
+ }
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown dataspace class" && 0);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, 0, "internal error (unknown dataspace class)")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sget_simple_extent_ndims
+ *
+ * Purpose: Determines the dimensionality of a dataspace.
+ *
+ * Return: Success: The number of dimensions in a dataspace.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Sget_simple_extent_ndims(hid_t space_id)
+{
+ H5S_t *ds;
+ int ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", space_id);
+
+ /* Check args */
+ if(NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = (int)H5S_GET_EXTENT_NDIMS(ds);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sget_simple_extent_ndims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_get_simple_extent_ndims
+ *
+ * Purpose: Returns the number of dimensions in a dataspace.
+ *
+ * Return: Success: Non-negative number of dimensions. Zero
+ * implies a scalar.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 11, 1997
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5S_get_simple_extent_ndims(const H5S_t *ds)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(ds);
+
+ switch(H5S_GET_EXTENT_TYPE(ds)) {
+ case H5S_NULL:
+ case H5S_SCALAR:
+ case H5S_SIMPLE:
+ ret_value = (int)ds->extent.rank;
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown dataspace class" && 0);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "internal error (unknown dataspace class)")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_get_simple_extent_ndims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sget_simple_extent_dims
+ *
+ * Purpose: Returns the size and maximum sizes in each dimension of
+ * a dataspace DS through the DIMS and MAXDIMS arguments.
+ *
+ * Return: Success: Number of dimensions, the same value as
+ * returned by H5Sget_simple_extent_ndims().
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 11, 1997
+ *
+ * Modifications:
+ * June 18, 1998 Albert Cheng
+ * Added maxdims argument. Removed dims argument check
+ * since it can still return ndims even if both dims and
+ * maxdims are NULLs.
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Sget_simple_extent_dims(hid_t space_id, hsize_t dims[]/*out*/,
+ hsize_t maxdims[]/*out*/)
+{
+ H5S_t *ds;
+ int ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Is", "ixx", space_id, dims, maxdims);
+
+ /* Check args */
+ if (NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = H5S_get_simple_extent_dims(ds, dims, maxdims);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extent_get_dims
+ *
+ * Purpose: Returns the size in each dimension of a dataspace. This
+ * function may not be meaningful for all types of dataspaces.
+ *
+ * Return: Success: Number of dimensions. Zero implies scalar.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 30, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5S_extent_get_dims(const H5S_extent_t *ext, hsize_t dims[], hsize_t max_dims[])
+{
+ int i; /* Local index variable */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(ext);
+
+ switch(ext->type) {
+ case H5S_NULL:
+ case H5S_SCALAR:
+ ret_value = 0;
+ break;
+
+ case H5S_SIMPLE:
+ ret_value = (int)ext->rank;
+ for(i = 0; i < ret_value; i++) {
+ if(dims)
+ dims[i] = ext->size[i];
+ if(max_dims) {
+ if(ext->max)
+ max_dims[i] = ext->max[i];
+ else
+ max_dims[i] = ext->size[i];
+ } /* end if */
+ } /* end for */
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown dataspace class" && 0);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "internal error (unknown dataspace class)")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extent_get_dims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_get_simple_extent_dims
+ *
+ * Purpose: Returns the size in each dimension of a dataspace. This
+ * function may not be meaningful for all types of dataspaces.
+ *
+ * Return: Success: Number of dimensions. Zero implies scalar.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5S_get_simple_extent_dims(const H5S_t *ds, hsize_t dims[], hsize_t max_dims[])
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(ds);
+
+ /* Get dims for extent */
+ if((ret_value = H5S_extent_get_dims(&ds->extent, dims, max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve dataspace extent dims")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_get_simple_extent_dims() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_write
+ *
+ * Purpose: Updates a dataspace by writing a message to an object
+ * header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_write(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned update_flags, H5S_t *ds)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(oh);
+ HDassert(ds);
+ HDassert(H5S_GET_EXTENT_TYPE(ds) >= 0);
+
+ /* Write the current dataspace extent to the dataspace message */
+ if(H5O_msg_write_oh(f, dxpl_id, oh, H5O_SDSPACE_ID, 0, update_flags, &(ds->extent)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update simple dataspace message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_append
+ *
+ * Purpose: Updates a dataspace by adding a message to an object
+ * header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 31, 2002
+ *
+ * Modifications:
+ *
+ * John Mainzer, 6/6/05
+ * Updated function to use the new dirtied parameter of
+ * H5AC_unprotect() instead of manipulating the is_dirty
+ * field of the cache info.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_append(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5S_t *ds)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(oh);
+ HDassert(ds);
+ HDassert(H5S_GET_EXTENT_TYPE(ds) >= 0);
+
+ /* Add the dataspace message to the object header */
+ if(H5O_msg_append_oh(f, dxpl_id, oh, H5O_SDSPACE_ID, 0, 0, &(ds->extent)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't add simple dataspace message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_append() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_read
+ *
+ * Purpose: Reads the dataspace from an object header.
+ *
+ * Return: Success: Pointer to a new dataspace.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_t *
+H5S_read(const H5O_loc_t *loc, hid_t dxpl_id)
+{
+ H5S_t *ds = NULL; /* Dataspace to return */
+ H5S_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(loc);
+
+ if(NULL == (ds = H5FL_CALLOC(H5S_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ if(H5O_msg_read(loc, H5O_SDSPACE_ID, &(ds->extent), dxpl_id) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to load dataspace info from dataset header")
+
+ /* Default to entire dataspace being selected */
+ if(H5S_select_all(ds, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, NULL, "unable to set all selection")
+
+ /* Set the value for successful return */
+ ret_value = ds;
+
+done:
+ if(ret_value == NULL) {
+ if(ds != NULL)
+ ds = H5FL_FREE(H5S_t, ds);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_read() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_is_simple
+ PURPOSE
+ Check if a dataspace is simple (internal)
+ USAGE
+ htri_t H5S_is_simple(sdim)
+ H5S_t *sdim; IN: Pointer to dataspace object to query
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ This function determines the if a dataspace is "simple". ie. if it
+ has orthogonal, evenly spaced dimensions.
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_is_simple(const H5S_t *sdim)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args and all the boring stuff. */
+ HDassert(sdim);
+
+ /* H5S_NULL shouldn't be simple dataspace */
+ ret_value = (H5S_GET_EXTENT_TYPE(sdim) == H5S_SIMPLE ||
+ H5S_GET_EXTENT_TYPE(sdim) == H5S_SCALAR) ? TRUE : FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_is_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sis_simple
+ PURPOSE
+ Check if a dataspace is simple
+ USAGE
+ htri_t H5Sis_simple(space_id)
+ hid_t space_id; IN: ID of dataspace object to query
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ This function determines the if a dataspace is "simple". ie. if it
+ has orthogonal, evenly spaced dimensions.
+--------------------------------------------------------------------------*/
+htri_t
+H5Sis_simple(hid_t space_id)
+{
+ H5S_t *space; /* dataspace to modify */
+ htri_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", space_id);
+
+ /* Check args and all the boring stuff. */
+ if ((space = (H5S_t *)H5I_object_verify(space_id,H5I_DATASPACE)) == NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "not a dataspace")
+
+ ret_value = H5S_is_simple(space);
+
+ done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sset_extent_simple
+ PURPOSE
+ Sets the size of a simple dataspace
+ USAGE
+ herr_t H5Sset_extent_simple(space_id, rank, dims, max)
+ hid_t space_id; IN: Dataspace object to query
+ int rank; IN: # of dimensions for the dataspace
+ const size_t *dims; IN: Size of each dimension for the dataspace
+ const size_t *max; IN: Maximum size of each dimension for the
+ dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function sets the number and size of each dimension in the
+ dataspace. Setting RANK to a value of zero converts the dataspace to a
+ scalar dataspace. Dimensions are specified from slowest to fastest
+ changing in the DIMS array (i.e. 'C' order). Setting the size of a
+ dimension in the MAX array to zero indicates that the dimension is of
+ unlimited size and should be allowed to expand. If MAX is NULL, the
+ dimensions in the DIMS array are used as the maximum dimensions.
+ Currently, only the first dimension in the array (the slowest) may be
+ unlimited in size.
+
+ MODIFICATION
+ A null dataspace cannot be created from simple space with this function.
+
+ Christian Chilan 01/17/2007
+ Verifies that each element of DIMS is not equal to H5S_UNLIMITED.
+
+ Raymond Lu 03/30/2011
+ We allow 0 dimension size for non-unlimited dimension starting from 1.8.7
+ release.
+--------------------------------------------------------------------------*/
+herr_t
+H5Sset_extent_simple(hid_t space_id, int rank, const hsize_t dims[/*rank*/],
+ const hsize_t max[/*rank*/])
+{
+ H5S_t *space; /* dataspace to modify */
+ int u; /* local counting variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iIs*[a1]h*[a1]h", space_id, rank, dims, max);
+
+ /* Check args */
+ if ((space = (H5S_t *)H5I_object_verify(space_id,H5I_DATASPACE)) == NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "not a dataspace")
+ if (rank > 0 && dims == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no dimensions specified")
+ if (rank<0 || rank>H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid rank")
+ if (dims) {
+ for (u=0; u<rank; u++) {
+ if (H5S_UNLIMITED==dims[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "current dimension must have a specific size, not H5S_UNLIMITED")
+ }
+ }
+ if (max!=NULL) {
+ if(dims==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "maximum dimension specified, but no current dimensions specified")
+ for (u=0; u<rank; u++) {
+ if (max[u]!=H5S_UNLIMITED && max[u]<dims[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid maximum dimension size")
+ }
+ }
+
+ /* Do it */
+ if (H5S_set_extent_simple(space, (unsigned)rank, dims, max)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set simple extent")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_set_extent_simple
+ *
+ * Purpose: This is where the real work happens for
+ * H5Sset_extent_simple().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke (copied from H5Sset_extent_simple)
+ * Wednesday, July 8, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_set_extent_simple(H5S_t *space, unsigned rank, const hsize_t *dims,
+ const hsize_t *max)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(rank <= H5S_MAX_RANK);
+ HDassert(0 == rank || dims);
+
+ /* shift out of the previous state to a "simple" dataspace. */
+ if(H5S_extent_release(&space->extent) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "failed to release previous dataspace extent")
+
+ if(rank == 0) { /* scalar variable */
+ space->extent.type = H5S_SCALAR;
+ space->extent.nelem = 1;
+ space->extent.rank = 0; /* set to scalar rank */
+ } /* end if */
+ else {
+ hsize_t nelem; /* Number of elements in extent */
+
+ space->extent.type = H5S_SIMPLE;
+
+ /* Set the rank and allocate space for the dims */
+ space->extent.rank = rank;
+ space->extent.size = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)rank);
+
+ /* Copy the dimensions & compute the number of elements in the extent */
+ for(u = 0, nelem = 1; u < space->extent.rank; u++) {
+ space->extent.size[u] = dims[u];
+ nelem *= dims[u];
+ } /* end for */
+ space->extent.nelem = nelem;
+
+ /* Copy the maximum dimensions if specified. Otherwise, the maximal dimensions are the
+ * same as the dimension */
+ space->extent.max = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, (size_t)rank);
+ if(max != NULL) {
+ HDmemcpy(space->extent.max, max, sizeof(hsize_t) * rank);
+ } else {
+ for(u = 0; u < space->extent.rank; u++)
+ space->extent.max[u] = dims[u];
+ }
+ } /* end else */
+
+ /* Selection related cleanup */
+
+ /* Set offset to zeros */
+ for(u = 0; u < space->extent.rank; u++)
+ space->select.offset[u] = 0;
+ space->select.offset_changed = FALSE;
+
+ /* If the selection is 'all', update the number of elements selected */
+ if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_ALL)
+ if(H5S_select_all(space, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_set_extent_simple() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Screate_simple
+ *
+ * Purpose: Creates a new simple dataspace object and opens it for
+ * access. The DIMS argument is the size of the simple dataset
+ * and the MAXDIMS argument is the upper limit on the size of
+ * the dataset. MAXDIMS may be the null pointer in which case
+ * the upper limit is the same as DIMS. If an element of
+ * MAXDIMS is H5S_UNLIMITED then the corresponding dimension is
+ * unlimited, otherwise no element of MAXDIMS should be smaller
+ * than the corresponding element of DIMS.
+ *
+ * Return: Success: The ID for the new simple dataspace object.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, January 27, 1998
+ *
+ * Modification:
+ * Raymond Lu 03/30/2011
+ * We allow 0-dimension for non-unlimited dimension starting
+ * from 1.8.7 release.
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Screate_simple(int rank, const hsize_t dims[/*rank*/],
+ const hsize_t maxdims[/*rank*/])
+{
+ H5S_t *space = NULL;
+ int i;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "Is*[a0]h*[a0]h", rank, dims, maxdims);
+
+ /* Check arguments */
+ if(rank < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality cannot be negative")
+ if(rank > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality is too large")
+
+ /* We allow users to use this function to create scalar or null dataspace.
+ * Check DIMS isn't set when the RANK is 0.
+ */
+ if(!dims && rank != 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid dataspace information")
+
+ /* Check whether the current dimensions are valid */
+ for(i = 0; i < rank; i++) {
+ if(H5S_UNLIMITED == dims[i])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "current dimension must have a specific size, not H5S_UNLIMITED")
+ if(maxdims && H5S_UNLIMITED != maxdims[i] && maxdims[i]<dims[i])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "maxdims is smaller than dims")
+ } /* end for */
+
+ /* Create the space and set the extent */
+ if(NULL == (space = H5S_create_simple((unsigned)rank,dims,maxdims)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Atomize */
+ if((ret_value = H5I_register (H5I_DATASPACE, space, TRUE)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+
+done:
+ if(ret_value < 0) {
+ if(space && H5S_close(space) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Screate_simple() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_create_simple
+ *
+ * Purpose: Internal function to create simple dataspace
+ *
+ * Return: Success: The ID for the new simple dataspace object.
+ * Failure: Negative
+ *
+ * Errors:
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 3, 2003
+ *
+ * Modifications:
+ * Extracted from H5Screate_simple
+ * Quincey Koziol, Thursday, April 3, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_t *
+H5S_create_simple(unsigned rank, const hsize_t dims[/*rank*/],
+ const hsize_t maxdims[/*rank*/])
+{
+ H5S_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check arguments */
+ HDassert(rank <=H5S_MAX_RANK);
+
+ /* Create the space and set the extent */
+ if(NULL==(ret_value=H5S_create(H5S_SIMPLE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "can't create simple dataspace")
+ if(H5S_set_extent_simple(ret_value,rank,dims,maxdims)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "can't set dimensions")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_create_simple() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sencode
+ *
+ * Purpose: Given a dataspace ID, converts the object description
+ * (including selection) into binary in a buffer.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Sencode(hid_t obj_id, void *buf, size_t *nalloc)
+{
+ H5S_t *dspace;
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x*z", obj_id, buf, nalloc);
+
+ /* Check argument and retrieve object */
+ if (NULL==(dspace=(H5S_t *)H5I_object_verify(obj_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ if(H5S_encode(dspace, (unsigned char **)&buf, nalloc)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTENCODE, FAIL, "can't encode dataspace")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_encode
+ *
+ * Purpose: Private function for H5Sencode. Converts an object
+ * description for dataspace and its selection into binary
+ * in a buffer.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_encode(H5S_t *obj, unsigned char **p, size_t *nalloc)
+{
+ H5F_t *f = NULL; /* Fake file structure*/
+ size_t extent_size; /* Size of serialized dataspace extent */
+ hssize_t sselect_size; /* Signed size of serialized dataspace selection */
+ size_t select_size; /* Size of serialized dataspace selection */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate "fake" file structure */
+ if(NULL == (f = H5F_fake_alloc((uint8_t)0)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate fake file struct")
+
+ /* Find out the size of buffer needed for extent */
+ if((extent_size = H5O_msg_raw_size(f, H5O_SDSPACE_ID, TRUE, obj)) == 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSIZE, FAIL, "can't find dataspace size")
+
+ /* Find out the size of buffer needed for selection */
+ if((sselect_size = H5S_SELECT_SERIAL_SIZE(obj)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSIZE, FAIL, "can't find dataspace selection size")
+ H5_CHECKED_ASSIGN(select_size, size_t, sselect_size, hssize_t);
+
+ /* Verify the size of buffer. If it's not big enough, simply return the
+ * right size without filling the buffer. */
+ if(!*p || *nalloc < (extent_size + select_size + 1 + 1 + 1 + 4))
+ *nalloc = extent_size + select_size + 1 + 1 + 1 + 4;
+ else {
+ unsigned char *pp = (*p); /* Local pointer for decoding */
+
+ /* Encode the type of the information */
+ *pp++ = H5O_SDSPACE_ID;
+
+ /* Encode the version of the dataspace information */
+ *pp++ = H5S_ENCODE_VERSION;
+
+ /* Encode the "size of size" information */
+ *pp++ = (unsigned char)H5F_SIZEOF_SIZE(f);
+
+ /* Encode size of extent information. Pointer is actually moved in this macro. */
+ UINT32ENCODE(pp, extent_size);
+
+ /* Encode the extent part of dataspace */
+ if(H5O_msg_encode(f, H5O_SDSPACE_ID, TRUE, pp, obj) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTENCODE, FAIL, "can't encode extent space")
+ pp += extent_size;
+
+ /* Encode the selection part of dataspace. */
+ *p = pp;
+ if(H5S_SELECT_SERIALIZE(obj, p) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTENCODE, FAIL, "can't encode select space")
+ } /* end else */
+
+done:
+ /* Release fake file structure */
+ if(f && H5F_fake_free(f) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release fake file struct")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sdecode
+ *
+ * Purpose: Decode a binary object description of dataspace and
+ * return a new object handle.
+ *
+ * Return: Success: dataspace ID(non-negative)
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Sdecode(const void *buf)
+{
+ H5S_t *ds;
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "*x", buf);
+
+ if(buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "empty buffer")
+
+ if((ds = H5S_decode((const unsigned char **)&buf)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDECODE, FAIL, "can't decode object")
+
+ /* Register the type and return the ID */
+ if((ret_value = H5I_register(H5I_DATASPACE, ds, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTREGISTER, FAIL, "unable to register dataspace")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sdecode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_decode
+ *
+ * Purpose: Private function for H5Sdecode. Reconstructs a binary
+ * description of dataspace and returns a new object handle.
+ *
+ * Return: Success: dataspace ID(non-negative)
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_t*
+H5S_decode(const unsigned char **p)
+{
+ H5F_t *f = NULL; /* Fake file structure*/
+ H5S_t *ds; /* Decoded dataspace */
+ H5S_extent_t *extent; /* Entent of decoded dataspace */
+ const unsigned char *pp = (*p); /* Local pointer for decoding */
+ size_t extent_size; /* size of the extent message*/
+ uint8_t sizeof_size; /* 'Size of sizes' for file */
+ H5S_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Decode the type of the information */
+ if(*pp++ != H5O_SDSPACE_ID)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADMESG, NULL, "not an encoded dataspace")
+
+ /* Decode the version of the dataspace information */
+ if(*pp++ != H5S_ENCODE_VERSION)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_VERSION, NULL, "unknown version of encoded dataspace")
+
+ /* Decode the "size of size" information */
+ sizeof_size = *pp++;
+
+ /* Allocate "fake" file structure */
+ if(NULL == (f = H5F_fake_alloc(sizeof_size)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate fake file struct")
+
+ /* Decode size of extent information */
+ UINT32DECODE(pp, extent_size);
+
+ /* Decode the extent part of dataspace */
+ /* (pass mostly bogus file pointer and bogus DXPL) */
+ if((extent = (H5S_extent_t *)H5O_msg_decode(f, H5P_DEFAULT, NULL, H5O_SDSPACE_ID, pp))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDECODE, NULL, "can't decode object")
+ pp += extent_size;
+
+ /* Copy the extent into dataspace structure */
+ if((ds = H5FL_CALLOC(H5S_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for dataspace conversion path table")
+ if(H5O_msg_copy(H5O_SDSPACE_ID, extent, &(ds->extent)) == NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy object")
+ if(H5S_extent_release(extent) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTDELETE, NULL, "can't release previous dataspace")
+ extent = H5FL_FREE(H5S_extent_t, extent);
+
+ /* Initialize to "all" selection. Deserialization relies on valid existing selection. */
+ if(H5S_select_all(ds, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, NULL, "unable to set all selection")
+
+ /* Decode the select part of dataspace. I believe this part always exists. */
+ *p = pp;
+ if(H5S_SELECT_DESERIALIZE(&ds, p) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDECODE, NULL, "can't decode space selection")
+
+ /* Set return value */
+ ret_value = ds;
+
+done:
+ /* Release fake file structure */
+ if(f && H5F_fake_free(f) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release fake file struct")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_get_simple_extent_type
+ *
+ * Purpose: Internal function for retrieving the type of extent for a dataspace object
+ *
+ * Return: Success: The class of the dataspace object
+ *
+ * Failure: N5S_NO_CLASS
+ *
+ * Errors:
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 28, 2000
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_class_t
+H5S_get_simple_extent_type(const H5S_t *space)
+{
+ H5S_class_t ret_value = H5S_NO_CLASS; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5S_NO_CLASS)
+
+ HDassert(space);
+
+ ret_value=H5S_GET_EXTENT_TYPE(space);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sget_simple_extent_type
+ *
+ * Purpose: Retrieves the type of extent for a dataspace object
+ *
+ * Return: Success: The class of the dataspace object
+ *
+ * Failure: N5S_NO_CLASS
+ *
+ * Errors:
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5S_class_t
+H5Sget_simple_extent_type(hid_t sid)
+{
+ H5S_t *space;
+ H5S_class_t ret_value;
+
+ FUNC_ENTER_API(H5S_NO_CLASS)
+ H5TRACE1("Sc", "i", sid);
+
+ /* Check arguments */
+ if (NULL == (space = (H5S_t *)H5I_object_verify(sid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5S_NO_CLASS, "not a dataspace")
+
+ ret_value=H5S_GET_EXTENT_TYPE(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sset_extent_none
+ PURPOSE
+ Resets the extent of a dataspace back to "none"
+ USAGE
+ herr_t H5Sset_extent_none(space_id)
+ hid_t space_id; IN: Dataspace object to reset
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function resets the type of a dataspace back to "none" with no
+ extent information stored for the dataspace.
+--------------------------------------------------------------------------*/
+herr_t
+H5Sset_extent_none(hid_t space_id)
+{
+ H5S_t *space; /* dataspace to modify */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", space_id);
+
+ /* Check args */
+ if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "not a dataspace")
+
+ /* Clear the previous extent from the dataspace */
+ if(H5S_extent_release(&space->extent)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTDELETE, FAIL, "can't release previous dataspace")
+
+ space->extent.type=H5S_NO_CLASS;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sset_extent_none() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Soffset_simple
+ PURPOSE
+ Changes the offset of a selection within a simple dataspace extent
+ USAGE
+ herr_t H5Soffset_simple(space_id, offset)
+ hid_t space_id; IN: Dataspace object to reset
+ const hssize_t *offset; IN: Offset to position the selection at
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function creates an offset for the selection within an extent, allowing
+ the same shaped selection to be moved to different locations within a
+ dataspace without requiring it to be re-defined.
+--------------------------------------------------------------------------*/
+herr_t
+H5Soffset_simple(hid_t space_id, const hssize_t *offset)
+{
+ H5S_t *space; /* dataspace to modify */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Hs", space_id, offset);
+
+ /* Check args */
+ if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "not a dataspace")
+ if (space->extent.rank==0 || (H5S_GET_EXTENT_TYPE(space)==H5S_SCALAR
+ || H5S_GET_EXTENT_TYPE(space)==H5S_NULL))
+ HGOTO_ERROR(H5E_ATOM, H5E_UNSUPPORTED, FAIL, "can't set offset on scalar or null dataspace")
+ if (offset == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no offset specified")
+
+ /* Set the selection offset */
+ if(H5S_select_offset(space,offset)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set offset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Soffset_simple() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_set_extent
+ *
+ * Purpose: Modify the dimensions of a dataspace. Based on H5S_extend
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * March 13, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5S_set_extent(H5S_t *space, const hsize_t *size)
+{
+ unsigned u; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space && H5S_SIMPLE == H5S_GET_EXTENT_TYPE(space));
+ HDassert(size);
+
+ /* Verify that the dimensions being changed are allowed to change */
+ for(u = 0; u < space->extent.rank; u++) {
+ if(space->extent.size[u] != size[u]) {
+ /* Check for invalid dimension size modification */
+ if(space->extent.max && H5S_UNLIMITED != space->extent.max[u] &&
+ space->extent.max[u] < size[u])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "dimension cannot exceed the existing maximal size (new: %llu max: %llu)", (unsigned long long)size[u], (unsigned long long)space->extent.max[u])
+
+ /* Indicate that dimension size can be modified */
+ ret_value = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* Update dimension size(s) */
+ if(ret_value)
+ if(H5S_set_extent_real(space, size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "failed to change dimension size(s)")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_set_extent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_has_extent
+ *
+ * Purpose: Determines if a simple dataspace's extent has been set (e.g.,
+ * by H5Sset_extent_simple() ). Helps avoid write errors.
+ *
+ * Return: TRUE if dataspace has extent set
+ * FALSE if dataspace's extent is uninitialized
+ *
+ * Programmer: James Laird
+ *
+ * Date: July 23, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5S_has_extent(const H5S_t *ds)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(ds);
+
+ if(0 == ds->extent.rank && 0 == ds->extent.nelem && H5S_NULL != ds->extent.type)
+ ret_value = FALSE;
+ else
+ ret_value = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_has_extent() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_set_extent_real
+ *
+ * Purpose: Modify the dimensions of a dataspace. Based on H5S_extend
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
+ * March 13, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_set_extent_real(H5S_t *space, const hsize_t *size)
+{
+ hsize_t nelem; /* Number of elements in extent */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space && H5S_SIMPLE == H5S_GET_EXTENT_TYPE(space));
+ HDassert(size);
+
+ /* Change the dataspace size & re-compute the number of elements in the extent */
+ for(u = 0, nelem = 1; u < space->extent.rank; u++ ) {
+ space->extent.size[u] = size[u];
+ nelem *= size[u];
+ } /* end for */
+ space->extent.nelem = nelem;
+
+ /* If the selection is 'all', update the number of elements selected */
+ if(H5S_SEL_ALL == H5S_GET_SELECT_TYPE(space))
+ if(H5S_select_all(space, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+ /* Mark the dataspace as no longer shared if it was before */
+ if(H5O_msg_reset_share(H5O_SDSPACE_ID, space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRESET, FAIL, "can't stop sharing dataspace")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_set_extent_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Sextent_equal
+ *
+ * Purpose: Determines if two dataspace extents are equal.
+ *
+ * Return: Success: TRUE if equal, FALSE if unequal
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, October 24, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Sextent_equal(hid_t space1_id, hid_t space2_id)
+{
+ const H5S_t *ds1, *ds2; /* Dataspaces to compare */
+ htri_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "ii", space1_id, space2_id);
+
+ /* check args */
+ if(NULL == (ds1 = (const H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)) ||
+ NULL == (ds2 = (const H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Check dataspaces for extent's equality */
+ if((ret_value = H5S_extent_equal(ds1, ds2)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "dataspace comparison failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sextent_equal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_extent_equal
+ PURPOSE
+ Check if two dataspaces have equal extents
+ USAGE
+ htri_t H5S_extent_equal(ds1, ds2)
+ H5S_t *ds1, *ds2; IN: Dataspace objects to compare
+ RETURNS
+ TRUE if equal, FALSE if unequal on succeess/Negative on failure
+ DESCRIPTION
+ Compare two dataspaces if their extents are identical.
+--------------------------------------------------------------------------*/
+htri_t
+H5S_extent_equal(const H5S_t *ds1, const H5S_t *ds2)
+{
+ unsigned u; /* Local index variable */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(ds1);
+ HDassert(ds2);
+
+ /* Make certain the dataspaces are the same type */
+ if(ds1->extent.type != ds2->extent.type)
+ HGOTO_DONE(FALSE)
+
+ /* Make certain the dataspaces are the same rank */
+ if(ds1->extent.rank != ds2->extent.rank)
+ HGOTO_DONE(FALSE)
+
+ /* Make certain the dataspaces' current dimensions are the same size */
+ if(ds1->extent.rank > 0) {
+ HDassert(ds1->extent.size);
+ HDassert(ds2->extent.size);
+ for(u = 0; u < ds1->extent.rank; u++)
+ if(ds1->extent.size[u] != ds2->extent.size[u])
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* Make certain the dataspaces' maximum dimensions are the same size */
+ if(ds1->extent.rank > 0) {
+ /* Check for no maximum dimensions on dataspaces */
+ if(ds1->extent.max != NULL && ds2->extent.max != NULL) {
+ for(u = 0; u < ds1->extent.rank; u++)
+ if(ds1->extent.max[u] != ds2->extent.max[u])
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else
+ if((ds1->extent.max == NULL && ds2->extent.max != NULL) ||
+ (ds1->extent.max != NULL && ds2->extent.max == NULL))
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extent_equal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extent_nelem
+ *
+ * Purpose: Determines how many elements a dataset extent describes.
+ *
+ * Return: Success: Number of data points in the dataset extent.
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 30, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5S_extent_nelem(const H5S_extent_t *ext)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(ext);
+
+ /* Return the number of elements in extent */
+ FUNC_LEAVE_NOAPI(ext->nelem)
+} /* end H5S_extent_nelem() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_set_latest_version
+ *
+ * Purpose: Set the encoding for a dataspace to the latest version.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 24, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_set_latest_version(H5S_t *ds)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(ds);
+
+ /* Set encoding of extent to latest version */
+ ds->extent.version = H5O_SDSPACE_VERSION_LATEST;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_set_latest_version() */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_extend
+ *
+ * Purpose: Extend the dimensions of a dataspace.
+ *
+ * Return: Success: Number of dimensions whose size increased.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 30, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5S_extend(H5S_t *space, const hsize_t *size)
+{
+ unsigned u;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space && H5S_SIMPLE == H5S_GET_EXTENT_TYPE(space));
+ HDassert(size);
+
+ /* Check through all the dimensions to see if modifying the dataspace is allowed */
+ for(u = 0; u < space->extent.rank; u++)
+ if(space->extent.size[u] < size[u]) {
+ if(space->extent.max && H5S_UNLIMITED != space->extent.max[u] &&
+ space->extent.max[u] < size[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimension cannot be increased")
+ ret_value++;
+ } /* end if */
+
+ /* Update */
+ if(ret_value) {
+ hsize_t nelem; /* Number of elements in extent */
+
+ /* Change the dataspace size & re-compute the number of elements in the extent */
+ for(u = 0, nelem = 1; u < space->extent.rank; u++) {
+ if(space->extent.size[u] < size[u])
+ space->extent.size[u] = size[u];
+
+ nelem *= space->extent.size[u];
+ } /* end for */
+ space->extent.nelem = nelem;
+
+ /* If the selection is 'all', update the number of elements selected */
+ if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_ALL)
+ if(H5S_select_all(space, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+ /* Mark the dataspace as no longer shared if it was before */
+ if(H5O_msg_reset_share(H5O_SDSPACE_ID, space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRESET, FAIL, "can't stop sharing dataspace")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_extend() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5SL.c b/src/H5SL.c
new file mode 100644
index 0000000..c0934ca
--- /dev/null
+++ b/src/H5SL.c
@@ -0,0 +1,2571 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Provides a skip list abstract data type.
+ *
+ * (See "Deterministic Skip Lists" by Munro, Papadakis & Sedgewick)
+ *
+ * (Implementation changed to a deterministic skip list from a
+ * probabilistic one. This implementation uses a 1-2-3 skip list
+ * using arrays, as described by Munro, Papadakis & Sedgewick.
+ *
+ * Arrays are allocated using a free list factory for each size
+ * that is a power of two. Factories are created as soon as they
+ * are needed, and are never destroyed until the package is shut
+ * down. There is no longer a maximum level or "p" value.
+ * -NAF 2008/11/05)
+ *
+ * (See "Skip Lists: A Probabilistic Alternative to Balanced Trees"
+ * by William Pugh for additional information)
+ *
+ * (This implementation has the optimization for reducing key
+ * key comparisons mentioned in section 3.5 of "A Skip List
+ * Cookbook" by William Pugh
+ * -Removed as our implementation of this was useless for a 1-2-3
+ * skip list. The implementation in that document hurts
+ * performance, at least for integer keys. -NAF)
+ *
+ * (Also, this implementation has a couple of home-grown
+ * optimizations, including setting the "update" vector to the
+ * actual 'forward' pointer to update, instead of the node
+ * containing the forward pointer -QAK
+ * -No longer uses update vector, as insertions/deletions are now
+ * always at level 0. -NAF)
+ *
+ * (Note: This implementation does not have the information for
+ * implementing the "Linear List Operations" (like insert/delete/
+ * search by position) in section 3.4 of "A Skip List Cookbook",
+ * but they shouldn't be that hard to add, if necessary)
+ *
+ * (This implementation has an additional backward pointer, which
+ * allows the list to be iterated in reverse)
+ *
+ * (There's also an article on "Alternating Skip Lists", which
+ * are similar to deterministic skip lists, in the August 2000
+ * issue of Dr. Dobb's Journal)
+ *
+ */
+
+#include "H5SLmodule.h" /* This source code file is part of the H5SL module */
+
+
+/* Private headers needed */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5SLprivate.h" /* Skip list routines */
+
+/* Local Macros */
+
+/* Define the code template for searches for the "OP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_SEARCH_FOUND(SLIST, X, I) \
+{ \
+ HDassert(!X->removed); \
+ HGOTO_DONE(X->item); \
+} /* end block */
+
+/* Define the code template for deferred removals for the "OP" in the
+ * H5SL_LOCATE macro */
+#define H5SL_LOCATE_SEARCH_DEFER_REMOVE_FOUND(SLIST, X, I) \
+{ \
+ HDassert(!X->removed); \
+ X->removed = TRUE; \
+ HGOTO_DONE(X->item); \
+} /* end block */
+
+/* Define the code template for finds for the "OP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_FIND_FOUND(SLIST, X, I) \
+{ \
+ HDassert(!X->removed); \
+ HGOTO_DONE(X); \
+} /* end block */
+
+
+/* Define a code template for comparing scalar keys for the "CMP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_SCALAR_CMP(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ (*(TYPE *)((PNODE)->key) < *(TYPE *)PKEY)
+
+/* Define a code template for comparing string keys for the "CMP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_STRING_CMP(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ (((PNODE)->hashval == HASHVAL) ? \
+ (HDstrcmp((const char *)(PNODE)->key, (const char *)PKEY) < 0) : \
+ ((PNODE)->hashval < HASHVAL))
+
+/* Define a code template for comparing H5_obj_t keys for the "CMP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_OBJ_CMP(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ ((((TYPE *)((PNODE)->key))->fileno == ((TYPE *)PKEY)->fileno) \
+ ? (((TYPE *)((PNODE)->key))->addr < ((TYPE *)PKEY)->addr) \
+ : (((TYPE *)((PNODE)->key))->fileno < ((TYPE *)PKEY)->fileno))
+
+/* Define a code template for comparing generic keys for the "CMP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_GENERIC_CMP(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ ((SLIST)->cmp((TYPE *)((PNODE)->key), (TYPE *)PKEY) < 0)
+
+
+/* Define a code template for comparing scalar keys for the "EQ" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_SCALAR_EQ(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ (*(TYPE *)((PNODE)->key) == *(TYPE *)PKEY)
+
+/* Define a code template for comparing string keys for the "EQ" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_STRING_EQ(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ (((PNODE)->hashval == HASHVAL) && (HDstrcmp((const char *)(PNODE)->key, (const char *)PKEY) == 0))
+
+/* Define a code template for comparing H5_obj_t keys for the "EQ" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_OBJ_EQ(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ ((((TYPE *)((PNODE)->key))->fileno == ((TYPE *)PKEY)->fileno) && (((TYPE *)((PNODE)->key))->addr == ((TYPE *)PKEY)->addr))
+
+/* Define a code template for comparing generic keys for the "EQ" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_GENERIC_EQ(SLIST, TYPE, PNODE, PKEY, HASHVAL) \
+ ((SLIST)->cmp((TYPE *)((PNODE)->key), (TYPE *)PKEY) == 0)
+
+
+/* Define a code template for initializing the hash value for scalar keys for the "HASHINIT" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_SCALAR_HASHINIT(KEY, HASHVAL)
+
+/* Define a code template for initializing the hash value for string keys for the "HASHINIT" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_STRING_HASHINIT(KEY, HASHVAL) \
+ HASHVAL = H5_hash_string((const char *)KEY);
+
+/* Define a code template for initializing the hash value for H5_obj_t keys for the "HASHINIT" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_OBJ_HASHINIT(KEY, HASHVAL)
+
+/* Define a code template for initializing the hash value for generic keys for the "HASHINIT" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_GENERIC_HASHINIT(KEY, HASHVAL)
+
+
+/* Macro used to find node for operation, if all keys are valid */
+#define H5SL_LOCATE_OPT(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+{ \
+ int _i; /* Local index variable */ \
+ unsigned _count; /* Num nodes searched at this height */ \
+ \
+ H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \
+ for(_i = (int)SLIST->curr_level; _i >= 0; _i--) { \
+ _count = 0; \
+ while(_count < 3 && X->forward[_i] && \
+ H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, X->forward[_i], KEY, HASHVAL) ) { \
+ X = X->forward[_i]; \
+ _count++; \
+ } /* end while */ \
+ } /* end for */ \
+ X = X->forward[0]; \
+ if(X != NULL && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(SLIST, TYPE, X, KEY, HASHVAL) ) { \
+ /* What to do when a node is found */ \
+ H5_GLUE3(H5SL_LOCATE_,OP,_FOUND)(SLIST, X, _i) \
+ } /* end if */ \
+}
+
+/* Macro used to find node for operation, if there may be "removed" nodes in the
+ * list (whose keys cannot be read) */
+#define H5SL_LOCATE_SAFE(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+{ \
+ int _i; /* Local index variable */ \
+ H5SL_node_t *_low = X; \
+ H5SL_node_t *_high = NULL; \
+ \
+ H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \
+ for(_i = (int)SLIST->curr_level; _i >= 0; _i--) { \
+ X = _low->forward[_i]; \
+ while(X != _high) { \
+ if(!X->removed) { \
+ if(H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, X, KEY, HASHVAL)) \
+ _low = X; \
+ else \
+ break; \
+ } /* end if */ \
+ X = X->forward[_i]; \
+ } /* end while */ \
+ _high = X; \
+ if(X != NULL && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(SLIST, TYPE, X, KEY, HASHVAL) ) { \
+ /* What to do when a node is found */ \
+ H5_GLUE3(H5SL_LOCATE_,OP,_FOUND)(SLIST, X, _i) \
+ break; \
+ } /* end if */ \
+ } /* end for */ \
+}
+
+/* Macro used to find node for operation */
+#define H5SL_LOCATE(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+{ \
+ if((SLIST)->safe_iterating) \
+ H5SL_LOCATE_SAFE(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+ else \
+ H5SL_LOCATE_OPT(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+}
+
+
+/* Macro used to grow a node by 1. Does not update pointers. LVL is the current
+ * level of X. Does not update LVL but does update X->lvl. */
+#define H5SL_GROW(X, LVL, ERR) \
+{ \
+ /* Check if we need to increase allocation of forward pointers */ \
+ if(LVL + 1 >= 1u << X->log_nalloc) { \
+ H5SL_node_t **_tmp; \
+ HDassert(LVL + 1 == 1u << X->log_nalloc); \
+ /* Double the amount of allocated space */ \
+ X->log_nalloc++; \
+ \
+ /* Check if we need to create a new factory */ \
+ if(X->log_nalloc >= H5SL_fac_nused_g) { \
+ HDassert(X->log_nalloc == H5SL_fac_nused_g); \
+ \
+ /* Check if we need to allocate space for the factory pointer*/ \
+ if(H5SL_fac_nused_g >= H5SL_fac_nalloc_g) { \
+ HDassert(H5SL_fac_nused_g == H5SL_fac_nalloc_g); \
+ /* Double the size of the array of factory pointers */ \
+ H5SL_fac_nalloc_g *= 2; \
+ if(NULL == (H5SL_fac_g = (H5FL_fac_head_t **)H5MM_realloc( \
+ (void *)H5SL_fac_g, H5SL_fac_nalloc_g \
+ * sizeof(H5FL_fac_head_t *)))) \
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTALLOC, ERR, "memory allocation failed") \
+ } /* end if */ \
+ \
+ /* Create the new factory */ \
+ H5SL_fac_g[H5SL_fac_nused_g] = H5FL_fac_init((1u << H5SL_fac_nused_g) * sizeof(H5SL_node_t *)); \
+ H5SL_fac_nused_g++; \
+ } /* end if */ \
+ \
+ /* Allocate space for new forward pointers */ \
+ if(NULL == (_tmp = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[X->log_nalloc]))) \
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTALLOC, ERR, "memory allocation failed") \
+ HDmemcpy((void *)_tmp, (const void *)X->forward, (LVL + 1) * sizeof(H5SL_node_t *)); \
+ X->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[X->log_nalloc-1], (void *)X->forward); \
+ X->forward = _tmp; \
+ } /* end if */ \
+ \
+ X->level++; \
+}
+
+
+/* Macro used to shrink a node by 1. Does not update pointers. LVL is the
+ * current level of X. Does not update LVL but does update X->level. */
+#define H5SL_SHRINK(X, LVL) \
+{ \
+ /* Check if we can reduce the allocation of forward pointers */ \
+ if(LVL <= 1u << (X->log_nalloc - 1)) { \
+ H5SL_node_t **_tmp; \
+ HDassert(LVL == 1u << (X->log_nalloc - 1)); \
+ X->log_nalloc--; \
+ \
+ /* Allocate space for new forward pointers */ \
+ if(NULL == (_tmp = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[X->log_nalloc]))) \
+ HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed") \
+ HDmemcpy((void *)_tmp, (const void *)X->forward, (LVL) * sizeof(H5SL_node_t *)); \
+ X->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[X->log_nalloc+1], (void *)X->forward); \
+ X->forward = _tmp; \
+ } /* end if */ \
+ \
+ X->level--; \
+}
+
+
+/* Macro used to grow the level of a node by 1, with appropriate changes to the
+ * head node if necessary. PREV is the previous node of the height that X is to
+ * grow to. */
+#define H5SL_PROMOTE(SLIST, X, PREV, ERR) \
+{ \
+ size_t _lvl = X->level; \
+ \
+ H5SL_GROW(X, _lvl, ERR); \
+ \
+ if(_lvl == (size_t) SLIST->curr_level) { \
+ HDassert(PREV == SLIST->header); \
+ /* Grow the head */ \
+ H5SL_GROW(PREV, _lvl, ERR) \
+ SLIST->curr_level++; \
+ X->forward[_lvl+1] = NULL; \
+ } else { \
+ HDassert(_lvl < (size_t) SLIST->curr_level); \
+ X->forward[_lvl+1] = PREV->forward[_lvl+1]; \
+ } /* end else */ \
+ PREV->forward[_lvl+1] = X; \
+}
+
+
+/* Macro used to reduce the level of a node by 1. Does not update the head node
+ * "current level". PREV is the previous node of the currrent height of X. */
+#define H5SL_DEMOTE(X, PREV) \
+{ \
+ size_t _lvl = X->level; \
+ \
+ HDassert(PREV->forward[_lvl] == X); \
+ PREV->forward[_lvl] = X->forward[_lvl]; \
+ H5SL_SHRINK(X, _lvl); \
+}
+
+
+/* Macro used to insert node. Does not actually insert the node. After running
+ * this macro, X will contain the node before where the new node should be
+ * inserted (at level 0). */
+#define H5SL_INSERT(CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+{ \
+ H5SL_node_t *_last = X; /* Lowest node in the current gap */ \
+ H5SL_node_t *_next = NULL; /* Highest node in the currect gap */ \
+ H5SL_node_t *_drop; /* Low node of the gap to drop into */ \
+ int _count; /* Number of nodes in the current gap */ \
+ int _i; \
+ \
+ H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \
+ for(_i = (int)SLIST->curr_level; _i >= 0; _i--) { \
+ /* Search for the node to drop into, also count the number of nodes */ \
+ /* of height _i in this gap */ \
+ _drop = NULL; \
+ for(_count = 0; ; _count++) { \
+ /* Terminate if this is the last node in the gap */ \
+ if(X->forward[_i] == _next) { \
+ if(!_drop) \
+ _drop = X; \
+ break; \
+ } /* end if */ \
+ \
+ /* Check if this node is the start of the next gap */ \
+ if(!_drop && !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, X->forward[_i], KEY, HASHVAL)) \
+ _drop = X; \
+ \
+ /* No need to check the last node in the gap if there are 3, as */ \
+ /* there cannot be a fourth */ \
+ if(_count == 2) { \
+ if(!_drop) \
+ _drop = X->forward[_i]; \
+ _count = 3; \
+ break; \
+ } \
+ X = X->forward[_i]; \
+ } /* end for */ \
+ HDassert(!_drop->forward[_i] || \
+ !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, _drop->forward[_i], KEY, HASHVAL)); \
+ \
+ /* Promote the middle node if necessary */ \
+ if(_count == 3) { \
+ HDassert(X == _last->forward[_i]->forward[_i]); \
+ H5SL_PROMOTE(SLIST, X, _last, NULL) \
+ } \
+ \
+ /* Prepare to drop down */ \
+ X = _last = _drop; \
+ _next = _drop->forward[_i]; \
+ } /* end for */ \
+ \
+ if(_next && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(SLIST, TYPE, _next, KEY, HASHVAL)) \
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTINSERT, NULL, "can't insert duplicate key") \
+}
+
+
+/* Macro used to remove node */
+#define H5SL_REMOVE(CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+{ \
+ /* Check for deferred removal */ \
+ if(SLIST->safe_iterating) \
+ H5SL_LOCATE(SEARCH_DEFER_REMOVE, CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+ else { \
+ H5SL_node_t *_last = X; /* Lowest node in the current gap */ \
+ H5SL_node_t *_llast = X; /* Lowest node in the previous gap */ \
+ H5SL_node_t *_next = NULL; /* Highest node in the currect gap */ \
+ H5SL_node_t *_drop = NULL; /* Low node of the gap to drop into */ \
+ H5SL_node_t *_ldrop = NULL; /* Low node of gap before the one to drop into */ \
+ H5SL_node_t *_head = SLIST->header; /* Head of the skip list */ \
+ int _count; /* Number of nodes in the current gap */ \
+ int _i = (int)SLIST->curr_level; \
+ \
+ if(_i < 0) \
+ HGOTO_DONE(NULL); \
+ \
+ H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \
+ \
+ /* Find the gap to drop in to at the highest level */ \
+ while(X && (!X->key || H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, X, KEY, HASHVAL))) { \
+ _llast = _last; \
+ _last = X; \
+ X = X->forward[_i]; \
+ } \
+ _next = X; \
+ \
+ /* Main loop */ \
+ for(_i--; _i >= 0; _i--) { \
+ /* Search for the node to drop into, also count the number of */ \
+ /* nodes of height _i in this gap and keep track of of the node */ \
+ /* before the one to drop into (_ldrop will become _llast, */ \
+ /* _drop will become _last). */ \
+ X = _ldrop = _last; \
+ _drop = NULL; \
+ for(_count = 0; ; _count++) { \
+ /* Terminate if this is the last node in the gap */ \
+ if(X->forward[_i] == _next) { \
+ if(!_drop) \
+ _drop = X; \
+ break; \
+ } /* end if */ \
+ \
+ /* If we have already found the node to drop into and there */ \
+ /* is more than one node in this gap, we can stop searching */ \
+ if(_drop) { \
+ HDassert(_count >= 1); \
+ _count = 2; \
+ break; \
+ } else { /* !_drop */ \
+ /* Check if this node is the start of the next gap */ \
+ if (!H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, X->forward[_i], KEY, HASHVAL)) { \
+ _drop = X; \
+ /* Again check if we can stop searching */ \
+ if(_count) { \
+ _count = 2; \
+ break; \
+ } /* end if */ \
+ } /* end if */ \
+ else \
+ _ldrop = X; \
+ } /* end else */ \
+ \
+ /* No need to check the last node in the gap if there are */ \
+ /* 3, as there cannot be a fourth */ \
+ if(_count == 2) { \
+ if(!_drop) \
+ _drop = X->forward[_i]; \
+ break; \
+ } /* end if */ \
+ X = X->forward[_i]; \
+ } /* end for */ \
+ HDassert(_count >= 1 && _count <= 3); \
+ HDassert(!_drop->forward[_i] || \
+ !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(SLIST, TYPE, _drop->forward[_i], KEY, HASHVAL)); \
+ \
+ /* Check if we need to adjust node heights */ \
+ if(_count == 1) { \
+ /* Check if we are in the first gap */ \
+ if(_llast == _last) { \
+ /* We are in the first gap, count the number of nodes */ \
+ /* of height _i in the next gap. We need only check */ \
+ /* onenode to see if we should promote the first node */ \
+ /* in the next gap */ \
+ _llast = _next->forward[_i+1]; \
+ \
+ /* Demote the separator node */ \
+ H5SL_DEMOTE(_next, _last) \
+ \
+ /* If there are 2 or more nodes, promote the first */ \
+ if(_next->forward[_i]->forward[_i] != _llast) { \
+ X = _next->forward[_i]; \
+ H5SL_PROMOTE(SLIST, X, _last, NULL) \
+ } else if(!_head->forward[_i+1]) { \
+ /* shrink the header */ \
+ HDassert(_i == SLIST->curr_level - 1); \
+ HDassert((size_t) SLIST->curr_level == _head->level); \
+ \
+ H5SL_SHRINK(_head, (size_t) (_i+1)) \
+ SLIST->curr_level--; \
+ } /* end else */ \
+ } else { \
+ /* We are not in the first gap, count the number of */ \
+ /* nodes of height _i in the previous gap. Note we */ \
+ /* "look ahead" in this loop so X has the value of the */ \
+ /* last node in the previous gap. */ \
+ X = _llast->forward[_i]; \
+ for(_count = 1; _count < 3 && X->forward[_i] != _last; _count++) \
+ X = X->forward[_i]; \
+ HDassert(X->forward[_i] == _last); \
+ \
+ /* Demote the separator node */ \
+ H5SL_DEMOTE(_last, _llast) \
+ \
+ /* If there are 2 or more nodes, promote the last */ \
+ if(_count >= 2) \
+ H5SL_PROMOTE(SLIST, X, _llast, NULL) \
+ else if(!_head->forward[_i+1]) { \
+ /* shrink the header */ \
+ HDassert(_i == SLIST->curr_level - 1); \
+ HDassert((size_t) SLIST->curr_level == _head->level); \
+ \
+ H5SL_SHRINK(_head, (size_t) (_i+1)) \
+ SLIST->curr_level--; \
+ } /* end else */ \
+ } /* end else */ \
+ } /* end if */ \
+ \
+ /* Prepare to drop down */ \
+ _llast = _ldrop; \
+ _last = _drop; \
+ _next = _drop->forward[_i]; \
+ } /* end for */ \
+ \
+ /* Check if we've found the node */ \
+ if(_next && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(SLIST, TYPE, _next, KEY, HASHVAL)) { \
+ void *tmp = _next->item; \
+ X = _next; \
+ \
+ /* If the node has a height > 0, swap it with its (lower) */ \
+ /* neighbor */ \
+ if(X->level) { \
+ X = X->backward; \
+ _next->key = X->key; \
+ _next->item = X->item; \
+ _next->hashval = X->hashval; \
+ } /* end if */ \
+ HDassert(!X->level); \
+ \
+ /* Remove the node */ \
+ X->backward->forward[0] = X->forward[0]; \
+ if(SLIST->last == X) \
+ SLIST->last = X->backward; \
+ else \
+ X->forward[0]->backward = X->backward; \
+ SLIST->nobjs--; \
+ X->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[0], X->forward); \
+ X = H5FL_FREE(H5SL_node_t, X); \
+ \
+ HGOTO_DONE(tmp); \
+ } /* end if */ \
+ } /* end else */ \
+}
+
+
+/* Macro used to search for node */
+#define H5SL_SEARCH(CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+ H5SL_LOCATE(SEARCH, CMP, SLIST, X, TYPE, KEY, HASHVAL)
+
+/* Macro used to find a node */
+#define H5SL_FIND(CMP, SLIST, X, TYPE, KEY, HASHVAL) \
+ H5SL_LOCATE(FIND, CMP, SLIST, X, TYPE, KEY, HASHVAL)
+
+
+/* Private typedefs & structs */
+
+/* Skip list node data structure */
+struct H5SL_node_t {
+ const void *key; /* Pointer to node's key */
+ void *item; /* Pointer to node's item */
+ size_t level; /* The level of this node */
+ size_t log_nalloc; /* log2(Number of slots allocated in forward) */
+ uint32_t hashval; /* Hash value for key (only for strings, currently) */
+ hbool_t removed; /* Whether the node is "removed" (actual removal deferred) */
+ struct H5SL_node_t **forward; /* Array of forward pointers from this node */
+ struct H5SL_node_t *backward; /* Backward pointer from this node */
+};
+
+/* Main skip list data structure */
+struct H5SL_t {
+ /* Static values for each list */
+ H5SL_type_t type; /* Type of skip list */
+ H5SL_cmp_t cmp; /* Comparison callback, if type is H5SL_TYPE_GENERIC */
+
+ /* Dynamic values for each list */
+ int curr_level; /* Current top level used in list */
+ size_t nobjs; /* Number of active objects in skip list */
+ H5SL_node_t *header; /* Header for nodes in skip list */
+ H5SL_node_t *last; /* Pointer to last node in skip list */
+ hbool_t safe_iterating; /* Whether a routine is "safely" iterating over the list and removals should be deferred */
+};
+
+/* Static functions */
+static H5SL_node_t * H5SL_new_node(void *item, const void *key, uint32_t hashval);
+static H5SL_node_t *H5SL_insert_common(H5SL_t *slist, void *item, const void *key);
+static herr_t H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data);
+static herr_t H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data);
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declare a free list to manage the H5SL_t struct */
+H5FL_DEFINE_STATIC(H5SL_t);
+
+/* Declare a free list to manage the H5SL_node_t struct */
+H5FL_DEFINE_STATIC(H5SL_node_t);
+
+/* Global variables */
+static H5FL_fac_head_t **H5SL_fac_g;
+static size_t H5SL_fac_nused_g;
+static size_t H5SL_fac_nalloc_g;
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL__init_package
+ PURPOSE
+ Initialize interface-specific information
+ USAGE
+ herr_t H5SL__init_package()
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Initializes any interface-specific data or routines.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL__init_package(void)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Allocate space for array of factories */
+ H5SL_fac_g = (H5FL_fac_head_t **)H5MM_malloc(sizeof(H5FL_fac_head_t *));
+ HDassert(H5SL_fac_g);
+ H5SL_fac_nalloc_g = 1;
+
+ /* Initialize first factory */
+ H5SL_fac_g[0] = H5FL_fac_init(sizeof(H5SL_node_t *));
+ HDassert(H5SL_fac_g[0]);
+ H5SL_fac_nused_g = 1;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SL__init_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_term_package
+ PURPOSE
+ Terminate all the H5FL factories used in this package, and clear memory
+ USAGE
+ int H5SL_term_package()
+ RETURNS
+ Success: Positive if any action might have caused a change in some
+ other interface; zero otherwise.
+ Failure: Negative
+ DESCRIPTION
+ Release any resources allocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Can't report errors...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int H5SL_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Terminate all the factories */
+ if(H5SL_fac_nused_g > 0) {
+ size_t i;
+ herr_t ret;
+
+ for(i = 0; i < H5SL_fac_nused_g; i++) {
+ ret = H5FL_fac_term(H5SL_fac_g[i]);
+ HDassert(ret >= 0);
+ } /* end if */
+ H5SL_fac_nused_g = 0;
+
+ n++;
+ } /* end if */
+
+ /* Free the list of factories */
+ if(H5SL_fac_g) {
+ H5SL_fac_g = (H5FL_fac_head_t **)H5MM_xfree((void *)H5SL_fac_g);
+ H5SL_fac_nalloc_g = 0;
+
+ n++;
+ } /* end if */
+
+ /* Mark the interface as uninitialized */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* H5SL_term_package() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_new_node
+ PURPOSE
+ Create a new skip list node of level 0
+ USAGE
+ H5SL_node_t *H5SL_new_node(item,key,hasval)
+ void *item; IN: Pointer to item info for node
+ void *key; IN: Pointer to key info for node
+ uint32_t hashval; IN: Hash value for node
+
+ RETURNS
+ Returns a pointer to a skip list node on success, NULL on failure.
+ DESCRIPTION
+ Create a new skip list node of the height 0, setting the item
+ and key values internally.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine does _not_ initialize the 'forward' pointers
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5SL_node_t *
+H5SL_new_node(void *item, const void *key, uint32_t hashval)
+{
+ H5SL_node_t *ret_value = NULL; /* New skip list node */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate the node */
+ if(NULL == (ret_value = (H5SL_node_t *)H5FL_MALLOC(H5SL_node_t)))
+ HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Initialize node */
+ ret_value->key = key;
+ ret_value->item = item;
+ ret_value->level = 0;
+ ret_value->hashval = hashval;
+ ret_value->removed = FALSE;
+ if(NULL == (ret_value->forward = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[0]))) {
+ ret_value = H5FL_FREE(H5SL_node_t, ret_value);
+ HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed")
+ } /* end if */
+ ret_value->log_nalloc = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_new_node() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_insert_common
+ PURPOSE
+ Common code for inserting an object into a skip list
+ USAGE
+ H5SL_node_t *H5SL_insert_common(slist,item,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *item; IN: Item to insert
+ void *key; IN: Key for item to insert
+
+ RETURNS
+ Returns pointer to new node on success, NULL on failure.
+ DESCRIPTION
+ Common code for inserting an element into a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Inserting an item with the same key as an existing object fails.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5SL_node_t *
+H5SL_insert_common(H5SL_t *slist, void *item, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ H5SL_node_t *prev; /* Node before the new node */
+ uint32_t hashval = 0; /* Hash value for key */
+ H5SL_node_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ prev=slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_INSERT(SCALAR, slist, prev, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_INSERT(SCALAR, slist, prev, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_INSERT(STRING, slist, prev, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_INSERT(SCALAR, slist, prev, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_INSERT(SCALAR, slist, prev, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_INSERT(SCALAR, slist, prev, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_INSERT(OBJ, slist, prev, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_INSERT(SCALAR, slist, prev, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_INSERT(GENERIC, slist, prev, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+
+ /* 'key' must not have been found in existing list, if we get here */
+
+ if(slist->curr_level < 0)
+ slist->curr_level = 0;
+
+ /* Create new node of level 0 */
+ if(NULL == (x = H5SL_new_node(item, key, hashval)))
+ HGOTO_ERROR(H5E_SLIST ,H5E_NOSPACE, NULL, "can't create new skip list node")
+
+ /* Update the links */
+ x->backward = prev;
+ x->forward[0] = prev->forward[0];
+ prev->forward[0] = x;
+ if(x->forward[0])
+ x->forward[0]->backward = x;
+ else {
+ HDassert(slist->last == prev);
+ slist->last = x;
+ }
+
+ /* Increment the number of nodes in the skip list */
+ slist->nobjs++;
+
+ /* Set return value */
+ ret_value=x;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_insert_common() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_release_common
+ PURPOSE
+ Release all nodes from a skip list, optionally calling a 'free' operator
+ USAGE
+ herr_t H5SL_release_common(slist,op,opdata)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to release nodes
+ H5SL_operator_t op; IN: Callback function to free item & key
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Release all the nodes in a skip list. The 'op' routine is called for
+ each node in the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The return value from the 'op' routine is ignored.
+
+ The skip list itself is still valid, it just has all its nodes removed.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data)
+{
+ H5SL_node_t *node, *next_node; /* Pointers to skip list nodes */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Free skip list nodes */
+ node = slist->header->forward[0];
+ while(node) {
+ next_node = node->forward[0];
+
+ /* Call callback, if one is given */
+ if(op)
+ /* Casting away const OK -QAK */
+ (void)(op)(node->item, (void *)node->key, op_data);
+
+ node->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[node->log_nalloc], node->forward);
+ node = H5FL_FREE(H5SL_node_t, node);
+ node = next_node;
+ } /* end while */
+
+ /* Reset the header pointers */
+ slist->header->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[slist->header->log_nalloc], slist->header->forward);
+ if(NULL == (slist->header->forward = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[0])))
+ HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, FAIL, "memory allocation failed")
+ slist->header->forward[0] = NULL;
+ slist->header->log_nalloc = 0;
+ slist->header->level = 0;
+
+ /* Reset the last pointer */
+ slist->last = slist->header;
+
+ /* Reset the dynamic internal fields */
+ slist->curr_level = -1;
+ slist->nobjs = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_release_common() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_close_common
+ PURPOSE
+ Close a skip list, deallocating it and potentially freeing all its nodes.
+ USAGE
+ herr_t H5SL_close_common(slist,op,opdata)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to close
+ H5SL_operator_t op; IN: Callback function to free item & key
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a skip list, freeing all internal information. Any objects left in
+ the skip list have the 'op' routine called for each.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ If the 'op' routine returns non-zero, only the nodes up to that
+ point in the list are released and the list is still valid.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Free skip list nodes */
+ if(H5SL_release_common(slist, op, op_data) < 0)
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTFREE, FAIL, "can't release skip list nodes")
+
+ /* Release header node */
+ slist->header->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[slist->header->log_nalloc], slist->header->forward);
+ slist->header = H5FL_FREE(H5SL_node_t, slist->header);
+
+ /* Free skip list object */
+ slist = H5FL_FREE(H5SL_t, slist);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_close_common() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_create
+ PURPOSE
+ Create a skip list
+ USAGE
+ H5SL_t *H5SL_create(H5SL_type_t type, H5SL_cmp_t cmp)
+
+ RETURNS
+ Returns a pointer to a skip list on success, NULL on failure.
+ DESCRIPTION
+ Create a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_t *
+H5SL_create(H5SL_type_t type, H5SL_cmp_t cmp)
+{
+ H5SL_t *new_slist = NULL; /* Pointer to new skip list object created */
+ H5SL_node_t *header; /* Pointer to skip list header node */
+ H5SL_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check args */
+ HDassert(type >= H5SL_TYPE_INT && type <= H5SL_TYPE_GENERIC);
+
+ /* Allocate skip list structure */
+ if(NULL == (new_slist = H5FL_MALLOC(H5SL_t)))
+ HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the static internal fields */
+ new_slist->type = type;
+ HDassert((type == H5SL_TYPE_GENERIC) == !!cmp);
+ new_slist->cmp = cmp;
+
+ /* Set the dynamic internal fields */
+ new_slist->curr_level = -1;
+ new_slist->nobjs = 0;
+ new_slist->safe_iterating = FALSE;
+
+ /* Allocate the header node */
+ if(NULL == (header = H5SL_new_node(NULL, NULL, (uint32_t)ULONG_MAX)))
+ HGOTO_ERROR(H5E_SLIST ,H5E_NOSPACE, NULL, "can't create new skip list node")
+
+ /* Initialize header node's forward pointer */
+ header->forward[0] = NULL;
+
+ /* Initialize header node's backward pointer */
+ header->backward = NULL;
+
+ /* Attach the header */
+ new_slist->header = header;
+ new_slist->last = header;
+
+ /* Set the return value */
+ ret_value = new_slist;
+
+done:
+ /* Error cleanup */
+ if(ret_value == NULL) {
+ if(new_slist != NULL)
+ new_slist = H5FL_FREE(H5SL_t, new_slist);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_count
+ PURPOSE
+ Count the number of objects in a skip list
+ USAGE
+ size_t H5SL_count(slist)
+ H5SL_t *slist; IN: Pointer to skip list to count
+
+ RETURNS
+ Returns number of objects on success, can't fail
+ DESCRIPTION
+ Count elements in a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+size_t
+H5SL_count(H5SL_t *slist)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ FUNC_LEAVE_NOAPI(slist->nobjs)
+} /* end H5SL_count() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_insert
+ PURPOSE
+ Insert an object into a skip list
+ USAGE
+ herr_t H5SL_insert(slist,item,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *item; IN: Item to insert
+ void *key; IN: Key for item to insert
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Insert element into a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Inserting an item with the same key as an existing object fails.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_insert(H5SL_t *slist, void *item, const void *key)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+ if(H5SL_insert_common(slist,item,key)==NULL)
+ HGOTO_ERROR(H5E_SLIST,H5E_CANTINSERT,FAIL,"can't create new skip list node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_insert() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_add
+ PURPOSE
+ Insert an object into a skip list
+ USAGE
+ H5SL_node_t *H5SL_add(slist,item,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *item; IN: Item to insert
+ void *key; IN: Key for item to insert
+
+ RETURNS
+ Returns pointer to new skip list node on success, NULL on failure.
+ DESCRIPTION
+ Insert element into a skip list and return the skip list node for the
+ new element in the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Inserting an item with the same key as an existing object fails.
+
+ This routine is a useful starting point for next/prev calls
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_add(H5SL_t *slist, void *item, const void *key)
+{
+ H5SL_node_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+ if((ret_value=H5SL_insert_common(slist,item,key))==NULL)
+ HGOTO_ERROR(H5E_SLIST,H5E_CANTINSERT,NULL,"can't create new skip list node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_add() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_remove
+ PURPOSE
+ Removes an object from a skip list
+ USAGE
+ void *H5SL_remove(slist,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to remove
+
+ RETURNS
+ Returns pointer to item removed on success, NULL on failure.
+ DESCRIPTION
+ Remove element from a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_remove(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Remove item from skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to remove
+ */
+ x = slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_REMOVE(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_REMOVE(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_REMOVE(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_REMOVE(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_REMOVE(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_REMOVE(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_REMOVE(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_REMOVE(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_REMOVE(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_remove() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_remove_first
+ PURPOSE
+ Removes the first object from a skip list
+ USAGE
+ void *H5SL_remove_first(slist)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+
+ RETURNS
+ Returns pointer to item removed on success, NULL on failure.
+ DESCRIPTION
+ Remove first element from a skip list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_remove_first(H5SL_t *slist)
+{
+ void *ret_value = NULL; /* Return value */
+ H5SL_node_t *head = slist->header; /* Skip list header */
+ H5SL_node_t *tmp = slist->header->forward[0]; /* Temporary node pointer */
+ H5SL_node_t *next; /* Next node to search for */
+ size_t level; /* Skip list level */
+ size_t i; /* Index */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Assign level */
+ H5_CHECK_OVERFLOW(slist->curr_level, int, size_t);
+ level = (size_t)slist->curr_level;
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Remove item from skip list */
+
+ /* Check for empty list */
+ if(slist->last != slist->header) {
+
+ /* Assign return value */
+ ret_value = tmp->item;
+ HDassert(level == head->level);
+ HDassert(0 == tmp->level);
+
+ /* Remove the first node */
+ head->forward[0] = tmp->forward[0];
+ if(slist->last == tmp)
+ slist->last = head;
+ else
+ tmp->forward[0]->backward = head;
+ slist->nobjs--;
+ /* Free memory */
+ tmp->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[0], tmp->forward);
+ tmp = H5FL_FREE(H5SL_node_t, tmp);
+
+ /* Reshape the skip list as necessary to maintain 1-2-3 condition */
+ for(i=0; i < level; i++) {
+ next = head->forward[i+1];
+ HDassert(next);
+
+ /* Check if head->forward[i] == head->forward[i+1] (illegal) */
+ if(head->forward[i] == next) {
+ tmp = next;
+ next = next->forward[i+1];
+
+ HDassert(tmp->level == i+1);
+
+ /* Demote head->forward[i] */
+ H5SL_DEMOTE(tmp, head)
+
+ /* Check if we need to promote the following node to maintain
+ * 1-2-3 condition */
+ if(tmp->forward[i]->forward[i] != next) {
+ HDassert(tmp->forward[i]->forward[i]->forward[i] == next ||
+ tmp->forward[i]->forward[i]->forward[i]->forward[i] == next);
+ tmp = tmp->forward[i];
+ H5SL_PROMOTE(slist, tmp, head, NULL);
+ /* In this case, since there is a node of height = i+1 here
+ * now (tmp), we know the skip list must be valid and can
+ * break */
+ break;
+ } else if(!head->forward[i+1]) {
+ /* We just shrunk the largest node, shrink the header */
+ HDassert(i == level - 1);
+
+ H5SL_SHRINK(head, level)
+ slist->curr_level--;
+ } /* end else */
+ } else
+ break;
+ } /* end for */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_remove_first() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_search
+ PURPOSE
+ Search for object in a skip list
+ USAGE
+ void *H5SL_search(slist,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to item on success, NULL on failure
+ DESCRIPTION
+ Search for an object in a skip list, according to it's key
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_search(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x=slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_SEARCH(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_SEARCH(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_SEARCH(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_SEARCH(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* 'key' must not have been found in list, if we get here */
+ ret_value=NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_search() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_less
+ PURPOSE
+ Search for object in a skip list that is less than or equal to 'key'
+ USAGE
+ void *H5SL_less(slist,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to item who key is less than or equal to 'key' on success,
+ NULL on failure
+ DESCRIPTION
+ Search for an object in a skip list, according to it's key, returning the
+ object itself (for an exact match), or the object with the next highest
+ key that is less than 'key'
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_less(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x=slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_SEARCH(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_SEARCH(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_SEARCH(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_SEARCH(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* An exact match for 'key' must not have been found in list, if we get here */
+ /* Check for a node with a key that is less than the given 'key' */
+ if(x==NULL) {
+ /* Check for walking off the list */
+ if(slist->last!=slist->header)
+ ret_value=slist->last->item;
+ else
+ ret_value=NULL;
+ } /* end if */
+ else {
+ if(x->backward!=slist->header)
+ ret_value=x->backward->item;
+ else
+ ret_value=NULL;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_less() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_greater
+ PURPOSE
+ Search for object in a skip list that is greater than or equal to 'key'
+ USAGE
+ void *H5SL_greater(slist, key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to item who key is greater than or equal to 'key' on success,
+ NULL on failure
+ DESCRIPTION
+ Search for an object in a skip list, according to it's key, returning the
+ object itself (for an exact match), or the object with the next lowest
+ key that is greater than 'key'
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_greater(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x = slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_SEARCH(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_SEARCH(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_SEARCH(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_SEARCH(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* An exact match for 'key' must not have been found in list, if we get here */
+ /* ('x' must be the next node with a key greater than the 'key', or NULL) */
+ if(x)
+ ret_value = x->item;
+ else
+ ret_value = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_greater() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_find
+ PURPOSE
+ Search for _node_ in a skip list
+ USAGE
+ H5SL_node_t *H5SL_node(slist,key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to _node_ matching key on success, NULL on failure
+ DESCRIPTION
+ Search for an object in a skip list, according to it's key and returns
+ the node that the object is attached to
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine is a useful starting point for next/prev calls
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_find(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ H5SL_node_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x=slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_FIND(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_FIND(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_FIND(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_FIND(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_FIND(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_FIND(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* 'key' must not have been found in list, if we get here */
+ ret_value=NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_find() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_below
+ PURPOSE
+ Search for _node_ in a skip list whose object is less than or equal to 'key'
+ USAGE
+ H5SL_node_t *H5SL_below(slist, key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to _node_ who key is less than or equal to 'key' on success,
+ NULL on failure
+ DESCRIPTION
+ Search for a node with an object in a skip list, according to it's key,
+ returning the node itself (for an exact match), or the node with the next
+ highest key that is less than 'key'
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_below(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ H5SL_node_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x = slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_FIND(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_FIND(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_FIND(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_FIND(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_FIND(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_FIND(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* An exact match for 'key' must not have been found in list, if we get here */
+ /* Check for a node with a key that is less than the given 'key' */
+ if(NULL == x) {
+ /* Check for walking off the list */
+ if(slist->last != slist->header)
+ ret_value = slist->last;
+ else
+ ret_value = NULL;
+ } /* end if */
+ else {
+ if(x->backward != slist->header)
+ ret_value = x->backward;
+ else
+ ret_value = NULL;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_below() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_above
+ PURPOSE
+ Search for _node_ in a skip list whose object is greater than or equal to 'key'
+ USAGE
+ H5SL_node_t *H5SL_above(slist, key)
+ H5SL_t *slist; IN/OUT: Pointer to skip list
+ void *key; IN: Key for item to search for
+
+ RETURNS
+ Returns pointer to _node_ with object that has a key is greater than or
+ equal to 'key' on success, NULL on failure
+ DESCRIPTION
+ Search for a node with an object in a skip list, according to it's key,
+ returning the node itself (for an exact match), or the node with the next
+ lowest key that is greater than 'key'
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_above(H5SL_t *slist, const void *key)
+{
+ H5SL_node_t *x; /* Current node to examine */
+ uint32_t hashval = 0; /* Hash value for key */
+ H5SL_node_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(key);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Insert item into skip list */
+
+ /* Work through the forward pointers for a node, finding the node at each
+ * level that is before the location to insert
+ */
+ x = slist->header;
+ switch(slist->type) {
+ case H5SL_TYPE_INT:
+ H5SL_FIND(SCALAR, slist, x, const int, key, -)
+ break;
+
+ case H5SL_TYPE_HADDR:
+ H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -)
+ break;
+
+ case H5SL_TYPE_STR:
+ H5SL_FIND(STRING, slist, x, char *, key, hashval)
+ break;
+
+ case H5SL_TYPE_HSIZE:
+ H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -)
+ break;
+
+ case H5SL_TYPE_UNSIGNED:
+ H5SL_FIND(SCALAR, slist, x, const unsigned, key, -)
+ break;
+
+ case H5SL_TYPE_SIZE:
+ H5SL_FIND(SCALAR, slist, x, const size_t, key, -)
+ break;
+
+ case H5SL_TYPE_OBJ:
+ H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -)
+ break;
+
+ case H5SL_TYPE_HID:
+ H5SL_FIND(SCALAR, slist, x, const hid_t, key, -)
+ break;
+
+ case H5SL_TYPE_GENERIC:
+ H5SL_FIND(GENERIC, slist, x, const void, key, -)
+ break;
+
+ default:
+ HDassert(0 && "Unknown skiplist type!");
+ } /* end switch */
+
+ /* An exact match for 'key' must not have been found in list, if we get here */
+ /* ('x' must be the next node with a key greater than the 'key', or NULL) */
+ if(x)
+ ret_value = x;
+ else
+ ret_value = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_above() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_first
+ PURPOSE
+ Gets a pointer to the first node in a skip list
+ USAGE
+ H5SL_node_t *H5SL_first(slist)
+ H5SL_t *slist; IN: Pointer to skip list
+
+ RETURNS
+ Returns pointer to first node in skip list on success, NULL on failure.
+ DESCRIPTION
+ Retrieves a pointer to the first node in a skip list, for iterating over
+ the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_first(H5SL_t *slist)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ FUNC_LEAVE_NOAPI(slist->header->forward[0])
+} /* end H5SL_first() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_next
+ PURPOSE
+ Gets a pointer to the next node in a skip list
+ USAGE
+ H5SL_node_t *H5SL_next(slist_node)
+ H5SL_node_t *slist_node; IN: Pointer to skip list node
+
+ RETURNS
+ Returns pointer to node after slist_node in skip list on success, NULL on failure.
+ DESCRIPTION
+ Retrieves a pointer to the next node in a skip list, for iterating over
+ the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_next(H5SL_node_t *slist_node)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist_node);
+
+ /* Not currently supported */
+ HDassert(!slist_node->removed);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ FUNC_LEAVE_NOAPI(slist_node->forward[0])
+} /* end H5SL_next() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_prev
+ PURPOSE
+ Gets a pointer to the previos node in a skip list
+ USAGE
+ H5SL_node_t *H5SL_prev(slist_node)
+ H5SL_node_t *slist_node; IN: Pointer to skip list node
+
+ RETURNS
+ Returns pointer to node before slist_node in skip list on success, NULL on failure.
+ DESCRIPTION
+ Retrieves a pointer to the previous node in a skip list, for iterating over
+ the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_prev(H5SL_node_t *slist_node)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist_node);
+
+ /* Not currently supported */
+ HDassert(!slist_node->removed);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Walk backward, detecting the header node (which has it's key set to NULL) */
+ FUNC_LEAVE_NOAPI(slist_node->backward->key==NULL ? NULL : slist_node->backward)
+} /* end H5SL_prev() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_last
+ PURPOSE
+ Gets a pointer to the last node in a skip list
+ USAGE
+ H5SL_node_t *H5SL_last(slist)
+ H5SL_t *slist; IN: Pointer to skip list
+
+ RETURNS
+ Returns pointer to last node in skip list on success, NULL on failure.
+ DESCRIPTION
+ Retrieves a pointer to the last node in a skip list, for iterating over
+ the list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5SL_node_t *
+H5SL_last(H5SL_t *slist)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Find last node, avoiding the header node */
+ FUNC_LEAVE_NOAPI(slist->last==slist->header ? NULL : slist->last)
+} /* end H5SL_last() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_item
+ PURPOSE
+ Gets pointer to the 'item' for a skip list node
+ USAGE
+ void *H5SL_item(slist_node)
+ H5SL_node_t *slist_node; IN: Pointer to skip list node
+
+ RETURNS
+ Returns pointer to node 'item' on success, NULL on failure.
+ DESCRIPTION
+ Retrieves a node's 'item'
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5SL_item(H5SL_node_t *slist_node)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist_node);
+
+ /* Not currently supported */
+ HDassert(!slist_node->removed);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ FUNC_LEAVE_NOAPI(slist_node->item)
+} /* end H5SL_item() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_iterate
+ PURPOSE
+ Iterate over all nodes in a skip list
+ USAGE
+ herr_t H5SL_iterate(slist, op, op_data)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to iterate over
+ H5SL_operator_t op; IN: Callback function for iteration
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns a negative value if something is wrong, the return
+ value of the last operator if it was non-zero, or zero if all
+ nodes were processed.
+ DESCRIPTION
+ Iterate over all the nodes in a skip list, calling an application callback
+ with the item, key and any operator data.
+
+ The operator callback receives a pointer to the item and key for the list
+ being iterated over ('mesg'), and the pointer to the operator data passed
+ in to H5SL_iterate ('op_data'). The return values from an operator are:
+ A. Zero causes the iterator to continue, returning zero when all
+ nodes of that type have been processed.
+ B. Positive causes the iterator to immediately return that positive
+ value, indicating short-circuit success.
+ C. Negative causes the iterator to immediately return that value,
+ indicating failure.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_iterate(H5SL_t *slist, H5SL_operator_t op, void *op_data)
+{
+ H5SL_node_t *node; /* Pointer to current skip list node */
+ H5SL_node_t *next; /* Pointer to next skip list node */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Free skip list nodes */
+ node = slist->header->forward[0];
+ while(node != NULL) {
+ /* Protect against the node being deleted by the callback */
+ next = node->forward[0];
+
+ /* Call the iterator callback */
+ /* Casting away const OK -QAK */
+ if(!node->removed)
+ if((ret_value = (op)(node->item, (void *)node->key, op_data)) != 0)
+ break;
+
+ /* Advance to next node */
+ node = next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_iterate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_release
+ PURPOSE
+ Release all nodes from a skip list
+ USAGE
+ herr_t H5SL_release(slist)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to release nodes
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Release all the nodes in a skip list. Any objects left in the skip list
+ nodes are not deallocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The skip list itself is still valid, it just has all its nodes removed.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_release(H5SL_t *slist)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Free skip list nodes */
+ H5SL_release_common(slist,NULL,NULL); /* always succeeds */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SL_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_free
+ PURPOSE
+ Release all nodes from a skip list, freeing all nodes
+ USAGE
+ herr_t H5SL_free(slist,op,op_data)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to release nodes
+ H5SL_operator_t op; IN: Callback function to free item & key
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Release all the nodes in a skip list. Any objects left in
+ the skip list have the 'op' routine called for each.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The skip list itself is still valid, it just has all its nodes removed.
+
+ The return value from the 'op' routine is ignored.
+
+ This routine is essentially a combination of iterating over all the nodes
+ (where the iterator callback is supposed to free the items and/or keys)
+ followed by a call to H5SL_release().
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_free(H5SL_t *slist, H5SL_operator_t op, void *op_data)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Free skip list nodes */
+ H5SL_release_common(slist,op,op_data); /* always succeeds */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SL_free() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_try_free_safe
+ PURPOSE
+ Makes the supplied callback on all nodes in the skip list, freeing each
+ node that the callback returns TRUE for.
+ USAGE
+ herr_t PURPOSE(slist,op,opdata)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to release nodes
+ H5SL_try_free_op_t op; IN: Callback function to try to free item & key
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Makes the supplied callback on all nodes in the skip list, freeing each
+ node that the callback returns TRUE for. The iteration is performed in
+ a safe manner, such that the callback can call H5SL_remove(),
+ H5SL_search(), H5SL_find(), and H5SL_iterate() on nodes in this
+ skiplist, except H5SL_remove() may not be call on *this* node.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This function is written to be most efficient when most nodes are
+ removed from the skiplist, as it rebuilds the nodes afterwards.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_try_free_safe(H5SL_t *slist, H5SL_try_free_op_t op, void *op_data)
+{
+ H5SL_node_t *node, *next_node, *last_node; /* Pointers to skip list nodes */
+ htri_t op_ret;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(slist);
+ HDassert(op);
+
+ /* Not currently supported */
+ HDassert(!slist->safe_iterating);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Mark skip list as safe iterating, so nodes aren't freed out from under
+ * us */
+ slist->safe_iterating = TRUE;
+
+ /* Iterate over skip list nodes, making the callback for each and marking
+ * them as removed if requested by the callback */
+ node = slist->header->forward[0];
+ while(node) {
+ /* Check if the node was already removed */
+ if(!node->removed) {
+ /* Call callback */
+ /* Casting away const OK -NAF */
+ if((op_ret = (op)(node->item , (void *)node->key, op_data)) < 0)
+ HGOTO_ERROR(H5E_SLIST, H5E_CALLBACK, FAIL, "callback operation failed")
+
+ /* Check if op indicated that the node should be removed */
+ if(op_ret)
+ /* Mark the node as removed */
+ node->removed = TRUE;
+ } /* end if */
+
+ /* Advance node */
+ node = node->forward[0];
+ } /* end while */
+
+ /* Reset safe_iterating */
+ slist->safe_iterating = FALSE;
+
+ /* Iterate over nodes, freeing ones marked as removed */
+ node = slist->header->forward[0];
+ last_node = slist->header;
+ while(node) {
+ /* Save next node */
+ next_node = node->forward[0];
+
+ /* Check if the node was marked as removed */
+ if(node->removed) {
+ /* Remove the node */
+ node->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[node->log_nalloc], node->forward);
+ node = H5FL_FREE(H5SL_node_t, node);
+ slist->nobjs--;
+ } /* end if */
+ else {
+ /* Update backwards and forwards[0] pointers, and set the level to
+ * 0. Since the list is flattened we must rebuild the skiplist
+ * afterwards. */
+ /* Set level to 0. Note there is no need to preserve
+ * node->forward[0] since it was cached above and will always be
+ * updated later. */
+ if(node->level > 0) {
+ node->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[node->log_nalloc], (void *)node->forward);
+ if(NULL == (node->forward = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[0])))
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ node->log_nalloc = 0;
+ node->level = 0;
+ } /* end if */
+
+ /* Update pointers */
+ last_node->forward[0] = node;
+ node->backward = last_node;
+ last_node = node;
+ } /* end else */
+
+ /* Advance node */
+ node = next_node;
+ } /* end while */
+
+ /* Final pointer update */
+ last_node->forward[0] = NULL;
+ slist->last = last_node;
+
+ /* Demote skip list to level 0 */
+ if(slist->curr_level > 0) {
+ HDassert(slist->header->level == (size_t)slist->curr_level);
+
+ node = slist->header->forward[0];
+ slist->header->forward = (H5SL_node_t **)H5FL_FAC_FREE(H5SL_fac_g[slist->header->log_nalloc], (void *)slist->header->forward);
+ if(NULL == (slist->header->forward = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[0])))
+ HGOTO_ERROR(H5E_SLIST, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ slist->header->forward[0] = node;
+ slist->header->log_nalloc = 0;
+ slist->header->level = 0;
+ } /* end if */
+
+ /* Check if there are any nodes left */
+ if(slist->nobjs > 0) {
+ int i;
+
+ HDassert(slist->header->forward[0]);
+
+ /* Set skiplist level to 0 */
+ slist->curr_level = 0;
+
+ /* Rebuild the forward arrays */
+ for(i = 0; slist->curr_level >= i; i++) {
+ HDassert(slist->curr_level == i);
+
+ /* Promote every third node this level until we run out of nodes */
+ node = last_node = slist->header;
+ while(1) {
+ /* Check second node in gap, if not present, no need to promote
+ * further this level. */
+ HDassert(node->forward[i]);
+ node = node->forward[i]->forward[i];
+ if(!node)
+ break;
+
+ /* Check third and fourth node in gap, if either is not present,
+ * no need to promote further this level. */
+ node = node->forward[i];
+ if(!node || !node->forward[i])
+ break;
+
+ /* Promote the third node in the gap */
+ H5SL_PROMOTE(slist, node, last_node, FAIL)
+ last_node = node;
+ } /* end while */
+ } /* end for */
+ } /* end if */
+ else {
+ HDassert(!slist->header->forward[0]);
+ HDassert(slist->last == slist->header);
+ HDassert(slist->nobjs == 0);
+
+ /* Reset the skiplist level */
+ slist->curr_level = -1;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_try_free_safe() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_destroy
+ PURPOSE
+ Close a skip list, deallocating it and freeing all its nodes.
+ USAGE
+ herr_t H5SL_destroy(slist,op,opdata)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to close
+ H5SL_operator_t op; IN: Callback function to free item & key
+ void *op_data; IN/OUT: Pointer to application data for callback
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a skip list, freeing all internal information. Any objects left in
+ the skip list have the 'op' routine called for each.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The return value from the 'op' routine is ignored.
+
+ This routine is essentially a combination of iterating over all the nodes
+ (where the iterator callback is supposed to free the items and/or keys)
+ followed by a call to H5SL_close().
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_destroy(H5SL_t *slist, H5SL_operator_t op, void *op_data)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Close skip list */
+ (void)H5SL_close_common(slist,op,op_data); /* always succeeds */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SL_destroy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5SL_close
+ PURPOSE
+ Close a skip list, deallocating it.
+ USAGE
+ herr_t H5SL_close(slist)
+ H5SL_t *slist; IN/OUT: Pointer to skip list to close
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a skip list, freeing all internal information. Any objects left in
+ the skip list are not deallocated.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5SL_close(H5SL_t *slist)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(slist);
+
+ /* Check internal consistency */
+ /* (Pre-condition) */
+
+ /* Close skip list */
+ (void)H5SL_close_common(slist,NULL,NULL); /* always succeeds */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SL_close() */
+
diff --git a/src/H5SLmodule.h b/src/H5SLmodule.h
new file mode 100644
index 0000000..34f08a1
--- /dev/null
+++ b/src/H5SLmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5SL package. Including this header means that the source file
+ * is part of the H5SL package.
+ */
+#ifndef _H5SLmodule_H
+#define _H5SLmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5SL_MODULE
+#define H5_MY_PKG H5SL
+#define H5_MY_PKG_ERR H5E_SLIST
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5SLmodule_H */
+
diff --git a/src/H5SLprivate.h b/src/H5SLprivate.h
new file mode 100644
index 0000000..1393a25
--- /dev/null
+++ b/src/H5SLprivate.h
@@ -0,0 +1,98 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5SL module
+ */
+#ifndef _H5SLprivate_H
+#define _H5SLprivate_H
+
+/**************************************/
+/* Public headers needed by this file */
+/**************************************/
+#ifdef LATER
+#include "H5SLpublic.h"
+#endif /* LATER */
+
+/***************************************/
+/* Private headers needed by this file */
+/***************************************/
+#include "H5private.h"
+
+/************/
+/* Typedefs */
+/************/
+
+/* Typedefs for skip list struct (defined in H5SL.c) */
+typedef struct H5SL_t H5SL_t;
+typedef struct H5SL_node_t H5SL_node_t;
+
+/* Typedef for kinds of skip lists supported */
+typedef enum {
+ H5SL_TYPE_INT, /* Skip list keys are 'int's */
+ H5SL_TYPE_HADDR, /* Skip list keys are 'haddr_t's */
+ H5SL_TYPE_STR, /* Skip list keys are 'char *'s (ie. strings) */
+ H5SL_TYPE_HSIZE, /* Skip list keys are 'hsize_t's */
+ H5SL_TYPE_UNSIGNED, /* Skip list keys are 'unsigned's */
+ H5SL_TYPE_SIZE, /* Skip list keys are 'size_t's */
+ H5SL_TYPE_OBJ, /* Skip list keys are 'H5_obj_t's */
+ H5SL_TYPE_HID, /* Skip list keys are 'hid_t's */
+ H5SL_TYPE_GENERIC /* Skip list keys are unknown, comparison callback supplied */
+} H5SL_type_t;
+
+/**********/
+/* Macros */
+/**********/
+
+/* Typedef for comparison operations */
+typedef int (*H5SL_cmp_t)(const void *key1, const void *key2);
+
+/* Typedef for iteration operations */
+typedef herr_t (*H5SL_operator_t)(void *item, void *key,
+ void *operator_data/*in,out*/);
+
+/* Typedef for H5SL_try_free_safe operation callback */
+typedef htri_t (*H5SL_try_free_op_t)(void *item, void *key,
+ void *operator_data/*in,out*/);
+
+/********************/
+/* Private routines */
+/********************/
+H5_DLL H5SL_t *H5SL_create(H5SL_type_t type, H5SL_cmp_t cmp);
+H5_DLL size_t H5SL_count(H5SL_t *slist);
+H5_DLL herr_t H5SL_insert(H5SL_t *slist, void *item, const void *key);
+H5_DLL H5SL_node_t *H5SL_add(H5SL_t *slist, void *item, const void *key);
+H5_DLL void *H5SL_remove(H5SL_t *slist, const void *key);
+H5_DLL void *H5SL_remove_first(H5SL_t *slist);
+H5_DLL void *H5SL_search(H5SL_t *slist, const void *key);
+H5_DLL void *H5SL_less(H5SL_t *slist, const void *key);
+H5_DLL void *H5SL_greater(H5SL_t *slist, const void *key);
+H5_DLL H5SL_node_t *H5SL_find(H5SL_t *slist, const void *key);
+H5_DLL H5SL_node_t *H5SL_below(H5SL_t *slist, const void *key);
+H5_DLL H5SL_node_t *H5SL_above(H5SL_t *slist, const void *key);
+H5_DLL H5SL_node_t *H5SL_first(H5SL_t *slist);
+H5_DLL H5SL_node_t *H5SL_next(H5SL_node_t *slist_node);
+H5_DLL H5SL_node_t *H5SL_prev(H5SL_node_t *slist_node);
+H5_DLL H5SL_node_t *H5SL_last(H5SL_t *slist);
+H5_DLL void *H5SL_item(H5SL_node_t *slist_node);
+H5_DLL herr_t H5SL_iterate(H5SL_t *slist, H5SL_operator_t op, void *op_data);
+H5_DLL herr_t H5SL_release(H5SL_t *slist);
+H5_DLL herr_t H5SL_free(H5SL_t *slist, H5SL_operator_t op, void *op_data);
+H5_DLL herr_t H5SL_try_free_safe(H5SL_t *slist, H5SL_try_free_op_t op,
+ void *op_data);
+H5_DLL herr_t H5SL_close(H5SL_t *slist);
+H5_DLL herr_t H5SL_destroy(H5SL_t *slist, H5SL_operator_t op, void *op_data);
+H5_DLL int H5SL_term_interface(void);
+
+#endif /* _H5SLprivate_H */
+
diff --git a/src/H5SM.c b/src/H5SM.c
new file mode 100644
index 0000000..d5ede7e
--- /dev/null
+++ b/src/H5SM.c
@@ -0,0 +1,2830 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Opkg.h" /* Object Headers */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Udata struct for calls to H5SM_read_iter_op */
+typedef struct H5SM_read_udata_t {
+ H5F_t *file; /* File in which sharing is happening (in) */
+ H5O_msg_crt_idx_t idx; /* Creation index of this message (in) */
+ size_t buf_size; /* Size of the encoded message (out) */
+ void *encoding_buf; /* The encoded message (out) */
+} H5SM_read_udata_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5SM_create_index(H5F_t *f, H5SM_index_header_t *header,
+ hid_t dxpl_id);
+static herr_t H5SM_delete_index(H5F_t *f, H5SM_index_header_t *header,
+ hid_t dxpl_id, hbool_t delete_heap);
+static haddr_t H5SM_create_list(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id);
+static herr_t H5SM__find_in_list(const H5SM_list_t *list, const H5SM_mesg_key_t *key,
+ size_t *empty_pos, size_t *list_pos);
+static herr_t H5SM_convert_list_to_btree(H5F_t * f, H5SM_index_header_t * header,
+ H5SM_list_t **_list, H5HF_t *fheap, H5O_t *open_oh, hid_t dxpl_id);
+static herr_t H5SM_convert_btree_to_list(H5F_t * f, H5SM_index_header_t * header, hid_t dxpl_id);
+static herr_t H5SM_incr_ref(void *record, void *_op_data, hbool_t *changed);
+static herr_t H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ H5SM_index_header_t *header, hbool_t defer, unsigned type_id, void *mesg,
+ unsigned *cache_flags_ptr);
+static herr_t H5SM_decr_ref(void *record, void *op_data, hbool_t *changed);
+static herr_t H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ H5SM_index_header_t *header, const H5O_shared_t * mesg,
+ unsigned *cache_flags, void ** /*out*/ encoded_mesg);
+static herr_t H5SM_type_to_flag(unsigned type_id, unsigned *type_flag);
+static herr_t H5SM_read_iter_op(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence,
+ unsigned *oh_modified, void *_udata);
+static herr_t H5SM_read_mesg_fh_cb(const void *obj, size_t obj_len, void *_udata);
+static herr_t H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap,
+ H5O_t * open_oh, hid_t dxpl_id, size_t *encoding_size /*out*/,
+ void ** encoded_mesg /*out*/);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+H5FL_DEFINE(H5SM_master_table_t);
+H5FL_ARR_DEFINE(H5SM_index_header_t, H5O_SHMESG_MAX_NINDEXES);
+H5FL_DEFINE(H5SM_list_t);
+H5FL_ARR_DEFINE(H5SM_sohm_t, H5O_SHMESG_MAX_LIST_SIZE);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_init
+ *
+ * Purpose: Initializes the Shared Message interface.
+ *
+ * Creates a master SOHM table in the file and in the cache.
+ * This function should not be called for files that have
+ * SOHMs disabled in the FCPL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_init(H5F_t *f, H5P_genplist_t * fc_plist, const H5O_loc_t *ext_loc, hid_t dxpl_id)
+{
+ H5O_shmesg_table_t sohm_table; /* SOHM message for superblock extension */
+ H5SM_master_table_t *table = NULL; /* SOHM master table for file */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t ring, orig_ring = H5AC_RING_INV; /* Original ring value */
+ haddr_t table_addr = HADDR_UNDEF; /* Address of SOHM master table in file */
+ unsigned list_max, btree_min; /* Phase change limits for SOHM indices */
+ unsigned index_type_flags[H5O_SHMESG_MAX_NINDEXES]; /* Messages types stored in each index */
+ unsigned minsizes[H5O_SHMESG_MAX_NINDEXES]; /* Message size sharing threshhold for each index */
+ unsigned type_flags_used; /* Message type flags used, for sanity checking */
+ unsigned x; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ HDassert(f);
+ /* File should not already have a SOHM table */
+ HDassert(!H5F_addr_defined(H5F_SOHM_ADDR(f)));
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_USER, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Initialize master table */
+ if(NULL == (table = H5FL_CALLOC(H5SM_master_table_t)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTALLOC, FAIL, "memory allocation failed for SOHM table")
+ table->num_indexes = H5F_SOHM_NINDEXES(f);
+ table->table_size = H5SM_TABLE_SIZE(f);
+
+ /* Get information from fcpl */
+ if(H5P_get(fc_plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, &index_type_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM type flags")
+ if(H5P_get(fc_plist, H5F_CRT_SHMSG_LIST_MAX_NAME, &list_max) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM list maximum")
+ if(H5P_get(fc_plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, &btree_min) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM btree minimum")
+ if(H5P_get(fc_plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, &minsizes) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM message min sizes")
+
+ /* Verify that values are valid */
+ if(table->num_indexes > H5O_SHMESG_MAX_NINDEXES)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADRANGE, FAIL, "number of indexes in property list is too large")
+
+ /* Check that type flags weren't duplicated anywhere */
+ type_flags_used = 0;
+ for(x = 0; x < table->num_indexes; ++x) {
+ if(index_type_flags[x] & type_flags_used)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "the same shared message type flag is assigned to more than one index")
+ type_flags_used |= index_type_flags[x];
+ } /* end for */
+
+ /* Check that number of indexes in table and in superblock make sense.
+ * Right now we just use one byte to hold the number of indexes.
+ */
+ HDassert(table->num_indexes < 256);
+
+ /* Check that list and btree cutoffs make sense. There can't be any
+ * values greater than the list max but less than the btree min; the
+ * list max has to be greater than or equal to one less than the btree
+ * min.
+ */
+ HDassert(list_max + 1 >= btree_min);
+ HDassert(table->num_indexes > 0 && table->num_indexes <= H5O_SHMESG_MAX_NINDEXES);
+
+ /* Allocate the SOHM indexes as an array. */
+ if(NULL == (table->indexes = (H5SM_index_header_t *)H5FL_ARR_MALLOC(H5SM_index_header_t, (size_t)table->num_indexes)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "memory allocation failed for SOHM indexes")
+
+ /* Initialize all of the indexes, but don't allocate space for them to
+ * hold messages until we actually need to write to them.
+ */
+ for(x = 0; x < table->num_indexes; x++) {
+ table->indexes[x].btree_min = btree_min;
+ table->indexes[x].list_max = list_max;
+ table->indexes[x].mesg_types = index_type_flags[x];
+ table->indexes[x].min_mesg_size = minsizes[x];
+ table->indexes[x].index_addr = HADDR_UNDEF;
+ table->indexes[x].heap_addr = HADDR_UNDEF;
+ table->indexes[x].num_messages = 0;
+
+ /* Indexes start as lists unless the list-to-btree threshold is zero */
+ if(table->indexes[x].list_max > 0)
+ table->indexes[x].index_type = H5SM_LIST;
+ else
+ table->indexes[x].index_type = H5SM_BTREE;
+
+ /* Compute the size of a list index for this SOHM index */
+ table->indexes[x].list_size = H5SM_LIST_SIZE(f, list_max);
+ } /* end for */
+
+ /* Allocate space for the table on disk */
+ if(HADDR_UNDEF == (table_addr = H5MF_alloc(f, H5FD_MEM_SOHM_TABLE, dxpl_id, (hsize_t)table->table_size)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "file allocation failed for SOHM table")
+
+ /* Cache the new table */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINS, FAIL, "can't add SOHM table to cache")
+
+ /* Record the address of the master table in the file */
+ H5F_SET_SOHM_ADDR(f, table_addr);
+
+ /* Check for sharing attributes in this file, which means that creation
+ * indices must be tracked on object header message in the file.
+ */
+ if(type_flags_used & H5O_SHMESG_ATTR_FLAG)
+ H5F_SET_STORE_MSG_CRT_IDX(f, TRUE);
+
+ /* Set the ring type to superblock extension */
+ ring = H5AC_RING_SBE;
+ if((H5P_set(dxpl, H5AC_RING_NAME, &ring)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Write shared message information to the superblock extension */
+ sohm_table.addr = H5F_SOHM_ADDR(f);
+ sohm_table.version = H5F_SOHM_VERS(f);
+ sohm_table.nindexes = H5F_SOHM_NINDEXES(f);
+ if(H5O_msg_create(ext_loc, H5O_SHMESG_ID, H5O_MSG_FLAG_CONSTANT | H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &sohm_table, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to update SOHM header message")
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
+
+ if(ret_value < 0) {
+ if(table_addr != HADDR_UNDEF)
+ H5MF_xfree(f, H5FD_MEM_SOHM_TABLE, dxpl_id, table_addr, (hsize_t)table->table_size);
+ if(table != NULL)
+ table = H5FL_FREE(H5SM_master_table_t, table);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_type_to_flag
+ *
+ * Purpose: Get the shared message flag for a given message type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, October 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_type_to_flag(unsigned type_id, unsigned *type_flag)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Translate the H5O type_id into an H5SM type flag */
+ switch(type_id) {
+ case H5O_FILL_ID:
+ type_id = H5O_FILL_NEW_ID;
+ /* Fall through... */
+
+ case H5O_SDSPACE_ID:
+ case H5O_DTYPE_ID:
+ case H5O_FILL_NEW_ID:
+ case H5O_PLINE_ID:
+ case H5O_ATTR_ID:
+ *type_flag = (unsigned)1 << type_id;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "unknown message type ID")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_type_to_flag() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_index
+ *
+ * Purpose: Get the index number for a given message type.
+ *
+ * Returns the number of the index in the supplied table
+ * that holds messages of type type_id, or negative if
+ * there is no index for this message type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, October 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5SM_get_index(const H5SM_master_table_t *table, unsigned type_id)
+{
+ size_t x;
+ unsigned type_flag;
+ ssize_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Translate the H5O type_id into an H5SM type flag */
+ if(H5SM_type_to_flag(type_id, &type_flag) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't map message type to flag")
+
+ /* Search the indexes until we find one that matches this flag or we've
+ * searched them all.
+ */
+ for(x = 0; x < table->num_indexes; ++x)
+ if(table->indexes[x].mesg_types & type_flag)
+ HGOTO_DONE((ssize_t)x)
+
+ /* At this point, ret_value is either the location of the correct
+ * index or it's still FAIL because we didn't find an index.
+ */
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_get_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_type_shared
+ *
+ * Purpose: Check if a given message type is shared in a file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 12, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM_type_shared(H5F_t *f, unsigned type_id, hid_t dxpl_id)
+{
+ H5SM_master_table_t *table = NULL; /* Shared object master table */
+ unsigned type_flag; /* Flag corresponding to message type */
+ size_t u; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Translate the H5O type_id into an H5SM type flag */
+ if(H5SM_type_to_flag(type_id, &type_flag) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't map message type to flag")
+
+ /* Look up the master SOHM table */
+ if(H5F_addr_defined(H5F_SOHM_ADDR(f))) {
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+ } /* end if */
+ else
+ /* No shared messages of any type */
+ HGOTO_DONE(FALSE)
+
+ /* Search the indexes until we find one that matches this flag or we've
+ * searched them all.
+ */
+ for(u = 0; u < table->num_indexes; u++)
+ if(table->indexes[u].mesg_types & type_flag)
+ HGOTO_DONE(TRUE)
+
+done:
+ /* Release the master SOHM table */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_type_shared() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_fheap_addr
+ *
+ * Purpose: Gets the address of the fractal heap used to store
+ * messages of type type_id.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, October 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_get_fheap_addr(H5F_t *f, hid_t dxpl_id, unsigned type_id, haddr_t *fheap_addr)
+{
+ H5SM_master_table_t *table = NULL; /* Shared object master table */
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ ssize_t index_num; /* Which index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(fheap_addr);
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Look up index for message type */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to find correct SOHM index")
+
+ /* Retrieve heap address for index */
+ *fheap_addr = table->indexes[index_num].heap_addr;
+
+done:
+ /* Release the master SOHM table */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_get_fheap_addr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_create_index
+ *
+ * Purpose: Allocates storage for an index, populating the HEADER struct.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_create_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id)
+{
+ H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(header);
+ HDassert(header->index_addr == HADDR_UNDEF);
+ HDassert(header->btree_min <= header->list_max + 1);
+
+ /* In most cases, the index starts as a list */
+ if(header->list_max > 0) {
+ haddr_t list_addr = HADDR_UNDEF; /* Address of SOHM list */
+
+ /* Create the list index */
+ if((list_addr = H5SM_create_list(f, header, dxpl_id)) == HADDR_UNDEF)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "list creation failed for SOHM index")
+
+ /* Set the index type & address */
+ header->index_type = H5SM_LIST;
+ header->index_addr = list_addr;
+ } /* end if */
+ /* index is a B-tree */
+ else {
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ haddr_t tree_addr = HADDR_UNDEF; /* Address of SOHM B-tree */
+
+ /* Create the v2 B-tree index */
+ bt2_cparam.cls = H5SM_INDEX;
+ bt2_cparam.node_size = (uint32_t)H5SM_B2_NODE_SIZE;
+ bt2_cparam.rrec_size = (uint32_t)H5SM_SOHM_ENTRY_SIZE(f);
+ bt2_cparam.split_percent = H5SM_B2_SPLIT_PERCENT;
+ bt2_cparam.merge_percent = H5SM_B2_MERGE_PERCENT;
+ if(NULL == (bt2 = H5B2_create(f, dxpl_id, &bt2_cparam, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "B-tree creation failed for SOHM index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2, &tree_addr) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for SOHM index")
+
+ /* Set the index type & address */
+ header->index_type = H5SM_BTREE;
+ header->index_addr = tree_addr;
+ } /* end else */
+
+ /* Create a heap to hold the shared messages that the list or B-tree will index */
+ HDmemset(&fheap_cparam, 0, sizeof(fheap_cparam));
+ fheap_cparam.managed.width = H5O_FHEAP_MAN_WIDTH;
+ fheap_cparam.managed.start_block_size = H5O_FHEAP_MAN_START_BLOCK_SIZE;
+ fheap_cparam.managed.max_direct_size = H5O_FHEAP_MAN_MAX_DIRECT_SIZE;
+ fheap_cparam.managed.max_index = H5O_FHEAP_MAN_MAX_INDEX;
+ fheap_cparam.managed.start_root_rows = H5O_FHEAP_MAN_START_ROOT_ROWS;
+ fheap_cparam.checksum_dblocks = H5O_FHEAP_CHECKSUM_DBLOCKS;
+ fheap_cparam.id_len = 0;
+ fheap_cparam.max_man_size = H5O_FHEAP_MAX_MAN_SIZE;
+ if(NULL == (fheap = H5HF_create(f, dxpl_id, &fheap_cparam)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create fractal heap")
+
+ if(H5HF_get_heap_addr(fheap, &(header->heap_addr)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap address")
+
+#ifndef NDEBUG
+{
+ size_t fheap_id_len; /* Size of a fractal heap ID */
+
+ /* Sanity check ID length */
+ if(H5HF_get_id_len(fheap, &fheap_id_len) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length")
+ HDassert(fheap_id_len == H5O_FHEAP_ID_LEN);
+}
+#endif /* NDEBUG */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_create_index */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_delete_index
+ *
+ * Purpose: De-allocates storage for an index whose header is HEADER.
+ *
+ * If DELETE_HEAP is TRUE, deletes the index's heap, eliminating
+ * it completely.
+ *
+ * If DELETE_HEAP is FALSE, the heap is not deleted. This is
+ * useful when deleting only the index header as the index is
+ * converted from a list to a B-tree and back again.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, January 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_delete_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id,
+ hbool_t delete_heap)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Determine whether index is a list or a B-tree. */
+ if(header->index_type == H5SM_LIST) {
+ unsigned index_status = 0; /* Index list's status in the metadata cache */
+
+ /* Check the index list's status in the metadata cache */
+ if(H5AC_get_entry_status(f, header->index_addr, &index_status) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to check metadata cache status for direct block")
+
+ /* If the index list is in the cache, expunge it now */
+ if(index_status & H5AC_ES__IN_CACHE) {
+ /* Sanity checks on index list */
+ HDassert(!(index_status & H5AC_ES__IS_PINNED));
+ HDassert(!(index_status & H5AC_ES__IS_PROTECTED));
+
+ /* Evict the index list from the metadata cache */
+ if(H5AC_expunge_entry(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to remove list index from cache")
+ } /* end if */
+ } /* end if */
+ else {
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* Delete the B-tree. */
+ if(H5B2_delete(f, dxpl_id, header->index_addr, f, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete B-tree")
+
+ /* Revert to list unless B-trees can have zero records */
+ if(header->btree_min > 0)
+ header->index_type = H5SM_LIST;
+ } /* end else */
+
+ /* Free the index's heap if requested. */
+ if(delete_heap == TRUE) {
+ if(H5HF_delete(f, dxpl_id, header->heap_addr) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
+ header->heap_addr = HADDR_UNDEF;
+ } /* end if */
+
+ /* Reset index info */
+ header->index_addr = HADDR_UNDEF;
+ header->num_messages = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_delete_index */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_create_list
+ *
+ * Purpose: Creates a list of SOHM messages.
+ *
+ * Called when a new index is created from scratch or when a
+ * B-tree needs to be converted back into a list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, August 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5SM_create_list(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id)
+{
+ H5SM_list_t *list = NULL; /* List of messages */
+ hsize_t x; /* Counter variable */
+ size_t num_entries; /* Number of messages to create in list */
+ haddr_t addr = HADDR_UNDEF; /* Address of the list on disk */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, HADDR_UNDEF)
+
+ HDassert(f);
+ HDassert(header);
+
+ num_entries = header->list_max;
+
+ /* Allocate list in memory */
+ if(NULL == (list = H5FL_CALLOC(H5SM_list_t)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+ if(NULL == (list->messages = (H5SM_sohm_t *)H5FL_ARR_CALLOC(H5SM_sohm_t, num_entries)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+
+ /* Initialize messages in list */
+ for(x = 0; x < num_entries; x++)
+ list->messages[x].location = H5SM_NO_LOC;
+
+ /* Point list at header passed in */
+ list->header = header;
+
+ /* Allocate space for the list on disk */
+ if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_SOHM_INDEX, dxpl_id, (hsize_t)header->list_size)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+
+ /* Put the list into the cache */
+ if(H5AC_insert_entry(f, dxpl_id, H5AC_SOHM_LIST, addr, list, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINS, HADDR_UNDEF, "can't add SOHM list to cache")
+
+ /* Set return value */
+ ret_value = addr;
+
+done:
+ if(ret_value == HADDR_UNDEF) {
+ if(list != NULL) {
+ if(list->messages != NULL)
+ list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
+ list = H5FL_FREE(H5SM_list_t, list);
+ } /* end if */
+ if(addr != HADDR_UNDEF)
+ H5MF_xfree(f, H5FD_MEM_SOHM_INDEX, dxpl_id, addr, (hsize_t)header->list_size);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF)
+} /* end H5SM_create_list */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_convert_list_to_btree
+ *
+ * Purpose: Given a list index, turns it into a B-tree index. This is
+ * done when too many messages are added to the list.
+ *
+ * Requires that *_LIST be a valid list and currently protected
+ * in the cache. Unprotects (and expunges) *_LIST from the cache.
+ *
+ * _LIST needs to be a double pointer so that the calling function
+ * knows if it is released from the cache if this function exits
+ * in error. Trying to free it again will trigger an assert.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, January 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_convert_list_to_btree(H5F_t *f, H5SM_index_header_t *header,
+ H5SM_list_t **_list, H5HF_t *fheap, H5O_t *open_oh, hid_t dxpl_id)
+{
+ H5SM_list_t *list; /* Pointer to the existing message list */
+ H5SM_mesg_key_t key; /* Key for inserting records in v2 B-tree */
+ H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ haddr_t tree_addr; /* New v2 B-tree's address */
+ size_t num_messages; /* Number of messages being tracked */
+ size_t x;
+ void * encoding_buf = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(_list && *_list);
+ HDassert(header);
+
+ /* Get pointer to list of messages to convert */
+ list = *_list;
+
+ /* Create the new v2 B-tree for tracking the messages */
+ bt2_cparam.cls = H5SM_INDEX;
+ bt2_cparam.node_size = (uint32_t)H5SM_B2_NODE_SIZE;
+ bt2_cparam.rrec_size = (uint32_t)H5SM_SOHM_ENTRY_SIZE(f);
+ bt2_cparam.split_percent = H5SM_B2_SPLIT_PERCENT;
+ bt2_cparam.merge_percent = H5SM_B2_MERGE_PERCENT;
+ if(NULL == (bt2 = H5B2_create(f, dxpl_id, &bt2_cparam, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "B-tree creation failed for SOHM index")
+
+ /* Retrieve the v2 B-tree's address in the file */
+ if(H5B2_get_addr(bt2, &tree_addr) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for SOHM index")
+
+ /* Set up key values that all messages will use. Since these messages
+ * are in the heap, they have a heap ID and no encoding or type_id.
+ */
+ key.file = f;
+ key.dxpl_id = dxpl_id;
+ key.fheap = fheap;
+ key.encoding_size = 0;
+ key.encoding = NULL;
+
+ /* Insert each record into the new B-tree */
+ for(x = 0; x < header->list_max; x++) {
+ if(list->messages[x].location != H5SM_NO_LOC) {
+ /* Copy message into key */
+ key.message = list->messages[x];
+
+ /* Get the encoded message */
+ if(H5SM_read_mesg(f, &(key.message), fheap, open_oh, dxpl_id, &key.encoding_size, &encoding_buf) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "Couldn't read SOHM message in list")
+
+ key.encoding = encoding_buf;
+
+ /* Insert the message into the B-tree */
+ if(H5B2_insert(bt2, dxpl_id, &key) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "couldn't add SOHM to B-tree")
+
+ /* Free buffer from H5SM_read_mesg */
+ if(encoding_buf)
+ encoding_buf = H5MM_xfree(encoding_buf);
+ } /* end if */
+ } /* end for */
+
+ /* Unprotect list in cache and release heap */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release SOHM list")
+ *_list = list = NULL;
+
+ /* Delete the old list index (but not its heap, which the new index is
+ * still using!)
+ */
+ num_messages = header->num_messages; /* preserve this across the index deletion */
+ if(H5SM_delete_index(f, header, dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "can't free list index")
+
+ /* Set/restore header info */
+ header->index_addr = tree_addr;
+ header->index_type = H5SM_BTREE;
+ header->num_messages = num_messages;
+
+done:
+ /* Release resources */
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+ if(encoding_buf)
+ encoding_buf = H5MM_xfree(encoding_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5SM_convert_list_to_btree() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_convert_btree_to_list
+ *
+ * Purpose: Given a B-tree index, turns it into a list index. This is
+ * done when too many messages are deleted from the B-tree.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, January 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_convert_btree_to_list(H5F_t * f, H5SM_index_header_t * header, hid_t dxpl_id)
+{
+ H5SM_list_t *list = NULL;
+ H5SM_list_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ haddr_t btree_addr;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Remember the address of the old B-tree, but change the header over to be
+ * a list..
+ */
+ btree_addr = header->index_addr;
+
+ header->num_messages = 0;
+ header->index_type = H5SM_LIST;
+
+ /* Create a new list index */
+ if(HADDR_UNDEF == (header->index_addr = H5SM_create_list(f, header, dxpl_id)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create shared message list")
+
+ /* Set up user data for metadata cache callback */
+ cache_udata.f = f;
+ cache_udata.header = header;
+
+ /* Protect the SOHM list */
+ if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM list index")
+
+ /* Delete the B-tree and have messages copy themselves to the
+ * list as they're deleted
+ */
+ if(H5B2_delete(f, dxpl_id, btree_addr, f, H5SM_bt2_convert_to_list_op, list) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete B-tree")
+
+done:
+ /* Release the SOHM list from the cache */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect SOHM index")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_convert_btree_to_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_can_share_common
+ *
+ * Purpose: "trivial" checks for determining if a message can be shared.
+ *
+ * Note: These checks are common to the "can share" and "try share"
+ * routines and are the "fast" checks before we need to protect
+ * the SOHM master table.
+ *
+ * Return: TRUE if message could be a SOHM
+ * FALSE if this message couldn't be a SOHM
+ * Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 21, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5SM_can_share_common(const H5F_t *f, unsigned type_id, const void *mesg)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check whether this message ought to be shared or not */
+ /* If sharing is disabled in this file, don't share the message */
+ if(!H5F_addr_defined(H5F_SOHM_ADDR(f)))
+ HGOTO_DONE(FALSE)
+
+ /* Type-specific check */
+ if((ret_value = H5O_msg_can_share(type_id, mesg)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "can_share callback returned error")
+ if(ret_value == FALSE)
+ HGOTO_DONE(FALSE)
+
+ /* At this point, the message passes the "trivial" checks and is worth
+ * further checks.
+ */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_can_share_common() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_can_share
+ *
+ * Purpose: Checks if an object header message would be shared or is
+ * already shared.
+ *
+ * If not, returns FALSE and does nothing.
+ *
+ * Return: TRUE if message will be a SOHM
+ * FALSE if this message won't be a SOHM
+ * Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, February 21, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table,
+ ssize_t *sohm_index_num, unsigned type_id, const void *mesg)
+{
+ size_t mesg_size;
+ H5SM_master_table_t *my_table = NULL;
+ ssize_t index_num;
+ htri_t tri_ret;
+ htri_t ret_value = TRUE;
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* "trivial" sharing checks */
+ if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error")
+ if(tri_ret == FALSE)
+ HGOTO_DONE(FALSE)
+
+ /* Look up the master SOHM table */
+ /* (use incoming master SOHM table if possible) */
+ if(table)
+ my_table = table;
+ else {
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ if(NULL == (my_table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+ } /* end if */
+
+ /* Find the right index for this message type. If there is no such index
+ * then this type of message isn't shareable
+ */
+ if((index_num = H5SM_get_index(my_table, type_id)) < 0) {
+ H5E_clear_stack(NULL); /*ignore error*/
+ HGOTO_DONE(FALSE)
+ } /* end if */
+
+ /* If the message isn't big enough, don't bother sharing it */
+ if(0 == (mesg_size = H5O_msg_raw_size(f, type_id, TRUE, mesg)))
+ HGOTO_ERROR(H5E_SOHM, H5E_BADMESG, FAIL, "unable to get OH message size")
+ if(mesg_size < my_table->indexes[index_num].min_mesg_size)
+ HGOTO_DONE(FALSE)
+
+ /* At this point, the message will be shared, set the index number if requested. */
+ if(sohm_index_num)
+ *sohm_index_num = index_num;
+
+done:
+ /* Release the master SOHM table, if we protected it */
+ if(my_table && my_table != table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), my_table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_can_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_try_share
+ *
+ * Purpose: Attempts to share an object header message.
+ *
+ * MESG_LOC is an H5O_mesg_loc_t struct that gives the message's
+ * location in an object header (address and index). This
+ * function sets the type_id in MESG_LOC.
+ * If MESG_LOC is not NULL, this message will be "unique but
+ * shareable" and will be entered in the index but not actually
+ * shared. If it is NULL, this message will be fully shared if
+ * it is shareable at all.
+ *
+ * OPEN_OH is the object header that is currently open and
+ * protected. If NULL, the SM module will protect any object
+ * header it needs (which can cause an error if that OH is
+ * already protected!).
+ *
+ * DEFER_FLAGS indicates whether the sharing operation should
+ * actually occur, or whether this is just a set up call for a
+ * future sharing operation. In the latter case this argument
+ * should be H5SM_DEFER. If the message was previously deferred
+ * this argument should be H5SM_WAS_DEFERRED.
+ *
+ * MESG_FLAGS will have the H5O_MSG_FLAG_SHAREABLE or
+ * H5O_MSG_FLAG_SHARED flag set if one is appropriate. This is
+ * the only way to tell the difference between a message that
+ * has just been fully shared and a message that is only
+ * "shareable" and is still in the object header, so it cannot
+ * be NULL if MESG_LOC is not NULL. If MESG_LOC is NULL, then
+ * the message won't be "unique but shareable" and MESG_FLAGS
+ * can be NULL as well.
+ *
+ * If the message should be shared (if sharing has been
+ * enabled and this message qualifies), this function turns the
+ * message into a shared message, sets the H5O_MSG_FLAG_SHARED
+ * flag in mesg_flags, and returns TRUE.
+ *
+ * If the message isn't shared, returns FALSE. If the message
+ * isn't shared but was entered in the shared message index,
+ * the H5O_MSG_FLAG_SHAREABLE flag will be set in mesg_flags
+ * and returns TRUE.
+ *
+ * If this message was already shared, increments its reference
+ * count, and leaves it otherwise unchanged, returning TRUE and
+ * setting the H5O_MSG_FLAG_SHARED flag in mesg_flags.
+ *
+ * If mesg_flags is NULL, the calling function should just look
+ * at the return value to determine if the message was shared
+ * or not. Such messages should never be "unique but shareable."
+ *
+ * Return: TRUE if message is now a SOHM
+ * FALSE if this message is not a SOHM
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM_try_share(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned defer_flags,
+ unsigned type_id, void *mesg, unsigned *mesg_flags)
+{
+ H5SM_master_table_t *table = NULL;
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+ ssize_t index_num;
+ htri_t tri_ret;
+#ifndef NDEBUG
+ unsigned deferred_type = -1u;
+#endif
+ htri_t ret_value = TRUE;
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* If we previously deferred this operation, the saved message type should
+ * be the same as the one we get here. In debug mode, we make sure this
+ * holds true; otherwise we can leave now if it wasn't shared in the DEFER
+ * pass. */
+ if(defer_flags & H5SM_WAS_DEFERRED)
+#ifndef NDEBUG
+ deferred_type = ((H5O_shared_t *)mesg)->type;
+#else /* NDEBUG */
+ if((((H5O_shared_t *)mesg)->type != H5O_SHARE_TYPE_HERE)
+ && (((H5O_shared_t *)mesg)->type != H5O_SHARE_TYPE_SOHM))
+ HGOTO_DONE(FALSE);
+#endif /* NDEBUG */
+
+ /* "trivial" sharing checks */
+ if(mesg_flags && (*mesg_flags & H5O_MSG_FLAG_DONTSHARE))
+ HGOTO_DONE(FALSE)
+ if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error")
+ if(tri_ret == FALSE)
+ HGOTO_DONE(FALSE)
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* "complex" sharing checks */
+ if((tri_ret = H5SM_can_share(f, dxpl_id, table, &index_num, type_id, mesg)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'complex' sharing checks returned error")
+ if(tri_ret == FALSE)
+ HGOTO_DONE(FALSE)
+
+ /* At this point, the message will be shared. */
+
+ /* If the index hasn't been allocated yet, create it */
+ if(table->indexes[index_num].index_addr == HADDR_UNDEF) {
+ if(H5SM_create_index(f, &(table->indexes[index_num]), dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create SOHM index")
+ cache_flags |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+ /* Write the message as a shared message. This may or may not cause the
+ * message to become shared (if it is unique, it will not be shared).
+ */
+ if(H5SM_write_mesg(f, dxpl_id, open_oh, &(table->indexes[index_num]),
+ (defer_flags & H5SM_DEFER) != 0, type_id, mesg, &cache_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "can't write shared message")
+
+ /* Set flags if this message was "written" without error and wasn't a
+ * 'defer' attempt; it is now either fully shared or "shareable".
+ */
+ if(mesg_flags) {
+ if(((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_HERE)
+ *mesg_flags |= H5O_MSG_FLAG_SHAREABLE;
+ else {
+ HDassert(((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_SOHM);
+ *mesg_flags |= H5O_MSG_FLAG_SHARED;
+ } /* end else */
+ } /* end if */
+
+done:
+ HDassert((ret_value != TRUE)
+ || ((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_HERE
+ || ((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_SOHM);
+#ifndef NDEBUG
+ /* If we previously deferred this operation, make sure the saved message
+ * type is the same as the one we get here. */
+ if(defer_flags & H5SM_WAS_DEFERRED)
+ HDassert(deferred_type == ((H5O_shared_t *)mesg)->type);
+#endif /* NDEBUG */
+
+ /* Release the master SOHM table */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_try_share() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_incr_ref
+ *
+ * Purpose: Increment the reference count for a SOHM message and return
+ * the message's heap ID.
+ *
+ * The message pointer is actually returned via op_data, which
+ * should be a pointer to a H5SM_fheap_id_t.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_incr_ref(void *record, void *_op_data, hbool_t *changed)
+{
+ H5SM_sohm_t *message = (H5SM_sohm_t *) record;
+ H5SM_incr_ref_opdata *op_data = (H5SM_incr_ref_opdata *) _op_data;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(record);
+ HDassert(op_data);
+ HDassert(changed);
+
+ /* If the message was previously shared in an object header, share
+ * it in the heap now.
+ */
+ if(message->location == H5SM_IN_OH) {
+ HDassert(op_data->key && op_data->key->fheap);
+
+ /* Put the message in the heap and record its new heap ID */
+ if(H5HF_insert(op_data->key->fheap, op_data->dxpl_id, op_data->key->encoding_size, op_data->key->encoding, &message->u.heap_loc.fheap_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
+
+ message->location = H5SM_IN_HEAP;
+ message->u.heap_loc.ref_count = 2;
+ } /* end if */
+ else {
+ HDassert(message->location == H5SM_IN_HEAP);
+ /* If it's already in the heap, just increment the ref count */
+ ++message->u.heap_loc.ref_count;
+ } /* end else */
+
+ /* If we got here, the message has changed */
+ *changed = TRUE;
+
+ /* Check for retrieving the heap ID */
+ if(op_data)
+ op_data->fheap_id = message->u.heap_loc.fheap_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_incr_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_write_mesg
+ *
+ * Purpose: This routine adds a shareable message to an index.
+ * The behavior is controlled by the DEFER parameter:
+ *
+ * If DEFER is TRUE, this routine Simulates adding a shareable
+ * message to an index. It determines what the outcome would
+ * be with DEFER set the FALSE and updates the shared message
+ * info, but does not actually add the message to a heap, list,
+ * or b-tree. Assumes that an open object header will be
+ * available when H5SM_write_mesg is called with DEFER set to
+ * FALSE.
+ *
+ * If DEFER is FALSE, this routine adds a shareable message to
+ * an index. If this is the first such message and we have an
+ * object header location for this message, we record it in the
+ * index but don't modify the message passed in. If the message
+ * is already in the index or we don't have an object header
+ * location for it, it is shared in the heap and this function
+ * sets its sharing struct to reflect this.
+ *
+ * The index could be a list or a B-tree.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ H5SM_index_header_t *header, hbool_t defer, unsigned type_id, void *mesg,
+ unsigned *cache_flags_ptr)
+{
+ H5SM_list_t *list = NULL; /* List index */
+ H5SM_mesg_key_t key; /* Key used to search the index */
+ H5SM_list_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ H5O_shared_t shared; /* Shared H5O message */
+ hbool_t found = FALSE; /* Was the message in the index? */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ size_t buf_size; /* Size of the encoded message */
+ void * encoding_buf = NULL; /* Buffer for encoded message */
+ size_t empty_pos = UFAIL; /* Empty entry in list */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(header);
+ HDassert(header->index_type != H5SM_BADTYPE);
+ HDassert(cache_flags_ptr);
+
+ /* Encode the message to be written */
+ if((buf_size = H5O_msg_raw_size(f, type_id, TRUE, mesg)) == 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADSIZE, FAIL, "can't find message size")
+ if(NULL == (encoding_buf = H5MM_malloc(buf_size)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "can't allocate buffer for encoding")
+ if(H5O_msg_encode(f, type_id, TRUE, (unsigned char *)encoding_buf, mesg) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, FAIL, "can't encode message to be shared")
+
+ /* Open the fractal heap for this index */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up a key for the message to be written */
+ key.dxpl_id = dxpl_id;
+ key.file = f;
+ key.fheap = fheap;
+ key.encoding = encoding_buf;
+ key.encoding_size = buf_size;
+ key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
+ key.message.location = H5SM_NO_LOC;
+
+ /* Assume the message is already in the index and try to increment its
+ * reference count. If this fails, the message isn't in the index after
+ * all and we'll need to add it.
+ */
+ if(header->index_type == H5SM_LIST) {
+ size_t list_pos; /* Position in a list index */
+
+ /* Set up user data for metadata cache callback */
+ cache_udata.f = f;
+ cache_udata.header = header;
+
+ /* The index is a list; get it from the cache */
+ if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, defer ? H5AC__READ_ONLY_FLAG : H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* See if the message is already in the index and get its location.
+ * Also record the first empty list position we find in case we need it
+ * later.
+ */
+ if(H5SM__find_in_list(list, &key, &empty_pos, &list_pos) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to search for message in list")
+
+ if(defer) {
+ if(list_pos != UFAIL)
+ found = TRUE;
+ } /* end if */
+ else {
+ if(list_pos != UFAIL) {
+ /* If the message was previously shared in an object header, share
+ * it in the heap now.
+ */
+ if(list->messages[list_pos].location == H5SM_IN_OH) {
+ /* Put the message in the heap and record its new heap ID */
+ if(H5HF_insert(fheap, dxpl_id, key.encoding_size, key.encoding, &shared.u.heap_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
+
+ list->messages[list_pos].location = H5SM_IN_HEAP;
+ list->messages[list_pos].u.heap_loc.fheap_id = shared.u.heap_id;
+ list->messages[list_pos].u.heap_loc.ref_count = 2;
+ } /* end if */
+ else {
+ /* If the message was already in the heap, increase its ref count */
+ HDassert(list->messages[list_pos].location == H5SM_IN_HEAP);
+ ++(list->messages[list_pos].u.heap_loc.ref_count);
+ } /* end else */
+
+ /* Set up the shared location to point to the shared location */
+ shared.u.heap_id = list->messages[list_pos].u.heap_loc.fheap_id;
+ found = TRUE;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ /* Index is a B-tree */
+ else {
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+
+ if(defer) {
+ htri_t bt2_find; /* Result from searching in the v2 B-tree */
+
+ /* If this returns 0, it means that the message wasn't found. */
+ /* If it return 1, set the heap_id in the shared struct. It will
+ * return a heap ID, since a message with a reference count greater
+ * than 1 is always shared in the heap.
+ */
+ if((bt2_find = H5B2_find(bt2, dxpl_id, &key, NULL, NULL)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "can't search for message in index")
+ found = (hbool_t)bt2_find;
+ } /* end if */
+ else {
+ H5SM_incr_ref_opdata op_data;
+
+ /* Set up callback info */
+ op_data.key = &key;
+ op_data.dxpl_id = dxpl_id;
+
+ /* If this returns failure, it means that the message wasn't found. */
+ /* If it succeeds, set the heap_id in the shared struct. It will
+ * return a heap ID, since a message with a reference count greater
+ * than 1 is always shared in the heap.
+ */
+ if(H5B2_modify(bt2, dxpl_id, &key, H5SM_incr_ref, &op_data) >= 0) {
+ shared.u.heap_id = op_data.fheap_id;
+ found = TRUE;
+ } /* end if */
+ else
+ H5E_clear_stack(NULL); /*ignore error*/
+ } /* end else */
+ } /* end else */
+
+ if(found) {
+ /* If the message was found, it's shared in the heap (now). Set up a
+ * shared message so we can mark it as shared.
+ */
+ shared.type = H5O_SHARE_TYPE_SOHM;
+
+#ifdef H5_USING_MEMCHECKER
+ /* Reset the shared message payload if deferring. This doesn't matter
+ * in the long run since the payload will get overwritten when the
+ * non-deferred call to this routine occurs, but it stops memory
+ * checkers like valgrind from whining when the partially initialized
+ * shared message is serialized. -QAK
+ */
+ if(defer)
+ HDmemset(&shared.u, 0, sizeof(shared.u));
+#endif /* H5_USING_MEMCHECKER */
+ } /* end if */
+ else {
+ htri_t share_in_ohdr; /* Whether the new message can be shared in another object's header */
+
+ /* Add the message to the index */
+
+ /* Check if the message can be shared in another object's header */
+ if((share_in_ohdr = H5O_msg_can_share_in_ohdr(type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'share in ohdr' check returned error")
+
+ /* If this message can be shared in an object header location, it is
+ * "shareable" but not shared in the heap.
+ *
+ * If 'defer' flag is set:
+ * We will insert it in the index but not modify the original
+ * message.
+ * If it can't be shared in an object header location, we will
+ * insert it in the heap. Note that we will only share
+ * the message in the object header if there is an
+ * "open_oh" available.
+ *
+ * If 'defer' flag is not set:
+ * Insert it in the index but don't modify the original message.
+ * If it can't be shared in an object header location or there's
+ * no object header location available, insert it in the
+ * heap.
+ */
+ if(share_in_ohdr && open_oh) {
+ /* Set up shared component info */
+ shared.type = H5O_SHARE_TYPE_HERE;
+
+ /* Retrieve any creation index from the native message */
+ if(H5O_msg_get_crt_index(type_id, mesg, &shared.u.loc.index) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to retrieve creation index")
+
+ if(defer)
+ shared.u.loc.oh_addr = HADDR_UNDEF;
+ else {
+ shared.u.loc.oh_addr = H5O_OH_GET_ADDR(open_oh);
+
+ /* Copy shared component info into key for inserting into index */
+ key.message.location = H5SM_IN_OH;
+ key.message.u.mesg_loc = shared.u.loc;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Set up shared component info */
+ /* (heap ID set below, if not deferred) */
+ shared.type = H5O_SHARE_TYPE_SOHM;
+
+ if(!defer) {
+ /* Put the message in the heap and record its new heap ID */
+ if(H5HF_insert(fheap, dxpl_id, key.encoding_size, key.encoding, &shared.u.heap_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
+
+ key.message.location = H5SM_IN_HEAP;
+ key.message.u.heap_loc.fheap_id = shared.u.heap_id;
+ key.message.u.heap_loc.ref_count = 1;
+ } /* end if */
+ } /* end else */
+
+ if(!defer) {
+ /* Set common information */
+ key.message.msg_type_id = type_id;
+
+ /* Check whether the list has grown enough that it needs to become a B-tree */
+ if(header->index_type == H5SM_LIST && header->num_messages >= header->list_max)
+ if(H5SM_convert_list_to_btree(f, header, &list, fheap, open_oh, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to convert list to B-tree")
+
+ /* Insert the new message into the SOHM index */
+ if(header->index_type == H5SM_LIST) {
+ /* Index is a list. Find an empty spot if we haven't already */
+ if(empty_pos == UFAIL) {
+ size_t pos;
+
+ if(H5SM__find_in_list(list, NULL, &empty_pos, &pos) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to search for message in list")
+
+ if(pos == UFAIL || empty_pos == UFAIL)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to find empty entry in list")
+ }
+ /* Insert message into list */
+ HDassert(list->messages[empty_pos].location == H5SM_NO_LOC);
+ HDassert(key.message.location != H5SM_NO_LOC);
+ list->messages[empty_pos] = key.message;
+ } /* end if */
+ /* Index is a B-tree */
+ else {
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* Open the index v2 B-tree, if it isn't already */
+ if(NULL == bt2) {
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+ } /* end if */
+
+ if(H5B2_insert(bt2, dxpl_id, &key) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "couldn't add SOHM to B-tree")
+ } /* end else */
+
+ ++(header->num_messages);
+ (*cache_flags_ptr) |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ } /* end else */
+
+ /* Set the file pointer & message type for the shared component */
+ shared.file = f;
+ shared.msg_type_id = type_id;
+
+ /* Update the original message's shared component */
+ if(H5O_msg_set_share(type_id, &shared, mesg) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADMESG, FAIL, "unable to set sharing information")
+
+done:
+ /* Release the fractal heap & v2 B-tree if we opened them */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+
+ /* If we got a list out of the cache, release it (it is always dirty after writing a message) */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, defer ? H5AC__NO_FLAGS_SET : H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+
+ if(encoding_buf)
+ encoding_buf = H5MM_xfree(encoding_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_write_mesg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_delete
+ *
+ * Purpose: Given an object header message that is being deleted,
+ * checks if it is a SOHM. If so, decrements its reference
+ * count.
+ *
+ * If an object header is currently protected, it needs to
+ * be passed in as open_oh so the SM code doesn't try to
+ * re-protect it.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, H5O_shared_t *sh_mesg)
+{
+ H5SM_master_table_t *table = NULL;
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ ssize_t index_num;
+ void *mesg_buf = NULL;
+ void *native_mesg = NULL;
+ unsigned type_id; /* Message type ID to operate on */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
+ HDassert(sh_mesg);
+
+ /* Get message type */
+ type_id = sh_mesg->msg_type_id;
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Find the correct index and try to delete from it */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to find correct SOHM index")
+
+ /* If mesg_buf is not NULL, the message's reference count has reached
+ * zero and any file space it uses needs to be freed. mesg_buf holds the
+ * serialized form of the message.
+ */
+ if(H5SM_delete_from_index(f, dxpl_id, open_oh, &(table->indexes[index_num]), sh_mesg, &cache_flags, &mesg_buf) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete mesage from SOHM index")
+
+ /* Release the master SOHM table */
+ if(H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+ table = NULL;
+
+ /* If buf was allocated, delete the message it holds. This message may
+ * reference other shared messages that also need to be deleted, so the
+ * master table needs to be unprotected when we do this.
+ */
+ if(mesg_buf) {
+ if(NULL == (native_mesg = H5O_msg_decode(f, dxpl_id, open_oh, type_id, (const unsigned char *)mesg_buf)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDECODE, FAIL, "can't decode shared message.")
+
+ if(H5O_msg_delete(f, dxpl_id, open_oh, type_id, native_mesg) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "can't delete shared message.")
+ } /* end if */
+
+done:
+ /* Release the master SOHM table (should only happen on error) */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ /* Release any native message we decoded */
+ if(native_mesg)
+ H5O_msg_free(type_id, native_mesg);
+
+ /* Free encoding buf */
+ if(mesg_buf)
+ mesg_buf = H5MM_xfree(mesg_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__find_in_list
+ *
+ * Purpose: Find a message's location in a list. Also find the first
+ * empty location in the list (since if we don't find the
+ * message, we may want to insert it into an open spot).
+ *
+ * If KEY is NULL, simply find the first empty location in the
+ * list.
+ *
+ * If EMPTY_POS is NULL, don't store anything in it.
+ *
+ * Return: Message's position in the list on success
+ * UFAIL if message couldn't be found
+ * empty_pos set to position of empty message or UFAIL.
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__find_in_list(const H5SM_list_t *list, const H5SM_mesg_key_t *key, size_t *empty_pos, size_t *pos)
+{
+ size_t x;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(list);
+ /* Both key and empty_pos can be NULL, but not both! */
+ HDassert(key || empty_pos);
+
+ /* Initialize empty_pos to an invalid value */
+ if(empty_pos)
+ *empty_pos = UFAIL;
+
+ /* Find the first (only) message equal to the key passed in.
+ * Also record the first empty position we find.
+ */
+ for(x = 0; x < list->header->list_max; x++) {
+ if(list->messages[x].location != H5SM_NO_LOC) {
+ int cmp;
+
+ if(H5SM__message_compare(key, &(list->messages[x]), &cmp) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCOMPARE, FAIL, "can't compare message records")
+
+ if(0 == cmp) {
+ *pos = x;
+ HGOTO_DONE(SUCCEED)
+ }
+ }
+ else if(empty_pos && list->messages[x].location == H5SM_NO_LOC) {
+ /* Note position */
+ *empty_pos = x;
+
+ /* Found earlier position possible, don't check any more */
+ empty_pos = NULL;
+ } /* end if */
+ } /* end for */
+
+ /* If we reached this point, we didn't find the message */
+ *pos = UFAIL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__find_in_list */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_hash_fh_cb
+ *
+ * Purpose: Callback for fractal heap operator, to make copy of link when
+ * when lookup up a link by index
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 7 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_get_hash_fh_cb(const void *obj, size_t obj_len, void *_udata)
+{
+ H5SM_fh_ud_gh_t *udata = (H5SM_fh_ud_gh_t *)_udata; /* User data for fractal heap 'op' callback */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Compute hash value on raw message */
+ udata->hash = H5_checksum_lookup3(obj, obj_len, udata->type_id);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_get_hash_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_decr_ref
+ *
+ * Purpose: Decrement the reference count for a SOHM message. Doesn't
+ * remove the record from the B-tree even if the refcount
+ * reaches zero.
+ *
+ * The new message is returned through op_data. If its
+ * reference count is zero, the calling function should
+ * remove this record from the B-tree.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_decr_ref(void *record, void *op_data, hbool_t *changed)
+{
+ H5SM_sohm_t *message = (H5SM_sohm_t *) record;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(record);
+ HDassert(op_data);
+ HDassert(changed);
+
+ /* Adjust the message's reference count if it's stored in the heap.
+ * Messages stored in object headers always have refcounts of 1,
+ * so the calling function should know to just delete such a message
+ */
+ if(message->location == H5SM_IN_HEAP) {
+ --message->u.heap_loc.ref_count;
+ *changed = TRUE;
+ } /* end if */
+
+ if(op_data)
+ *(H5SM_sohm_t *)op_data = *message;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_decr_ref() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_delete_from_index
+ *
+ * Purpose: Decrement the reference count for a particular message in this
+ * index. If the reference count reaches zero, allocate a buffer
+ * to hold the serialized form of this message so that any
+ * resources it uses can be freed, and return this buffer in
+ * ENCODED_MESG.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ H5SM_index_header_t *header, const H5O_shared_t *mesg,
+ unsigned *cache_flags, void ** /*out*/ encoded_mesg)
+{
+ H5SM_list_t *list = NULL;
+ H5SM_mesg_key_t key;
+ H5SM_sohm_t message; /* Deleted message returned from index */
+ H5SM_sohm_t *message_ptr; /* Pointer to deleted message returned from index */
+ H5HF_t *fheap = NULL; /* Fractal heap that contains the message */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ size_t buf_size; /* Size of the encoded message (out) */
+ void *encoding_buf = NULL; /* The encoded message (out) */
+ unsigned type_id; /* Message type to operate on */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(header);
+ HDassert(mesg);
+ HDassert(cache_flags);
+ HDassert(*encoded_mesg == NULL);
+
+ /* Get the message type for later */
+ type_id = mesg->msg_type_id;
+
+ /* Open the heap for this type of message. */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Get the message size and encoded message for the message to be deleted,
+ * either from its OH or from the heap.
+ */
+ if(mesg->type == H5O_SHARE_TYPE_HERE) {
+ key.message.location = H5SM_IN_OH;
+ key.message.msg_type_id = type_id;
+ key.message.u.mesg_loc = mesg->u.loc;
+ } /* end if */
+ else {
+ key.message.location = H5SM_IN_HEAP;
+ key.message.msg_type_id = type_id;
+ key.message.u.heap_loc.ref_count = 0; /* Refcount isn't relevant here */
+ key.message.u.heap_loc.fheap_id = mesg->u.heap_id;
+ } /* end else */
+
+ /* Get the encoded message */
+ if(H5SM_read_mesg(f, &key.message, fheap, open_oh, dxpl_id, &buf_size, &encoding_buf) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up key for message to be deleted. */
+ key.file = f;
+ key.dxpl_id = dxpl_id;
+ key.fheap = fheap;
+ key.encoding = encoding_buf;
+ key.encoding_size = buf_size;
+ key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
+
+ /* Try to find the message in the index */
+ if(header->index_type == H5SM_LIST) {
+ H5SM_list_cache_ud_t cache_udata; /* User-data for metadata cache callback */
+ size_t list_pos; /* Position of the message in the list */
+
+ /* Set up user data for metadata cache callback */
+ cache_udata.f = f;
+ cache_udata.header = header;
+
+ /* If the index is stored as a list, get it from the cache */
+ if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* Find the message in the list */
+ if(H5SM__find_in_list(list, &key, NULL, &list_pos) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to search for message in list")
+ if(list_pos == UFAIL)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+
+ if(list->messages[list_pos].location == H5SM_IN_HEAP)
+ --(list->messages[list_pos].u.heap_loc.ref_count);
+
+ /* Point to the message */
+ message_ptr = &list->messages[list_pos];
+ } /* end if */
+ else {
+ /* Index is a B-tree */
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+
+ /* If this returns failure, it means that the message wasn't found.
+ * If it succeeds, a copy of the modified message will be returned.
+ */
+ if(H5B2_modify(bt2, dxpl_id, &key, H5SM_decr_ref, &message) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+
+ /* Point to the message */
+ message_ptr = &message;
+ } /* end else */
+
+ /* If the ref count is zero or this message was in an OH (which always
+ * has a ref count of 1) delete the message from the index
+ */
+ if(message_ptr->location == H5SM_IN_OH || message_ptr->u.heap_loc.ref_count == 0) {
+ /* Save the location */
+ H5SM_storage_loc_t old_loc = message_ptr->location;
+
+ /* Updated the index header, so set its dirty flag */
+ --header->num_messages;
+ *cache_flags |= H5AC__DIRTIED_FLAG;
+
+ /* Remove the message from the index */
+ if(header->index_type == H5SM_LIST)
+ message_ptr->location = H5SM_NO_LOC;
+ else {
+ /* Open the index v2 B-tree, if it isn't already */
+ if(NULL == bt2) {
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+ } /* end if */
+
+ if(H5B2_remove(bt2, dxpl_id, &key, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to delete message from index")
+ } /* end else */
+
+ /* Remove the message from the heap if it was stored in the heap*/
+ if(old_loc == H5SM_IN_HEAP)
+ if(H5HF_remove(fheap, dxpl_id, &(message_ptr->u.heap_loc.fheap_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to remove message from heap")
+
+
+ /* Return the message's encoding so anything it references can be freed */
+ *encoded_mesg = encoding_buf;
+
+ /* If there are no messages left in the index, delete it */
+ if(header->num_messages == 0) {
+
+ /* Unprotect cache and release heap */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release SOHM list")
+ list = NULL;
+
+ HDassert(fheap);
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ fheap = NULL;
+
+ /* Delete the index and its heap */
+ if(H5SM_delete_index(f, header, dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "can't delete empty index")
+ } /* end if */
+ else if(header->index_type == H5SM_BTREE && header->num_messages < header->btree_min) {
+ /* Otherwise, if we've just passed the btree-to-list cutoff, convert
+ * this B-tree into a list
+ */
+ if(H5SM_convert_btree_to_list(f, header, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to convert btree to list")
+ } /* end if */
+ } /* end if */
+
+done:
+ /* Release the SOHM list */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+
+ /* Release the fractal heap & v2 B-tree if we opened them */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+
+ /* Free the message encoding, if we're not returning it in encoded_mesg
+ * or if there's been an error.
+ */
+ if(encoding_buf && (NULL == *encoded_mesg || ret_value < 0))
+ encoding_buf = H5MM_xfree(encoding_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_delete_from_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_info
+ *
+ * Purpose: Get the shared message info for a file, if there is any.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, May 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_get_info(const H5O_loc_t *ext_loc, H5P_genplist_t *fc_plist, hid_t dxpl_id)
+{
+ H5F_t *f = ext_loc->file; /* File pointer (convenience variable) */
+ H5O_shmesg_table_t sohm_table; /* SOHM message from superblock extension */
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */
+ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */
+ unsigned tmp_sohm_nindexes; /* Number of shared messages indexes in the table */
+ htri_t status; /* Status for message existing */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(ext_loc);
+ HDassert(f);
+ HDassert(fc_plist);
+
+ /* Check for the extension having a 'shared message info' message */
+ if((status = H5O_msg_exists(ext_loc, H5O_SHMESG_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(status) {
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ unsigned index_flags[H5O_SHMESG_MAX_NINDEXES]; /* Message flags for each index */
+ unsigned minsizes[H5O_SHMESG_MAX_NINDEXES]; /* Minimum message size for each index */
+ unsigned sohm_l2b; /* SOHM list-to-btree cutoff */
+ unsigned sohm_b2l; /* SOHM btree-to-list cutoff */
+ unsigned u; /* Local index variable */
+
+ /* Retrieve the 'shared message info' structure */
+ if(NULL == H5O_msg_read(ext_loc, H5O_SHMESG_ID, &sohm_table, dxpl_id))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "shared message info message not present")
+
+ /* Portably initialize the arrays */
+ HDmemset(index_flags, 0, sizeof(index_flags));
+ HDmemset(minsizes, 0, sizeof(minsizes));
+
+ /* Set SOHM info from file */
+ H5F_SET_SOHM_ADDR(f, sohm_table.addr);
+ H5F_SET_SOHM_VERS(f, sohm_table.version);
+ H5F_SET_SOHM_NINDEXES(f, sohm_table.nindexes);
+ HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
+ HDassert(H5F_SOHM_NINDEXES(f) > 0 && H5F_SOHM_NINDEXES(f) <= H5O_SHMESG_MAX_NINDEXES);
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Set the ring type in the DXPL */
+ if(H5AC_set_ring(dxpl_id, H5AC_RING_USER, &dxpl, &orig_ring) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set ring value")
+
+ /* Read the rest of the SOHM table information from the cache */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Get index conversion limits */
+ sohm_l2b = (unsigned)table->indexes[0].list_max;
+ sohm_b2l = (unsigned)table->indexes[0].btree_min;
+
+ /* Iterate through all indices */
+ for(u = 0; u < table->num_indexes; ++u) {
+ /* Pack information about the individual SOHM index */
+ index_flags[u] = table->indexes[u].mesg_types;
+ minsizes[u] = (unsigned)table->indexes[u].min_mesg_size;
+
+ /* Sanity check */
+ HDassert(sohm_l2b == table->indexes[u].list_max);
+ HDassert(sohm_b2l == table->indexes[u].btree_min);
+
+ /* Check for sharing attributes in this file, which means that creation
+ * indices must be tracked on object header message in the file.
+ */
+ if(index_flags[u] & H5O_SHMESG_ATTR_FLAG)
+ H5F_SET_STORE_MSG_CRT_IDX(f, TRUE);
+ } /* end for */
+
+ /* Set values in the property list */
+ tmp_sohm_nindexes = H5F_SOHM_NINDEXES(f);
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_NINDEXES_NAME, &tmp_sohm_nindexes) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set number of SOHM indexes")
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, index_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set type flags for indexes")
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, minsizes) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set type flags for indexes")
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_LIST_MAX_NAME, &sohm_l2b) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't set SOHM cutoff in property list")
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, &sohm_b2l) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't set SOHM cutoff in property list")
+ } /* end if */
+ else {
+ /* No SOHM info in file */
+ H5F_SET_SOHM_ADDR(f, HADDR_UNDEF);
+ H5F_SET_SOHM_VERS(f, 0);
+ H5F_SET_SOHM_NINDEXES(f, 0);
+
+ /* Shared object header messages are disabled */
+ tmp_sohm_nindexes = H5F_SOHM_NINDEXES(f);
+ if(H5P_set(fc_plist, H5F_CRT_SHMSG_NINDEXES_NAME, &tmp_sohm_nindexes) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set number of SOHM indexes")
+ } /* end else */
+
+done:
+ /* Reset the ring in the DXPL */
+ if(H5AC_reset_ring(dxpl, orig_ring) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
+
+ /* Release the master SOHM table if we took it out of the cache */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_get_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_reconstitute
+ *
+ * Purpose: Reconstitute a shared object header message structure from
+ * a plain heap ID.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 18, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_reconstitute(H5O_shared_t *sh_mesg, H5F_t *f, unsigned msg_type_id,
+ H5O_fheap_id_t heap_id)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check args */
+ HDassert(sh_mesg);
+
+ /* Set flag for shared message */
+ sh_mesg->type = H5O_SHARE_TYPE_SOHM;
+ sh_mesg->file = f;
+ sh_mesg->msg_type_id = msg_type_id;
+ sh_mesg->u.heap_id = heap_id;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_reconstitute() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_refcount_bt2_cb
+ *
+ * Purpose: v2 B-tree 'find' callback to retrieve the record for a message
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_get_refcount_bt2_cb(const void *_record, void *_op_data)
+{
+ const H5SM_sohm_t *record = (const H5SM_sohm_t *)_record; /* v2 B-tree record for message */
+ H5SM_sohm_t *op_data = (H5SM_sohm_t *)_op_data; /* "op data" from v2 B-tree find */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(record);
+ HDassert(op_data);
+
+ /* Make a copy of the record */
+ *op_data = *record;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_get_refcount_bt2_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_refcount
+ *
+ * Purpose: Retrieve the reference count for a message shared in the heap
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id,
+ const H5O_shared_t *sh_mesg, hsize_t *ref_count)
+{
+ H5HF_t *fheap = NULL; /* Fractal heap that contains shared messages */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ H5SM_table_cache_ud_t tbl_cache_udata; /* User-data for callback */
+ H5SM_list_t *list = NULL; /* SOHM index list for message type (if in list form) */
+ H5SM_index_header_t *header=NULL; /* Index header for message type */
+ H5SM_mesg_key_t key; /* Key for looking up message */
+ H5SM_sohm_t message; /* Shared message returned from callback */
+ ssize_t index_num; /* Table index for message type */
+ size_t buf_size; /* Size of the encoded message */
+ void * encoding_buf = NULL; /* Buffer for encoded message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(sh_mesg);
+ HDassert(ref_count);
+
+ /* Set up user data for callback */
+ tbl_cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &tbl_cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Find the correct index and find the message in it */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to find correct SOHM index")
+ header = &(table->indexes[index_num]);
+
+ /* Open the heap for this message type */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up a SOHM message to correspond to the shared message passed in */
+ key.message.location = H5SM_IN_HEAP;
+ key.message.u.heap_loc.fheap_id = sh_mesg->u.heap_id;
+ key.message.u.heap_loc.ref_count = 0; /* Ref count isn't needed to find message */
+
+ /* Get the encoded message */
+ if(H5SM_read_mesg(f, &key.message, fheap, NULL, dxpl_id, &buf_size, &encoding_buf) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up key for message to locate */
+ key.file = f;
+ key.dxpl_id = dxpl_id;
+ key.fheap = fheap;
+ key.encoding = encoding_buf;
+ key.encoding_size = buf_size;
+ key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
+
+ /* Try to find the message in the index */
+ if(header->index_type == H5SM_LIST) {
+ H5SM_list_cache_ud_t lst_cache_udata; /* User-data for metadata cache callback */
+ size_t list_pos; /* Position of the message in the list */
+
+ /* Set up user data for metadata cache callback */
+ lst_cache_udata.f = f;
+ lst_cache_udata.header = header;
+
+ /* If the index is stored as a list, get it from the cache */
+ if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &lst_cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* Find the message in the list */
+ if(H5SM__find_in_list(list, &key, NULL, &list_pos) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to search for message in list")
+ if(list_pos == UFAIL)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+
+ /* Copy the message */
+ message = list->messages[list_pos];
+ } /* end if */
+ else {
+ htri_t msg_exists; /* Whether the message exists in the v2 B-tree */
+
+ /* Index is a B-tree */
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+
+ /* Look up the message in the v2 B-tree */
+ if((msg_exists = H5B2_find(bt2, dxpl_id, &key, H5SM_get_refcount_bt2_cb, &message)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "error finding message in index")
+ if(!msg_exists)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+ } /* end else */
+
+ /* Set the refcount for the message */
+ HDassert(message.location == H5SM_IN_HEAP);
+ *ref_count = message.u.heap_loc.ref_count;
+
+done:
+ /* Release resources */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+ if(encoding_buf)
+ encoding_buf = H5MM_xfree(encoding_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_get_refcount() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_read_iter_op
+ *
+ * Purpose: OH iteration callback to get the encoded version of a message
+ * by index.
+ *
+ * The buffer needs to be freed.
+ *
+ * Return: 0 if this is not the message we're searching for
+ * 1 if this is the message we're searching for (with encoded
+ * value returned in udata)
+ * negative on error
+ *
+ * Programmer: James Laird
+ * Wednesday, February 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_read_iter_op(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence,
+ unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5SM_read_udata_t *udata = (H5SM_read_udata_t *) _udata;
+ herr_t ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(udata);
+ HDassert(NULL == udata->encoding_buf);
+
+ /* Check the creation index for this message */
+ if(sequence == udata->idx) {
+ /* Check if the message is dirty & flush it to the object header if so */
+ if(mesg->dirty)
+ if(H5O_msg_flush(udata->file, oh, mesg) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, H5_ITER_ERROR, "unable to encode object header message")
+
+ /* Get the message's encoded size */
+ udata->buf_size = mesg->raw_size;
+ HDassert(udata->buf_size);
+
+ /* Allocate buffer to return the message in */
+ if(NULL == (udata->encoding_buf = H5MM_malloc(udata->buf_size)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed")
+
+ /* Copy the encoded message into the buffer to return */
+ HDmemcpy(udata->encoding_buf, mesg->raw, udata->buf_size);
+
+ /* Found the message we were looking for */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_read_iter_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_read_mesg_fh_cb
+ *
+ * Purpose: Callback for H5HF_op, used in H5SM_read_mesg below.
+ * Makes a copy of the message in the heap data, returned in the
+ * UDATA struct.
+ *
+ * Return: Negative on error, non-negative on success
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 26, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_read_mesg_fh_cb(const void *obj, size_t obj_len, void *_udata)
+{
+ H5SM_read_udata_t *udata = (H5SM_read_udata_t *)_udata;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate a buffer to hold the message */
+ if(NULL == (udata->encoding_buf = H5MM_malloc(obj_len)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Copy the message from the heap */
+ HDmemcpy(udata->encoding_buf, obj, obj_len);
+ udata->buf_size = obj_len;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_read_mesg_fh_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_read_mesg
+ *
+ * Purpose: Given an H5SM_sohm_t sohm, encodes the message into a buffer.
+ * This buffer should then be freed.
+ *
+ * Return: Non-negative on success/negative on error
+ *
+ * Programmer: James Laird
+ * Wednesday, February 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap,
+ H5O_t *open_oh, hid_t dxpl_id, size_t *encoding_size /*out*/,
+ void ** encoded_mesg /*out*/)
+{
+ H5SM_read_udata_t udata; /* User data for callbacks */
+ H5O_loc_t oloc; /* Object location for message in object header */
+ H5O_t *oh = NULL; /* Object header for message in object header */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(mesg);
+ HDassert(fheap);
+
+ /* Set up user data for message iteration */
+ udata.file = f;
+ udata.idx = mesg->u.mesg_loc.index;
+ udata.encoding_buf = NULL;
+ udata.idx = 0;
+
+ /* Get the message size and encoded message for the message to be deleted,
+ * either from its OH or from the heap.
+ */
+ if(mesg->location == H5SM_IN_OH) {
+ /* Read message from object header */
+ const H5O_msg_class_t *type = NULL; /* Actual H5O class type for the ID */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ type = H5O_msg_class_g[mesg->msg_type_id]; /* map the type ID to the actual type object */
+ HDassert(type);
+
+ /* Reset object location for operation */
+ if(H5O_loc_reset(&oloc) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTRESET, FAIL, "unable to initialize location")
+
+ if(NULL == open_oh || mesg->u.mesg_loc.oh_addr != H5O_OH_GET_ADDR(open_oh)) {
+ /* Open the object in the file */
+ oloc.file = f;
+ oloc.addr = mesg->u.mesg_loc.oh_addr;
+ if(H5O_open(&oloc) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "unable to open object header")
+
+ /* Load the object header from the cache */
+ if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load object header")
+ } /* end if */
+ else
+ oh = open_oh;
+
+ /* Use the "real" iterate routine so it doesn't try to protect the OH */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5SM_read_iter_op;
+ if((ret_value = H5O_msg_iterate_real(f, oh, type, &op, &udata, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADITER, FAIL, "unable to iterate over object header messages")
+ } /* end if */
+ else {
+ HDassert(mesg->location == H5SM_IN_HEAP);
+
+ /* Copy the message from the heap */
+ if(H5HF_op(fheap, dxpl_id, &(mesg->u.heap_loc.fheap_id), H5SM_read_mesg_fh_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "can't read message from fractal heap.")
+ } /* end else */
+ HDassert(udata.encoding_buf);
+ HDassert(udata.buf_size);
+
+ /* Record the returned values */
+ *encoded_mesg = udata.encoding_buf;
+ *encoding_size = udata.buf_size;
+
+done:
+ /* Close the object header if we opened one and had an error */
+ if(oh && oh != open_oh) {
+ if(oh && H5O_unprotect(&oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
+ if(H5O_close(&oloc, NULL) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "unable to close object header")
+ } /* end if */
+
+ /* Release the encoding buffer on error */
+ if(ret_value < 0 && udata.encoding_buf)
+ udata.encoding_buf = H5MM_xfree(udata.encoding_buf);
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_read_mesg */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_table_free
+ *
+ * Purpose: Frees memory used by the SOHM table.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_table_free(H5SM_master_table_t *table)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(table);
+ HDassert(table->indexes);
+
+ table->indexes = H5FL_ARR_FREE(H5SM_index_header_t, table->indexes);
+
+ table = H5FL_FREE(H5SM_master_table_t, table);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_table_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_list_free
+ *
+ * Purpose: Frees all memory used by the list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_list_free(H5SM_list_t *list)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(list);
+ HDassert(list->messages);
+
+ list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
+
+ list = H5FL_FREE(H5SM_list_t, list);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_list_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_table_debug
+ *
+ * Purpose: Print debugging information for the master table.
+ *
+ * If table_vers and num_indexes are not UFAIL, they are used
+ * instead of the values in the superblock.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, January 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_table_debug(H5F_t *f, hid_t dxpl_id, haddr_t table_addr,
+ FILE *stream, int indent, int fwidth,
+ unsigned table_vers, unsigned num_indexes)
+{
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ unsigned x; /* Counter variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(table_addr != HADDR_UNDEF);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* If table_vers and num_indexes are UFAIL, replace them with values from
+ * userblock
+ */
+ if(table_vers == UFAIL)
+ table_vers = H5F_SOHM_VERS(f);
+ else if(table_vers != H5F_SOHM_VERS(f))
+ HDfprintf(stream, "*** SOHM TABLE VERSION DOESN'T MATCH VERSION IN SUPERBLOCK!\n");
+ if(num_indexes == UFAIL)
+ num_indexes = H5F_SOHM_NINDEXES(f);
+ else if(num_indexes != H5F_SOHM_NINDEXES(f))
+ HDfprintf(stream, "*** NUMBER OF SOHM INDEXES DOESN'T MATCH VALUE IN SUPERBLOCK!\n");
+
+ /* Check arguments. Version must be 0, the only version implemented so far */
+ if(table_vers > HDF5_SHAREDHEADER_VERSION)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "unknown shared message table version")
+ if(num_indexes == 0 || num_indexes > H5O_SHMESG_MAX_NINDEXES)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "number of indexes must be between 1 and H5O_SHMESG_MAX_NINDEXES")
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ HDfprintf(stream, "%*sShared Message Master Table...\n", indent, "");
+ for(x = 0; x < num_indexes; ++x) {
+ HDfprintf(stream, "%*sIndex %d...\n", indent, "", x);
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
+ "SOHM Index Type:",
+ (table->indexes[x].index_type == H5SM_LIST ? "List" :
+ (table->indexes[x].index_type == H5SM_BTREE ? "B-Tree" : "Unknown")));
+
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
+ "Address of index:", table->indexes[x].index_addr);
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
+ "Address of index's heap:", table->indexes[x].heap_addr);
+ HDfprintf(stream, "%*s%-*s 0x%08x\n", indent + 3, "", fwidth,
+ "Message type flags:", table->indexes[x].mesg_types);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
+ "Minimum size of messages:", table->indexes[x].min_mesg_size);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
+ "Number of messages:", table->indexes[x].num_messages);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
+ "Maximum list size:", table->indexes[x].list_max);
+ HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
+ "Minimum B-tree size:", table->indexes[x].btree_min);
+ } /* end for */
+
+done:
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_table_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_list_debug
+ *
+ * Purpose: Print debugging information for a SOHM list.
+ *
+ * Relies on the list version and number of messages passed in.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, January 18, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_list_debug(H5F_t *f, hid_t dxpl_id, haddr_t list_addr, FILE *stream,
+ int indent, int fwidth, haddr_t table_addr)
+{
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ H5SM_list_t *list = NULL; /* SOHM index list for message type (if in list form) */
+ H5SM_list_cache_ud_t lst_cache_udata; /* List user-data for metadata cache callback */
+ H5SM_table_cache_ud_t tbl_cache_udata; /* Table user-data for metadata cache callback */
+ H5HF_t *fh = NULL; /* Fractal heap for SOHM messages */
+ unsigned index_num; /* Index of list, within master table */
+ unsigned x; /* Counter variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ HDassert(f);
+ HDassert(list_addr != HADDR_UNDEF);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ /* Set up user data for callback */
+ tbl_cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &tbl_cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Determine which index the list is part of */
+ index_num = table->num_indexes;
+ for(x = 0; x < table->num_indexes; x++) {
+ if(H5F_addr_eq(table->indexes[x].index_addr, list_addr)) {
+ index_num = x;
+ break;
+ } /* end if */
+ } /* end for */
+ if(x == table->num_indexes)
+ HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "list address doesn't match address for any indices in table")
+
+ /* Set up user data for metadata cache callback */
+ lst_cache_udata.f = f;
+ lst_cache_udata.header = &(table->indexes[index_num]);
+
+ /* Get the list from the cache */
+ if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, &lst_cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* Open the heap, if one exists */
+ if(H5F_addr_defined(table->indexes[index_num].heap_addr))
+ if(NULL == (fh = H5HF_open(f, dxpl_id, table->indexes[index_num].heap_addr)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open SOHM heap")
+
+ HDfprintf(stream, "%*sShared Message List Index...\n", indent, "");
+ for(x = 0; x < table->indexes[index_num].num_messages; ++x) {
+ HDfprintf(stream, "%*sShared Object Header Message %d...\n", indent, "", x);
+ HDfprintf(stream, "%*s%-*s %08lu\n", indent + 3, "", fwidth,
+ "Hash value:", (unsigned long)list->messages[x].hash);
+ if(list->messages[x].location == H5SM_IN_HEAP) {
+ HDassert(fh);
+
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
+ "Location:", "in heap");
+ HDfprintf(stream, "%*s%-*s 0x%Zx\n", indent + 3, "", fwidth,
+ "Heap ID:", list->messages[x].u.heap_loc.fheap_id);
+ HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
+ "Reference count:", list->messages[x].u.heap_loc.ref_count);
+ } /* end if */
+ else if(list->messages[x].location == H5SM_IN_OH) {
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
+ "Location:", "in object header");
+ HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
+ "Object header address:", list->messages[x].u.mesg_loc.oh_addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
+ "Message creation index:", list->messages[x].u.mesg_loc.oh_addr);
+ HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
+ "Message type ID:", list->messages[x].msg_type_id);
+ } /* end if */
+ else
+ HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
+ "Location:", "invalid");
+ } /* end for */
+
+done:
+ if(fh && H5HF_close(fh, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "unable to close SOHM heap")
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, list, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_list_debug() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_ih_size
+ *
+ * Purpose: Loop through the master SOHM table (if there is one) to:
+ * 1. collect storage used for header
+ * 1. collect storage used for B-tree and List
+ * (include btree storage used by huge objects in fractal heap)
+ * 2. collect fractal heap storage
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * June 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_ih_size(H5F_t *f, hid_t dxpl_id, hsize_t *hdr_size, H5_ih_info_t *ih_info)
+{
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
+ HDassert(hdr_size);
+ HDassert(ih_info);
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Get SOHM header size */
+ *hdr_size = table->table_size;
+
+ /* Loop over all the indices for shared messages */
+ for(u = 0; u < table->num_indexes; u++) {
+ /* Get index storage size (for either B-tree or list) */
+ if(table->indexes[u].index_type == H5SM_BTREE) {
+ if(H5F_addr_defined(table->indexes[u].index_addr)) {
+ /* Open the index v2 B-tree */
+ if(NULL == (bt2 = H5B2_open(f, dxpl_id, table->indexes[u].index_addr, f)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
+
+ if(H5B2_size(bt2, dxpl_id, &(ih_info->index_size)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
+
+ /* Close the v2 B-tree */
+ if(H5B2_close(bt2, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+ bt2 = NULL;
+ } /* end if */
+ } /* end if */
+ else {
+ HDassert(table->indexes[u].index_type == H5SM_LIST);
+ ih_info->index_size += table->indexes[u].list_size;
+ } /* end else */
+
+ /* Check for heap for this index */
+ if(H5F_addr_defined(table->indexes[u].heap_addr)) {
+ /* Open the fractal heap for this index */
+ if(NULL == (fheap = H5HF_open(f, dxpl_id, table->indexes[u].heap_addr)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Get heap storage size */
+ if(H5HF_size(fheap, dxpl_id, &(ih_info->heap_size)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't retrieve fractal heap storage info")
+
+ /* Close the fractal heap */
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ fheap = NULL;
+ } /* end if */
+ } /* end for */
+
+done:
+ /* Release resources */
+ if(fheap && H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
+ if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_ih_size() */
+
diff --git a/src/H5SMbtree2.c b/src/H5SMbtree2.c
new file mode 100644
index 0000000..f0c4963
--- /dev/null
+++ b/src/H5SMbtree2.c
@@ -0,0 +1,255 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object Headers */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* v2 B-tree callbacks */
+static void *H5SM__bt2_crt_context(void *udata);
+static herr_t H5SM__bt2_dst_context(void *ctx);
+static herr_t H5SM__bt2_store(void *native, const void *udata);
+static herr_t H5SM__bt2_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void *_udata);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+/* v2 B-tree class for SOHM indexes*/
+const H5B2_class_t H5SM_INDEX[1]={{ /* B-tree class information */
+ H5B2_SOHM_INDEX_ID, /* Type of B-tree */
+ "H5B2_SOHM_INDEX_ID", /* Name of B-tree class */
+ sizeof(H5SM_sohm_t), /* Size of native record */
+ H5SM__bt2_crt_context, /* Create client callback context */
+ H5SM__bt2_dst_context, /* Destroy client callback context */
+ H5SM__bt2_store, /* Record storage callback */
+ H5SM__message_compare, /* Record comparison callback */
+ H5SM__message_encode, /* Record encoding callback */
+ H5SM__message_decode, /* Record decoding callback */
+ H5SM__bt2_debug /* Record debugging callback */
+}};
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5SM_bt2_ctx_t struct */
+H5FL_DEFINE_STATIC(H5SM_bt2_ctx_t);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__bt2_crt_context
+ *
+ * Purpose: Create client callback context
+ *
+ * Return: Success: non-NULL
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5SM__bt2_crt_context(void *_f)
+{
+ H5F_t *f = (H5F_t *)_f; /* User data for building callback context */
+ H5SM_bt2_ctx_t *ctx; /* Callback context structure */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Allocate callback context */
+ if(NULL == (ctx = H5FL_MALLOC(H5SM_bt2_ctx_t)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate callback context")
+
+ /* Determine the size of addresses & lengths in the file */
+ ctx->sizeof_addr = H5F_SIZEOF_ADDR(f);
+
+ /* Set return value */
+ ret_value = ctx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5SM__bt2_crt_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__bt2_dst_context
+ *
+ * Purpose: Destroy client callback context
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 26, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__bt2_dst_context(void *_ctx)
+{
+ H5SM_bt2_ctx_t *ctx = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ /* Release callback context */
+ ctx = H5FL_FREE(H5SM_bt2_ctx_t, ctx);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5SM__bt2_dst_context() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__bt2_store
+ *
+ * Purpose: Store a H5SM_sohm_t SOHM message in the B-tree. The message
+ * comes in UDATA as a H5SM_mesg_key_t* and is copied to
+ * NATIVE as a H5SM_sohm_t.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__bt2_store(void *native, const void *udata)
+{
+ const H5SM_mesg_key_t *key = (const H5SM_mesg_key_t *)udata;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Copy the source message to the B-tree */
+ *(H5SM_sohm_t *)native = key->message;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__bt2_store */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__bt2_debug
+ *
+ * Purpose: Print debugging information for a H5SM_sohm_t.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__bt2_debug(FILE *stream, int indent, int fwidth,
+ const void *record, const void H5_ATTR_UNUSED *_udata)
+{
+ const H5SM_sohm_t *sohm = (const H5SM_sohm_t *)record;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(sohm->location == H5SM_IN_HEAP)
+ HDfprintf(stream, "%*s%-*s {%a, %lo, %Hx}\n", indent, "", fwidth,
+ "Shared Message in heap:",
+ sohm->u.heap_loc.fheap_id, sohm->hash, sohm->u.heap_loc.ref_count);
+ else {
+ HDassert(sohm->location == H5SM_IN_OH);
+ HDfprintf(stream, "%*s%-*s {%a, %lo, %Hx, %Hx}\n", indent, "", fwidth,
+ "Shared Message in OH:",
+ sohm->u.mesg_loc.oh_addr, sohm->hash, sohm->msg_type_id, sohm->u.mesg_loc.index);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__bt2_debug */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_bt2_convert_to_list_op
+ *
+ * Purpose: An H5B2_remove_t callback function to convert a SOHM
+ * B-tree index to a list.
+ *
+ * Inserts this record into the list passed through op_data.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_bt2_convert_to_list_op(const void * record, void *op_data)
+{
+ const H5SM_sohm_t *message = (const H5SM_sohm_t *)record;
+ const H5SM_list_t *list = (const H5SM_list_t *)op_data;
+ size_t mesg_idx; /* Index of message to modify */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(record);
+ HDassert(op_data);
+
+ /* Get the message index, and increment the # of messages in list */
+ mesg_idx = list->header->num_messages++;
+ HDassert(list->header->num_messages <= list->header->list_max);
+
+ /* Insert this message at the end of the list */
+ HDassert(list->messages[mesg_idx].location == H5SM_NO_LOC);
+ HDassert(message->location != H5SM_NO_LOC);
+ HDmemcpy(&(list->messages[mesg_idx]), message, sizeof(H5SM_sohm_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_bt2_convert_to_list_op() */
+
diff --git a/src/H5SMcache.c b/src/H5SMcache.c
new file mode 100644
index 0000000..f0b469a
--- /dev/null
+++ b/src/H5SMcache.c
@@ -0,0 +1,787 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5SMcache.c
+ * Nov 13 2006
+ * James Laird <jlaird@hdfgroup.org>
+ *
+ * Purpose: Implement shared message metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5SMpkg.h" /* Shared object header messages */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache (H5AC) callbacks */
+static herr_t H5SM__cache_table_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5SM__cache_table_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5SM__cache_table_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5SM__cache_table_image_len(const void *thing, size_t *image_len);
+static herr_t H5SM__cache_table_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5SM__cache_table_free_icr(void *thing);
+
+static herr_t H5SM__cache_list_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5SM__cache_list_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
+static void *H5SM__cache_list_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5SM__cache_list_image_len(const void *thing, size_t *image_len);
+static herr_t H5SM__cache_list_serialize(const H5F_t *f, void *image,
+ size_t len, void *thing);
+static herr_t H5SM__cache_list_free_icr(void *thing);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5SM inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_SOHM_TABLE[1] = {{
+ H5AC_SOHM_TABLE_ID, /* Metadata client ID */
+ "shared message table", /* Metadata client name (for debugging) */
+ H5FD_MEM_SOHM_TABLE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5SM__cache_table_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5SM__cache_table_verify_chksum, /* 'verify_chksum' callback */
+ H5SM__cache_table_deserialize, /* 'deserialize' callback */
+ H5SM__cache_table_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5SM__cache_table_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5SM__cache_table_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+const H5AC_class_t H5AC_SOHM_LIST[1] = {{
+ H5AC_SOHM_LIST_ID, /* Metadata client ID */
+ "shared message list", /* Metadata client name (for debugging) */
+ H5FD_MEM_SOHM_TABLE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5SM__cache_list_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5SM__cache_list_verify_chksum, /* 'verify_chksum' callback */
+ H5SM__cache_list_deserialize, /* 'deserialize' callback */
+ H5SM__cache_list_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5SM__cache_list_serialize, /* 'serialize' callback */
+ NULL, /* 'notify' callback */
+ H5SM__cache_list_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_get_initial_load_size()
+ *
+ * Purpose: Return the size of the master table of Shared Object Header
+ * Message indexes on disk.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_table_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ const H5SM_table_cache_ud_t *udata = (const H5SM_table_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = H5SM_TABLE_SIZE(udata->f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__cache_table_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM__cache_table_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__cache_table_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk representation of the
+ * master table of Shared Object Header Message indexes, deserialize
+ * the table, copy the contents into a newly allocated instance of
+ * H5SM_master_table_t, and return a pointer to the new instance.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5SM__cache_table_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5F_t *f; /* File pointer -- from user data */
+ H5SM_master_table_t *table = NULL; /* Shared message table that we deserializing */
+ H5SM_table_cache_ud_t *udata = (H5SM_table_cache_ud_t *)_udata; /* Pointer to user data */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ size_t u; /* Counter variable for index headers */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(udata->f);
+ f = udata->f;
+ HDassert(dirty);
+
+ /* Verify that we're reading version 0 of the table; this is the only
+ * version defined so far.
+ */
+ HDassert(H5F_SOHM_VERS(f) == HDF5_SHAREDHEADER_VERSION);
+
+ /* Allocate space for the master table in memory */
+ if(NULL == (table = H5FL_CALLOC(H5SM_master_table_t)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Read number of indexes and version from file superblock */
+ table->num_indexes = H5F_SOHM_NINDEXES(f);
+ HDassert(table->num_indexes > 0);
+
+ /* Compute the size of the SOHM table header on disk. This is the "table"
+ * itself plus each index within the table
+ */
+ table->table_size = H5SM_TABLE_SIZE(f);
+ HDassert(table->table_size == len);
+
+ /* Check magic number */
+ if(HDmemcmp(image, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM table signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Allocate space for the index headers in memory*/
+ if(NULL == (table->indexes = (H5SM_index_header_t *)H5FL_ARR_MALLOC(H5SM_index_header_t, (size_t)table->num_indexes)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "memory allocation failed for SOHM indexes")
+
+ /* Read in the index headers */
+ for(u = 0; u < table->num_indexes; ++u) {
+ /* Verify correct version of index list */
+ if(H5SM_LIST_VERSION != *image++)
+ HGOTO_ERROR(H5E_SOHM, H5E_VERSION, NULL, "bad shared message list version number")
+
+ /* Type of the index (list or B-tree) */
+ table->indexes[u].index_type= (H5SM_index_type_t)*image++;
+
+ /* Type of messages in the index */
+ UINT16DECODE(image, table->indexes[u].mesg_types);
+
+ /* Minimum size of message to share */
+ UINT32DECODE(image, table->indexes[u].min_mesg_size);
+
+ /* List cutoff; fewer than this number and index becomes a list */
+ UINT16DECODE(image, table->indexes[u].list_max);
+
+ /* B-tree cutoff; more than this number and index becomes a B-tree */
+ UINT16DECODE(image, table->indexes[u].btree_min);
+
+ /* Number of messages shared */
+ UINT16DECODE(image, table->indexes[u].num_messages);
+
+ /* Address of the actual index */
+ H5F_addr_decode(f, &image, &(table->indexes[u].index_addr));
+
+ /* Address of the index's heap */
+ H5F_addr_decode(f, &image, &(table->indexes[u].heap_addr));
+
+ /* Compute the size of a list index for this SOHM index */
+ table->indexes[u].list_size = H5SM_LIST_SIZE(f, table->indexes[u].list_max);
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Read in checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == table->table_size);
+
+ /* Set return value */
+ ret_value = table;
+
+done:
+ if(!ret_value && table)
+ if(H5SM_table_free(table) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTFREE, NULL, "unable to destroy sohm table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__cache_table_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_image_len
+ *
+ * Purpose: Compute the size in bytes of the specified instance of
+ * H5SM_master_table_t on disk, and return it in *image_len.
+ * On failure, the value of *image_len is undefined.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_table_image_len(const void *_thing, size_t *image_len)
+{
+ const H5SM_master_table_t *table = (const H5SM_master_table_t *)_thing; /* Shared message table to query */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(table);
+ HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(table->cache_info.type == H5AC_SOHM_TABLE);
+ HDassert(image_len);
+
+ *image_len = table->table_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__cache_table_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_serialize
+ *
+ * Purpose: Serialize the contents of the supplied shared message table, and
+ * load this data into the supplied buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_table_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5SM_master_table_t *table = (H5SM_master_table_t *)_thing; /* Shared message table to encode */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ size_t u; /* Counter variable */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(table);
+ HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(table->cache_info.type == H5AC_SOHM_TABLE);
+ HDassert(table->table_size == len);
+
+ /* Verify that we're writing version 0 of the table; this is the only
+ * version defined so far.
+ */
+ HDassert(H5F_SOHM_VERS(f) == HDF5_SHAREDHEADER_VERSION);
+
+ /* Encode magic number */
+ HDmemcpy(image, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Encode each index header */
+ for(u = 0; u < table->num_indexes; ++u) {
+ /* Version for this list */
+ *image++ = H5SM_LIST_VERSION;
+
+ /* Is message index a list or a B-tree? */
+ *image++ = table->indexes[u].index_type;
+
+ /* Type of messages in the index */
+ UINT16ENCODE(image, table->indexes[u].mesg_types);
+
+ /* Minimum size of message to share */
+ UINT32ENCODE(image, table->indexes[u].min_mesg_size);
+
+ /* List cutoff; fewer than this number and index becomes a list */
+ UINT16ENCODE(image, table->indexes[u].list_max);
+
+ /* B-tree cutoff; more than this number and index becomes a B-tree */
+ UINT16ENCODE(image, table->indexes[u].btree_min);
+
+ /* Number of messages shared */
+ UINT16ENCODE(image, table->indexes[u].num_messages);
+
+ /* Address of the actual index */
+ H5F_addr_encode(f, &image, table->indexes[u].index_addr);
+
+ /* Address of the index's heap */
+ H5F_addr_encode(f, &image, table->indexes[u].heap_addr);
+ } /* end for */
+
+ /* Compute checksum on buffer */
+ computed_chksum = H5_checksum_metadata(_image, (table->table_size - H5SM_SIZEOF_CHECKSUM), 0);
+ UINT32ENCODE(image, computed_chksum);
+
+ /* sanity check */
+ HDassert((size_t)(image - ((uint8_t *)_image)) == table->table_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__cache_table_serialize() */
+
+/*****************************************/
+/* no H5SM_cache_table_notify() function */
+/*****************************************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_table_free_icr
+ *
+ * Purpose: Free memory used by the SOHM table.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_table_free_icr(void *_thing)
+{
+ H5SM_master_table_t *table = (H5SM_master_table_t *)_thing; /* Shared message table to release */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(table);
+ HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(table->cache_info.type == H5AC_SOHM_TABLE);
+
+ /* Destroy Shared Object Header Message table */
+ if(H5SM_table_free(table) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTRELEASE, FAIL, "unable to free shared message table")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_cache_table_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_get_initial_load_size()
+ *
+ * Purpose: Return the on disk size of list of SOHM messages. In this case,
+ * we simply look up the size in the user data, and return that value
+ * in *image_len.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_list_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ const H5SM_list_cache_ud_t *udata = (const H5SM_list_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->header);
+ HDassert(udata->header->list_size > 0);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->header->list_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__cache_list_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM__cache_list_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */
+ size_t chk_size; /* Exact size of the node with checksum at the end */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Exact size with checksum at the end */
+ chk_size = H5SM_LIST_SIZE(udata->f, udata->header->num_messages);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__cache_list_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_deserialize
+ *
+ * Purpose: Given a buffer containing the on disk image of a list of
+ * SOHM message, deserialize the list, load it into a newly allocated
+ * instance of H5SM_list_t, and return a pointer to same.
+ *
+ * Return: Success: Pointer to in core representation
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5SM__cache_list_deserialize(const void *_image, size_t len, void *_udata,
+ hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5SM_list_t *list = NULL; /* The SOHM list being read in */
+ H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */
+ H5SM_bt2_ctx_t ctx; /* Message encoding context */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ size_t u; /* Counter variable for messages in list */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(len > 0);
+ HDassert(udata);
+ HDassert(udata->header);
+ HDassert(udata->header->list_size == len);
+ HDassert(dirty);
+
+ /* Allocate space for the SOHM list data structure */
+ if(NULL == (list = H5FL_MALLOC(H5SM_list_t)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "memory allocation failed")
+ HDmemset(&list->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Allocate list in memory as an array*/
+ if(NULL == (list->messages = (H5SM_sohm_t *)H5FL_ARR_MALLOC(H5SM_sohm_t, udata->header->list_max)))
+ HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "file allocation failed for SOHM list")
+ list->header = udata->header;
+
+ /* Check magic number */
+ if(HDmemcmp(image, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM list signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Read messages into the list array */
+ ctx.sizeof_addr = H5F_SIZEOF_ADDR(udata->f);
+ for(u = 0; u < udata->header->num_messages; u++) {
+ if(H5SM__message_decode(image, &(list->messages[u]), &ctx) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "can't decode shared message")
+
+ image += H5SM_SOHM_ENTRY_SIZE(udata->f);
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Read in checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= udata->header->list_size);
+
+ /* Initialize the rest of the array */
+ for(u = udata->header->num_messages; u < udata->header->list_max; u++)
+ list->messages[u].location = H5SM_NO_LOC;
+
+ /* Set return value */
+ ret_value = list;
+
+done:
+ if(!ret_value && list) {
+ if(list->messages)
+ list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
+ list = H5FL_FREE(H5SM_list_t, list);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__cache_list_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_image_len
+ *
+ * Purpose: Get the size of the shared message list on disk.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_list_image_len(const void *_thing, size_t *image_len)
+{
+ const H5SM_list_t *list = (const H5SM_list_t *)_thing; /* Shared message list to query */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(list);
+ HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(list->cache_info.type == H5AC_SOHM_LIST);
+ HDassert(list->header);
+ HDassert(image_len);
+
+ *image_len = list->header->list_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__cache_list_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_serialize
+ *
+ * Purpose: Serialize the contents of the supplied shared message list, and
+ * load this data into the supplied buffer.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_list_serialize(const H5F_t *f, void *_image, size_t len,
+ void *_thing)
+{
+ H5SM_list_t *list = (H5SM_list_t *)_thing ; /* Instance being serialized */
+ H5SM_bt2_ctx_t ctx; /* Message encoding context */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ size_t mesgs_serialized; /* Number of messages serialized */
+ size_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(list);
+ HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(list->cache_info.type == H5AC_SOHM_LIST);
+ HDassert(list->header);
+ HDassert(list->header->list_size == len);
+
+ /* Encode magic number */
+ HDmemcpy(image, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* serialize messages from the messages array */
+ mesgs_serialized = 0;
+ ctx.sizeof_addr = H5F_SIZEOF_ADDR(f);
+ for(u = 0; ((u < list->header->list_max) && (mesgs_serialized < list->header->num_messages)); u++) {
+ if(list->messages[u].location != H5SM_NO_LOC) {
+ if(H5SM__message_encode(image, &(list->messages[u]), &ctx) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTFLUSH, FAIL, "unable to serialize shared message")
+
+ image += H5SM_SOHM_ENTRY_SIZE(f);
+ ++mesgs_serialized;
+ } /* end if */
+ } /* end for */
+
+ HDassert(mesgs_serialized == list->header->num_messages);
+
+ /* Compute checksum on buffer */
+ computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+ UINT32ENCODE(image, computed_chksum);
+
+ /* sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= list->header->list_size);
+
+ /* Clear memory */
+ HDmemset(image, 0, (list->header->list_size - (size_t)(image - (uint8_t *)_image)));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__cache_list_serialize() */
+
+/****************************************/
+/* no H5SM_cache_list_notify() function */
+/****************************************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__cache_list_free_icr
+ *
+ * Purpose: Free all memory used by the list.
+ *
+ * Note: The metadata cache sets the object's cache_info.magic to
+ * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
+ * callback (checked in assert).
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: John Mainzer
+ * 7/28/14
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM__cache_list_free_icr(void *_thing)
+{
+ H5SM_list_t *list = (H5SM_list_t *)_thing; /* Shared message list to release */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(list);
+ HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
+ HDassert(list->cache_info.type == H5AC_SOHM_LIST);
+
+ /* Destroy Shared Object Header Message list */
+ if(H5SM_list_free(list) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTRELEASE, FAIL, "unable to free shared message list")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cache_list_free_icr() */
+
diff --git a/src/H5SMmessage.c b/src/H5SMmessage.c
new file mode 100644
index 0000000..7df9f8f
--- /dev/null
+++ b/src/H5SMmessage.c
@@ -0,0 +1,359 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Opkg.h" /* Object Headers */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Udata struct for calls to H5SM_compare_cb and H5SM_compare_iter_op*/
+typedef struct H5SM_compare_udata_t {
+ const H5SM_mesg_key_t *key; /* Key; compare this against stored message */
+ H5O_msg_crt_idx_t idx; /* Index of the message in the OH, if applicable */
+ herr_t ret; /* Return value; set this to result of memcmp */
+} H5SM_compare_udata_t;
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5SM_compare_cb(const void *obj, size_t obj_len, void *udata);
+static herr_t H5SM_compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence,
+ unsigned *oh_modified, void *udata);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_compare_cb
+ *
+ * Purpose: Callback for H5HF_op, used in H5SM__message_compare below.
+ * Determines whether the search key passed in in _UDATA is
+ * equal to OBJ or not.
+ *
+ * Passes back the result in _UDATA->RET
+ *
+ * Return: Negative on error, non-negative on success
+ *
+ * Programmer: James Laird
+ * Monday, January 8, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_compare_cb(const void *obj, size_t obj_len, void *_udata)
+{
+ H5SM_compare_udata_t *udata = (H5SM_compare_udata_t *)_udata;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* If the encoding sizes are different, it's not the same object */
+ if(udata->key->encoding_size > obj_len)
+ udata->ret = 1;
+ else if(udata->key->encoding_size < obj_len)
+ udata->ret = -1;
+ else
+ /* Sizes are the same. Return result of memcmp */
+ udata->ret = HDmemcmp(udata->key->encoding, obj, obj_len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM_compare_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_compare_iter_op
+ *
+ * Purpose: OH iteration callback to compare a key against a message in
+ * an OH
+ *
+ * Return: 0 if this is not the message we're searching for
+ * 1 if this is the message we're searching for (with memcmp
+ * result returned in udata)
+ * negative on error
+ *
+ * Programmer: James Laird
+ * Wednesday, February 7, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence,
+ unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
+{
+ H5SM_compare_udata_t *udata = (H5SM_compare_udata_t *) _udata;
+ herr_t ret_value = H5_ITER_CONT;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(udata && udata->key);
+
+ /* Check the creation index for this message */
+ if(sequence == udata->idx) {
+ size_t aligned_encoded_size = H5O_ALIGN_OH(oh, udata->key->encoding_size);
+
+ /* Sanity check the message's length */
+ HDassert(mesg->raw_size > 0);
+
+ if(aligned_encoded_size > mesg->raw_size)
+ udata->ret = 1;
+ else if(aligned_encoded_size < mesg->raw_size)
+ udata->ret = -1;
+ else {
+ /* Check if the message is dirty & flush it to the object header if so */
+ if(mesg->dirty)
+ if(H5O_msg_flush(udata->key->file, oh, mesg) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, H5_ITER_ERROR, "unable to encode object header message")
+
+ HDassert(udata->key->encoding_size <= mesg->raw_size);
+ udata->ret = HDmemcmp(udata->key->encoding, mesg->raw, udata->key->encoding_size);
+ } /* end else */
+
+ /* Indicate that we found the message we were looking for */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_compare_iter_op() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__message_compare
+ *
+ * Purpose: Determine whether the search key rec1 represents a shared
+ * message that is equal to rec2 or not, and if not, whether
+ * rec1 is "greater than" or "less than" rec2.
+ *
+ * Return: 0 if rec1 == rec2
+ * Negative if rec1 < rec2
+ * Positive if rec1 > rec2
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM__message_compare(const void *rec1, const void *rec2, int *result)
+{
+ const H5SM_mesg_key_t *key = (const H5SM_mesg_key_t *) rec1;
+ const H5SM_sohm_t *mesg = (const H5SM_sohm_t *) rec2;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_PACKAGE
+
+ /* If the key has an fheap ID, we're looking for a message that's
+ * already in the index; if the fheap ID matches, we've found the message
+ * and can stop immediately.
+ * Likewise, if the message has an OH location that is matched by the
+ * message in the index, we've found the message.
+ */
+ if(mesg->location == H5SM_IN_HEAP && key->message.location == H5SM_IN_HEAP) {
+ if(key->message.u.heap_loc.fheap_id.val == mesg->u.heap_loc.fheap_id.val) {
+ *result = 0;
+ HGOTO_DONE(SUCCEED);
+ }
+ } /* end if */
+ else if(mesg->location == H5SM_IN_OH && key->message.location == H5SM_IN_OH) {
+ if(key->message.u.mesg_loc.oh_addr == mesg->u.mesg_loc.oh_addr &&
+ key->message.u.mesg_loc.index == mesg->u.mesg_loc.index &&
+ key->message.msg_type_id == mesg->msg_type_id) {
+ *result = 0;
+ HGOTO_DONE(SUCCEED);
+ }
+ } /* end if */
+
+ /* Compare hash values */
+ if(key->message.hash > mesg->hash)
+ *result = 1;
+ else if(key->message.hash < mesg->hash)
+ *result = -1;
+ /* If the hash values match, make sure the messages are really the same */
+ else {
+ /* Hash values match; compare the encoded message with the one in
+ * the index.
+ */
+ H5SM_compare_udata_t udata;
+
+ HDassert(key->message.hash == mesg->hash);
+ HDassert(key->encoding_size > 0 && key->encoding);
+
+ /* Set up user data for callback */
+ udata.key = key;
+
+ /* Compare the encoded message with either the message in the heap or
+ * the message in an object header.
+ */
+ if(mesg->location == H5SM_IN_HEAP) {
+ /* Call heap op routine with comparison callback */
+ if(H5HF_op(key->fheap, key->dxpl_id, &(mesg->u.heap_loc.fheap_id), H5SM_compare_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
+ } /* end if */
+ else {
+ H5O_loc_t oloc; /* Object owning the message */
+ H5O_mesg_operator_t op; /* Message operator */
+
+ /* Sanity checks */
+ HDassert(key->file);
+ HDassert(mesg->location == H5SM_IN_OH);
+
+ /* Reset the object location */
+ if(H5O_loc_reset(&oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location")
+
+ /* Set up object location */
+ oloc.file = key->file;
+ oloc.addr = mesg->u.mesg_loc.oh_addr;
+
+ /* Finish setting up user data for iterator */
+ udata.idx = mesg->u.mesg_loc.index;
+
+ /* Locate the right message and compare with it */
+ op.op_type = H5O_MESG_OP_LIB;
+ op.u.lib_op = H5SM_compare_iter_op;
+ if(H5O_msg_iterate(&oloc, mesg->msg_type_id, &op, &udata, key->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links")
+ } /* end else */
+
+ *result = udata.ret;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM__message_compare */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__message_encode
+ *
+ * Purpose: Serialize a H5SM_sohm_t struct into a buffer RAW.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM__message_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
+{
+ H5SM_bt2_ctx_t *ctx = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
+ const H5SM_sohm_t *message = (const H5SM_sohm_t *)_nrecord;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity check */
+ HDassert(ctx);
+
+ *raw++ = message->location;
+ UINT32ENCODE(raw, message->hash);
+
+ if(message->location == H5SM_IN_HEAP) {
+ UINT32ENCODE(raw, message->u.heap_loc.ref_count);
+ HDmemcpy(raw, message->u.heap_loc.fheap_id.id, (size_t)H5O_FHEAP_ID_LEN);
+ } /* end if */
+ else {
+ HDassert(message->location == H5SM_IN_OH);
+
+ *raw++ = 0; /* reserved (possible flags byte) */
+ *raw++ = (uint8_t)message->msg_type_id;
+ UINT16ENCODE(raw, message->u.mesg_loc.index);
+ H5F_addr_encode_len((size_t)ctx->sizeof_addr, &raw, message->u.mesg_loc.oh_addr);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__message_encode */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM__message_decode
+ *
+ * Purpose: Read an encoded SOHM message from RAW into an H5SM_sohm_t struct.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM__message_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
+{
+ H5SM_bt2_ctx_t *ctx = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
+ H5SM_sohm_t *message = (H5SM_sohm_t *)_nrecord;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ message->location = (H5SM_storage_loc_t)*raw++;
+ UINT32DECODE(raw, message->hash);
+
+ if(message->location == H5SM_IN_HEAP) {
+ UINT32DECODE(raw, message->u.heap_loc.ref_count);
+ HDmemcpy(message->u.heap_loc.fheap_id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
+ } /* end if */
+ else {
+ HDassert(message->location == H5SM_IN_OH);
+
+ raw++; /* reserved */
+ message->msg_type_id = *raw++;
+ UINT16DECODE(raw, message->u.mesg_loc.index);
+ H5F_addr_decode_len((size_t)ctx->sizeof_addr, &raw, &message->u.mesg_loc.oh_addr);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5SM__message_decode */
+
diff --git a/src/H5SMmodule.h b/src/H5SMmodule.h
new file mode 100644
index 0000000..656c7dd
--- /dev/null
+++ b/src/H5SMmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5SM package. Including this header means that the source file
+ * is part of the H5SM package.
+ */
+#ifndef _H5SMmodule_H
+#define _H5SMmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5SM_MODULE
+#define H5_MY_PKG H5SM
+#define H5_MY_PKG_ERR H5E_SOHM
+#define H5_MY_PKG_INIT NO
+
+#endif /* _H5SMmodule_H */
+
diff --git a/src/H5SMpkg.h b/src/H5SMpkg.h
new file mode 100644
index 0000000..6dea7ae
--- /dev/null
+++ b/src/H5SMpkg.h
@@ -0,0 +1,288 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: James Laird <jlaird@ncsa.uiuc.edu>
+ * Thursday, March 30, 2006
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5SM shared object header messages package. Source files
+ * outside the H5SM package should include H5SMprivate.h instead.
+ */
+#if !(defined H5SM_FRIEND || defined H5SM_MODULE)
+#error "Do not include this file outside the H5SM package!"
+#endif
+
+#ifndef _H5SMpkg_H
+#define _H5SMpkg_H
+
+/* Get package's private header */
+#include "H5SMprivate.h" /* Shared Object Header Messages */
+
+/* Other private headers needed by this file */
+#include "H5ACprivate.h" /* Metadata Cache */
+#include "H5B2private.h" /* B-trees */
+#include "H5HFprivate.h" /* Fractal heaps */
+
+
+/****************************/
+/* Package Macros */
+/****************************/
+
+/* Size of checksum information (on disk) */
+#define H5SM_SIZEOF_CHECKSUM 4
+
+#define H5SM_HEAP_LOC_SIZE ( \
+ (unsigned)4 /* Reference count */ \
+ + sizeof(H5O_fheap_id_t) /* size of heap ID on disk */ \
+ )
+
+#define H5SM_OH_LOC_SIZE(f) ( \
+ (unsigned)1 /* reserved (possible flags?) */ \
+ + (unsigned)1 /* message type ID */ \
+ + (unsigned)2 /* creation index of message in OH */ \
+ + H5F_SIZEOF_ADDR(f) /* address of OH */ \
+ )
+
+#define H5SM_SOHM_ENTRY_SIZE(f) ( \
+ (unsigned)1 /* Message location */ \
+ + (unsigned)4 /* Hash value */ \
+ + MAX(H5SM_HEAP_LOC_SIZE, H5SM_OH_LOC_SIZE(f)) /* Entry */ \
+ )
+
+#define H5SM_INDEX_HEADER_SIZE(f) ( \
+ (unsigned)1 /* Whether index is a list or B-tree */ \
+ + (unsigned)1 /* Version of index format */ \
+ + (unsigned)2 /* Type of messages stored in the index */ \
+ + (unsigned)4 /* Minimum size of messages to share */ \
+ + (unsigned)(3 * 2) /* B-tree cutoff, list cutoff, # of shared messages */ \
+ + H5F_SIZEOF_ADDR(f) /* Location of list or B-tree */ \
+ + H5F_SIZEOF_ADDR(f) /* Address of heap */ \
+ )
+
+/* Format overhead for all SOHM tree metadata in the file */
+#define H5SM_METADATA_PREFIX_SIZE ( \
+ H5_SIZEOF_MAGIC /* Signature */ \
+ + H5SM_SIZEOF_CHECKSUM /* Checksum */ \
+ )
+
+#define H5SM_TABLE_SIZE(f) ( \
+ /* General metadata fields */ \
+ H5SM_METADATA_PREFIX_SIZE \
+ \
+ /* Indices */ \
+ + (H5F_SOHM_NINDEXES(f) * H5SM_INDEX_HEADER_SIZE(f)) \
+ )
+
+#define H5SM_LIST_SIZE(f, num_mesg) ( \
+ /* General metadata fields */ \
+ H5SM_METADATA_PREFIX_SIZE \
+ \
+ /* Message entries */ \
+ + (H5SM_SOHM_ENTRY_SIZE(f) * num_mesg) \
+ )
+
+#define H5SM_B2_NODE_SIZE 512
+#define H5SM_B2_SPLIT_PERCENT 100
+#define H5SM_B2_MERGE_PERCENT 40
+
+#define H5SM_LIST_VERSION 0 /* Verion of Shared Object Header Message List Indexes */
+
+/****************************/
+/* Package Typedefs */
+/****************************/
+
+/* There are a number of Shared Object Header Message-specific structs here.
+ *
+ * The H5SM_master_table_t is pointed to by the file superblock. Since a file
+ * can have more than one SOHM index, this table collects all the indexes into
+ * one place. It holds an array of H5SM_index_header_t structs.
+ *
+ * An H5SM_index_header_t is actually the for a given index. It holds
+ * the number of messages in the index, the types of messages in the index,
+ * etc. It also records whether the index is a list or a b-tree, and has
+ * the address of the list or b-tree.
+ *
+ * If the index is a list, the address in the index header should be given
+ * to the cache, which can load it into a H5SM_list_t struct. This is mostly
+ * just a header for the cache information; it contains a pointer back to
+ * the index header and an unsorted array of messages.
+ *
+ * These messages are H5SM_sohm_t structs. They hold the actual SOHM's
+ * address, hash value, and refcount.
+ *
+ * If the index is a b-tree, the H5SM_index_header_t struct holds the address
+ * of the b-tree instead of the address of a H5SM_list_t. The B-tree's nodes
+ * are still 'H5SM_sohm_t's.
+ *
+ * H5SM_mesg_key_t structs are used to search lists and B-trees for a certain
+ * message. They correspond to a message that hasn't yet been written to
+ * disk.
+ */
+
+/* Where a message is stored */
+typedef enum {
+ H5SM_NO_LOC = -1,
+ H5SM_IN_HEAP = 0, /* Message is stored in the heap */
+ H5SM_IN_OH /* Message is stored in an object header */
+} H5SM_storage_loc_t;
+
+/* Typedef for a record's location if it's stored in the heap */
+typedef struct {
+ hsize_t ref_count; /* Number of times this message is used in the file */
+ H5O_fheap_id_t fheap_id; /* ID of the OHM in the fractal heap */
+} H5SM_heap_loc_t;
+
+/* Typedef for a SOHM index node */
+typedef struct {
+ H5SM_storage_loc_t location; /* Type of message location */
+ uint32_t hash; /* Hash value for encoded OHM */
+ unsigned msg_type_id; /* Message's type ID */
+ union {
+ H5O_mesg_loc_t mesg_loc; /* Location of message in object header */
+ H5SM_heap_loc_t heap_loc; /* Heap ID for message in SOHM heap */
+ } u;
+} H5SM_sohm_t;
+
+/* Types of message indices */
+typedef enum {
+ H5SM_BADTYPE = -1,
+ H5SM_LIST, /* Index is an unsorted list */
+ H5SM_BTREE /* Index is a sorted B-tree */
+} H5SM_index_type_t;
+
+/* Typedef for a SOHM index header */
+typedef struct {
+/* Stored */
+ unsigned mesg_types; /* Bit flag vector of message types */
+ size_t min_mesg_size; /* number of messages being tracked */
+ size_t list_max; /* >= this many messages, index with a B-tree */
+ size_t btree_min; /* <= this many messages, index with a list again */
+ size_t num_messages; /* number of messages being tracked */
+ H5SM_index_type_t index_type; /* Is the index a list or a B-tree? */
+ haddr_t index_addr; /* Address of the actual index (list or B-tree) */
+ haddr_t heap_addr; /* Address of the fheap used to store shared messages */
+
+/* Not stored */
+ size_t list_size; /* Size of list index on disk */
+} H5SM_index_header_t;
+
+/* Typedef for a SOHM list */
+typedef struct {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ H5SM_index_header_t *header; /* Pointer to the corresponding index header */
+ H5SM_sohm_t *messages; /* Actual list, stored as an array */
+} H5SM_list_t;
+
+/* Typedef for shared object header message master table */
+struct H5SM_master_table_t {
+ /* Information for H5AC cache functions, _must_ be first field in structure */
+ H5AC_info_t cache_info;
+
+ size_t table_size; /* Size of table on disk */
+ unsigned num_indexes; /* Number of indexes */
+ H5SM_index_header_t *indexes; /* Array of num_indexes indexes */
+};
+
+/* Typedef for searching an index (list or B-tree) */
+typedef struct {
+ H5F_t *file; /* File in which sharing is happening */
+ hid_t dxpl_id; /* DXPL for sharing messages in heap */
+ H5HF_t *fheap; /* The heap for this message type, open. */
+ void *encoding; /* The message encoded, or NULL */
+ size_t encoding_size; /* Size of the encoding, or 0 */
+ H5SM_sohm_t message; /* The message to find/insert.
+ * If the message doesn't yet have a
+ * heap ID, the heap ID will be 0. */
+} H5SM_mesg_key_t;
+
+/*
+ * Data exchange structure to pass through the fractal heap layer for the
+ * H5HF_op function when computing a hash value for a message.
+ */
+typedef struct {
+ /* downward (internal) */
+ unsigned type_id; /* Message type */
+
+ /* upward */
+ uint32_t hash; /* Hash value */
+} H5SM_fh_ud_gh_t;
+
+/* Typedef to increment a reference count in the B-tree */
+typedef struct {
+ H5SM_mesg_key_t *key; /* IN: key for message being incremented */
+ H5O_fheap_id_t fheap_id; /* OUT: fheap ID of record */
+ hid_t dxpl_id;
+} H5SM_incr_ref_opdata;
+
+/* v2 B-tree client callback context */
+typedef struct H5SM_bt2_ctx_t {
+ uint8_t sizeof_addr; /* Size of file addresses */
+} H5SM_bt2_ctx_t;
+
+/* Callback info for loading a shared message table index into the cache */
+typedef struct H5SM_table_cache_ud_t {
+ H5F_t *f; /* File that shared message index stored as a table is in */
+} H5SM_table_cache_ud_t;
+
+/* Callback info for loading a shared message list index into the cache */
+typedef struct H5SM_list_cache_ud_t {
+ H5F_t *f; /* File that shared message index stored as a table is in */
+ H5SM_index_header_t *header; /* Index header for this list */
+} H5SM_list_cache_ud_t;
+
+
+/****************************/
+/* Package Variables */
+/****************************/
+
+/* Declare free lists to manage H5SM structs */
+H5FL_EXTERN(H5SM_master_table_t);
+H5FL_ARR_EXTERN(H5SM_index_header_t);
+H5FL_EXTERN(H5SM_list_t);
+H5FL_ARR_EXTERN(H5SM_sohm_t);
+
+H5_DLLVAR const H5B2_class_t H5SM_INDEX[1];
+
+/****************************/
+/* Package Prototypes */
+/****************************/
+
+/* General routines */
+H5_DLL ssize_t H5SM_get_index(const H5SM_master_table_t *table, unsigned type_id);
+
+/* Encode and decode routines, used for B-tree and cache encoding/decoding */
+H5_DLL herr_t H5SM__message_compare(const void *rec1, const void *rec2, int *result);
+H5_DLL herr_t H5SM__message_encode(uint8_t *raw, const void *native, void *ctx);
+H5_DLL herr_t H5SM__message_decode(const uint8_t *raw, void *native, void *ctx);
+
+/* H5B2_remove_t callback to add messages to a list index */
+H5_DLL herr_t H5SM_bt2_convert_to_list_op(const void * record, void *op_data);
+
+/* Fractal heap 'op' callback to compute hash value for message "in place" */
+H5_DLL herr_t H5SM_get_hash_fh_cb(const void *obj, size_t obj_len, void *_udata);
+
+/* Routines to release data structures */
+herr_t H5SM_table_free(H5SM_master_table_t *table);
+herr_t H5SM_list_free(H5SM_list_t *list);
+
+/* Testing functions */
+#ifdef H5SM_TESTING
+H5_DLL herr_t H5SM_get_mesg_count_test(H5F_t *f, hid_t dxpl_id, unsigned type_id,
+ size_t *mesg_count);
+#endif /* H5SM_TESTING */
+
+#endif /* _H5SMpkg_H */
+
diff --git a/src/H5SMprivate.h b/src/H5SMprivate.h
new file mode 100644
index 0000000..8f9f533
--- /dev/null
+++ b/src/H5SMprivate.h
@@ -0,0 +1,78 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: James Laird <jlaird@ncsa.uiuc.edu>
+ * Thursday, March 2, 2006
+ *
+ * Purpose: This file contains private declarations for the H5SM
+ * shared object header messages module.
+ */
+#ifndef _H5SMprivate_H
+#define _H5SMprivate_H
+
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Flags for the "defer_flags" argument to H5SM_try_share
+ */
+#define H5SM_DEFER 0x01u /* Don't actually write shared message to index, heap; just update shared info */
+#define H5SM_WAS_DEFERRED 0x02u /* Message was previously updated by a call to H5SM_try_share with H5SM_DEFER */
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Forward references of package typedefs */
+typedef struct H5SM_master_table_t H5SM_master_table_t;
+
+
+/******************************/
+/* Library Private Prototypes */
+/******************************/
+
+/* Generally useful shared message routines */
+H5_DLL herr_t H5SM_init(H5F_t *f, H5P_genplist_t *fc_plist,
+ const H5O_loc_t *ext_loc, hid_t dxpl_id);
+H5_DLL htri_t H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table,
+ ssize_t *sohm_index_num, unsigned type_id, const void *mesg);
+H5_DLL htri_t H5SM_try_share(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ unsigned defer_flags, unsigned type_id, void *mesg, unsigned *mesg_flags);
+H5_DLL herr_t H5SM_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
+ H5O_shared_t *sh_mesg);
+H5_DLL herr_t H5SM_get_info(const H5O_loc_t *ext_loc, H5P_genplist_t *fc_plist,
+ hid_t dxpl_id);
+H5_DLL htri_t H5SM_type_shared(H5F_t *f, unsigned type_id, hid_t dxpl_id);
+H5_DLL herr_t H5SM_get_fheap_addr(H5F_t *f, hid_t dxpl_id, unsigned type_id,
+ haddr_t *fheap_addr);
+H5_DLL herr_t H5SM_reconstitute(H5O_shared_t *sh_mesg, H5F_t *f,
+ unsigned msg_type_id, H5O_fheap_id_t heap_id);
+H5_DLL herr_t H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id,
+ const H5O_shared_t *sh_mesg, hsize_t *ref_count);
+H5_DLL herr_t H5SM_ih_size(H5F_t *f, hid_t dxpl_id, hsize_t *hdr_size, H5_ih_info_t *ih_info);
+
+
+/* Debugging routines */
+H5_DLL herr_t H5SM_table_debug(H5F_t *f, hid_t dxpl_id, haddr_t table_addr,
+ FILE *stream, int indent, int fwidth, unsigned table_vers,
+ unsigned num_indexes);
+H5_DLL herr_t H5SM_list_debug(H5F_t *f, hid_t dxpl_id, haddr_t list_addr,
+ FILE *stream, int indent, int fwidth, haddr_t table_addr);
+
+#endif /*_H5SMprivate_H*/
+
diff --git a/src/H5SMtest.c b/src/H5SMtest.c
new file mode 100644
index 0000000..6a4b63a
--- /dev/null
+++ b/src/H5SMtest.c
@@ -0,0 +1,121 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
+#define H5SM_TESTING /*suppress warning about H5SM testing funcs*/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_mesg_count_test
+ *
+ * Purpose: Retrieve the number of messages tracked of a certain type
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 3, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_get_mesg_count_test(H5F_t *f, hid_t dxpl_id, unsigned type_id,
+ size_t *mesg_count)
+{
+ H5SM_master_table_t *table = NULL; /* SOHM master table */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(mesg_count);
+
+ /* Check for shared messages being enabled */
+ if(H5F_addr_defined(H5F_SOHM_ADDR(f))) {
+ H5SM_index_header_t *header; /* Index header for message type */
+ H5SM_table_cache_ud_t cache_udata; /* User-data for callback */
+ ssize_t index_num; /* Table index for message type */
+
+ /* Set up user data for callback */
+ cache_udata.f = f;
+
+ /* Look up the master SOHM table */
+ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Find the correct index for this message type */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to find correct SOHM index")
+ header = &(table->indexes[index_num]);
+
+ /* Set the message count for the type */
+ *mesg_count = header->num_messages;
+ } /* end if */
+ else
+ /* No shared messages of any type */
+ *mesg_count = 0;
+
+done:
+ /* Release resources */
+ if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
+} /* end H5SM_get_mesg_count_test() */
+
diff --git a/src/H5ST.c b/src/H5ST.c
new file mode 100644
index 0000000..dd5b63c
--- /dev/null
+++ b/src/H5ST.c
@@ -0,0 +1,795 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* TERNARY SEARCH TREE ALGS
+ This code is described in "Ternary Search Trees" by Jon
+Bentley and Robert Sedgewick in the April, 1998, Dr. Dobb's Journal.
+*/
+
+
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5STprivate.h" /* Ternary search trees */
+
+#ifdef H5ST_DEBUG
+static herr_t H5ST__dump_internal(H5ST_ptr_t p);
+#endif /* H5ST_DEBUG */
+
+/* Declare a free list to manage the H5ST_node_t struct */
+H5FL_DEFINE_STATIC(H5ST_node_t);
+
+/* Declare a free list to manage the H5ST_tree_t struct */
+H5FL_DEFINE_STATIC(H5ST_tree_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_create
+ PURPOSE
+ Create a TST
+ USAGE
+ H5ST_ptr_t H5ST_create()
+
+ RETURNS
+ Returns a pointer to the new TST tree on success, NULL on failure.
+ DESCRIPTION
+ Create a TST.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5ST_tree_t *
+H5ST_create(void)
+{
+ H5ST_tree_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Allocate wrapper for TST */
+ if(NULL == (ret_value = H5FL_MALLOC(H5ST_tree_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Set the internal fields */
+ ret_value->root = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_close_internal
+ PURPOSE
+ Close a TST, deallocating it.
+ USAGE
+ herr_t H5ST_close(p)
+ H5ST_ptr_t p; IN/OUT: Root of TST to free
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a TST, freeing all nodes.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5ST_close_internal(H5ST_ptr_t p)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Recursively free TST */
+ if(p) {
+ H5ST_close_internal(p->lokid);
+ if(p->splitchar)
+ H5ST_close_internal(p->eqkid);
+ H5ST_close_internal(p->hikid);
+ p = H5FL_FREE(H5ST_node_t, p);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5ST_close_internal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_close
+ PURPOSE
+ Close a TST, deallocating it.
+ USAGE
+ herr_t H5ST_close(tree)
+ H5ST_tree_t *tree; IN/OUT: TST tree to free
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Close a TST, freeing all nodes.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5ST_close(H5ST_tree_t *tree)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if(NULL == tree)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid TST")
+
+ /* Free the TST itself */
+ if(H5ST_close_internal(tree->root) < 0)
+ HGOTO_ERROR(H5E_TST, H5E_CANTFREE, FAIL, "can't free TST")
+
+ /* Free root node itself */
+ tree = H5FL_FREE(H5ST_tree_t, tree);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_close() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_insert
+ PURPOSE
+ Insert a string/object pair into a TST
+ USAGE
+ herr_t H5ST_insert(tree,s,obj)
+ H5ST_tree_t *tree; IN/OUT: TST to insert string into
+ const char *s; IN: String to use as key for object
+ void *obj; IN: Pointer to object to insert
+
+ RETURNS
+ Returns non-negative on success, negative on failure.
+ DESCRIPTION
+ Insert a key (string)/object pair into a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5ST_insert(H5ST_tree_t *tree, const char *s, void *obj)
+{
+ int d; /* Comparison value */
+ H5ST_ptr_t pp, *p; /* Pointer to current node and pointer to that */
+ H5ST_ptr_t parent=NULL; /* Pointer to parent node */
+ H5ST_ptr_t up=NULL; /* Pointer to up node */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Find the correct location to insert object */
+ p = &tree->root;
+ while((pp = *p)) {
+ /* If this node matches the character in the key, then drop down to the lower tree */
+ if(0 == (d = *s - pp->splitchar)) {
+ if(*s++ == 0)
+ HGOTO_ERROR(H5E_TST, H5E_EXISTS, FAIL, "key already in tree")
+ up=pp;
+ p = &(pp->eqkid);
+ } /* end if */
+ else {
+ /* Walk through the current tree, searching for the matching character */
+ parent = pp;
+ if(d < 0)
+ p = &(pp->lokid);
+ else
+ p = &(pp->hikid);
+ } /* end else */
+ } /* end while */
+
+ /* Finish walking through the key string, adding nodes until the end */
+ for (;;) {
+ if(NULL == (*p = H5FL_MALLOC(H5ST_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ pp = *p;
+ pp->splitchar = *s;
+ pp->up = up;
+ pp->parent = parent;
+ pp->lokid = pp->eqkid = pp->hikid = NULL;
+
+ /* If this is the end of the key string, break out */
+ if(*s++ == 0) {
+ pp->eqkid = (H5ST_ptr_t)obj;
+ break;
+ } /* end if */
+
+ /* Continue to next character */
+ parent = NULL;
+ up = pp;
+ p = &(pp->eqkid);
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_insert() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_search
+ PURPOSE
+ Determine if a key is in the TST
+ USAGE
+ hbool_t H5ST_search(tree,s)
+ H5ST_tree_t *tree; IN: TST to find string in
+ const char *s; IN: String to use as key to locate
+
+ RETURNS
+ Success: TRUE if key string in TST, FALSE if not
+ Failure: negative
+ DESCRIPTION
+ Locate a key (string) in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5ST_search(H5ST_tree_t *tree, const char *s)
+{
+ H5ST_ptr_t p; /* Temporary pointer to TST node */
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ p = tree->root;
+ while (p) {
+ if (*s < p->splitchar)
+ p = p->lokid;
+ else if (*s == p->splitchar) {
+ if (*s++ == 0)
+ HGOTO_DONE(TRUE);
+ p = p->eqkid;
+ } else
+ p = p->hikid;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_search() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_find_internal
+ PURPOSE
+ Find the node matching a particular key string
+ USAGE
+ H5ST_ptr_t H5ST_find(p,s)
+ H5ST_ptr_t p; IN: TST to find string in
+ const char *s; IN: String to use as key to locate
+
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Locate a key (string) in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5ST_ptr_t
+H5ST_find_internal(H5ST_ptr_t p, const char *s)
+{
+ H5ST_ptr_t ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ while (p) {
+ if (*s < p->splitchar)
+ p = p->lokid;
+ else if (*s == p->splitchar) {
+ if (*s++ == 0)
+ HGOTO_DONE(p);
+ p = p->eqkid;
+ } else
+ p = p->hikid;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_find_internal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_find
+ PURPOSE
+ Find the node matching a particular key string
+ USAGE
+ H5ST_ptr_t H5ST_find(tree,s)
+ H5ST_tree_t *tree; IN: TST to find string in
+ const char *s; IN: String to use as key to locate
+
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Locate a key (string) in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5ST_ptr_t
+H5ST_find(H5ST_tree_t *tree, const char *s)
+{
+ H5ST_ptr_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(NULL == (ret_value = H5ST_find_internal(tree->root, s)))
+ HGOTO_ERROR(H5E_TST, H5E_NOTFOUND, NULL, "key not found in TST")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_find() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_locate
+ PURPOSE
+ Find an object in a TST
+ USAGE
+ void *H5ST_locate(tree,s)
+ H5ST_tree_t *tree; IN: TST to locate object within
+ const char *s; IN: String of key for object to locate
+ RETURNS
+ Success: Non-NULL, pointer to object stored for key
+ Failure: Negative
+ DESCRIPTION
+ Locate a node in a TST, returning the object from the node.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5ST_locate(H5ST_tree_t *tree, const char *s)
+{
+ H5ST_ptr_t node; /* Pointer to node located */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Locate the node to remove */
+ if(NULL == (node = H5ST_find_internal(tree->root, s)))
+ HGOTO_ERROR(H5E_TST, H5E_NOTFOUND, NULL, "key not found in TST")
+
+ /* Get the pointer to the object to return */
+ ret_value = node->eqkid;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5ST_locate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_findfirst_internal
+ PURPOSE
+ Find the first node in a TST
+ USAGE
+ H5ST_ptr_t H5ST_findfirst_internal(p)
+ H5ST_ptr_t p; IN: TST to locate first node within
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Get the first (lexicographically) node in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5ST_ptr_t
+H5ST_findfirst_internal(H5ST_ptr_t p)
+{
+ H5ST_ptr_t ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ while(p) {
+ /* Find least node in current tree */
+ while(p->lokid)
+ p = p->lokid;
+
+ /* Is least node '\0'? */
+ if(p->splitchar == '\0') {
+ /* Return it */
+ HGOTO_DONE(p);
+ } /* end if */
+ else {
+ /* Go down to next level of tree */
+ p = p->eqkid;
+ } /* end else */
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_findfirst_internal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_findfirst
+ PURPOSE
+ Find the first node in a TST
+ USAGE
+ H5ST_ptr_t H5ST_findfirst(tree)
+ H5ST_tree_t *tree; IN: TST to locate first node within
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Get the first (lexicographically) node in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5ST_ptr_t
+H5ST_findfirst(H5ST_tree_t *tree)
+{
+ H5ST_ptr_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(NULL == (ret_value = H5ST_findfirst_internal(tree->root)))
+ HGOTO_ERROR(H5E_TST,H5E_NOTFOUND,NULL,"no nodes in TST");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_findfirst() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_getnext
+ PURPOSE
+ Internal routine to find the next node in a given level of a TST
+ USAGE
+ H5ST_ptr_t H5ST_getnext(p)
+ H5ST_ptr_t *p; IN: Pointer to node to find next node from
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Get the next (lexicographically) node in the current level of a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5ST_ptr_t
+H5ST_getnext(H5ST_ptr_t p)
+{
+ H5ST_ptr_t ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* If the node to continue from has higher-valued nodes attached */
+ if(p->hikid) {
+ /* Go to first higher-valued node */
+ p = p->hikid;
+
+ /* Find least node from here */
+ while(p->lokid)
+ p = p->lokid;
+ HGOTO_DONE(p);
+ } /* end if */
+ else {
+ H5ST_ptr_t q; /* Temporary TST node pointer */
+
+ /* Go up one level in current tree */
+ q = p->parent;
+ if(q == NULL)
+ HGOTO_DONE(NULL);
+
+ /* While the previous node was the higher-valued node, keep backing up the tree */
+ while(q->hikid == p) {
+ p = q;
+ q = p->parent;
+ if(NULL == q)
+ HGOTO_DONE(NULL);
+ } /* end while */
+ HGOTO_DONE(q);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_getnext() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_findnext
+ PURPOSE
+ Find the next node from a node in a TST
+ USAGE
+ H5ST_ptr_t H5ST_findnext(p)
+ H5ST_ptr_t p; IN: Current node to continue from
+ RETURNS
+ Success: Non-NULL
+ Failure: NULL
+ DESCRIPTION
+ Get the next (lexicographically) node in a TST
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5ST_ptr_t
+H5ST_findnext(H5ST_ptr_t p)
+{
+ H5ST_ptr_t q; /* Temporary pointer to TST node */
+ H5ST_ptr_t ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Find the next node at the current level, or go back up the tree */
+ do {
+ q = H5ST_getnext(p);
+ if(q) {
+ HGOTO_DONE(H5ST_findfirst_internal(q->eqkid));
+ } /* end if */
+ else
+ p = p->up;
+ } while(p);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_findnext() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_delete_internal
+ PURPOSE
+ Delete a node from a TST
+ USAGE
+ herr_t H5ST_delete_internal(root,p)
+ H5ST_ptr_t *root; IN/OUT: Root of TST to delete node from
+ H5ST_ptr_t p; IN: Node to delete
+ RETURNS
+ Success: Non-negative
+ Failure: Negative
+ DESCRIPTION
+ Delete a node from a TST.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This should be the final node for a string.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5ST_delete_internal(H5ST_ptr_t *root, H5ST_ptr_t p)
+{
+ H5ST_ptr_t q, /* Temporary pointer to TST node */
+ newp; /* Pointer to node which will replace deleted node in tree */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Find node to replace one being deleted */
+ if(p->lokid) {
+ /* If the deleted node has lo & hi kids, attach them together */
+ if(p->hikid) {
+ q = p->lokid;
+ while(q->hikid)
+ q = q->hikid;
+ q->hikid = p->hikid;
+ p->hikid->parent = q;
+ } /* end if */
+ newp = p->lokid;
+ } /* end if */
+ else if(p->hikid) {
+ newp = p->hikid;
+ } /* end if */
+ else {
+ newp = NULL;
+ } /* end else */
+
+ /* Deleted node is in middle of tree */
+ if(p->parent) {
+ /* Attach new node to correct side of parent */
+ if(p == p->parent->lokid)
+ p->parent->lokid = newp;
+ else
+ p->parent->hikid = newp;
+ if(newp)
+ newp->parent = p->parent;
+ } /* end if */
+ else {
+ if(newp)
+ newp->parent = p->parent;
+ if(p->up) {
+ p->up->eqkid = newp;
+
+ /* If we deleted the last node in the TST, delete the upper node also */
+ if(NULL == newp)
+ H5ST_delete_internal(root, p->up);
+ } /* end if */
+ else /* Deleted last node at top level of tree */
+ *root = newp;
+ } /* end else */
+
+ p = H5FL_FREE(H5ST_node_t, p);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5ST_delete_internal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_delete
+ PURPOSE
+ Delete a node from a TST
+ USAGE
+ herr_t H5ST_delete(tree,p)
+ H5ST_tree_t *tree; IN/OUT: TST to delete node from
+ H5ST_ptr_t p; IN: Node to delete
+ RETURNS
+ Success: Non-negative
+ Failure: Negative
+ DESCRIPTION
+ Delete a node from a TST.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This should be the final node for a string.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5ST_delete(H5ST_tree_t *tree, H5ST_ptr_t p)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5ST_delete_internal(&tree->root, p) < 0)
+ HGOTO_ERROR(H5E_TST, H5E_CANTDELETE, FAIL, "can't delete node from TST")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5ST_delete() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_remove
+ PURPOSE
+ Remove a node from a TST
+ USAGE
+ void *H5ST_remove(tree,s)
+ H5ST_tree_t *tree; IN/OUT: TST to remove node from
+ const char *s; IN: String of key for node to remove
+ RETURNS
+ Success: Non-NULL, pointer to object stored for key
+ Failure: Negative
+ DESCRIPTION
+ Remove a node from a TST, returning the object from the node.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void *
+H5ST_remove(H5ST_tree_t *tree, const char *s)
+{
+ H5ST_ptr_t node; /* Pointer to node to remove */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Locate the node to remove */
+ if(NULL == (node = H5ST_find_internal(tree->root, s)))
+ HGOTO_ERROR(H5E_TST, H5E_NOTFOUND, NULL, "key not found in TST")
+
+ /* Get the pointer to the object to return */
+ ret_value = node->eqkid;
+
+ /* Remove the node from the TST */
+ if(H5ST_delete_internal(&tree->root, node) < 0)
+ HGOTO_ERROR(H5E_TST, H5E_CANTDELETE, NULL, "can't delete node from TST")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5ST_remove() */
+
+#ifdef H5ST_DEBUG
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST__dump_internal
+ PURPOSE
+ Dump all the nodes of a TST
+ USAGE
+ herr_t H5ST_dump(p)
+ H5ST_ptr_t p; IN: Root of TST to dump
+ RETURNS
+ Success: Non-negative
+ Failure: Negative
+ DESCRIPTION
+ Dump information for a TST.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5ST__dump_internal(H5ST_ptr_t p)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ if(p) {
+ printf("p=%p\n", (void *)p);
+ printf("\tp->up=%p\n", (void *)p->up);
+ printf("\tp->parent=%p\n", (void *)p->parent);
+ printf("\tp->lokid=%p\n", (void *)p->lokid);
+ printf("\tp->hikid=%p\n", (void *)p->hikid);
+ printf("\tp->eqkid=%p\n", (void *)p->eqkid);
+ printf("\tp->splitchar=%c\n", p->splitchar);
+
+ H5ST__dump_internal(p->lokid);
+ if(p->splitchar)
+ H5ST__dump_internal(p->eqkid);
+ else
+ printf("%s\n", (char *)p->eqkid);
+ H5ST__dump_internal(p->hikid);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5ST__dump_internal() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5ST_dump
+ PURPOSE
+ Dump all the nodes of a TST
+ USAGE
+ herr_t H5ST_dump(tree)
+ H5ST_tree_t *tree; IN: TST to dump
+ RETURNS
+ Success: Non-negative
+ Failure: Negative
+ DESCRIPTION
+ Dump information for a TST.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5ST_dump(H5ST_tree_t *tree)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Dump the tree */
+ H5ST__dump_internal(tree->root);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5ST_dump() */
+#endif /* H5ST_DEBUG */
+
diff --git a/src/H5STprivate.h b/src/H5STprivate.h
new file mode 100644
index 0000000..07e9afe
--- /dev/null
+++ b/src/H5STprivate.h
@@ -0,0 +1,64 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5ST module
+ */
+#ifndef _H5STprivate_H
+#define _H5STprivate_H
+
+#ifdef LATER
+#include "H5STpublic.h"
+#endif /* LATER */
+
+/* Private headers needed by this file */
+#include "H5private.h"
+
+/* Typedefs */
+
+/* Internal nodes for TST */
+typedef struct H5ST_node *H5ST_ptr_t;
+typedef struct H5ST_node {
+ char splitchar; /* Character represented at node */
+ H5ST_ptr_t up; /* Pointer to the node in the tree above (before) this node */
+ H5ST_ptr_t parent; /* Pointer to the next higher tree node in this tree */
+ H5ST_ptr_t lokid; /* Pointer to the lower node from this one, in this tree */
+ H5ST_ptr_t eqkid; /* Pointer to the parent node in the next tree down (after) this node */
+ H5ST_ptr_t hikid; /* Pointer to the higher node from this one, in this tree */
+} H5ST_node_t;
+
+/* Wrapper about TST */
+typedef struct {
+ H5ST_ptr_t root; /* Pointer to actual TST */
+} H5ST_tree_t;
+
+/* Macro to access "data" pointer in H5ST_node_t's returned from functions */
+#define H5ST_NODE_DATA(p) ((void *)(p->eqkid))
+
+/* Private routines */
+H5_DLL H5ST_tree_t *H5ST_create(void);
+H5_DLL herr_t H5ST_close(H5ST_tree_t *p);
+H5_DLL herr_t H5ST_insert(H5ST_tree_t *root, const char *s, void *obj);
+H5_DLL htri_t H5ST_search(H5ST_tree_t *root, const char *s);
+H5_DLL H5ST_ptr_t H5ST_find(H5ST_tree_t *root, const char *s);
+H5_DLL void *H5ST_locate(H5ST_tree_t *root, const char *s);
+H5_DLL H5ST_ptr_t H5ST_findfirst(H5ST_tree_t *p);
+H5_DLL H5ST_ptr_t H5ST_findnext(H5ST_ptr_t p);
+H5_DLL void *H5ST_remove(H5ST_tree_t *root, const char *s);
+H5_DLL herr_t H5ST_delete(H5ST_tree_t *root, H5ST_ptr_t p);
+#ifdef H5ST_DEBUG
+H5_DLL herr_t H5ST_dump(H5ST_tree_t *tree);
+#endif /* H5ST_DEBUG */
+
+#endif /* _H5STprivate_H */
+
diff --git a/src/H5Sall.c b/src/H5Sall.c
new file mode 100644
index 0000000..710727b
--- /dev/null
+++ b/src/H5Sall.c
@@ -0,0 +1,1039 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Tuesday, June 16, 1998
+ *
+ * Purpose: "All" selection data space I/O functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* ID Functions */
+#include "H5Spkg.h" /* Dataspace functions */
+#include "H5VMprivate.h" /* Vector functions */
+
+/* Static function prototypes */
+
+/* Selection callbacks */
+static herr_t H5S_all_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+static herr_t H5S_all_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+static herr_t H5S_all_release(H5S_t *space);
+static htri_t H5S_all_is_valid(const H5S_t *space);
+static hssize_t H5S_all_serial_size(const H5S_t *space);
+static herr_t H5S_all_serialize(const H5S_t *space, uint8_t **p);
+static herr_t H5S_all_deserialize(H5S_t *space, uint32_t version, uint8_t flags,
+ const uint8_t **p);
+static herr_t H5S_all_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
+static herr_t H5S_all_offset(const H5S_t *space, hsize_t *off);
+static int H5S__all_unlim_dim(const H5S_t *space);
+static htri_t H5S_all_is_contiguous(const H5S_t *space);
+static htri_t H5S_all_is_single(const H5S_t *space);
+static htri_t H5S_all_is_regular(const H5S_t *space);
+static herr_t H5S_all_adjust_u(H5S_t *space, const hsize_t *offset);
+static herr_t H5S_all_project_scalar(const H5S_t *space, hsize_t *offset);
+static herr_t H5S_all_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+static herr_t H5S_all_iter_init(H5S_sel_iter_t *iter, const H5S_t *space);
+
+/* Selection iteration callbacks */
+static herr_t H5S_all_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords);
+static herr_t H5S_all_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+static hsize_t H5S_all_iter_nelmts(const H5S_sel_iter_t *iter);
+static htri_t H5S_all_iter_has_next_block(const H5S_sel_iter_t *iter);
+static herr_t H5S_all_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
+static herr_t H5S_all_iter_next_block(H5S_sel_iter_t *sel_iter);
+static herr_t H5S_all_iter_release(H5S_sel_iter_t *sel_iter);
+
+/* Selection properties for "all" selections */
+const H5S_select_class_t H5S_sel_all[1] = {{
+ H5S_SEL_ALL,
+
+ /* Methods on selection */
+ H5S_all_copy,
+ H5S_all_get_seq_list,
+ H5S_all_release,
+ H5S_all_is_valid,
+ H5S_all_serial_size,
+ H5S_all_serialize,
+ H5S_all_deserialize,
+ H5S_all_bounds,
+ H5S_all_offset,
+ H5S__all_unlim_dim,
+ NULL,
+ H5S_all_is_contiguous,
+ H5S_all_is_single,
+ H5S_all_is_regular,
+ H5S_all_adjust_u,
+ H5S_all_project_scalar,
+ H5S_all_project_simple,
+ H5S_all_iter_init,
+}};
+
+/* Iteration properties for "all" selections */
+static const H5S_sel_iter_class_t H5S_sel_iter_all[1] = {{
+ H5S_SEL_ALL,
+
+ /* Methods on selection iterator */
+ H5S_all_iter_coords,
+ H5S_all_iter_block,
+ H5S_all_iter_nelmts,
+ H5S_all_iter_has_next_block,
+ H5S_all_iter_next,
+ H5S_all_iter_next_block,
+ H5S_all_iter_release,
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_iter_init
+ *
+ * Purpose: Initializes iteration information for "all" selection.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_all_iter_init (H5S_sel_iter_t *iter, const H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (space && H5S_SEL_ALL==H5S_GET_SELECT_TYPE(space));
+ HDassert (iter);
+
+ /* Initialize the number of elements to iterate over */
+ iter->elmt_left=H5S_GET_SELECT_NPOINTS(space);
+
+ /* Start at the upper left location */
+ iter->u.all.elmt_offset=0;
+ iter->u.all.byte_offset=0;
+
+ /* Initialize type of selection iterator */
+ iter->type=H5S_sel_iter_all;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_iter_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_iter_coords
+ *
+ * Purpose: Retrieve the current coordinates of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 22, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_all_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert (iter);
+ HDassert (coords);
+
+ /* Calculate the coordinates for the current iterator offset */
+ if(H5VM_array_calc(iter->u.all.elmt_offset,iter->rank,iter->dims,coords)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve coordinates");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_all_iter_coords() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_iter_block
+ *
+ * Purpose: Retrieve the current block of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 2, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_all_iter_block (const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+ HDassert (start);
+ HDassert (end);
+
+ for(u=0; u<iter->rank; u++) {
+ /* Set the start of the 'all' block */
+ /* (Always '0' coordinates for now) */
+ start[u]=0;
+
+ /* Compute the end of the 'all' block */
+ /* (Always size of the extent for now) */
+ end[u]=iter->dims[u]-1;
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_iter_coords() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_iter_nelmts
+ *
+ * Purpose: Return number of elements left to process in iterator
+ *
+ * Return: non-negative number of elements on success, zero on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5S_all_iter_nelmts (const H5S_sel_iter_t *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+
+ FUNC_LEAVE_NOAPI(iter->elmt_left)
+} /* H5S_all_iter_nelmts() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_iter_next
+ PURPOSE
+ Check if there is another block left in the current iterator
+ USAGE
+ htri_t H5S_all_iter_has_next_block(iter)
+ const H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative (TRUE/FALSE) on success/Negative on failure
+ DESCRIPTION
+ Check if there is another block available in the selection iterator.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_all_iter_has_next_block (const H5S_sel_iter_t H5_ATTR_UNUSED *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+
+ FUNC_LEAVE_NOAPI(FALSE)
+} /* H5S_all_iter_has_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_iter_next
+ PURPOSE
+ Increment selection iterator
+ USAGE
+ herr_t H5S_all_iter_next(iter, nelem)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ size_t nelem; IN: Number of elements to advance by
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the NELEM'th next element in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_iter_next(H5S_sel_iter_t *iter, size_t nelem)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+ HDassert (nelem>0);
+
+ /* Increment the iterator */
+ iter->u.all.elmt_offset+=nelem;
+ iter->u.all.byte_offset+=(nelem*iter->elmt_size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_iter_next() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_iter_next_block
+ PURPOSE
+ Increment selection iterator to next block
+ USAGE
+ herr_t H5S_all_iter_next_block(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the next block in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_all_iter_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_iter_release
+ PURPOSE
+ Release "all" selection iterator information for a dataspace
+ USAGE
+ herr_t H5S_all_iter_release(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all information for a dataspace "all" selection iterator
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_iter_release (H5S_sel_iter_t H5_ATTR_UNUSED * iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert (iter);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_iter_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_release
+ PURPOSE
+ Release all selection information for a dataspace
+ USAGE
+ herr_t H5S_all_release(space)
+ H5S_t *space; IN: Pointer to dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases "all" selection information for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_release(H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ /* Reset the number of elements in the selection */
+ space->select.num_elem = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_copy
+ PURPOSE
+ Copy a selection from one dataspace to another
+ USAGE
+ herr_t H5S_all_copy(dst, src)
+ H5S_t *dst; OUT: Pointer to the destination dataspace
+ H5S_t *src; IN: Pointer to the source dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Copies the 'all' selection information from the source
+ dataspace to the destination dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_copy(H5S_t *dst, const H5S_t H5_ATTR_UNUSED *src, hbool_t H5_ATTR_UNUSED share_selection)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(src);
+ HDassert(dst);
+
+ /* Set number of elements in selection */
+ dst->select.num_elem = (hsize_t)H5S_GET_EXTENT_NPOINTS(dst);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_all_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_is_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_all_is_valid(space);
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace. Offset is irrelevant for this type of selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_all_is_valid (const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* end H5S_all_is_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_serial_size
+ PURPOSE
+ Determine the number of bytes needed to store the serialized "all"
+ selection information.
+ USAGE
+ hssize_t H5S_all_serial_size(space)
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ The number of bytes required on success, negative on an error.
+ DESCRIPTION
+ Determines the number of bytes required to serialize an "all"
+ selection for storage on disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hssize_t
+H5S_all_serial_size (const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Basic number of bytes required to serialize point selection:
+ * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> +
+ * <length (4 bytes)> = 16 bytes
+ */
+ FUNC_LEAVE_NOAPI(16)
+} /* end H5S_all_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_serialize
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ herr_t H5S_all_serialize(space, p)
+ const H5S_t *space; IN: Dataspace with selection to serialize
+ uint8_t **p; OUT: Pointer to buffer to put serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_serialize(const H5S_t *space, uint8_t **p)
+{
+ uint8_t *pp = (*p); /* Local pointer for decoding */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Store the preamble information */
+ UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
+ UINT32ENCODE(pp, (uint32_t)1); /* Store the version number */
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the additional information length */
+
+ /* Update encoding pointer */
+ *p = pp;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_serialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_deserialize
+ PURPOSE
+ Deserialize the current selection from a user-provided buffer.
+ USAGE
+ herr_t H5S_all_deserialize(space, p)
+ H5S_t *space; IN/OUT: Dataspace pointer to place
+ selection into
+ uint32_t version IN: Selection version
+ uint8_t flags IN: Selection flags
+ uint8 **p; OUT: Pointer to buffer holding serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Deserializes the current selection into a buffer. (Primarily for retrieving
+ from disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t H5_ATTR_UNUSED flags,
+ const uint8_t H5_ATTR_UNUSED **p)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+ HDassert(p);
+ HDassert(*p);
+
+ /* Change to "all" selection */
+ if(H5S_select_all(space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_all_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_all_bounds(space, start, end)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *start; OUT: Starting coordinate of bounding box
+ hsize_t *end; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8). Calling this function on a "none" selection
+ returns fail.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
+{
+ unsigned rank; /* Dataspace rank */
+ unsigned i; /* index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ /* Get the dataspace extent rank */
+ rank = space->extent.rank;
+
+ /* Just copy over the complete extent */
+ for(i = 0; i < rank; i++) {
+ start[i] = 0;
+ end[i] = space->extent.size[i] - 1;
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_offset
+ PURPOSE
+ Gets the linear offset of the first element for the selection.
+ USAGE
+ herr_t H5S_all_offset(space, offset)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *offset; OUT: Linear offset of first element in selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the linear offset (in "units" of elements) of the first element
+ selected within the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Calling this function on a "none" selection returns fail.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_offset(const H5S_t H5_ATTR_UNUSED *space, hsize_t *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(offset);
+
+ /* 'All' selections always start at offset 0 */
+ *offset = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__all_unlim_dim
+ PURPOSE
+ Return unlimited dimension of selection, or -1 if none
+ USAGE
+ int H5S__all_unlim_dim(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ Unlimited dimension of selection, or -1 if none (never fails).
+ DESCRIPTION
+ Returns the index of the unlimited dimension in this selection, or -1
+ if the selection has no unlimited dimension. "All" selections are
+ always unlimited in every dimension, though this is not reflected in
+ other calls, where the selection is "clipped" against the current
+ extent, so for consistency this function always returns -1.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5S__all_unlim_dim(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(-1)
+} /* end H5S__all_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_is_contiguous
+ PURPOSE
+ Check if a "all" selection is contiguous within the dataspace extent.
+ USAGE
+ htri_t H5S_all_is_contiguous(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is contiguous.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_all_is_contiguous(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* H5S_all_is_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_is_single
+ PURPOSE
+ Check if a "all" selection is a single block within the dataspace extent.
+ USAGE
+ htri_t H5S_all_is_single(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is a single block.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_all_is_single(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* H5S_all_is_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_is_regular
+ PURPOSE
+ Check if a "all" selection is "regular"
+ USAGE
+ htri_t H5S_all_is_regular(space)
+ const H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in a dataspace is the a regular
+ pattern.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_all_is_regular(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* H5S_all_is_regular() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_adjust_u
+ PURPOSE
+ Adjust an "all" selection by subtracting an offset
+ USAGE
+ herr_t H5S_all_adjust_u(space, offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_adjust_u(H5S_t H5_ATTR_UNUSED *space, const hsize_t H5_ATTR_UNUSED *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(offset);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_adjust_u() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_project_scalar
+ *
+ * Purpose: Projects a single element 'all' selection into a scalar
+ * dataspace
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_all_project_scalar(const H5S_t H5_ATTR_UNUSED *space, hsize_t *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space && H5S_SEL_ALL == H5S_GET_SELECT_TYPE(space));
+ HDassert(offset);
+
+ /* Set offset of selection in projected buffer */
+ *offset = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_all_project_scalar() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_all_project_simple
+ *
+ * Purpose: Projects an 'all' selection onto/into a simple dataspace
+ * of a different rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_all_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_ALL == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(offset);
+
+ /* Select the entire new space */
+ if(H5S_select_all(new_space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to set all selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_all_project_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_all
+ PURPOSE
+ Specify the the entire extent is selected
+ USAGE
+ herr_t H5S_select_all(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ hbool_t rel_prev; IN: Flag whether to release previous selection or not
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function selects the entire extent for a dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_all(H5S_t *space, hbool_t rel_prev)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+
+ /* Remove current selection first */
+ if(rel_prev)
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Set number of elements in selection */
+ space->select.num_elem = (hsize_t)H5S_GET_EXTENT_NPOINTS(space);
+
+ /* Set selection type */
+ space->select.type = H5S_sel_all;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_all() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_all
+ PURPOSE
+ Specify the the entire extent is selected
+ USAGE
+ herr_t H5Sselect_all(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function selects the entire extent for a dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_all(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Call internal routine to do the work */
+ if(H5S_select_all(space, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sselect_all() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_all_get_seq_list
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_all_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_all_get_seq_list(const H5S_t H5_ATTR_UNUSED *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t *iter,
+ size_t H5_ATTR_UNUSED maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ size_t elem_used; /* The number of elements used */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq>0);
+ HDassert(maxelem>0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* Determine the actual number of elements to use */
+ H5_CHECK_OVERFLOW(iter->elmt_left,hsize_t,size_t);
+ elem_used=MIN(maxelem,(size_t)iter->elmt_left);
+ HDassert(elem_used > 0);
+
+ /* Compute the offset in the dataset */
+ off[0]=iter->u.all.byte_offset;
+ len[0]=elem_used*iter->elmt_size;
+
+ /* Should only need one sequence for 'all' selections */
+ *nseq=1;
+
+ /* Set the number of elements used */
+ *nelem=elem_used;
+
+ /* Update the iterator */
+ iter->elmt_left-=elem_used;
+ iter->u.all.elmt_offset+=elem_used;
+ iter->u.all.byte_offset+=len[0];
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_all_get_seq_list() */
+
diff --git a/src/H5Sdbg.c b/src/H5Sdbg.c
new file mode 100644
index 0000000..c9103f7
--- /dev/null
+++ b/src/H5Sdbg.c
@@ -0,0 +1,123 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Sdbg.c
+ * Jul 24 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Dump debugging information about a dataspace
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Spkg.h" /* Dataspaces */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_debug
+ *
+ * Purpose: Prints debugging information about a data space.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, July 21, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream, int indent,
+ int fwidth)
+{
+ const H5S_t *mesg = (const H5S_t*)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ switch(H5S_GET_EXTENT_TYPE(mesg)) {
+ case H5S_NULL:
+ fprintf(stream, "%*s%-*s H5S_NULL\n", indent, "", fwidth,
+ "Space class:");
+ break;
+
+ case H5S_SCALAR:
+ fprintf(stream, "%*s%-*s H5S_SCALAR\n", indent, "", fwidth,
+ "Space class:");
+ break;
+
+ case H5S_SIMPLE:
+ fprintf(stream, "%*s%-*s H5S_SIMPLE\n", indent, "", fwidth,
+ "Space class:");
+ H5O_debug_id(H5O_SDSPACE_ID, f, dxpl_id, &(mesg->extent), stream,
+ indent + 3, MAX(0, fwidth - 3));
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ fprintf(stream, "%*s%-*s **UNKNOWN-%ld**\n", indent, "", fwidth,
+ "Space class:", (long)(H5S_GET_EXTENT_TYPE(mesg)));
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_debug() */
+
diff --git a/src/H5Shyper.c b/src/H5Shyper.c
new file mode 100644
index 0000000..e6e6cff
--- /dev/null
+++ b/src/H5Shyper.c
@@ -0,0 +1,10452 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, June 18, 1998
+ *
+ * Purpose: Hyperslab selection data space I/O functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* ID Functions */
+#include "H5Spkg.h" /* Dataspace functions */
+#include "H5VMprivate.h" /* Vector functions */
+
+/* Local datatypes */
+
+/* Static function prototypes */
+static herr_t H5S_hyper_free_span_info(H5S_hyper_span_info_t *span_info);
+static herr_t H5S_hyper_free_span(H5S_hyper_span_t *span);
+static H5S_hyper_span_info_t *H5S_hyper_copy_span(H5S_hyper_span_info_t *spans);
+static void H5S_hyper_span_scratch(H5S_hyper_span_info_t *spans, void *scr_value);
+static herr_t H5S_hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size);
+static herr_t H5S_generate_hyperslab(H5S_t *space, H5S_seloper_t op,
+ const hsize_t start[], const hsize_t stride[], const hsize_t count[], const hsize_t block[]);
+static herr_t H5S_hyper_generate_spans(H5S_t *space);
+/* Needed for use in hyperslab code (H5Shyper.c) */
+#ifdef NEW_HYPERSLAB_API
+static herr_t H5S_select_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2);
+#endif /*NEW_HYPERSLAB_API*/
+static void H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride,
+ hsize_t *count, hsize_t *block, hsize_t clip_size);
+static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space,
+ hsize_t num_slices, hbool_t incl_trail);
+
+/* Selection callbacks */
+static herr_t H5S_hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+static herr_t H5S_hyper_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+static herr_t H5S_hyper_release(H5S_t *space);
+static htri_t H5S_hyper_is_valid(const H5S_t *space);
+static hssize_t H5S_hyper_serial_size(const H5S_t *space);
+static herr_t H5S_hyper_serialize(const H5S_t *space, uint8_t **p);
+static herr_t H5S_hyper_deserialize(H5S_t *space, uint32_t version, uint8_t flags,
+ const uint8_t **p);
+static herr_t H5S_hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
+static herr_t H5S_hyper_offset(const H5S_t *space, hsize_t *offset);
+static int H5S__hyper_unlim_dim(const H5S_t *space);
+static herr_t H5S_hyper_num_elem_non_unlim(const H5S_t *space,
+ hsize_t *num_elem_non_unlim);
+static htri_t H5S_hyper_is_contiguous(const H5S_t *space);
+static htri_t H5S_hyper_is_single(const H5S_t *space);
+static htri_t H5S_hyper_is_regular(const H5S_t *space);
+static herr_t H5S_hyper_adjust_u(H5S_t *space, const hsize_t *offset);
+static herr_t H5S_hyper_project_scalar(const H5S_t *space, hsize_t *offset);
+static herr_t H5S_hyper_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+static herr_t H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space);
+
+/* Selection iteration callbacks */
+static herr_t H5S_hyper_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords);
+static herr_t H5S_hyper_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+static hsize_t H5S_hyper_iter_nelmts(const H5S_sel_iter_t *iter);
+static htri_t H5S_hyper_iter_has_next_block(const H5S_sel_iter_t *sel_iter);
+static herr_t H5S_hyper_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
+static herr_t H5S_hyper_iter_next_block(H5S_sel_iter_t *sel_iter);
+static herr_t H5S_hyper_iter_release(H5S_sel_iter_t *sel_iter);
+
+/* Static function for optimizing hyperslab */
+static hbool_t H5S_hyper_rebuild_helper(const H5S_hyper_span_t *span,
+ H5S_hyper_dim_t span_slab_info[], unsigned rank);
+static htri_t H5S_hyper_rebuild(H5S_t *space);
+
+/* Selection properties for hyperslab selections */
+const H5S_select_class_t H5S_sel_hyper[1] = {{
+ H5S_SEL_HYPERSLABS,
+
+ /* Methods on selection */
+ H5S_hyper_copy,
+ H5S_hyper_get_seq_list,
+ H5S_hyper_release,
+ H5S_hyper_is_valid,
+ H5S_hyper_serial_size,
+ H5S_hyper_serialize,
+ H5S_hyper_deserialize,
+ H5S_hyper_bounds,
+ H5S_hyper_offset,
+ H5S__hyper_unlim_dim,
+ H5S_hyper_num_elem_non_unlim,
+ H5S_hyper_is_contiguous,
+ H5S_hyper_is_single,
+ H5S_hyper_is_regular,
+ H5S_hyper_adjust_u,
+ H5S_hyper_project_scalar,
+ H5S_hyper_project_simple,
+ H5S_hyper_iter_init,
+}};
+
+/* Iteration properties for hyperslab selections */
+static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{
+ H5S_SEL_HYPERSLABS,
+
+ /* Methods on selection iterator */
+ H5S_hyper_iter_coords,
+ H5S_hyper_iter_block,
+ H5S_hyper_iter_nelmts,
+ H5S_hyper_iter_has_next_block,
+ H5S_hyper_iter_next,
+ H5S_hyper_iter_next_block,
+ H5S_hyper_iter_release,
+}};
+
+/* Static variables */
+
+/* Array for default stride, block, etc. */
+static const hsize_t _ones[H5O_LAYOUT_NDIMS]={
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,1};
+
+/* Declare a free list to manage the H5S_hyper_sel_t struct */
+H5FL_DEFINE_STATIC(H5S_hyper_sel_t);
+
+/* Declare a free list to manage the H5S_hyper_span_t struct */
+H5FL_DEFINE_STATIC(H5S_hyper_span_t);
+
+/* Declare a free list to manage the H5S_hyper_span_info_t struct */
+H5FL_DEFINE_STATIC(H5S_hyper_span_info_t);
+
+/* Declare extern free list to manage the H5S_sel_iter_t struct */
+H5FL_EXTERN(H5S_sel_iter_t);
+
+/* #define H5S_HYPER_DEBUG */
+#ifdef H5S_HYPER_DEBUG
+static herr_t
+H5S_hyper_print_spans_helper(FILE *f, struct H5S_hyper_span_t *span,unsigned depth)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ while(span) {
+ HDfprintf(f,"%s: depth=%u, span=%p, (%d, %d), nelem=%u, pstride=%u\n",FUNC,depth,span,(int)span->low,(int)span->high,(unsigned)span->nelem,(unsigned)span->pstride);
+ if(span->down && span->down->head) {
+ HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,span->down,span->down->count,span->down->scratch,span->down->head);
+ H5S_hyper_print_spans_helper(f,span->down->head,depth+1);
+ } /* end if */
+ span=span->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+herr_t
+H5S_hyper_print_spans(FILE *f, const struct H5S_hyper_span_info_t *span_lst)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(span_lst!=NULL) {
+ HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,span_lst,span_lst->count,span_lst->scratch,span_lst->head);
+ H5S_hyper_print_spans_helper(f,span_lst->head,0);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+herr_t
+H5S_space_print_spans(FILE *f, const H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5S_hyper_print_spans(f,space->select.sel_info.hslab->span_lst);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+static herr_t
+H5S_hyper_print_diminfo_helper(FILE *f, const char *field, unsigned ndims, const H5S_hyper_dim_t *dinfo)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(dinfo!=NULL) {
+ HDfprintf(f,"%s: %s: start=[",FUNC,field);
+ for(u=0; u<ndims; u++)
+ HDfprintf(f,"%Hd%s",dinfo[u].start, (u<(ndims-1) ? ", " : "]\n"));
+ HDfprintf(f,"%s: %s: stride=[",FUNC,field);
+ for(u=0; u<ndims; u++)
+ HDfprintf(f,"%Hu%s",dinfo[u].stride, (u<(ndims-1) ? ", " : "]\n"));
+ HDfprintf(f,"%s: %s: count=[",FUNC,field);
+ for(u=0; u<ndims; u++)
+ HDfprintf(f,"%Hu%s",dinfo[u].count, (u<(ndims-1) ? ", " : "]\n"));
+ HDfprintf(f,"%s: %s: block=[",FUNC,field);
+ for(u=0; u<ndims; u++)
+ HDfprintf(f,"%Hu%s",dinfo[u].block, (u<(ndims-1) ? ", " : "]\n"));
+ } /* end if */
+ else
+ HDfprintf(f,"%s: %s==NULL\n",FUNC,field);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+herr_t
+H5S_hyper_print_diminfo(FILE *f, const H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5S_hyper_print_diminfo_helper(f,"opt_diminfo",space->extent.rank,space->select.sel_info.hslab->opt_diminfo);
+ H5S_hyper_print_diminfo_helper(f,"app_diminfo",space->extent.rank,space->select.sel_info.hslab->app_diminfo);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+#endif /* H5S_HYPER_DEBUG */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_init
+ *
+ * Purpose: Initializes iteration information for hyperslab span tree selection.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 24, 2001
+ *
+ * Notes: If the 'elmt_size' parameter is set to zero, the regular
+ * hyperslab selection iterator will not be 'flattened'. This
+ * is used by the H5S_select_shape_same() code to avoid changing
+ * the rank and appearance of the selection.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space)
+{
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */
+ unsigned rank; /* Dataspace's dimension rank */
+ unsigned u; /* Index variable */
+ int i; /* Index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
+ HDassert(iter);
+ HDassert(space->select.sel_info.hslab->unlim_dim < 0);
+
+ /* Initialize the number of points to iterate over */
+ iter->elmt_left = space->select.num_elem;
+ iter->u.hyp.iter_rank = 0;
+
+ /* Get the rank of the dataspace */
+ rank = space->extent.rank;
+
+ /* Set the temporary pointer to the dimension information */
+ tdiminfo = space->select.sel_info.hslab->opt_diminfo;
+
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+/* Initialize the information needed for regular hyperslab I/O */
+ const hsize_t *mem_size; /* Temporary pointer to dataspace extent's dimension sizes */
+ hsize_t acc; /* Accumulator for "flattened" dimension's sizes */
+ unsigned cont_dim = 0; /* # of contiguous dimensions */
+
+ /* Set the temporary pointer to the dataspace extent's dimension sizes */
+ mem_size = space->extent.size;
+
+ /*
+ * For a regular hyperslab to be contiguous up to some dimension, it
+ * must have only one block (i.e. count==1 in all dimensions up to that
+ * dimension) and the block size must be the same as the dataspace's
+ * extent in that dimension and all dimensions up to that dimension.
+ */
+
+ /* Don't flatten adjacent elements into contiguous block if the
+ * element size is 0. This is for the H5S_select_shape_same() code.
+ */
+ if(iter->elmt_size > 0) {
+ /* Check for any "contiguous" blocks that can be flattened */
+ for(u = (rank - 1); u > 0; u--) {
+ if(tdiminfo[u].count == 1 && tdiminfo[u].block == mem_size[u]) {
+ cont_dim++;
+ iter->u.hyp.flattened[u] = TRUE;
+ } /* end if */
+ else
+ iter->u.hyp.flattened[u] = FALSE;
+ } /* end for */
+ iter->u.hyp.flattened[0] = FALSE;
+ } /* end if */
+
+ /* Check if the regular selection can be "flattened" */
+ if(cont_dim > 0) {
+ unsigned last_dim_flattened = 1; /* Flag to indicate that the last dimension was flattened */
+ unsigned flat_rank = rank-cont_dim; /* Number of dimensions after flattening */
+ unsigned curr_dim; /* Current dimension */
+
+ /* Set the iterator's rank to the contiguous dimensions */
+ iter->u.hyp.iter_rank = flat_rank;
+
+ /* "Flatten" dataspace extent and selection information */
+ curr_dim = flat_rank - 1;
+ for(i = (int)rank - 1, acc = 1; i >= 0; i--) {
+ if(tdiminfo[i].block == mem_size[i] && i > 0) {
+ /* "Flatten" this dimension */
+ HDassert(tdiminfo[i].start == 0);
+ acc *= mem_size[i];
+
+ /* Indicate that the dimension was flattened */
+ last_dim_flattened = 1;
+ } /* end if */
+ else {
+ if(last_dim_flattened) {
+ /* First dimension after flattened dimensions */
+ iter->u.hyp.diminfo[curr_dim].start = tdiminfo[i].start * acc;
+
+ /* Special case for single block regular selections */
+ if(tdiminfo[i].count == 1)
+ iter->u.hyp.diminfo[curr_dim].stride = 1;
+ else
+ iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride * acc;
+ iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count;
+ iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block * acc;
+ iter->u.hyp.size[curr_dim] = mem_size[i] * acc;
+ iter->u.hyp.sel_off[curr_dim] = space->select.offset[i] * (hssize_t)acc;
+
+ /* Reset the "last dim flattened" flag to avoid flattened any further dimensions */
+ last_dim_flattened = 0;
+
+ /* Reset the "accumulator" for possible further dimension flattening */
+ acc = 1;
+ } /* end if */
+ else {
+ /* All other dimensions */
+ iter->u.hyp.diminfo[curr_dim].start = tdiminfo[i].start;
+ iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride;
+ iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count;
+ iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block;
+ iter->u.hyp.size[curr_dim] = mem_size[i];
+ iter->u.hyp.sel_off[curr_dim] = space->select.offset[i];
+ } /* end else */
+
+ /* Decrement "current" flattened dimension */
+ curr_dim--;
+ } /* end if */
+ } /* end for */
+
+ /* Initialize "flattened" iterator offset to initial location and dataspace extent and selection information to correct values */
+ for(u = 0; u < flat_rank; u++)
+ iter->u.hyp.off[u] = iter->u.hyp.diminfo[u].start;
+ } /* end if */
+ else {
+ /* Initialize position to initial location */
+ /* Also make local copy of the regular selection information */
+ for(u = 0; u < rank; u++) {
+ /* Regular selection information */
+ iter->u.hyp.diminfo[u].start = tdiminfo[u].start;
+ iter->u.hyp.diminfo[u].stride = tdiminfo[u].stride;
+ iter->u.hyp.diminfo[u].count = tdiminfo[u].count;
+ iter->u.hyp.diminfo[u].block = tdiminfo[u].block;
+
+ /* Position information */
+ iter->u.hyp.off[u] = tdiminfo[u].start;
+ } /* end if */
+ } /* end else */
+
+ /* Flag the diminfo information as valid in the iterator */
+ iter->u.hyp.diminfo_valid = TRUE;
+
+ /* Initialize irregular region information also (for release) */
+ iter->u.hyp.spans = NULL;
+ } /* end if */
+ else {
+/* Initialize the information needed for non-regular hyperslab I/O */
+ HDassert(space->select.sel_info.hslab->span_lst);
+ /* Make a copy of the span tree to iterate over */
+ iter->u.hyp.spans = H5S_hyper_copy_span(space->select.sel_info.hslab->span_lst);
+
+ /* Set the nelem & pstride values according to the element size */
+ H5S_hyper_span_precompute(iter->u.hyp.spans,iter->elmt_size);
+
+ /* Initialize the starting span_info's and spans */
+ spans = iter->u.hyp.spans;
+ for(u = 0; u < rank; u++) {
+ /* Set the pointers to the initial span in each dimension */
+ HDassert(spans);
+ HDassert(spans->head);
+
+ /* Set the pointer to the first span in the list for this node */
+ iter->u.hyp.span[u] = spans->head;
+
+ /* Set the initial offset to low bound of span */
+ iter->u.hyp.off[u] = iter->u.hyp.span[u]->low;
+
+ /* Get the pointer to the next level down */
+ spans = spans->head->down;
+ } /* end for */
+
+ /* Flag the diminfo information as not valid in the iterator */
+ iter->u.hyp.diminfo_valid = FALSE;
+ } /* end else */
+
+ /* Initialize type of selection iterator */
+ iter->type = H5S_sel_iter_hyper;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_coords
+ *
+ * Purpose: Retrieve the current coordinates of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 22, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(coords);
+
+ /* Copy the offset of the current point */
+
+ /* Check for a single "regular" hyperslab */
+ if(iter->u.hyp.diminfo_valid) {
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
+ int u, v; /* Dimension indices */
+
+ /* Set the starting rank of both the "natural" & "flattened" dimensions */
+ u = (int)iter->rank - 1;
+ v = (int)iter->u.hyp.iter_rank - 1;
+
+ /* Construct the "natural" dimensions from a set of flattened coordinates */
+ while(u >= 0) {
+ if(iter->u.hyp.flattened[u]) {
+ int begin = u; /* The rank of the first flattened dimension */
+
+ /* Walk up through as many flattened dimensions as possible */
+ do {
+ u--;
+ } while(u >= 0 && iter->u.hyp.flattened[u]);
+
+ /* Compensate for possibly overshooting dim 0 */
+ if(u < 0)
+ u = 0;
+
+ /* Sanity check */
+ HDassert(v >= 0);
+
+ /* Compute the coords for the flattened dimensions */
+ H5VM_array_calc(iter->u.hyp.off[v], (unsigned)((begin - u) + 1), &(iter->dims[u]), &(coords[u]));
+
+ /* Continue to faster dimension in both indices */
+ u--;
+ v--;
+ } /* end if */
+ else {
+ /* Walk up through as many non-flattened dimensions as possible */
+ while(u >= 0 && !iter->u.hyp.flattened[u]) {
+ /* Sanity check */
+ HDassert(v >= 0);
+
+ /* Copy the coordinate */
+ coords[u] = iter->u.hyp.off[v];
+
+ /* Continue to faster dimension in both indices */
+ u--;
+ v--;
+ } /* end while */
+ } /* end else */
+ } /* end while */
+ HDassert(v < 0);
+ } /* end if */
+ else
+ HDmemcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank);
+ } /* end if */
+ else
+ HDmemcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_coords() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_block
+ *
+ * Purpose: Retrieve the current block of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 2, 2003
+ *
+ * Notes: This routine assumes that the iterator is always located at
+ * the beginning of a block.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_iter_block (const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(start);
+ HDassert(end);
+
+ /* Copy the offset of the current point */
+
+ /* Check for a single "regular" hyperslab */
+ if(iter->u.hyp.diminfo_valid) {
+ /* Compute the end of the block */
+ for(u=0; u<iter->rank; u++) {
+ start[u]=iter->u.hyp.off[u];
+ end[u]=(start[u]+iter->u.hyp.diminfo[u].block)-1;
+ } /* end for */
+ } /* end if */
+ else {
+ /* Copy the start of the block */
+ for(u=0; u<iter->rank; u++)
+ start[u]=iter->u.hyp.span[u]->low;
+
+ /* Copy the end of the block */
+ for(u=0; u<iter->rank; u++)
+ end[u]=iter->u.hyp.span[u]->high;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_block() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_nelmts
+ *
+ * Purpose: Return number of elements left to process in iterator
+ *
+ * Return: non-negative number of elements on success, zero on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5S_hyper_iter_nelmts (const H5S_sel_iter_t *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(iter->elmt_left)
+} /* H5S_hyper_iter_nelmts() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_iter_has_next_block
+ PURPOSE
+ Check if there is another block left in the current iterator
+ USAGE
+ htri_t H5S_hyper_iter_has_next_block(iter)
+ const H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative (TRUE/FALSE) on success/Negative on failure
+ DESCRIPTION
+ Check if there is another block available in the selection iterator.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_iter_has_next_block(const H5S_sel_iter_t *iter)
+{
+ unsigned u; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ /* Check for a single "regular" hyperslab */
+ if(iter->u.hyp.diminfo_valid) {
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ const hsize_t *toff; /* Temporary offset in selection */
+
+ /* Check if the offset of the iterator is at the last location in all dimensions */
+ tdiminfo = iter->u.hyp.diminfo;
+ toff = iter->u.hyp.off;
+ for(u = 0; u < iter->rank; u++) {
+ /* If there is only one block, continue */
+ if(tdiminfo[u].count == 1)
+ continue;
+ if(toff[u] != (tdiminfo[u].start + ((tdiminfo[u].count - 1) * tdiminfo[u].stride)))
+ HGOTO_DONE(TRUE);
+ } /* end for */
+ } /* end if */
+ else {
+ /* Check for any levels of the tree with more sequences in them */
+ for(u = 0; u < iter->rank; u++)
+ if(iter->u.hyp.span[u]->next != NULL)
+ HGOTO_DONE(TRUE);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_iter_has_next_block() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_next
+ *
+ * Purpose: Moves a hyperslab iterator to the beginning of the next sequence
+ * of elements to read. Handles walking off the end in all dimensions.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 8, 2000
+ *
+ * Modifications:
+ * Modified for both general and optimized hyperslab I/O
+ * Quincey Koziol, April 17, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_iter_next(H5S_sel_iter_t *iter, size_t nelem)
+{
+ unsigned ndims; /* Number of dimensions of dataset */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned i; /* Counters */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ /* (i.e. a regular hyperslab selection */
+ if(iter->u.hyp.diminfo_valid) {
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ hsize_t iter_offset[H5O_LAYOUT_NDIMS];
+ hsize_t iter_count[H5O_LAYOUT_NDIMS];
+ int temp_dim; /* Temporary rank holder */
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rank<iter->rank) {
+ /* Set the aliases for the dimension rank */
+ ndims=iter->u.hyp.iter_rank;
+ } /* end if */
+ else {
+ /* Set the aliases for the dimension rank */
+ ndims=iter->rank;
+ } /* end else */
+
+ /* Set the fastest dimension rank */
+ fast_dim = (int)ndims - 1;
+
+ /* Set the local copy of the diminfo pointer */
+ tdiminfo=iter->u.hyp.diminfo;
+
+ /* Calculate the offset and block count for each dimension */
+ for(i=0; i<ndims; i++) {
+ if(tdiminfo[i].count==1) {
+ iter_offset[i]=iter->u.hyp.off[i]-tdiminfo[i].start;
+ iter_count[i]=0;
+ } /* end if */
+ else {
+ iter_offset[i]=(iter->u.hyp.off[i]-tdiminfo[i].start)%tdiminfo[i].stride;
+ iter_count[i]=(iter->u.hyp.off[i]-tdiminfo[i].start)/tdiminfo[i].stride;
+ } /* end else */
+ } /* end for */
+
+ /* Loop through, advancing the offset & counts, until all the nelements are accounted for */
+ while(nelem>0) {
+ /* Start with the fastest changing dimension */
+ temp_dim=fast_dim;
+ while(temp_dim>=0) {
+ if(temp_dim==fast_dim) {
+ size_t actual_elem; /* Actual # of elements advanced on each iteration through loop */
+ hsize_t block_elem; /* Number of elements left in a block */
+
+ /* Compute the number of elements left in block */
+ block_elem=tdiminfo[temp_dim].block-iter_offset[temp_dim];
+
+ /* Compute the number of actual elements to advance */
+ actual_elem=(size_t)MIN(nelem,block_elem);
+
+ /* Move the iterator over as many elements as possible */
+ iter_offset[temp_dim]+=actual_elem;
+
+ /* Decrement the number of elements advanced */
+ nelem-=actual_elem;
+ } /* end if */
+ else {
+ /* Move to the next row in the current dimension */
+ iter_offset[temp_dim]++;
+ } /* end else */
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_offset[temp_dim]<tdiminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ iter_offset[temp_dim]=0;
+ iter_count[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_count[temp_dim]<tdiminfo[temp_dim].count)
+ break;
+ else
+ iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+ } /* end while */
+
+ /* Translate current iter_offset and iter_count into iterator position */
+ for(i=0; i<ndims; i++)
+ iter->u.hyp.off[i]=tdiminfo[i].start+(tdiminfo[i].stride*iter_count[i])+iter_offset[i];
+ } /* end if */
+ /* Must be an irregular hyperslab selection */
+ else {
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ hsize_t *abs_arr; /* Absolute hyperslab span position */
+ int curr_dim; /* Temporary rank holder */
+
+ /* Set the rank of the fastest changing dimension */
+ ndims=iter->rank;
+ fast_dim = (int)ndims - 1;
+
+ /* Get the pointers to the current span info and span nodes */
+ abs_arr=iter->u.hyp.off;
+ ispan=iter->u.hyp.span;
+
+ /* Loop through, advancing the span information, until all the nelements are accounted for */
+ while(nelem>0) {
+ /* Start at the fastest dim */
+ curr_dim=fast_dim;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=ispan[curr_dim];
+
+ /* Increment absolute position */
+ if(curr_dim==fast_dim) {
+ size_t actual_elem; /* Actual # of elements advanced on each iteration through loop */
+ hsize_t span_elem; /* Number of elements left in a span */
+
+ /* Compute the number of elements left in block */
+ span_elem=(curr_span->high-abs_arr[curr_dim])+1;
+
+ /* Compute the number of actual elements to advance */
+ actual_elem=(size_t)MIN(nelem,span_elem);
+
+ /* Move the iterator over as many elements as possible */
+ abs_arr[curr_dim]+=actual_elem;
+
+ /* Decrement the number of elements advanced */
+ nelem-=actual_elem;
+ } /* end if */
+ else {
+ /* Move to the next row in the current dimension */
+ abs_arr[curr_dim]++;
+ } /* end else */
+
+ /* Check if we are still within the span */
+ if(abs_arr[curr_dim]<=curr_span->high) {
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Reset absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim>=0) {
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* Increment current dimension */
+ curr_dim++;
+
+ /* Set the new span_info & span for this dimension */
+ ispan[curr_dim]=curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span=curr_span->down->head;
+
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim]=curr_span->low;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span==ispan[fast_dim]);
+ } /* end if */
+ } /* end while */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_next() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_iter_next_block
+ *
+ * Purpose: Moves a hyperslab iterator to the beginning of the next sequence
+ * of elements to read. Handles walking off the end in all dimensions.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_iter_next_block(H5S_sel_iter_t *iter)
+{
+ unsigned ndims; /* Number of dimensions of dataset */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned u; /* Counters */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ /* (i.e. a regular hyperslab selection */
+ if(iter->u.hyp.diminfo_valid) {
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ hsize_t iter_offset[H5O_LAYOUT_NDIMS];
+ hsize_t iter_count[H5O_LAYOUT_NDIMS];
+ int temp_dim; /* Temporary rank holder */
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rank<iter->rank) {
+ /* Set the aliases for the dimension rank */
+ ndims=iter->u.hyp.iter_rank;
+ } /* end if */
+ else {
+ /* Set the aliases for the dimension rank */
+ ndims=iter->rank;
+ } /* end else */
+
+ /* Set the fastest dimension rank */
+ fast_dim = (int)ndims - 1;
+
+ /* Set the local copy of the diminfo pointer */
+ tdiminfo=iter->u.hyp.diminfo;
+
+ /* Calculate the offset and block count for each dimension */
+ for(u=0; u<ndims; u++) {
+ if(tdiminfo[u].count==1) {
+ iter_offset[u]=iter->u.hyp.off[u]-tdiminfo[u].start;
+ iter_count[u]=0;
+ } /* end if */
+ else {
+ iter_offset[u]=(iter->u.hyp.off[u]-tdiminfo[u].start)%tdiminfo[u].stride;
+ iter_count[u]=(iter->u.hyp.off[u]-tdiminfo[u].start)/tdiminfo[u].stride;
+ } /* end else */
+ } /* end for */
+
+ /* Advance one block */
+ temp_dim=fast_dim; /* Start with the fastest changing dimension */
+ while(temp_dim>=0) {
+ if(temp_dim==fast_dim) {
+ /* Move iterator over current block */
+ iter_offset[temp_dim]+=tdiminfo[temp_dim].block;
+ } /* end if */
+ else {
+ /* Move to the next row in the current dimension */
+ iter_offset[temp_dim]++;
+ } /* end else */
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_offset[temp_dim]<tdiminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ iter_offset[temp_dim]=0;
+ iter_count[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_count[temp_dim]<tdiminfo[temp_dim].count)
+ break;
+ else
+ iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+
+ /* Translate current iter_offset and iter_count into iterator position */
+ for(u=0; u<ndims; u++)
+ iter->u.hyp.off[u]=tdiminfo[u].start+(tdiminfo[u].stride*iter_count[u])+iter_offset[u];
+ } /* end if */
+ /* Must be an irregular hyperslab selection */
+ else {
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ hsize_t *abs_arr; /* Absolute hyperslab span position */
+ int curr_dim; /* Temporary rank holder */
+
+ /* Set the rank of the fastest changing dimension */
+ ndims = iter->rank;
+ fast_dim = (int)ndims - 1;
+
+ /* Get the pointers to the current span info and span nodes */
+ abs_arr=iter->u.hyp.off;
+ ispan=iter->u.hyp.span;
+
+ /* Loop through, advancing the span information, until all the nelements are accounted for */
+ curr_dim=fast_dim; /* Start at the fastest dim */
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=ispan[curr_dim];
+
+ /* Increment absolute position */
+ if(curr_dim==fast_dim) {
+ /* Move the iterator over rest of element in span */
+ abs_arr[curr_dim]=curr_span->high+1;
+ } /* end if */
+ else {
+ /* Move to the next row in the current dimension */
+ abs_arr[curr_dim]++;
+ } /* end else */
+
+ /* Check if we are still within the span */
+ if(abs_arr[curr_dim]<=curr_span->high) {
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Reset absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim>=0) {
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* Increment current dimension */
+ curr_dim++;
+
+ /* Set the new span_info & span for this dimension */
+ ispan[curr_dim]=curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span=curr_span->down->head;
+
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim]=curr_span->low;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span == ispan[fast_dim]);
+ } /* end if */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_next() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_iter_release
+ PURPOSE
+ Release hyperslab selection iterator information for a dataspace
+ USAGE
+ herr_t H5S_hyper_iter_release(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all information for a dataspace hyperslab selection iterator
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_iter_release (H5S_sel_iter_t *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+/* Release the information needed for non-regular hyperslab I/O */
+ /* Free the copy of the selections span tree */
+ if(iter->u.hyp.spans != NULL)
+ H5S_hyper_free_span_info(iter->u.hyp.spans);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_iter_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_new_span
+ PURPOSE
+ Make a new hyperslab span node
+ USAGE
+ H5S_hyper_span_t *H5S_hyper_new_span(low, high, down, next)
+ hsize_t low, high; IN: Low and high bounds for new span node
+ H5S_hyper_span_info_t *down; IN: Down span tree for new node
+ H5S_hyper_span_t *next; IN: Next span for new node
+ RETURNS
+ Pointer to next span node on success, NULL on failure
+ DESCRIPTION
+ Allocate and initialize a new hyperslab span node, filling in the low &
+ high bounds, the down span and next span pointers also. Increment the
+ reference count of the 'down span' if applicable.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_t *
+H5S_hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
+{
+ H5S_hyper_span_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate a new span node */
+ if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Copy the span's basic information */
+ ret_value->low = low;
+ ret_value->high = high;
+ ret_value->nelem = (high - low) + 1;
+ ret_value->pstride = 0;
+ ret_value->down = down;
+ ret_value->next = next;
+
+ /* Increment the reference count of the 'down span' if there is one */
+ if(ret_value->down)
+ ret_value->down->count++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_new_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_precompute_helper
+ PURPOSE
+ Helper routine to precompute the nelem and pstrides in bytes.
+ USAGE
+ herr_t H5S_hyper_span_precompute_helper(span_info, elmt_size)
+ H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on
+ size_t elmt_size; IN: element size to work with
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Change the nelem and pstride values in the span tree from elements to
+ bytes using the elmt_size parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_span_precompute_helper (H5S_hyper_span_info_t *spans, size_t elmt_size)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(spans);
+
+ /* Check if we've already set this down span tree */
+ if(spans->scratch!=(H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Set the tree's scratch pointer */
+ spans->scratch=(H5S_hyper_span_info_t *)~((size_t)NULL);
+
+ /* Set the scratch pointers in all the nodes */
+ span=spans->head;
+
+ /* Loop over all the spans for this down span tree */
+ while(span!=NULL) {
+ /* If there are down spans, set their scratch value also */
+ if(span->down!=NULL) {
+ if(H5S_hyper_span_precompute_helper(span->down,elmt_size)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't reset hyperslab scratch pointer")
+ } /* end if */
+
+ /* Change the nelem & pstride values into bytes */
+ span->nelem *= elmt_size;
+ span->pstride *= elmt_size;
+
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_span_precompute_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_precompute
+ PURPOSE
+ Precompute the nelem and pstrides in bytes.
+ USAGE
+ herr_t H5S_hyper_span_precompute(span_info, elmt_size)
+ H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on
+ size_t elmt_size; IN: element size to work with
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Change the nelem and pstride values in the span tree from elements to
+ bytes using the elmt_size parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(spans);
+
+ /* Call the helper routine to actually do the work */
+ if(H5S_hyper_span_precompute_helper(spans, elmt_size) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't precompute span info")
+
+ /* Reset the scratch pointers for the next routine which needs them */
+ H5S_hyper_span_scratch(spans, NULL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_span_precompute() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_scratch
+ PURPOSE
+ Set the scratch pointers on hyperslab span trees
+ USAGE
+ void H5S_hyper_span_scratch(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span tree to reset
+ RETURNS
+ <none>
+ DESCRIPTION
+ Set the scratch pointers on a hyperslab span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static void
+H5S_hyper_span_scratch(H5S_hyper_span_info_t *spans, void *scr_value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(spans);
+
+ /* Check if we've already set this down span tree */
+ if(spans->scratch != scr_value) {
+ H5S_hyper_span_t *span; /* Hyperslab span */
+
+ /* Set the tree's scratch pointer */
+ spans->scratch = (H5S_hyper_span_info_t *)scr_value;
+
+ /* Set the scratch pointers in all the nodes */
+ span = spans->head;
+ while(span != NULL) {
+ /* If there are down spans, set their scratch value also */
+ if(span->down != NULL)
+ H5S_hyper_span_scratch(span->down, scr_value);
+
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5S_hyper_span_scratch() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_copy_span_helper
+ PURPOSE
+ Helper routine to copy a hyperslab span tree
+ USAGE
+ H5S_hyper_span_info_t * H5S_hyper_copy_span_helper(spans)
+ H5S_hyper_span_info_t *spans; IN: Span tree to copy
+ RETURNS
+ Pointer to the copied span tree on success, NULL on failure
+ DESCRIPTION
+ Copy a hyperslab span tree, using reference counting as appropriate.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_copy_span_helper (H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ H5S_hyper_span_t *new_span; /* Temporary hyperslab span */
+ H5S_hyper_span_t *prev_span; /* Previous hyperslab span */
+ H5S_hyper_span_info_t *new_down; /* New down span tree */
+ H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(spans);
+
+ /* Check if the span tree was already copied */
+ if(spans->scratch != NULL && spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Just return the value of the already copied span tree */
+ ret_value = spans->scratch;
+
+ /* Increment the reference count of the span tree */
+ ret_value->count++;
+ } /* end if */
+ else {
+ /* Allocate a new span_info node */
+ if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_info_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info")
+
+ /* Copy the span_info information */
+ ret_value->count = 1;
+ ret_value->scratch = NULL;
+ ret_value->head = NULL;
+
+ /* Set the scratch pointer in the node being copied to the newly allocated node */
+ spans->scratch = ret_value;
+
+ /* Copy over the nodes in the span list */
+ span = spans->head;
+ prev_span = NULL;
+ while(span != NULL) {
+ /* Allocate a new node */
+ if(NULL == (new_span = H5S_hyper_new_span(span->low, span->high, NULL, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Append to list of spans */
+ if(NULL == prev_span)
+ ret_value->head = new_span;
+ else
+ prev_span->next = new_span;
+
+ /* Copy the pstride */
+ new_span->pstride = span->pstride;
+
+ /* Recurse to copy the 'down' spans, if there are any */
+ if(span->down != NULL) {
+ if(NULL == (new_down = H5S_hyper_copy_span_helper(span->down)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab spans")
+ new_span->down = new_down;
+ } /* end if */
+
+ /* Update the previous (new) span */
+ prev_span = new_span;
+
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_copy_span_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_copy_span
+ PURPOSE
+ Copy a hyperslab span tree
+ USAGE
+ H5S_hyper_span_info_t * H5S_hyper_copy_span(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span tree to copy
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Copy a hyperslab span tree, using reference counting as appropriate.
+ (Which means that just the nodes in the top span tree are duplicated and
+ the reference counts of their 'down spans' are just incremented)
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_copy_span(H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(spans);
+
+ /* Copy the hyperslab span tree */
+ if(NULL == (ret_value = H5S_hyper_copy_span_helper(spans)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree")
+
+ /* Reset the scratch pointers for the next routine which needs them */
+ H5S_hyper_span_scratch(spans, NULL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_copy_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_cmp_spans
+ PURPOSE
+ Check if two hyperslab slabs are the same
+ USAGE
+ htri_d H5S_hyper_cmp_spans(span1, span2)
+ H5S_hyper_span_t *span1; IN: First span tree to compare
+ H5S_hyper_span_t *span2; IN: Second span tree to compare
+ RETURNS
+ TRUE (1) or FALSE (0) on success, negative on failure
+ DESCRIPTION
+ Compare two hyperslab slabs to determine if they refer to the same
+ selection. If span1 & span2 are both NULL, that counts as equal
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_cmp_spans (H5S_hyper_span_info_t *span_info1, H5S_hyper_span_info_t *span_info2)
+{
+ H5S_hyper_span_t *span1;
+ H5S_hyper_span_t *span2;
+ htri_t nest=FAIL;
+ htri_t ret_value=FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check for redundant comparison */
+ if(span_info1==span_info2)
+ ret_value=TRUE;
+ else {
+ /* Check for both spans being NULL */
+ if(span_info1==NULL && span_info2==NULL)
+ ret_value=TRUE;
+ else {
+ /* Check for one span being NULL */
+ if(span_info1==NULL || span_info2==NULL)
+ ret_value=FALSE;
+ else {
+ /* Get the pointers to the actual lists of spans */
+ span1=span_info1->head;
+ span2=span_info2->head;
+
+ /* Sanity checking */
+ HDassert(span1);
+ HDassert(span2);
+
+ /* infinite loop which must be broken out of */
+ while (1) {
+ /* Check for both spans being NULL */
+ if(span1==NULL && span2==NULL) {
+ ret_value=TRUE;
+ break;
+ } /* end if */
+ else {
+ /* Check for one span being NULL */
+ if(span1==NULL || span2==NULL) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Check if the actual low & high span information is the same */
+ if(span1->low!=span2->low || span1->high!=span2->high) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ if(span1->down!=NULL || span2!=NULL) {
+ if((nest=H5S_hyper_cmp_spans(span1->down,span2->down))==FAIL) {
+ ret_value=FAIL;
+ break;
+ } /* end if */
+ else {
+ if(nest==FALSE) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Keep going... */
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Keep going... */
+ } /* end else */
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+ /* Advance to the next nodes in the span list */
+ span1=span1->next;
+ span2=span2->next;
+ } /* end while */
+ } /* end else */
+ } /* end else */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_cmp_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_free_span_info
+ PURPOSE
+ Free a hyperslab span info node
+ USAGE
+ herr_t H5S_hyper_free_span_info(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span info node to free
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Free a hyperslab span info node, along with all the span nodes and the
+ 'down spans' from the nodes, if reducing their reference count to zero
+ indicates it is appropriate to do so.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_free_span_info (H5S_hyper_span_info_t *span_info)
+{
+ H5S_hyper_span_t *span, *next_span;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(span_info);
+
+ /* Decrement the span tree's reference count */
+ span_info->count--;
+
+ /* Free the span tree if the reference count drops to zero */
+ if(span_info->count==0) {
+
+ /* Work through the list of spans pointed to by this 'info' node */
+ span=span_info->head;
+ while(span!=NULL) {
+ next_span=span->next;
+ if(H5S_hyper_free_span(span)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span")
+ span=next_span;
+ } /* end while */
+
+ /* Free this span info */
+ span_info = H5FL_FREE(H5S_hyper_span_info_t, span_info);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_free_span_info() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_free_span
+ PURPOSE
+ Free a hyperslab span node
+ USAGE
+ herr_t H5S_hyper_free_span(span)
+ H5S_hyper_span_t *span; IN: Span node to free
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Free a hyperslab span node, along with the 'down spans' from the node,
+ if reducing their reference count to zero indicates it is appropriate to
+ do so.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_free_span (H5S_hyper_span_t *span)
+{
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(span);
+
+ /* Decrement the reference count of the 'down spans', freeing them if appropriate */
+ if(span->down!=NULL) {
+ if(H5S_hyper_free_span_info(span->down)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span tree")
+ } /* end if */
+
+ /* Free this span */
+ span = H5FL_FREE(H5S_hyper_span_t, span);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_free_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_copy
+ PURPOSE
+ Copy a selection from one dataspace to another
+ USAGE
+ herr_t H5S_hyper_copy(dst, src)
+ H5S_t *dst; OUT: Pointer to the destination dataspace
+ H5S_t *src; IN: Pointer to the source dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Copies all the hyperslab selection information from the source
+ dataspace to the destination dataspace.
+
+ If the SHARE_SELECTION flag is set, then the selection can be shared
+ between the source and destination dataspaces. (This should only occur in
+ situations where the destination dataspace will immediately change to a new
+ selection)
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_copy (H5S_t *dst, const H5S_t *src, hbool_t share_selection)
+{
+ H5S_hyper_sel_t *dst_hslab; /* Pointer to destination hyperslab info */
+ const H5S_hyper_sel_t *src_hslab; /* Pointer to source hyperslab info */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(src);
+ HDassert(dst);
+
+ /* Allocate space for the hyperslab selection information */
+ if(NULL == (dst->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set temporary pointers */
+ dst_hslab=dst->select.sel_info.hslab;
+ src_hslab=src->select.sel_info.hslab;
+
+ /* Copy the hyperslab information */
+ dst_hslab->diminfo_valid=src_hslab->diminfo_valid;
+ if(src_hslab->diminfo_valid) {
+ size_t u; /* Local index variable */
+
+ for(u=0; u<src->extent.rank; u++) {
+ dst_hslab->opt_diminfo[u]=src_hslab->opt_diminfo[u];
+ dst_hslab->app_diminfo[u]=src_hslab->app_diminfo[u];
+ } /* end for */
+ } /* end if */
+ dst_hslab->unlim_dim = src_hslab->unlim_dim;
+ dst_hslab->num_elem_non_unlim = src_hslab->num_elem_non_unlim;
+ dst->select.sel_info.hslab->span_lst=src->select.sel_info.hslab->span_lst;
+
+ /* Check if there is hyperslab span information to copy */
+ /* (Regular hyperslab information is copied with the selection structure) */
+ if(src->select.sel_info.hslab->span_lst!=NULL) {
+ if(share_selection) {
+ /* Share the source's span tree by incrementing the reference count on it */
+ dst->select.sel_info.hslab->span_lst->count++;
+ } /* end if */
+ else
+ /* Copy the hyperslab span information */
+ dst->select.sel_info.hslab->span_lst = H5S_hyper_copy_span(src->select.sel_info.hslab->span_lst);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_is_valid_helper
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_hyper_is_valid_helper(spans, offset, rank);
+ const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree
+ const hssize_t *offset; IN: Pointer to offset array
+ const hsize_t *size; IN: Pointer to size array
+ hsize_t rank; IN: Current rank looking at
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_is_valid_helper (const H5S_hyper_span_info_t *spans, const hssize_t *offset, const hsize_t *size, hsize_t rank)
+{
+ H5S_hyper_span_t *curr; /* Hyperslab information nodes */
+ htri_t tmp; /* temporary return value */
+ htri_t ret_value=TRUE; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(spans);
+ HDassert(offset);
+ HDassert(size);
+ HDassert(rank < H5O_LAYOUT_NDIMS);
+
+ /* Check each point to determine whether selection+offset is within extent */
+ curr=spans->head;
+ while(curr!=NULL && ret_value==TRUE) {
+ /* Check if an offset has been defined */
+ /* Bounds check the selected point + offset against the extent */
+ if((((hssize_t)curr->low+offset[rank])>=(hssize_t)size[rank])
+ || (((hssize_t)curr->low+offset[rank])<0)
+ || (((hssize_t)curr->high+offset[rank])>=(hssize_t)size[rank])
+ || (((hssize_t)curr->high+offset[rank])<0)) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+
+ /* Recurse if this node has down spans */
+ if(curr->down!=NULL) {
+ if((tmp=H5S_hyper_is_valid_helper(curr->down,offset,size,rank+1))!=TRUE) {
+ ret_value=tmp;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_is_valid_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_is_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_hyper_is_valid(space);
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_is_valid (const H5S_t *space)
+{
+ unsigned u; /* Counter */
+ htri_t ret_value = TRUE; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+
+ /* Check for unlimited selection */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_DONE(FALSE)
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */
+ hssize_t end; /* The high bound of a region in a dimension */
+
+ /* Check each dimension */
+ for(u=0; u<space->extent.rank; u++) {
+ /* if block or count is zero, then can skip the test since */
+ /* no data point is chosen */
+ if (diminfo[u].count && diminfo[u].block) {
+ /* Bounds check the start point in this dimension */
+ if(((hssize_t)diminfo[u].start+space->select.offset[u])<0 ||
+ ((hssize_t)diminfo[u].start+space->select.offset[u])>=(hssize_t)space->extent.size[u])
+ HGOTO_DONE(FALSE)
+
+ /* Compute the largest location in this dimension */
+ end=(hssize_t)(diminfo[u].start+diminfo[u].stride*(diminfo[u].count-1)+(diminfo[u].block-1))+space->select.offset[u];
+
+ /* Bounds check the end point in this dimension */
+ if(end<0 || end>=(hssize_t)space->extent.size[u])
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else {
+ /* Call the recursive routine to validate the span tree */
+ ret_value=H5S_hyper_is_valid_helper(space->select.sel_info.hslab->span_lst,space->select.offset,space->extent.size,(hsize_t)0);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_is_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_nblocks
+ PURPOSE
+ Count the number of blocks in a span tree
+ USAGE
+ hsize_t H5S_hyper_span_nblocks(spans)
+ const H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count elements of
+ RETURNS
+ Number of blocks in span tree on success; negative on failure
+ DESCRIPTION
+ Counts the number of blocks described by the spans in a span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hsize_t
+H5S_hyper_span_nblocks(H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Count the number of elements in the span tree */
+ if(spans != NULL) {
+ span = spans->head;
+ while(span != NULL) {
+ /* If there are down spans, add the total down span blocks */
+ if(span->down!=NULL)
+ ret_value += H5S_hyper_span_nblocks(span->down);
+ /* If there are no down spans, just count the block in this span */
+ else
+ ret_value++;
+
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_span_nblocks() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_hyper_nblocks
+ PURPOSE
+ Get the number of hyperslab blocks in current hyperslab selection
+ USAGE
+ hsize_t H5S_get_select_hyper_nblocks(space)
+ H5S_t *space; IN: Dataspace ptr of selection to query
+ RETURNS
+ The number of hyperslab blocks in selection on success, negative on failure
+ DESCRIPTION
+ Returns the number of hyperslab blocks in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hsize_t
+H5S_get_select_hyper_nblocks(H5S_t *space)
+{
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(space->select.sel_info.hslab->unlim_dim < 0);
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ unsigned u; /* Local index variable */
+
+ /* Check each dimension */
+ for(ret_value = 1, u = 0; u < space->extent.rank; u++)
+ ret_value *= space->select.sel_info.hslab->app_diminfo[u].count;
+ } /* end if */
+ else
+ ret_value = H5S_hyper_span_nblocks(space->select.sel_info.hslab->span_lst);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_hyper_nblocks() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_hyper_nblocks
+ PURPOSE
+ Get the number of hyperslab blocks in current hyperslab selection
+ USAGE
+ hssize_t H5Sget_select_hyper_nblocks(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ RETURNS
+ The number of hyperslab blocks in selection on success, negative on failure
+ DESCRIPTION
+ Returns the number of hyperslab blocks in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hssize_t
+H5Sget_select_hyper_nblocks(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ hssize_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Hs", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection")
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get number of blocks for unlimited selection")
+
+ ret_value = (hssize_t)H5S_get_select_hyper_nblocks(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_hyper_nblocks() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_serial_size
+ PURPOSE
+ Determine the number of bytes needed to store the serialized hyperslab
+ selection information.
+ USAGE
+ hssize_t H5S_hyper_serial_size(space)
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ The number of bytes required on success, negative on an error.
+ DESCRIPTION
+ Determines the number of bytes required to serialize the current hyperslab
+ selection information for storage on disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hssize_t
+H5S_hyper_serial_size(const H5S_t *space)
+{
+ hsize_t block_count; /* block counter for regular hyperslabs */
+ unsigned u; /* Counter */
+ hssize_t ret_value = -1; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Check for version (right now, an unlimited dimension is the only thing
+ * that would bump the version) */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ /* Version 2 */
+ /* Size required is always:
+ * <type (4 bytes)> + <version (4 bytes)> + <flags (1 byte)> +
+ * <length (4 bytes)> + <rank (4 bytes)> +
+ * (4 (start/stride/count/block) * <rank> * <value (8 bytes)>) =
+ * 17 + (4 * rank * 8) bytes
+ */
+ ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)space->extent.rank
+ * (hssize_t)8);
+ else {
+ /* Version 1 */
+ /* Basic number of bytes required to serialize hyperslab selection:
+ * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> +
+ * <length (4 bytes)> + <rank (4 bytes)> + <# of blocks (4 bytes)>
+ * = 24 bytes
+ */
+ ret_value = 24;
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ /* Check each dimension */
+ for(block_count = 1, u = 0; u < space->extent.rank; u++)
+ block_count *= space->select.sel_info.hslab->opt_diminfo[u].count;
+ } /* end if */
+ else
+ /* Spin through hyperslab spans, adding 8 * rank bytes for each
+ * block */
+ block_count = H5S_hyper_span_nblocks(space->select.sel_info.hslab->span_lst);
+
+ H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t);
+ ret_value += (hssize_t)(8 * block_count * space->extent.rank);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_serialize_helper
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ void H5S_hyper_serialize_helper(spans, start, end, rank, buf)
+ H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to serialize
+ hssize_t start[]; IN/OUT: Accumulated start points
+ hssize_t end[]; IN/OUT: Accumulated end points
+ hsize_t rank; IN: Current rank looking at
+ uint8 *buf; OUT: Buffer to put serialized selection into
+ RETURNS
+ <none>
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static void
+H5S_hyper_serialize_helper(const H5S_hyper_span_info_t *spans,
+ hsize_t *start, hsize_t *end, hsize_t rank, uint8_t **p)
+{
+ H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ uint8_t *pp = (*p); /* Local pointer for decoding */
+ hsize_t u; /* Index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity checks */
+ HDassert(spans);
+ HDassert(start);
+ HDassert(end);
+ HDassert(rank < H5O_LAYOUT_NDIMS);
+ HDassert(p && pp);
+
+ /* Walk through the list of spans, recursing or outputing them */
+ curr=spans->head;
+ while(curr!=NULL) {
+ /* Recurse if this node has down spans */
+ if(curr->down!=NULL) {
+ /* Add the starting and ending points for this span to the list */
+ start[rank]=curr->low;
+ end[rank]=curr->high;
+
+ /* Recurse down to the next dimension */
+ H5S_hyper_serialize_helper(curr->down, start, end, rank + 1, &pp);
+ } /* end if */
+ else {
+ /* Encode all the previous dimensions starting & ending points */
+
+ /* Encode previous starting points */
+ for(u=0; u<rank; u++)
+ UINT32ENCODE(pp, (uint32_t)start[u]);
+
+ /* Encode starting point for this span */
+ UINT32ENCODE(pp, (uint32_t)curr->low);
+
+ /* Encode previous ending points */
+ for(u=0; u<rank; u++)
+ UINT32ENCODE(pp, (uint32_t)end[u]);
+
+ /* Encode starting point for this span */
+ UINT32ENCODE(pp, (uint32_t)curr->high);
+ } /* end else */
+
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
+
+ /* Update encoding pointer */
+ *p = pp;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* H5S_hyper_serialize_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_serialize
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ herr_t H5S_hyper_serialize(space, p)
+ const H5S_t *space; IN: Dataspace with selection to serialize
+ uint8_t **p; OUT: Pointer to buffer to put serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_serialize(const H5S_t *space, uint8_t **p)
+{
+ const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
+ uint8_t *pp = (*p); /* Local pointer for decoding */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */
+ hsize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */
+ hsize_t start[H5O_LAYOUT_NDIMS]; /* Location of start of hyperslab */
+ hsize_t end[H5O_LAYOUT_NDIMS]; /* Location of end of hyperslab */
+ hsize_t temp_off; /* Offset in a given dimension */
+ uint8_t *lenp; /* pointer to length location for later storage */
+ uint32_t len = 0; /* number of bytes used */
+ uint32_t version; /* Version number */
+ uint8_t flags = 0; /* Flags for message */
+ hsize_t block_count; /* block counter for regular hyperslabs */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned ndims; /* Rank of the dataspace */
+ int done; /* Whether we are done with the iteration */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Calculate version */
+ if(space->select.sel_info.hslab->unlim_dim >= 0) {
+ version = 2;
+ flags |= H5S_SELECT_FLAG_UNLIM;
+ } /* end if */
+ else
+ version = 1;
+
+ /* Store the preamble information */
+ UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
+ UINT32ENCODE(pp, version); /* Store the version number */
+ if(version >= 2)
+ *(pp)++ = flags; /* Store the flags */
+ else
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
+ lenp = pp; /* keep the pointer to the length location for later */
+ pp += 4; /* skip over space for length */
+
+ /* Encode number of dimensions */
+ UINT32ENCODE(pp, (uint32_t)space->extent.rank);
+ len += 4;
+
+ /* If there is an unlimited dimension, only encode opt_unlim_diminfo */
+ if(flags & H5S_SELECT_FLAG_UNLIM) {
+ unsigned i;
+
+ HDassert(H5S_UNLIMITED == HSIZE_UNDEF);
+
+ /* Iterate over dimensions */
+ for(i = 0; i < space->extent.rank; i++) {
+ /* Encode start/stride/block/count */
+ UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].start);
+ UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].stride);
+ UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].count);
+ UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].block);
+ } /* end for */
+ } /* end if */
+ /* Check for a "regular" hyperslab selection */
+ else if(space->select.sel_info.hslab->diminfo_valid) {
+ unsigned u; /* Local counting variable */
+
+ /* Set some convienence values */
+ ndims = space->extent.rank;
+ fast_dim = ndims - 1;
+ diminfo=space->select.sel_info.hslab->opt_diminfo;
+
+ /* Check each dimension */
+ for(block_count = 1, u = 0; u < ndims; u++)
+ block_count *= diminfo[u].count;
+
+ /* Encode number of hyperslabs */
+ H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
+ UINT32ENCODE(pp, (uint32_t)block_count);
+ len+=4;
+
+ /* Now serialize the information for the regular hyperslab */
+
+ /* Build the tables of count sizes as well as the initial offset */
+ for(u = 0; u < ndims; u++) {
+ tmp_count[u] = diminfo[u].count;
+ offset[u] = diminfo[u].start;
+ } /* end for */
+
+ /* We're not done with the iteration */
+ done=0;
+
+ /* Go iterate over the hyperslabs */
+ while(done==0) {
+ /* Iterate over the blocks in the fastest dimension */
+ while(tmp_count[fast_dim]>0) {
+ /* Add 8 bytes times the rank for each hyperslab selected */
+ len+=8*ndims;
+
+ /* Encode hyperslab starting location */
+ for(u = 0; u < ndims; u++)
+ UINT32ENCODE(pp, (uint32_t)offset[u]);
+
+ /* Encode hyperslab ending location */
+ for(u = 0; u < ndims; u++)
+ UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1)));
+
+ /* Move the offset to the next sequence to start */
+ offset[fast_dim]+=diminfo[fast_dim].stride;
+
+ /* Decrement the block count */
+ tmp_count[fast_dim]--;
+ } /* end while */
+
+ /* Work on other dimensions if necessary */
+ if(fast_dim > 0) {
+ int temp_dim; /* Temporary rank holder */
+
+ /* Reset the block counts */
+ tmp_count[fast_dim]=diminfo[fast_dim].count;
+
+ /* Bubble up the decrement to the slower changing dimensions */
+ temp_dim = (int)fast_dim - 1;
+ while(temp_dim >= 0 && done == 0) {
+ /* Decrement the block count */
+ tmp_count[temp_dim]--;
+
+ /* Check if we have more blocks left */
+ if(tmp_count[temp_dim] > 0)
+ break;
+
+ /* Check for getting out of iterator */
+ if(temp_dim == 0)
+ done = 1;
+
+ /* Reset the block count in this dimension */
+ tmp_count[temp_dim] = diminfo[temp_dim].count;
+
+ /* Wrapped a dimension, go up to next dimension */
+ temp_dim--;
+ } /* end while */
+ } /* end if */
+ else
+ break; /* Break out now, for 1-D selections */
+
+ /* Re-compute offset array */
+ for(u = 0; u < ndims; u++) {
+ temp_off = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
+ offset[u] = temp_off;
+ } /* end for */
+ } /* end while */
+ } /* end if */
+ else {
+ /* Encode number of hyperslabs */
+ block_count = H5S_hyper_span_nblocks(space->select.sel_info.hslab->span_lst);
+ H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
+ UINT32ENCODE(pp, (uint32_t)block_count);
+ len+=4;
+
+ /* Add 8 bytes times the rank for each hyperslab selected */
+ H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, size_t);
+ len += (uint32_t)(8 * space->extent.rank * block_count);
+
+ /* Encode each hyperslab in selection */
+ H5S_hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp);
+ } /* end else */
+
+ /* Encode length */
+ UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */
+
+ /* Update encoding pointer */
+ *p = pp;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_serialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_deserialize
+ PURPOSE
+ Deserialize the current selection from a user-provided buffer.
+ USAGE
+ herr_t H5S_hyper_deserialize(space, p)
+ H5S_t *space; IN/OUT: Dataspace pointer to place
+ selection into
+ uint32_t version IN: Selection version
+ uint8_t flags IN: Selection flags
+ uint8 **p; OUT: Pointer to buffer holding serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Deserializes the current selection into a buffer. (Primarily for retrieving
+ from disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t flags,
+ const uint8_t **p)
+{
+ unsigned rank; /* rank of points */
+ const uint8_t *pp = (*p); /* Local pointer for decoding */
+ size_t num_elem=0; /* number of elements in selection */
+ hsize_t start[H5O_LAYOUT_NDIMS]; /* hyperslab start information */
+ hsize_t end[H5O_LAYOUT_NDIMS]; /* hyperslab end information */
+ hsize_t stride[H5O_LAYOUT_NDIMS]; /* hyperslab stride information */
+ hsize_t count[H5O_LAYOUT_NDIMS]; /* hyperslab count information */
+ hsize_t block[H5O_LAYOUT_NDIMS]; /* hyperslab block information */
+ hsize_t *tstart=NULL; /* temporary hyperslab pointers */
+ hsize_t *tend=NULL; /* temporary hyperslab pointers */
+ hsize_t *tstride=NULL; /* temporary hyperslab pointers */
+ hsize_t *tcount=NULL; /* temporary hyperslab pointers */
+ hsize_t *tblock=NULL; /* temporary hyperslab pointers */
+ unsigned i,j; /* local counting variables */
+ herr_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Deserialize slabs to select */
+ /* (The header and rank have already beed decoded) */
+ rank = space->extent.rank; /* Retrieve rank from space */
+
+ /* If there is an unlimited dimension, only encode opt_unlim_diminfo */
+ if(flags & H5S_SELECT_FLAG_UNLIM) {
+ HDassert(H5S_UNLIMITED == HSIZE_UNDEF);
+ HDassert(version >= 2);
+
+ /* Iterate over dimensions */
+ for(i = 0; i < space->extent.rank; i++) {
+ /* Decode start/stride/block/count */
+ UINT64DECODE(pp, start[i]);
+ UINT64DECODE(pp, stride[i]);
+ UINT64DECODE(pp, count[i]);
+ UINT64DECODE(pp, block[i]);
+ } /* end for */
+
+ /* Select the hyperslab to the current selection */
+ if((ret_value = H5S_select_hyperslab(space, H5S_SELECT_SET, start, stride, count, block)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+ } /* end if */
+ else {
+ /* decode the number of points */
+ UINT32DECODE(pp,num_elem);
+
+ /* Set the count & stride for all blocks */
+ for(tcount = count, tstride = stride, j = 0; j < rank; j++, tstride++, tcount++) {
+ *tcount=1;
+ *tstride=1;
+ } /* end for */
+
+ /* Retrieve the coordinates from the buffer */
+ for(i = 0; i < num_elem; i++) {
+ /* Decode the starting points */
+ for(tstart=start,j=0; j<rank; j++,tstart++)
+ UINT32DECODE(pp, *tstart);
+
+ /* Decode the ending points */
+ for(tend = end, j = 0; j < rank; j++, tend++)
+ UINT32DECODE(pp, *tend);
+
+ /* Change the ending points into blocks */
+ for(tblock=block,tstart=start,tend=end,j=0; j<rank; j++,tstart++,tend++,tblock++)
+ *tblock=(*tend-*tstart)+1;
+
+ /* Select or add the hyperslab to the current selection */
+ if((ret_value=H5S_select_hyperslab(space,(i==0 ? H5S_SELECT_SET : H5S_SELECT_OR),start,stride,count,block))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+ } /* end for */
+ } /* end else */
+
+ /* Update decoding pointer */
+ *p = pp;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_blocklist
+ PURPOSE
+ Get a list of hyperslab blocks currently selected
+ USAGE
+ herr_t H5S_hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf)
+ H5S_hyper_span_info_t *spans; IN: Dataspace pointer of selection to query
+ hsize_t start[]; IN/OUT: Accumulated start points
+ hsize_t end[]; IN/OUT: Accumulated end points
+ hsize_t rank; IN: Rank of dataspace
+ hsize_t *startblock; IN/OUT: Hyperslab block to start with
+ hsize_t *numblocks; IN/OUT: Number of hyperslab blocks to get
+ hsize_t **buf; OUT: List of hyperslab blocks selected
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Puts a list of the hyperslab blocks into the user's buffer. The blocks
+ start with the '*startblock'th block in the list of blocks and put
+ '*numblocks' number of blocks into the user's buffer (or until the end of
+ the list of blocks, whichever happens first)
+ The block coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of blocks is formatted as
+ follows: <"start" coordinate> immediately followed by <"opposite" corner
+ coordinate>, followed by the next "start" and "opposite" coordinate, etc.
+ until all the block information requested has been put into the user's
+ buffer.
+ No guarantee of any order of the blocks is implied.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_span_blocklist(H5S_hyper_span_info_t *spans, hsize_t start[], hsize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks, hsize_t **buf)
+{
+ H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ hsize_t u; /* Index variable */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(spans);
+ HDassert(rank < H5O_LAYOUT_NDIMS);
+ HDassert(start);
+ HDassert(end);
+ HDassert(startblock);
+ HDassert(numblocks && *numblocks > 0);
+ HDassert(buf && *buf);
+
+ /* Walk through the list of spans, recursing or outputing them */
+ curr = spans->head;
+ while(curr != NULL && *numblocks > 0) {
+ /* Recurse if this node has down spans */
+ if(curr->down != NULL) {
+ /* Add the starting and ending points for this span to the list */
+ start[rank] = curr->low;
+ end[rank] = curr->high;
+
+ /* Recurse down to the next dimension */
+ if(H5S_hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ } /* end if */
+ else {
+ /* Skip this block if we haven't skipped all the startblocks yet */
+ if(*startblock > 0) {
+ /* Decrement the starting block */
+ (*startblock)--;
+ } /* end if */
+ /* Process this block */
+ else {
+ /* Encode all the previous dimensions starting & ending points */
+
+ /* Copy previous starting points */
+ for(u = 0; u < rank; u++, (*buf)++)
+ HDmemcpy(*buf, &start[u], sizeof(hsize_t));
+
+ /* Copy starting point for this span */
+ HDmemcpy(*buf, &curr->low, sizeof(hsize_t));
+ (*buf)++;
+
+ /* Copy previous ending points */
+ for(u = 0; u < rank; u++, (*buf)++)
+ HDmemcpy(*buf, &end[u], sizeof(hsize_t));
+
+ /* Copy starting point for this span */
+ HDmemcpy(*buf, &curr->high, sizeof(hsize_t));
+ (*buf)++;
+
+ /* Decrement the number of blocks processed */
+ (*numblocks)--;
+ } /* end else */
+ } /* end else */
+
+ /* Advance to next node */
+ curr = curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_span_blocklist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_hyper_blocklist
+ PURPOSE
+ Get the list of hyperslab blocks currently selected
+ USAGE
+ herr_t H5S_get_select_hyper_blocklist(space, startblock, numblocks, buf)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t startblock; IN: Hyperslab block to start with
+ hsize_t numblocks; IN: Number of hyperslab blocks to get
+ hsize_t *buf; OUT: List of hyperslab blocks selected
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Puts a list of the hyperslab blocks into the user's buffer. The blocks
+ start with the 'startblock'th block in the list of blocks and put
+ 'numblocks' number of blocks into the user's buffer (or until the end of
+ the list of blocks, whichever happens first)
+ The block coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of blocks is formatted as
+ follows: <"start" coordinate> immediately followed by <"opposite" corner
+ coordinate>, followed by the next "start" and "opposite" coordinate, etc.
+ until all the block information requested has been put into the user's
+ buffer.
+ No guarantee of any order of the blocks is implied.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblock, hsize_t numblocks, hsize_t *buf)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(buf);
+ HDassert(space->select.sel_info.hslab->unlim_dim < 0);
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */
+ hsize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned ndims; /* Rank of the dataspace */
+ hbool_t done; /* Whether we are done with the iteration */
+ unsigned u; /* Counter */
+
+ /* Set some convienence values */
+ ndims = space->extent.rank;
+ fast_dim = ndims - 1;
+
+ /* Check which set of dimension information to use */
+ if(internal)
+ /*
+ * Use the "optimized dimension information" to pass back information
+ * on the blocks set, not the "application information".
+ */
+ diminfo = space->select.sel_info.hslab->opt_diminfo;
+ else
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ /*
+ * There is an unlimited dimension so we must use opt_diminfo as
+ * it has been "clipped" to the current extent.
+ */
+ diminfo = space->select.sel_info.hslab->opt_diminfo;
+ else
+ /*
+ * Use the "application dimension information" to pass back to
+ * the user the blocks they set, not the optimized, internal
+ * information.
+ */
+ diminfo = space->select.sel_info.hslab->app_diminfo;
+
+ /* Build the tables of count sizes as well as the initial offset */
+ for(u = 0; u < ndims; u++) {
+ tmp_count[u] = diminfo[u].count;
+ offset[u] = diminfo[u].start;
+ } /* end for */
+
+ /* We're not done with the iteration */
+ done = FALSE;
+
+ /* Go iterate over the hyperslabs */
+ while(!done && numblocks > 0) {
+ hsize_t temp_off; /* Offset in a given dimension */
+
+ /* Iterate over the blocks in the fastest dimension */
+ while(tmp_count[fast_dim] > 0 && numblocks > 0) {
+
+ /* Check if we should copy this block information */
+ if(startblock == 0) {
+ /* Copy the starting location */
+ HDmemcpy(buf, offset, sizeof(hsize_t) * ndims);
+ buf += ndims;
+
+ /* Compute the ending location */
+ HDmemcpy(buf, offset, sizeof(hsize_t) * ndims);
+ for(u = 0; u < ndims; u++)
+ buf[u] += (diminfo[u].block - 1);
+ buf += ndims;
+
+ /* Decrement the number of blocks to retrieve */
+ numblocks--;
+ } /* end if */
+ else
+ startblock--;
+
+ /* Move the offset to the next sequence to start */
+ offset[fast_dim] += diminfo[fast_dim].stride;
+
+ /* Decrement the block count */
+ tmp_count[fast_dim]--;
+ } /* end while */
+
+ /* Work on other dimensions if necessary */
+ if(fast_dim > 0 && numblocks > 0) {
+ int temp_dim; /* Temporary rank holder */
+
+ /* Reset the block counts */
+ tmp_count[fast_dim] = diminfo[fast_dim].count;
+
+ /* Bubble up the decrement to the slower changing dimensions */
+ temp_dim = (int)(fast_dim - 1);
+ while(temp_dim >= 0 && !done) {
+ /* Decrement the block count */
+ tmp_count[temp_dim]--;
+
+ /* Check if we have more blocks left */
+ if(tmp_count[temp_dim] > 0)
+ break;
+
+ /* Check for getting out of iterator */
+ if(temp_dim == 0)
+ done = TRUE;
+
+ /* Reset the block count in this dimension */
+ tmp_count[temp_dim] = diminfo[temp_dim].count;
+
+ /* Wrapped a dimension, go up to next dimension */
+ temp_dim--;
+ } /* end while */
+ } /* end if */
+
+ /* Re-compute offset array */
+ for(u = 0; u < ndims; u++) {
+ temp_off = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
+ offset[u] = temp_off;
+ } /* end for */
+ } /* end while */
+ } /* end if */
+ else {
+ hsize_t start[H5O_LAYOUT_NDIMS]; /* Location of start of hyperslab */
+ hsize_t end[H5O_LAYOUT_NDIMS]; /* Location of end of hyperslab */
+
+ ret_value = H5S_hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &startblock, &numblocks, &buf);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_hyper_blocklist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_hyper_blocklist
+ PURPOSE
+ Get the list of hyperslab blocks currently selected
+ USAGE
+ herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ hsize_t startblock; IN: Hyperslab block to start with
+ hsize_t numblocks; IN: Number of hyperslab blocks to get
+ hsize_t buf[]; OUT: List of hyperslab blocks selected
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Puts a list of the hyperslab blocks into the user's buffer. The blocks
+ start with the 'startblock'th block in the list of blocks and put
+ 'numblocks' number of blocks into the user's buffer (or until the end of
+ the list of blocks, whichever happen first)
+ The block coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of blocks is formatted as
+ follows: <"start" coordinate> immediately followed by <"opposite" corner
+ coordinate>, followed by the next "start" and "opposite" coordinate, etc.
+ until all the block information requested has been put into the user's
+ buffer.
+ No guarantee of any order of the blocks is implied.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock,
+ hsize_t numblocks, hsize_t buf[/*numblocks*/])
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf);
+
+ /* Check args */
+ if(buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(H5S_GET_SELECT_TYPE(space)!=H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection")
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get blocklist for unlimited selection")
+
+ /* Go get the correct number of blocks */
+ if(numblocks > 0)
+ ret_value = H5S_get_select_hyper_blocklist(space, 0, startblock, numblocks, buf);
+ else
+ ret_value=SUCCEED; /* Successfully got 0 blocks... */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_hyper_blocklist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_bounds_helper
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ htri_t H5S_hyper_bounds_helper(spans, offset, rank);
+ const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree
+ const hssize_t *offset; IN: Pointer to offset array
+ hsize_t rank; IN: Current rank looking at
+ hsize_t *start; OUT: Start array bounds
+ hsize_t *end; OUT: End array bounds
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8).
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_bounds_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, hsize_t rank, hsize_t *start, hsize_t *end)
+{
+ H5S_hyper_span_t *curr; /* Hyperslab information nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(spans);
+ HDassert(offset);
+ HDassert(rank < H5O_LAYOUT_NDIMS);
+ HDassert(start);
+ HDassert(end);
+
+ /* Check each point to determine whether selection+offset is within extent */
+ curr=spans->head;
+ while(curr!=NULL) {
+ /* Check for offset moving selection negative */
+ if(((hssize_t)curr->low + offset[rank]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ /* Check if the current span extends the bounding box */
+ if((curr->low + (hsize_t)offset[rank]) < start[rank])
+ start[rank] = curr->low + (hsize_t)offset[rank];
+ if((curr->high + (hsize_t)offset[rank]) > end[rank])
+ end[rank] = curr->high + (hsize_t)offset[rank];
+
+ /* Recurse if this node has down spans */
+ if(curr->down != NULL) {
+ if(H5S_hyper_bounds_helper(curr->down, offset, (rank + 1), start, end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "failure in lower dimension")
+ } /* end if */
+
+ /* Advance to next node */
+ curr = curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_bounds_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_hyper_bounds(space, hsize_t *start, hsize_t *end)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *start; OUT: Starting coordinate of bounding box
+ hsize_t *end; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8).
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
+{
+ unsigned rank; /* Dataspace rank */
+ unsigned i; /* index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ /* Set the start and end arrays up */
+ rank = space->extent.rank;
+ for(i = 0; i < rank; i++) {
+ start[i] = HSIZET_MAX;
+ end[i] = 0;
+ } /* end for */
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */
+
+ /* Check each dimension */
+ for(i = 0; i < rank; i++) {
+ /* Check for offset moving selection negative */
+ if((space->select.offset[i] + (hssize_t)diminfo[i].start) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ /* Compute the smallest location in this dimension */
+ start[i] = diminfo[i].start + (hsize_t)space->select.offset[i];
+
+ /* Compute the largest location in this dimension */
+ if((int)i == space->select.sel_info.hslab->unlim_dim)
+ end[i] = H5S_UNLIMITED;
+ else
+ end[i] = diminfo[i].start + diminfo[i].stride * (diminfo[i].count - 1) + (diminfo[i].block - 1) + (hsize_t)space->select.offset[i];
+ } /* end for */
+ } /* end if */
+ else {
+ /* Call the recursive routine to get the bounds for the span tree */
+ ret_value = H5S_hyper_bounds_helper(space->select.sel_info.hslab->span_lst, space->select.offset, (hsize_t)0, start, end);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_offset
+ PURPOSE
+ Gets the linear offset of the first element for the selection.
+ USAGE
+ herr_t H5S_hyper_offset(space, offset)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *offset; OUT: Linear offset of first element in selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the linear offset (in "units" of elements) of the first element
+ selected within the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Calling this function on a "none" selection returns fail.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_offset(const H5S_t *space, hsize_t *offset)
+{
+ const hssize_t *sel_offset; /* Pointer to the selection's offset */
+ const hsize_t *dim_size; /* Pointer to a dataspace's extent */
+ hsize_t accum; /* Accumulator for dimension sizes */
+ unsigned rank; /* Dataspace rank */
+ int i; /* index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space && space->extent.rank>0);
+ HDassert(offset);
+
+ /* Start at linear offset 0 */
+ *offset = 0;
+
+ /* Set up pointers to arrays of values */
+ rank = space->extent.rank;
+ sel_offset = space->select.offset;
+ dim_size = space->extent.size;
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Local alias for diminfo */
+
+ /* Loop through starting coordinates, calculating the linear offset */
+ accum = 1;
+ for(i = (int)(rank - 1); i >= 0; i--) {
+ hssize_t hyp_offset = (hssize_t)diminfo[i].start + sel_offset[i]; /* Hyperslab's offset in this dimension */
+
+ /* Check for offset moving selection out of the dataspace */
+ if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ /* Add the hyperslab's offset in this dimension to the total linear offset */
+ *offset += (hsize_t)(hyp_offset * (hssize_t)accum);
+
+ /* Increase the accumulator */
+ accum *= dim_size[i];
+ } /* end for */
+ } /* end if */
+ else {
+ const H5S_hyper_span_t *span; /* Hyperslab span node */
+ hsize_t dim_accum[H5S_MAX_RANK]; /* Accumulators, for each dimension */
+
+ /* Calculate the accumulator for each dimension */
+ accum = 1;
+ for(i = (int)(rank - 1); i >= 0; i--) {
+ /* Set the accumulator for this dimension */
+ dim_accum[i] = accum;
+
+ /* Increase the accumulator */
+ accum *= dim_size[i];
+ } /* end for */
+
+ /* Get information for the first span, in the slowest changing dimension */
+ span = space->select.sel_info.hslab->span_lst->head;
+
+ /* Work down the spans, computing the linear offset */
+ i = 0;
+ while(span) {
+ hssize_t hyp_offset = (hssize_t)span->low + sel_offset[i]; /* Hyperslab's offset in this dimension */
+
+ /* Check for offset moving selection out of the dataspace */
+ if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ /* Add the hyperslab's offset in this dimension to the total linear offset */
+ *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]);
+
+ /* Advance to first span in "down" dimension */
+ if(span->down) {
+ HDassert(span->down->head);
+ span = span->down->head;
+ } /* end if */
+ else
+ span = NULL;
+ i++;
+ } /* end while */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_unlim_dim
+ PURPOSE
+ Return unlimited dimension of selection, or -1 if none
+ USAGE
+ int H5S__hyper_unlim_dim(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ Unlimited dimension of selection, or -1 if none (never fails).
+ DESCRIPTION
+ Returns the index of the unlimited dimension of the selection, or -1
+ if the selection has no unlimited dimension.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5S__hyper_unlim_dim(const H5S_t *space)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim);
+} /* end H5S__hyper_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_num_elem_non_unlim
+ PURPOSE
+ Return number of elements in the non-unlimited dimensions
+ USAGE
+ herr_t H5S_hyper_num_elem_non_unlim(space,num_elem_non_unlim)
+ H5S_t *space; IN: Dataspace pointer to check
+ hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Returns the number of elements in a slice through the non-unlimited
+ dimensions of the selection. Fails if the selection has no unlimited
+ dimension.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(space);
+ HDassert(num_elem_non_unlim);
+
+ /* Get number of elements in the non-unlimited dimensions */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ *num_elem_non_unlim = space->select.sel_info.hslab->num_elem_non_unlim;
+ else
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "selection has no unlimited dimension")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_num_elem_non_unlim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_is_contiguous
+ PURPOSE
+ Check if a hyperslab selection is contiguous within the dataspace extent.
+ USAGE
+ htri_t H5S_hyper_is_contiguous(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is contiguous.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_is_contiguous(const H5S_t *space)
+{
+ unsigned small_contiguous, /* Flag for small contiguous block */
+ large_contiguous; /* Flag for large contiguous block */
+ unsigned u; /* index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */
+
+ /*
+ * For a regular hyperslab to be contiguous, it must have only one
+ * block (i.e. count==1 in all dimensions) and the block size must be
+ * the same as the dataspace extent's in all but the slowest changing
+ * dimension. (dubbed "large contiguous" block)
+ *
+ * OR
+ *
+ * The selection must have only one block (i.e. count==1) in all
+ * dimensions and the block size must be 1 in all but the fastest
+ * changing dimension. (dubbed "small contiguous" block)
+ */
+
+ /* Initialize flags */
+ large_contiguous=TRUE; /* assume true and reset if the dimensions don't match */
+ small_contiguous=FALSE; /* assume false initially */
+
+ /* Check for a "large contigous" block */
+ for(u=0; u<space->extent.rank; u++) {
+ if(diminfo[u].count>1) {
+ large_contiguous=FALSE;
+ break;
+ } /* end if */
+ if(u>0 && diminfo[u].block!=space->extent.size[u]) {
+ large_contiguous=FALSE;
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* If we didn't find a large contiguous block, check for a small one */
+ if(large_contiguous==FALSE) {
+ small_contiguous=TRUE;
+ for(u=0; u<space->extent.rank; u++) {
+ if(diminfo[u].count>1) {
+ small_contiguous=FALSE;
+ break;
+ } /* end if */
+ if(u<(space->extent.rank-1) && diminfo[u].block!=1) {
+ small_contiguous=FALSE;
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+
+ /* Indicate true if it's either a large or small contiguous block */
+ if(large_contiguous || small_contiguous)
+ ret_value=TRUE;
+ } /* end if */
+ else {
+ H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
+ H5S_hyper_span_t *span; /* Hyperslab span node */
+
+ /*
+ * For a hyperslab to be contiguous, it must have only one block and
+ * (either it's size must be the same as the dataspace extent's in all
+ * but the slowest changing dimension
+ * OR
+ * block size must be 1 in all but the fastest changing dimension).
+ */
+ /* Initialize flags */
+ large_contiguous=TRUE; /* assume true and reset if the dimensions don't match */
+ small_contiguous=FALSE; /* assume false initially */
+
+ /* Get information for slowest changing information */
+ spans=space->select.sel_info.hslab->span_lst;
+ span=spans->head;
+
+ /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */
+ if(span->next!=NULL)
+ large_contiguous=FALSE;
+ else {
+ /* Now check the rest of the dimensions */
+ if(span->down!=NULL) {
+ u=1; /* Current dimension working on */
+
+ /* Get the span information for the next fastest dimension */
+ spans=span->down;
+
+ /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
+ while(spans!=NULL) {
+ span=spans->head;
+
+ /* Check that this is the only span and it spans the entire dimension */
+ if(span->next!=NULL) {
+ large_contiguous=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */
+ if(((span->high-span->low)+1)!=space->extent.size[u]) {
+ large_contiguous=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Walk down to the next span */
+ spans=span->down;
+
+ /* Increment dimension */
+ u++;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+ } /* end if */
+ } /* end else */
+
+ /* If we didn't find a large contiguous block, check for a small one */
+ if(large_contiguous==FALSE) {
+ small_contiguous=TRUE;
+
+ /* Get information for slowest changing information */
+ spans=space->select.sel_info.hslab->span_lst;
+ span=spans->head;
+
+ /* Current dimension working on */
+ u=0;
+
+ /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
+ while(spans!=NULL) {
+ span=spans->head;
+
+ /* Check that this is the only span and it spans the entire dimension */
+ if(span->next!=NULL) {
+ small_contiguous=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */
+ if(u<(space->extent.rank-1) && ((span->high-span->low)+1)!=1) {
+ small_contiguous=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Walk down to the next span */
+ spans=span->down;
+
+ /* Increment dimension */
+ u++;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+ } /* end if */
+
+ /* Indicate true if it's either a large or small contiguous block */
+ if(large_contiguous || small_contiguous)
+ ret_value=TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_is_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_is_single
+ PURPOSE
+ Check if a hyperslab selection is a single block within the dataspace extent.
+ USAGE
+ htri_t H5S_hyper_is_single(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is a single block.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_is_single(const H5S_t *space)
+{
+ H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
+ H5S_hyper_span_t *span; /* Hyperslab span node */
+ unsigned u; /* index variable */
+ htri_t ret_value=TRUE; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+
+ /* Check for a "single" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ /*
+ * For a regular hyperslab to be single, it must have only one
+ * block (i.e. count==1 in all dimensions)
+ */
+
+ /* Check for a single block */
+ for(u=0; u<space->extent.rank; u++) {
+ if(space->select.sel_info.hslab->opt_diminfo[u].count>1)
+ HGOTO_DONE(FALSE)
+ } /* end for */
+ } /* end if */
+ else {
+ /*
+ * For a region to be single, it must have only one block
+ */
+ /* Get information for slowest changing information */
+ spans=space->select.sel_info.hslab->span_lst;
+
+ /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
+ while(spans!=NULL) {
+ span=spans->head;
+
+ /* Check that this is the only span and it spans the entire dimension */
+ if(span->next!=NULL)
+ HGOTO_DONE(FALSE)
+ else
+ /* Walk down to the next span */
+ spans=span->down;
+ } /* end while */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_is_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_is_regular
+ PURPOSE
+ Check if a hyperslab selection is "regular"
+ USAGE
+ htri_t H5S_hyper_is_regular(space)
+ const H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in a dataspace is the a regular
+ pattern.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Doesn't check for "regular" hyperslab selections composed of spans
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_is_regular(const H5S_t *space)
+{
+ htri_t ret_value = FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ /* Only simple check for regular hyperslabs for now... */
+ if(space->select.sel_info.hslab->diminfo_valid)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_is_regular() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_release
+ PURPOSE
+ Release hyperslab selection information for a dataspace
+ USAGE
+ herr_t H5S_hyper_release(space)
+ H5S_t *space; IN: Pointer to dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all hyperslab selection information for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+ * Robb Matzke, 1998-08-25
+ * The fields which are freed are set to NULL to prevent them from being
+ * freed again later. This fixes some allocation problems where
+ * changing the hyperslab selection of one data space causes a core dump
+ * when closing some other data space.
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_release(H5S_t *space)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
+
+ /* Reset the number of points selected */
+ space->select.num_elem = 0;
+
+ /* Release irregular hyperslab information */
+ if(space->select.sel_info.hslab) {
+ if(space->select.sel_info.hslab->span_lst != NULL) {
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ } /* end if */
+
+ /* Release space for the hyperslab selection information */
+ space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_recover_span
+ PURPOSE
+ Recover a generated span, if appropriate
+ USAGE
+ herr_t H5S_hyper_recover_span(recover, curr_span, next_span)
+ unsigned *recover; IN/OUT: Pointer recover flag
+ H5S_hyper_span_t **curr_span; IN/OUT: Pointer to current span in list
+ H5S_hyper_span_t *next_span; IN: Pointer to next span
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Check if the current span needs to be recovered and free it if so.
+ Set the current span to the next span in any case.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_recover_span (unsigned *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(recover);
+ HDassert(curr_span);
+
+ /* Check if the span should be recovered */
+ if(*recover) {
+ H5S_hyper_free_span(*curr_span);
+ *recover=0;
+ } /* end if */
+
+ /* Set the current span to next span */
+ *curr_span=next_span;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_recover_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_coord_to_span
+ PURPOSE
+ Create a span tree for a single element
+ USAGE
+ H5S_hyper_span_t *H5S_hyper_coord_to_span(rank, coords)
+ unsigned rank; IN: Number of dimensions of coordinate
+ hsize_t *coords; IN: Location of element
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Create a span tree for a single element
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_t *
+H5S_hyper_coord_to_span(unsigned rank, hsize_t *coords)
+{
+ H5S_hyper_span_t *new_span; /* Pointer to new span tree for coordinate */
+ H5S_hyper_span_info_t *down=NULL; /* Pointer to new span tree for next level down */
+ H5S_hyper_span_t *ret_value=NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(rank > 0);
+ HDassert(coords);
+
+ /* Search for location to insert new element in tree */
+ if(rank>1) {
+ /* Allocate a span info node */
+ if((down = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ down->count=0;
+
+ /* Reset the scratch pad space */
+ down->scratch=0;
+
+ /* Build span tree for coordinates below this one */
+ if((down->head=H5S_hyper_coord_to_span(rank-1,&coords[1]))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+ } /* end if */
+
+ /* Build span for this coordinate */
+ if((new_span = H5S_hyper_new_span(coords[0],coords[0],down,NULL))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Set return value */
+ ret_value=new_span;
+
+done:
+ if(ret_value==NULL) {
+ if(down!=NULL)
+ H5S_hyper_free_span_info(down);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_coord_to_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_add_span_element_helper
+ PURPOSE
+ Add a single elment to a span tree
+ USAGE
+ herr_t H5S_hyper_add_span_element_helper(prev_span, span_tree, rank, coords)
+ H5S_hyper_span_info_t *span_tree; IN/OUT: Pointer to span tree to append to
+ unsigned rank; IN: Number of dimensions of coordinates
+ hsize_t *coords; IN: Location of element to add to span tree
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Add a single element to an existing span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Assumes that the element is not already covered by the span tree
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, unsigned rank, hsize_t *coords)
+{
+ H5S_hyper_span_info_t *tspan_info; /* Temporary pointer to span info */
+ H5S_hyper_span_info_t *prev_span_info; /* Pointer to span info for level above current position */
+ H5S_hyper_span_t *tmp_span; /* Temporary pointer to a span */
+ H5S_hyper_span_t *tmp2_span; /* Another temporary pointer to a span */
+ H5S_hyper_span_t *new_span; /* New span created for element */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(span_tree);
+ HDassert(rank > 0);
+ HDassert(coords);
+
+ /* Get pointer to last span in span tree */
+ tspan_info=span_tree;
+ if(span_tree->scratch)
+ tmp_span=(H5S_hyper_span_t *)span_tree->scratch;
+ else {
+ tmp_span=span_tree->head;
+ HDassert(tmp_span);
+ span_tree->scratch=(H5S_hyper_span_info_t *)tmp_span;
+ } /* end else */
+
+ /* Find last span tree which includes a portion of the coordinate */
+ prev_span_info=NULL;
+ while(coords[0]>=tmp_span->low && coords[0]<=tmp_span->high) {
+ /* Move rank & coordinate offset down a dimension */
+ rank--;
+ coords++;
+
+ /* Remember the span tree we are descending into */
+ prev_span_info=tspan_info;
+ tspan_info=tmp_span->down;
+
+ /* Get the last span in this span's 'down' tree */
+ if(tspan_info->scratch)
+ tmp_span=(H5S_hyper_span_t *)tspan_info->scratch;
+ else {
+ tmp_span=tspan_info->head;
+ HDassert(tmp_span);
+ tspan_info->scratch=(H5S_hyper_span_info_t *)tmp_span;
+ } /* end else */
+ } /* end while */
+
+ /* Check if we made it all the way to the bottom span in the tree */
+ if(rank>1) {
+ /* Before we create another span at this level in the tree, check if
+ * the last span's "down tree" was equal to any other spans in this
+ * list of spans in the span tree.
+ *
+ * If so, release last span information and make last span merge into
+ * previous span (if possible), or at least share their "down tree"
+ * information.
+ */
+ tmp2_span=tspan_info->head;
+ while(tmp2_span!=tmp_span) {
+ if(H5S_hyper_cmp_spans(tmp2_span->down,tmp_span->down)==TRUE) {
+ /* Check for merging into previous span */
+ if(tmp2_span->high+1==tmp_span->low) {
+ /* Release last span created */
+ H5S_hyper_free_span(tmp_span);
+
+ /* Increase size of previous span */
+ tmp2_span->high++;
+ tmp2_span->nelem++;
+
+ /* Reset the 'tmp_span' for the rest of this block's algorithm */
+ tmp_span=tmp2_span;
+ } /* end if */
+ /* Span is disjoint, but has the same "down tree" selection */
+ else {
+ /* Release "down tree" information */
+ H5S_hyper_free_span_info(tmp_span->down);
+
+ /* Point at earlier span's "down tree" */
+ tmp_span->down=tmp2_span->down;
+
+ /* Increment reference count on shared "down tree" */
+ tmp_span->down->count++;
+ } /* end else */
+
+ /* Found span to merge into, break out now */
+ break;
+ } /* end if */
+
+ /* Advance to next span to check */
+ tmp2_span=tmp2_span->next;
+ } /* end while */
+
+ /* Make span tree for current coordinates */
+ if((new_span=H5S_hyper_coord_to_span(rank,coords))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Add new span tree as span */
+ HDassert(tmp_span);
+ tmp_span->next=new_span;
+
+ /* Make scratch pointer point to last span in list */
+ HDassert(tspan_info);
+ tspan_info->scratch=(H5S_hyper_span_info_t *)new_span;
+
+ /* Set the proper 'pstride' for new span */
+ new_span->pstride=new_span->low-tmp_span->low;
+ } /* end if */
+ else {
+ /* Does new node adjoin existing node? */
+ if(tmp_span->high+1==coords[0]) {
+ tmp_span->high++;
+ tmp_span->nelem++;
+
+ /* Check if this span tree should now be merged with a level higher in the tree */
+ if(prev_span_info!=NULL) {
+ /* Before we create another span at this level in the tree, check if
+ * the last span's "down tree" was equal to any other spans in this
+ * list of spans in the span tree.
+ *
+ * If so, release last span information and make last span merge into
+ * previous span (if possible), or at least share their "down tree"
+ * information.
+ */
+ tmp2_span=prev_span_info->head;
+ tmp_span=(H5S_hyper_span_t *)prev_span_info->scratch;
+ while(tmp2_span!=tmp_span) {
+ if(H5S_hyper_cmp_spans(tmp2_span->down,tmp_span->down)==TRUE) {
+ /* Check for merging into previous span */
+ if(tmp2_span->high+1==tmp_span->low) {
+ /* Release last span created */
+ H5S_hyper_free_span(tmp_span);
+
+ /* Increase size of previous span */
+ tmp2_span->high++;
+ tmp2_span->nelem++;
+
+ /* Update pointers */
+ tmp2_span->next=NULL;
+ prev_span_info->scratch=(H5S_hyper_span_info_t *)tmp2_span;
+ } /* end if */
+ /* Span is disjoint, but has the same "down tree" selection */
+ else {
+ /* Release "down tree" information */
+ H5S_hyper_free_span_info(tmp_span->down);
+
+ /* Point at earlier span's "down tree" */
+ tmp_span->down=tmp2_span->down;
+
+ /* Increment reference count on shared "down tree" */
+ tmp_span->down->count++;
+ } /* end else */
+
+ /* Found span to merge into, break out now */
+ break;
+ } /* end if */
+
+ /* Advance to next span to check */
+ tmp2_span=tmp2_span->next;
+ } /* end while */
+ } /* end if */
+ } /* end if */
+ else {
+ if((new_span = H5S_hyper_new_span(coords[0],coords[0],NULL,NULL))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Add new span tree as span */
+ HDassert(tmp_span);
+ tmp_span->next=new_span;
+
+ /* Make scratch pointer point to last span in list */
+ tspan_info->scratch=(H5S_hyper_span_info_t *)new_span;
+
+ /* Set the proper 'pstride' for new span */
+ new_span->pstride=new_span->low-tmp_span->low;
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_add_span_element_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_add_span_element
+ PURPOSE
+ Add a single elment to a span tree
+ USAGE
+ herr_t H5S_hyper_add_span_element(space, span_tree, rank, coords)
+ H5S_t *space; IN/OUT: Pointer to dataspace to add coordinate to
+ unsigned rank; IN: Number of dimensions of coordinates
+ hsize_t *coords; IN: Location of element to add to span tree
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Add a single element to an existing span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Assumes that the element is not already in the dataspace's selection
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_add_span_element(H5S_t *space, unsigned rank, hsize_t *coords)
+{
+ H5S_hyper_span_info_t *head = NULL; /* Pointer to new head of span tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(rank > 0);
+ HDassert(coords);
+
+ /* Check if this is the first element in the selection */
+ if(NULL == space->select.sel_info.hslab) {
+ /* Allocate a span info node */
+ if(NULL == (head = H5FL_MALLOC(H5S_hyper_span_info_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ head->count = 1;
+
+ /* Reset the scratch pad space */
+ head->scratch = 0;
+
+ /* Build span tree for this coordinate */
+ if(NULL == (head->head = H5S_hyper_coord_to_span(rank, coords)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Allocate selection info */
+ if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set the selection to the new span tree */
+ space->select.sel_info.hslab->span_lst = head;
+
+ /* Set selection type */
+ space->select.type = H5S_sel_hyper;
+
+ /* Reset "regular" hyperslab flag */
+ space->select.sel_info.hslab->diminfo_valid = FALSE;
+
+ /* Set unlim_dim */
+ space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Set # of elements in selection */
+ space->select.num_elem = 1;
+ } /* end if */
+ else {
+ if(H5S_hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Increment # of elements in selection */
+ space->select.num_elem++;
+ } /* end else */
+
+done:
+ if(ret_value < 0)
+ if(head)
+ H5S_hyper_free_span_info(head);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_add_span_element() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_reset_scratch
+ PURPOSE
+ Reset the scratch information for span tree
+ USAGE
+ herr_t H5S_hyper_reset_scratch(space)
+ H5S_t *space; IN/OUT: Pointer to dataspace to reset scratch pointers
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Resets the "scratch" pointers used for various tasks in computing hyperslab
+ spans.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_reset_scratch(H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Check if there are spans in the span tree */
+ if(space->select.sel_info.hslab->span_lst != NULL)
+ /* Reset the scratch pointers for the next routine which needs them */
+ H5S_hyper_span_scratch(space->select.sel_info.hslab->span_lst, NULL);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_reset_scratch() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_convert
+ PURPOSE
+ Convert a compatible selection to span tree form
+ USAGE
+ herr_t H5S_hyper_convert(space)
+ H5S_t *space; IN/OUT: Pointer to dataspace to convert
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Converts a compatible selection (currently only "all" selections) to the
+ span-tree form of a hyperslab selection. (Point and "none" selection aren't
+ currently supported and hyperslab selection always have the span-tree form
+ available).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_convert(H5S_t *space)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+
+ /* Check the type of selection */
+ switch(H5S_GET_SELECT_TYPE(space)) {
+ case H5S_SEL_ALL: /* All elements selected in dataspace */
+ /* Convert current "all" selection to "real" hyperslab selection */
+ {
+ hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */
+ hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */
+ unsigned u; /* Local index variable */
+
+ /* Fill in temporary information for the dimensions */
+ for(u=0; u<space->extent.rank; u++) {
+ tmp_start[u]=0;
+ tmp_stride[u]=1;
+ tmp_count[u]=1;
+ tmp_block[u]=space->extent.size[u];
+ } /* end for */
+
+ /* Convert to hyperslab selection */
+ if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ } /* end case */
+ break;
+
+ case H5S_SEL_HYPERSLABS: /* Hyperslab selection */
+ break;
+
+ case H5S_SEL_NONE: /* No elements selected in dataspace */
+ case H5S_SEL_POINTS: /* Point selection */
+ case H5S_SEL_ERROR: /* Selection error */
+ case H5S_SEL_N: /* Selection count */
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "can't convert to span tree selection")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_convert() */
+
+#ifdef LATER
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_intersect_helper
+ PURPOSE
+ Helper routine to detect intersections in span trees
+ USAGE
+ htri_t H5S_hyper_intersect_helper(spans1, spans2)
+ H5S_hyper_span_info_t *spans1; IN: First span tree to operate with
+ H5S_hyper_span_info_t *spans2; IN: Second span tree to operate with
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Quickly detect intersections between two span trees
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_intersect_helper (H5S_hyper_span_info_t *spans1, H5S_hyper_span_info_t *spans2)
+{
+ H5S_hyper_span_t *curr1; /* Pointer to current span in 1st span tree */
+ H5S_hyper_span_t *curr2; /* Pointer to current span in 2nd span tree */
+ htri_t status; /* Status from recursive call */
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert((spans1 && spans2) || (spans1 == NULL && spans2 == NULL));
+
+ /* "NULL" span trees compare as overlapping */
+ if(spans1==NULL && spans2==NULL)
+ HGOTO_DONE(TRUE);
+
+ /* Get the span lists for each span in this tree */
+ curr1=spans1->head;
+ curr2=spans2->head;
+
+ /* Iterate over the spans in each tree */
+ while(curr1!=NULL && curr2!=NULL) {
+ /* Check for 1st span entirely before 2nd span */
+ if(curr1->high<curr2->low)
+ curr1=curr1->next;
+ /* Check for 2nd span entirely before 1st span */
+ else if(curr2->high<curr1->low)
+ curr2=curr2->next;
+ /* Spans must overlap */
+ else {
+ /* Recursively check spans in next dimension down */
+ if((status=H5S_hyper_intersect_helper(curr1->down,curr2->down))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check")
+
+ /* If there is a span intersection in the down dimensions, the span trees overlap */
+ if(status==TRUE)
+ HGOTO_DONE(TRUE);
+
+ /* No intersection in down dimensions, advance to next span */
+ if(curr1->high<curr2->high)
+ curr1=curr1->next;
+ else
+ curr2=curr2->next;
+ } /* end else */
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_intersect_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_intersect
+ PURPOSE
+ Detect intersections in span trees
+ USAGE
+ htri_t H5S_hyper_intersect(space1, space2)
+ H5S_t *space1; IN: First dataspace to operate on span tree
+ H5S_t *space2; IN: Second dataspace to operate on span tree
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Quickly detect intersections between two span trees
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_hyper_intersect (H5S_t *space1, H5S_t *space2)
+{
+ htri_t ret_value=FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(space1);
+ HDassert(space2);
+
+ /* Check that the space selections both have span trees */
+ if(space1->select.sel_info.hslab->span_lst==NULL ||
+ space2->select.sel_info.hslab->span_lst==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Check that the dataspaces are both the same rank */
+ if(space1->extent.rank!=space2->extent.rank)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "dataspace ranks don't match")
+
+ /* Perform the span-by-span intersection check */
+ if((ret_value=H5S_hyper_intersect_helper(space1->select.sel_info.hslab->span_lst,space2->select.sel_info.hslab->span_lst))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_intersect() */
+#endif /* LATER */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_intersect_block_helper
+ PURPOSE
+ Helper routine to detect intersections in span trees
+ USAGE
+ htri_t H5S_hyper_intersect_block_helper(spans, start, end)
+ H5S_hyper_span_info_t *spans; IN: First span tree to operate with
+ hssize_t *offset; IN: Selection offset coordinate
+ hsize_t *start; IN: Starting coordinate for block
+ hsize_t *end; IN: Ending coordinate for block
+ RETURN
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Quickly detect intersections between span tree and block
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hsize_t *start, hsize_t *end)
+{
+ H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */
+ htri_t status; /* Status from recursive call */
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(spans);
+ HDassert(start);
+ HDassert(end);
+
+ /* Get the span list for spans in this tree */
+ curr=spans->head;
+
+ /* Iterate over the spans in the tree */
+ while(curr!=NULL) {
+ /* Check for span entirely before block */
+ if(curr->high < *start)
+ /* Advance to next span in this dimension */
+ curr=curr->next;
+ /* If this span is past the end of the block, then we're done in this dimension */
+ else if(curr->low > *end)
+ HGOTO_DONE(FALSE)
+ /* block & span overlap */
+ else {
+ if(curr->down==NULL)
+ HGOTO_DONE(TRUE)
+ else {
+ /* Recursively check spans in next dimension down */
+ if((status=H5S_hyper_intersect_block_helper(curr->down,start+1,end+1))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check")
+
+ /* If there is a span intersection in the down dimensions, the span trees overlap */
+ if(status==TRUE)
+ HGOTO_DONE(TRUE);
+
+ /* No intersection in down dimensions, advance to next span */
+ curr=curr->next;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_intersect_block_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_intersect_block
+ PURPOSE
+ Detect intersections in span trees
+ USAGE
+ htri_t H5S_hyper_intersect_block(space, start, end)
+ H5S_t *space; IN: First dataspace to operate on span tree
+ hssize_t *start; IN: Starting coordinate for block
+ hssize_t *end; IN: Ending coordinate for block
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Quickly detect intersections between span tree and block
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_hyper_intersect_block (H5S_t *space, hsize_t *start, hsize_t *end)
+{
+ htri_t ret_value=FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ /* Check for 'all' selection, instead of a hyperslab selection */
+ /* (Technically, this shouldn't be in the "hyperslab" routines...) */
+ if(H5S_GET_SELECT_TYPE(space)==H5S_SEL_ALL)
+ HGOTO_DONE(TRUE);
+
+ /* Check that the space selection has a span tree */
+ if(space->select.sel_info.hslab->span_lst==NULL)
+ if(H5S_hyper_generate_spans(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Perform the span-by-span intersection check */
+ if((ret_value=H5S_hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,start,end))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_intersect_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_adjust_helper_u
+ PURPOSE
+ Helper routine to adjust offsets in span trees
+ USAGE
+ herr_t H5S_hyper_adjust_helper_u(spans, offset)
+ H5S_hyper_span_info_t *spans; IN: Span tree to operate with
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Adjust the location of the spans in a span tree by subtracting an offset
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_adjust_helper_u (H5S_hyper_span_info_t *spans, const hsize_t *offset)
+{
+ H5S_hyper_span_t *span; /* Pointer to current span in span tree */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(spans);
+ HDassert(offset);
+
+ /* Check if we've already set this down span tree */
+ if(spans->scratch!=(H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Set the tree's scratch pointer */
+ spans->scratch=(H5S_hyper_span_info_t *)~((size_t)NULL);
+
+ /* Get the span lists for each span in this tree */
+ span=spans->head;
+
+ /* Iterate over the spans in tree */
+ while(span!=NULL) {
+ /* Adjust span offset */
+ HDassert(span->low>=*offset);
+ span->low-=*offset;
+ span->high-=*offset;
+
+ /* Recursively adjust spans in next dimension down */
+ if(span->down!=NULL)
+ H5S_hyper_adjust_helper_u(span->down,offset+1);
+
+ /* Advance to next span in this dimension */
+ span=span->next;
+ } /* end while */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_adjust_helper_u() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_adjust_u
+ PURPOSE
+ Adjust a hyperslab selection by subtracting an offset
+ USAGE
+ herr_t H5S_hyper_adjust_u(space,offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves a hyperslab selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_adjust_u(H5S_t *space, const hsize_t *offset)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(offset);
+
+ /* Subtract the offset from the "regular" coordinates, if they exist */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ for(u=0; u<space->extent.rank; u++) {
+ HDassert(space->select.sel_info.hslab->opt_diminfo[u].start>=offset[u]);
+ space->select.sel_info.hslab->opt_diminfo[u].start-=offset[u];
+ } /* end for */
+ } /* end if */
+
+ /* Subtract the offset from the span tree coordinates, if they exist */
+ if(space->select.sel_info.hslab->span_lst) {
+ if(H5S_hyper_adjust_helper_u(space->select.sel_info.hslab->span_lst,offset)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab offset adjustment")
+
+ /* Reset the scratch pointers for the next routine which needs them */
+ H5S_hyper_span_scratch(space->select.sel_info.hslab->span_lst, NULL);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_adjust_u() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_project_scalar
+ *
+ * Purpose: Projects a single element hyperslab selection into a scalar
+ * dataspace
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_project_scalar(const H5S_t *space, hsize_t *offset)
+{
+ hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
+ HDassert(offset);
+
+ /* Check for a "regular" hyperslab selection */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Alias for dataspace's diminfo information */
+ unsigned u; /* Counter */
+
+ /* Build the table of the initial offset */
+ for(u = 0; u < space->extent.rank; u++) {
+ block[u] = diminfo[u].start;
+
+ /* Check for more than one hyperslab */
+ if(diminfo[u].count > 1 || diminfo[u].block > 1)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "hyperslab selection of one element has more than one node!")
+ } /* end for */
+ } /* end if */
+ else {
+ const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ unsigned curr_dim; /* Current dimension being operated on */
+
+ /* Advance down selected spans */
+ curr = space->select.sel_info.hslab->span_lst->head;
+ curr_dim = 0;
+ while(curr) {
+ /* Check for more than one span */
+ if(curr->next || curr->low != curr->high)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "hyperslab selection of one element has more than one node!")
+
+ /* Save the location of the selection in current dimension */
+ block[curr_dim] = curr->low;
+
+ /* Advance down to next dimension */
+ curr = curr->down->head;
+ curr_dim++;
+ } /* end while */
+ } /* end else */
+
+ /* Calculate offset of selection in projected buffer */
+ *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_project_scalar() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_project_simple_lower
+ *
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * of a lower rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space)
+{
+ H5S_hyper_span_info_t *down; /* Pointer to list of spans */
+ unsigned curr_dim; /* Current dimension being operated on */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(new_space->extent.rank < base_space->extent.rank);
+
+ /* Walk down the span tree until we reach the selection to project */
+ down = base_space->select.sel_info.hslab->span_lst;
+ curr_dim = 0;
+ while(down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
+ /* Sanity check */
+ HDassert(NULL == down->head->next);
+
+ /* Advance down to next dimension */
+ down = down->head->down;
+ curr_dim++;
+ } /* end while */
+ HDassert(down);
+
+ /* Share the underlying hyperslab span information */
+ new_space->select.sel_info.hslab->span_lst = down;
+ new_space->select.sel_info.hslab->span_lst->count++;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_project_simple_lower() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_project_simple_higher
+ *
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * of a higher rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
+{
+ H5S_hyper_span_t *prev_span = NULL; /* Pointer to previous list of spans */
+ unsigned curr_dim; /* Current dimension being operated on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(new_space->extent.rank > base_space->extent.rank);
+
+ /* Create nodes until reaching the correct # of dimensions */
+ new_space->select.sel_info.hslab->span_lst = NULL;
+ curr_dim = 0;
+ while(curr_dim < (new_space->extent.rank - base_space->extent.rank)) {
+ H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */
+ H5S_hyper_span_t *new_span; /* Temporary hyperslab span */
+
+ /* Allocate a new span_info node */
+ if(NULL == (new_span_info = H5FL_MALLOC(H5S_hyper_span_info_t))) {
+ if(prev_span)
+ if(H5S_hyper_free_span(prev_span) < 0)
+ HERROR(H5E_DATASPACE, H5E_CANTFREE, "can't free hyperslab span");
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info")
+ } /* end if */
+
+ /* Check for linking into higher span */
+ if(prev_span)
+ prev_span->down = new_span_info;
+
+ /* Allocate a new node */
+ if(NULL == (new_span = H5S_hyper_new_span(0, 0, NULL, NULL))) {
+ HDassert(new_span_info);
+ if(!prev_span)
+ (void)H5FL_FREE(H5S_hyper_span_info_t, new_span_info);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+
+ /* Set the span_info information */
+ new_span_info->count = 1;
+ new_span_info->scratch = NULL;
+ new_span_info->head = new_span;
+
+ /* Attach to new space, if top span info */
+ if(NULL == new_space->select.sel_info.hslab->span_lst)
+ new_space->select.sel_info.hslab->span_lst = new_span_info;
+
+ /* Remember previous span info */
+ prev_span = new_span;
+
+ /* Advance to next dimension */
+ curr_dim++;
+ } /* end while */
+ HDassert(new_space->select.sel_info.hslab->span_lst);
+ HDassert(prev_span);
+
+ /* Share the underlying hyperslab span information */
+ prev_span->down = base_space->select.sel_info.hslab->span_lst;
+ prev_span->down->count++;
+
+done:
+ if(ret_value < 0 && new_space->select.sel_info.hslab->span_lst) {
+ if(new_space->select.sel_info.hslab->span_lst->head)
+ if(H5S_hyper_free_span(
+ new_space->select.sel_info.hslab->span_lst->head) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free hyperslab span")
+
+ new_space->select.sel_info.hslab->span_lst = H5FL_FREE(H5S_hyper_span_info_t, new_space->select.sel_info.hslab->span_lst);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_project_simple_higher() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_hyper_project_simple
+ *
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * of a different rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(offset);
+
+ /* We are setting a new selection, remove any current selection in new dataspace */
+ if(H5S_SELECT_RELEASE(new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if(NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set unlim_dim */
+ new_space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Check for a "regular" hyperslab selection */
+ if(base_space->select.sel_info.hslab->diminfo_valid) {
+ unsigned base_space_dim; /* Current dimension in the base dataspace */
+ unsigned new_space_dim; /* Current dimension in the new dataspace */
+
+ /* Check if the new space's rank is < or > base space's rank */
+ if(new_space->extent.rank < base_space->extent.rank) {
+ const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->opt_diminfo; /* Alias for dataspace's diminfo information */
+ hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
+ unsigned u; /* Local index variable */
+
+ /* Compute the offset for the down-projection */
+ HDmemset(block, 0, sizeof(block));
+ for(u = 0; u < (base_space->extent.rank - new_space->extent.rank); u++)
+ block[u] = opt_diminfo[u].start;
+ *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
+
+ /* Set the correct dimensions for the base & new spaces */
+ base_space_dim = base_space->extent.rank - new_space->extent.rank;
+ new_space_dim = 0;
+ } /* end if */
+ else {
+ HDassert(new_space->extent.rank > base_space->extent.rank);
+
+ /* The offset is zero when projected into higher dimensions */
+ *offset = 0;
+
+ /* Set the diminfo information for the higher dimensions */
+ for(new_space_dim = 0; new_space_dim < (new_space->extent.rank - base_space->extent.rank); new_space_dim++) {
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].start = 0;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride = 1;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count = 1;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block = 1;
+
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start = 0;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride = 1;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count = 1;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block = 1;
+ } /* end for */
+
+ /* Start at beginning of base space's dimension info */
+ base_space_dim = 0;
+ } /* end else */
+
+ /* Copy the diminfo */
+ while(base_space_dim < base_space->extent.rank) {
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].start =
+ base_space->select.sel_info.hslab->app_diminfo[base_space_dim].start;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride =
+ base_space->select.sel_info.hslab->app_diminfo[base_space_dim].stride;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count =
+ base_space->select.sel_info.hslab->app_diminfo[base_space_dim].count;
+ new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block =
+ base_space->select.sel_info.hslab->app_diminfo[base_space_dim].block;
+
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start =
+ base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].start;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride =
+ base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].stride;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count =
+ base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].count;
+ new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block =
+ base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].block;
+
+ /* Advance to next dimensions */
+ base_space_dim++;
+ new_space_dim++;
+ } /* end for */
+
+ /* Indicate that the dimension information is valid */
+ new_space->select.sel_info.hslab->diminfo_valid = TRUE;
+
+ /* Indicate that there's no slab information */
+ new_space->select.sel_info.hslab->span_lst = NULL;
+ } /* end if */
+ else {
+ /* Check if the new space's rank is < or > base space's rank */
+ if(new_space->extent.rank < base_space->extent.rank) {
+ const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
+ unsigned curr_dim; /* Current dimension being operated on */
+
+ /* Clear the block buffer */
+ HDmemset(block, 0, sizeof(block));
+
+ /* Advance down selected spans */
+ curr = base_space->select.sel_info.hslab->span_lst->head;
+ curr_dim = 0;
+ while(curr && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
+ /* Save the location of the selection in current dimension */
+ block[curr_dim] = curr->low;
+
+ /* Advance down to next dimension */
+ curr = curr->down->head;
+ curr_dim++;
+ } /* end while */
+
+ /* Compute the offset for the down-projection */
+ *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
+
+ /* Project the base space's selection down in less dimensions */
+ if(H5S_hyper_project_simple_lower(base_space, new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions")
+ } /* end if */
+ else {
+ HDassert(new_space->extent.rank > base_space->extent.rank);
+
+ /* The offset is zero when projected into higher dimensions */
+ *offset = 0;
+
+ /* Project the base space's selection down in less dimensions */
+ if(H5S_hyper_project_simple_higher(base_space, new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions")
+ } /* end else */
+
+ /* Indicate that the dimension information is not valid */
+ new_space->select.sel_info.hslab->diminfo_valid = FALSE;
+ } /* end else */
+
+ /* Number of elements selected will be the same */
+ new_space->select.num_elem = base_space->select.num_elem;
+
+ /* Set selection type */
+ new_space->select.type = H5S_sel_hyper;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_project_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_adjust_helper_s
+ PURPOSE
+ Helper routine to adjust offsets in span trees
+ USAGE
+ herr_t H5S_hyper_adjust_helper_s(spans, offset)
+ H5S_hyper_span_info_t *spans; IN: Span tree to operate with
+ const hssize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Adjust the location of the spans in a span tree by subtracting an offset
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_adjust_helper_s(H5S_hyper_span_info_t *spans, const hssize_t *offset)
+{
+ H5S_hyper_span_t *span; /* Pointer to current span in span tree */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(spans);
+ HDassert(offset);
+
+ /* Check if we've already set this down span tree */
+ if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Set the tree's scratch pointer */
+ spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL);
+
+ /* Get the span lists for each span in this tree */
+ span = spans->head;
+
+ /* Iterate over the spans in tree */
+ while(span != NULL) {
+ /* Adjust span offset */
+ HDassert((hssize_t)span->low >= *offset);
+ span->low = (hsize_t)((hssize_t)span->low - *offset);
+ span->high = (hsize_t)((hssize_t)span->high - *offset);
+
+ /* Recursively adjust spans in next dimension down */
+ if(span->down != NULL)
+ H5S_hyper_adjust_helper_s(span->down, offset + 1);
+
+ /* Advance to next span in this dimension */
+ span = span->next;
+ } /* end while */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_adjust_helper_s() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_adjust_s
+ PURPOSE
+ Adjust a hyperslab selection by subtracting an offset
+ USAGE
+ herr_t H5S_hyper_adjust_s(space,offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hssize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves a hyperslab selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(offset);
+
+ /* Subtract the offset from the "regular" coordinates, if they exist */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ for(u = 0; u < space->extent.rank; u++) {
+ HDassert((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start >= offset[u]);
+ space->select.sel_info.hslab->opt_diminfo[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start - offset[u]);
+ } /* end for */
+ } /* end if */
+
+ /* Subtract the offset from the span tree coordinates, if they exist */
+ if(space->select.sel_info.hslab->span_lst) {
+ if(H5S_hyper_adjust_helper_s(space->select.sel_info.hslab->span_lst, offset) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab offset adjustment")
+
+ /* Reset the scratch pointers for the next routine which needs them */
+ H5S_hyper_span_scratch(space->select.sel_info.hslab->span_lst, NULL);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_adjust_s() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_normalize_offset
+ PURPOSE
+ "Normalize" a hyperslab selection by adjusting it's coordinates by the
+ amount of the selection offset.
+ USAGE
+ herr_t H5S_hyper_normalize_offset(space, old_offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to move
+ hssize_t *old_offset; OUT: Pointer to space to store old offset
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Copies the current selection offset into the array provided, then
+ inverts the selection offset, subtracts the offset from the hyperslab
+ selection and resets the offset to zero.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+
+ /* Check for hyperslab selection & offset changed */
+ if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) {
+ /* Copy & invert the selection offset */
+ for(u = 0; u<space->extent.rank; u++) {
+ old_offset[u] = space->select.offset[u];
+ space->select.offset[u] = -space->select.offset[u];
+ } /* end for */
+
+ /* Call the existing 'adjust' routine */
+ if(H5S_hyper_adjust_s(space, space->select.offset) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization")
+
+ /* Zero out the selection offset */
+ HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank);
+
+ /* Indicate that the offset was normalized */
+ ret_value = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_normalize_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_denormalize_offset
+ PURPOSE
+ "Denormalize" a hyperslab selection by reverse adjusting it's coordinates
+ by the amount of the former selection offset.
+ USAGE
+ herr_t H5S_hyper_normalize_offset(space, old_offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to move
+ hssize_t *old_offset; IN: Pointer to old offset array
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Subtracts the old offset from the current selection (canceling out the
+ effect of the "normalize" routine), then restores the old offset into
+ the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
+
+ /* Call the existing 'adjust' routine */
+ if(H5S_hyper_adjust_s(space, old_offset) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization")
+
+ /* Copy the selection offset over */
+ HDmemcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_denormalize_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_append_span
+ PURPOSE
+ Create a new span and append to span list
+ USAGE
+ herr_t H5S_hyper_append_span(prev_span, span_tree, low, high, down, next)
+ H5S_hyper_span_t **prev_span; IN/OUT: Pointer to previous span in list
+ H5S_hyper_span_info_t **span_tree; IN/OUT: Pointer to span tree to append to
+ hsize_t low, high; IN: Low and high bounds for new span node
+ H5S_hyper_span_info_t *down; IN: Down span tree for new node
+ H5S_hyper_span_t *next; IN: Next span for new node
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Create a new span node and append to a span list. Update the previous
+ span in the list also.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_append_span (H5S_hyper_span_t **prev_span, H5S_hyper_span_info_t ** span_tree, hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
+{
+ H5S_hyper_span_t *new_span = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(prev_span);
+ HDassert(span_tree);
+
+ /* Check for adding first node to merged spans */
+ if(*prev_span==NULL) {
+ /* Allocate new span node to append to list */
+ if((new_span = H5S_hyper_new_span(low,high,down,next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Make first node in span list */
+
+ /* Check that we haven't already allocated a span tree */
+ HDassert(*span_tree==NULL);
+
+ /* Allocate a new span_info node */
+ if((*span_tree = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Set the span tree's basic information */
+ (*span_tree)->count=1;
+ (*span_tree)->scratch=NULL;
+ (*span_tree)->head=new_span;
+
+ /* Update previous merged span */
+ *prev_span=new_span;
+ } /* end if */
+ /* Merge or append to existing merged spans list */
+ else {
+ /* Check if span can just extend the previous merged span */
+ if((((*prev_span)->high+1)==low) &&
+ H5S_hyper_cmp_spans(down,(*prev_span)->down)==TRUE) {
+ /* Extend previous merged span to include new high bound */
+ (*prev_span)->high=high;
+ (*prev_span)->nelem+=(high-low)+1;
+ } /* end if */
+ else {
+ /* Allocate new span node to append to list */
+ if((new_span = H5S_hyper_new_span(low,high,down,next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Check if there is actually a down span */
+ if(new_span->down) {
+ /* Check if the down spans for the new span node are the same as the previous span node */
+ if(H5S_hyper_cmp_spans(new_span->down,(*prev_span)->down)==TRUE) {
+ /* Release the down span for the new node */
+ H5S_hyper_free_span_info(new_span->down);
+
+ /* Point the new node's down span at the previous node's down span */
+ new_span->down=(*prev_span)->down;
+
+ /* Increment the reference count to the shared down span */
+ new_span->down->count++;
+ } /* end if */
+ } /* end if */
+
+ /* Indicate elements from previous span */
+ new_span->pstride=low-(*prev_span)->low;
+
+ /* Append to end of merged spans list */
+ (*prev_span)->next=new_span;
+ *prev_span=new_span;
+ } /* end else */
+ } /* end else */
+
+done:
+ if(ret_value < 0) {
+ if(new_span)
+ if(H5S_hyper_free_span(new_span) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "failed to release new hyperslab span")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_append_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_clip_spans
+ PURPOSE
+ Clip a new span tree against the current spans in the hyperslab selection
+ USAGE
+ herr_t H5S_hyper_clip_spans(span_a, span_b, a_not_b, a_and_b, b_not_a)
+ H5S_hyper_span_t *a_spans; IN: Span tree 'a' to clip with.
+ H5S_hyper_span_t *b_spans; IN: Span tree 'b' to clip with.
+ H5S_hyper_span_t **a_not_b; OUT: Span tree of 'a' hyperslab spans which
+ doesn't overlap with 'b' hyperslab
+ spans.
+ H5S_hyper_span_t **a_and_b; OUT: Span tree of 'a' hyperslab spans which
+ overlaps with 'b' hyperslab spans.
+ H5S_hyper_span_t **b_not_a; OUT: Span tree of 'b' hyperslab spans which
+ doesn't overlap with 'a' hyperslab
+ spans.
+ RETURNS
+ non-negative on success, negative on failure
+ DESCRIPTION
+ Clip one span tree ('a') against another span tree ('b'). Creates span
+ trees for the area defined by the 'a' span tree which does not overlap the
+ 'b' span tree, the area defined by the overlap of the 'a' hyperslab span
+ tree and the 'b' span tree, and the area defined by the 'b' hyperslab span
+ tree which does not overlap the 'a' span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_clip_spans (H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans,
+ H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b,
+ H5S_hyper_span_info_t **b_not_a)
+{
+ H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */
+ H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */
+ H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */
+ H5S_hyper_span_t *last_a_not_b; /* Pointer to previous node in span tree 'a_not_b' */
+ H5S_hyper_span_t *last_a_and_b; /* Pointer to previous node in span tree 'a_and_b' */
+ H5S_hyper_span_t *last_b_not_a; /* Pointer to previous node in span tree 'b_not_a' */
+ H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */
+ unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(a_spans);
+ HDassert(b_spans);
+ HDassert(a_not_b);
+ HDassert(a_and_b);
+ HDassert(b_not_a);
+
+ /* Check if both span trees are not defined */
+ if(a_spans==NULL && b_spans==NULL) {
+ *a_not_b=NULL;
+ *a_and_b=NULL;
+ *b_not_a=NULL;
+ } /* end if */
+ /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */
+ else if(a_spans==NULL) {
+ *a_not_b=NULL;
+ *a_and_b=NULL;
+ if((*b_not_a=H5S_hyper_copy_span(b_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ } /* end if */
+ /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */
+ else if(b_spans==NULL) {
+ if((*a_not_b=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ *a_and_b=NULL;
+ *b_not_a=NULL;
+ } /* end if */
+ /* If span 'a' and 'b' are both defined, calculate the proper span trees */
+ else {
+ /* Check if both span trees completely overlap */
+ if(H5S_hyper_cmp_spans(a_spans,b_spans)==TRUE) {
+ *a_not_b=NULL;
+ if((*a_and_b=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ *b_not_a=NULL;
+ } /* end if */
+ else {
+ /* Get the pointers to the new and old span lists */
+ span_a=a_spans->head;
+ span_b=b_spans->head;
+
+ /* Set the pointer to the previous spans */
+ last_a_not_b=NULL;
+ last_a_and_b=NULL;
+ last_b_not_a=NULL;
+
+ /* No spans to recover yet */
+ recover_a=recover_b=0;
+
+ /* Work through the list of spans in the new list */
+ while(span_a!=NULL && span_b!=NULL) {
+ /* Check if span 'a' is completely before span 'b' */
+ /* AAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ if(span_a->high<span_b->low) {
+ /* Copy span 'a' and add to a_not_b list */
+
+ /* Merge/add span 'a' with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Advance span 'a', leave span 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end if */
+ /* Check if span 'a' overlaps only the lower bound */
+ /* of span 'b' , up to the upper bound of span 'b' */
+ /* AAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && (span_a->high>=span_b->low && span_a->high<=span_b->high)) {
+ /* Split span 'a' into two parts at the low bound of span 'b' */
+
+ /* Merge/add lower part of span 'a' with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_a->high,NULL,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_a->high,down_a_not_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_a->high,down_a_and_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->high,down_b_not_a,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'b' at upper span of span 'a' */
+
+ /* Check if there is actually an upper part of span 'b' to split off */
+ if(span_a->high<span_b->high) {
+ /* Allocate new span node for upper part of span 'b' */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Make upper part of span 'b' into new span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ /* No upper part of span 'b' to split */
+ else {
+ /* Advance both 'a' and 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps the lower & upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAAAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && span_a->high>span_b->high) {
+ /* Split off lower part of span 'a' at lower span of span 'b' */
+
+ /* Merge/add lower part of span 'a' with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Check for overlaps between middle part of span 'a' and span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,NULL,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_b->high,down_a_not_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,down_a_and_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,down_b_not_a,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'a' at upper span of span 'b' */
+
+ /* Allocate new span node for upper part of span 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Make upper part of span 'a' the new span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Check if span 'a' is entirely within span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low>=span_b->low && span_a->high<=span_b->high) {
+ /* Split off lower part of span 'b' at lower span of span 'a' */
+
+ /* Check if there is actually a lower part of span 'b' to split off */
+ if(span_a->low>span_b->low) {
+ /* Merge/add lower part of span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Keep going, nothing to split off */
+ } /* end else */
+
+ /* Check for overlaps between span 'a' and midle of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,NULL,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,down_a_not_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,down_a_and_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_a->high,down_b_not_a,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Check if there is actually an upper part of span 'b' to split off */
+ if(span_a->high<span_b->high) {
+ /* Split off upper part of span 'b' at upper span of span 'a' */
+
+ /* Allocate new span node for upper part of spans 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* And advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Make upper part of span 'b' the new span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both span 'a' & span 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps only the upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) {
+ /* Check if there is actually a lower part of span 'b' to split off */
+ if(span_a->low>span_b->low) {
+ /* Split off lower part of span 'b' at lower span of span 'a' */
+
+ /* Merge/add lower part of span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Keep going, nothing to split off */
+ } /* end else */
+
+ /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,NULL,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->high,down_a_not_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,down_a_and_b,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_b->high,down_b_not_a,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'a' at upper span of span 'b' */
+
+ /* Allocate new span node for upper part of span 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Make upper part of span 'a' into new span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* span 'a' must be entirely above span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else {
+ /* Copy span 'b' and add to b_not_a list */
+
+ /* Merge/add span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Advance span 'b', leave span 'a' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end while */
+
+ /* Clean up 'a' spans which haven't been covered yet */
+ if(span_a!=NULL && span_b==NULL) {
+ while(span_a!=NULL) {
+ /* Copy span 'a' and add to a_not_b list */
+
+ /* Merge/add span 'a' with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Advance to the next 'a' span */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end while */
+ } /* end if */
+ /* Clean up 'b' spans which haven't been covered yet */
+ else if(span_a==NULL && span_b!=NULL) {
+ while(span_b!=NULL) {
+ /* Copy span 'b' and add to b_not_a list */
+
+ /* Merge/add span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Advance to the next 'b' span */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end while */
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_clip_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_merge_spans_helper
+ PURPOSE
+ Merge two hyperslab span tree together
+ USAGE
+ H5S_hyper_span_info_t *H5S_hyper_merge_spans_helper(a_spans, b_spans)
+ H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge
+ together
+ H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge
+ together
+ RETURNS
+ Pointer to span tree containing the merged spans on success, NULL on failure
+ DESCRIPTION
+ Merge two sets of hyperslab spans together and return the span tree from
+ the merged set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_merge_spans_helper (H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans)
+{
+ H5S_hyper_span_info_t *merged_spans=NULL; /* Pointer to the merged span tree */
+ H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
+ H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */
+ H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */
+ H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */
+ H5S_hyper_span_t *prev_span_merge; /* Pointer to previous merged span */
+ unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+ H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Make certain both 'a' & 'b' spans have down span trees or neither does */
+ HDassert((a_spans != NULL && b_spans != NULL) || (a_spans == NULL && b_spans == NULL));
+
+ /* Check if the span trees for the 'a' span and the 'b' span are the same */
+ if(H5S_hyper_cmp_spans(a_spans,b_spans)==TRUE) {
+ if(a_spans==NULL)
+ merged_spans=NULL;
+ else {
+ /* Copy one of the span trees to return */
+ if((merged_spans=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Get the pointers to the 'a' and 'b' span lists */
+ span_a=a_spans->head;
+ span_b=b_spans->head;
+
+ /* Set the pointer to the previous spans */
+ prev_span_merge=NULL;
+
+ /* No spans to recover yet */
+ recover_a=recover_b=0;
+
+ /* Work through the list of spans in the new list */
+ while(span_a!=NULL && span_b!=NULL) {
+ /* Check if the 'a' span is completely before 'b' span */
+ /* AAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ if(span_a->high<span_b->low) {
+ /* Merge/add span 'a' with/to the merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end if */
+ /* Check if span 'a' overlaps only the lower bound */
+ /* of span 'b', up to the upper bound of span 'b' */
+ /* AAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && (span_a->high>=span_b->low && span_a->high<=span_b->high)) {
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of span 'a' with/to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Merge/add lower part of span 'a' with/to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,tmp_spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Check if there is an upper part of span 'b' */
+ if(span_a->high<span_b->high) {
+ /* Copy upper part of span 'b' as new span 'b' */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Set new span 'b' to tmp_span */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both span 'a' & 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps the lower & upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAAAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && span_a->high>span_b->high) {
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of lower & middle parts of span 'a' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Merge/add lower part of span 'a' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,tmp_spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Copy upper part of span 'a' as new span 'a' (remember to free) */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Set new span 'a' to tmp_span */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Check if span 'a' is entirely within span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low>=span_b->low && span_a->high<=span_b->high) {
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of lower & middle parts of span 'b' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Check if there is a lower part of span 'b' */
+ if(span_a->low>span_b->low) {
+ /* Merge/add lower part of span 'b' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* No lower part of span 'b' , keep going... */
+ } /* end else */
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,tmp_spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Check if there is an upper part of span 'b' */
+ if(span_a->high<span_b->high) {
+ /* Copy upper part of span 'b' as new span 'b' (remember to free) */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Set new span 'b' to tmp_span */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both spans */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps only the upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) {
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of span 'b' to merged spans if so */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* Check if there is a lower part of span 'b' */
+ if(span_a->low>span_b->low) {
+ /* Merge/add lower part of span 'b' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* No lower part of span 'b' , keep going... */
+ } /* end else */
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,tmp_spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Copy upper part of span 'a' as new span 'a' */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Set new span 'a' to tmp_span */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Span 'a' must be entirely above span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else {
+ /* Merge/add span 'b' with the merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end while */
+
+ /* Clean up 'a' spans which haven't been added to the list of merged spans */
+ if(span_a!=NULL && span_b==NULL) {
+ while(span_a!=NULL) {
+ /* Merge/add all 'a' spans into the merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Advance to next 'a' span, until all processed */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end while */
+ } /* end if */
+
+ /* Clean up 'b' spans which haven't been added to the list of merged spans */
+ if(span_a==NULL && span_b!=NULL) {
+ while(span_b!=NULL) {
+ /* Merge/add all 'b' spans into the merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+
+ /* Advance to next 'b' span, until all processed */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end while */
+ } /* end if */
+ } /* end else */
+
+ /* Set return value */
+ ret_value = merged_spans;
+
+done:
+ if(ret_value == NULL) {
+ if(merged_spans)
+ if(H5S_hyper_free_span_info(merged_spans) < 0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, NULL, "failed to release merged hyperslab spans")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_merge_spans_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_merge_spans
+ PURPOSE
+ Merge new hyperslab spans to existing hyperslab selection
+ USAGE
+ herr_t H5S_hyper_merge_spans(space, new_spans, can_own)
+ H5S_t *space; IN: Dataspace to add new spans to hyperslab
+ selection.
+ H5S_hyper_span_t *new_spans; IN: Span tree of new spans to add to
+ hyperslab selection
+ hbool_t can_own; IN: Flag to indicate that it is OK to point
+ directly to the new spans, instead of
+ copying them.
+ RETURNS
+ non-negative on success, negative on failure
+ DESCRIPTION
+ Add a set of hyperslab spans to an existing hyperslab selection. The
+ new spans are required to be non-overlapping with the existing spans in
+ the dataspace's current hyperslab selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_merge_spans (H5S_t *space, H5S_hyper_span_info_t *new_spans, hbool_t can_own)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(new_spans);
+
+ /* If this is the first span tree in the hyperslab selection, just use it */
+ if(space->select.sel_info.hslab->span_lst==NULL) {
+ if(can_own)
+ space->select.sel_info.hslab->span_lst=new_spans;
+ else
+ space->select.sel_info.hslab->span_lst=H5S_hyper_copy_span(new_spans);
+ } /* end if */
+ else {
+ H5S_hyper_span_info_t *merged_spans;
+
+ /* Get the merged spans */
+ merged_spans=H5S_hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans);
+
+ /* Sanity checking since we started with some spans, we should still have some after the merge */
+ HDassert(merged_spans);
+
+ /* Free the previous spans */
+ H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst);
+
+ /* Point to the new merged spans */
+ space->select.sel_info.hslab->span_lst=merged_spans;
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_hyper_merge_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_spans_nelem
+ PURPOSE
+ Count the number of elements in a span tree
+ USAGE
+ hsize_t H5S_hyper_spans_nelem(spans)
+ const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
+ RETURNS
+ Number of elements in span tree on success; negative on failure
+ DESCRIPTION
+ Counts the number of elements described by the spans in a span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hsize_t
+H5S_hyper_spans_nelem (H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Count the number of elements in the span tree */
+ if(spans==NULL)
+ ret_value=0;
+ else {
+ span=spans->head;
+ ret_value=0;
+ while(span!=NULL) {
+ /* If there are down spans, multiply the size of this span by the total down span elements */
+ if(span->down!=NULL)
+ ret_value+=span->nelem*H5S_hyper_spans_nelem(span->down);
+ /* If there are no down spans, just count the elements in this span */
+ else
+ ret_value+=span->nelem;
+
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_spans_nelem() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_make_spans
+ PURPOSE
+ Create a span tree
+ USAGE
+ H5S_hyper_span_t *H5S_hyper_make_spans(rank, start, stride, count, block)
+ unsigned rank; IN: # of dimensions of the space
+ const hsize_t *start; IN: Starting location of the hyperslabs
+ const hsize_t *stride; IN: Stride from the beginning of one block to
+ the next
+ const hsize_t *count; IN: Number of blocks
+ const hsize_t *block; IN: Size of hyperslab block
+ RETURNS
+ Pointer to new span tree on success, NULL on failure
+ DESCRIPTION
+ Generates a new span tree for the hyperslab parameters specified.
+ Each span tree has a list of the elements spanned in each dimension, with
+ each span node containing a pointer to the list of spans in the next
+ dimension down.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride,
+ const hsize_t *count, const hsize_t *block)
+{
+ H5S_hyper_span_info_t *down = NULL; /* Pointer to spans in next dimension down */
+ H5S_hyper_span_t *last_span; /* Current position in hyperslab span list */
+ H5S_hyper_span_t *head = NULL; /* Head of new hyperslab span list */
+ hsize_t stride_iter; /* Iterator over the stride values */
+ int i; /* Counters */
+ unsigned u; /* Counters */
+ H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(rank > 0);
+ HDassert(start);
+ HDassert(stride);
+ HDassert(count);
+ HDassert(block);
+
+ /* Start creating spans in fastest changing dimension */
+ for(i = (int)(rank - 1); i >= 0; i--) {
+
+ /* Sanity check */
+ if(0 == count[i])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid")
+
+ /* Start a new list in this dimension */
+ head = NULL;
+ last_span = NULL;
+
+ /* Generate all the span segments for this dimension */
+ for(u = 0, stride_iter = 0; u < count[i]; u++, stride_iter += stride[i]) {
+ H5S_hyper_span_t *span; /* New hyperslab span */
+
+ /* Allocate a span node */
+ if(NULL == (span = H5FL_MALLOC(H5S_hyper_span_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Set the span's basic information */
+ span->low = start[i] + stride_iter;
+ span->high = span->low + (block[i] - 1);
+ span->nelem = block[i];
+ span->pstride = stride[i];
+ span->next = NULL;
+
+ /* Append to the list of spans in this dimension */
+ if(head == NULL)
+ head = span;
+ else
+ last_span->next = span;
+
+ /* Move current pointer */
+ last_span = span;
+
+ /* Set the information for the next dimension down's spans, if appropriate */
+ if(down != NULL) {
+ span->down = down;
+ down->count++; /* Increment reference count for shared span */
+ } /* end if */
+ else {
+ span->down = NULL;
+ } /* end else */
+ } /* end for */
+
+ /* Allocate a span info node */
+ if(NULL == (down = H5FL_MALLOC(H5S_hyper_span_info_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ down->count = 0;
+
+ /* Reset the scratch pad space */
+ down->scratch = 0;
+
+ /* Keep the pointer to the next dimension down's completed list */
+ down->head = head;
+ } /* end for */
+
+ /* Indicate that there is a pointer to this tree */
+ down->count = 1;
+
+ /* Success! Return the head of the list in the slowest changing dimension */
+ ret_value = down;
+
+done:
+ /* cleanup if error (ret_value will be NULL) */
+ if(!ret_value) {
+ if(head || down) {
+ if(head && down)
+ if(down->head != head)
+ down = NULL;
+
+ do {
+ if(down) {
+ head = down->head;
+ down = H5FL_FREE(H5S_hyper_span_info_t, down);
+ } /* end if */
+ down = head->down;
+
+ while(head) {
+ last_span = head->next;
+ head = H5FL_FREE(H5S_hyper_span_t, head);
+ head = last_span;
+ } /* end while */
+ } while(down);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_make_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_rebuild_helper
+ PURPOSE
+ Helper routine to rebuild optimized hyperslab information if possible.
+ (It can be recovered with regular selection)
+ USAGE
+ herr_t H5S_hyper_rebuild_helper(space)
+ const H5S_hyper_span_t *span; IN: Portion of span tree to check
+ H5S_hyper_dim_t span_slab[]; OUT: Rebuilt section of hyperslab description
+ unsigned rank; IN: Current dimension to work on
+ RETURNS
+ >=0 on success, <0 on failure
+ DESCRIPTION
+ Examine the span tree for a hyperslab selection and rebuild
+ the start/stride/count/block information for the selection, if possible.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ To be able to recover the optimized information, the span tree must conform
+ to span tree able to be generated from a single H5S_SELECT_SET operation.
+
+ EXAMPLES
+ REVISION LOG
+ KY, 2005/9/22
+--------------------------------------------------------------------------*/
+static hbool_t
+H5S_hyper_rebuild_helper(const H5S_hyper_span_t *span, H5S_hyper_dim_t span_slab_info[],
+ unsigned rank)
+{
+ hsize_t curr_stride, next_stride;
+ hsize_t curr_block, next_block;
+ hsize_t curr_start;
+ hsize_t curr_low;
+ size_t outcount;
+ unsigned u;
+ H5S_hyper_dim_t canon_down_span_slab_info[H5S_MAX_RANK];
+ hbool_t ret_value = TRUE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(span) {
+ /* Initialization */
+ curr_stride = 1;
+ curr_block = 0;
+ outcount = 0;
+ curr_low = 0;
+
+ /* Get "canonical" down span information */
+ if(span->down) {
+ HDassert(span->down->head);
+
+ /* Go to the next down span and check whether the selection can be rebuilt.*/
+ if(!H5S_hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1))
+ HGOTO_DONE(FALSE)
+
+ HDmemcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank);
+ } /* end if */
+
+ /* Assign the initial starting point & block size */
+ curr_start = span->low;
+ curr_block = (span->high - span->low) + 1;
+
+ /* Loop the span */
+ while(span) {
+ if(outcount > 0) {
+ if(span->down) {
+ H5S_hyper_dim_t *curr_down_span_slab_info;
+
+ HDassert(span->down->head);
+
+ /* Go to the next down span and check whether the selection can be rebuilt.*/
+ if(!H5S_hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1))
+ HGOTO_DONE(FALSE)
+
+ /* Compare the slab information of the adjacent spans in the down span tree.
+ We have to compare all the sub-tree slab information with the canon_down_span_slab_info.*/
+
+ for( u = 0; u < rank - 1; u++) {
+ curr_down_span_slab_info = &span_slab_info[u];
+
+ if(curr_down_span_slab_info->count > 0 && canon_down_span_slab_info[u].count > 0) {
+ if(curr_down_span_slab_info->start != canon_down_span_slab_info[u].start
+ || curr_down_span_slab_info->stride != canon_down_span_slab_info[u].stride
+ || curr_down_span_slab_info->block != canon_down_span_slab_info[u].block
+ || curr_down_span_slab_info->count != canon_down_span_slab_info[u].count)
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else if (!((curr_down_span_slab_info->count == 0) && (canon_down_span_slab_info[u].count == 0)))
+ HGOTO_DONE(FALSE)
+ }
+ } /* end if */
+ } /* end if */
+
+ /* Obtain values for stride and block */
+ next_stride = span->low - curr_low;
+ next_block = (span->high - span->low) + 1;
+
+ /* Compare stride and block in this span, to compare stride,
+ * three spans are needed. Ignore the first two spans.
+ */
+ if(outcount > 1 && curr_stride != next_stride)
+ HGOTO_DONE(FALSE)
+ if(outcount != 0 && next_block != curr_block)
+ HGOTO_DONE(FALSE)
+
+ /* Keep the isolated stride to be 1 */
+ if(outcount != 0)
+ curr_stride = next_stride;
+
+ /* Keep current starting point */
+ curr_low = span->low;
+
+ /* Advance to next span */
+ span = span->next;
+ outcount++;
+ } /* end while */
+
+ /* Save the span information. */
+ span_slab_info[rank - 1].start = curr_start;
+ span_slab_info[rank - 1].count = outcount;
+ span_slab_info[rank - 1].block = curr_block;
+ span_slab_info[rank - 1].stride = curr_stride;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_rebuild_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_rebuild
+ PURPOSE
+ Rebuild optimized hyperslab information if possible.
+ (It can be recovered with regular selection)
+ USAGE
+ herr_t H5S_hyper_rebuild(space)
+ const H5S_t *space; IN: Dataspace to check
+ RETURNS
+ >=0 on success, <0 on failure
+ DESCRIPTION
+ Examine the span tree for a hyperslab selection and rebuild
+ the start/stride/count/block information for the selection, if possible.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ To be able to recover the optimized information, the span tree must conform
+ to span tree able to be generated from a single H5S_SELECT_SET operation.
+
+ EXAMPLES
+ REVISION LOG
+
+ This routine is the optimization of the old version. The previous version
+ can only detect a singluar selection. This version is general enough to
+ detect any regular selection.
+ KY, 2005/9/22
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_rebuild(H5S_t *space)
+{
+ H5S_hyper_dim_t top_span_slab_info[H5O_LAYOUT_NDIMS];
+ H5S_hyper_dim_t *diminfo;
+ H5S_hyper_dim_t *app_diminfo;
+ unsigned rank, curr_dim;
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(space->select.sel_info.hslab->span_lst);
+
+ /* Check the rank of space */
+ rank = space->extent.rank;
+
+ /* Check whether the slab can be rebuilt. Only regular selection can be rebuilt. If yes, fill in correct values.*/
+ if(!H5S_hyper_rebuild_helper(space->select.sel_info.hslab->span_lst->head, top_span_slab_info, rank)) {
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else {
+ diminfo=space->select.sel_info.hslab->opt_diminfo;
+ app_diminfo=space->select.sel_info.hslab->app_diminfo;
+
+ for(curr_dim = 0; curr_dim < rank; curr_dim++) {
+
+ app_diminfo[(rank - curr_dim) - 1].start = diminfo[(rank - curr_dim) - 1].start = top_span_slab_info[curr_dim].start;
+ app_diminfo[(rank - curr_dim) - 1].stride = diminfo[(rank - curr_dim) - 1].stride = top_span_slab_info[curr_dim].stride;
+ app_diminfo[(rank - curr_dim) - 1].count = diminfo[(rank - curr_dim) - 1].count = top_span_slab_info[curr_dim].count;
+ app_diminfo[(rank - curr_dim) - 1].block = diminfo[(rank - curr_dim) - 1].block = top_span_slab_info[curr_dim].block;
+
+ } /* end for */
+
+ space->select.sel_info.hslab->diminfo_valid = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_rebuild() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_generate_spans
+ PURPOSE
+ Create span tree for a regular hyperslab selection
+ USAGE
+ herr_t H5S_hyper_generate_spans(space)
+ H5S_t *space; IN/OUT: Pointer to dataspace
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Create a span tree representation of a regular hyperslab selection and
+ add it to the information for the hyperslab selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_generate_spans(H5S_t *space)
+{
+ hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */
+ hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */
+ unsigned u; /* Counter */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
+
+ /* Get the diminfo */
+ for(u=0; u<space->extent.rank; u++) {
+ /* Check for unlimited dimension and return error */
+ /* These should be able to be converted to assertions once everything
+ * that calls this function checks for unlimited selections first
+ * (especially the new hyperslab API) -NAF */
+ if(space->select.sel_info.hslab->opt_diminfo[u].count == H5S_UNLIMITED)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count")
+ if(space->select.sel_info.hslab->opt_diminfo[u].block == H5S_UNLIMITED)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block")
+
+ tmp_start[u]=space->select.sel_info.hslab->opt_diminfo[u].start;
+ tmp_stride[u]=space->select.sel_info.hslab->opt_diminfo[u].stride;
+ tmp_count[u]=space->select.sel_info.hslab->opt_diminfo[u].count;
+ tmp_block[u]=space->select.sel_info.hslab->opt_diminfo[u].block;
+ } /* end for */
+
+ /* Build the hyperslab information also */
+ if(H5S_generate_hyperslab (space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_hyper_generate_spans() */
+
+#ifndef NEW_HYPERSLAB_API
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_generate_hyperlab
+ *
+ * Purpose: Generate hyperslab information from H5S_select_hyperslab()
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol (split from HS_select_hyperslab()).
+ * Tuesday, September 12, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t stride[],
+ const hsize_t count[],
+ const hsize_t block[])
+{
+ H5S_hyper_span_info_t *new_spans=NULL; /* Span tree for new hyperslab */
+ H5S_hyper_span_info_t *a_not_b=NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
+ H5S_hyper_span_info_t *a_and_b=NULL; /* Span tree for hyperslab spans in both old and new span trees */
+ H5S_hyper_span_info_t *b_not_a=NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+ HDassert(start);
+ HDassert(stride);
+ HDassert(count);
+ HDassert(block);
+
+ /* Generate span tree for new hyperslab information */
+ if((new_spans=H5S_hyper_make_spans(space->extent.rank,start,stride,count,block))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information")
+
+ /* Generate list of blocks to add/remove based on selection operation */
+ if(op==H5S_SELECT_SET) {
+ /* Add new spans to current selection */
+ if(H5S_hyper_merge_spans(space,new_spans,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Set the number of elements in current selection */
+ space->select.num_elem=H5S_hyper_spans_nelem(new_spans);
+
+ /* Indicate that the new_spans are owned */
+ new_spans=NULL;
+ } /* end if */
+ else {
+ hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */
+
+ /* Generate lists of spans which overlap and don't overlap */
+ if(H5S_hyper_clip_spans(space->select.sel_info.hslab->span_lst,new_spans,&a_not_b,&a_and_b,&b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ switch(op) {
+ case H5S_SELECT_OR:
+ /* Add any new spans from b_not_a to current selection */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem+=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_AND:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ space->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
+
+ /* Check if there are any overlapped selections */
+ if(a_and_b!=NULL) {
+ if(H5S_hyper_merge_spans(space,a_and_b,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem=H5S_hyper_spans_nelem(a_and_b);
+
+ /* Indicate that the a_and_b spans are owned */
+ a_and_b=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_XOR:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ space->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
+
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b!=NULL) {
+ if(H5S_hyper_merge_spans(space,a_not_b,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem=H5S_hyper_spans_nelem(a_not_b);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem+=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTB:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ space->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
+
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b!=NULL) {
+ if(H5S_hyper_merge_spans(space,a_not_b,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem=H5S_hyper_spans_nelem(a_not_b);
+
+ /* Indicate that the a_not_b are owned */
+ a_not_b=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTA:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans")
+ space->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
+
+ /* Check if there are any non-overlapped selections */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ space->select.num_elem=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the b_not_a are owned */
+ b_not_a=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_SET:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+
+ /* Check if the resulting hyperslab span tree is empty */
+ if(space->select.sel_info.hslab->span_lst==NULL) {
+ H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */
+
+ /* Sanity check */
+ HDassert(space->select.num_elem == 0);
+
+ /* Allocate a span info node */
+ if((spans = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ spans->count=1;
+
+ /* Reset the scratch pad space */
+ spans->scratch=0;
+
+ /* Set to empty tree */
+ spans->head=NULL;
+
+ /* Set pointer to empty span tree */
+ space->select.sel_info.hslab->span_lst=spans;
+ } /* end if */
+ else {
+ /* Check if we updated the spans */
+ if(updated_spans) {
+ /* Attempt to rebuild "optimized" start/stride/count/block information.
+ * from resulting hyperslab span tree
+ */
+ if(H5S_hyper_rebuild(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info")
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+done:
+ /* Free resources */
+ if(a_not_b)
+ if(H5S_hyper_free_span_info(a_not_b) < 0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+ if(a_and_b)
+ if(H5S_hyper_free_span_info(a_and_b) < 0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+ if(b_not_a)
+ if(H5S_hyper_free_span_info(b_not_a) < 0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+ if(new_spans)
+ if(H5S_hyper_free_span_info(new_spans) < 0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_generate_hyperslab() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_hyperslab
+ *
+ * Purpose: Internal version of H5Sselect_hyperslab().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 10, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t *stride,
+ const hsize_t count[],
+ const hsize_t *block)
+{
+ hsize_t int_stride[H5O_LAYOUT_NDIMS]; /* Internal storage for stride information */
+ hsize_t int_count[H5O_LAYOUT_NDIMS]; /* Internal storage for count information */
+ hsize_t int_block[H5O_LAYOUT_NDIMS]; /* Internal storage for block information */
+ const hsize_t *opt_stride; /* Optimized stride information */
+ const hsize_t *opt_count; /* Optimized count information */
+ const hsize_t *opt_block; /* Optimized block information */
+ unsigned u; /* Counters */
+ int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+ HDassert(start);
+ HDassert(count);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+
+ /* Point to the correct stride values */
+ if(stride==NULL)
+ stride = _ones;
+
+ /* Point to the correct block values */
+ if(block==NULL)
+ block = _ones;
+
+ /* Check for unlimited dimension */
+ for(u = 0; u<space->extent.rank; u++)
+ if((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) {
+ if(unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot have more than one unlimited dimension in selection")
+ else {
+ if(count[u] == block[u] /* == H5S_UNLIMITED */)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "count and block cannot both be unlimited")
+ unlim_dim = (int)u;
+ } /* end else */
+ } /* end if */
+
+ /*
+ * Check new selection.
+ */
+ for(u=0; u<space->extent.rank; u++) {
+ /* Check for overlapping hyperslab blocks in new selection. */
+ if(count[u]>1 && stride[u]<block[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap")
+
+ /* Detect zero-sized hyperslabs in new selection */
+ if(count[u] == 0 || block[u] == 0) {
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ /* Convert to "none" selection */
+ if(H5S_select_none(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ HGOTO_DONE(SUCCEED);
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays same */
+
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ } /* end if */
+ } /* end for */
+
+ /* Optimize hyperslab parameters to merge contiguous blocks, etc. */
+ if(stride == _ones && block == _ones) {
+ /* Point to existing arrays */
+ opt_stride = _ones;
+ opt_count = _ones;
+ opt_block = count;
+ } /* end if */
+ else {
+ /* Point to local arrays */
+ opt_stride = int_stride;
+ opt_count = int_count;
+ opt_block = int_block;
+ for(u=0; u<space->extent.rank; u++) {
+ /* contiguous hyperslabs have the block size equal to the stride */
+ if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) {
+ int_count[u]=1;
+ int_stride[u]=1;
+ if(block[u]==1)
+ int_block[u]=count[u];
+ else
+ int_block[u]=block[u]*count[u];
+ } /* end if */
+ else {
+ if(count[u]==1)
+ int_stride[u]=1;
+ else {
+ HDassert((stride[u] > block[u]) || ((stride[u] == block[u])
+ && (count[u] == H5S_UNLIMITED)));
+ int_stride[u]=stride[u];
+ } /* end else */
+ int_count[u]=count[u];
+ int_block[u]=block[u];
+ } /* end else */
+ } /* end for */
+ } /* end else */
+
+ /* Check for operating on unlimited selection */
+ if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS)
+ && (space->select.sel_info.hslab->unlim_dim >= 0)
+ && (op != H5S_SELECT_SET))
+ {
+ /* Check for invalid operation */
+ if(unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection")
+ if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection")
+ HDassert(space->select.sel_info.hslab->diminfo_valid);
+
+ /* Clip unlimited selection to include new selection */
+ if(H5S_hyper_clip_unlim(space,
+ start[space->select.sel_info.hslab->unlim_dim]
+ + ((opt_count[space->select.sel_info.hslab->unlim_dim]
+ - (hsize_t)1)
+ * opt_stride[space->select.sel_info.hslab->unlim_dim])
+ + opt_block[space->select.sel_info.hslab->unlim_dim]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* If an empty space was returned it must be "none" */
+ HDassert((space->select.num_elem > (hsize_t)0)
+ || (space->select.type->type == H5S_SEL_NONE));
+ } /* end if */
+
+ /* Fixup operation for non-hyperslab selections */
+ switch(H5S_GET_SELECT_TYPE(space)) {
+ case H5S_SEL_NONE: /* No elements selected in dataspace */
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ /* Change "none" selection to hyperslab selection */
+ break;
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
+ break;
+
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays "none" */
+
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ break;
+
+ case H5S_SEL_ALL: /* All elements selected in dataspace */
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ /* Change "all" selection to hyperslab selection */
+ break;
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays "all" */
+
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
+ break;
+
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ /* Convert current "all" selection to "real" hyperslab selection */
+ /* Then allow operation to proceed */
+ {
+ hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */
+ hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */
+
+ /* Fill in temporary information for the dimensions */
+ for(u=0; u<space->extent.rank; u++) {
+ tmp_start[u]=0;
+ tmp_stride[u]=1;
+ tmp_count[u]=1;
+ tmp_block[u]=space->extent.size[u];
+ } /* end for */
+
+ /* Convert to hyperslab selection */
+ if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ } /* end case */
+ break;
+
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ /* Convert to "none" selection */
+ if(H5S_select_none(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ HGOTO_DONE(SUCCEED);
+
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ break;
+
+ case H5S_SEL_HYPERSLABS:
+ /* Hyperslab operation on hyperslab selection, OK */
+ break;
+
+ case H5S_SEL_POINTS: /* Can't combine hyperslab operations and point selections currently */
+ if(op==H5S_SELECT_SET) /* Allow only "set" operation to proceed */
+ break;
+ /* Else fall through to error */
+
+ case H5S_SEL_ERROR:
+ case H5S_SEL_N:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+
+ if(op == H5S_SELECT_SET) {
+ /* If we are setting a new selection, remove current selection first */
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Save the diminfo */
+ space->select.num_elem = 1;
+ for(u = 0; u < space->extent.rank; u++) {
+ space->select.sel_info.hslab->app_diminfo[u].start = start[u];
+ space->select.sel_info.hslab->app_diminfo[u].stride = stride[u];
+ space->select.sel_info.hslab->app_diminfo[u].count = count[u];
+ space->select.sel_info.hslab->app_diminfo[u].block = block[u];
+
+ space->select.sel_info.hslab->opt_diminfo[u].start = start[u];
+ space->select.sel_info.hslab->opt_diminfo[u].stride = opt_stride[u];
+ space->select.sel_info.hslab->opt_diminfo[u].count = opt_count[u];
+ space->select.sel_info.hslab->opt_diminfo[u].block = opt_block[u];
+
+ space->select.num_elem *= (opt_count[u] * opt_block[u]);
+ } /* end for */
+
+ /* Save unlim_dim */
+ space->select.sel_info.hslab->unlim_dim = unlim_dim;
+
+ /* Indicate that the dimension information is valid */
+ space->select.sel_info.hslab->diminfo_valid = TRUE;
+
+ /* Indicate that there's no slab information */
+ space->select.sel_info.hslab->span_lst = NULL;
+
+ /* Handle unlimited selections */
+ if(unlim_dim >= 0) {
+ /* Calculate num_elem_non_unlim */
+ space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1;
+ for(u = 0; u < space->extent.rank; u++)
+ if((int)u != unlim_dim)
+ space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]);
+
+ /* Set num_elem */
+ if(space->select.num_elem != (hsize_t)0)
+ space->select.num_elem = H5S_UNLIMITED;
+ } /* end if */
+ } /* end if */
+ else if(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) {
+ /* Sanity check */
+ HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
+
+ /* Handle unlimited selections */
+ if(unlim_dim >= 0) {
+ hsize_t bounds_start[H5S_MAX_RANK];
+ hsize_t bounds_end[H5S_MAX_RANK];
+ hsize_t tmp_count = opt_count[unlim_dim];
+ hsize_t tmp_block = opt_block[unlim_dim];
+
+ /* Check for invalid operation */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection")
+ if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation with unlimited selection")
+
+ /* Get bounds of existing selection */
+ if(H5S_hyper_bounds(space, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds")
+
+ /* Patch count and block to remove unlimited and include the
+ * existing selection */
+ H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block, bounds_end[unlim_dim] + (hsize_t)1);
+ HDassert((tmp_count == 1) || (opt_count != _ones));
+ HDassert((tmp_block == 1) || (opt_block != _ones));
+ if(opt_count != _ones) {
+ HDassert(opt_count == int_count);
+ int_count[unlim_dim] = tmp_count;
+ } /* end if */
+ if(opt_block != _ones) {
+ HDassert(opt_block == int_block);
+ int_block[unlim_dim] = tmp_block;
+ } /* end if */
+ } /* end if */
+
+ /* Check if there's no hyperslab span information currently */
+ if(NULL == space->select.sel_info.hslab->span_lst)
+ if(H5S_hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Indicate that the regular dimensions are no longer valid */
+ space->select.sel_info.hslab->diminfo_valid = FALSE;
+
+ /* Add in the new hyperslab information */
+ if(H5S_generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+
+ /* Set selection type */
+ space->select.type = H5S_sel_hyper;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_hyperslab() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_hyperslab
+ PURPOSE
+ Specify a hyperslab to combine with the current hyperslab selection
+ USAGE
+ herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ const hsize_t *start; IN: Offset of start of hyperslab
+ const hsize_t *stride; IN: Hyperslab stride
+ const hsize_t *count; IN: Number of blocks included in hyperslab
+ const hsize_t *block; IN: Size of block in hyperslab
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Combines a hyperslab selection with the current selection for a dataspace.
+ If the current selection is not a hyperslab, it is freed and the hyperslab
+ parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
+ selection composing the entire current extent). If STRIDE or BLOCK is
+ NULL, they are assumed to be set to all '1'.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(H5S_SCALAR == H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space")
+ if(H5S_NULL == H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space")
+ if(start == NULL || count == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified")
+ if(!(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ if(stride!=NULL) {
+ /* Check for 0-sized strides */
+ for(u=0; u<space->extent.rank; u++) {
+ if(stride[u]==0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value")
+ } /* end for */
+ } /* end if */
+
+ if (H5S_select_hyperslab(space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sselect_hyperslab() */
+#else /* NEW_HYPERSLAB_API */ /* Works */
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_operate_hyperslab
+ *
+ * Purpose: Combines two hyperslabs with an operation, putting the
+ * result into a third hyperslab selection
+ *
+ * Return: non-negative on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 30, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_operate_hyperslab (H5S_t *result, H5S_hyper_span_info_t *spans1, H5S_seloper_t op, H5S_hyper_span_info_t *spans2,
+ hbool_t can_own_span2, hbool_t *span2_owned)
+{
+ H5S_hyper_span_info_t *a_not_b=NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
+ H5S_hyper_span_info_t *a_and_b=NULL; /* Span tree for hyperslab spans in both old and new span trees */
+ H5S_hyper_span_info_t *b_not_a=NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(result);
+ HDassert(spans2);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+
+ /* Just copy the selection from spans2 if we are setting the selection */
+ /* ('space1' to 'result' aliasing happens at the next layer up) */
+ if(op==H5S_SELECT_SET) {
+ if(H5S_hyper_merge_spans(result,spans2,can_own_span2)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(spans2);
+
+ /* Indicate that we took ownership of span2, if allowed */
+ if(can_own_span2)
+ *span2_owned=TRUE;
+ } /* end if */
+ else {
+ hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */
+
+ HDassert(spans1);
+
+ /* Generate lists of spans which overlap and don't overlap */
+ if(H5S_hyper_clip_spans(spans1,spans2,&a_not_b,&a_and_b,&b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Switch on the operation */
+ switch(op) {
+ case H5S_SELECT_OR:
+ /* Copy spans from spans1 to current selection */
+ if(spans1!=NULL) {
+ if(H5S_hyper_merge_spans(result,spans1,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(spans1);
+ } /* end if */
+
+ /* Add any new spans from spans2 to current selection */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(result,b_not_a,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem+=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_AND:
+ /* Check if there are any overlapped selections */
+ if(a_and_b!=NULL) {
+ if(H5S_hyper_merge_spans(result,a_and_b,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(a_and_b);
+
+ /* Indicate that the result owns the a_and_b spans */
+ a_and_b=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_XOR:
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b!=NULL) {
+ if(H5S_hyper_merge_spans(result,a_not_b,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(a_not_b);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(result,b_not_a,FALSE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem+=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTB:
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b!=NULL) {
+ if(H5S_hyper_merge_spans(result,a_not_b,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(a_not_b);
+
+ /* Indicate that the result owns the a_not_b spans */
+ a_not_b=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTA:
+ /* Check if there are any non-overlapped selections */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(result,b_not_a,TRUE)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ result->select.num_elem=H5S_hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the result owns the b_not_a spans */
+ b_not_a=NULL;
+
+ /* Indicate that the spans were updated */
+ updated_spans = TRUE;
+ } /* end if */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+
+ /* Free the hyperslab trees generated from the clipping algorithm */
+ if(a_not_b)
+ H5S_hyper_free_span_info(a_not_b);
+ if(a_and_b)
+ H5S_hyper_free_span_info(a_and_b);
+ if(b_not_a)
+ H5S_hyper_free_span_info(b_not_a);
+
+ /* Check if the resulting hyperslab span tree is empty */
+ if(result->select.sel_info.hslab->span_lst==NULL) {
+ H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */
+
+ /* Sanity check */
+ HDassert(result->select.num_elem == 0);
+
+ /* Allocate a span info node */
+ if((spans = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ spans->count=1;
+
+ /* Reset the scratch pad space */
+ spans->scratch=0;
+
+ /* Set to empty tree */
+ spans->head=NULL;
+
+ /* Set pointer to empty span tree */
+ result->select.sel_info.hslab->span_lst=spans;
+ } /* end if */
+ else {
+ /* Check if we updated the spans */
+ if(updated_spans) {
+ /* Attempt to rebuild "optimized" start/stride/count/block information.
+ * from resulting hyperslab span tree
+ */
+ if(H5S_hyper_rebuild(result) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info")
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_operate_hyperslab() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_generate_hyperlab
+ *
+ * Purpose: Generate hyperslab information from H5S_select_hyperslab()
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol (split from HS_select_hyperslab()).
+ * Tuesday, September 12, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t stride[],
+ const hsize_t count[],
+ const hsize_t block[])
+{
+ H5S_hyper_span_info_t *new_spans=NULL; /* Span tree for new hyperslab */
+ H5S_hyper_span_info_t *tmp_spans=NULL; /* Temporary copy of selection */
+ hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+ HDassert(start);
+ HDassert(stride);
+ HDassert(count);
+ HDassert(block);
+
+ /* Generate span tree for new hyperslab information */
+ if((new_spans=H5S_hyper_make_spans(space->extent.rank,start,stride,count,block))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information")
+
+ /* Copy the original dataspace */
+ if(space->select.sel_info.hslab->span_lst!=NULL) {
+ /* Take ownership of the dataspace's hyperslab spans */
+ /* (These are freed later) */
+ tmp_spans=space->select.sel_info.hslab->span_lst;
+ space->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the other dataspace selection information */
+ if(H5S_SELECT_RELEASE(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if((space->select.sel_info.hslab=H5FL_MALLOC(H5S_hyper_sel_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set unlim_dim */
+ space->select.sel_info.hslab->unlim_dim = -1;
+ } /* end if */
+
+ /* Combine tmp_space (really space) & new_space, with the result in space */
+ if(H5S_operate_hyperslab(space,tmp_spans,op,new_spans,TRUE,&span2_owned)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+done:
+ /* Free temporary data structures */
+ if(tmp_spans!=NULL)
+ if(H5S_hyper_free_span_info(tmp_spans)<0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+ if(new_spans!=NULL && span2_owned==FALSE)
+ if(H5S_hyper_free_span_info(new_spans)<0)
+ HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_generate_hyperslab() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_hyperslab
+ *
+ * Purpose: Internal version of H5Sselect_hyperslab().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, January 10, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t *stride,
+ const hsize_t count[],
+ const hsize_t *block)
+{
+ hsize_t int_stride[H5O_LAYOUT_NDIMS]; /* Internal storage for stride information */
+ hsize_t int_count[H5O_LAYOUT_NDIMS]; /* Internal storage for count information */
+ hsize_t int_block[H5O_LAYOUT_NDIMS]; /* Internal storage for block information */
+ const hsize_t *opt_stride; /* Optimized stride information */
+ const hsize_t *opt_count; /* Optimized count information */
+ const hsize_t *opt_block; /* Optimized block information */
+ unsigned u; /* Counters */
+ int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+ HDassert(start);
+ HDassert(count);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+
+ /* Point to the correct stride values */
+ if(stride==NULL)
+ stride = _ones;
+
+ /* Point to the correct block values */
+ if(block==NULL)
+ block = _ones;
+
+ /* Check for unlimited dimension */
+ for(u = 0; u<space->extent.rank; u++)
+ if((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) {
+ if(unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot have more than one unlimited dimension in selection")
+ else {
+ if(count[u] == block[u] /* == H5S_UNLIMITED */)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "count and block cannot both be unlimited")
+ unlim_dim = (int)u;
+ } /* end else */
+ } /* end if */
+
+ /*
+ * Check new selection.
+ */
+ for(u=0; u<space->extent.rank; u++) {
+ /* Check for overlapping hyperslab blocks in new selection. */
+ if(count[u]>1 && stride[u]<block[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap")
+
+ /* Detect zero-sized hyperslabs in new selection */
+ if(count[u] == 0 || block[u] == 0) {
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ /* Convert to "none" selection */
+ if(H5S_select_none(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ HGOTO_DONE(SUCCEED);
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays same */
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ } /* end if */
+ } /* end for */
+
+ /* Optimize hyperslab parameters to merge contiguous blocks, etc. */
+ if(stride == _ones && block == _ones) {
+ /* Point to existing arrays */
+ opt_stride = _ones;
+ opt_count = _ones;
+ opt_block = count;
+ } /* end if */
+ else {
+ /* Point to local arrays */
+ opt_stride = int_stride;
+ opt_count = int_count;
+ opt_block = int_block;
+ for(u=0; u<space->extent.rank; u++) {
+ /* contiguous hyperslabs have the block size equal to the stride */
+ if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) {
+ int_count[u]=1;
+ int_stride[u]=1;
+ if(block[u]==1)
+ int_block[u]=count[u];
+ else
+ int_block[u]=block[u]*count[u];
+ } /* end if */
+ else {
+ if(count[u]==1)
+ int_stride[u]=1;
+ else {
+ HDassert((stride[u] > block[u]) || ((stride[u] == block[u])
+ && (count[u] == H5S_UNLIMITED)));
+ int_stride[u]=stride[u];
+ } /* end else */
+ int_count[u]=count[u];
+ int_block[u]=block[u];
+ } /* end else */
+ } /* end for */
+ } /* end else */
+
+ /* Check for operating on unlimited selection */
+ if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS)
+ && (space->select.sel_info.hslab->unlim_dim >= 0)
+ && (op != H5S_SELECT_SET))
+ {
+ /* Check for invalid operation */
+ if(unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection")
+ if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection")
+ HDassert(space->select.sel_info.hslab->diminfo_valid);
+
+ /* Clip unlimited selection to include new selection */
+ if(H5S_hyper_clip_unlim(space,
+ start[space->select.sel_info.hslab->unlim_dim]
+ + ((opt_count[space->select.sel_info.hslab->unlim_dim]
+ - (hsize_t)1)
+ * opt_stride[space->select.sel_info.hslab->unlim_dim])
+ + opt_block[space->select.sel_info.hslab->unlim_dim]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection")
+
+ /* If an empty space was returned it must be "none" */
+ HDassert((space->select.num_elem > (hsize_t)0)
+ || (space->select.type->type == H5S_SEL_NONE));
+ } /* end if */
+
+ /* Fixup operation for non-hyperslab selections */
+ switch(H5S_GET_SELECT_TYPE(space)) {
+ case H5S_SEL_NONE: /* No elements selected in dataspace */
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ /* Change "none" selection to hyperslab selection */
+ break;
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
+ break;
+
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays "none" */
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ break;
+
+ case H5S_SEL_ALL: /* All elements selected in dataspace */
+ switch(op) {
+ case H5S_SELECT_SET: /* Select "set" operation */
+ /* Change "all" selection to hyperslab selection */
+ break;
+
+ case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
+ HGOTO_DONE(SUCCEED); /* Selection stays "all" */
+
+ case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */
+ op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
+ break;
+
+ case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
+ case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ /* Convert current "all" selection to "real" hyperslab selection */
+ /* Then allow operation to proceed */
+ {
+ hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */
+ hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */
+
+ /* Fill in temporary information for the dimensions */
+ for(u=0; u<space->extent.rank; u++) {
+ tmp_start[u]=0;
+ tmp_stride[u]=1;
+ tmp_count[u]=1;
+ tmp_block[u]=space->extent.size[u];
+ } /* end for */
+
+ /* Convert to hyperslab selection */
+ if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ } /* end case */
+ break;
+
+ case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
+ /* Convert to "none" selection */
+ if(H5S_select_none(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ HGOTO_DONE(SUCCEED);
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+ break;
+
+ case H5S_SEL_HYPERSLABS:
+ /* Hyperslab operation on hyperslab selection, OK */
+ break;
+
+ case H5S_SEL_POINTS: /* Can't combine hyperslab operations and point selections currently */
+ if(op==H5S_SELECT_SET) /* Allow only "set" operation to proceed */
+ break;
+ /* Else fall through to error */
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+
+
+ if(op==H5S_SELECT_SET) {
+ /* If we are setting a new selection, remove current selection first */
+ if(H5S_SELECT_RELEASE(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release hyperslab")
+
+ /* Allocate space for the hyperslab selection information */
+ if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Save the diminfo */
+ space->select.num_elem=1;
+ for(u=0; u<space->extent.rank; u++) {
+ space->select.sel_info.hslab->app_diminfo[u].start = start[u];
+ space->select.sel_info.hslab->app_diminfo[u].stride = stride[u];
+ space->select.sel_info.hslab->app_diminfo[u].count = count[u];
+ space->select.sel_info.hslab->app_diminfo[u].block = block[u];
+
+ space->select.sel_info.hslab->opt_diminfo[u].start = start[u];
+ space->select.sel_info.hslab->opt_diminfo[u].stride = opt_stride[u];
+ space->select.sel_info.hslab->opt_diminfo[u].count = opt_count[u];
+ space->select.sel_info.hslab->opt_diminfo[u].block = opt_block[u];
+
+ space->select.num_elem*=(opt_count[u]*opt_block[u]);
+ } /* end for */
+
+ /* Save unlim_dim */
+ space->select.sel_info.hslab->unlim_dim = unlim_dim;
+
+ /* Indicate that the dimension information is valid */
+ space->select.sel_info.hslab->diminfo_valid = TRUE;
+
+ /* Indicate that there's no slab information */
+ space->select.sel_info.hslab->span_lst = NULL;
+
+ /* Handle unlimited selections */
+ if(unlim_dim >= 0) {
+ /* Calculate num_elem_non_unlim */
+ space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1;
+ for(u = 0; u < space->extent.rank; u++)
+ if((int)u != unlim_dim)
+ space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]);
+
+ /* Set num_elem */
+ if(space->select.num_elem != (hsize_t)0)
+ space->select.num_elem = H5S_UNLIMITED;
+ } /* end if */
+ } /* end if */
+ else if(op>=H5S_SELECT_OR && op<=H5S_SELECT_NOTA) {
+ /* Sanity check */
+ HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
+
+ /* Handle unlimited selections */
+ if(unlim_dim >= 0) {
+ hsize_t bounds_start[H5S_MAX_RANK];
+ hsize_t bounds_end[H5S_MAX_RANK];
+ hsize_t tmp_count = opt_count[unlim_dim];
+ hsize_t tmp_block = opt_block[unlim_dim];
+
+ /* Check for invalid operation */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection")
+ if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation with unlimited selection")
+
+ /* Get bounds of existing selection */
+ if(H5S_hyper_bounds(space, bounds_start, bounds_end) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds")
+
+ /* Patch count and block to remove unlimited and include the
+ * existing selection */
+ H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block, bounds_end[unlim_dim] + (hsize_t)1);
+ HDassert((tmp_count == 1) || (opt_count != _ones));
+ HDassert((tmp_block == 1) || (opt_block != _ones));
+ if(opt_count != _ones) {
+ HDassert(opt_count == int_count);
+ int_count[unlim_dim] = tmp_count;
+ } /* end if */
+ if(opt_block != _ones) {
+ HDassert(opt_block == int_block);
+ int_block[unlim_dim] = tmp_block;
+ } /* end if */
+ } /* end if */
+
+ /* Check if there's no hyperslab span information currently */
+ if(NULL == space->select.sel_info.hslab->span_lst)
+ if(H5S_hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Indicate that the regular dimensions are no longer valid */
+ space->select.sel_info.hslab->diminfo_valid = FALSE;
+
+ /* Add in the new hyperslab information */
+ if(H5S_generate_hyperslab (space, op, start, opt_stride, opt_count, opt_block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+
+ /* Set selection type */
+ space->select.type = H5S_sel_hyper;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_hyperslab() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_hyperslab
+ PURPOSE
+ Specify a hyperslab to combine with the current hyperslab selection
+ USAGE
+ herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ const hsize_t *start; IN: Offset of start of hyperslab
+ const hsize_t *stride; IN: Hyperslab stride
+ const hsize_t *count; IN: Number of blocks included in hyperslab
+ const hsize_t *block; IN: Size of block in hyperslab
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Combines a hyperslab selection with the current selection for a dataspace.
+ If the current selection is not a hyperslab, it is freed and the hyperslab
+ parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
+ selection composing the entire current extent). If STRIDE or BLOCK is
+ NULL, they are assumed to be set to all '1'.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
+{
+ H5S_t *space = NULL; /* Dataspace to modify selection of */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block);
+
+ /* Check args */
+ if (NULL == (space=H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if (H5S_SCALAR==H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space")
+ if (H5S_NULL==H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space")
+ if(start==NULL || count==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified")
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ if(stride!=NULL) {
+ unsigned u; /* Local index variable */
+
+ /* Check for 0-sized strides */
+ for(u=0; u<space->extent.rank; u++) {
+ if(stride[u]==0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value")
+ } /* end for */
+ } /* end if */
+
+ if (H5S_select_hyperslab(space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sselect_hyperslab() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Scombine_hyperslab
+ PURPOSE
+ Specify a hyperslab to combine with the current hyperslab selection and
+ return a new dataspace with the combined selection as the selection in the
+ new dataspace.
+ USAGE
+ hid_t H5Srefine_hyperslab(dsid, op, start, stride, count, block)
+ hid_t dsid; IN: Dataspace ID of selection to use
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ const hsize_t *start; IN: Offset of start of hyperslab
+ const hsize_t *stride; IN: Hyperslab stride
+ const hsize_t *count; IN: Number of blocks included in hyperslab
+ const hsize_t *block; IN: Size of block in hyperslab
+ RETURNS
+ Dataspace ID on success/Negative on failure
+ DESCRIPTION
+ Combines a hyperslab selection with the current selection for a dataspace,
+ creating a new dataspace to return the generated selection.
+ If the current selection is not a hyperslab, it is freed and the hyperslab
+ parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
+ selection composing the entire current extent). If STRIDE or BLOCK is
+ NULL, they are assumed to be set to all '1'.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
+{
+ H5S_t *space = NULL; /* Dataspace to modify selection of */
+ H5S_t *new_space = NULL; /* New dataspace created */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("i", "iSs*h*h*h*h", space_id, op, start, stride, count, block);
+
+ /* Check args */
+ if (NULL == (space=H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(start==NULL || count==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified")
+
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+
+ /* Copy the first dataspace */
+ if (NULL == (new_space = H5S_copy (space, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space")
+
+ /* Go modify the selection in the new dataspace */
+ if (H5S_select_hyperslab(new_space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection")
+
+ /* Atomize */
+ if ((ret_value=H5I_register (H5I_DATASPACE, new_space, TRUE))<0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ if (ret_value<0 && new_space)
+ H5S_close(new_space);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Scombine_hyperslab() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_combine_select
+ *
+ * Purpose: Internal version of H5Scombine_select().
+ *
+ * Return: New dataspace on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 30, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5S_t *
+H5S_combine_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
+{
+ H5S_t *new_space=NULL; /* New dataspace generated */
+ hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */
+ H5S_t *ret_value; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space1);
+ HDassert(space2);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+
+ /* Check that the space selections both have span trees */
+ if(space1->select.sel_info.hslab->span_lst==NULL)
+ if(H5S_hyper_generate_spans(space1)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree")
+ if(space2->select.sel_info.hslab->span_lst==NULL)
+ if(H5S_hyper_generate_spans(space2)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree")
+
+ /* Copy the first dataspace */
+ if (NULL == (new_space = H5S_copy (space1, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space")
+
+ /* Free the current selection for the new dataspace */
+ if(H5S_SELECT_RELEASE(new_space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, NULL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if((new_space->select.sel_info.hslab=H5FL_CALLOC(H5S_hyper_sel_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab info")
+
+ /* Set unlim_dim */
+ new_space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Combine space1 & space2, with the result in new_space */
+ if(H5S_operate_hyperslab(new_space,space1->select.sel_info.hslab->span_lst,op,space2->select.sel_info.hslab->span_lst,FALSE,&span2_owned)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information")
+
+ /* Set return value */
+ ret_value=new_space;
+
+done:
+ if(ret_value==NULL && new_space!=NULL)
+ H5S_close(new_space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_combine_select() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Scombine_select
+ PURPOSE
+ Combine two hyperslab selections with an operation, returning a dataspace
+ with the resulting selection.
+ USAGE
+ hid_t H5Scombine_select(space1, op, space2)
+ hid_t space1; IN: First Dataspace ID
+ H5S_seloper_t op; IN: Selection operation
+ hid_t space2; IN: Second Dataspace ID
+ RETURNS
+ Dataspace ID on success/Negative on failure
+ DESCRIPTION
+ Combine two existing hyperslab selections with an operation, returning
+ a new dataspace with the resulting selection. The dataspace extent from
+ space1 is copied for the dataspace extent of the newly created dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
+{
+ H5S_t *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
+ H5S_t *new_space = NULL; /* New Dataspace */
+ hid_t ret_value;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iSsi", space1_id, op, space2_id);
+
+ /* Check args */
+ if (NULL == (space1=H5I_object_verify(space1_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if (NULL == (space2=H5I_object_verify(space2_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+
+ /* Check that both dataspaces have the same rank */
+ if(space1->extent.rank!=space2->extent.rank)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank")
+
+ /* Check that both dataspaces have hyperslab selections */
+ if(H5S_GET_SELECT_TYPE(space1)!=H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2)!=H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections")
+
+ /* Go combine the dataspaces */
+ if ((new_space=H5S_combine_select(space1, op, space2))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to create hyperslab selection")
+
+ /* Atomize */
+ if ((ret_value=H5I_register (H5I_DATASPACE, new_space, TRUE))<0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom")
+
+done:
+ if (ret_value<0 && new_space)
+ H5S_close(new_space);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Scombine_select() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_select
+ *
+ * Purpose: Internal version of H5Sselect_select().
+ *
+ * Return: New dataspace on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 30, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_select_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
+{
+ H5S_hyper_span_info_t *tmp_spans=NULL; /* Temporary copy of selection */
+ hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space1);
+ HDassert(space2);
+ HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+
+ /* Check that the space selections both have span trees */
+ if(space1->select.sel_info.hslab->span_lst==NULL)
+ if(H5S_hyper_generate_spans(space1)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+ if(space2->select.sel_info.hslab->span_lst==NULL)
+ if(H5S_hyper_generate_spans(space2)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Take ownership of the dataspace's hyperslab spans */
+ /* (These are freed later) */
+ tmp_spans=space1->select.sel_info.hslab->span_lst;
+ space1->select.sel_info.hslab->span_lst=NULL;
+
+ /* Reset the other dataspace selection information */
+ if(H5S_SELECT_RELEASE(space1)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if((space1->select.sel_info.hslab=H5FL_CALLOC(H5S_hyper_sel_t))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set unlim_dim */
+ space1->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Combine tmp_spans (from space1) & spans from space2, with the result in space1 */
+ if(H5S_operate_hyperslab(space1,tmp_spans,op,space2->select.sel_info.hslab->span_lst,FALSE,&span2_owned)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+done:
+ if(tmp_spans!=NULL)
+ H5S_hyper_free_span_info(tmp_spans);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_select() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_select
+ PURPOSE
+ Refine a hyperslab selection with an operation using a second hyperslab
+ to modify it.
+ USAGE
+ herr_t H5Sselect_select(space1, op, space2)
+ hid_t space1; IN/OUT: First Dataspace ID
+ H5S_seloper_t op; IN: Selection operation
+ hid_t space2; IN: Second Dataspace ID
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Refine an existing hyperslab selection with an operation, using a second
+ hyperslab. The first selection is modified to contain the result of
+ space1 operated on by space2.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
+{
+ H5S_t *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iSsi", space1_id, op, space2_id);
+
+ /* Check args */
+ if (NULL == (space1=H5I_object_verify(space1_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if (NULL == (space2=H5I_object_verify(space2_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+
+ /* Check that both dataspaces have the same rank */
+ if(space1->extent.rank!=space2->extent.rank)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank")
+
+ /* Check that both dataspaces have hyperslab selections */
+ if(H5S_GET_SELECT_TYPE(space1)!=H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2)!=H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections")
+
+ /* Go refine the first selection */
+ if (H5S_select_select(space1, op, space2)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sselect_select() */
+#endif /* NEW_HYPERSLAB_API */ /* Works */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_seq_list_gen
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_select_hyper_get_file_list_gen(space,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_get_seq_list_gen(const H5S_t *space,H5S_sel_iter_t *iter,
+ size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hsize_t loc_off; /* Element offset in the dataspace */
+ hsize_t last_span_end = 0; /* The offset of the end of the last span */
+ hsize_t *abs_arr; /* Absolute hyperslab span position */
+ const hssize_t *off_arr; /* Offset within the dataspace extent */
+ size_t span_size = 0; /* Number of bytes in current span to actually process */
+ size_t io_left; /* Number of elements left to process */
+ size_t io_bytes_left; /* Number of bytes left to process */
+ size_t io_used; /* Number of elements processed */
+ size_t curr_seq = 0; /* Number of sequence/offsets stored in the arrays */
+ size_t elem_size; /* Size of each element iterating over */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ unsigned u; /* Index variable */
+ int i; /* Index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* Set the rank of the fastest changing dimension */
+ ndims = space->extent.rank;
+ fast_dim = (ndims - 1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span = iter->u.hyp.span[fast_dim];
+ abs_arr = iter->u.hyp.off;
+ off_arr = space->select.offset;
+ ispan = iter->u.hyp.span;
+ elem_size = iter->elmt_size;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ io_left = MIN(maxelem, (size_t)iter->elmt_left);
+ io_bytes_left = io_left * elem_size;
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) {
+ slab[i] = acc;
+ acc *= space->extent.size[i];
+ } /* end for */
+
+ /* Set the offset of the first element iterated on */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ /* Compute the sequential element offset */
+ loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u];
+
+ /* Range check against number of elements left in selection */
+ HDassert(io_bytes_left <= (iter->elmt_left * elem_size));
+
+ /* Take care of any partial spans leftover from previous I/Os */
+ if(abs_arr[fast_dim]!=curr_span->low) {
+
+ /* Finish the span in the fastest changing dimension */
+
+ /* Compute the number of bytes to attempt in this span */
+ H5_CHECKED_ASSIGN(span_size, size_t, ((curr_span->high-abs_arr[fast_dim])+1)*elem_size, hsize_t);
+
+ /* Check number of bytes against upper bounds allowed */
+ if(span_size>io_bytes_left)
+ span_size=io_bytes_left;
+
+ /* Add the partial span to the list of sequences */
+ off[curr_seq]=loc_off;
+ len[curr_seq]=span_size;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Set the location of the last span's end */
+ last_span_end=loc_off+span_size;
+
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
+
+ /* Advance the hyperslab iterator */
+ /* Check if we are done */
+ if(io_bytes_left > 0) {
+ /* Move to next span in fastest changing dimension */
+ curr_span = curr_span->next;
+
+ if(NULL != curr_span) {
+ /* Move location offset of destination */
+ loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size;
+
+ /* Move iterator for fastest changing dimension */
+ abs_arr[fast_dim] = curr_span->low;
+ } /* end if */
+ } /* end if */
+ else {
+ abs_arr[fast_dim] += span_size / elem_size;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim] <= curr_span->high) {
+ iter->u.hyp.span[fast_dim] = curr_span;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(NULL != curr_span) {
+ /* Reset absolute position */
+ abs_arr[fast_dim] = curr_span->low;
+ iter->u.hyp.span[fast_dim] = curr_span;
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+ /* Adjust iterator pointers */
+
+ if(NULL == curr_span) {
+/* Same as code in main loop */
+ /* Start at the next fastest dim */
+ curr_dim = (int)(fast_dim - 1);
+
+ /* Work back up through the dimensions */
+ while(curr_dim >= 0) {
+ /* Reset the current span */
+ curr_span = iter->u.hyp.span[curr_dim];
+
+ /* Increment absolute position */
+ abs_arr[curr_dim]++;
+
+ /* Check if we are still within the span */
+ if(abs_arr[curr_dim] <= curr_span->high) {
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(NULL != curr_span) {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim] = curr_span;
+
+ /* Reset absolute position */
+ abs_arr[curr_dim] = curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we have more spans in the tree */
+ if(curr_dim >= 0) {
+ /* Walk back down the iterator positions, reseting them */
+ while((unsigned)curr_dim < fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* Increment current dimension */
+ curr_dim++;
+
+ /* Set the new span_info & span for this dimension */
+ iter->u.hyp.span[curr_dim] = curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span = curr_span->down->head;
+
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim] = curr_span->low;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span == iter->u.hyp.span[fast_dim]);
+
+ /* Reset the buffer offset */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u];
+ } /* end else */
+ else
+ /* We had better be done with I/O or bad things are going to happen... */
+ HDassert(io_bytes_left == 0);
+ } /* end if */
+ } /* end if */
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_bytes_left > 0 && curr_seq < maxseq) {
+ /* Sanity check */
+ HDassert(curr_span);
+
+ /* Adjust location offset of destination to compensate for initial increment below */
+ loc_off -= curr_span->pstride;
+
+ /* Loop over all the spans in the fastest changing dimension */
+ while(curr_span != NULL) {
+ /* Move location offset of destination */
+ loc_off += curr_span->pstride;
+
+ /* Compute the number of elements to attempt in this span */
+ H5_CHECKED_ASSIGN(span_size, size_t, curr_span->nelem, hsize_t);
+
+ /* Check number of elements against upper bounds allowed */
+ if(span_size >= io_bytes_left) {
+ /* Trim the number of bytes to output */
+ span_size = io_bytes_left;
+ io_bytes_left = 0;
+
+/* COMMON */
+ /* Store the I/O information for the span */
+
+ /* Check if this is appending onto previous sequence */
+ if(curr_seq > 0 && last_span_end == loc_off)
+ len[curr_seq - 1] += span_size;
+ else {
+ off[curr_seq] = loc_off;
+ len[curr_seq] = span_size;
+
+ /* Increment the number of sequences in arrays */
+ curr_seq++;
+ } /* end else */
+
+ /* Set the location of the last span's end */
+ last_span_end = loc_off + span_size;
+/* end COMMON */
+
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ io_bytes_left -= span_size;
+
+/* COMMON */
+ /* Store the I/O information for the span */
+
+ /* Check if this is appending onto previous sequence */
+ if(curr_seq > 0 && last_span_end == loc_off)
+ len[curr_seq-1]+=span_size;
+ else {
+ off[curr_seq] = loc_off;
+ len[curr_seq] = span_size;
+
+ /* Increment the number of sequences in arrays */
+ curr_seq++;
+ } /* end else */
+
+ /* Set the location of the last span's end */
+ last_span_end = loc_off + span_size;
+/* end COMMON */
+
+ /* If the sequence & offset arrays are full, do what? */
+ if(curr_seq >= maxseq) {
+ /* Break out now, we are finished with sequences */
+ break;
+ } /* end else */
+ } /* end else */
+
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+ } /* end while */
+
+ /* Check if we are done */
+ if(io_bytes_left==0 || curr_seq>=maxseq) {
+ HDassert(curr_span);
+ abs_arr[fast_dim]=curr_span->low+(span_size/elem_size);
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->u.hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset absolute position */
+ abs_arr[fast_dim]=curr_span->low;
+ iter->u.hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Adjust iterator pointers */
+
+ /* Start at the next fastest dim */
+ curr_dim = (int)(fast_dim - 1);
+
+ /* Work back up through the dimensions */
+ while(curr_dim >= 0) {
+ /* Reset the current span */
+ curr_span=iter->u.hyp.span[curr_dim];
+
+ /* Increment absolute position */
+ abs_arr[curr_dim]++;
+
+ /* Check if we are still within the span */
+ if(abs_arr[curr_dim]<=curr_span->high) {
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Reset absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim < 0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ HDassert(io_bytes_left == 0);
+ break;
+ } /* end if */
+ else {
+ /* Walk back down the iterator positions, reseting them */
+ while((unsigned)curr_dim < fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* Increment current dimension to the next dimension down */
+ curr_dim++;
+
+ /* Set the new span for the next dimension down */
+ iter->u.hyp.span[curr_dim] = curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span = curr_span->down->head;
+
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim] = curr_span->low;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span == iter->u.hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u];
+ } /* end while */
+
+ /* Decrement number of elements left in iterator */
+ io_used = (io_left - (io_bytes_left / elem_size));
+ iter->elmt_left -= io_used;
+
+ /* Set the number of sequences generated */
+ *nseq = curr_seq;
+
+ /* Set the number of elements used */
+ *nelem = io_used;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_hyper_get_seq_list_gen() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_seq_list_opt
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_select_hyper_get_file_list_opt(space,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_get_seq_list_opt(const H5S_t *space, H5S_sel_iter_t *iter,
+ size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ hsize_t *mem_size; /* Size of the source buffer */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ hsize_t offset[H5O_LAYOUT_NDIMS]; /* Coordinate offset in dataspace */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS];/* Temporary block count */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS];/* Temporary block offset */
+ hsize_t wrap[H5O_LAYOUT_NDIMS]; /* Bytes to wrap around at the end of a row */
+ hsize_t skip[H5O_LAYOUT_NDIMS]; /* Bytes to skip between blocks */
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ hsize_t fast_dim_start, /* Local copies of fastest changing dimension info */
+ fast_dim_stride,
+ fast_dim_block,
+ fast_dim_offset;
+ size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */
+ size_t fast_dim_count; /* Number of blocks left in fastest changing dimension */
+ size_t tot_blk_count; /* Total number of blocks left to output */
+ size_t act_blk_count; /* Actual number of blocks to output */
+ size_t total_rows; /* Total number of entire rows to output */
+ size_t curr_rows; /* Current number of entire rows to output */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned ndims; /* Number of dimensions of dataset */
+ int temp_dim; /* Temporary rank holder */
+ hsize_t acc; /* Accumulator */
+ hsize_t loc; /* Coordinate offset */
+ size_t curr_seq = 0; /* Current sequence being operated on */
+ size_t actual_elem; /* The actual number of elements to count */
+ size_t actual_bytes;/* The actual number of bytes to copy */
+ size_t io_left; /* The number of elements left in I/O operation */
+ size_t start_io_left; /* The initial number of elements left in I/O operation */
+ size_t elem_size; /* Size of each element iterating over */
+ unsigned u; /* Local index variable */
+ int i; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* Set the local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
+ fast_dim = ndims - 1;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = iter->u.hyp.size;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = space->extent.rank;
+ fast_dim = ndims - 1;
+
+ /* Set the local copy of the selection offset */
+ sel_off = space->select.offset;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = space->extent.size;
+ } /* end else */
+
+ /* initialize row sizes for each dimension */
+ elem_size = iter->elmt_size;
+ for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) {
+ slab[i] = acc;
+ acc *= mem_size[i];
+ } /* end for */
+
+ /* Calculate the number of elements to sequence through */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ io_left = MIN((size_t)iter->elmt_left, maxelem);
+
+ /* Sanity check that there aren't any "remainder" sequences in process */
+ HDassert(!((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
+ ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)));
+
+ /* We've cleared the "remainder" of the previous fastest dimension
+ * sequence before calling this routine, so we must be at the beginning of
+ * a sequence. Use the fancy algorithm to compute the offsets and run
+ * through as many as possible, until the buffer fills up.
+ */
+
+ /* Keep the number of elements we started with */
+ start_io_left = io_left;
+
+ /* Compute the arrays to perform I/O on */
+
+ /* Copy the location of the point to get */
+ /* (Add in the selection offset) */
+ for(u = 0; u < ndims; u++)
+ offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]);
+
+ /* Compute the current "counts" for this location */
+ for(u = 0; u < ndims; u++) {
+ if(tdiminfo[u].count == 1) {
+ tmp_count[u] = 0;
+ tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
+ } /* end if */
+ else {
+ tmp_count[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride;
+ tmp_block[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride;
+ } /* end else */
+ } /* end for */
+
+ /* Compute the initial buffer offset */
+ for(u = 0, loc = 0; u < ndims; u++)
+ loc += offset[u] * slab[u];
+
+ /* Set the number of elements to write each time */
+ H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t);
+
+ /* Set the number of actual bytes */
+ actual_bytes = actual_elem * elem_size;
+
+ /* Set local copies of information for the fastest changing dimension */
+ fast_dim_start = tdiminfo[fast_dim].start;
+ fast_dim_stride = tdiminfo[fast_dim].stride;
+ fast_dim_block = tdiminfo[fast_dim].block;
+ H5_CHECKED_ASSIGN(fast_dim_buf_off, size_t, slab[fast_dim] * fast_dim_stride, hsize_t);
+ fast_dim_offset = (hsize_t)((hssize_t)fast_dim_start + sel_off[fast_dim]);
+
+ /* Compute the number of blocks which would fit into the buffer */
+ H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t);
+ tot_blk_count = (size_t)(io_left / fast_dim_block);
+
+ /* Don't go over the maximum number of sequences allowed */
+ tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq));
+
+ /* Compute the amount to wrap at the end of each row */
+ for(u = 0; u < ndims; u++)
+ wrap[u] = (mem_size[u] - (tdiminfo[u].stride * tdiminfo[u].count)) * slab[u];
+
+ /* Compute the amount to skip between blocks */
+ for(u = 0; u < ndims; u++)
+ skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u];
+
+ /* Check if there is a partial row left (with full blocks) */
+ if(tmp_count[fast_dim] > 0) {
+ /* Get number of blocks in fastest dimension */
+ H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count - tmp_count[fast_dim], hsize_t);
+
+ /* Make certain this entire row will fit into buffer */
+ fast_dim_count = MIN(fast_dim_count, tot_blk_count);
+
+ /* Number of blocks to sequence over */
+ act_blk_count = fast_dim_count;
+
+ /* Loop over all the blocks in the fastest changing dimension */
+ while(fast_dim_count > 0) {
+ /* Store the sequence information */
+ off[curr_seq] = loc;
+ len[curr_seq] = actual_bytes;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Increment information to reflect block just processed */
+ loc += fast_dim_buf_off;
+
+ /* Decrement number of blocks */
+ fast_dim_count--;
+ } /* end while */
+
+ /* Decrement number of elements left */
+ io_left -= actual_elem * act_blk_count;
+
+ /* Decrement number of blocks left */
+ tot_blk_count -= act_blk_count;
+
+ /* Increment information to reflect block just processed */
+ tmp_count[fast_dim] += act_blk_count;
+
+ /* Check if we finished the entire row of blocks */
+ if(tmp_count[fast_dim] >= tdiminfo[fast_dim].count) {
+ /* Increment offset in destination buffer */
+ loc += wrap[fast_dim];
+
+ /* Increment information to reflect block just processed */
+ offset[fast_dim] = fast_dim_offset; /* reset the offset in the fastest dimension */
+ tmp_count[fast_dim] = 0;
+
+ /* Increment the offset and count for the other dimensions */
+ temp_dim = (int)fast_dim - 1;
+ while(temp_dim >= 0) {
+ /* Move to the next row in the curent dimension */
+ offset[temp_dim]++;
+ tmp_block[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
+ loc += skip[temp_dim];
+ tmp_block[temp_dim] = 0;
+ tmp_count[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_count[temp_dim] < tdiminfo[temp_dim].count)
+ break;
+ else {
+ offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]);
+ loc += wrap[temp_dim];
+ tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */
+ tmp_block[temp_dim] = 0;
+ } /* end else */
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+ } /* end if */
+ else {
+ /* Update the offset in the fastest dimension */
+ offset[fast_dim] += (fast_dim_stride * act_blk_count);
+ } /* end else */
+ } /* end if */
+
+ /* Compute the number of entire rows to read in */
+ H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t);
+ curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count);
+
+ /* Reset copy of number of blocks in fastest dimension */
+ H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t);
+
+ /* Read in data until an entire sequence can't be written out any longer */
+ while(curr_rows > 0) {
+
+#define DUFF_GUTS \
+/* Store the sequence information */ \
+off[curr_seq] = loc; \
+len[curr_seq] = actual_bytes; \
+ \
+/* Increment sequence count */ \
+curr_seq++; \
+ \
+/* Increment information to reflect block just processed */ \
+loc += fast_dim_buf_off;
+
+#ifdef NO_DUFFS_DEVICE
+ /* Loop over all the blocks in the fastest changing dimension */
+ while(fast_dim_count > 0) {
+ DUFF_GUTS
+
+ /* Decrement number of blocks */
+ fast_dim_count--;
+ } /* end while */
+#else /* NO_DUFFS_DEVICE */
+ {
+ size_t duffs_index; /* Counting index for Duff's device */
+
+ duffs_index = (fast_dim_count + 7) / 8;
+ switch (fast_dim_count % 8) {
+ default:
+ HDassert(0 && "This Should never be executed!");
+ break;
+ case 0:
+ do
+ {
+ DUFF_GUTS
+ case 7:
+ DUFF_GUTS
+ case 6:
+ DUFF_GUTS
+ case 5:
+ DUFF_GUTS
+ case 4:
+ DUFF_GUTS
+ case 3:
+ DUFF_GUTS
+ case 2:
+ DUFF_GUTS
+ case 1:
+ DUFF_GUTS
+ } while (--duffs_index > 0);
+ } /* end switch */
+ }
+#endif /* NO_DUFFS_DEVICE */
+#undef DUFF_GUTS
+
+ /* Increment offset in destination buffer */
+ loc += wrap[fast_dim];
+
+ /* Increment the offset and count for the other dimensions */
+ temp_dim = (int)fast_dim - 1;
+ while(temp_dim >= 0) {
+ /* Move to the next row in the curent dimension */
+ offset[temp_dim]++;
+ tmp_block[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
+ loc += skip[temp_dim];
+ tmp_block[temp_dim] = 0;
+ tmp_count[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_count[temp_dim] < tdiminfo[temp_dim].count)
+ break;
+ else {
+ offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]);
+ loc += wrap[temp_dim];
+ tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */
+ tmp_block[temp_dim] = 0;
+ } /* end else */
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+
+ /* Decrement the number of rows left */
+ curr_rows--;
+ } /* end while */
+
+ /* Adjust the number of blocks & elements left to transfer */
+
+ /* Decrement number of elements left */
+ H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
+ io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count));
+
+ /* Decrement number of blocks left */
+ H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
+ tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count);
+
+ /* Read in partial row of blocks */
+ if(io_left > 0 && curr_seq < maxseq) {
+ /* Get remaining number of blocks left to output */
+ fast_dim_count = tot_blk_count;
+
+ /* Loop over all the blocks in the fastest changing dimension */
+ while(fast_dim_count > 0) {
+ /* Store the sequence information */
+ off[curr_seq] = loc;
+ len[curr_seq] = actual_bytes;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Increment information to reflect block just processed */
+ loc += fast_dim_buf_off;
+
+ /* Decrement number of blocks */
+ fast_dim_count--;
+ } /* end while */
+
+ /* Decrement number of elements left */
+ io_left -= actual_elem * tot_blk_count;
+
+ /* Increment information to reflect block just processed */
+ offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */
+
+ /* Handle any leftover, partial blocks in this row */
+ if(io_left > 0 && curr_seq < maxseq) {
+ actual_elem = io_left;
+ actual_bytes = actual_elem * elem_size;
+
+ /* Store the sequence information */
+ off[curr_seq] = loc;
+ len[curr_seq] = actual_bytes;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Decrement the number of elements left */
+ io_left -= actual_elem;
+
+ /* Increment buffer correctly */
+ offset[fast_dim] += actual_elem;
+ } /* end if */
+
+ /* don't bother checking slower dimensions */
+ HDassert(io_left == 0 || curr_seq == maxseq);
+ } /* end if */
+
+ /* Update the iterator */
+
+ /* Update the iterator with the location we stopped */
+ /* (Subtract out the selection offset) */
+ for(u = 0; u < ndims; u++)
+ iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= (start_io_left - io_left);
+
+ /* Increment the number of sequences generated */
+ *nseq += curr_seq;
+
+ /* Increment the number of elements used */
+ *nelem += start_io_left - io_left;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_hyper_get_seq_list_opt() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_seq_list_single
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_hyper_get_seq_list_single(space, flags, iter, maxseq, maxelem, nseq, nelem, off, len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_get_seq_list_single(const H5S_t *space, H5S_sel_iter_t *iter,
+ size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ hsize_t *mem_size; /* Size of the source buffer */
+ hsize_t base_offset[H5O_LAYOUT_NDIMS]; /* Base coordinate offset in dataspace */
+ hsize_t offset[H5O_LAYOUT_NDIMS]; /* Coordinate offset in dataspace */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */
+ hsize_t fast_dim_block; /* Local copies of fastest changing dimension info */
+ hsize_t acc; /* Accumulator */
+ hsize_t loc; /* Coordinate offset */
+ size_t tot_blk_count; /* Total number of blocks left to output */
+ size_t elem_size; /* Size of each element iterating over */
+ size_t io_left; /* The number of elements left in I/O operation */
+ size_t actual_elem; /* The actual number of elements to count */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned skip_dim; /* Rank of the dimension to skip along */
+ unsigned u; /* Local index variable */
+ int i; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* Set a local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = iter->u.hyp.size;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = space->extent.rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = space->select.offset;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = space->extent.size;
+ } /* end else */
+ fast_dim = ndims - 1;
+
+ /* initialize row sizes for each dimension */
+ elem_size = iter->elmt_size;
+ for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) {
+ slab[i] = acc;
+ acc *= mem_size[i];
+ } /* end for */
+
+ /* Copy the base location of the block */
+ /* (Add in the selection offset) */
+ for(u = 0; u < ndims; u++)
+ base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]);
+
+ /* Copy the location of the point to get */
+ /* (Add in the selection offset) */
+ for(u = 0; u < ndims; u++)
+ offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]);
+
+ /* Compute the initial buffer offset */
+ for(u = 0, loc = 0; u < ndims; u++)
+ loc += offset[u] * slab[u];
+
+ /* Set local copies of information for the fastest changing dimension */
+ fast_dim_block = tdiminfo[fast_dim].block;
+
+ /* Calculate the number of elements to sequence through */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ io_left = MIN((size_t)iter->elmt_left, maxelem);
+
+ /* Compute the number of blocks which would fit into the buffer */
+ H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t);
+ tot_blk_count = (size_t)(io_left / fast_dim_block);
+
+ /* Don't go over the maximum number of sequences allowed */
+ tot_blk_count = MIN(tot_blk_count, maxseq);
+
+ /* Set the number of elements to write each time */
+ H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t);
+
+ /* Check for blocks to operate on */
+ if(tot_blk_count > 0) {
+ size_t actual_bytes; /* The actual number of bytes to copy */
+
+ /* Set the number of actual bytes */
+ actual_bytes = actual_elem * elem_size;
+
+ /* Check for 1-dim selection */
+ if(0 == fast_dim) {
+ /* Sanity checks */
+ HDassert(1 == tot_blk_count);
+ HDassert(io_left == actual_elem);
+
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+ } /* end if */
+ else {
+ hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */
+ size_t blk_count; /* Total number of blocks left to output */
+
+ /* Find first dimension w/block >1 */
+ skip_dim = fast_dim;
+ for(i = (int)(fast_dim - 1); i >= 0; i--)
+ if(tdiminfo[i].block > 1) {
+ skip_dim = (unsigned)i;
+ break;
+ } /* end if */
+ skip_slab = slab[skip_dim];
+
+ /* Check for being able to use fast algorithm for 1-D */
+ if(0 == skip_dim) {
+ /* Create sequences until an entire row can't be used */
+ blk_count = tot_blk_count;
+ while(blk_count > 0) {
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+
+ /* Increment offset in destination buffer */
+ loc += skip_slab;
+
+ /* Decrement block count */
+ blk_count--;
+ } /* end while */
+
+ /* Move to the next location */
+ offset[skip_dim] += tot_blk_count;
+ } /* end if */
+ else {
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS];/* Temporary block offset */
+ hsize_t skip[H5O_LAYOUT_NDIMS]; /* Bytes to skip between blocks */
+ int temp_dim; /* Temporary rank holder */
+
+ /* Set the starting block location */
+ for(u = 0; u < ndims; u++)
+ tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
+
+ /* Compute the amount to skip between sequences */
+ for(u = 0; u < ndims; u++)
+ skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u];
+
+ /* Create sequences until an entire row can't be used */
+ blk_count = tot_blk_count;
+ while(blk_count > 0) {
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+
+ /* Set temporary dimension for advancing offsets */
+ temp_dim = (int)skip_dim;
+
+ /* Increment offset in destination buffer */
+ loc += skip_slab;
+
+ /* Increment the offset and count for the other dimensions */
+ while(temp_dim >= 0) {
+ /* Move to the next row in the curent dimension */
+ offset[temp_dim]++;
+ tmp_block[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
+ break;
+ else {
+ offset[temp_dim] = base_offset[temp_dim];
+ loc += skip[temp_dim];
+ tmp_block[temp_dim] = 0;
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+
+ /* Decrement block count */
+ blk_count--;
+ } /* end while */
+ } /* end else */
+ } /* end else */
+
+ /* Update the iterator, if there were any blocks used */
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= tot_blk_count * actual_elem;
+
+ /* Check if there are elements left in iterator */
+ if(iter->elmt_left > 0) {
+ /* Update the iterator with the location we stopped */
+ /* (Subtract out the selection offset) */
+ for(u = 0; u < ndims; u++)
+ iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
+ } /* end if */
+
+ /* Increment the number of sequences generated */
+ *nseq += tot_blk_count;
+
+ /* Increment the number of elements used */
+ *nelem += tot_blk_count * actual_elem;
+ } /* end if */
+
+ /* Check for partial block, with room for another sequence */
+ if(io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) {
+ size_t elmt_remainder; /* Elements remaining */
+
+ /* Compute elements left */
+ elmt_remainder = io_left - (tot_blk_count * actual_elem);
+ HDassert(elmt_remainder < fast_dim_block);
+ HDassert(elmt_remainder > 0);
+
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = elmt_remainder * elem_size;
+
+ /* Update the iterator with the location we stopped */
+ iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder;
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= elmt_remainder;
+
+ /* Increment the number of sequences generated */
+ (*nseq)++;
+
+ /* Increment the number of elements used */
+ *nelem += elmt_remainder;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(*nseq > 0);
+ HDassert(*nelem > 0);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_hyper_get_seq_list_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_seq_list
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_hyper_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t *iter,
+ size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ herr_t ret_value = FAIL; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(iter->elmt_left > 0);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+ HDassert(space->select.sel_info.hslab->unlim_dim < 0);
+
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ if(space->select.sel_info.hslab->diminfo_valid) {
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ hsize_t *mem_size; /* Size of the source buffer */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ hbool_t single_block; /* Whether the selection is a single block */
+ unsigned u; /* Local index variable */
+
+ /* Set a local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = iter->u.hyp.size;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = space->extent.rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = space->select.offset;
+
+ /* Set up the pointer to the size of the memory space */
+ mem_size = space->extent.size;
+ } /* end else */
+ fast_dim = ndims - 1;
+
+ /* Check if we stopped in the middle of a sequence of elements */
+ if((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
+ ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) {
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */
+ hsize_t loc; /* Coordinate offset */
+ hsize_t acc; /* Accumulator */
+ size_t leftover; /* The number of elements left over from the last sequence */
+ size_t actual_elem; /* The actual number of elements to count */
+ size_t elem_size; /* Size of each element iterating over */
+ int i; /* Local index variable */
+
+
+ /* Calculate the number of elements left in the sequence */
+ if(tdiminfo[fast_dim].count == 1) {
+ H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start), hsize_t);
+ } /* end if */
+ else {
+ H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride), hsize_t);
+ } /* end else */
+
+ /* Make certain that we don't write too many */
+ actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem);
+
+ /* Initialize row sizes for each dimension */
+ elem_size = iter->elmt_size;
+ for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) {
+ slab[i] = acc;
+ acc *= mem_size[i];
+ } /* end for */
+
+ /* Compute the initial buffer offset */
+ for(u = 0, loc = 0; u < ndims; u++)
+ loc += ((hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u])) * slab[u];
+
+ /* Add a new sequence */
+ off[0] = loc;
+ H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t);
+
+ /* Increment sequence array locations */
+ off++;
+ len++;
+
+ /* Advance the hyperslab iterator */
+ H5S_hyper_iter_next(iter, actual_elem);
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= actual_elem;
+
+ /* Decrement element/sequence limits */
+ maxelem -= actual_elem;
+ maxseq--;
+
+ /* Set the number of sequences generated and elements used */
+ *nseq = 1;
+ *nelem = actual_elem;
+
+ /* Check for using up all the sequences/elements */
+ if(0 == iter->elmt_left || 0 == maxelem || 0 == maxseq)
+ return(SUCCEED);
+ } /* end if */
+ else {
+ /* Reset the number of sequences generated and elements used */
+ *nseq = 0;
+ *nelem = 0;
+ } /* end else */
+
+ /* Check for a single block selected */
+ single_block = TRUE;
+ for(u = 0; u < ndims; u++)
+ if(1 != tdiminfo[u].count) {
+ single_block = FALSE;
+ break;
+ } /* end if */
+
+ /* Check for single block selection */
+ if(single_block)
+ /* Use single-block optimized call to generate sequence list */
+ ret_value = H5S_hyper_get_seq_list_single(space, iter, maxseq, maxelem, nseq, nelem, off, len);
+ else
+ /* Use optimized call to generate sequence list */
+ ret_value = H5S_hyper_get_seq_list_opt(space, iter, maxseq, maxelem, nseq, nelem, off, len);
+ } /* end if */
+ else
+ /* Call the general sequence generator routine */
+ ret_value = H5S_hyper_get_seq_list_gen(space, iter, maxseq, maxelem, nseq, nelem, off, len);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_get_seq_list() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_project_intersection
+ PURPOSE
+ Projects the intersection of of the selections of src_space and
+ src_intersect_space within the selection of src_space as a selection
+ within the selection of dst_space
+ USAGE
+ herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space)
+ H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space
+ H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result
+ H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result
+ H5S_t *proj_space; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Projects the intersection of of the selections of src_space and
+ src_intersect_space within the selection of src_space as a selection
+ within the selection of dst_space. The result is placed in the
+ selection of proj_space. Note src_space, dst_space, and
+ src_intersect_space do not need to use hyperslab selections, but they
+ cannot use point selections. The result is always a hyperslab
+ selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S__hyper_project_intersection(const H5S_t *src_space, const H5S_t *dst_space,
+ const H5S_t *src_intersect_space, H5S_t *proj_space)
+{
+ hsize_t ss_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_space */
+ size_t ss_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_space */
+ size_t ss_nseq; /* Number of sequences for src_space */
+ size_t ss_nelem; /* Number of elements for src_space */
+ size_t ss_i = (size_t)0; /* Index into offset/length arrays for src_space */
+ hbool_t advance_ss = FALSE; /* Whether to advance ss_i on the next iteration */
+ H5S_sel_iter_t *ss_iter = NULL; /* Selection iterator for src_space */
+ hbool_t ss_iter_init = FALSE; /* Whether ss_iter is initialized */
+ hsize_t ss_sel_off = (hsize_t)0; /* Offset within src_space selection */
+ hsize_t ds_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for dst_space */
+ size_t ds_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for dst_space */
+ size_t ds_nseq; /* Number of sequences for dst_space */
+ size_t ds_nelem; /* Number of elements for dst_space */
+ size_t ds_i = (size_t)0; /* Index into offset/length arrays for dst_space */
+ H5S_sel_iter_t *ds_iter = NULL; /* Selection iterator for dst_space */
+ hbool_t ds_iter_init = FALSE; /* Whether ds_iter is initialized */
+ hsize_t ds_sel_off = (hsize_t)0; /* Offset within dst_space selection */
+ hsize_t sis_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_intersect_space */
+ size_t sis_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_intersect_space */
+ size_t sis_nseq; /* Number of sequences for src_intersect_space */
+ size_t sis_nelem; /* Number of elements for src_intersect_space */
+ size_t sis_i = (size_t)0; /* Index into offset/length arrays for src_intersect_space */
+ hbool_t advance_sis = FALSE; /* Whether to advance sis_i on the next iteration */
+ H5S_sel_iter_t *sis_iter = NULL; /* Selection iterator for src_intersect_space */
+ hbool_t sis_iter_init = FALSE; /* Whether sis_iter is initialized */
+ hsize_t int_sel_off; /* Offset within intersected selections (ss/sis and ds/ps) */
+ size_t int_len; /* Length of segment in intersected selections */
+ hsize_t proj_off; /* Segment offset in proj_space */
+ size_t proj_len; /* Segment length in proj_space */
+ size_t proj_len_rem; /* Remaining length in proj_space for segment */
+ hsize_t proj_down_dims[H5S_MAX_RANK]; /* "Down" dimensions in proj_space */
+ H5S_hyper_span_info_t *curr_span_tree[H5S_MAX_RANK]; /* Current span tree being built (in each dimension) */
+ H5S_hyper_span_t *prev_span[H5S_MAX_RANK]; /* Previous span in tree (in each dimension) */
+ hsize_t curr_span_up_dim[H5S_MAX_RANK]; /* "Up" dimensions for current span */
+ unsigned proj_rank; /* Rank of proj_space */
+ hsize_t low; /* Low value of span */
+ hsize_t high; /* High value of span */
+ size_t span_len; /* Length of span */
+ size_t nelem; /* Number of elements returned for get_seq_list op */
+ unsigned i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check parameters */
+ HDassert(src_space);
+ HDassert(dst_space);
+ HDassert(src_intersect_space);
+ HDassert(proj_space);
+
+ /* Assert that src_space and src_intersect_space have same extent and there
+ * are no point selections */
+ HDassert(H5S_GET_EXTENT_NDIMS(src_space)
+ == H5S_GET_EXTENT_NDIMS(src_intersect_space));
+ HDassert(!HDmemcmp(src_space->extent.size, src_intersect_space->extent.size,
+ (size_t)H5S_GET_EXTENT_NDIMS(src_space)
+ * sizeof(src_space->extent.size[0])));
+ HDassert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS);
+ HDassert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS);
+ HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) != H5S_SEL_POINTS);
+
+ /* Initialize prev_space, curr_span_tree, and curr_span_up_dim */
+ for(i = 0; i < H5S_MAX_RANK; i++) {
+ curr_span_tree[i] = NULL;
+ prev_span[i] = NULL;
+ curr_span_up_dim[i] = (hsize_t)0;
+ } /* end for */
+
+ /* Save rank of projected space */
+ proj_rank = proj_space->extent.rank;
+ HDassert(proj_rank > 0);
+
+ /* Get numbers of elements */
+ ss_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_space);
+ ds_nelem = (size_t)H5S_GET_SELECT_NPOINTS(dst_space);
+ sis_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_intersect_space);
+ HDassert(ss_nelem == ds_nelem);
+
+ /* Calculate proj_down_dims (note loop relies on unsigned i wrapping around)
+ */
+ if(H5VM_array_down(proj_rank, proj_space->extent.size, proj_down_dims) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value")
+
+ /* Remove current selection from proj_space */
+ if(H5S_SELECT_RELEASE(proj_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* If any selections are empty, skip to the end so "none" is selected */
+ if((ss_nelem == 0) || (ds_nelem == 0) || (sis_nelem == 0))
+ goto loop_end;
+
+ /* Allocate space for the hyperslab selection information (note this sets
+ * diminfo_valid to FALSE, diminfo arrays to 0, and span list to NULL) */
+ if((proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info")
+
+ /* Set selection type */
+ proj_space->select.type = H5S_sel_hyper;
+
+ /* Set unlim_dim */
+ proj_space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Allocate the source space iterator */
+ if(NULL == (ss_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source space iterator")
+
+ /* Initialize source space iterator */
+ if(H5S_select_iter_init(ss_iter, src_space, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ ss_iter_init = TRUE;
+
+ /* Get sequence list for source space */
+ if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ ss_nelem -= nelem;
+ HDassert(ss_nseq > 0);
+
+ /* Allocate the destination space iterator */
+ if(NULL == (ds_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate destination space iterator")
+
+ /* Initialize destination space iterator */
+ if(H5S_select_iter_init(ds_iter, dst_space, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ ds_iter_init = TRUE;
+
+ /* Get sequence list for destination space */
+ if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ ds_nelem -= nelem;
+ HDassert(ds_nseq > 0);
+
+ /* Allocate the source intersect space iterator */
+ if(NULL == (sis_iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source intersect space iterator")
+
+ /* Initialize source intersect space iterator */
+ if(H5S_select_iter_init(sis_iter, src_intersect_space, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ sis_iter_init = TRUE;
+
+ /* Get sequence list for source intersect space */
+ if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ sis_nelem -= nelem;
+ HDassert(sis_nseq > 0);
+
+ /* Loop until we run out of sequences in either the source or source
+ * intersect space */
+ while(1) {
+ while(advance_ss || (ss_off[ss_i] + ss_len[ss_i] <= sis_off[sis_i])) {
+ /* Either we finished the current source sequence or the
+ * sequences do not intersect. Advance source space. */
+ ss_sel_off += (hsize_t)ss_len[ss_i];
+ if(++ss_i == ss_nseq) {
+ if(ss_nelem > 0) {
+ /* Try to grab more sequences from src_space */
+ if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(ss_len[0] > 0);
+
+ /* Update ss_nelem */
+ HDassert(nelem > 0);
+ HDassert(nelem <= ss_nelem);
+ ss_nelem -= nelem;
+
+ /* Reset source space index */
+ ss_i = 0;
+ } /* end if */
+ else
+ /* There are no more sequences in src_space, so we can exit
+ * the loop. Use goto instead of break so we exit the outer
+ * loop. */
+ goto loop_end;
+ } /* end if */
+
+ /* Reset advance_ss */
+ advance_ss = FALSE;
+ } /* end if */
+ if(advance_sis
+ || (sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i])) {
+ do {
+ /* Either we finished the current source intersect sequence or
+ * the sequences do not intersect. Advance source intersect
+ * space. */
+ if(++sis_i == sis_nseq) {
+ if(sis_nelem > 0) {
+ /* Try to grab more sequences from src_intersect_space
+ */
+ if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(sis_len[0] > 0);
+
+ /* Update ss_nelem */
+ HDassert(nelem > 0);
+ HDassert(nelem <= sis_nelem);
+ sis_nelem -= nelem;
+
+ /* Reset source space index */
+ sis_i = 0;
+ } /* end if */
+ else
+ /* There are no more sequences in src_intersect_space,
+ * so we can exit the loop. Use goto instead of break
+ * so we exit the outer loop. */
+ goto loop_end;
+ } /* end if */
+ } while(sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i]);
+
+ /* Reset advance_sis */
+ advance_sis = FALSE;
+ } /* end if */
+ else {
+ /* Sequences intersect, add intersection to projected space */
+ /* Calculate intersection sequence in terms of offset within source
+ * selection and advance any sequences we complete */
+ if(ss_off[ss_i] >= sis_off[sis_i])
+ int_sel_off = ss_sel_off;
+ else
+ int_sel_off = sis_off[sis_i] - ss_off[ss_i] + ss_sel_off;
+ if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) <= (sis_off[sis_i]
+ + (hsize_t)sis_len[sis_i])) {
+ int_len = (size_t)((hsize_t)ss_len[ss_i] + ss_sel_off - int_sel_off);
+ advance_ss = TRUE;
+ } /* end if */
+ else
+ int_len = (size_t)(sis_off[sis_i] + (hsize_t)sis_len[sis_i] - ss_off[ss_i] + ss_sel_off - int_sel_off);
+ if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) >= (sis_off[sis_i]
+ + (hsize_t)sis_len[sis_i]))
+ advance_sis = TRUE;
+
+ /* Project intersection sequence to destination selection */
+ while(int_len > (size_t)0) {
+ while(ds_sel_off + (hsize_t)ds_len[ds_i] <= int_sel_off) {
+ /* Intersection is not projected to this destination
+ * sequence, advance destination space */
+ ds_sel_off += (hsize_t)ds_len[ds_i];
+ if(++ds_i == ds_nseq) {
+ HDassert(ds_nelem > 0);
+
+ /* Try to grab more sequences from dst_space */
+ if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+ HDassert(ds_len[0] > 0);
+
+ /* Update ss_nelem */
+ HDassert(nelem > 0);
+ HDassert(nelem <= ds_nelem);
+ ds_nelem -= nelem;
+
+ /* Reset source space index */
+ ds_i = 0;
+ } /* end if */
+ } /* end while */
+
+ /* Add sequence to projected space */
+ HDassert(ds_sel_off <= int_sel_off);
+ proj_off = ds_off[ds_i] + int_sel_off - ds_sel_off;
+ proj_len = proj_len_rem = (size_t)MIN(int_len,
+ (size_t)(ds_sel_off + (hsize_t)ds_len[ds_i]
+ - int_sel_off));
+
+ /* Add to span tree */
+ while(proj_len_rem > (size_t)0) {
+ /* Check for more than one full row (in every dim) and
+ * append multiple spans at once? -NAF */
+ /* Append spans in higher dimensions if we're going ouside
+ * the plane of the span currently being built (i.e. it's
+ * finished being built) */
+ for(i = proj_rank - 1; ((i > 0)
+ && ((proj_off / proj_down_dims[i - 1])
+ != curr_span_up_dim[i - 1])); i--) {
+ if(curr_span_tree[i]) {
+ HDassert(prev_span[i]);
+
+ /* Append complete lower dimension span tree to
+ * current dimension */
+ low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1];
+ if(H5S_hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Reset lower dimension's span tree and previous
+ * span since we just committed it and will start
+ * over with a new one */
+ if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
+ curr_span_tree[i] = NULL;
+ prev_span[i] = NULL;
+ } /* end if */
+
+ /* Update curr_span_up_dim */
+ curr_span_up_dim[i - 1] = proj_off / proj_down_dims[i - 1];
+ } /* end for */
+
+ /* Compute bounds for new span in lowest dimension */
+ low = proj_off % proj_space->extent.size[proj_rank - 1];
+ span_len = MIN(proj_len_rem,
+ (size_t)(proj_space->extent.size[proj_rank - 1]
+ - low));
+ HDassert(proj_len_rem >= span_len);
+ high = low + (hsize_t)span_len - (hsize_t)1;
+
+ /* Append span in lowest dimension */
+ if(H5S_hyper_append_span(&prev_span[proj_rank - 1], &curr_span_tree[proj_rank - 1], low, high, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Update remaining offset and length */
+ proj_off += (hsize_t)span_len;
+ proj_len_rem -= span_len;
+ } /* end while */
+
+ /* Update intersection sequence */
+ int_sel_off += (hsize_t)proj_len;
+ int_len -= proj_len;
+ } /* end while */
+ } /* end else */
+ } /* end while */
+
+loop_end:
+ /* Add remaining spans to span tree */
+ for(i = proj_rank - 1; i > 0; i--)
+ if(curr_span_tree[i]) {
+ HDassert(prev_span[i]);
+
+ /* Append remaining span tree to higher dimension */
+ low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1];
+ if(H5S_hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+
+ /* Reset span tree */
+ if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
+ curr_span_tree[i] = NULL;
+ } /* end if */
+
+ /* Add span tree to proj_space */
+ if(curr_span_tree[0]) {
+ proj_space->select.sel_info.hslab->span_lst = curr_span_tree[0];
+ curr_span_tree[0] = NULL;
+
+ /* Set the number of elements in current selection */
+ proj_space->select.num_elem = H5S_hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst);
+
+ /* Attempt to rebuild "optimized" start/stride/count/block information.
+ * from resulting hyperslab span tree */
+ if(H5S_hyper_rebuild(proj_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info")
+ } /* end if */
+ else
+ /* If we did not add anything to proj_space, select none instead */
+ if(H5S_select_none(proj_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+
+done:
+ /* Release source selection iterator */
+ if(ss_iter_init && H5S_SELECT_ITER_RELEASE(ss_iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(ss_iter)
+ ss_iter = H5FL_FREE(H5S_sel_iter_t, ss_iter);
+
+ /* Release destination selection iterator */
+ if(ds_iter_init && H5S_SELECT_ITER_RELEASE(ds_iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(ds_iter)
+ ds_iter = H5FL_FREE(H5S_sel_iter_t, ds_iter);
+
+ /* Release source intersect selection iterator */
+ if(sis_iter_init && H5S_SELECT_ITER_RELEASE(sis_iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(sis_iter)
+ sis_iter = H5FL_FREE(H5S_sel_iter_t, sis_iter);
+
+ /* Cleanup on error */
+ if(ret_value < 0) {
+ /* Remove current selection from proj_space */
+ if(H5S_SELECT_RELEASE(proj_space) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Free span trees */
+ for(i = 0; i < proj_rank; i++)
+ if(curr_span_tree[i]) {
+ if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
+ curr_span_tree[i] = NULL;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_project_intersection() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_subtract
+ PURPOSE
+ Subtract one hyperslab selection from another
+ USAGE
+ herr_t H5S__hyper_subtract(space,subtract_space)
+ H5S_t *space; IN/OUT: Selection to be operated on
+ H5S_t *subtract_space; IN: Selection that will be subtracted from space
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Removes any and all portions of space that are also present in
+ subtract_space. In essence, performs an A_NOT_B operation with the
+ two selections.
+
+ Note this function basically duplicates a subset of the functionality
+ of H5S_select_select(). It should probably be removed when that
+ function is enabled.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space)
+{
+ H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
+ H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */
+ H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(subtract_space);
+
+ /* Check that the space selections both have span trees */
+ if(space->select.sel_info.hslab->span_lst == NULL)
+ if(H5S_hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+ if(subtract_space->select.sel_info.hslab->span_lst == NULL)
+ if(H5S_hyper_generate_spans(subtract_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+
+ /* Generate lists of spans which overlap and don't overlap */
+ if(H5S_hyper_clip_spans(space->select.sel_info.hslab->span_lst, subtract_space->select.sel_info.hslab->span_lst, &a_not_b, &a_and_b, &b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+
+ /* Reset the other dataspace selection information */
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate space for the hyperslab selection information */
+ if((space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
+
+ /* Set unlim_dim */
+ space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Check for anything returned in a_not_b */
+ if(a_not_b) {
+ /* Update spans in space */
+ space->select.sel_info.hslab->span_lst = a_not_b;
+ a_not_b = NULL;
+
+ /* Update number of elements */
+ space->select.num_elem = H5S_hyper_spans_nelem(space->select.sel_info.hslab->span_lst);
+
+ /* Attempt to rebuild "optimized" start/stride/count/block information.
+ * from resulting hyperslab span tree */
+ if(H5S_hyper_rebuild(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info")
+ } /* end if */
+ else {
+ H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */
+
+ /* Set number of elements */
+ space->select.num_elem = 0;
+
+ /* Allocate a span info node */
+ if(NULL == (spans = H5FL_MALLOC(H5S_hyper_span_info_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
+
+ /* Set the reference count */
+ spans->count = 1;
+
+ /* Reset the scratch pad space */
+ spans->scratch = 0;
+
+ /* Set to empty tree */
+ spans->head = NULL;
+
+ /* Set pointer to empty span tree */
+ space->select.sel_info.hslab->span_lst = spans;
+ } /* end if */
+
+done:
+ /* Free span trees */
+ if(a_and_b)
+ H5S_hyper_free_span_info(a_and_b);
+ if(b_not_a)
+ H5S_hyper_free_span_info(b_not_a);
+ if(a_not_b) {
+ HDassert(ret_value < 0);
+ H5S_hyper_free_span_info(b_not_a);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_subtract() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_get_clip_diminfo
+ PURPOSE
+ Calculates the count and block required to clip the specified
+ unlimited dimension to include clip_size. The returned selection may
+ extent beyond clip_size.
+ USAGE
+ void H5S__hyper_get_clip_diminfo(start,stride,count,block,clip_size)
+ hsize_t start; IN: Start of hyperslab in unlimited dimension
+ hsize_t stride; IN: Stride of hyperslab in unlimited dimension
+ hsize_t *count; IN/OUT: Count of hyperslab in unlimited dimension
+ hsize_t *block; IN/OUT: Block of hyperslab in unlimited dimension
+ hsize_t clip_size; IN: Extent that hyperslab will be clipped to
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ This function recalculates the internal description of the hyperslab
+ to make the unlimited dimension extend to the specified extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void
+H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count,
+ hsize_t *block, hsize_t clip_size)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check for selection outside clip size */
+ if(start >= clip_size) {
+ if(*block == H5S_UNLIMITED)
+ *block = 0;
+ else
+ *count = 0;
+ } /* end if */
+ /* Check for single block in unlimited dimension */
+ else if((*block == H5S_UNLIMITED) || (*block == stride)) {
+ /* Calculate actual block size for this clip size */
+ *block = clip_size - start;
+ *count = (hsize_t)1;
+ } /* end if */
+ else {
+ HDassert(*count == H5S_UNLIMITED);
+
+ /* Calculate initial count (last block may be partial) */
+ *count = (clip_size - start + stride - (hsize_t)1) / stride;
+ HDassert(*count > (hsize_t)0);
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5S_hyper_get_clip_diminfo() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_clip_unlim
+ PURPOSE
+ Clips the unlimited dimension of the hyperslab selection to the
+ specified size
+ USAGE
+ void H5S_hyper_clip_unlim(space,clip_size)
+ H5S_t *space, IN/OUT: Unlimited space to clip
+ hsize_t clip_size; IN: Extent that hyperslab will be clipped to
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ This function changes the unlimited selection into a limited selection
+ with the extent of the formerly unlimited dimension specified by
+ * clip_size.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this function does not take the offset into account.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size)
+{
+ H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */
+ hsize_t orig_count; /* Original count in unlimited dimension */
+ int orig_unlim_dim; /* Original unliminted dimension */
+ H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_diminfo in unlimited dimension */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check parameters */
+ HDassert(space);
+ hslab = space->select.sel_info.hslab;
+ HDassert(hslab);
+ HDassert(hslab->unlim_dim >= 0);
+ HDassert(!hslab->span_lst);
+
+ /* Save original unlimited dimension */
+ orig_unlim_dim = hslab->unlim_dim;
+
+ diminfo = &hslab->opt_diminfo[orig_unlim_dim];
+
+ /* Save original count in unlimited dimension */
+ orig_count = diminfo->count;
+
+ /* Get initial diminfo */
+ H5S__hyper_get_clip_diminfo(diminfo->start, diminfo->stride, &diminfo->count, &diminfo->block, clip_size);
+
+ /* Selection is no longer unlimited */
+ space->select.sel_info.hslab->unlim_dim = -1;
+
+ /* Check for nothing returned */
+ if((diminfo->block == 0) || (diminfo->count == 0)) {
+ /* Convert to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
+ } /* end if */
+ /* Check for single block in unlimited dimension */
+ else if(orig_count == (hsize_t)1) {
+ /* Calculate number of elements */
+ space->select.num_elem = diminfo->block * hslab->num_elem_non_unlim;
+
+ /* Mark that opt_diminfo is valid */
+ hslab->diminfo_valid = TRUE;
+ } /* end if */
+ else {
+ /* Calculate number of elements */
+ space->select.num_elem = diminfo->count * diminfo->block
+ * hslab->num_elem_non_unlim;
+
+ /* Check if last block is partial. If superset is set, just keep the
+ * last block complete to speed computation. */
+ HDassert(clip_size > diminfo->start);
+ if(((diminfo->stride * (diminfo->count - (hsize_t)1)) + diminfo->block)
+ > (clip_size - diminfo->start)) {
+ hsize_t start[H5S_MAX_RANK];
+ hsize_t block[H5S_MAX_RANK];
+ unsigned i;
+
+ /* Last block is partial, need to construct compound selection */
+ /* Fill start with zeros */
+ HDmemset(start, 0, sizeof(start));
+
+ /* Set block to clip_size in unlimited dimension, H5S_MAX_SIZE in
+ * others so only unlimited dimension is clipped */
+ for(i = 0; i < space->extent.rank; i++)
+ if((int)i == orig_unlim_dim)
+ block[i] = clip_size;
+ else
+ block[i] = H5S_MAX_SIZE;
+
+ /* Generate span tree in selection */
+ if(!hslab->span_lst)
+ if(H5S_hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to generate span tree")
+
+ /* Indicate that the regular dimensions are no longer valid */
+ hslab->diminfo_valid = FALSE;
+
+ /* "And" selection with calculated block to perform clip operation
+ */
+ if(H5S_generate_hyperslab(space, H5S_SELECT_AND, start, _ones, _ones, block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+ } /* end if */
+ else
+ /* Last block is complete, simply mark that opt_diminfo is valid */
+ hslab->diminfo_valid = TRUE;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_clip_unlim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_get_clip_extent_real
+ PURPOSE
+ Gets the extent a space should be clipped to in order to contain the
+ specified number of slices in the unlimited dimension
+ USAGE
+ hsize_t H5S__hyper_get_clip_extent_real(clip_space,num_slices,incl_trail)
+ const H5S_t *clip_space, IN: Space that clip size will be calculated based on
+ hsize_t num_slizes, IN: Number of slices clip_space should contain when clipped
+ hbool_t incl_trail; IN: Whether to include trailing unselected space
+ RETURNS
+ Clip extent to match num_slices (never fails)
+ DESCRIPTION
+ Calculates and returns the extent that clip_space should be clipped to
+ (via H5S_hyper_clip_unlim) in order for it to contain num_slices
+ slices in the unlimited dimension. If the clipped selection would end
+ immediately before a section of unselected space (i.e. at the end of a
+ block), then if incl_trail is TRUE, the returned clip extent is
+ selected to include that trailing "blank" space, otherwise it is
+ selected to end at the end before the blank space.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this assumes the offset has been normalized.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hsize_t
+H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, hsize_t num_slices,
+ hbool_t incl_trail)
+{
+ const H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension */
+ hsize_t count;
+ hsize_t rem_slices;
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check parameters */
+ HDassert(clip_space);
+ HDassert(clip_space->select.sel_info.hslab);
+ HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
+
+ diminfo = &clip_space->select.sel_info.hslab->opt_diminfo[clip_space->select.sel_info.hslab->unlim_dim];
+
+ if(num_slices == 0)
+ ret_value = incl_trail ? diminfo->start : 0;
+ else if((diminfo->block == H5S_UNLIMITED)
+ || (diminfo->block == diminfo->stride))
+ /* Unlimited block, just set the extent large enough for the block size
+ * to match num_slices */
+ ret_value = diminfo->start + num_slices;
+ else {
+ /* Unlimited count, need to match extent so a block (possibly) gets cut
+ * off so the number of slices matches num_slices */
+ HDassert(diminfo->count == H5S_UNLIMITED);
+
+ /* Calculate number of complete blocks in clip_space */
+ count = num_slices / diminfo->block;
+
+ /* Calculate slices remaining */
+ rem_slices = num_slices - (count * diminfo->block);
+
+ if(rem_slices > 0)
+ /* Must end extent in middle of partial block (or beginning of empty
+ * block if include_trailing_space and rem_slices == 0) */
+ ret_value = diminfo->start + (count * diminfo->stride) + rem_slices;
+ else {
+ if(incl_trail)
+ /* End extent just before first missing block */
+ ret_value = diminfo->start + (count * diminfo->stride);
+ else
+ /* End extent at end of last block */
+ ret_value = diminfo->start + ((count - (hsize_t)1)
+ * diminfo->stride) + diminfo->block;
+ } /* end else */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_get_clip_extent_real() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_clip_extent
+ PURPOSE
+ Gets the extent a space should be clipped to in order to contain the
+ same number of elements as another space
+ USAGE
+ hsize_t H5S__hyper_get_clip_extent(clip_space,match_space,incl_trail)
+ const H5S_t *clip_space, IN: Space that clip size will be calculated based on
+ const H5S_t *match_space, IN: Space containing the same number of elements as clip_space should after clipping
+ hbool_t incl_trail; IN: Whether to include trailing unselected space
+ RETURNS
+ Calculated clip extent (never fails)
+ DESCRIPTION
+ Calculates and returns the extent that clip_space should be clipped to
+ (via H5S_hyper_clip_unlim) in order for it to contain the same number
+ of elements as match_space. If the clipped selection would end
+ immediately before a section of unselected space (i.e. at the end of a
+ block), then if incl_trail is TRUE, the returned clip extent is
+ selected to include that trailing "blank" space, otherwise it is
+ selected to end at the end before the blank space.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this assumes the offset has been normalized.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hsize_t
+H5S_hyper_get_clip_extent(const H5S_t *clip_space, const H5S_t *match_space,
+ hbool_t incl_trail)
+{
+ hsize_t num_slices; /* Number of slices in unlimited dimension */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check parameters */
+ HDassert(clip_space);
+ HDassert(match_space);
+ HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
+
+ /* Check for "none" match space */
+ if(match_space->select.type->type == H5S_SEL_NONE)
+ num_slices = (hsize_t)0;
+ else {
+ HDassert(match_space->select.type->type == H5S_SEL_HYPERSLABS);
+ HDassert(match_space->select.sel_info.hslab);
+
+ /* Calculate number of slices */
+ num_slices = match_space->select.num_elem
+ / clip_space->select.sel_info.hslab->num_elem_non_unlim;
+ HDassert((match_space->select.num_elem
+ % clip_space->select.sel_info.hslab->num_elem_non_unlim) == 0);
+ } /* end else */
+
+ /* Call "real" get_clip_extent function */
+ ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_get_clip_extent() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_clip_extent_match
+ PURPOSE
+ Gets the extent a space should be clipped to in order to contain the
+ same number of elements as another unlimited space that has been
+ clipped to a different extent
+ USAGE
+ hsize_t H5S__hyper_get_clip_extent_match(clip_space,match_space,match_clip_size,incl_trail)
+ const H5S_t *clip_space, IN: Space that clip size will be calculated based on
+ const H5S_t *match_space, IN: Space that, after being clipped to match_clip_size, contains the same number of elements as clip_space should after clipping
+ hsize_t match_clip_size, IN: Extent match_space would be clipped to to match the number of elements in clip_space
+ hbool_t incl_trail; IN: Whether to include trailing unselected space
+ RETURNS
+ Calculated clip extent (never fails)
+ DESCRIPTION
+ Calculates and returns the extent that clip_space should be clipped to
+ (via H5S_hyper_clip_unlim) in order for it to contain the same number
+ of elements as match_space would have after being clipped to
+ match_clip_size. If the clipped selection would end immediately
+ before a section of unselected space (i.e. at the end of a block),
+ then if incl_trail is TRUE, the returned clip extent is selected to
+ include that trailing "blank" space, otherwise it is selected to end
+ at the end before the blank space.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this assumes the offset has been normalized.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hsize_t
+H5S_hyper_get_clip_extent_match(const H5S_t *clip_space,
+ const H5S_t *match_space, hsize_t match_clip_size, hbool_t incl_trail)
+{
+ const H5S_hyper_dim_t *match_diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension in match_space */
+ hsize_t count; /* Temporary count */
+ hsize_t block; /* Temporary block */
+ hsize_t num_slices; /* Number of slices in unlimited dimension */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check parameters */
+ HDassert(clip_space);
+ HDassert(match_space);
+ HDassert(clip_space->select.sel_info.hslab);
+ HDassert(match_space->select.sel_info.hslab);
+ HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
+ HDassert(match_space->select.sel_info.hslab->unlim_dim >= 0);
+ HDassert(clip_space->select.sel_info.hslab->num_elem_non_unlim
+ == match_space->select.sel_info.hslab->num_elem_non_unlim);
+
+ match_diminfo = &match_space->select.sel_info.hslab->opt_diminfo[match_space->select.sel_info.hslab->unlim_dim];
+
+ /* Get initial count and block */
+ count = match_diminfo->count;
+ block = match_diminfo->block;
+ H5S__hyper_get_clip_diminfo(match_diminfo->start, match_diminfo->stride, &count, &block, match_clip_size);
+
+ /* Calculate number of slices */
+ /* Check for nothing returned */
+ if((block == 0) || (count == 0))
+ num_slices = (hsize_t)0;
+ /* Check for single block in unlimited dimension */
+ else if(count == (hsize_t)1)
+ num_slices = block;
+ else {
+ /* Calculate initial num_slices */
+ num_slices = block * count;
+
+ /* Check for partial last block */
+ HDassert(match_clip_size >= match_diminfo->start);
+ if(((match_diminfo->stride * (count - (hsize_t)1)) + block)
+ > (match_clip_size - match_diminfo->start)) {
+ /* Subtract slices missing from last block */
+ HDassert((((match_diminfo->stride * (count - (hsize_t)1)) + block)
+ - (match_clip_size - match_diminfo->start)) < num_slices);
+ num_slices -= ((match_diminfo->stride * (count - (hsize_t)1))
+ + block) - (match_clip_size - match_diminfo->start);
+ } /* end if */
+ } /* end else */
+
+ /* Call "real" get_clip_extent function */
+ ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_get_clip_extent_match() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_unlim_block
+ PURPOSE
+ Get the nth block in the unlimited dimension
+ USAGE
+ H5S_t *H5S_hyper_get_unlim_block(space,block_index)
+ const H5S_t *space, IN: Space with unlimited selection
+ hsize_t block_index, IN: Index of block to return in unlimited dimension
+ hbool_t incl_trail; IN: Whether to include trailing unselected space
+ RETURNS
+ New space on success/NULL on failure.
+ DESCRIPTION
+ Returns a space containing only the block_indexth block in the
+ unlimited dimension on space. All blocks in all other dimensions are
+ preserved.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this assumes the offset has been normalized.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5S_t *
+H5S_hyper_get_unlim_block(const H5S_t *space, hsize_t block_index)
+{
+ H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */
+ H5S_t *space_out = NULL;
+ hsize_t start[H5S_MAX_RANK];
+ hsize_t stride[H5S_MAX_RANK];
+ hsize_t count[H5S_MAX_RANK];
+ hsize_t block[H5S_MAX_RANK];
+ unsigned i;
+ H5S_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check parameters */
+ HDassert(space);
+ hslab = space->select.sel_info.hslab;
+ HDassert(hslab);
+ HDassert(hslab->unlim_dim >= 0);
+ HDassert(hslab->opt_diminfo[hslab->unlim_dim].count == H5S_UNLIMITED);
+
+ /* Set start to select block_indexth block in unlimited dimension and set
+ * count to 1 in that dimension to only select that block. Copy all other
+ * diminfo parameters. */
+ for(i = 0; i < space->extent.rank; i++) {
+ if((int)i == hslab->unlim_dim){
+ start[i] = hslab->opt_diminfo[i].start + (block_index
+ * hslab->opt_diminfo[i].stride);
+ count[i] = (hsize_t)1;
+ } /* end if */
+ else {
+ start[i] = hslab->opt_diminfo[i].start;
+ count[i] = hslab->opt_diminfo[i].count;
+ } /* end else */
+ stride[i] = hslab->opt_diminfo[i].stride;
+ block[i] = hslab->opt_diminfo[i].block;
+ } /* end for */
+
+ /* Create output space, copy extent */
+ if(NULL == (space_out = H5S_create(H5S_SIMPLE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "unable to create output dataspace")
+ if(H5S_extent_copy_real(&space_out->extent, &space->extent, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "unable to copy destination space extent")
+
+ /* Select block as defined by start/stride/count/block computed above */
+ if(H5S_select_hyperslab(space_out, H5S_SELECT_SET, start, stride, count, block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "can't select hyperslab")
+
+ /* Set return value */
+ ret_value = space_out;
+
+done:
+ /* Free space on error */
+ if(!ret_value)
+ if(space_out && H5S_close(space_out) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_get_unlim_block */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_get_first_inc_block
+ PURPOSE
+ Get the index of the first incomplete block in the specified extent
+ USAGE
+ hsize_t H5S_hyper_get_first_inc_block(space,clip_size,partial)
+ const H5S_t *space, IN: Space with unlimited selection
+ hsize_t clip_size, IN: Extent space would be clipped to
+ hbool_t *partial; OUT: Whether the ret_valueth block (first incomplete block) is partial
+ RETURNS
+ Index of first incomplete block in clip_size (never fails).
+ DESCRIPTION
+ Calculates and returns the index (as would be passed to
+ H5S_hyper_get_unlim_block()) of the first block in the unlimited
+ dimension of space which would be incomplete or missing when space is
+ clipped to clip_size. partial is set to TRUE if the first incomplete
+ block is partial, and FALSE if the first incomplete block is missing.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note this assumes the offset has been normalized.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hsize_t
+H5S_hyper_get_first_inc_block(const H5S_t *space, hsize_t clip_size,
+ hbool_t *partial)
+{
+ H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */
+ H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_diminfo in unlimited dimension */
+ hsize_t ret_value = 0;
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check parameters */
+ HDassert(space);
+ hslab = space->select.sel_info.hslab;
+ HDassert(hslab);
+ HDassert(hslab->unlim_dim >= 0);
+ HDassert(hslab->opt_diminfo[hslab->unlim_dim].count == H5S_UNLIMITED);
+
+ diminfo = &hslab->opt_diminfo[hslab->unlim_dim];
+
+ /* Check for selection outside of clip_size */
+ if(diminfo->start >= clip_size) {
+ ret_value = 0;
+ if(partial)
+ partial = FALSE;
+ } /* end if */
+ else {
+ /* Calculate index of first incomplete block */
+ ret_value = (clip_size - diminfo->start + diminfo->stride
+ - diminfo->block) / diminfo->stride;
+
+ if(partial) {
+ /* Check for partial block */
+ if((diminfo->stride * ret_value) < (clip_size - diminfo->start))
+ *partial = TRUE;
+ else
+ *partial = FALSE;
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_hyper_get_first_inc_block */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sis_regular_hyperslab
+ PURPOSE
+ Determine if a hyperslab selection is regular
+ USAGE
+ htri_t H5Sis_regular_hyperslab(dsid)
+ hid_t dsid; IN: Dataspace ID of hyperslab selection to query
+ RETURNS
+ TRUE/FALSE for hyperslab selection, FAIL on error or when querying other
+ selection types.
+ DESCRIPTION
+ If a hyperslab can be represented as a single call to H5Sselect_hyperslab,
+ with the H5S_SELECT_SET option, it is regular. If the hyperslab selection
+ would require multiple calls to H5Sselect_hyperslab, it is irregular.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5Sis_regular_hyperslab(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to query */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection")
+
+ ret_value = H5S_hyper_is_regular(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sis_regular_hyperslab() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sgetregular_hyperslab
+ PURPOSE
+ Retrieve a regular hyperslab selection
+ USAGE
+ herr_t H5Sget_regular_hyperslab(dsid, start, stride, block, count)
+ hid_t dsid; IN: Dataspace ID of hyperslab selection to query
+ hsize_t start[]; OUT: Offset of start of hyperslab
+ hsize_t stride[]; OUT: Hyperslab stride
+ hsize_t count[]; OUT: Number of blocks included in hyperslab
+ hsize_t block[]; OUT: Size of block in hyperslab
+ RETURNS
+ Non-negative on success/Negative on failure. (It is an error to query
+ the regular hyperslab selections for non-regular hyperslab selections)
+ DESCRIPTION
+ Retrieve the start/stride/count/block for a regular hyperslab selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note that if a hyperslab is originally regular, then becomes irregular
+ through selection operations, and then becomes regular again, the new
+ final regular selection may be equivalent but not identical to the
+ original regular selection.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[], hsize_t stride[],
+ hsize_t count[], hsize_t block[])
+{
+ H5S_t *space; /* Dataspace to query */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "i*h*h*h*h", spaceid, start, stride, count, block);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection")
+ if(TRUE != H5S_hyper_is_regular(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a regular hyperslab selection")
+
+ /* Retrieve hyperslab parameters */
+ if(start)
+ for(u = 0; u < space->extent.rank; u++)
+ start[u] = space->select.sel_info.hslab->app_diminfo[u].start;
+ if(stride)
+ for(u = 0; u < space->extent.rank; u++)
+ stride[u] = space->select.sel_info.hslab->app_diminfo[u].stride;
+ if(count)
+ for(u = 0; u < space->extent.rank; u++)
+ count[u] = space->select.sel_info.hslab->app_diminfo[u].count;
+ if(block)
+ for(u = 0; u < space->extent.rank; u++)
+ block[u] = space->select.sel_info.hslab->app_diminfo[u].block;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_regular_hyperslab() */
+
diff --git a/src/H5Smodule.h b/src/H5Smodule.h
new file mode 100644
index 0000000..962f0a2
--- /dev/null
+++ b/src/H5Smodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5S package. Including this header means that the source file
+ * is part of the H5S package.
+ */
+#ifndef _H5Smodule_H
+#define _H5Smodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5S_MODULE
+#define H5_MY_PKG H5S
+#define H5_MY_PKG_ERR H5E_DATASPACE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Smodule_H */
+
diff --git a/src/H5Smpio.c b/src/H5Smpio.c
new file mode 100644
index 0000000..c24c455
--- /dev/null
+++ b/src/H5Smpio.c
@@ -0,0 +1,1095 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: rky 980813
+ *
+ * Purpose: Functions to read/write directly between app buffer and file.
+ *
+ * Beware of the ifdef'ed print statements.
+ * I didn't make them portable.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Spkg.h" /* Dataspaces */
+#include "H5VMprivate.h" /* Vector and array functions */
+
+#ifdef H5_HAVE_PARALLEL
+
+static herr_t H5S_mpio_all_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type);
+static herr_t H5S_mpio_none_type(MPI_Datatype *new_type, int *count,
+ hbool_t *is_derived_type);
+static herr_t H5S_mpio_create_point_datatype(size_t elmt_size, hsize_t num_points,
+ MPI_Aint *disp, MPI_Datatype *new_type);
+static herr_t H5S_mpio_point_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type,
+ hbool_t do_permute, hsize_t **permute_map, hbool_t *is_permuted);
+static herr_t H5S_mpio_permute_type(const H5S_t *space, size_t elmt_size,
+ hsize_t **permute_map, MPI_Datatype *new_type, int *count,
+ hbool_t *is_derived_type);
+static herr_t H5S_mpio_hyper_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type);
+static herr_t H5S_mpio_span_hyper_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type);
+static herr_t H5S_obtain_datatype(const hsize_t down[], H5S_hyper_span_t* span,
+ const MPI_Datatype *elmt_type, MPI_Datatype *span_type, size_t elmt_size);
+
+#define H5S_MPIO_INITIAL_ALLOC_COUNT 256
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_all_type
+ *
+ * Purpose: Translate an HDF5 "all" selection into an MPI type.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: rky 980813
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_all_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type)
+{
+ hsize_t total_bytes;
+ hssize_t snelmts; /* Total number of elmts (signed) */
+ hsize_t nelmts; /* Total number of elmts */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+
+ /* Just treat the entire extent as a block of bytes */
+ if((snelmts = (hssize_t)H5S_GET_EXTENT_NPOINTS(space)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection")
+ H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t);
+
+ total_bytes = (hsize_t)elmt_size * nelmts;
+
+ /* fill in the return values */
+ *new_type = MPI_BYTE;
+ H5_CHECKED_ASSIGN(*count, int, total_bytes, hsize_t);
+ *is_derived_type = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_mpio_all_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_none_type
+ *
+ * Purpose: Translate an HDF5 "none" selection into an MPI type.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: Quincey Koziol, October 29, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_none_type(MPI_Datatype *new_type, int *count, hbool_t *is_derived_type)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* fill in the return values */
+ *new_type = MPI_BYTE;
+ *count = 0;
+ *is_derived_type = FALSE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_mpio_none_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_create_point_datatype
+ *
+ * Purpose: Create a derived datatype for point selections.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_create_point_datatype (size_t elmt_size, hsize_t num_points,
+ MPI_Aint *disp, MPI_Datatype *new_type)
+{
+ MPI_Datatype elmt_type; /* MPI datatype for individual element */
+ hbool_t elmt_type_created = FALSE; /* Whether the element MPI datatype was created */
+ int mpi_code; /* MPI error code */
+ int *blocks = NULL; /* Array of block sizes for MPI hindexed create call */
+ hsize_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Create an MPI datatype for an element */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_contiguous((int)elmt_size, MPI_BYTE, &elmt_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code)
+ elmt_type_created = TRUE;
+
+#if MPI_VERSION >= 3
+ /* Create an MPI datatype for the whole point selection */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed_block((int)num_points, 1, disp, elmt_type, new_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_indexed_block failed", mpi_code)
+#else
+ /* Allocate block sizes for MPI datatype call */
+ if(NULL == (blocks = (int *)H5MM_malloc(sizeof(int) * num_points)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of blocks")
+
+ for(u = 0; u < num_points; u++)
+ blocks[u] = 1;
+
+ /* Create an MPI datatype for the whole point selection */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)num_points, blocks, disp, elmt_type, new_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_indexed_block failed", mpi_code)
+#endif
+
+ /* Commit MPI datatype for later use */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(new_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+done:
+ if(elmt_type_created)
+ MPI_Type_free(&elmt_type);
+ if(blocks)
+ H5MM_free(blocks);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_mpio_create_point_datatype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_point_type
+ *
+ * Purpose: Translate an HDF5 "point" selection into an MPI type.
+ * Create a permutation array to handle out-of-order point selections.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ * *permute_map the permutation of the displacements to create
+ * the MPI_Datatype
+ * *is_permuted 0 if the displacements are permuted, 1 if not
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_point_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type,
+ int *count, hbool_t *is_derived_type, hbool_t do_permute, hsize_t **permute,
+ hbool_t *is_permuted)
+{
+ MPI_Aint *disp = NULL; /* Datatype displacement for each point*/
+ H5S_pnt_node_t *curr = NULL; /* Current point being operated on in from the selection */
+ hssize_t snum_points; /* Signed number of elements in selection */
+ hsize_t num_points; /* Sumber of points in the selection */
+ hsize_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+
+ /* Get the total number of points selected */
+ if((snum_points = (hssize_t)H5S_GET_SELECT_NPOINTS(space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ num_points = (hsize_t)snum_points;
+
+ /* Allocate array for element displacements */
+ if(NULL == (disp = (MPI_Aint *)H5MM_malloc(sizeof(MPI_Aint) * num_points)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements")
+
+ /* Allocate array for element permutation - returned to caller */
+ if(do_permute)
+ if(NULL == (*permute = (hsize_t *)H5MM_malloc(sizeof(hsize_t) * num_points)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate permutation array")
+
+ /* Iterate through list of elements */
+ curr = space->select.sel_info.pnt_lst->head;
+ for(u = 0 ; u < num_points ; u++) {
+ /* calculate the displacement of the current point */
+ disp[u] = H5VM_array_offset(space->extent.rank, space->extent.size, curr->pnt);
+ disp[u] *= elmt_size;
+
+ /* This is a File Space used to set the file view, so adjust the displacements
+ * to have them monotonically non-decreasing.
+ * Generate the permutation array by indicating at each point being selected,
+ * the position it will shifted in the new displacement. Example:
+ * Suppose 4 points with corresponding are selected
+ * Pt 1: disp=6 ; Pt 2: disp=3 ; Pt 3: disp=0 ; Pt 4: disp=4
+ * The permute map to sort the displacements in order will be:
+ * point 1: map[0] = L, indicating that this point is not moved (1st point selected)
+ * point 2: map[1] = 0, indicating that this point is moved to the first position,
+ * since disp_pt1(6) > disp_pt2(3)
+ * point 3: map[2] = 0, move to position 0, bec it has the lowest disp between
+ * the points selected so far.
+ * point 4: map[3] = 2, move the 2nd position since point 1 has a higher disp,
+ * but points 2 and 3 have lower displacements.
+ */
+ if(do_permute) {
+ if(u > 0 && disp[u] < disp[u - 1]) {
+ unsigned s = 0, l = u, m = u / 2;
+
+ *is_permuted = TRUE;
+ do {
+ if(disp[u] > disp[m])
+ s = m + 1;
+ else if(disp[u] < disp[m])
+ l = m;
+ else
+ break;
+ m = s + ((l - s) / 2);
+ } while(s < l);
+
+ if(m < u) {
+ MPI_Aint temp;
+
+ temp = disp[u];
+ HDmemmove(disp + m + 1, disp + m, (u - m) * sizeof(MPI_Aint));
+ disp[m] = temp;
+ } /* end if */
+ (*permute)[u] = m;
+ } /* end if */
+ else
+ (*permute)[u] = num_points;
+ } /* end if */
+ /* this is a memory space, and no permutation is necessary to create
+ the derived datatype */
+ else {
+ ;/* do nothing */
+ } /* end else */
+
+ /* get the next point */
+ curr = curr->next;
+ } /* end for */
+
+ /* Create the MPI datatype for the set of element displacements */
+ if(H5S_mpio_create_point_datatype(elmt_size, num_points, disp, new_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create an MPI Datatype from point selection")
+
+ /* Set values about MPI datatype created */
+ *count = 1;
+ *is_derived_type = TRUE;
+
+done:
+ if(NULL != disp)
+ H5MM_free(disp);
+
+ /* Release the permutation buffer, if it wasn't used */
+ if(!(*is_permuted) && (*permute)) {
+ H5MM_free(*permute);
+ *permute = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_mpio_point_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_permute_type
+ *
+ * Purpose: Translate an HDF5 "all/hyper/point" selection into an MPI type,
+ * while applying the permutation map. This function is called if
+ * the file space selection is permuted due to out-of-order point
+ * selection and so the memory datatype has to be permuted using the
+ * permutation map created by the file selection.
+ *
+ * Note: This routine is called from H5S_mpio_space_type(), which is
+ * called first for the file dataspace and creates
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: Mohamad Chaarawi
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_permute_type(const H5S_t *space, size_t elmt_size, hsize_t **permute,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type)
+{
+ MPI_Aint *disp = NULL; /* Datatype displacement for each point*/
+ H5S_sel_iter_t sel_iter; /* Selection iteration info */
+ hbool_t sel_iter_init = FALSE; /* Selection iteration info has been initialized */
+ hssize_t snum_points; /* Signed number of elements in selection */
+ hsize_t num_points; /* Number of points in the selection */
+ size_t max_elem; /* Maximum number of elements allowed in sequences */
+ hsize_t u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+
+ /* Get the total number of points selected */
+ if((snum_points = (hssize_t)H5S_GET_SELECT_NPOINTS(space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+ num_points = (hsize_t)snum_points;
+
+ /* Allocate array to store point displacements */
+ if(NULL == (disp = (MPI_Aint *)H5MM_malloc(sizeof(MPI_Aint) * num_points)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements")
+
+ /* Initialize selection iterator */
+ if(H5S_select_iter_init(&sel_iter, space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ sel_iter_init = TRUE; /* Selection iteration info has been initialized */
+
+ /* Set the number of elements to iterate over */
+ H5_CHECKED_ASSIGN(max_elem, size_t, num_points, hsize_t);
+
+ /* Loop, while elements left in selection */
+ u = 0;
+ while(max_elem > 0) {
+ hsize_t off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */
+ size_t len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being worked on */
+
+ /* Get the sequences of bytes */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, &sel_iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Loop, while sequences left to process */
+ for(curr_seq = 0; curr_seq < nseq; curr_seq++) {
+ hsize_t curr_off; /* Current offset within sequence */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+
+ /* Get the current offset */
+ curr_off = off[curr_seq];
+
+ /* Get the number of bytes in sequence */
+ curr_len = len[curr_seq];
+
+ /* Loop, while bytes left in sequence */
+ while(curr_len > 0) {
+ /* Set the displacement of the current point */
+ disp[u] = curr_off;
+
+ /* This is a memory displacement, so for each point selected,
+ * apply the map that was generated by the file selection */
+ if((*permute)[u] != num_points) {
+ MPI_Aint temp = disp[u];
+
+ HDmemmove(disp + (*permute)[u] + 1, disp + (*permute)[u],
+ (u - (*permute)[u]) * sizeof(MPI_Aint));
+ disp[(*permute)[u]] = temp;
+ } /* end if */
+
+ /* Advance to next element */
+ u++;
+
+ /* Increment offset in dataspace */
+ curr_off += elmt_size;
+
+ /* Decrement number of bytes left in sequence */
+ curr_len -= elmt_size;
+ } /* end while */
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ max_elem -= nelem;
+ } /* end while */
+
+ /* Create the MPI datatype for the set of element displacements */
+ if(H5S_mpio_create_point_datatype(elmt_size, num_points, disp, new_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create an MPI Datatype from point selection")
+
+ /* Set values about MPI datatype created */
+ *count = 1;
+ *is_derived_type = TRUE;
+
+done:
+ /* Release selection iterator */
+ if(sel_iter_init)
+ if(H5S_SELECT_ITER_RELEASE(&sel_iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+
+ /* Free memory */
+ if(disp)
+ H5MM_free(disp);
+ if(*permute) {
+ H5MM_free(*permute);
+ *permute = NULL;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_mpio_permute_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_hyper_type
+ *
+ * Purpose: Translate an HDF5 hyperslab selection into an MPI type.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: rky 980813
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_hyper_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type)
+{
+ H5S_sel_iter_t sel_iter; /* Selection iteration info */
+ hbool_t sel_iter_init = FALSE; /* Selection iteration info has been initialized */
+
+ struct dim { /* less hassle than malloc/free & ilk */
+ hssize_t start;
+ hsize_t strid;
+ hsize_t block;
+ hsize_t xtent;
+ hsize_t count;
+ } d[H5S_MAX_RANK];
+
+ hsize_t offset[H5S_MAX_RANK];
+ hsize_t max_xtent[H5S_MAX_RANK];
+ H5S_hyper_dim_t *diminfo; /* [rank] */
+ unsigned rank;
+ MPI_Datatype inner_type, outer_type;
+ MPI_Aint extent_len, start_disp, new_extent;
+ MPI_Aint lb; /* Needed as an argument for MPI_Type_get_extent */
+ unsigned u; /* Local index variable */
+ int i; /* Local index variable */
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(sizeof(MPI_Aint) >= sizeof(elmt_size));
+
+ /* Initialize selection iterator */
+ if(H5S_select_iter_init(&sel_iter, space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ sel_iter_init = TRUE; /* Selection iteration info has been initialized */
+
+ /* Abbreviate args */
+ diminfo = sel_iter.u.hyp.diminfo;
+ HDassert(diminfo);
+
+ /* make a local copy of the dimension info so we can operate with them */
+
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(sel_iter.u.hyp.iter_rank != 0 && sel_iter.u.hyp.iter_rank < space->extent.rank) {
+ /* Flattened selection */
+ rank = sel_iter.u.hyp.iter_rank;
+ HDassert(rank <= H5S_MAX_RANK); /* within array bounds */
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S), "%s: Flattened selection\n",FUNC);
+#endif
+ for(u = 0; u < rank; ++u) {
+ H5_CHECK_OVERFLOW(diminfo[u].start, hsize_t, hssize_t)
+ d[u].start = (hssize_t)diminfo[u].start + sel_iter.u.hyp.sel_off[u];
+ d[u].strid = diminfo[u].stride;
+ d[u].block = diminfo[u].block;
+ d[u].count = diminfo[u].count;
+ d[u].xtent = sel_iter.u.hyp.size[u];
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S)){
+ HDfprintf(H5DEBUG(S), "%s: start=%Hd stride=%Hu count=%Hu block=%Hu xtent=%Hu",
+ FUNC, d[u].start, d[u].strid, d[u].count, d[u].block, d[u].xtent );
+ if (u==0)
+ HDfprintf(H5DEBUG(S), " rank=%u\n", rank );
+ else
+ HDfprintf(H5DEBUG(S), "\n" );
+ }
+#endif
+ if(0 == d[u].block)
+ goto empty;
+ if(0 == d[u].count)
+ goto empty;
+ if(0 == d[u].xtent)
+ goto empty;
+ } /* end for */
+ } /* end if */
+ else {
+ /* Non-flattened selection */
+ rank = space->extent.rank;
+ HDassert(rank <= H5S_MAX_RANK); /* within array bounds */
+ if(0 == rank)
+ goto empty;
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S),"%s: Non-flattened selection\n",FUNC);
+#endif
+ for(u = 0; u < rank; ++u) {
+ H5_CHECK_OVERFLOW(diminfo[u].start, hsize_t, hssize_t)
+ d[u].start = (hssize_t)diminfo[u].start + space->select.offset[u];
+ d[u].strid = diminfo[u].stride;
+ d[u].block = diminfo[u].block;
+ d[u].count = diminfo[u].count;
+ d[u].xtent = space->extent.size[u];
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S)){
+ HDfprintf(H5DEBUG(S), "%s: start=%Hd stride=%Hu count=%Hu block=%Hu xtent=%Hu",
+ FUNC, d[u].start, d[u].strid, d[u].count, d[u].block, d[u].xtent );
+ if (u==0)
+ HDfprintf(H5DEBUG(S), " rank=%u\n", rank );
+ else
+ HDfprintf(H5DEBUG(S), "\n" );
+ }
+#endif
+ if(0 == d[u].block)
+ goto empty;
+ if(0 == d[u].count)
+ goto empty;
+ if(0 == d[u].xtent)
+ goto empty;
+ } /* end for */
+ } /* end else */
+
+/**********************************************************************
+ Compute array "offset[rank]" which gives the offsets for a multi-
+ dimensional array with dimensions "d[i].xtent" (i=0,1,...,rank-1).
+**********************************************************************/
+ offset[rank - 1] = 1;
+ max_xtent[rank - 1] = d[rank - 1].xtent;
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S)) {
+ i = ((int)rank) - 1;
+ HDfprintf(H5DEBUG(S), " offset[%2d]=%Hu; max_xtent[%2d]=%Hu\n",
+ i, offset[i], i, max_xtent[i]);
+ }
+#endif
+ for(i = ((int)rank) - 2; i >= 0; --i) {
+ offset[i] = offset[i + 1] * d[i + 1].xtent;
+ max_xtent[i] = max_xtent[i + 1] * d[i].xtent;
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S), " offset[%2d]=%Hu; max_xtent[%2d]=%Hu\n",
+ i, offset[i], i, max_xtent[i]);
+#endif
+ } /* end for */
+
+ /* Create a type covering the selected hyperslab.
+ * Multidimensional dataspaces are stored in row-major order.
+ * The type is built from the inside out, going from the
+ * fastest-changing (i.e., inner) dimension * to the slowest (outer). */
+
+/*******************************************************
+* Construct contig type for inner contig dims:
+*******************************************************/
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S)) {
+ HDfprintf(H5DEBUG(S), "%s: Making contig type %Zu MPI_BYTEs\n", FUNC, elmt_size);
+ for(i = ((int)rank) - 1; i >= 0; --i)
+ HDfprintf(H5DEBUG(S), "d[%d].xtent=%Hu \n", i, d[i].xtent);
+ }
+#endif
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_contiguous((int)elmt_size, MPI_BYTE, &inner_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code)
+
+/*******************************************************
+* Construct the type by walking the hyperslab dims
+* from the inside out:
+*******************************************************/
+ for(i = ((int)rank) - 1; i >= 0; --i) {
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S), "%s: Dimension i=%d \n"
+ "start=%Hd count=%Hu block=%Hu stride=%Hu, xtent=%Hu max_xtent=%d\n",
+ FUNC, i, d[i].start, d[i].count, d[i].block, d[i].strid, d[i].xtent, max_xtent[i]);
+#endif
+
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S), "%s: i=%d Making vector-type \n", FUNC,i);
+#endif
+ /****************************************
+ * Build vector type of the selection.
+ ****************************************/
+ mpi_code = MPI_Type_vector((int)(d[i].count), /* count */
+ (int)(d[i].block), /* blocklength */
+ (int)(d[i].strid), /* stride */
+ inner_type, /* old type */
+ &outer_type); /* new type */
+
+ MPI_Type_free(&inner_type);
+ if(mpi_code != MPI_SUCCESS)
+ HMPI_GOTO_ERROR(FAIL, "couldn't create MPI vector type", mpi_code)
+
+ /****************************************
+ * Then build the dimension type as (start, vector type, xtent).
+ ****************************************/
+ /* calculate start and extent values of this dimension */
+ start_disp = d[i].start * offset[i] * elmt_size;
+ new_extent = (MPI_Aint)elmt_size * max_xtent[i];
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_get_extent(outer_type, &lb, &extent_len)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_get_extent failed", mpi_code)
+
+ /*************************************************
+ * Restructure this datatype ("outer_type")
+ * so that it still starts at 0, but its extent
+ * is the full extent in this dimension.
+ *************************************************/
+ if(start_disp > 0 || extent_len < new_extent) {
+ MPI_Datatype interm_type;
+ int block_len = 1;
+
+ HDassert(0 == lb);
+
+ mpi_code = MPI_Type_create_hindexed(1, &block_len, &start_disp, outer_type, &interm_type);
+ MPI_Type_free(&outer_type);
+ if(mpi_code != MPI_SUCCESS)
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
+
+ mpi_code = MPI_Type_create_resized(interm_type, lb, new_extent, &inner_type);
+ MPI_Type_free(&interm_type);
+ if(mpi_code != MPI_SUCCESS)
+ HMPI_GOTO_ERROR(FAIL, "couldn't resize MPI vector type", mpi_code)
+ } /* end if */
+ else
+ inner_type = outer_type;
+ } /* end for */
+/***************************
+* End of loop, walking
+* thru dimensions.
+***************************/
+
+ /* At this point inner_type is actually the outermost type, even for 0-trip loop */
+ *new_type = inner_type;
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(new_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+
+ /* fill in the remaining return values */
+ *count = 1; /* only have to move one of these suckers! */
+ *is_derived_type = TRUE;
+ HGOTO_DONE(SUCCEED);
+
+empty:
+ /* special case: empty hyperslab */
+ *new_type = MPI_BYTE;
+ *count = 0;
+ *is_derived_type = FALSE;
+
+done:
+ /* Release selection iterator */
+ if(sel_iter_init)
+ if(H5S_SELECT_ITER_RELEASE(&sel_iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+
+#ifdef H5S_DEBUG
+ if(H5DEBUG(S))
+ HDfprintf(H5DEBUG(S), "Leave %s, count=%ld is_derived_type=%t\n",
+ FUNC, *count, *is_derived_type );
+#endif
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_mpio_hyper_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_span_hyper_type
+ *
+ * Purpose: Translate an HDF5 irregular hyperslab selection into an
+ MPI type.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: kyang
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_mpio_span_hyper_type(const H5S_t *space, size_t elmt_size,
+ MPI_Datatype *new_type, int *count, hbool_t *is_derived_type)
+{
+ MPI_Datatype elmt_type; /* MPI datatype for an element */
+ hbool_t elmt_type_is_derived = FALSE; /* Whether the element type has been created */
+ MPI_Datatype span_type; /* MPI datatype for overall span tree */
+ hsize_t down[H5S_MAX_RANK]; /* 'down' sizes for each dimension */
+ int mpi_code; /* MPI return code */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(space->extent.size);
+ HDassert(space->select.sel_info.hslab->span_lst);
+ HDassert(space->select.sel_info.hslab->span_lst->head);
+
+ /* Create the base type for an element */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_contiguous((int)elmt_size, MPI_BYTE, &elmt_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code)
+ elmt_type_is_derived = TRUE;
+
+ /* Compute 'down' sizes for each dimension */
+ if(H5VM_array_down(space->extent.rank, space->extent.size, down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGETSIZE, FAIL, "couldn't compute 'down' dimension sizes")
+
+ /* Obtain derived data type */
+ if(H5S_obtain_datatype(down, space->select.sel_info.hslab->span_lst->head, &elmt_type, &span_type, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type")
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&span_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code)
+ *new_type = span_type;
+
+ /* fill in the remaining return values */
+ *count = 1;
+ *is_derived_type = TRUE;
+
+done:
+ /* Release resources */
+ if(elmt_type_is_derived)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&elmt_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_mpio_span_hyper_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_obtain_datatype
+ *
+ * Purpose: Obtain an MPI derived datatype based on span-tree
+ * implementation
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *span_type the MPI type corresponding to the selection
+ *
+ * Programmer: kyang
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_obtain_datatype(const hsize_t *down, H5S_hyper_span_t *span,
+ const MPI_Datatype *elmt_type, MPI_Datatype *span_type, size_t elmt_size)
+{
+ size_t alloc_count; /* Number of span tree nodes allocated at this level */
+ size_t outercount; /* Number of span tree nodes at this level */
+ MPI_Datatype *inner_type = NULL;
+ hbool_t inner_types_freed = FALSE; /* Whether the inner_type MPI datatypes have been freed */
+ hbool_t span_type_valid = FALSE; /* Whether the span_type MPI datatypes is valid */
+ int *blocklen = NULL;
+ MPI_Aint *disp = NULL;
+ H5S_hyper_span_t *tspan; /* Temporary pointer to span tree node */
+ int mpi_code; /* MPI return status code */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(span);
+
+ /* Allocate the initial displacement & block length buffers */
+ alloc_count = H5S_MPIO_INITIAL_ALLOC_COUNT;
+ if(NULL == (disp = (MPI_Aint *)H5MM_malloc(alloc_count * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements")
+ if(NULL == (blocklen = (int *)H5MM_malloc(alloc_count * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths")
+
+ /* if this is the fastest changing dimension, it is the base case for derived datatype. */
+ if(NULL == span->down) {
+ tspan = span;
+ outercount = 0;
+ while(tspan) {
+ /* Check if we need to increase the size of the buffers */
+ if(outercount >= alloc_count) {
+ MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */
+ int *tmp_blocklen; /* Temporary pointer to new block length buffer */
+
+ /* Double the allocation count */
+ alloc_count *= 2;
+
+ /* Re-allocate the buffers */
+ if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements")
+ disp = tmp_disp;
+ if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths")
+ blocklen = tmp_blocklen;
+ } /* end if */
+
+ /* Store displacement & block length */
+ disp[outercount] = (MPI_Aint)elmt_size * tspan->low;
+ H5_CHECK_OVERFLOW(tspan->nelem, hsize_t, int)
+ blocklen[outercount] = (int)tspan->nelem;
+
+ tspan = tspan->next;
+ outercount++;
+ } /* end while */
+
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)outercount, blocklen, disp, *elmt_type, span_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code)
+ span_type_valid = TRUE;
+ } /* end if */
+ else {
+ size_t u; /* Local index variable */
+
+ if(NULL == (inner_type = (MPI_Datatype *)H5MM_malloc(alloc_count * sizeof(MPI_Datatype))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes")
+
+ tspan = span;
+ outercount = 0;
+ while(tspan) {
+ MPI_Datatype down_type; /* Temporary MPI datatype for a span tree node's children */
+ MPI_Aint stride; /* Distance between inner MPI datatypes */
+
+ /* Check if we need to increase the size of the buffers */
+ if(outercount >= alloc_count) {
+ MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */
+ int *tmp_blocklen; /* Temporary pointer to new block length buffer */
+ MPI_Datatype *tmp_inner_type; /* Temporary pointer to inner MPI datatype buffer */
+
+ /* Double the allocation count */
+ alloc_count *= 2;
+
+ /* Re-allocate the buffers */
+ if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements")
+ disp = tmp_disp;
+ if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths")
+ blocklen = tmp_blocklen;
+ if(NULL == (tmp_inner_type = (MPI_Datatype *)H5MM_realloc(inner_type, alloc_count * sizeof(MPI_Datatype))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes")
+ inner_type = tmp_inner_type;
+ } /* end if */
+
+ /* Displacement should be in byte and should have dimension information */
+ /* First using MPI Type vector to build derived data type for this span only */
+ /* Need to calculate the disp in byte for this dimension. */
+ /* Calculate the total bytes of the lower dimension */
+ disp[outercount] = tspan->low * (*down) * elmt_size;
+ blocklen[outercount] = 1;
+
+ /* Generate MPI datatype for next dimension down */
+ if(H5S_obtain_datatype(down + 1, tspan->down->head, elmt_type, &down_type, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type")
+
+ /* Build the MPI datatype for this node */
+ stride = (*down) * elmt_size;
+ H5_CHECK_OVERFLOW(tspan->nelem, hsize_t, int)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hvector((int)tspan->nelem, 1, stride, down_type, &inner_type[outercount]))) {
+ MPI_Type_free(&down_type);
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hvector failed", mpi_code)
+ } /* end if */
+
+ /* Release MPI datatype for next dimension down */
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&down_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+
+ tspan = tspan->next;
+ outercount++;
+ } /* end while */
+
+ /* building the whole vector datatype */
+ H5_CHECK_OVERFLOW(outercount, size_t, int)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)outercount, blocklen, disp, inner_type, span_type)))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code)
+ span_type_valid = TRUE;
+
+ /* Release inner node types */
+ for(u = 0; u < outercount; u++)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&inner_type[u])))
+ HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ inner_types_freed = TRUE;
+ } /* end else */
+
+done:
+ /* General cleanup */
+ if(inner_type != NULL) {
+ if(!inner_types_freed) {
+ size_t u; /* Local index variable */
+
+ for(u = 0; u < outercount; u++)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&inner_type[u])))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ } /* end if */
+
+ H5MM_free(inner_type);
+ } /* end if */
+ if(blocklen != NULL)
+ H5MM_free(blocklen);
+ if(disp != NULL)
+ H5MM_free(disp);
+
+ /* Error cleanup */
+ if(ret_value < 0) {
+ if(span_type_valid)
+ if(MPI_SUCCESS != (mpi_code = MPI_Type_free(span_type)))
+ HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code)
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_obtain_datatype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_mpio_space_type
+ *
+ * Purpose: Translate an HDF5 dataspace selection into an MPI type.
+ * Currently handle only hyperslab and "all" selections.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Outputs: *new_type the MPI type corresponding to the selection
+ * *count how many objects of the new_type in selection
+ * (useful if this is the buffer type for xfer)
+ * *is_derived_type 0 if MPI primitive type, 1 if derived
+ *
+ * Programmer: rky 980813
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_mpio_space_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type,
+ int *count, hbool_t *is_derived_type, hbool_t do_permute, hsize_t **permute_map,
+ hbool_t *is_permuted)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(elmt_size);
+
+ /* Create MPI type based on the kind of selection */
+ switch(H5S_GET_EXTENT_TYPE(space)) {
+ case H5S_NULL:
+ case H5S_SCALAR:
+ case H5S_SIMPLE:
+ /* If the file space has been permuted previously due to
+ * out-of-order point selection, then permute this selection which
+ * should be a memory selection to match the file space permutation.
+ */
+ if(TRUE == *is_permuted) {
+ switch(H5S_GET_SELECT_TYPE(space)) {
+ case H5S_SEL_NONE:
+ if(H5S_mpio_none_type(new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't convert 'none' selection to MPI type")
+ break;
+
+ case H5S_SEL_ALL:
+ case H5S_SEL_POINTS:
+ case H5S_SEL_HYPERSLABS:
+ /* Sanity check */
+ HDassert(!do_permute);
+
+ if(H5S_mpio_permute_type(space, elmt_size, permute_map, new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't convert 'all' selection to MPI type")
+ break;
+
+ case H5S_SEL_ERROR:
+ case H5S_SEL_N:
+ default:
+ HDassert("unknown selection type" && 0);
+ break;
+ } /* end switch */
+ } /* end if */
+ /* the file space is not permuted, so do a regular selection */
+ else {
+ switch(H5S_GET_SELECT_TYPE(space)) {
+ case H5S_SEL_NONE:
+ if(H5S_mpio_none_type(new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't convert 'none' selection to MPI type")
+ break;
+
+ case H5S_SEL_ALL:
+ if(H5S_mpio_all_type(space, elmt_size, new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't convert 'all' selection to MPI type")
+ break;
+
+ case H5S_SEL_POINTS:
+ if(H5S_mpio_point_type(space, elmt_size, new_type, count, is_derived_type, do_permute, permute_map, is_permuted) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't convert 'point' selection to MPI type")
+ break;
+
+ case H5S_SEL_HYPERSLABS:
+ if((H5S_SELECT_IS_REGULAR(space) == TRUE)) {
+ if(H5S_mpio_hyper_type(space, elmt_size, new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't convert regular 'hyperslab' selection to MPI type")
+ } /* end if */
+ else {
+ if(H5S_mpio_span_hyper_type(space, elmt_size, new_type, count, is_derived_type) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't convert irregular 'hyperslab' selection to MPI type")
+ } /* end else */
+ break;
+
+ case H5S_SEL_ERROR:
+ case H5S_SEL_N:
+ default:
+ HDassert("unknown selection type" && 0);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case H5S_NO_CLASS:
+ default:
+ HDassert("unknown data space type" && 0);
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_mpio_space_type() */
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/src/H5Snone.c b/src/H5Snone.c
new file mode 100644
index 0000000..104b0bb
--- /dev/null
+++ b/src/H5Snone.c
@@ -0,0 +1,968 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Tuesday, November 10, 1998
+ *
+ * Purpose: "None" selection data space I/O functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h"
+#include "H5Eprivate.h"
+#include "H5Iprivate.h"
+#include "H5Spkg.h"
+#include "H5VMprivate.h"
+#include "H5Dprivate.h"
+
+/* Static function prototypes */
+
+/* Selection callbacks */
+static herr_t H5S_none_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+static herr_t H5S_none_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+static herr_t H5S_none_release(H5S_t *space);
+static htri_t H5S_none_is_valid(const H5S_t *space);
+static hssize_t H5S_none_serial_size(const H5S_t *space);
+static herr_t H5S_none_serialize(const H5S_t *space, uint8_t **p);
+static herr_t H5S_none_deserialize(H5S_t *space, uint32_t version, uint8_t flags,
+ const uint8_t **p);
+static herr_t H5S_none_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
+static herr_t H5S_none_offset(const H5S_t *space, hsize_t *off);
+static int H5S__none_unlim_dim(const H5S_t *space);
+static htri_t H5S_none_is_contiguous(const H5S_t *space);
+static htri_t H5S_none_is_single(const H5S_t *space);
+static htri_t H5S_none_is_regular(const H5S_t *space);
+static herr_t H5S_none_adjust_u(H5S_t *space, const hsize_t *offset);
+static herr_t H5S_none_project_scalar(const H5S_t *space, hsize_t *offset);
+static herr_t H5S_none_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+static herr_t H5S_none_iter_init(H5S_sel_iter_t *iter, const H5S_t *space);
+
+/* Selection iteration callbacks */
+static herr_t H5S_none_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords);
+static herr_t H5S_none_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+static hsize_t H5S_none_iter_nelmts(const H5S_sel_iter_t *iter);
+static htri_t H5S_none_iter_has_next_block(const H5S_sel_iter_t *iter);
+static herr_t H5S_none_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
+static herr_t H5S_none_iter_next_block(H5S_sel_iter_t *sel_iter);
+static herr_t H5S_none_iter_release(H5S_sel_iter_t *sel_iter);
+
+/* Selection properties for "none" selections */
+const H5S_select_class_t H5S_sel_none[1] = {{
+ H5S_SEL_NONE,
+
+ /* Methods on selection */
+ H5S_none_copy,
+ H5S_none_get_seq_list,
+ H5S_none_release,
+ H5S_none_is_valid,
+ H5S_none_serial_size,
+ H5S_none_serialize,
+ H5S_none_deserialize,
+ H5S_none_bounds,
+ H5S_none_offset,
+ H5S__none_unlim_dim,
+ NULL,
+ H5S_none_is_contiguous,
+ H5S_none_is_single,
+ H5S_none_is_regular,
+ H5S_none_adjust_u,
+ H5S_none_project_scalar,
+ H5S_none_project_simple,
+ H5S_none_iter_init,
+}};
+
+/* Iteration properties for "none" selections */
+static const H5S_sel_iter_class_t H5S_sel_iter_none[1] = {{
+ H5S_SEL_NONE,
+
+ /* Methods on selection iterator */
+ H5S_none_iter_coords,
+ H5S_none_iter_block,
+ H5S_none_iter_nelmts,
+ H5S_none_iter_has_next_block,
+ H5S_none_iter_next,
+ H5S_none_iter_next_block,
+ H5S_none_iter_release,
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_iter_init
+ *
+ * Purpose: Initializes iteration information for "none" selection.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_none_iter_init(H5S_sel_iter_t *iter, const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space && H5S_SEL_NONE==H5S_GET_SELECT_TYPE(space));
+ HDassert(iter);
+
+ /* Initialize type of selection iterator */
+ iter->type = H5S_sel_iter_none;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_none_iter_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_iter_coords
+ *
+ * Purpose: Retrieve the current coordinates of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 22, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_none_iter_coords(const H5S_sel_iter_t H5_ATTR_UNUSED *iter, hsize_t H5_ATTR_UNUSED *coords)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(coords);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_iter_coords() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_iter_block
+ *
+ * Purpose: Retrieve the current block of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 2, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_none_iter_block(const H5S_sel_iter_t H5_ATTR_UNUSED *iter, hsize_t H5_ATTR_UNUSED *start, hsize_t H5_ATTR_UNUSED *end)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(start);
+ HDassert(end);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_iter_block() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_iter_nelmts
+ *
+ * Purpose: Return number of elements left to process in iterator
+ *
+ * Return: non-negative number of elements on success, zero on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5S_none_iter_nelmts(const H5S_sel_iter_t H5_ATTR_UNUSED *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(0)
+} /* H5S_none_iter_nelmts() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_iter_has_next_block
+ PURPOSE
+ Check if there is another block left in the current iterator
+ USAGE
+ htri_t H5S_none_iter_has_next_block(iter)
+ const H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative (TRUE/FALSE) on success/Negative on failure
+ DESCRIPTION
+ Check if there is another block available in the selection iterator.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_none_iter_has_next_block(const H5S_sel_iter_t H5_ATTR_UNUSED *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_iter_has_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_iter_next
+ PURPOSE
+ Increment selection iterator
+ USAGE
+ herr_t H5S_none_iter_next(iter, nelem)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ size_t nelem; IN: Number of elements to advance by
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the NELEM'th next element in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_iter_next(H5S_sel_iter_t H5_ATTR_UNUSED *iter, size_t H5_ATTR_UNUSED nelem)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(nelem>0);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_none_iter_next() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_iter_next_block
+ PURPOSE
+ Increment selection iterator to next block
+ USAGE
+ herr_t H5S_none_iter_next(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the next block in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_iter_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_iter_release
+ PURPOSE
+ Release "none" selection iterator information for a dataspace
+ USAGE
+ herr_t H5S_none_iter_release(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all information for a dataspace "none" selection iterator
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_iter_release(H5S_sel_iter_t H5_ATTR_UNUSED * iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_none_iter_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_release
+ PURPOSE
+ Release none selection information for a dataspace
+ USAGE
+ herr_t H5S_none_release(space)
+ H5S_t *space; IN: Pointer to dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases "none" selection information for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_release(H5S_t H5_ATTR_UNUSED * space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_none_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_copy
+ PURPOSE
+ Copy a selection from one dataspace to another
+ USAGE
+ herr_t H5S_none_copy(dst, src)
+ H5S_t *dst; OUT: Pointer to the destination dataspace
+ H5S_t *src; IN: Pointer to the source dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Copies the 'none' selection information from the source
+ dataspace to the destination dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_copy(H5S_t *dst, const H5S_t H5_ATTR_UNUSED *src, hbool_t H5_ATTR_UNUSED share_selection)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(src);
+ HDassert(dst);
+
+ /* Set number of elements in selection */
+ dst->select.num_elem = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_none_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_is_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_none_is_valid(space);
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace. Offset is irrelevant for this type of selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_none_is_valid(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* end H5S_none_is_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_serial_size
+ PURPOSE
+ Determine the number of bytes needed to store the serialized "none"
+ selection information.
+ USAGE
+ hssize_t H5S_none_serial_size(space)
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ The number of bytes required on success, negative on an error.
+ DESCRIPTION
+ Determines the number of bytes required to serialize an "none"
+ selection for storage on disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hssize_t
+H5S_none_serial_size(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Basic number of bytes required to serialize point selection:
+ * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> +
+ * <length (4 bytes)> = 16 bytes
+ */
+ FUNC_LEAVE_NOAPI(16)
+} /* end H5S_none_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_serialize
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ herr_t H5S_none_serialize(space, p)
+ const H5S_t *space; IN: Dataspace with selection to serialize
+ uint8_t **p; OUT: Pointer to buffer to put serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_serialize(const H5S_t *space, uint8_t **p)
+{
+ uint8_t *pp = (*p); /* Local pointer for decoding */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Store the preamble information */
+ UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
+ UINT32ENCODE(pp, (uint32_t)1); /* Store the version number */
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the additional information length */
+
+ /* Update encoding pointer */
+ *p = pp;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_none_serialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_deserialize
+ PURPOSE
+ Deserialize the current selection from a user-provided buffer.
+ USAGE
+ herr_t H5S_none_deserialize(space, version, flags, p)
+ H5S_t *space; IN/OUT: Dataspace pointer to place
+ selection into
+ uint32_t version IN: Selection version
+ uint8_t flags IN: Selection flags
+ uint8 **p; OUT: Pointer to buffer holding serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Deserializes the current selection into a buffer. (Primarily for retrieving
+ from disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t H5_ATTR_UNUSED flags,
+ const uint8_t H5_ATTR_UNUSED **p)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(p);
+ HDassert(*p);
+
+ /* Change to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_none_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_none_bounds(space, start, end)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *start; OUT: Starting coordinate of bounding box
+ hsize_t *end; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8). Calling this function on a "none" selection
+ returns fail.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_bounds(const H5S_t H5_ATTR_UNUSED *space, hsize_t H5_ATTR_UNUSED *start, hsize_t H5_ATTR_UNUSED *end)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5Sget_none_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_offset
+ PURPOSE
+ Gets the linear offset of the first element for the selection.
+ USAGE
+ herr_t H5S_none_offset(space, offset)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *offset; OUT: Linear offset of first element in selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the linear offset (in "units" of elements) of the first element
+ selected within the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Calling this function on a "none" selection returns fail.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_offset(const H5S_t H5_ATTR_UNUSED *space, hsize_t H5_ATTR_UNUSED *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(offset);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__none_unlim_dim
+ PURPOSE
+ Return unlimited dimension of selection, or -1 if none
+ USAGE
+ int H5S__none_unlim_dim(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ Unlimited dimension of selection, or -1 if none (never fails).
+ DESCRIPTION
+ Returns the index of the unlimited dimension in this selection, or -1
+ if the selection has no unlimited dimension. "None" selections cannot
+ have an unlimited dimension, so this function always returns -1.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5S__none_unlim_dim(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(-1)
+} /* end H5S__none_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_is_contiguous
+ PURPOSE
+ Check if a "none" selection is contiguous within the dataspace extent.
+ USAGE
+ htri_t H5S_none_is_contiguous(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is contiguous.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_none_is_contiguous(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(FALSE)
+} /* H5S_none_is_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_is_single
+ PURPOSE
+ Check if a "none" selection is a single block within the dataspace extent.
+ USAGE
+ htri_t H5S_none_is_single(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is a single block.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_none_is_single(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(FALSE)
+} /* H5S_none_is_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_is_regular
+ PURPOSE
+ Check if a "none" selection is "regular"
+ USAGE
+ htri_t H5S_none_is_regular(space)
+ const H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in a dataspace is the a regular
+ pattern.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_none_is_regular(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI(TRUE)
+} /* H5S_none_is_regular() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_adjust_u
+ PURPOSE
+ Adjust an "none" selection by subtracting an offset
+ USAGE
+ herr_t H5S_none_adjust_u(space, offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_adjust_u(H5S_t H5_ATTR_UNUSED *space, const hsize_t H5_ATTR_UNUSED *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(offset);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_adjust_u() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_project_scalar
+ *
+ * Purpose: Projects a 'none' selection into a scalar dataspace
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_none_project_scalar(const H5S_t H5_ATTR_UNUSED *space, hsize_t H5_ATTR_UNUSED *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space && H5S_SEL_NONE == H5S_GET_SELECT_TYPE(space));
+ HDassert(offset);
+
+ FUNC_LEAVE_NOAPI(FAIL)
+} /* H5S_none_project_scalar() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_none_project_simple
+ *
+ * Purpose: Projects an 'none' selection onto/into a simple dataspace
+ * of a different rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_none_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_NONE == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(offset);
+
+ /* Select the entire new space */
+ if(H5S_select_none(new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to set none selection")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_none_project_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_none
+ PURPOSE
+ Specify that nothing is selected in the extent
+ USAGE
+ herr_t H5S_select_none(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function de-selects the entire extent for a dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_none(H5S_t *space)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+
+ /* Remove current selection first */
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release hyperslab")
+
+ /* Set number of elements in selection */
+ space->select.num_elem = 0;
+
+ /* Set selection type */
+ space->select.type = H5S_sel_none;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_none() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_none
+ PURPOSE
+ Specify that nothing is selected in the extent
+ USAGE
+ herr_t H5Sselect_none(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function de-selects the entire extent for a dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_none(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Change to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sselect_none() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_none_get_seq_list
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_none_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_none_get_seq_list(const H5S_t H5_ATTR_UNUSED *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t H5_ATTR_UNUSED *iter,
+ size_t H5_ATTR_UNUSED maxseq, size_t H5_ATTR_UNUSED maxelem, size_t *nseq, size_t *nelem,
+ hsize_t H5_ATTR_UNUSED *off, size_t H5_ATTR_UNUSED *len)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* "none" selections don't generate sequences of bytes */
+ *nseq = 0;
+
+ /* They don't use any elements, either */
+ *nelem = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S_none_get_seq_list() */
+
diff --git a/src/H5Spkg.h b/src/H5Spkg.h
new file mode 100644
index 0000000..315af29
--- /dev/null
+++ b/src/H5Spkg.h
@@ -0,0 +1,283 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, September 28, 2000
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5S package. Source files outside the H5S package should
+ * include H5Sprivate.h instead.
+ */
+#if !(defined H5S_FRIEND || defined H5S_MODULE)
+#error "Do not include this file outside the H5S package!"
+#endif
+
+#ifndef _H5Spkg_H
+#define _H5Spkg_H
+
+#include "H5Sprivate.h"
+
+/* Flags to indicate special dataspace features are active */
+#define H5S_VALID_MAX 0x01
+#define H5S_VALID_PERM 0x02
+
+/* Flags for serialization of selections */
+#define H5S_SELECT_FLAG_UNLIM 0x01
+#define H5S_SELECT_FLAG_BITS (H5S_SELECT_FLAG_UNLIM)
+
+/* Length of stack-allocated sequences for "project intersect" routines */
+#define H5S_PROJECT_INTERSECT_NSEQS 256
+
+
+/* Initial version of the dataspace information */
+#define H5O_SDSPACE_VERSION_1 1
+
+/* This version adds support for "null" dataspaces, encodes the type of the
+ * dataspace in the message and eliminated the rest of the "reserved"
+ * bytes.
+ */
+#define H5O_SDSPACE_VERSION_2 2
+
+/* The latest version of the format. Look through the 'encode'
+ * and 'size' callbacks for places to change when updating this. */
+#define H5O_SDSPACE_VERSION_LATEST H5O_SDSPACE_VERSION_2
+
+/* Maximum dimension size (highest value that is not a special value e.g.
+ * H5S_UNLIMITED) */
+#define H5S_MAX_SIZE ((hsize_t)(hssize_t)(-2))
+
+
+/*
+ * Dataspace extent information
+ */
+/* Extent container */
+struct H5S_extent_t {
+ H5O_shared_t sh_loc; /* Shared message info (must be first) */
+
+ H5S_class_t type; /* Type of extent */
+ unsigned version; /* Version of object header message to encode this object with */
+ hsize_t nelem; /* Number of elements in extent */
+
+ unsigned rank; /* Number of dimensions */
+ hsize_t *size; /* Current size of the dimensions */
+ hsize_t *max; /* Maximum size of the dimensions */
+};
+
+/*
+ * Dataspace selection information
+ */
+/* Node in point selection list (typedef'd in H5Sprivate.h) */
+struct H5S_pnt_node_t {
+ hsize_t *pnt; /* Pointer to a selected point */
+ struct H5S_pnt_node_t *next; /* pointer to next point in list */
+};
+
+/* Information about point selection list */
+typedef struct {
+ H5S_pnt_node_t *head; /* Pointer to head of point list */
+} H5S_pnt_list_t;
+
+/* Information about new-style hyperslab spans */
+
+/* Information a particular hyperslab span */
+struct H5S_hyper_span_t {
+ hsize_t low, high; /* Low & high bounds of span */
+ hsize_t nelem; /* Number of elements in span (only needed during I/O) */
+ hsize_t pstride; /* Pseudo-stride from start of previous span (only used during I/O) */
+ struct H5S_hyper_span_info_t *down; /* Pointer to list of spans in next dimension down */
+ struct H5S_hyper_span_t *next; /* Pointer to next span in list */
+};
+
+/* Information about a list of hyperslab spans */
+struct H5S_hyper_span_info_t {
+ unsigned count; /* Ref. count of number of spans which share this span */
+ struct H5S_hyper_span_info_t *scratch; /* Scratch pointer
+ * (used during copies, as mark
+ * during precomputes for I/O &
+ * to point to the last span in a
+ * list during single element adds)
+ */
+ struct H5S_hyper_span_t *head; /* Pointer to list of spans in next dimension down */
+};
+
+/* Information about new-style hyperslab selection */
+typedef struct {
+ hbool_t diminfo_valid; /* Whether the dataset has valid diminfo */
+ H5S_hyper_dim_t opt_diminfo[H5S_MAX_RANK]; /* per-dim selection info */
+ H5S_hyper_dim_t app_diminfo[H5S_MAX_RANK]; /* per-dim selection info */
+ /* 'opt_diminfo' points to a [potentially] optimized version of the user's
+ * hyperslab information. 'app_diminfo' points to the actual parameters
+ * that the application used for setting the hyperslab selection. These
+ * are only used for re-gurgitating the original values used to set the
+ * hyperslab to the application when it queries the hyperslab selection
+ * information. */
+ int unlim_dim; /* Dimension where selection is unlimited, or -1 if none */
+ hsize_t num_elem_non_unlim; /* # of elements in a "slice" excluding the unlimited dimension */
+ H5S_hyper_span_info_t *span_lst; /* List of hyperslab span information */
+} H5S_hyper_sel_t;
+
+/* Selection information methods */
+/* Method to copy a selection */
+typedef herr_t (*H5S_sel_copy_func_t)(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+/* Method to retrieve a list of offset/length sequences for selection */
+typedef herr_t (*H5S_sel_get_seq_list_func_t)(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+/* Method to release current selection */
+typedef herr_t (*H5S_sel_release_func_t)(H5S_t *space);
+/* Method to determine if current selection is valid for dataspace */
+typedef htri_t (*H5S_sel_is_valid_func_t)(const H5S_t *space);
+/* Method to determine number of bytes required to store current selection */
+typedef hssize_t (*H5S_sel_serial_size_func_t)(const H5S_t *space);
+/* Method to store current selection in "serialized" form (a byte sequence suitable for storing on disk) */
+typedef herr_t (*H5S_sel_serialize_func_t)(const H5S_t *space, uint8_t **p);
+/* Method to create selection from "serialized" form (a byte sequence suitable for storing on disk) */
+typedef herr_t (*H5S_sel_deserialize_func_t)(H5S_t *space, uint32_t version, uint8_t flags,
+ const uint8_t **p);
+/* Method to determine smallest n-D bounding box containing the current selection */
+typedef herr_t (*H5S_sel_bounds_func_t)(const H5S_t *space, hsize_t *start, hsize_t *end);
+/* Method to determine linear offset of initial element in selection within dataspace */
+typedef herr_t (*H5S_sel_offset_func_t)(const H5S_t *space, hsize_t *offset);
+/* Method to get unlimited dimension of selection (or -1 for none) */
+typedef int (*H5S_sel_unlim_dim_func_t)(const H5S_t *space);
+/* Method to get the number of elements in a slice through the unlimited dimension */
+typedef herr_t (*H5S_sel_num_elem_non_unlim_func_t)(const H5S_t *space,
+ hsize_t *num_elem_non_unlim);
+/* Method to determine if current selection is contiguous */
+typedef htri_t (*H5S_sel_is_contiguous_func_t)(const H5S_t *space);
+/* Method to determine if current selection is a single block */
+typedef htri_t (*H5S_sel_is_single_func_t)(const H5S_t *space);
+/* Method to determine if current selection is "regular" */
+typedef htri_t (*H5S_sel_is_regular_func_t)(const H5S_t *space);
+/* Method to adjust a selection by an offset */
+typedef herr_t (*H5S_sel_adjust_u_func_t)(H5S_t *space, const hsize_t *offset);
+/* Method to construct single element projection onto scalar dataspace */
+typedef herr_t (*H5S_sel_project_scalar)(const H5S_t *space, hsize_t *offset);
+/* Method to construct selection projection onto/into simple dataspace */
+typedef herr_t (*H5S_sel_project_simple)(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+/* Method to initialize iterator for current selection */
+typedef herr_t (*H5S_sel_iter_init_func_t)(H5S_sel_iter_t *sel_iter, const H5S_t *space);
+
+/* Selection class information */
+typedef struct {
+ H5S_sel_type type; /* Type of selection (all, none, points or hyperslab) */
+
+ /* Methods */
+ H5S_sel_copy_func_t copy; /* Method to make a copy of a selection */
+ H5S_sel_get_seq_list_func_t get_seq_list; /* Method to retrieve a list of offset/length sequences for selection */
+ H5S_sel_release_func_t release; /* Method to release current selection */
+ H5S_sel_is_valid_func_t is_valid; /* Method to determine if current selection is valid for dataspace */
+ H5S_sel_serial_size_func_t serial_size; /* Method to determine number of bytes required to store current selection */
+ H5S_sel_serialize_func_t serialize; /* Method to store current selection in "serialized" form (a byte sequence suitable for storing on disk) */
+ H5S_sel_deserialize_func_t deserialize; /* Method to store create selection from "serialized" form (a byte sequence suitable for storing on disk) */
+ H5S_sel_bounds_func_t bounds; /* Method to determine to smallest n-D bounding box containing the current selection */
+ H5S_sel_offset_func_t offset; /* Method to determine linear offset of initial element in selection within dataspace */
+ H5S_sel_unlim_dim_func_t unlim_dim; /* Method to get unlimited dimension of selection (or -1 for none) */
+ H5S_sel_num_elem_non_unlim_func_t num_elem_non_unlim; /* Method to get the number of elements in a slice through the unlimited dimension */
+ H5S_sel_is_contiguous_func_t is_contiguous; /* Method to determine if current selection is contiguous */
+ H5S_sel_is_single_func_t is_single; /* Method to determine if current selection is a single block */
+ H5S_sel_is_regular_func_t is_regular; /* Method to determine if current selection is "regular" */
+ H5S_sel_adjust_u_func_t adjust_u; /* Method to adjust a selection by an offset */
+ H5S_sel_project_scalar project_scalar; /* Method to construct scalar dataspace projection */
+ H5S_sel_project_simple project_simple; /* Method to construct simple dataspace projection */
+ H5S_sel_iter_init_func_t iter_init; /* Method to initialize iterator for current selection */
+} H5S_select_class_t;
+
+/* Selection information object */
+typedef struct {
+ const H5S_select_class_t *type; /* Pointer to selection's class info */
+ hbool_t offset_changed; /* Indicate that the offset for the selection has been changed */
+ hssize_t offset[H5S_MAX_RANK]; /* Offset within the extent */
+ hsize_t num_elem; /* Number of elements in selection */
+ union {
+ H5S_pnt_list_t *pnt_lst; /* List of selected points (order is important) */
+ H5S_hyper_sel_t *hslab; /* Info about hyperslab selections */
+ } sel_info;
+} H5S_select_t;
+
+/* Main dataspace structure (typedef'd in H5Sprivate.h) */
+struct H5S_t {
+ H5S_extent_t extent; /* Dataspace extent (must stay first) */
+ H5S_select_t select; /* Dataspace selection */
+};
+
+/* Selection iteration methods */
+/* Method to retrieve the current coordinates of iterator for current selection */
+typedef herr_t (*H5S_sel_iter_coords_func_t)(const H5S_sel_iter_t *iter, hsize_t *coords);
+/* Method to retrieve the current block of iterator for current selection */
+typedef herr_t (*H5S_sel_iter_block_func_t)(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+/* Method to determine number of elements left in iterator for current selection */
+typedef hsize_t (*H5S_sel_iter_nelmts_func_t)(const H5S_sel_iter_t *iter);
+/* Method to determine if there are more blocks left in the current selection */
+typedef htri_t (*H5S_sel_iter_has_next_block_func_t)(const H5S_sel_iter_t *iter);
+/* Method to move selection iterator to the next element in the selection */
+typedef herr_t (*H5S_sel_iter_next_func_t)(H5S_sel_iter_t *iter, size_t nelem);
+/* Method to move selection iterator to the next block in the selection */
+typedef herr_t (*H5S_sel_iter_next_block_func_t)(H5S_sel_iter_t *iter);
+/* Method to release iterator for current selection */
+typedef herr_t (*H5S_sel_iter_release_func_t)(H5S_sel_iter_t *iter);
+
+/* Selection iteration class */
+typedef struct H5S_sel_iter_class_t {
+ H5S_sel_type type; /* Type of selection (all, none, points or hyperslab) */
+
+ /* Methods on selections */
+ H5S_sel_iter_coords_func_t iter_coords; /* Method to retrieve the current coordinates of iterator for current selection */
+ H5S_sel_iter_block_func_t iter_block; /* Method to retrieve the current block of iterator for current selection */
+ H5S_sel_iter_nelmts_func_t iter_nelmts; /* Method to determine number of elements left in iterator for current selection */
+ H5S_sel_iter_has_next_block_func_t iter_has_next_block; /* Method to query if there is another block left in the selection */
+ H5S_sel_iter_next_func_t iter_next; /* Method to move selection iterator to the next element in the selection */
+ H5S_sel_iter_next_block_func_t iter_next_block; /* Method to move selection iterator to the next block in the selection */
+ H5S_sel_iter_release_func_t iter_release; /* Method to release iterator for current selection */
+} H5S_sel_iter_class_t;
+
+/*
+ * All selection class methods.
+ */
+H5_DLLVAR const H5S_select_class_t H5S_sel_all[1];
+
+/*
+ * Hyperslab selection class methods.
+ */
+H5_DLLVAR const H5S_select_class_t H5S_sel_hyper[1];
+
+/*
+ * None selection class methods.
+ */
+H5_DLLVAR const H5S_select_class_t H5S_sel_none[1];
+
+/*
+ * Pointer selection class methods.
+ */
+H5_DLLVAR const H5S_select_class_t H5S_sel_point[1];
+
+/* Extent functions */
+H5_DLL herr_t H5S_extent_release(H5S_extent_t *extent);
+H5_DLL herr_t H5S_extent_copy_real(H5S_extent_t *dst, const H5S_extent_t *src,
+ hbool_t copy_max);
+
+/* Operations on selections */
+H5_DLL herr_t H5S__hyper_project_intersection(const H5S_t *src_space,
+ const H5S_t *dst_space, const H5S_t *src_intersect_space,
+ H5S_t *proj_space);
+H5_DLL herr_t H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space);
+
+/* Testing functions */
+#ifdef H5S_TESTING
+H5_DLL htri_t H5S_select_shape_same_test(hid_t sid1, hid_t sid2);
+H5_DLL htri_t H5S_get_rebuild_status_test(hid_t space_id);
+#endif /* H5S_TESTING */
+
+#endif /*_H5Spkg_H*/
+
diff --git a/src/H5Spoint.c b/src/H5Spoint.c
new file mode 100644
index 0000000..251a063
--- /dev/null
+++ b/src/H5Spoint.c
@@ -0,0 +1,1766 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Tuesday, June 16, 1998
+ *
+ * Purpose: Point selection data space I/O functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* ID Functions */
+#include "H5MMprivate.h" /* Memory Management functions */
+#include "H5Spkg.h" /* Dataspace functions */
+#include "H5VMprivate.h" /* Vector functions */
+
+/* Static function prototypes */
+
+/* Selection callbacks */
+static herr_t H5S_point_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+static herr_t H5S_point_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+static herr_t H5S_point_release(H5S_t *space);
+static htri_t H5S_point_is_valid(const H5S_t *space);
+static hssize_t H5S_point_serial_size(const H5S_t *space);
+static herr_t H5S_point_serialize(const H5S_t *space, uint8_t **p);
+static herr_t H5S_point_deserialize(H5S_t *space, uint32_t version, uint8_t flags,
+ const uint8_t **p);
+static herr_t H5S_point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
+static herr_t H5S_point_offset(const H5S_t *space, hsize_t *off);
+static int H5S__point_unlim_dim(const H5S_t *space);
+static htri_t H5S_point_is_contiguous(const H5S_t *space);
+static htri_t H5S_point_is_single(const H5S_t *space);
+static htri_t H5S_point_is_regular(const H5S_t *space);
+static herr_t H5S_point_adjust_u(H5S_t *space, const hsize_t *offset);
+static herr_t H5S_point_project_scalar(const H5S_t *space, hsize_t *offset);
+static herr_t H5S_point_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+static herr_t H5S_point_iter_init(H5S_sel_iter_t *iter, const H5S_t *space);
+
+/* Selection iteration callbacks */
+static herr_t H5S_point_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords);
+static herr_t H5S_point_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+static hsize_t H5S_point_iter_nelmts(const H5S_sel_iter_t *iter);
+static htri_t H5S_point_iter_has_next_block(const H5S_sel_iter_t *iter);
+static herr_t H5S_point_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
+static herr_t H5S_point_iter_next_block(H5S_sel_iter_t *sel_iter);
+static herr_t H5S_point_iter_release(H5S_sel_iter_t *sel_iter);
+
+/* Selection properties for point selections */
+const H5S_select_class_t H5S_sel_point[1] = {{
+ H5S_SEL_POINTS,
+
+ /* Methods on selection */
+ H5S_point_copy,
+ H5S_point_get_seq_list,
+ H5S_point_release,
+ H5S_point_is_valid,
+ H5S_point_serial_size,
+ H5S_point_serialize,
+ H5S_point_deserialize,
+ H5S_point_bounds,
+ H5S_point_offset,
+ H5S__point_unlim_dim,
+ NULL,
+ H5S_point_is_contiguous,
+ H5S_point_is_single,
+ H5S_point_is_regular,
+ H5S_point_adjust_u,
+ H5S_point_project_scalar,
+ H5S_point_project_simple,
+ H5S_point_iter_init,
+}};
+
+/* Iteration properties for point selections */
+static const H5S_sel_iter_class_t H5S_sel_iter_point[1] = {{
+ H5S_SEL_POINTS,
+
+ /* Methods on selection iterator */
+ H5S_point_iter_coords,
+ H5S_point_iter_block,
+ H5S_point_iter_nelmts,
+ H5S_point_iter_has_next_block,
+ H5S_point_iter_next,
+ H5S_point_iter_next_block,
+ H5S_point_iter_release,
+}};
+
+/* Declare a free list to manage the H5S_pnt_node_t struct */
+H5FL_DEFINE_STATIC(H5S_pnt_node_t);
+
+/* Declare a free list to manage the H5S_pnt_list_t struct */
+H5FL_DEFINE_STATIC(H5S_pnt_list_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_iter_init
+ *
+ * Purpose: Initializes iteration information for point selection.
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_point_iter_init(H5S_sel_iter_t *iter, const H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space && H5S_SEL_POINTS==H5S_GET_SELECT_TYPE(space));
+ HDassert(iter);
+
+ /* Initialize the number of points to iterate over */
+ iter->elmt_left=space->select.num_elem;
+
+ /* Start at the head of the list of points */
+ iter->u.pnt.curr=space->select.sel_info.pnt_lst->head;
+
+ /* Initialize type of selection iterator */
+ iter->type=H5S_sel_iter_point;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_iter_coords
+ *
+ * Purpose: Retrieve the current coordinates of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 22, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_point_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(coords);
+
+ /* Copy the offset of the current point */
+ HDmemcpy(coords,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_coords() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_iter_block
+ *
+ * Purpose: Retrieve the current block of iterator for current
+ * selection
+ *
+ * Return: non-negative on success, negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 2, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_point_iter_block (const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(start);
+ HDassert(end);
+
+ /* Copy the current point as a block */
+ HDmemcpy(start,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank);
+ HDmemcpy(end,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_block() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_iter_nelmts
+ *
+ * Purpose: Return number of elements left to process in iterator
+ *
+ * Return: non-negative number of elements on success, zero on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5S_point_iter_nelmts (const H5S_sel_iter_t *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(iter->elmt_left)
+} /* H5S_point_iter_nelmts() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_iter_has_next_block
+ PURPOSE
+ Check if there is another block left in the current iterator
+ USAGE
+ htri_t H5S_point_iter_has_next_block(iter)
+ const H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative (TRUE/FALSE) on success/Negative on failure
+ DESCRIPTION
+ Check if there is another block available in the selection iterator.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_point_iter_has_next_block(const H5S_sel_iter_t *iter)
+{
+ htri_t ret_value=TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ /* Check if there is another point in the list */
+ if(iter->u.pnt.curr->next==NULL)
+ HGOTO_DONE(FALSE);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_iter_has_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_iter_next
+ PURPOSE
+ Increment selection iterator
+ USAGE
+ herr_t H5S_point_iter_next(iter, nelem)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ size_t nelem; IN: Number of elements to advance by
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the NELEM'th next element in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_iter_next(H5S_sel_iter_t *iter, size_t nelem)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(nelem>0);
+
+ /* Increment the iterator */
+ while(nelem>0) {
+ iter->u.pnt.curr=iter->u.pnt.curr->next;
+ nelem--;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_next() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_iter_next_block
+ PURPOSE
+ Increment selection iterator to next block
+ USAGE
+ herr_t H5S_point_iter_next_block(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Advance selection iterator to the next block in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_iter_next_block(H5S_sel_iter_t *iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ /* Increment the iterator */
+ iter->u.pnt.curr=iter->u.pnt.curr->next;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_next_block() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_iter_release
+ PURPOSE
+ Release point selection iterator information for a dataspace
+ USAGE
+ herr_t H5S_point_iter_release(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all information for a dataspace point selection iterator
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_iter_release (H5S_sel_iter_t H5_ATTR_UNUSED * iter)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_iter_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_add
+ PURPOSE
+ Add a series of elements to a point selection
+ USAGE
+ herr_t H5S_point_add(space, num_elem, coord)
+ H5S_t *space; IN: Dataspace of selection to modify
+ size_t num_elem; IN: Number of elements in COORD array.
+ const hsize_t *coord[]; IN: The location of each element selected
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function adds elements to the current point selection for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_add(H5S_t *space, H5S_seloper_t op, size_t num_elem, const hsize_t *coord)
+{
+ H5S_pnt_node_t *top = NULL, *curr = NULL, *new_node = NULL; /* Point selection nodes */
+ unsigned u; /* Counter */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(num_elem > 0);
+ HDassert(coord);
+ HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND);
+
+ for(u = 0; u < num_elem; u++) {
+ /* Allocate space for the new node */
+ if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
+
+ /* Initialize fields in node */
+ new_node->next = NULL;
+ if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(space->extent.rank * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information")
+
+ /* Copy over the coordinates */
+ HDmemcpy(new_node->pnt, coord + (u * space->extent.rank), (space->extent.rank * sizeof(hsize_t)));
+
+ /* Link into list */
+ if(top == NULL)
+ top = new_node;
+ else
+ curr->next = new_node;
+ curr = new_node;
+ } /* end for */
+ new_node = NULL;
+
+ /* Insert the list of points selected in the proper place */
+ if(op == H5S_SELECT_SET || op == H5S_SELECT_PREPEND) {
+ /* Append current list, if there is one */
+ if(space->select.sel_info.pnt_lst->head != NULL)
+ curr->next = space->select.sel_info.pnt_lst->head;
+
+ /* Put new list in point selection */
+ space->select.sel_info.pnt_lst->head = top;
+ } /* end if */
+ else { /* op==H5S_SELECT_APPEND */
+ H5S_pnt_node_t *tmp_node; /* Temporary point selection node */
+
+ tmp_node = space->select.sel_info.pnt_lst->head;
+ if(tmp_node != NULL) {
+ while(tmp_node->next != NULL)
+ tmp_node = tmp_node->next;
+
+ /* Append new list to point selection */
+ tmp_node->next = top;
+ } /* end if */
+ else
+ space->select.sel_info.pnt_lst->head = top;
+ } /* end else */
+
+ /* Set the number of elements in the new selection */
+ if(op == H5S_SELECT_SET)
+ space->select.num_elem = num_elem;
+ else
+ space->select.num_elem += num_elem;
+
+done:
+ if(ret_value < 0) {
+ /* Release possibly partially initialized new node */
+ if(new_node)
+ new_node = H5FL_FREE(H5S_pnt_node_t, new_node);
+
+ /* Release possible linked list of nodes */
+ while(top) {
+ curr = top->next;
+ H5MM_xfree(top->pnt);
+ top = H5FL_FREE(H5S_pnt_node_t, top);
+ top = curr;
+ } /* end while */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_add() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_release
+ PURPOSE
+ Release point selection information for a dataspace
+ USAGE
+ herr_t H5S_point_release(space)
+ H5S_t *space; IN: Pointer to dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all point selection information for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_release (H5S_t *space)
+{
+ H5S_pnt_node_t *curr, *next; /* Point selection nodes */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ /* Delete all the nodes from the list */
+ curr = space->select.sel_info.pnt_lst->head;
+ while(curr != NULL) {
+ next = curr->next;
+ H5MM_xfree(curr->pnt);
+ curr = H5FL_FREE(H5S_pnt_node_t, curr);
+ curr = next;
+ } /* end while */
+
+ /* Free & reset the point list header */
+ space->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, space->select.sel_info.pnt_lst);
+
+ /* Reset the number of elements in the selection */
+ space->select.num_elem = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_elements
+ PURPOSE
+ Specify a series of elements in the dataspace to select
+ USAGE
+ herr_t H5S_select_elements(dsid, op, num_elem, coord)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ size_t num_elem; IN: Number of elements in COORD array.
+ const hsize_t *coord; IN: The location of each element selected
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function selects array elements to be included in the selection for
+ the dataspace. The COORD array is a 2-D array of size <dataspace rank>
+ by NUM_ELEM (ie. a list of coordinates in the dataspace). The order of
+ the element coordinates in the COORD array specifies the order that the
+ array elements are iterated through when I/O is performed. Duplicate
+ coordinates are not checked for. The selection operator, OP, determines
+ how the new selection is to be combined with the existing selection for
+ the dataspace. Currently, only H5S_SELECT_SET is supported, which replaces
+ the existing selection with the one defined in this call. When operators
+ other than H5S_SELECT_SET are used to combine a new selection with an
+ existing selection, the selection ordering is reset to 'C' array ordering.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_elements(H5S_t *space, H5S_seloper_t op, size_t num_elem,
+ const hsize_t *coord)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(num_elem);
+ HDassert(coord);
+ HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND);
+
+ /* If we are setting a new selection, remove current selection first */
+ if(op == H5S_SELECT_SET || H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS)
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release point selection")
+
+ /* Allocate space for the point selection information if necessary */
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS || space->select.sel_info.pnt_lst == NULL)
+ if(NULL == (space->select.sel_info.pnt_lst = H5FL_CALLOC(H5S_pnt_list_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate element information")
+
+ /* Add points to selection */
+ if(H5S_point_add(space, op, num_elem, coord) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert elements")
+
+ /* Set selection type */
+ space->select.type = H5S_sel_point;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_elements() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_copy
+ PURPOSE
+ Copy a selection from one dataspace to another
+ USAGE
+ herr_t H5S_point_copy(dst, src)
+ H5S_t *dst; OUT: Pointer to the destination dataspace
+ H5S_t *src; IN: Pointer to the source dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Copies all the point selection information from the source
+ dataspace to the destination dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selection)
+{
+ H5S_pnt_node_t *curr, *new_node, *new_tail; /* Point information nodes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(src);
+ HDassert(dst);
+
+ /* Allocate room for the head of the point list */
+ if(NULL == (dst->select.sel_info.pnt_lst = H5FL_MALLOC(H5S_pnt_list_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point list node")
+
+ curr = src->select.sel_info.pnt_lst->head;
+ new_tail = NULL;
+ while(curr) {
+ /* Create new point */
+ if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
+ new_node->next = NULL;
+ if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(src->extent.rank * sizeof(hsize_t)))) {
+ new_node = H5FL_FREE(H5S_pnt_node_t, new_node);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information")
+ } /* end if */
+
+ /* Copy over the point's coordinates */
+ HDmemcpy(new_node->pnt, curr->pnt, (src->extent.rank * sizeof(hsize_t)));
+
+ /* Keep the order the same when copying */
+ if(NULL == new_tail)
+ new_tail = dst->select.sel_info.pnt_lst->head = new_node;
+ else {
+ new_tail->next = new_node;
+ new_tail = new_node;
+ } /* end else */
+
+ curr = curr->next;
+ } /* end while */
+
+done:
+ if(ret_value < 0 && dst->select.sel_info.pnt_lst) {
+ /* Traverse the (incomplete?) dst list, freeing all memory */
+ curr = dst->select.sel_info.pnt_lst->head;
+ while(curr) {
+ H5S_pnt_node_t *tmp_node = curr;
+
+ curr->pnt = (hsize_t *)H5MM_xfree(curr->pnt);
+ curr = curr->next;
+ tmp_node = H5FL_FREE(H5S_pnt_node_t, tmp_node);
+ } /* end while */
+
+ dst->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, dst->select.sel_info.pnt_lst);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_point_copy() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_is_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_point_is_valid(space);
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_point_is_valid (const H5S_t *space)
+{
+ H5S_pnt_node_t *curr; /* Point information nodes */
+ unsigned u; /* Counter */
+ htri_t ret_value=TRUE; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Check each point to determine whether selection+offset is within extent */
+ curr = space->select.sel_info.pnt_lst->head;
+ while(curr != NULL) {
+ /* Check each dimension */
+ for(u = 0; u < space->extent.rank; u++) {
+ /* Check if an offset has been defined */
+ /* Bounds check the selected point + offset against the extent */
+ if(((curr->pnt[u] + (hsize_t)space->select.offset[u]) > space->extent.size[u])
+ || (((hssize_t)curr->pnt[u] + space->select.offset[u]) < 0))
+ HGOTO_DONE(FALSE)
+ } /* end for */
+
+ curr = curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_point_is_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_elem_npoints
+ PURPOSE
+ Get the number of points in current element selection
+ USAGE
+ hssize_t H5Sget_select_elem_npoints(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ RETURNS
+ The number of element points in selection on success, negative on failure
+ DESCRIPTION
+ Returns the number of element points in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hssize_t
+H5Sget_select_elem_npoints(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ hssize_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Hs", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an element selection")
+
+ ret_value = (hssize_t)H5S_GET_SELECT_NPOINTS(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_elem_npoints() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_serial_size
+ PURPOSE
+ Determine the number of bytes needed to store the serialized point selection
+ information.
+ USAGE
+ hssize_t H5S_point_serial_size(space)
+ H5S_t *space; IN: Dataspace pointer to query
+ RETURNS
+ The number of bytes required on success, negative on an error.
+ DESCRIPTION
+ Determines the number of bytes required to serialize the current point
+ selection information for storage on disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hssize_t
+H5S_point_serial_size (const H5S_t *space)
+{
+ H5S_pnt_node_t *curr; /* Point information nodes */
+ hssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Basic number of bytes required to serialize point selection:
+ * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> +
+ * <length (4 bytes)> + <rank (4 bytes)> + <# of points (4 bytes)> = 24 bytes
+ */
+ ret_value=24;
+
+ /* Count points in selection */
+ curr=space->select.sel_info.pnt_lst->head;
+ while(curr!=NULL) {
+ /* Add 4 bytes times the rank for each element selected */
+ ret_value+=4*space->extent.rank;
+ curr=curr->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_point_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_serialize
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ herr_t H5S_point_serialize(space, p)
+ const H5S_t *space; IN: Dataspace with selection to serialize
+ uint8_t **p; OUT: Pointer to buffer to put serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_serialize (const H5S_t *space, uint8_t **p)
+{
+ H5S_pnt_node_t *curr; /* Point information nodes */
+ uint8_t *pp = (*p); /* Local pointer for decoding */
+ uint8_t *lenp; /* pointer to length location for later storage */
+ uint32_t len=0; /* number of bytes used */
+ unsigned u; /* local counting variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Store the preamble information */
+ UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
+ UINT32ENCODE(pp, (uint32_t)1); /* Store the version number */
+ UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
+ lenp = pp; /* Keep the pointer to the length location for later */
+ pp += 4; /* Skip over space for length */
+
+ /* Encode number of dimensions */
+ UINT32ENCODE(pp, (uint32_t)space->extent.rank);
+ len+=4;
+
+ /* Encode number of elements */
+ UINT32ENCODE(pp, (uint32_t)space->select.num_elem);
+ len+=4;
+
+ /* Encode each point in selection */
+ curr=space->select.sel_info.pnt_lst->head;
+ while(curr!=NULL) {
+ /* Add 4 bytes times the rank for each element selected */
+ len+=4*space->extent.rank;
+
+ /* Encode each point */
+ for(u=0; u<space->extent.rank; u++)
+ UINT32ENCODE(pp, (uint32_t)curr->pnt[u]);
+
+ curr=curr->next;
+ } /* end while */
+
+ /* Encode length */
+ UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */
+
+ /* Update encoding pointer */
+ *p = pp;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_serialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_deserialize
+ PURPOSE
+ Deserialize the current selection from a user-provided buffer.
+ USAGE
+ herr_t H5S_point_deserialize(space, p)
+ H5S_t *space; IN/OUT: Dataspace pointer to place
+ selection into
+ uint32_t version IN: Selection version
+ uint8_t flags IN: Selection flags
+ uint8 **p; OUT: Pointer to buffer holding serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Deserializes the current selection into a buffer. (Primarily for retrieving
+ from disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t H5_ATTR_UNUSED flags,
+ const uint8_t **p)
+{
+ H5S_seloper_t op = H5S_SELECT_SET; /* Selection operation */
+ hsize_t *coord = NULL, *tcoord; /* Pointer to array of elements */
+ const uint8_t *pp = (*p); /* Local pointer for decoding */
+ size_t num_elem = 0; /* Number of elements in selection */
+ unsigned rank; /* Rank of points */
+ unsigned i, j; /* local counting variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(p);
+ HDassert(pp);
+
+ /* Deserialize points to select */
+ /* (The header and rank have already beed decoded) */
+ rank = space->extent.rank; /* Retrieve rank from space */
+ UINT32DECODE(pp, num_elem); /* decode the number of points */
+
+ /* Allocate space for the coordinates */
+ if(NULL == (coord = (hsize_t *)H5MM_malloc(num_elem * rank * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate coordinate information")
+
+ /* Retrieve the coordinates from the buffer */
+ for(tcoord = coord, i = 0; i < num_elem; i++)
+ for(j = 0; j < (unsigned)rank; j++, tcoord++)
+ UINT32DECODE(pp, *tcoord);
+
+ /* Select points */
+ if(H5S_select_elements(space, op, num_elem, (const hsize_t *)coord) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+
+ /* Update decoding pointer */
+ *p = pp;
+
+done:
+ /* Free the coordinate array if necessary */
+ if(coord != NULL)
+ H5MM_xfree(coord);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_elem_pointlist
+ PURPOSE
+ Get the list of element points currently selected
+ USAGE
+ herr_t H5S_get_select_elem_pointlist(space, hsize_t *buf)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t startpoint; IN: Element point to start with
+ hsize_t numpoints; IN: Number of element points to get
+ hsize_t *buf; OUT: List of element points selected
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Puts a list of the element points into the user's buffer. The points
+ start with the 'startpoint'th block in the list of points and put
+ 'numpoints' number of points into the user's buffer (or until the end of
+ the list of points, whichever happen first)
+ The point coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of points is formatted as
+ follows: <coordinate> followed by the next coordinate, etc. until all the
+ point information in the selection have been put into the user's buffer.
+ The points are returned in the order they will be interated through
+ when a selection is read/written from/to disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_get_select_elem_pointlist(H5S_t *space, hsize_t startpoint, hsize_t numpoints, hsize_t *buf)
+{
+ H5S_pnt_node_t *node; /* Point node */
+ unsigned rank; /* Dataspace rank */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(buf);
+
+ /* Get the dataspace extent rank */
+ rank = space->extent.rank;
+
+ /* Get the head of the point list */
+ node = space->select.sel_info.pnt_lst->head;
+
+ /* Iterate to the first point to return */
+ while(node != NULL && startpoint > 0) {
+ startpoint--;
+ node = node->next;
+ } /* end while */
+
+ /* Iterate through the node, copying each point's information */
+ while(node != NULL && numpoints > 0) {
+ HDmemcpy(buf, node->pnt, sizeof(hsize_t) * rank);
+ buf += rank;
+ numpoints--;
+ node = node->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_get_select_elem_pointlist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_elem_pointlist
+ PURPOSE
+ Get the list of element points currently selected
+ USAGE
+ herr_t H5Sget_select_elem_pointlist(dsid, hsize_t *buf)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ hsize_t startpoint; IN: Element point to start with
+ hsize_t numpoints; IN: Number of element points to get
+ hsize_t buf[]; OUT: List of element points selected
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Puts a list of the element points into the user's buffer. The points
+ start with the 'startpoint'th block in the list of points and put
+ 'numpoints' number of points into the user's buffer (or until the end of
+ the list of points, whichever happen first)
+ The point coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of points is formatted as
+ follows: <coordinate> followed by the next coordinate, etc. until all the
+ point information in the selection have been put into the user's buffer.
+ The points are returned in the order they will be interated through
+ when a selection is read/written from/to disk.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint,
+ hsize_t numpoints, hsize_t buf[/*numpoints*/])
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "ihh*[a2]h", spaceid, startpoint, numpoints, buf);
+
+ /* Check args */
+ if(NULL == buf)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a point selection")
+
+ ret_value = H5S_get_select_elem_pointlist(space, startpoint, numpoints, buf);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_elem_pointlist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_point_bounds(space, start, end)
+ H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *start; OUT: Starting coordinate of bounding box
+ hsize_t *end; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8).
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
+{
+ H5S_pnt_node_t *node; /* Point node */
+ unsigned rank; /* Dataspace rank */
+ unsigned u; /* index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ /* Get the dataspace extent rank */
+ rank = space->extent.rank;
+
+ /* Set the start and end arrays up */
+ for(u = 0; u < rank; u++) {
+ start[u] = HSIZET_MAX;
+ end[u] = 0;
+ } /* end for */
+
+ /* Iterate through the node, checking the bounds on each element */
+ node = space->select.sel_info.pnt_lst->head;
+ while(node != NULL) {
+ for(u = 0; u < rank; u++) {
+ /* Check for offset moving selection negative */
+ if(((hssize_t)node->pnt[u] + space->select.offset[u]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ if(start[u] > (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]))
+ start[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]);
+ if(end[u] < (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]))
+ end[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]);
+ } /* end for */
+ node = node->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_offset
+ PURPOSE
+ Gets the linear offset of the first element for the selection.
+ USAGE
+ herr_t H5S_point_offset(space, offset)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *offset; OUT: Linear offset of first element in selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the linear offset (in "units" of elements) of the first element
+ selected within the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Calling this function on a "none" selection returns fail.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_offset(const H5S_t *space, hsize_t *offset)
+{
+ const hsize_t *pnt; /* Pointer to a selected point's coordinates */
+ const hssize_t *sel_offset; /* Pointer to the selection's offset */
+ const hsize_t *dim_size; /* Pointer to a dataspace's extent */
+ hsize_t accum; /* Accumulator for dimension sizes */
+ int i; /* index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+ HDassert(offset);
+
+ /* Start at linear offset 0 */
+ *offset = 0;
+
+ /* Set up pointers to arrays of values */
+ pnt = space->select.sel_info.pnt_lst->head->pnt;
+ sel_offset = space->select.offset;
+ dim_size = space->extent.size;
+
+ /* Loop through coordinates, calculating the linear offset */
+ accum = 1;
+ for(i = (int)space->extent.rank - 1; i >= 0; i--) {
+ hssize_t pnt_offset = (hssize_t)pnt[i] + sel_offset[i]; /* Point's offset in this dimension */
+
+ /* Check for offset moving selection out of the dataspace */
+ if(pnt_offset < 0 || (hsize_t)pnt_offset >= dim_size[i])
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
+
+ /* Add the point's offset in this dimension to the total linear offset */
+ *offset += (hsize_t)pnt_offset * accum;
+
+ /* Increase the accumulator */
+ accum *= dim_size[i];
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__point_unlim_dim
+ PURPOSE
+ Return unlimited dimension of selection, or -1 if none
+ USAGE
+ int H5S__point_unlim_dim(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ Unlimited dimension of selection, or -1 if none (never fails).
+ DESCRIPTION
+ Returns the index of the unlimited dimension in this selection, or -1
+ if the selection has no unlimited dimension. Currently point
+ selections cannot have an unlimited dimension, so this function always
+ returns -1.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static int
+H5S__point_unlim_dim(const H5S_t H5_ATTR_UNUSED *space)
+{
+ FUNC_ENTER_STATIC_NOERR
+
+ FUNC_LEAVE_NOAPI(-1)
+} /* end H5S__point_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_is_contiguous
+ PURPOSE
+ Check if a point selection is contiguous within the dataspace extent.
+ USAGE
+ htri_t H5S_point_is_contiguous(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is contiguous.
+ This is primarily used for reading the entire selection in one swoop.
+ This code currently doesn't properly check for contiguousness when there is
+ more than one point, as that would take a lot of extra coding that we
+ don't need now.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_point_is_contiguous(const H5S_t *space)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* One point is definitely contiguous */
+ if(space->select.num_elem==1)
+ ret_value=TRUE;
+ else /* More than one point might be contiguous, but it's complex to check and we don't need it right now */
+ ret_value=FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_is_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_is_single
+ PURPOSE
+ Check if a point selection is single within the dataspace extent.
+ USAGE
+ htri_t H5S_point_is_single(space)
+ H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspace is a single block.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_point_is_single(const H5S_t *space)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* One point is definitely 'single' :-) */
+ if(space->select.num_elem==1)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_is_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_is_regular
+ PURPOSE
+ Check if a point selection is "regular"
+ USAGE
+ htri_t H5S_point_is_regular(space)
+ const H5S_t *space; IN: Dataspace pointer to check
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in a dataspace is the a regular
+ pattern.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Doesn't check for points selected to be next to one another in a regular
+ pattern yet.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_point_is_regular(const H5S_t *space)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ /* Only simple check for regular points for now... */
+ if(space->select.num_elem==1)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_is_regular() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_adjust_u
+ PURPOSE
+ Adjust a "point" selection by subtracting an offset
+ USAGE
+ herr_t H5S_point_adjust_u(space, offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves a point selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_adjust_u(H5S_t *space, const hsize_t *offset)
+{
+ H5S_pnt_node_t *node; /* Point node */
+ unsigned rank; /* Dataspace rank */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(offset);
+
+ /* Iterate through the nodes, checking the bounds on each element */
+ node = space->select.sel_info.pnt_lst->head;
+ rank = space->extent.rank;
+ while(node) {
+ unsigned u; /* Local index variable */
+
+ /* Adjust each coordinate for point node */
+ for(u = 0; u < rank; u++) {
+ /* Check for offset moving selection negative */
+ HDassert(node->pnt[u] >= offset[u]);
+
+ /* Adjust node's coordinate location */
+ node->pnt[u] -= offset[u];
+ } /* end for */
+
+ /* Advance to next point node in selection */
+ node = node->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_point_adjust_u() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_project_scalar
+ *
+ * Purpose: Projects a single element point selection into a scalar
+ * dataspace
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_point_project_scalar(const H5S_t *space, hsize_t *offset)
+{
+ const H5S_pnt_node_t *node; /* Point node */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space));
+ HDassert(offset);
+
+ /* Get the head of the point list */
+ node = space->select.sel_info.pnt_lst->head;
+
+ /* Check for more than one point selected */
+ if(node->next)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "point selection of one element has more than one node!")
+
+ /* Calculate offset of selection in projected buffer */
+ *offset = H5VM_array_offset(space->extent.rank, space->extent.size, node->pnt);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_project_scalar() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_point_project_simple
+ *
+ * Purpose: Projects a point selection onto/into a simple dataspace
+ * of a different rank
+ *
+ * Return: non-negative on success, negative on failure.
+ *
+ * Programmer: Quincey Koziol
+ * Sunday, July 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
+{
+ const H5S_pnt_node_t *base_node; /* Point node in base space */
+ H5S_pnt_node_t *new_node; /* Point node in new space */
+ H5S_pnt_node_t *prev_node; /* Previous point node in new space */
+ unsigned rank_diff; /* Difference in ranks between spaces */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(base_space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(base_space));
+ HDassert(new_space);
+ HDassert(offset);
+
+ /* We are setting a new selection, remove any current selection in new dataspace */
+ if(H5S_SELECT_RELEASE(new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+
+ /* Allocate room for the head of the point list */
+ if(NULL == (new_space->select.sel_info.pnt_lst = H5FL_MALLOC(H5S_pnt_list_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point list node")
+
+ /* Check if the new space's rank is < or > base space's rank */
+ if(new_space->extent.rank < base_space->extent.rank) {
+ hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
+
+ /* Compute the difference in ranks */
+ rank_diff = base_space->extent.rank - new_space->extent.rank;
+
+ /* Calculate offset of selection in projected buffer */
+ HDmemset(block, 0, sizeof(block));
+ HDmemcpy(block, base_space->select.sel_info.pnt_lst->head->pnt, sizeof(hsize_t) * rank_diff);
+ *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
+
+ /* Iterate through base space's point nodes, copying the point information */
+ base_node = base_space->select.sel_info.pnt_lst->head;
+ prev_node = NULL;
+ while(base_node) {
+ /* Create new point */
+ if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
+ new_node->next = NULL;
+ if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) {
+ new_node = H5FL_FREE(H5S_pnt_node_t, new_node);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information")
+ } /* end if */
+
+ /* Copy over the point's coordinates */
+ HDmemcpy(new_node->pnt, &base_node->pnt[rank_diff], (new_space->extent.rank * sizeof(hsize_t)));
+
+ /* Keep the order the same when copying */
+ if(NULL == prev_node)
+ prev_node = new_space->select.sel_info.pnt_lst->head = new_node;
+ else {
+ prev_node->next = new_node;
+ prev_node = new_node;
+ } /* end else */
+
+ /* Advance to next node */
+ base_node = base_node->next;
+ } /* end while */
+ } /* end if */
+ else {
+ HDassert(new_space->extent.rank > base_space->extent.rank);
+
+ /* Compute the difference in ranks */
+ rank_diff = new_space->extent.rank - base_space->extent.rank;
+
+ /* The offset is zero when projected into higher dimensions */
+ *offset = 0;
+
+ /* Iterate through base space's point nodes, copying the point information */
+ base_node = base_space->select.sel_info.pnt_lst->head;
+ prev_node = NULL;
+ while(base_node) {
+ /* Create new point */
+ if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
+ new_node->next = NULL;
+ if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) {
+ new_node = H5FL_FREE(H5S_pnt_node_t, new_node);
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information")
+ } /* end if */
+
+ /* Copy over the point's coordinates */
+ HDmemset(new_node->pnt, 0, sizeof(hsize_t) * rank_diff);
+ HDmemcpy(&new_node->pnt[rank_diff], base_node->pnt, (new_space->extent.rank * sizeof(hsize_t)));
+
+ /* Keep the order the same when copying */
+ if(NULL == prev_node)
+ prev_node = new_space->select.sel_info.pnt_lst->head = new_node;
+ else {
+ prev_node->next = new_node;
+ prev_node = new_node;
+ } /* end else */
+
+ /* Advance to next node */
+ base_node = base_node->next;
+ } /* end while */
+ } /* end else */
+
+ /* Number of elements selected will be the same */
+ new_space->select.num_elem = base_space->select.num_elem;
+
+ /* Set selection type */
+ new_space->select.type = H5S_sel_point;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_point_project_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_elements
+ PURPOSE
+ Specify a series of elements in the dataspace to select
+ USAGE
+ herr_t H5Sselect_elements(dsid, op, num_elem, coord)
+ hid_t dsid; IN: Dataspace ID of selection to modify
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ size_t num_elem; IN: Number of elements in COORD array.
+ const hsize_t *coord; IN: The location of each element selected
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ This function selects array elements to be included in the selection for
+ the dataspace. The COORD array is a 2-D array of size <dataspace rank>
+ by NUM_ELEM (ie. a list of coordinates in the dataspace). The order of
+ the element coordinates in the COORD array specifies the order that the
+ array elements are iterated through when I/O is performed. Duplicate
+ coordinates are not checked for. The selection operator, OP, determines
+ how the new selection is to be combined with the existing selection for
+ the dataspace. Currently, only H5S_SELECT_SET is supported, which replaces
+ the existing selection with the one defined in this call. When operators
+ other than H5S_SELECT_SET are used to combine a new selection with an
+ existing selection, the selection ordering is reset to 'C' array ordering.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sselect_elements(hid_t spaceid, H5S_seloper_t op, size_t num_elem,
+ const hsize_t *coord)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iSsz*h", spaceid, op, num_elem, coord);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(H5S_SCALAR == H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "point doesn't support H5S_SCALAR space")
+ if(H5S_NULL == H5S_GET_EXTENT_TYPE(space))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "point doesn't support H5S_NULL space")
+ if(coord == NULL || num_elem == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "elements not specified")
+ if(!(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "unsupported operation attempted")
+
+ /* Call the real element selection routine */
+ if((ret_value = H5S_select_elements(space, op, num_elem, coord)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't select elements")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sselect_elements() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_point_get_seq_list
+ PURPOSE
+ Create a list of offsets & lengths for a selection
+ USAGE
+ herr_t H5S_point_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_point_get_seq_list(const H5S_t *space, unsigned flags, H5S_sel_iter_t *iter,
+ size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
+ hsize_t *off, size_t *len)
+{
+ size_t io_left; /* The number of bytes left in the selection */
+ size_t start_io_left; /* The initial number of bytes left in the selection */
+ H5S_pnt_node_t *node; /* Point node */
+ hsize_t dims[H5O_LAYOUT_NDIMS]; /* Total size of memory buf */
+ int ndims; /* Dimensionality of space*/
+ hsize_t acc; /* Coordinate accumulator */
+ hsize_t loc; /* Coordinate offset */
+ size_t curr_seq; /* Current sequence being operated on */
+ int i; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(space);
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
+
+ /* Choose the minimum number of bytes to sequence through */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ start_io_left = io_left = (size_t)MIN(iter->elmt_left, maxelem);
+
+ /* Get the dataspace dimensions */
+ if((ndims = H5S_get_simple_extent_dims (space, dims, NULL)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to retrieve data space dimensions")
+
+ /* Walk through the points in the selection, starting at the current */
+ /* location in the iterator */
+ node = iter->u.pnt.curr;
+ curr_seq = 0;
+ while(NULL != node) {
+ /* Compute the offset of each selected point in the buffer */
+ for(i = ndims - 1, acc = iter->elmt_size, loc = 0; i >= 0; i--) {
+ loc += (hsize_t)((hssize_t)node->pnt[i] + space->select.offset[i]) * acc;
+ acc *= dims[i];
+ } /* end for */
+
+ /* Check if this is a later point in the selection */
+ if(curr_seq>0) {
+ /* If a sorted sequence is requested, make certain we don't go backwards in the offset */
+ if((flags&H5S_GET_SEQ_LIST_SORTED) && loc<off[curr_seq-1])
+ break;
+
+ /* Check if this point extends the previous sequence */
+ /* (Unlikely, but possible) */
+ if(loc==(off[curr_seq-1]+len[curr_seq-1])) {
+ /* Extend the previous sequence */
+ len[curr_seq-1]+=iter->elmt_size;
+ } /* end if */
+ else {
+ /* Add a new sequence */
+ off[curr_seq]=loc;
+ len[curr_seq]=iter->elmt_size;
+
+ /* Increment sequence count */
+ curr_seq++;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Add a new sequence */
+ off[curr_seq]=loc;
+ len[curr_seq]=iter->elmt_size;
+
+ /* Increment sequence count */
+ curr_seq++;
+ } /* end else */
+
+ /* Decrement number of elements left to process */
+ io_left--;
+
+ /* Move the iterator */
+ iter->u.pnt.curr=node->next;
+ iter->elmt_left--;
+
+ /* Check if we're finished with all sequences */
+ if(curr_seq==maxseq)
+ break;
+
+ /* Check if we're finished with all the elements available */
+ if(io_left==0)
+ break;
+
+ /* Advance to the next point */
+ node=node->next;
+ } /* end while */
+
+ /* Set the number of sequences generated */
+ *nseq=curr_seq;
+
+ /* Set the number of elements used */
+ *nelem=start_io_left-io_left;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_point_get_seq_list() */
+
diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h
new file mode 100644
index 0000000..60e0630
--- /dev/null
+++ b/src/H5Sprivate.h
@@ -0,0 +1,324 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5S module
+ */
+#ifndef _H5Sprivate_H
+#define _H5Sprivate_H
+
+/* Include package's public header */
+#include "H5Spublic.h"
+
+/* Public headers needed by this file */
+#include "H5Dpublic.h" /* Datasets */
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* Files */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tprivate.h" /* Datatypes */
+
+/* Flags for H5S_find */
+#define H5S_CONV_PAR_IO_POSSIBLE 0x0001
+/* The storage options are mutually exclusive */
+/* (2-bits reserved for storage type currently) */
+#define H5S_CONV_STORAGE_COMPACT 0x0000 /* i.e. '0' */
+#define H5S_CONV_STORAGE_CONTIGUOUS 0x0002 /* i.e. '1' */
+#define H5S_CONV_STORAGE_CHUNKED 0x0004 /* i.e. '2' */
+#define H5S_CONV_STORAGE_MASK 0x0006
+
+/* Flags for "get_seq_list" methods */
+#define H5S_GET_SEQ_LIST_SORTED 0x0001
+
+/* Forward references of package typedefs */
+typedef struct H5S_t H5S_t;
+typedef struct H5S_extent_t H5S_extent_t;
+typedef struct H5S_pnt_node_t H5S_pnt_node_t;
+typedef struct H5S_hyper_span_t H5S_hyper_span_t;
+typedef struct H5S_hyper_span_info_t H5S_hyper_span_info_t;
+
+/* Information about one dimension in a hyperslab selection */
+typedef struct H5S_hyper_dim_t {
+ hsize_t start;
+ hsize_t stride;
+ hsize_t count;
+ hsize_t block;
+} H5S_hyper_dim_t;
+
+/* Point selection iteration container */
+typedef struct {
+ H5S_pnt_node_t *curr; /* Pointer to next node to output */
+} H5S_point_iter_t;
+
+/* Hyperslab selection iteration container */
+typedef struct {
+ /* Common fields for all hyperslab selections */
+ hsize_t off[H5S_MAX_RANK]; /* Offset in span node (used as position for regular hyperslabs) */
+ unsigned iter_rank; /* Rank of iterator information */
+ /* (This should always be the same as the dataspace
+ * rank, except for regular hyperslab selections in
+ * which there are contiguous regions in the lower
+ * dimensions which have been "flattened" out
+ */
+ hbool_t diminfo_valid; /* Whether the dimension information is valid */
+
+ /* "Flattened" regular hyperslab selection fields */
+ H5S_hyper_dim_t diminfo[H5S_MAX_RANK]; /* "Flattened" regular selection information */
+ hsize_t size[H5S_MAX_RANK]; /* "Flattened" dataspace extent information */
+ hssize_t sel_off[H5S_MAX_RANK]; /* "Flattened" selection offset information */
+ hbool_t flattened[H5S_MAX_RANK]; /* Whether this dimension has been flattened */
+
+ /* Irregular hyperslab selection fields */
+ H5S_hyper_span_info_t *spans; /* Pointer to copy of the span tree */
+ H5S_hyper_span_t *span[H5S_MAX_RANK];/* Array of pointers to span nodes */
+} H5S_hyper_iter_t;
+
+/* "All" selection iteration container */
+typedef struct {
+ hsize_t elmt_offset; /* Next element to output */
+ hsize_t byte_offset; /* Next byte to output */
+} H5S_all_iter_t;
+
+/* Forward declaration of selection iteration class */
+struct H5S_sel_iter_class_t;
+
+/* Selection iteration container */
+typedef struct H5S_sel_iter_t {
+ /* Selection class */
+ const struct H5S_sel_iter_class_t *type; /* Selection iteration class info */
+
+ /* Information common to all iterators */
+ unsigned rank; /* Rank of dataspace the selection iterator is operating on */
+ hsize_t *dims; /* Dimensions of dataspace the selection is operating on */
+ hsize_t elmt_left; /* Number of elements left to iterate over */
+ size_t elmt_size; /* Size of elements to iterate over */
+
+ /* Information specific to each type of iterator */
+ union {
+ H5S_point_iter_t pnt; /* Point selection iteration information */
+ H5S_hyper_iter_t hyp; /* New Hyperslab selection iteration information */
+ H5S_all_iter_t all; /* "All" selection iteration information */
+ } u;
+} H5S_sel_iter_t;
+
+/* Selection iteration operator for internal library callbacks */
+typedef herr_t (*H5S_sel_iter_lib_op_t)(void *elem, const H5T_t *type,
+ unsigned ndim, const hsize_t *point, void *op_data);
+
+/* Describe kind of callback to make */
+typedef enum H5S_sel_iter_op_type_t {
+ H5S_SEL_ITER_OP_APP, /* Application callback */
+ H5S_SEL_ITER_OP_LIB /* Library internal callback */
+} H5S_sel_iter_op_type_t;
+
+typedef struct H5S_sel_iter_app_op_t {
+ H5D_operator_t op; /* Callback */
+ hid_t type_id; /* Type ID to be passed to callback */
+} H5S_sel_iter_app_op_t;
+
+typedef struct H5S_sel_iter_op_t {
+ H5S_sel_iter_op_type_t op_type;
+ union {
+ H5S_sel_iter_app_op_t app_op; /* Application callback */
+ H5S_sel_iter_lib_op_t lib_op; /* Library internal callback */
+ } u;
+} H5S_sel_iter_op_t;
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5S_MODULE
+#define H5S_GET_EXTENT_TYPE(S) ((S)->extent.type)
+#define H5S_GET_EXTENT_NDIMS(S) ((S)->extent.rank)
+#define H5S_GET_EXTENT_NPOINTS(S) ((S)->extent.nelem)
+#define H5S_GET_SELECT_NPOINTS(S) ((S)->select.num_elem)
+#define H5S_GET_SELECT_TYPE(S) ((S)->select.type->type)
+#define H5S_SELECT_GET_SEQ_LIST(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) ((*(S)->select.type->get_seq_list)(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN))
+#define H5S_SELECT_VALID(S) ((*(S)->select.type->is_valid)(S))
+#define H5S_SELECT_RELEASE(S) ((*(S)->select.type->release)(S))
+#define H5S_SELECT_SERIAL_SIZE(S) ((*(S)->select.type->serial_size)(S))
+#define H5S_SELECT_SERIALIZE(S,BUF) ((*(S)->select.type->serialize)(S,BUF))
+#define H5S_SELECT_BOUNDS(S,START,END) ((*(S)->select.type->bounds)(S,START,END))
+#define H5S_SELECT_OFFSET(S, OFFSET) ((*(S)->select.type->offset)(S, OFFSET))
+#define H5S_SELECT_IS_CONTIGUOUS(S) ((*(S)->select.type->is_contiguous)(S))
+#define H5S_SELECT_IS_SINGLE(S) ((*(S)->select.type->is_single)(S))
+#define H5S_SELECT_IS_REGULAR(S) ((*(S)->select.type->is_regular)(S))
+#define H5S_SELECT_ADJUST_U(S,O) ((*(S)->select.type->adjust_u)(S, O))
+#define H5S_SELECT_PROJECT_SCALAR(S,O) ((*(S)->select.type->project_scalar)(S, O))
+#define H5S_SELECT_PROJECT_SIMPLE(S,NS, O) ((*(S)->select.type->project_simple)(S, NS, O))
+#define H5S_SELECT_ITER_COORDS(ITER,COORDS) ((*(ITER)->type->iter_coords)(ITER,COORDS))
+#define H5S_SELECT_ITER_BLOCK(ITER,START,END) ((*(ITER)->type->iter_block)(ITER,START,END))
+#define H5S_SELECT_ITER_NELMTS(ITER) ((*(ITER)->type->iter_nelmts)(ITER))
+#define H5S_SELECT_ITER_HAS_NEXT_BLOCK(ITER) ((*(ITER)->type->iter_has_next_block)(ITER))
+#define H5S_SELECT_ITER_NEXT(ITER,NELEM)((*(ITER)->type->iter_next)(ITER,NELEM))
+#define H5S_SELECT_ITER_NEXT_BLOCK(ITER) ((*(ITER)->type->iter_next_block)(ITER))
+#define H5S_SELECT_ITER_RELEASE(ITER) ((*(ITER)->type->iter_release)(ITER))
+#else /* H5S_MODULE */
+#define H5S_GET_EXTENT_TYPE(S) (H5S_get_simple_extent_type(S))
+#define H5S_GET_EXTENT_NDIMS(S) (H5S_get_simple_extent_ndims(S))
+#define H5S_GET_EXTENT_NPOINTS(S) (H5S_get_simple_extent_npoints(S))
+#define H5S_GET_SELECT_NPOINTS(S) (H5S_get_select_npoints(S))
+#define H5S_GET_SELECT_TYPE(S) (H5S_get_select_type(S))
+#define H5S_SELECT_GET_SEQ_LIST(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) (H5S_select_get_seq_list(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN))
+#define H5S_SELECT_VALID(S) (H5S_select_valid(S))
+#define H5S_SELECT_RELEASE(S) (H5S_select_release(S))
+#define H5S_SELECT_SERIAL_SIZE(S) (H5S_select_serial_size(S))
+#define H5S_SELECT_SERIALIZE(S,BUF) (H5S_select_serialize(S,BUF))
+#define H5S_SELECT_BOUNDS(S,START,END) (H5S_get_select_bounds(S,START,END))
+#define H5S_SELECT_OFFSET(S, OFFSET) (H5S_get_select_offset(S, OFFSET))
+#define H5S_SELECT_IS_CONTIGUOUS(S) (H5S_select_is_contiguous(S))
+#define H5S_SELECT_IS_SINGLE(S) (H5S_select_is_single(S))
+#define H5S_SELECT_IS_REGULAR(S) (H5S_select_is_regular(S))
+#define H5S_SELECT_ADJUST_U(S,O) (H5S_select_adjust_u(S, O))
+#define H5S_SELECT_PROJECT_SCALAR(S,O) (H5S_select_project_scalar(S, O))
+#define H5S_SELECT_PROJECT_SIMPLE(S,NS,O) (H5S_select_project_simple(S, NS, O))
+#define H5S_SELECT_ITER_COORDS(ITER,COORDS) (H5S_select_iter_coords(ITER,COORDS))
+#define H5S_SELECT_ITER_BLOCK(ITER,START,END) (H5S_select_iter_block(ITER,START,END))
+#define H5S_SELECT_ITER_NELMTS(ITER) (H5S_select_iter_nelmts(ITER))
+#define H5S_SELECT_ITER_HAS_NEXT_BLOCK(ITER) (H5S_select_iter_has_next_block(ITER))
+#define H5S_SELECT_ITER_NEXT(ITER,NELEM)(H5S_select_iter_next(ITER,NELEM))
+#define H5S_SELECT_ITER_NEXT_BLOCK(ITER) (H5S_select_iter_next_block(ITER))
+#define H5S_SELECT_ITER_RELEASE(ITER) (H5S_select_iter_release(ITER))
+#endif /* H5S_MODULE */
+/* Handle these two callbacks in a special way, since they have prologs that need to be executed */
+#define H5S_SELECT_COPY(DST,SRC,SHARE) (H5S_select_copy(DST,SRC,SHARE))
+#define H5S_SELECT_DESERIALIZE(S,BUF) (H5S_select_deserialize(S,BUF))
+
+
+/* Operations on dataspaces */
+H5_DLL H5S_t *H5S_copy(const H5S_t *src, hbool_t share_selection, hbool_t copy_max);
+H5_DLL herr_t H5S_close(H5S_t *ds);
+H5_DLL H5S_class_t H5S_get_simple_extent_type(const H5S_t *ds);
+H5_DLL hssize_t H5S_get_simple_extent_npoints(const H5S_t *ds);
+H5_DLL hsize_t H5S_get_npoints_max(const H5S_t *ds);
+H5_DLL hbool_t H5S_has_extent(const H5S_t *ds);
+H5_DLL int H5S_get_simple_extent_ndims(const H5S_t *ds);
+H5_DLL int H5S_get_simple_extent_dims(const H5S_t *ds, hsize_t dims[]/*out*/,
+ hsize_t max_dims[]/*out*/);
+H5_DLL herr_t H5S_write(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned update_flags,
+ H5S_t *ds);
+H5_DLL herr_t H5S_append(H5F_t *f, hid_t dxpl_id, struct H5O_t *oh, H5S_t *ds);
+H5_DLL H5S_t *H5S_read(const struct H5O_loc_t *loc, hid_t dxpl_id);
+H5_DLL htri_t H5S_set_extent(H5S_t *space, const hsize_t *size);
+H5_DLL herr_t H5S_set_extent_real(H5S_t *space, const hsize_t *size);
+H5_DLL herr_t H5S_set_extent_simple(H5S_t *space, unsigned rank,
+ const hsize_t *dims, const hsize_t *max);
+H5_DLL H5S_t *H5S_create(H5S_class_t type);
+H5_DLL H5S_t *H5S_create_simple(unsigned rank, const hsize_t dims[/*rank*/],
+ const hsize_t maxdims[/*rank*/]);
+H5_DLL herr_t H5S_set_latest_version(H5S_t *ds);
+H5_DLL herr_t H5S_encode(H5S_t *obj, unsigned char **p, size_t *nalloc);
+H5_DLL H5S_t *H5S_decode(const unsigned char **p);
+H5_DLL herr_t H5S_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE *stream,
+ int indent, int fwidth);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+H5_DLL int H5S_extend(H5S_t *space, const hsize_t *size);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+/* Operations on dataspace extents */
+H5_DLL hsize_t H5S_extent_nelem(const H5S_extent_t *ext);
+H5_DLL int H5S_extent_get_dims(const H5S_extent_t *ext, hsize_t dims[], hsize_t max_dims[]);
+H5_DLL htri_t H5S_extent_equal(const H5S_t *ds1, const H5S_t *ds2);
+H5_DLL herr_t H5S_extent_copy(H5S_t *dst, const H5S_t *src);
+
+/* Operations on selections */
+H5_DLL herr_t H5S_select_deserialize(H5S_t **space, const uint8_t **p);
+H5_DLL H5S_sel_type H5S_get_select_type(const H5S_t *space);
+H5_DLL herr_t H5S_select_iterate(void *buf, const H5T_t *type, const H5S_t *space,
+ const H5S_sel_iter_op_t *op, void *op_data);
+H5_DLL herr_t H5S_select_fill(const void *fill, size_t fill_size,
+ const H5S_t *space, void *buf);
+H5_DLL htri_t H5S_select_valid(const H5S_t *space);
+H5_DLL hssize_t H5S_get_select_npoints(const H5S_t *space);
+H5_DLL herr_t H5S_get_select_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
+H5_DLL herr_t H5S_get_select_offset(const H5S_t *space, hsize_t *offset);
+H5_DLL int H5S_get_select_unlim_dim(const H5S_t *space);
+H5_DLL herr_t H5S_get_select_num_elem_non_unlim(const H5S_t *space,
+ hsize_t *num_elem_non_unlim);
+H5_DLL herr_t H5S_select_offset(H5S_t *space, const hssize_t *offset);
+H5_DLL herr_t H5S_select_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
+H5_DLL htri_t H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2);
+H5_DLL herr_t H5S_select_construct_projection(const H5S_t *base_space,
+ H5S_t **new_space_ptr, unsigned new_space_rank, const void *buf,
+ void const **adj_buf_ptr, hsize_t element_size);
+H5_DLL herr_t H5S_select_release(H5S_t *ds);
+H5_DLL herr_t H5S_select_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
+H5_DLL hssize_t H5S_select_serial_size(const H5S_t *space);
+H5_DLL herr_t H5S_select_serialize(const H5S_t *space, uint8_t **p);
+H5_DLL htri_t H5S_select_is_contiguous(const H5S_t *space);
+H5_DLL htri_t H5S_select_is_single(const H5S_t *space);
+H5_DLL htri_t H5S_select_is_regular(const H5S_t *space);
+H5_DLL herr_t H5S_select_adjust_u(H5S_t *space, const hsize_t *offset);
+H5_DLL herr_t H5S_select_project_scalar(const H5S_t *space, hsize_t *offset);
+H5_DLL herr_t H5S_select_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
+H5_DLL herr_t H5S_select_project_intersection(const H5S_t *src_space,
+ const H5S_t *dst_space, const H5S_t *src_intersect_space,
+ H5S_t **new_space_ptr);
+H5_DLL herr_t H5S_select_subtract(H5S_t *space, H5S_t *subtract_space);
+
+/* Operations on all selections */
+H5_DLL herr_t H5S_select_all(H5S_t *space, hbool_t rel_prev);
+
+/* Operations on none selections */
+H5_DLL herr_t H5S_select_none(H5S_t *space);
+
+/* Operations on point selections */
+H5_DLL herr_t H5S_select_elements(H5S_t *space, H5S_seloper_t op,
+ size_t num_elem, const hsize_t *coord);
+
+/* Operations on hyperslab selections */
+H5_DLL herr_t H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, const hsize_t start[],
+ const hsize_t *stride, const hsize_t count[], const hsize_t *block);
+H5_DLL herr_t H5S_hyper_add_span_element(H5S_t *space, unsigned rank,
+ hsize_t *coords);
+H5_DLL herr_t H5S_hyper_reset_scratch(H5S_t *space);
+H5_DLL herr_t H5S_hyper_convert(H5S_t *space);
+#ifdef LATER
+H5_DLL htri_t H5S_hyper_intersect (H5S_t *space1, H5S_t *space2);
+#endif /* LATER */
+H5_DLL htri_t H5S_hyper_intersect_block (H5S_t *space, hsize_t *start, hsize_t *end);
+H5_DLL herr_t H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset);
+H5_DLL htri_t H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset);
+H5_DLL herr_t H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset);
+H5_DLL herr_t H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size);
+H5_DLL hsize_t H5S_hyper_get_clip_extent(const H5S_t *clip_space,
+ const H5S_t *match_space, hbool_t incl_trail);
+H5_DLL hsize_t H5S_hyper_get_clip_extent_match(const H5S_t *clip_space,
+ const H5S_t *match_space, hsize_t match_clip_size, hbool_t incl_trail);
+H5_DLL H5S_t *H5S_hyper_get_unlim_block(const H5S_t *space,
+ hsize_t block_index);
+H5_DLL hsize_t H5S_hyper_get_first_inc_block(const H5S_t *space,
+ hsize_t clip_size, hbool_t *partial);
+
+/* Operations on selection iterators */
+H5_DLL herr_t H5S_select_iter_init(H5S_sel_iter_t *iter, const H5S_t *space, size_t elmt_size);
+H5_DLL herr_t H5S_select_iter_coords(const H5S_sel_iter_t *sel_iter, hsize_t *coords);
+H5_DLL hsize_t H5S_select_iter_nelmts(const H5S_sel_iter_t *sel_iter);
+H5_DLL herr_t H5S_select_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
+H5_DLL herr_t H5S_select_iter_release(H5S_sel_iter_t *sel_iter);
+
+#ifdef H5_HAVE_PARALLEL
+H5_DLL herr_t H5S_mpio_space_type(const H5S_t *space, size_t elmt_size,
+ /* out: */ MPI_Datatype *new_type,
+ int *count,
+ hbool_t *is_derived_type,
+ hbool_t do_permute,
+ hsize_t **permute_map,
+ hbool_t * is_permuted);
+#endif /* H5_HAVE_PARALLEL */
+
+#endif /* _H5Sprivate_H */
+
diff --git a/src/H5Spublic.h b/src/H5Spublic.h
new file mode 100644
index 0000000..5ed6249
--- /dev/null
+++ b/src/H5Spublic.h
@@ -0,0 +1,155 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5S module.
+ */
+#ifndef _H5Spublic_H
+#define _H5Spublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Ipublic.h"
+
+/* Define atomic datatypes */
+#define H5S_ALL (hid_t)0
+#define H5S_UNLIMITED HSIZE_UNDEF
+
+/* Define user-level maximum number of dimensions */
+#define H5S_MAX_RANK 32
+
+/* Different types of dataspaces */
+typedef enum H5S_class_t {
+ H5S_NO_CLASS = -1, /*error */
+ H5S_SCALAR = 0, /*scalar variable */
+ H5S_SIMPLE = 1, /*simple data space */
+ H5S_NULL = 2 /*null data space */
+} H5S_class_t;
+
+/* Different ways of combining selections */
+typedef enum H5S_seloper_t {
+ H5S_SELECT_NOOP = -1, /* error */
+ H5S_SELECT_SET = 0, /* Select "set" operation */
+ H5S_SELECT_OR, /* Binary "or" operation for hyperslabs
+ * (add new selection to existing selection)
+ * Original region: AAAAAAAAAA
+ * New region: BBBBBBBBBB
+ * A or B: CCCCCCCCCCCCCCCC
+ */
+ H5S_SELECT_AND, /* Binary "and" operation for hyperslabs
+ * (only leave overlapped regions in selection)
+ * Original region: AAAAAAAAAA
+ * New region: BBBBBBBBBB
+ * A and B: CCCC
+ */
+ H5S_SELECT_XOR, /* Binary "xor" operation for hyperslabs
+ * (only leave non-overlapped regions in selection)
+ * Original region: AAAAAAAAAA
+ * New region: BBBBBBBBBB
+ * A xor B: CCCCCC CCCCCC
+ */
+ H5S_SELECT_NOTB, /* Binary "not" operation for hyperslabs
+ * (only leave non-overlapped regions in original selection)
+ * Original region: AAAAAAAAAA
+ * New region: BBBBBBBBBB
+ * A not B: CCCCCC
+ */
+ H5S_SELECT_NOTA, /* Binary "not" operation for hyperslabs
+ * (only leave non-overlapped regions in new selection)
+ * Original region: AAAAAAAAAA
+ * New region: BBBBBBBBBB
+ * B not A: CCCCCC
+ */
+ H5S_SELECT_APPEND, /* Append elements to end of point selection */
+ H5S_SELECT_PREPEND, /* Prepend elements to beginning of point selection */
+ H5S_SELECT_INVALID /* Invalid upper bound on selection operations */
+} H5S_seloper_t;
+
+/* Enumerated type for the type of selection */
+typedef enum {
+ H5S_SEL_ERROR = -1, /* Error */
+ H5S_SEL_NONE = 0, /* Nothing selected */
+ H5S_SEL_POINTS = 1, /* Sequence of points selected */
+ H5S_SEL_HYPERSLABS = 2, /* "New-style" hyperslab selection defined */
+ H5S_SEL_ALL = 3, /* Entire extent selected */
+ H5S_SEL_N /*THIS MUST BE LAST */
+}H5S_sel_type;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions in H5S.c */
+H5_DLL hid_t H5Screate(H5S_class_t type);
+H5_DLL hid_t H5Screate_simple(int rank, const hsize_t dims[],
+ const hsize_t maxdims[]);
+H5_DLL herr_t H5Sset_extent_simple(hid_t space_id, int rank,
+ const hsize_t dims[],
+ const hsize_t max[]);
+H5_DLL hid_t H5Scopy(hid_t space_id);
+H5_DLL herr_t H5Sclose(hid_t space_id);
+H5_DLL herr_t H5Sencode(hid_t obj_id, void *buf, size_t *nalloc);
+H5_DLL hid_t H5Sdecode(const void *buf);
+H5_DLL hssize_t H5Sget_simple_extent_npoints(hid_t space_id);
+H5_DLL int H5Sget_simple_extent_ndims(hid_t space_id);
+H5_DLL int H5Sget_simple_extent_dims(hid_t space_id, hsize_t dims[],
+ hsize_t maxdims[]);
+H5_DLL htri_t H5Sis_simple(hid_t space_id);
+H5_DLL hssize_t H5Sget_select_npoints(hid_t spaceid);
+H5_DLL herr_t H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t _stride[],
+ const hsize_t count[],
+ const hsize_t _block[]);
+/* #define NEW_HYPERSLAB_API */
+/* Note that these haven't been working for a while and were never
+ * publicly released - QAK */
+#ifdef NEW_HYPERSLAB_API
+H5_DLL hid_t H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op,
+ const hsize_t start[],
+ const hsize_t _stride[],
+ const hsize_t count[],
+ const hsize_t _block[]);
+H5_DLL herr_t H5Sselect_select(hid_t space1_id, H5S_seloper_t op,
+ hid_t space2_id);
+H5_DLL hid_t H5Scombine_select(hid_t space1_id, H5S_seloper_t op,
+ hid_t space2_id);
+#endif /* NEW_HYPERSLAB_API */
+H5_DLL herr_t H5Sselect_elements(hid_t space_id, H5S_seloper_t op,
+ size_t num_elem, const hsize_t *coord);
+H5_DLL H5S_class_t H5Sget_simple_extent_type(hid_t space_id);
+H5_DLL herr_t H5Sset_extent_none(hid_t space_id);
+H5_DLL herr_t H5Sextent_copy(hid_t dst_id,hid_t src_id);
+H5_DLL htri_t H5Sextent_equal(hid_t sid1, hid_t sid2);
+H5_DLL herr_t H5Sselect_all(hid_t spaceid);
+H5_DLL herr_t H5Sselect_none(hid_t spaceid);
+H5_DLL herr_t H5Soffset_simple(hid_t space_id, const hssize_t *offset);
+H5_DLL htri_t H5Sselect_valid(hid_t spaceid);
+H5_DLL htri_t H5Sis_regular_hyperslab(hid_t spaceid);
+H5_DLL htri_t H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[],
+ hsize_t stride[], hsize_t count[], hsize_t block[]);
+H5_DLL hssize_t H5Sget_select_hyper_nblocks(hid_t spaceid);
+H5_DLL hssize_t H5Sget_select_elem_npoints(hid_t spaceid);
+H5_DLL herr_t H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock,
+ hsize_t numblocks, hsize_t buf[/*numblocks*/]);
+H5_DLL herr_t H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint,
+ hsize_t numpoints, hsize_t buf[/*numpoints*/]);
+H5_DLL herr_t H5Sget_select_bounds(hid_t spaceid, hsize_t start[],
+ hsize_t end[]);
+H5_DLL H5S_sel_type H5Sget_select_type(hid_t spaceid);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Spublic_H */
+
diff --git a/src/H5Sselect.c b/src/H5Sselect.c
new file mode 100644
index 0000000..c34e1cc
--- /dev/null
+++ b/src/H5Sselect.c
@@ -0,0 +1,2453 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.ued>
+ * Friday, May 29, 1998
+ *
+ * Purpose: Dataspace selection functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Spkg.h" /* Dataspaces */
+#include "H5VMprivate.h" /* Vector and array functions */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+/* Local functions */
+#ifdef LATER
+static herr_t H5S_select_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
+static htri_t H5S_select_iter_has_next_block(const H5S_sel_iter_t *iter);
+static herr_t H5S_select_iter_next_block(H5S_sel_iter_t *iter);
+#endif /* LATER */
+
+/* Declare a free list to manage the H5S_sel_iter_t struct */
+H5FL_DEFINE(H5S_sel_iter_t);
+
+/* Declare extern free list to manage sequences of size_t */
+H5FL_SEQ_EXTERN(size_t);
+
+/* Declare extern free list to manage sequences of hsize_t */
+H5FL_SEQ_EXTERN(hsize_t);
+
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_offset
+ PURPOSE
+ Set the selection offset for a datapace
+ USAGE
+ herr_t H5S_select_offset(space, offset)
+ H5S_t *space; IN/OUT: Dataspace object to set selection offset
+ const hssize_t *offset; IN: Offset to position the selection at
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Sets the selection offset for the dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Only works for simple dataspaces currently
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_offset(H5S_t *space, const hssize_t *offset)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(0 < space->extent.rank && space->extent.rank <= H5S_MAX_RANK);
+ HDassert(offset);
+
+ /* Copy the offset over */
+ HDmemcpy(space->select.offset, offset, sizeof(hssize_t)*space->extent.rank);
+
+ /* Indicate that the offset was changed */
+ space->select.offset_changed = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5S_select_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_copy
+ PURPOSE
+ Copy a selection from one dataspace to another
+ USAGE
+ herr_t H5S_select_copy(dst, src)
+ H5S_t *dst; OUT: Pointer to the destination dataspace
+ H5S_t *src; IN: Pointer to the source dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Copies all the selection information (include offset) from the source
+ dataspace to the destination dataspace.
+
+ If the SHARE_SELECTION flag is set, then the selection can be shared
+ between the source and destination dataspaces. (This should only occur in
+ situations where the destination dataspace will immediately change to a new
+ selection)
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_copy (H5S_t *dst, const H5S_t *src, hbool_t share_selection)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(dst);
+ HDassert(src);
+
+ /* Copy regular fields */
+ dst->select=src->select;
+
+ /* Perform correct type of copy based on the type of selection */
+ if((ret_value=(*src->select.type->copy)(dst,src,share_selection))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy selection specific information")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_release
+ *
+ * Purpose: Releases all memory associated with a dataspace selection.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 30, 2003
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_select_release(H5S_t *ds)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(ds);
+
+ /* Call the selection type's release function */
+ ret_value=(*ds->select.type->release)(ds);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_release() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_get_seq_list
+ *
+ * Purpose: Retrieves the next sequence of offset/length pairs for an
+ * iterator on a dataspace
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 18, 2004
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S_select_get_seq_list(const H5S_t *space, unsigned flags,
+ H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
+ size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Call the selection type's get_seq_list function */
+ ret_value = (*space->select.type->get_seq_list)(space, flags, iter, maxseq, maxbytes, nseq, nbytes, off, len);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_get_seq_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_serial_size
+ *
+ * Purpose: Determines the number of bytes required to store the current
+ * selection
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, May 18, 2004
+ *
+ * Note: This routine participates in the "Inlining C function pointers"
+ * pattern, don't call it directly, use the appropriate macro
+ * defined in H5Sprivate.h.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hssize_t
+H5S_select_serial_size(const H5S_t *space)
+{
+ hssize_t ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ /* Call the selection type's serial_size function */
+ ret_value=(*space->select.type->serial_size)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_serialize
+ PURPOSE
+ Serialize the selection for a dataspace into a buffer
+ USAGE
+ herr_t H5S_select_serialize(space, p)
+ const H5S_t *space; IN: Dataspace with selection to serialize
+ uint8_t **p; OUT: Pointer to buffer to put serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Calls the appropriate dataspace selection callback to serialize the
+ current selection into a buffer.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_serialize(const H5S_t *space, uint8_t **p)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+ HDassert(p);
+
+ /* Call the selection type's serialize function */
+ ret_value=(*space->select.type->serialize)(space,p);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_serialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_npoints
+ PURPOSE
+ Get the number of elements in current selection
+ USAGE
+ hssize_t H5Sget_select_npoints(dsid)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Returns the number of elements in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hssize_t
+H5Sget_select_npoints(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ hssize_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Hs", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = (hssize_t)H5S_GET_SELECT_NPOINTS(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_npoints() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_npoints
+ PURPOSE
+ Get the number of elements in current selection
+ USAGE
+ hssize_t H5Sget_select_npoints(space)
+ H5S_t *space; IN: Dataspace of selection to query
+ RETURNS
+ The number of elements in selection on success, 0 on failure
+ DESCRIPTION
+ Returns the number of elements in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hssize_t
+H5S_get_select_npoints(const H5S_t *space)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ FUNC_LEAVE_NOAPI((hssize_t)space->select.num_elem)
+} /* H5S_get_select_npoints() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sselect_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5Sselect_void(dsid)
+ hid_t dsid; IN: Dataspace ID to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+ Christian Chilan 01/17/2007
+ Changed the error return value from 0 to FAIL.
+--------------------------------------------------------------------------*/
+htri_t
+H5Sselect_valid(hid_t spaceid)
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ htri_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", spaceid);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = H5S_SELECT_VALID(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sselect_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_valid
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_select_void(space)
+ H5S_t *space; IN: Dataspace to query
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_valid(const H5S_t *space)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(space);
+
+ ret_value = (*space->select.type->is_valid)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_deserialize
+ PURPOSE
+ Deserialize the current selection from a user-provided buffer into a real
+ selection in the dataspace.
+ USAGE
+ herr_t H5S_select_deserialize(space, p)
+ H5S_t **space; IN/OUT: Dataspace pointer to place
+ selection into. Will be allocated if not
+ provided.
+ uint8 **p; OUT: Pointer to buffer holding serialized
+ selection. Will be advanced to end of
+ serialized selection.
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Deserializes the current selection into a buffer. (Primarily for retrieving
+ from disk). This routine just hands off to the appropriate routine for each
+ type of selection. The format of the serialized information is shown in
+ the H5S_select_serialize() header.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_deserialize(H5S_t **space, const uint8_t **p)
+{
+ H5S_t *tmp_space = NULL; /* Pointer to actual dataspace to use, either
+ *space or a newly allocated one */
+ uint32_t sel_type; /* Pointer to the selection type */
+ uint32_t version; /* Version number */
+ uint8_t flags = 0; /* Flags */
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(space);
+
+ /* Allocate space if not provided */
+ if(!*space) {
+ if(NULL == (tmp_space = H5S_create(H5S_SIMPLE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace")
+ } /* end if */
+ else
+ tmp_space = *space;
+
+ /* Decode selection type */
+ UINT32DECODE(*p, sel_type);
+
+ /* Decode version */
+ UINT32DECODE(*p, version);
+
+ if(version >= (uint32_t)2) {
+ /* Decode flags */
+ flags = *(*p)++;
+
+ /* Check for unknown flags */
+ if(flags & ~H5S_SELECT_FLAG_BITS)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown flag for selection")
+
+ /* Skip over the remainder of the header */
+ *p += 4;
+ } /* end if */
+ else
+ /* Skip over the remainder of the header */
+ *p += 8;
+
+ /* Decode and check or patch rank for point and hyperslab selections */
+ if((sel_type == H5S_SEL_POINTS) || (sel_type == H5S_SEL_HYPERSLABS)) {
+ uint32_t rank; /* Rank of dataspace */
+
+ /* Decode the rank of the point selection */
+ UINT32DECODE(*p,rank);
+
+ if(!*space) {
+ hsize_t dims[H5S_MAX_RANK];
+
+ /* Patch the rank of the allocated dataspace */
+ (void)HDmemset(dims, 0, (size_t)rank * sizeof(dims[0]));
+ if(H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions")
+ } /* end if */
+ else
+ /* Verify the rank of the provided dataspace */
+ if(rank != tmp_space->extent.rank)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "rank of serialized selection does not match dataspace")
+ } /* end if */
+
+ /* Make routine for selection type */
+ switch(sel_type) {
+ case H5S_SEL_POINTS: /* Sequence of points selected */
+ ret_value = (*H5S_sel_point->deserialize)(tmp_space, version, flags, p);
+ break;
+
+ case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */
+ ret_value = (*H5S_sel_hyper->deserialize)(tmp_space, version, flags, p);
+ break;
+
+ case H5S_SEL_ALL: /* Entire extent selected */
+ ret_value = (*H5S_sel_all->deserialize)(tmp_space, version, flags, p);
+ break;
+
+ case H5S_SEL_NONE: /* Nothing selected */
+ ret_value = (*H5S_sel_none->deserialize)(tmp_space, version, flags, p);
+ break;
+
+ default:
+ break;
+ }
+ if(ret_value < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "can't deserialize selection")
+
+ /* Return space to the caller if allocated */
+ if(!*space)
+ *space = tmp_space;
+
+done:
+ /* Free temporary space if not passed to caller (only happens on error) */
+ if(!*space && tmp_space)
+ if(H5S_close(tmp_space) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_get_select_bounds(space, start, end)
+ hid_t dsid; IN: Dataspace ID of selection to query
+ hsize_t start[]; OUT: Starting coordinate of bounding box
+ hsize_t end[]; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8). Calling this function on a "none" selection
+ returns fail.
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5Sget_select_bounds(hid_t spaceid, hsize_t start[], hsize_t end[])
+{
+ H5S_t *space; /* Dataspace to modify selection of */
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*h*h", spaceid, start, end);
+
+ /* Check args */
+ if(start == NULL || end == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer")
+ if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = H5S_SELECT_BOUNDS(space, start, end);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Sget_select_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_bounds
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ herr_t H5S_get_select_bounds(space, start, end)
+ H5S_t *space; IN: Dataspace ID of selection to query
+ hsize_t *start; OUT: Starting coordinate of bounding box
+ hsize_t *end; OUT: Opposite coordinate of bounding box
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8). Calling this function on a "none" selection
+ returns fail.
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_get_select_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(start);
+ HDassert(end);
+
+ ret_value = (*space->select.type->bounds)(space,start,end);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_bounds() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_offset
+ PURPOSE
+ Gets the linear offset of the first element for the selection.
+ USAGE
+ herr_t H5S_get_select_offset(space, offset)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ hsize_t *offset; OUT: Linear offset of first element in selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the linear offset (in "units" of elements) of the first element
+ selected within the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The offset calculation _does_ include the current offset of the
+ selection within the dataspace extent.
+
+ Calling this function on a "none" selection returns fail.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_get_select_offset(const H5S_t *space, hsize_t *offset)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(offset);
+
+ ret_value = (*space->select.type->offset)(space, offset);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_offset() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_unlim_dim
+ PURPOSE
+ Gets the unlimited dimension in the selection, or -1 if there is no
+ unlimited dimension.
+ USAGE
+ int H5S_get_select_unlim_dim(space)
+ const H5S_t *space; IN: Dataspace pointer of selection to query
+ RETURNS
+ Unlimited dimension in the selection, or -1 if there is no unlimited
+ dimension (never fails)
+ DESCRIPTION
+ Gets the unlimited dimension in the selection, or -1 if there is no
+ unlimited dimension.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Currently only implemented for hyperslab selections, all others
+ simply return -1.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+int
+H5S_get_select_unlim_dim(const H5S_t *space)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ ret_value = (*space->select.type->unlim_dim)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_num_elem_non_unlim
+ PURPOSE
+ Gets the number of elements in the non-unlimited dimensions
+ USAGE
+ herr_t H5S_get_select_num_elem_non_unlim(space,num_elem_non_unlim)
+ H5S_t *space; IN: Dataspace pointer to check
+ hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Returns the number of elements in a slice through the non-unlimited
+ dimensions of the selection. Fails if the selection has no unlimited
+ dimension.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_get_select_num_elem_non_unlim(const H5S_t *space,
+ hsize_t *num_elem_non_unlim)
+{
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space);
+ HDassert(num_elem_non_unlim);
+
+ /* Check for selection callback */
+ if(!space->select.type->num_elem_non_unlim)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "selection type has no num_elem_non_unlim callback")
+
+ /* Make selection callback */
+ if((*space->select.type->num_elem_non_unlim)(space, num_elem_non_unlim) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't get number of elements in non-unlimited dimension")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_select_unlim_dim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_is_contiguous
+ PURPOSE
+ Determines if a selection is contiguous in the dataspace
+ USAGE
+ htri_t H5S_select_is_contiguous(space)
+ const H5S_t *space; IN: Dataspace of selection to query
+ RETURNS
+ Non-negative (TRUE/FALSE) on success, negative on failure
+ DESCRIPTION
+ Checks the selection to determine if the points to iterated over will be
+ contiguous in the particular dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_is_contiguous(const H5S_t *space)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ ret_value = (*space->select.type->is_contiguous)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_is_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_is_single
+ PURPOSE
+ Determines if a selection is a single block in the dataspace
+ USAGE
+ htri_t H5S_select_is_single(space)
+ const H5S_t *space; IN: Dataspace of selection to query
+ RETURNS
+ Non-negative (TRUE/FALSE) on success, negative on failure
+ DESCRIPTION
+ Checks the selection to determine if it occupies a single block in the
+ particular dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_is_single(const H5S_t *space)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ ret_value = (*space->select.type->is_single)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_is_single() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_is_regular
+ PURPOSE
+ Determines if a selection is "regular" in the dataspace
+ USAGE
+ htri_t H5S_select_is_regular(space)
+ const H5S_t *space; IN: Dataspace of selection to query
+ RETURNS
+ Non-negative (TRUE/FALSE) on success, negative on failure
+ DESCRIPTION
+ Checks the selection to determine if it is "regular" (i.e. a single
+ block or a strided pattern) in the particular dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_is_regular(const H5S_t *space)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ ret_value = (*space->select.type->is_regular)(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_is_regular() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_adjust_u
+ PURPOSE
+ Adjust a selection by subtracting an offset
+ USAGE
+ herr_t H5S_select_adjust_u(space, offset)
+ H5S_t *space; IN/OUT: Pointer to dataspace to adjust
+ const hsize_t *offset; IN: Offset to subtract
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Moves a selection by subtracting an offset from it.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_adjust_u(H5S_t *space, const hsize_t *offset)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ ret_value = (*space->select.type->adjust_u)(space, offset);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_adjust_u() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_project_scalar
+ PURPOSE
+ Project a single element selection for a scalar dataspace
+ USAGE
+ herr_t H5S_select_project_scalar(space, offset)
+ const H5S_t *space; IN: Pointer to dataspace to project
+ hsize_t *offset; IN/OUT: Offset of projected point
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Projects a selection of a single element into a scalar dataspace, computing
+ the offset of the element in the original selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_project_scalar(const H5S_t *space, hsize_t *offset)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(offset);
+
+ ret_value = (*space->select.type->project_scalar)(space, offset);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_project_scalar() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_project_simple
+ PURPOSE
+ Project a selection onto/into a dataspace of different rank
+ USAGE
+ herr_t H5S_select_project_simple(space, new_space, offset)
+ const H5S_t *space; IN: Pointer to dataspace to project
+ H5S_t *new_space; IN/OUT: Pointer to dataspace projected onto
+ hsize_t *offset; IN/OUT: Offset of projected point
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Projects a selection onto/into a simple dataspace, computing
+ the offset of the first element in the original selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(new_space);
+ HDassert(offset);
+
+ ret_value = (*space->select.type->project_simple)(space, new_space, offset);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_project_simple() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_init
+ PURPOSE
+ Initializes iteration information for a selection.
+ USAGE
+ herr_t H5S_select_iter_init(sel_iter, space, elmt_size)
+ H5S_sel_iter_t *sel_iter; OUT: Selection iterator to initialize.
+ H5S_t *space; IN: Dataspace object containing selection to
+ iterate over
+ size_t elmt_size; IN: Size of elements in the selection
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ Initialize the selection iterator object to point to the first element
+ in the dataspace's selection.
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_iter_init(H5S_sel_iter_t *sel_iter, const H5S_t *space, size_t elmt_size)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(sel_iter);
+ HDassert(space);
+
+ /* Initialize common information */
+
+ /* Save the dataspace's rank */
+ sel_iter->rank = space->extent.rank;
+
+ /* Point to the dataspace dimensions, if there are any */
+ if(sel_iter->rank > 0)
+ sel_iter->dims = space->extent.size;
+ else
+ sel_iter->dims = NULL;
+
+ /* Save the element size */
+ sel_iter->elmt_size = elmt_size;
+
+ /* Call initialization routine for selection type */
+ ret_value = (*space->select.type->iter_init)(sel_iter, space);
+ HDassert(sel_iter->type);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_init() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_coords
+ PURPOSE
+ Get the coordinates of the current iterator position
+ USAGE
+ herr_t H5S_select_iter_coords(sel_iter,coords)
+ H5S_sel_iter_t *sel_iter; IN: Selection iterator to query
+ hsize_t *coords; OUT: Array to place iterator coordinates in
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ The current location of the iterator within the selection is placed in
+ the COORDS array.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_iter_coords(const H5S_sel_iter_t *sel_iter, hsize_t *coords)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(sel_iter);
+ HDassert(coords);
+
+ /* Call iter_coords routine for selection type */
+ ret_value = (*sel_iter->type->iter_coords)(sel_iter,coords);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_coords() */
+
+#ifdef LATER
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_block
+ PURPOSE
+ Get the block of the current iterator position
+ USAGE
+ herr_t H5S_select_iter_block(sel_iter,start,end)
+ const H5S_sel_iter_t *sel_iter; IN: Selection iterator to query
+ hsize_t *start; OUT: Array to place iterator start block coordinates
+ hsize_t *end; OUT: Array to place iterator end block coordinates
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ The current location of the iterator within the selection is placed in
+ the COORDS array.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_select_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
+{
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(start);
+ HDassert(end);
+
+ /* Call iter_block routine for selection type */
+ ret_value = (*iter->type->iter_block)(iter,start,end);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_block() */
+#endif /* LATER */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_nelmts
+ PURPOSE
+ Get the number of elements left to iterate over in selection
+ USAGE
+ hssize_t H5S_select_iter_nelmts(sel_iter)
+ H5S_sel_iter_t *sel_iter; IN: Selection iterator to query
+ RETURNS
+ The number of elements in selection on success, 0 on failure
+ DESCRIPTION
+ Returns the number of elements in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hsize_t
+H5S_select_iter_nelmts(const H5S_sel_iter_t *sel_iter)
+{
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(sel_iter);
+
+ /* Call iter_nelmts routine for selection type */
+ ret_value = (*sel_iter->type->iter_nelmts)(sel_iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_nelmts() */
+
+#ifdef LATER
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_has_next_block
+ PURPOSE
+ Check if there is another block available in the selection iterator
+ USAGE
+ htri_t H5S_select_iter_has_next_block(sel_iter)
+ const H5S_sel_iter_t *sel_iter; IN: Selection iterator to query
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ Check if there is another block available to advance to in the selection
+ iterator.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_select_iter_has_next_block(const H5S_sel_iter_t *iter)
+{
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ /* Call iter_has_next_block routine for selection type */
+ ret_value = (*iter->type->iter_has_next_block)(iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_has_next_block() */
+#endif /* LATER */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_next
+ PURPOSE
+ Advance selection iterator to next element
+ USAGE
+ herr_t H5S_select_iter_next(iter, nelem)
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator to change
+ size_t nelem; IN: Number of elements to advance by
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ Move the current element for the selection iterator to the NELEM'th next
+ element in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_iter_next(H5S_sel_iter_t *iter, size_t nelem)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+ HDassert(nelem>0);
+
+ /* Call iter_next routine for selection type */
+ ret_value = (*iter->type->iter_next)(iter,nelem);
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left-=nelem;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_next() */
+
+#ifdef LATER
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_next_block
+ PURPOSE
+ Advance selection iterator to next block
+ USAGE
+ herr_t H5S_select_iter_next_block(iter)
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator to change
+ RETURNS
+ Non-negative on success, negative on failure.
+ DESCRIPTION
+ Move the current element for the selection iterator to the next
+ block in the selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Doesn't maintain the 'elmt_left' field of the selection iterator.
+
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_select_iter_next_block(H5S_sel_iter_t *iter)
+{
+ herr_t ret_value; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(iter);
+
+ /* Call iter_next_block routine for selection type */
+ ret_value = (*iter->type->iter_next_block)(iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_next_block() */
+#endif /* LATER */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iter_release
+ PURPOSE
+ Release a selection iterator's resources.
+ USAGE
+ hssize_t H5S_select_iter_release(sel_iter)
+ H5S_sel_iter_t *sel_iter; IN: Selection iterator to query
+ RETURNS
+ The number of elements in selection on success, 0 on failure
+ DESCRIPTION
+ Returns the number of elements in current selection for dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_iter_release(H5S_sel_iter_t *sel_iter)
+{
+ herr_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(sel_iter);
+
+ /* Call selection type-specific release routine */
+ ret_value = (*sel_iter->type->iter_release)(sel_iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_iter_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_iterate
+ PURPOSE
+ Iterate over the selected elements in a memory buffer.
+ USAGE
+ herr_t H5S_select_iterate(buf, type, space, operator, operator_data)
+ void *buf; IN/OUT: Buffer containing elements to iterate over
+ H5T_t *type; IN: Datatype of BUF array.
+ H5S_t *space; IN: Dataspace object containing selection to iterate over
+ H5D_operator_t op; IN: Function pointer to the routine to be
+ called for each element in BUF iterated over.
+ void *operator_data; IN/OUT: Pointer to any user-defined data
+ associated with the operation.
+ RETURNS
+ Returns the return value of the last operator if it was non-zero, or zero
+ if all elements were processed. Otherwise returns a negative value.
+ DESCRIPTION
+ Iterates over the selected elements in a memory buffer, calling the user's
+ callback function for each element. The selection in the dataspace is
+ modified so that any elements already iterated over are removed from the
+ selection if the iteration is interrupted (by the H5D_operator_t function
+ returning non-zero) in the "middle" of the iteration and may be re-started
+ by the user where it left off.
+
+ NOTE: Until "subtracting" elements from a selection is implemented,
+ the selection is not modified.
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_iterate(void *buf, const H5T_t *type, const H5S_t *space,
+ const H5S_sel_iter_op_t *op, void *op_data)
+{
+ H5S_sel_iter_t *iter = NULL; /* Selection iteration info */
+ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
+ hsize_t *off = NULL; /* Array to store sequence offsets */
+ size_t *len = NULL; /* Array to store sequence lengths */
+ hssize_t nelmts; /* Number of elements in selection */
+ hsize_t space_size[H5O_LAYOUT_NDIMS]; /* Dataspace size */
+ size_t max_elem; /* Maximum number of elements allowed in sequences */
+ size_t elmt_size; /* Datatype size */
+ unsigned ndims; /* Number of dimensions in dataspace */
+ herr_t user_ret = 0; /* User's return value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(buf);
+ HDassert(type);
+ HDassert(space);
+ HDassert(op);
+
+ /* Get the datatype size */
+ if(0 == (elmt_size = H5T_get_size(type)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid")
+
+ /* Allocate the selection iterator */
+ if(NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+
+ /* Initialize iterator */
+ if(H5S_select_iter_init(iter, space, elmt_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ iter_init = TRUE; /* Selection iteration info has been initialized */
+
+ /* Get the number of elements in selection */
+ if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+
+ /* Get the rank of the dataspace */
+ ndims = space->extent.rank;
+
+ if(ndims > 0) {
+ /* Copy the size of the space */
+ HDassert(space->extent.size);
+ HDmemcpy(space_size, space->extent.size, ndims * sizeof(hsize_t));
+ } /* end if */
+ space_size[ndims] = elmt_size;
+
+ /* Compute the maximum number of bytes required */
+ H5_CHECKED_ASSIGN(max_elem, size_t, nelmts, hssize_t);
+
+ /* Allocate the offset & length arrays */
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, H5D_IO_VECTOR_SIZE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, H5D_IO_VECTOR_SIZE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate offset vector array")
+
+ /* Loop, while elements left in selection */
+ while(max_elem > 0 && user_ret == 0) {
+ size_t nelem; /* Number of elements used in sequences */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being worked on */
+
+ /* Get the sequences of bytes */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Loop, while sequences left to process */
+ for(curr_seq = 0; curr_seq < nseq && user_ret == 0; curr_seq++) {
+ hsize_t curr_off; /* Current offset within sequence */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+
+ /* Get the current offset */
+ curr_off = off[curr_seq];
+
+ /* Get the number of bytes in sequence */
+ curr_len = len[curr_seq];
+
+ /* Loop, while bytes left in sequence */
+ while(curr_len > 0 && user_ret == 0) {
+ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of element in dataspace */
+ hsize_t tmp_off; /* Temporary offset within sequence */
+ uint8_t *loc; /* Current element location in buffer */
+ int i; /* Local Index variable */
+
+ /* Compute the coordinate from the offset */
+ for(i = (int)ndims, tmp_off = curr_off; i >= 0; i--) {
+ coords[i] = tmp_off % space_size[i];
+ tmp_off /= space_size[i];
+ } /* end for */
+
+ /* Get the location within the user's buffer */
+ loc = (unsigned char *)buf + curr_off;
+
+ /* Check which type of callback to make */
+ switch(op->op_type) {
+ case H5S_SEL_ITER_OP_APP:
+ /* Make the application callback */
+ user_ret = (op->u.app_op.op)(loc, op->u.app_op.type_id, ndims, coords, op_data);
+ break;
+ case H5S_SEL_ITER_OP_LIB:
+ /* Call the library's callback */
+ user_ret = (op->u.lib_op)(loc, type, ndims, coords, op_data);
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported op type")
+ } /* end switch */
+
+ /* Increment offset in dataspace */
+ curr_off += elmt_size;
+
+ /* Decrement number of bytes left in sequence */
+ curr_len -= elmt_size;
+ } /* end while */
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ max_elem -= nelem;
+ } /* end while */
+
+ /* Set return value */
+ ret_value = user_ret;
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ /* Release selection iterator */
+ if(iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(iter)
+ iter = H5FL_FREE(H5S_sel_iter_t, iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_select_iterate() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Sget_select_type
+ PURPOSE
+ Retrieve the type of selection in a dataspace
+ USAGE
+ H5S_sel_type H5Sget_select_type(space_id)
+ hid_t space_id; IN: Dataspace object to query
+ RETURNS
+ Non-negative on success/Negative on failure. Return value is from the
+ set of values in the H5S_sel_type enumerated type.
+ DESCRIPTION
+ This function retrieves the type of selection currently defined for
+ a dataspace.
+--------------------------------------------------------------------------*/
+H5S_sel_type
+H5Sget_select_type(hid_t space_id)
+{
+ H5S_t *space; /* dataspace to modify */
+ H5S_sel_type ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5S_SEL_ERROR)
+ H5TRACE1("St", "i", space_id);
+
+ /* Check args */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5S_SEL_ERROR, "not a dataspace")
+
+ /* Set return value */
+ ret_value = H5S_GET_SELECT_TYPE(space);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Sget_select_type() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_select_type
+ PURPOSE
+ Retrieve the type of selection in a dataspace
+ USAGE
+ H5S_sel_type H5Sget_select_type(space)
+ const H5S_t *space; IN: Dataspace object to query
+ RETURNS
+ Non-negative on success/Negative on failure. Return value is from the
+ set of values in the H5S_sel_type enumerated type.
+ DESCRIPTION
+ This function retrieves the type of selection currently defined for
+ a dataspace.
+ COMMENTS
+ This routine participates in the "Inlining C function pointers"
+ pattern, don't call it directly, use the appropriate macro
+ defined in H5Sprivate.h.
+--------------------------------------------------------------------------*/
+H5S_sel_type
+H5S_get_select_type(const H5S_t *space)
+{
+ H5S_sel_type ret_value = H5S_SEL_ERROR; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Check args */
+ HDassert(space);
+
+ /* Set return value */
+ ret_value=H5S_GET_SELECT_TYPE(space);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S_get_select_type() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_shape_same
+ PURPOSE
+ Check if two selections are the same shape
+ USAGE
+ htri_t H5S_select_shape_same(space1, space2)
+ const H5S_t *space1; IN: 1st Dataspace pointer to compare
+ const H5S_t *space2; IN: 2nd Dataspace pointer to compare
+ RETURNS
+ TRUE/FALSE/FAIL
+ DESCRIPTION
+ Checks to see if the current selection in the dataspaces are the same
+ dimensionality and shape.
+ This is primarily used for reading the entire selection in one swoop.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Assumes that there is only a single "block" for hyperslab selections.
+ EXAMPLES
+ REVISION LOG
+ Modified function to view identical shapes with different dimensions
+ as being the same under some circumstances.
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2)
+{
+ H5S_sel_iter_t *iter_a = NULL; /* Selection a iteration info */
+ H5S_sel_iter_t *iter_b = NULL; /* Selection b iteration info */
+ hbool_t iter_a_init = 0; /* Selection a iteration info has been initialized */
+ hbool_t iter_b_init = 0; /* Selection b iteration info has been initialized */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(space1);
+ HDassert(space2);
+
+ /* Special case for one or both dataspaces being scalar */
+ if(space1->extent.rank == 0 || space2->extent.rank == 0) {
+ /* Check for different number of elements selected */
+ if(H5S_GET_SELECT_NPOINTS(space1) != H5S_GET_SELECT_NPOINTS(space2))
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ else {
+ const H5S_t *space_a; /* Dataspace with larger rank */
+ const H5S_t *space_b; /* Dataspace with smaller rank */
+ unsigned space_a_rank; /* Number of dimensions of dataspace A */
+ unsigned space_b_rank; /* Number of dimensions of dataspace B */
+
+ /* need to be able to handle spaces of different rank:
+ *
+ * To simplify logic, let space_a point to the element of the set
+ * {space1, space2} with the largest rank or space1 if the ranks
+ * are identical.
+ *
+ * Similarly, let space_b point to the element of {space1, space2}
+ * with the smallest rank, or space2 if they are identical.
+ *
+ * Let: space_a_rank be the rank of space_a,
+ * space_b_rank be the rank of space_b,
+ * delta_rank = space_a_rank - space_b_rank.
+ *
+ * Set all this up below.
+ */
+ if(space1->extent.rank >= space2->extent.rank) {
+ space_a = space1;
+ space_a_rank = space_a->extent.rank;
+
+ space_b = space2;
+ space_b_rank = space_b->extent.rank;
+ } /* end if */
+ else {
+ space_a = space2;
+ space_a_rank = space_a->extent.rank;
+
+ space_b = space1;
+ space_b_rank = space_b->extent.rank;
+ } /* end else */
+ HDassert(space_a_rank >= space_b_rank);
+ HDassert(space_b_rank > 0);
+
+ /* Check for different number of elements selected */
+ if(H5S_GET_SELECT_NPOINTS(space_a) != H5S_GET_SELECT_NPOINTS(space_b))
+ HGOTO_DONE(FALSE)
+
+ /* Check for "easy" cases before getting into generalized block iteration code */
+ if((H5S_GET_SELECT_TYPE(space_a) == H5S_SEL_ALL) && (H5S_GET_SELECT_TYPE(space_b) == H5S_SEL_ALL)) {
+ hsize_t dims1[H5O_LAYOUT_NDIMS]; /* End point of selection block in dataspace #1 */
+ hsize_t dims2[H5O_LAYOUT_NDIMS]; /* End point of selection block in dataspace #2 */
+ int space_a_dim; /* Current dimension in dataspace A */
+ int space_b_dim; /* Current dimension in dataspace B */
+
+ if(H5S_get_simple_extent_dims(space_a, dims1, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality")
+ if(H5S_get_simple_extent_dims(space_b, dims2, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality")
+
+ space_a_dim = (int)space_a_rank - 1;
+ space_b_dim = (int)space_b_rank - 1;
+
+ /* recall that space_a_rank >= space_b_rank.
+ *
+ * In the following while loop, we test to see if space_a and space_b
+ * have identical size in all dimensions they have in common.
+ */
+ while(space_b_dim >= 0) {
+ if(dims1[space_a_dim] != dims2[space_b_dim])
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ space_b_dim--;
+ } /* end while */
+
+ /* Since we are selecting the entire spaces, we must also verify that space_a
+ * has size 1 in all dimensions that it does not share with space_b.
+ */
+ while(space_a_dim >= 0) {
+ if(dims1[space_a_dim] != 1)
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ } /* end while */
+ } /* end if */
+ else if((H5S_GET_SELECT_TYPE(space1) == H5S_SEL_NONE) || (H5S_GET_SELECT_TYPE(space2) == H5S_SEL_NONE)) {
+ HGOTO_DONE(TRUE)
+ } /* end if */
+ else if((H5S_GET_SELECT_TYPE(space_a) == H5S_SEL_HYPERSLABS && space_a->select.sel_info.hslab->diminfo_valid)
+ && (H5S_GET_SELECT_TYPE(space_b) == H5S_SEL_HYPERSLABS && space_b->select.sel_info.hslab->diminfo_valid)) {
+ int space_a_dim; /* Current dimension in dataspace A */
+ int space_b_dim; /* Current dimension in dataspace B */
+
+ space_a_dim = (int)space_a_rank - 1;
+ space_b_dim = (int)space_b_rank - 1;
+
+ /* check that the shapes are the same in the common dimensions, and that
+ * block == 1 in all dimensions that appear only in space_a.
+ */
+ while(space_b_dim >= 0) {
+ if(space_a->select.sel_info.hslab->opt_diminfo[space_a_dim].stride !=
+ space_b->select.sel_info.hslab->opt_diminfo[space_b_dim].stride)
+ HGOTO_DONE(FALSE)
+
+ if(space_a->select.sel_info.hslab->opt_diminfo[space_a_dim].count !=
+ space_b->select.sel_info.hslab->opt_diminfo[space_b_dim].count)
+ HGOTO_DONE(FALSE)
+
+ if(space_a->select.sel_info.hslab->opt_diminfo[space_a_dim].block !=
+ space_b->select.sel_info.hslab->opt_diminfo[space_b_dim].block)
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ space_b_dim--;
+ } /* end while */
+
+ while(space_a_dim >= 0) {
+ if(space_a->select.sel_info.hslab->opt_diminfo[space_a_dim].block != 1)
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ } /* end while */
+ } /* end if */
+ /* Iterate through all the blocks in the selection */
+ else {
+ hsize_t start_a[H5O_LAYOUT_NDIMS]; /* Start point of selection block in dataspace a */
+ hsize_t start_b[H5O_LAYOUT_NDIMS]; /* Start point of selection block in dataspace b */
+ hsize_t end_a[H5O_LAYOUT_NDIMS]; /* End point of selection block in dataspace a */
+ hsize_t end_b[H5O_LAYOUT_NDIMS]; /* End point of selection block in dataspace b */
+ hsize_t off_a[H5O_LAYOUT_NDIMS]; /* Offset of selection a blocks */
+ hsize_t off_b[H5O_LAYOUT_NDIMS]; /* Offset of selection b blocks */
+ hbool_t first_block = TRUE; /* Flag to indicate the first block */
+
+ /* Allocate the selection iterators */
+ if(NULL == (iter_a = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+ if(NULL == (iter_b = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+
+ /* Initialize iterator for each dataspace selection
+ * Use '0' for element size instead of actual element size to indicate
+ * that the selection iterator shouldn't be "flattened", since we
+ * aren't actually going to be doing I/O with the iterators.
+ */
+ if(H5S_select_iter_init(iter_a, space_a, (size_t)0) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator a")
+ iter_a_init = 1;
+ if(H5S_select_iter_init(iter_b, space_b, (size_t)0) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator b")
+ iter_b_init = 1;
+
+ /* Iterate over all the blocks in each selection */
+ while(1) {
+ int space_a_dim; /* Current dimension in dataspace A */
+ int space_b_dim; /* Current dimension in dataspace B */
+ htri_t status_a, status_b; /* Status from next block checks */
+
+ /* Get the current block for each selection iterator */
+ if(H5S_SELECT_ITER_BLOCK(iter_a, start_a, end_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get iterator block a")
+ if(H5S_SELECT_ITER_BLOCK(iter_b, start_b, end_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get iterator block b")
+
+ space_a_dim = (int)space_a_rank - 1;
+ space_b_dim = (int)space_b_rank - 1;
+
+ /* The first block only compares the sizes and sets the
+ * relative offsets for later blocks
+ */
+ if(first_block) {
+ /* If the block sizes in the common dimensions from
+ * each selection don't match, get out
+ */
+ while(space_b_dim >= 0) {
+ if((end_a[space_a_dim] - start_a[space_a_dim]) !=
+ (end_b[space_b_dim] - start_b[space_b_dim]))
+ HGOTO_DONE(FALSE)
+
+ /* Set the relative locations of the selections */
+ off_a[space_a_dim] = start_a[space_a_dim];
+ off_b[space_b_dim] = start_b[space_b_dim];
+
+ space_a_dim--;
+ space_b_dim--;
+ } /* end while */
+
+ /* similarly, if the block size in any dimension that appears only
+ * in space_a is not equal to 1, get out.
+ */
+ while(space_a_dim >= 0) {
+ if((end_a[space_a_dim] - start_a[space_a_dim]) != 0)
+ HGOTO_DONE(FALSE)
+
+ /* Set the relative locations of the selections */
+ off_a[space_a_dim] = start_a[space_a_dim];
+
+ space_a_dim--;
+ } /* end while */
+
+ /* Reset "first block" flag */
+ first_block = FALSE;
+ } /* end if */
+ /* Check over the blocks for each selection */
+ else {
+ /* for dimensions that space_a and space_b have in common: */
+ while(space_b_dim >= 0) {
+ /* Check if the blocks are in the same relative location */
+ if((start_a[space_a_dim] - off_a[space_a_dim]) !=
+ (start_b[space_b_dim] - off_b[space_b_dim]))
+ HGOTO_DONE(FALSE)
+
+ /* If the block sizes from each selection doesn't match, get out */
+ if((end_a[space_a_dim] - start_a[space_a_dim]) !=
+ (end_b[space_b_dim] - start_b[space_b_dim]))
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ space_b_dim--;
+ } /* end while */
+
+ /* For dimensions that appear only in space_a: */
+ while(space_a_dim >= 0) {
+ /* If the block size isn't 1, get out */
+ if((end_a[space_a_dim] - start_a[space_a_dim]) != 0)
+ HGOTO_DONE(FALSE)
+
+ space_a_dim--;
+ } /* end while */
+ } /* end else */
+
+ /* Check if we are able to advance to the next selection block */
+ if((status_a = H5S_SELECT_ITER_HAS_NEXT_BLOCK(iter_a)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to check iterator block a")
+
+ if((status_b = H5S_SELECT_ITER_HAS_NEXT_BLOCK(iter_b)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to check iterator block b")
+
+ /* Did we run out of blocks at the same time? */
+ if((status_a == FALSE) && (status_b == FALSE))
+ break;
+ else if(status_a != status_b)
+ HGOTO_DONE(FALSE)
+ else {
+ /* Advance to next block in selection iterators */
+ if(H5S_SELECT_ITER_NEXT_BLOCK(iter_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to advance to next iterator block a")
+
+ if(H5S_SELECT_ITER_NEXT_BLOCK(iter_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to advance to next iterator block b")
+ } /* end else */
+ } /* end while */
+ } /* end else */
+ } /* end else */
+
+done:
+ if(iter_a_init && H5S_SELECT_ITER_RELEASE(iter_a) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator a")
+ if(iter_a)
+ iter_a = H5FL_FREE(H5S_sel_iter_t, iter_a);
+ if(iter_b_init && H5S_SELECT_ITER_RELEASE(iter_b) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator b")
+ if(iter_b)
+ iter_b = H5FL_FREE(H5S_sel_iter_t, iter_b);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_shape_same() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_construct_projection
+
+ PURPOSE
+ Given a dataspace a of rank n with some selection, construct a new
+ dataspace b of rank m (m != n), with the selection in a being
+ topologically identical to that in b (as verified by
+ H5S_select_shape_same().
+
+ This function exists, as some I/O code chokes of topologically
+ identical selections with different ranks. At least to begin
+ with, we will deal with the issue by constructing projections
+ of the memory dataspace with ranks equaling those of the file
+ dataspace.
+
+ Note that if m > n, it is possible that the starting point in the
+ buffer associated with the memory dataspace will have to be
+ adjusted to match the projected dataspace. If the buf parameter
+ is not NULL, the function must return an adjusted buffer base
+ address in *adj_buf_ptr.
+
+ USAGE
+ htri_t H5S_select_construct_projection(base_space,
+ new_space_ptr,
+ new_space_rank,
+ buf,
+ adj_buf_ptr)
+ const H5S_t *base_space; IN: Ptr to Dataspace to project
+ H5S_t ** new_space_ptr; OUT: Ptr to location in which to return
+ the address of the projected space
+ int new_space_rank; IN: Rank of the projected space.
+ const void * buf; IN: Base address of the buffer
+ associated with the base space.
+ May be NULL.
+ void ** adj_buf_ptr; OUT: If buf != NULL, store the base
+ address of the section of buf
+ that is described by *new_space_ptr
+ in *adj_buf_ptr.
+
+ RETURNS
+ Non-negative on success/Negative on failure.
+
+ DESCRIPTION
+ Construct a new dataspace and associated selection which is a
+ projection of the supplied dataspace and associated selection into
+ the specified rank. Return it in *new_space_ptr.
+
+ If buf is supplied, computes the base address of the projected
+ selection in buf, and stores the base address in *adj_buf_ptr.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The selection in the supplied base_space has thickness 1 in all
+ dimensions greater than new_space_rank. Note that here we count
+ dimensions from the fastest changing coordinate to the slowest
+ changing changing coordinate.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_construct_projection(const H5S_t *base_space, H5S_t **new_space_ptr,
+ unsigned new_space_rank, const void *buf, void const **adj_buf_ptr, hsize_t element_size)
+{
+ H5S_t * new_space = NULL; /* New dataspace constructed */
+ hsize_t base_space_dims[H5S_MAX_RANK]; /* Current dimensions of base dataspace */
+ hsize_t base_space_maxdims[H5S_MAX_RANK]; /* Maximum dimensions of base dataspace */
+ int sbase_space_rank; /* Signed # of dimensions of base dataspace */
+ unsigned base_space_rank; /* # of dimensions of base dataspace */
+ hsize_t projected_space_element_offset = 0; /* Offset of selected element in projected buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(base_space != NULL);
+ HDassert((H5S_GET_EXTENT_TYPE(base_space) == H5S_SCALAR) || (H5S_GET_EXTENT_TYPE(base_space) == H5S_SIMPLE));
+ HDassert(new_space_ptr != NULL);
+ HDassert((new_space_rank != 0) || (H5S_GET_SELECT_NPOINTS(base_space) <= 1));
+ HDassert(new_space_rank <= H5S_MAX_RANK);
+ HDassert((buf == NULL) || (adj_buf_ptr != NULL));
+ HDassert(element_size > 0 );
+
+ /* Get the extent info for the base dataspace */
+ if((sbase_space_rank = H5S_get_simple_extent_dims(base_space, base_space_dims, base_space_maxdims)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality of base space")
+ base_space_rank = (unsigned)sbase_space_rank;
+ HDassert(base_space_rank != new_space_rank);
+
+ /* Check if projected space is scalar */
+ if(new_space_rank == 0) {
+ hssize_t npoints; /* Number of points selected */
+
+ /* Retreve the number of elements selected */
+ if((npoints = (hssize_t)H5S_GET_SELECT_NPOINTS(base_space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get number of points selected")
+ HDassert(npoints <= 1);
+
+ /* Create new scalar dataspace */
+ if(NULL == (new_space = H5S_create(H5S_SCALAR)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create scalar dataspace")
+
+ /* No need to register the dataspace(i.e. get an ID) as
+ * we will just be discarding it shortly.
+ */
+
+ /* Selection for the new space will be either all or
+ * none, depending on whether the base space has 0 or
+ * 1 elements selected.
+ *
+ * Observe that the base space can't have more than
+ * one selected element, since its selection has the
+ * same shape as the file dataspace, and that data
+ * space is scalar.
+ */
+ if(1 == npoints) {
+ /* Assuming that the selection in the base dataspace is not
+ * empty, we must compute the offset of the selected item in
+ * the buffer associated with the base dataspace.
+ *
+ * Since the new space rank is zero, we know that the
+ * the base space must have rank at least 1 -- and
+ * hence it is a simple dataspace. However, the
+ * selection, may be either point, hyperspace, or all.
+ *
+ */
+ if(H5S_SELECT_PROJECT_SCALAR(base_space, &projected_space_element_offset) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to project scalar selection")
+ } /* end if */
+ else {
+ HDassert(0 == npoints);
+
+ if(H5S_select_none(new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't delete default selection")
+ } /* end else */
+ } /* end if */
+ else { /* projected space must be simple */
+ hsize_t new_space_dims[H5S_MAX_RANK]; /* Current dimensions for new dataspace */
+ hsize_t new_space_maxdims[H5S_MAX_RANK];/* Maximum dimensions for new dataspace */
+ unsigned rank_diff; /* Difference in ranks */
+
+ /* Set up the dimensions of the new, projected dataspace.
+ *
+ * How we do this depends on whether we are projecting up into
+ * increased dimensions, or down into a reduced number of
+ * dimensions.
+ *
+ * If we are projecting up (the first half of the following
+ * if statement), we copy the dimensions of the base data
+ * space into the fastest changing dimensions of the new
+ * projected dataspace, and set the remaining dimensions to
+ * one.
+ *
+ * If we are projecting down (the second half of the following
+ * if statement), we just copy the dimensions with the most
+ * quickly changing dimensions into the dims for the projected
+ * data set.
+ *
+ * This works, because H5S_select_shape_same() will return
+ * true on selections of different rank iff:
+ *
+ * 1) the selection in the lower rank dataspace matches that
+ * in the dimensions with the fastest changing indicies in
+ * the larger rank dataspace, and
+ *
+ * 2) the selection has thickness 1 in all ranks that appear
+ * only in the higher rank dataspace (i.e. those with
+ * more slowly changing indicies).
+ */
+ if(new_space_rank > base_space_rank) {
+ hsize_t tmp_dim_size = 1; /* Temporary dimension value, for filling arrays */
+
+ /* we must copy the dimensions of the base space into
+ * the fastest changing dimensions of the new space,
+ * and set the remaining dimensions to 1
+ */
+ rank_diff = new_space_rank - base_space_rank;
+ H5VM_array_fill(new_space_dims, &tmp_dim_size, sizeof(tmp_dim_size), rank_diff);
+ H5VM_array_fill(new_space_maxdims, &tmp_dim_size, sizeof(tmp_dim_size), rank_diff);
+ HDmemcpy(&new_space_dims[rank_diff], base_space_dims, sizeof(new_space_dims[0]) * base_space_rank);
+ HDmemcpy(&new_space_maxdims[rank_diff], base_space_maxdims, sizeof(new_space_maxdims[0]) * base_space_rank);
+ } /* end if */
+ else { /* new_space_rank < base_space_rank */
+ /* we must copy the fastest changing dimension of the
+ * base space into the dimensions of the new space.
+ */
+ rank_diff = base_space_rank - new_space_rank;
+ HDmemcpy(new_space_dims, &base_space_dims[rank_diff], sizeof(new_space_dims[0]) * new_space_rank);
+ HDmemcpy(new_space_maxdims, &base_space_maxdims[rank_diff], sizeof(new_space_maxdims[0]) * new_space_rank);
+ } /* end else */
+
+ /* now have the new space rank and dimensions set up --
+ * so we can create the new simple dataspace.
+ */
+ if(NULL == (new_space = H5S_create_simple(new_space_rank, new_space_dims, new_space_maxdims)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* No need to register the dataspace(i.e. get an ID) as
+ * we will just be discarding it shortly.
+ */
+
+ /* If we get this far, we have successfully created the projected
+ * dataspace. We must now project the selection in the base
+ * dataspace into the projected dataspace.
+ */
+ if(H5S_SELECT_PROJECT_SIMPLE(base_space, new_space, &projected_space_element_offset) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to project simple selection")
+
+ /* If we get this far, we have created the new dataspace, and projected
+ * the selection in the base dataspace into the new dataspace.
+ *
+ * If the base dataspace is simple, check to see if the
+ * offset_changed flag on the base selection has been set -- if so,
+ * project the offset into the new dataspace and set the
+ * offset_changed flag.
+ */
+ if(H5S_GET_EXTENT_TYPE(base_space) == H5S_SIMPLE && base_space->select.offset_changed) {
+ if(new_space_rank > base_space_rank) {
+ HDmemset(new_space->select.offset, 0, sizeof(new_space->select.offset[0]) * rank_diff);
+ HDmemcpy(&new_space->select.offset[rank_diff], base_space->select.offset, sizeof(new_space->select.offset[0]) * base_space_rank);
+ } /* end if */
+ else
+ HDmemcpy(new_space->select.offset, &base_space->select.offset[rank_diff], sizeof(new_space->select.offset[0]) * new_space_rank);
+
+ /* Propagate the offset changed flag into the new dataspace. */
+ new_space->select.offset_changed = TRUE;
+ } /* end if */
+ } /* end else */
+
+ /* If we have done the projection correctly, the following assertion
+ * should hold.
+ */
+ HDassert(TRUE == H5S_select_shape_same(base_space, new_space));
+
+ /* load the address of the new space into *new_space_ptr */
+ *new_space_ptr = new_space;
+
+ /* now adjust the buffer if required */
+ if(buf != NULL) {
+ if(new_space_rank < base_space_rank) {
+ /* a bit of pointer magic here:
+ *
+ * Since we can't do pointer arithmetic on void pointers, we first
+ * cast buf to a pointer to byte -- i.e. uint8_t.
+ *
+ * We then multiply the projected space element offset we
+ * calculated earlier by the supplied element size, add this
+ * value to the type cast buf pointer, cast the result back
+ * to a pointer to void, and assign the result to *adj_buf_ptr.
+ */
+ *adj_buf_ptr = (const void *)(((const uint8_t *)buf) +
+ ((size_t)(projected_space_element_offset * element_size)));
+ } /* end if */
+ else
+ /* No adjustment necessary */
+ *adj_buf_ptr = buf;
+ } /* end if */
+
+done:
+ /* Cleanup on error */
+ if(ret_value < 0) {
+ if(new_space && H5S_close(new_space) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_construct_projection() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_fill
+ PURPOSE
+ Fill a selection in memory with a value
+ USAGE
+ herr_t H5S_select_fill(fill,fill_size,space,buf)
+ const void *fill; IN: Pointer to fill value to use
+ size_t fill_size; IN: Size of elements in memory buffer & size of
+ fill value
+ H5S_t *space; IN: Dataspace describing memory buffer &
+ containing selection to use.
+ void *buf; IN/OUT: Memory buffer to fill selection in
+ RETURNS
+ Non-negative on success/Negative on failure.
+ DESCRIPTION
+ Use the selection in the dataspace to fill elements in a memory buffer.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The memory buffer elements are assumed to have the same datatype as the
+ fill value being placed into them.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_fill(const void *fill, size_t fill_size, const H5S_t *space, void *_buf)
+{
+ H5S_sel_iter_t *iter = NULL; /* Selection iteration info */
+ hbool_t iter_init = 0; /* Selection iteration info has been initialized */
+ hsize_t *off = NULL; /* Array to store sequence offsets */
+ size_t *len = NULL; /* Array to store sequence lengths */
+ hssize_t nelmts; /* Number of elements in selection */
+ size_t max_elem; /* Total number of elements in selection */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(fill);
+ HDassert(fill_size > 0);
+ HDassert(space);
+ HDassert(_buf);
+
+ /* Allocate the selection iterator */
+ if(NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
+
+ /* Initialize iterator */
+ if(H5S_select_iter_init(iter, space, fill_size) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
+ iter_init = 1; /* Selection iteration info has been initialized */
+
+ /* Get the number of elements in selection */
+ if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't get number of elements selected")
+
+ /* Compute the number of bytes to process */
+ H5_CHECKED_ASSIGN(max_elem, size_t, nelmts, hssize_t);
+
+ /* Allocate the offset & length arrays */
+ if(NULL == (len = H5FL_SEQ_MALLOC(size_t, H5D_IO_VECTOR_SIZE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate length vector array")
+ if(NULL == (off = H5FL_SEQ_MALLOC(hsize_t, H5D_IO_VECTOR_SIZE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate offset vector array")
+
+ /* Loop, while elements left in selection */
+ while(max_elem > 0) {
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequnce being worked on */
+ size_t nelem; /* Number of elements used in sequences */
+
+ /* Get the sequences of bytes */
+ if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
+
+ /* Loop over sequences */
+ for(curr_seq = 0; curr_seq < nseq; curr_seq++) {
+ uint8_t *buf; /* Current location in buffer */
+
+ /* Get offset in memory buffer */
+ buf = (uint8_t *)_buf + off[curr_seq];
+
+ /* Fill each sequence in memory with fill value */
+ HDassert((len[curr_seq] % fill_size) == 0);
+ H5VM_array_fill(buf, fill, fill_size, (len[curr_seq] / fill_size));
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ max_elem -= nelem;
+ } /* end while */
+
+done:
+ /* Release resources, if allocated */
+ if(len)
+ len = H5FL_SEQ_FREE(size_t, len);
+ if(off)
+ off = H5FL_SEQ_FREE(hsize_t, off);
+
+ /* Release selection iterator */
+ if(iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
+ if(iter)
+ iter = H5FL_FREE(H5S_sel_iter_t, iter);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_fill() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_project_intersection
+
+ PURPOSE
+ Projects the intersection of of the selections of src_space and
+ src_intersect_space within the selection of src_space as a selection
+ within the selection of dst_space
+
+ USAGE
+ herr_t H5S_select_project_intersection(src_space,dst_space,src_intersect_space,proj_space)
+ H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space
+ H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result
+ H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result
+ H5S_t *proj_space; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation
+
+ RETURNS
+ Non-negative on success/Negative on failure.
+
+ DESCRIPTION
+ Projects the intersection of of the selections of src_space and
+ src_intersect_space within the selection of src_space as a selection
+ within the selection of dst_space. The result is placed in the
+ selection of proj_space.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_project_intersection(const H5S_t *src_space, const H5S_t *dst_space,
+ const H5S_t *src_intersect_space, H5S_t **new_space_ptr)
+{
+ H5S_t *new_space = NULL; /* New dataspace constructed */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(src_space);
+ HDassert(dst_space);
+ HDassert(src_intersect_space);
+ HDassert(new_space_ptr);
+
+ /* Create new space, using dst extent. Start with "all" selection. */
+ if(NULL == (new_space = H5S_create(H5S_SIMPLE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create output dataspace")
+ if(H5S_extent_copy_real(&new_space->extent, &dst_space->extent, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy destination space extent")
+
+ /* If the intersecting space is "all", the intersection must be equal to the
+ * source space and the projection must be equal to the destination space */
+ if(src_intersect_space->select.type->type == H5S_SEL_ALL) {
+ /* Copy the destination selection. */
+ if(H5S_select_copy(new_space, dst_space, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination space selection")
+ } /* end if */
+ /* If any of the spaces are "none", the projection must also be "none" */
+ else if((src_intersect_space->select.type->type == H5S_SEL_NONE)
+ || (src_space->select.type->type == H5S_SEL_NONE)
+ || (dst_space->select.type->type == H5S_SEL_NONE)) {
+ /* Change to "none" selection */
+ if(H5S_select_none(new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+ } /* end if */
+ /* If any of the spaces use point selection, fall back to general algorithm
+ */
+ else if((src_intersect_space->select.type->type == H5S_SEL_POINTS)
+ || (src_space->select.type->type == H5S_SEL_POINTS)
+ || (dst_space->select.type->type == H5S_SEL_POINTS))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported")
+ else {
+ HDassert(src_intersect_space->select.type->type == H5S_SEL_HYPERSLABS);
+ /* Intersecting space is hyperslab selection. Call the hyperslab
+ * routine to project to another hyperslab selection. */
+ if(H5S__hyper_project_intersection(src_space, dst_space, src_intersect_space, new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't project hyperslab ondot destination selection")
+ } /* end else */
+
+ /* load the address of the new space into *new_space_ptr */
+ *new_space_ptr = new_space;
+
+done:
+ /* Cleanup on error */
+ if(ret_value < 0) {
+ if(new_space && H5S_close(new_space) < 0)
+ HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_project_intersection() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_subtract
+
+ PURPOSE
+ Subtract one selection from another
+
+ USAGE
+ herr_t H5S_select_subtract(space,subtract_space)
+ H5S_t *space; IN/OUT: Selection to be operated on
+ H5S_t *subtract_space; IN: Selection that will be subtracted from space
+
+ RETURNS
+ Non-negative on success/Negative on failure.
+
+ DESCRIPTION
+ Removes any and all portions of space that are also present in
+ subtract_space. In essence, performs an A_NOT_B operation with the
+ two selections.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_select_subtract(H5S_t *space, H5S_t *subtract_space)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(space);
+ HDassert(subtract_space);
+
+ /* If either space is using the none selection, then we do not need to do
+ * anything */
+ if((space->select.type->type != H5S_SEL_NONE)
+ && (subtract_space->select.type->type != H5S_SEL_NONE)) {
+ /* If subtract_space is using the all selection, set space to none */
+ if(subtract_space->select.type->type == H5S_SEL_ALL) {
+ /* Change to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
+ } /* end if */
+ else {
+ /* Check for point selection in subtract_space, convert to
+ * hyperslab */
+ if(subtract_space->select.type->type == H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported")
+
+ /* Check for point or all selection in space, convert to hyperslab
+ */
+ if(space->select.type->type == H5S_SEL_ALL) {
+ /* Convert current "all" selection to "real" hyperslab selection */
+ /* Then allow operation to proceed */
+ hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */
+ hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */
+ unsigned i; /* Local index variable */
+
+ /* Fill in temporary information for the dimensions */
+ for(i = 0; i < space->extent.rank; i++) {
+ tmp_start[i] = 0;
+ tmp_stride[i] = 1;
+ tmp_count[i] = 1;
+ tmp_block[i] = space->extent.size[i];
+ } /* end for */
+
+ /* Convert to hyperslab selection */
+ if(H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
+ } /* end if */
+ else if(space->select.type->type == H5S_SEL_POINTS)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported")
+
+ HDassert(space->select.type->type == H5S_SEL_HYPERSLABS);
+ HDassert(subtract_space->select.type->type == H5S_SEL_HYPERSLABS);
+
+ /* Both spaces are now hyperslabs, perform the operation */
+ if(H5S__hyper_subtract(space, subtract_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't subtract hyperslab")
+ } /* end else */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_subtract() */
+
diff --git a/src/H5Stest.c b/src/H5Stest.c
new file mode 100644
index 0000000..a7bee2b
--- /dev/null
+++ b/src/H5Stest.c
@@ -0,0 +1,109 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Saturday, May 31, 2003
+ *
+ * Purpose: Dataspace selection testing functions.
+ */
+
+#include "H5Smodule.h" /* This source code file is part of the H5S module */
+#define H5S_TESTING /*suppress warning about H5S testing funcs*/
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Spkg.h" /* Dataspaces */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_select_shape_same_test
+ PURPOSE
+ Determine if two dataspace selections are the same shape
+ USAGE
+ htri_t H5S_select_shape_same_test(sid1, sid2)
+ hid_t sid1; IN: 1st dataspace to compare
+ hid_t sid2; IN: 2nd dataspace to compare
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Checks to see if the current selection in the dataspaces are the same
+ dimensionality and shape.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_select_shape_same_test(hid_t sid1, hid_t sid2)
+{
+ H5S_t *space1; /* Pointer to 1st dataspace */
+ H5S_t *space2; /* Pointer to 2nd dataspace */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get dataspace structures */
+ if(NULL == (space1 = (H5S_t *)H5I_object_verify(sid1, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ if(NULL == (space2 = (H5S_t *)H5I_object_verify(sid2, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ /* Check if the dataspace selections are the same shape */
+ if((ret_value = H5S_select_shape_same(space1, space2)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "unable to compare dataspace selections")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_select_shape_same_test() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_get_rebuild_status_test
+ PURPOSE
+ Determine the status of hyperslab rebuild
+ USAGE
+ htri_t H5S_inquiry_rebuild_status(hid_t space_id)
+ hid_t space_id; IN: dataspace id
+ RETURNS
+ Non-negative TRUE/FALSE on success, negative on failure
+ DESCRIPTION
+ Query the status of rebuilding the hyperslab
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5S_get_rebuild_status_test(hid_t space_id)
+{
+ H5S_t *space; /* Pointer to 1st dataspace */
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get dataspace structures */
+ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+
+ ret_value = (htri_t)space->select.sel_info.hslab->diminfo_valid;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S_get_rebuild_status_test() */
+
diff --git a/src/H5T.c b/src/H5T.c
new file mode 100644
index 0000000..5e4171d
--- /dev/null
+++ b/src/H5T.c
@@ -0,0 +1,5610 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains most of the "core" functionality of
+ * the H5T interface, including the API initialization code, etc.
+ * Many routines that are infrequently used, or are specialized for
+ * one particular datatype class are in another module.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tpkg.h" /* Datatypes */
+
+/* Check for header needed for SGI floating-point code */
+#ifdef H5_HAVE_SYS_FPU_H
+#include <sys/fpu.h>
+#endif /* H5_HAVE_SYS_FPU_H */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define H5T_ENCODE_VERSION 0
+
+/*
+ * Type initialization macros
+ *
+ * These use the "template macro" technique to reduce the amount of gratuitous
+ * duplicated code when initializing the datatypes for the library. The main
+ * template macro is the H5T_INIT_TYPE() macro below.
+ *
+ */
+
+/* Define the code template for bitfields for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_BITFIELD_CORE { \
+ dt->shared->type = H5T_BITFIELD; \
+}
+
+/* Define the code template for times for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_TIME_CORE { \
+ dt->shared->type = H5T_TIME; \
+}
+
+/* Define the code template for types which reset the offset for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_OFFSET_CORE { \
+ dt->shared->u.atomic.offset = 0; \
+}
+
+/* Define common code for all numeric types (floating-point & int, signed & unsigned) */
+#define H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) { \
+ dt->shared->u.atomic.order = ENDIANNESS; \
+ dt->shared->u.atomic.offset = 0; \
+ dt->shared->u.atomic.lsb_pad = H5T_PAD_ZERO; \
+ dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO; \
+}
+
+/* Define the code templates for standard floats for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_FLOAT_COMMON(ENDIANNESS) { \
+ H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) \
+ dt->shared->u.atomic.u.f.sign = 31; \
+ dt->shared->u.atomic.u.f.epos = 23; \
+ dt->shared->u.atomic.u.f.esize = 8; \
+ dt->shared->u.atomic.u.f.ebias = 0x7f; \
+ dt->shared->u.atomic.u.f.mpos = 0; \
+ dt->shared->u.atomic.u.f.msize = 23; \
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED; \
+ dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; \
+}
+
+#define H5T_INIT_TYPE_FLOATLE_CORE { \
+ H5T_INIT_TYPE_FLOAT_COMMON(H5T_ORDER_LE) \
+}
+
+#define H5T_INIT_TYPE_FLOATBE_CORE { \
+ H5T_INIT_TYPE_FLOAT_COMMON(H5T_ORDER_BE) \
+}
+
+/* Define the code templates for standard doubles for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_DOUBLE_COMMON(ENDIANNESS) { \
+ H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) \
+ dt->shared->u.atomic.u.f.sign = 63; \
+ dt->shared->u.atomic.u.f.epos = 52; \
+ dt->shared->u.atomic.u.f.esize = 11; \
+ dt->shared->u.atomic.u.f.ebias = 0x03ff; \
+ dt->shared->u.atomic.u.f.mpos = 0; \
+ dt->shared->u.atomic.u.f.msize = 52; \
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED; \
+ dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; \
+}
+
+#define H5T_INIT_TYPE_DOUBLELE_CORE { \
+ H5T_INIT_TYPE_DOUBLE_COMMON(H5T_ORDER_LE) \
+}
+
+#define H5T_INIT_TYPE_DOUBLEBE_CORE { \
+ H5T_INIT_TYPE_DOUBLE_COMMON(H5T_ORDER_BE) \
+}
+
+/* Define the code templates for VAX float for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_FLOATVAX_CORE { \
+ H5T_INIT_TYPE_NUM_COMMON(H5T_ORDER_VAX) \
+ dt->shared->u.atomic.u.f.sign = 31; \
+ dt->shared->u.atomic.u.f.epos = 23; \
+ dt->shared->u.atomic.u.f.esize = 8; \
+ dt->shared->u.atomic.u.f.ebias = 0x81; \
+ dt->shared->u.atomic.u.f.mpos = 0; \
+ dt->shared->u.atomic.u.f.msize = 23; \
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED; \
+ dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; \
+ dt->shared->version = H5O_DTYPE_VERSION_3; \
+}
+
+/* Define the code templates for VAX double for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_DOUBLEVAX_CORE { \
+ H5T_INIT_TYPE_NUM_COMMON(H5T_ORDER_VAX) \
+ dt->shared->u.atomic.u.f.sign = 63; \
+ dt->shared->u.atomic.u.f.epos = 52; \
+ dt->shared->u.atomic.u.f.esize = 11; \
+ dt->shared->u.atomic.u.f.ebias = 0x0401; \
+ dt->shared->u.atomic.u.f.mpos = 0; \
+ dt->shared->u.atomic.u.f.msize = 52; \
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED; \
+ dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; \
+ dt->shared->version = H5O_DTYPE_VERSION_3; \
+}
+
+/* Define the code templates for standard signed integers for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_SINT_COMMON(ENDIANNESS) { \
+ H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) \
+ dt->shared->u.atomic.u.i.sign = H5T_SGN_2; \
+}
+
+#define H5T_INIT_TYPE_SINTLE_CORE { \
+ H5T_INIT_TYPE_SINT_COMMON(H5T_ORDER_LE) \
+}
+
+#define H5T_INIT_TYPE_SINTBE_CORE { \
+ H5T_INIT_TYPE_SINT_COMMON(H5T_ORDER_BE) \
+}
+
+/* Define the code templates for standard unsigned integers for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_UINT_COMMON(ENDIANNESS) { \
+ H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) \
+ dt->shared->u.atomic.u.i.sign = H5T_SGN_NONE; \
+}
+
+#define H5T_INIT_TYPE_UINTLE_CORE { \
+ H5T_INIT_TYPE_UINT_COMMON(H5T_ORDER_LE) \
+}
+
+#define H5T_INIT_TYPE_UINTBE_CORE { \
+ H5T_INIT_TYPE_UINT_COMMON(H5T_ORDER_BE) \
+}
+
+/* Define a macro for common code for all newly allocate datatypes */
+#define H5T_INIT_TYPE_ALLOC_COMMON(TYPE) { \
+ dt->sh_loc.type = H5O_SHARE_TYPE_UNSHARED; \
+ dt->shared->type = TYPE; \
+}
+
+/* Define the code templates for opaque for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_OPAQ_CORE { \
+ H5T_INIT_TYPE_ALLOC_COMMON(H5T_OPAQUE) \
+ dt->shared->u.opaque.tag = H5MM_xstrdup(""); \
+}
+
+/* Define the code templates for strings for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_STRING_COMMON { \
+ H5T_INIT_TYPE_ALLOC_COMMON(H5T_STRING) \
+ H5T_INIT_TYPE_NUM_COMMON(H5T_ORDER_NONE) \
+ dt->shared->u.atomic.u.s.cset = H5F_DEFAULT_CSET; \
+}
+
+#define H5T_INIT_TYPE_CSTRING_CORE { \
+ H5T_INIT_TYPE_STRING_COMMON \
+ dt->shared->u.atomic.u.s.pad = H5T_STR_NULLTERM; \
+}
+
+#define H5T_INIT_TYPE_FORSTRING_CORE { \
+ H5T_INIT_TYPE_STRING_COMMON \
+ dt->shared->u.atomic.u.s.pad = H5T_STR_SPACEPAD; \
+}
+
+/* Define the code templates for references for the "GUTS" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_REF_COMMON { \
+ H5T_INIT_TYPE_ALLOC_COMMON(H5T_REFERENCE) \
+ H5T_INIT_TYPE_NUM_COMMON(H5T_ORDER_NONE) \
+}
+
+#define H5T_INIT_TYPE_OBJREF_CORE { \
+ H5T_INIT_TYPE_REF_COMMON \
+ dt->shared->force_conv = TRUE; \
+ dt->shared->u.atomic.u.r.rtype = H5R_OBJECT; \
+ dt->shared->u.atomic.u.r.loc = H5T_LOC_MEMORY; \
+}
+
+#define H5T_INIT_TYPE_REGREF_CORE { \
+ H5T_INIT_TYPE_REF_COMMON \
+ dt->shared->u.atomic.u.r.rtype = H5R_DATASET_REGION; \
+}
+
+/* Define the code templates for the "SIZE_TMPL" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_SET_SIZE(SIZE) { \
+ dt->shared->size = SIZE; \
+ dt->shared->u.atomic.prec = 8 * SIZE; \
+}
+
+#define H5T_INIT_TYPE_NOSET_SIZE(SIZE) { \
+}
+
+/* Define the code templates for the "CRT_TMPL" in the H5T_INIT_TYPE macro */
+#define H5T_INIT_TYPE_COPY_CREATE(BASE) { \
+ /* Base off of existing datatype */ \
+ if(NULL == (dt = H5T_copy(BASE, H5T_COPY_TRANSIENT))) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "duplicating base type failed") \
+}
+
+#define H5T_INIT_TYPE_ALLOC_CREATE(BASE) { \
+ /* Allocate new datatype info */ \
+ if(NULL == (dt = H5T__alloc())) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed") \
+}
+
+
+#define H5T_INIT_TYPE(GUTS,GLOBAL,CRT_TMPL,BASE,SIZE_TMPL,SIZE) { \
+ /* Get new datatype struct */ \
+ H5_GLUE3(H5T_INIT_TYPE_,CRT_TMPL,_CREATE)(BASE) \
+ \
+ /* Adjust information for all types */ \
+ dt->shared->state = H5T_STATE_IMMUTABLE; \
+ H5_GLUE3(H5T_INIT_TYPE_,SIZE_TMPL,_SIZE)(SIZE) \
+ \
+ /* Adjust information for this type */ \
+ H5_GLUE3(H5T_INIT_TYPE_, GUTS, _CORE) \
+ \
+ /* Atomize result */ \
+ if((GLOBAL = H5I_register(H5I_DATATYPE, dt, FALSE)) < 0) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype atom") \
+}
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5T_unregister(H5T_pers_t pers, const char *name, H5T_t *src,
+ H5T_t *dst, H5T_conv_t func, hid_t dxpl_id);
+static herr_t H5T_register(H5T_pers_t pers, const char *name, H5T_t *src,
+ H5T_t *dst, H5T_conv_t func, hid_t dxpl_id, hbool_t api_call);
+static htri_t H5T_compiler_conv(H5T_t *src, H5T_t *dst);
+static herr_t H5T_set_size(H5T_t *dt, size_t size);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/* The native endianess of the platform */
+H5T_order_t H5T_native_order_g = H5T_ORDER_ERROR;
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/*
+ * Predefined data types. These are initialized at runtime in H5Tinit.c and
+ * by H5T__init_package() in this source file.
+ *
+ * If more of these are added, the new ones must be added to the list of
+ * types to reset in H5T_term_package().
+ */
+hid_t H5T_IEEE_F32BE_g = FAIL;
+hid_t H5T_IEEE_F32LE_g = FAIL;
+hid_t H5T_IEEE_F64BE_g = FAIL;
+hid_t H5T_IEEE_F64LE_g = FAIL;
+
+hid_t H5T_VAX_F32_g = FAIL;
+hid_t H5T_VAX_F64_g = FAIL;
+
+hid_t H5T_STD_I8BE_g = FAIL;
+hid_t H5T_STD_I8LE_g = FAIL;
+hid_t H5T_STD_I16BE_g = FAIL;
+hid_t H5T_STD_I16LE_g = FAIL;
+hid_t H5T_STD_I32BE_g = FAIL;
+hid_t H5T_STD_I32LE_g = FAIL;
+hid_t H5T_STD_I64BE_g = FAIL;
+hid_t H5T_STD_I64LE_g = FAIL;
+hid_t H5T_STD_U8BE_g = FAIL;
+hid_t H5T_STD_U8LE_g = FAIL;
+hid_t H5T_STD_U16BE_g = FAIL;
+hid_t H5T_STD_U16LE_g = FAIL;
+hid_t H5T_STD_U32BE_g = FAIL;
+hid_t H5T_STD_U32LE_g = FAIL;
+hid_t H5T_STD_U64BE_g = FAIL;
+hid_t H5T_STD_U64LE_g = FAIL;
+hid_t H5T_STD_B8BE_g = FAIL;
+hid_t H5T_STD_B8LE_g = FAIL;
+hid_t H5T_STD_B16BE_g = FAIL;
+hid_t H5T_STD_B16LE_g = FAIL;
+hid_t H5T_STD_B32BE_g = FAIL;
+hid_t H5T_STD_B32LE_g = FAIL;
+hid_t H5T_STD_B64BE_g = FAIL;
+hid_t H5T_STD_B64LE_g = FAIL;
+hid_t H5T_STD_REF_OBJ_g = FAIL;
+hid_t H5T_STD_REF_DSETREG_g = FAIL;
+
+hid_t H5T_UNIX_D32BE_g = FAIL;
+hid_t H5T_UNIX_D32LE_g = FAIL;
+hid_t H5T_UNIX_D64BE_g = FAIL;
+hid_t H5T_UNIX_D64LE_g = FAIL;
+
+hid_t H5T_C_S1_g = FAIL;
+
+hid_t H5T_FORTRAN_S1_g = FAIL;
+
+hid_t H5T_NATIVE_SCHAR_g = FAIL;
+hid_t H5T_NATIVE_UCHAR_g = FAIL;
+hid_t H5T_NATIVE_SHORT_g = FAIL;
+hid_t H5T_NATIVE_USHORT_g = FAIL;
+hid_t H5T_NATIVE_INT_g = FAIL;
+hid_t H5T_NATIVE_UINT_g = FAIL;
+hid_t H5T_NATIVE_LONG_g = FAIL;
+hid_t H5T_NATIVE_ULONG_g = FAIL;
+hid_t H5T_NATIVE_LLONG_g = FAIL;
+hid_t H5T_NATIVE_ULLONG_g = FAIL;
+hid_t H5T_NATIVE_FLOAT_g = FAIL;
+hid_t H5T_NATIVE_DOUBLE_g = FAIL;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+hid_t H5T_NATIVE_LDOUBLE_g = FAIL;
+#endif
+hid_t H5T_NATIVE_B8_g = FAIL;
+hid_t H5T_NATIVE_B16_g = FAIL;
+hid_t H5T_NATIVE_B32_g = FAIL;
+hid_t H5T_NATIVE_B64_g = FAIL;
+hid_t H5T_NATIVE_OPAQUE_g = FAIL;
+hid_t H5T_NATIVE_HADDR_g = FAIL;
+hid_t H5T_NATIVE_HSIZE_g = FAIL;
+hid_t H5T_NATIVE_HSSIZE_g = FAIL;
+hid_t H5T_NATIVE_HERR_g = FAIL;
+hid_t H5T_NATIVE_HBOOL_g = FAIL;
+
+hid_t H5T_NATIVE_INT8_g = FAIL;
+hid_t H5T_NATIVE_UINT8_g = FAIL;
+hid_t H5T_NATIVE_INT_LEAST8_g = FAIL;
+hid_t H5T_NATIVE_UINT_LEAST8_g = FAIL;
+hid_t H5T_NATIVE_INT_FAST8_g = FAIL;
+hid_t H5T_NATIVE_UINT_FAST8_g = FAIL;
+
+hid_t H5T_NATIVE_INT16_g = FAIL;
+hid_t H5T_NATIVE_UINT16_g = FAIL;
+hid_t H5T_NATIVE_INT_LEAST16_g = FAIL;
+hid_t H5T_NATIVE_UINT_LEAST16_g = FAIL;
+hid_t H5T_NATIVE_INT_FAST16_g = FAIL;
+hid_t H5T_NATIVE_UINT_FAST16_g = FAIL;
+
+hid_t H5T_NATIVE_INT32_g = FAIL;
+hid_t H5T_NATIVE_UINT32_g = FAIL;
+hid_t H5T_NATIVE_INT_LEAST32_g = FAIL;
+hid_t H5T_NATIVE_UINT_LEAST32_g = FAIL;
+hid_t H5T_NATIVE_INT_FAST32_g = FAIL;
+hid_t H5T_NATIVE_UINT_FAST32_g = FAIL;
+
+hid_t H5T_NATIVE_INT64_g = FAIL;
+hid_t H5T_NATIVE_UINT64_g = FAIL;
+hid_t H5T_NATIVE_INT_LEAST64_g = FAIL;
+hid_t H5T_NATIVE_UINT_LEAST64_g = FAIL;
+hid_t H5T_NATIVE_INT_FAST64_g = FAIL;
+hid_t H5T_NATIVE_UINT_FAST64_g = FAIL;
+
+/*
+ * Alignment constraints for native types. These are initialized at run time
+ * in H5Tinit.c. These alignments are mainly for offsets in HDF5 compound
+ * datatype or C structures, which are different from the alignments for memory
+ * address below this group of variables.
+ */
+size_t H5T_NATIVE_SCHAR_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_UCHAR_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_SHORT_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_USHORT_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_LONG_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_ULONG_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_LLONG_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_ULLONG_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_FLOAT_COMP_ALIGN_g = 0;
+size_t H5T_NATIVE_DOUBLE_COMP_ALIGN_g = 0;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+size_t H5T_NATIVE_LDOUBLE_COMP_ALIGN_g = 0;
+#endif
+
+size_t H5T_POINTER_COMP_ALIGN_g = 0;
+size_t H5T_HVL_COMP_ALIGN_g = 0;
+size_t H5T_HOBJREF_COMP_ALIGN_g = 0;
+size_t H5T_HDSETREGREF_COMP_ALIGN_g = 0;
+
+/*
+ * Alignment constraints for native types. These are initialized at run time
+ * in H5Tinit.c
+ */
+size_t H5T_NATIVE_SCHAR_ALIGN_g = 0;
+size_t H5T_NATIVE_UCHAR_ALIGN_g = 0;
+size_t H5T_NATIVE_SHORT_ALIGN_g = 0;
+size_t H5T_NATIVE_USHORT_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_ALIGN_g = 0;
+size_t H5T_NATIVE_LONG_ALIGN_g = 0;
+size_t H5T_NATIVE_ULONG_ALIGN_g = 0;
+size_t H5T_NATIVE_LLONG_ALIGN_g = 0;
+size_t H5T_NATIVE_ULLONG_ALIGN_g = 0;
+size_t H5T_NATIVE_FLOAT_ALIGN_g = 0;
+size_t H5T_NATIVE_DOUBLE_ALIGN_g = 0;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+size_t H5T_NATIVE_LDOUBLE_ALIGN_g = 0;
+#endif
+
+/*
+ * Alignment constraints for C9x types. These are initialized at run time in
+ * H5Tinit.c if the types are provided by the system. Otherwise we set their
+ * values to 0 here (no alignment calculated).
+ */
+size_t H5T_NATIVE_INT8_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT8_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_LEAST8_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_LEAST8_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_FAST8_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_FAST8_ALIGN_g = 0;
+
+size_t H5T_NATIVE_INT16_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT16_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_LEAST16_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_LEAST16_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_FAST16_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_FAST16_ALIGN_g = 0;
+
+size_t H5T_NATIVE_INT32_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT32_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_LEAST32_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_LEAST32_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_FAST32_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_FAST32_ALIGN_g = 0;
+
+size_t H5T_NATIVE_INT64_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT64_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_LEAST64_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_LEAST64_ALIGN_g = 0;
+size_t H5T_NATIVE_INT_FAST64_ALIGN_g = 0;
+size_t H5T_NATIVE_UINT_FAST64_ALIGN_g = 0;
+
+/* Useful floating-point values for conversion routines */
+/* (+/- Inf for all floating-point types) */
+float H5T_NATIVE_FLOAT_POS_INF_g = 0.0f;
+float H5T_NATIVE_FLOAT_NEG_INF_g = 0.0f;
+double H5T_NATIVE_DOUBLE_POS_INF_g = (double)0.0f;
+double H5T_NATIVE_DOUBLE_NEG_INF_g = (double)0.0f;
+
+/* Declare the free list for H5T_t's and H5T_shared_t's */
+H5FL_DEFINE(H5T_t);
+H5FL_DEFINE(H5T_shared_t);
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*
+ * The path database. Each path has a source and destination data type pair
+ * which is used as the key by which the `entries' array is sorted.
+ */
+static struct {
+ int npaths; /*number of paths defined */
+ size_t apaths; /*number of paths allocated */
+ H5T_path_t **path; /*sorted array of path pointers */
+ int nsoft; /*number of soft conversions defined */
+ size_t asoft; /*number of soft conversions allocated */
+ H5T_soft_t *soft; /*unsorted array of soft conversions */
+} H5T_g;
+
+/* Declare the free list for H5T_path_t's */
+H5FL_DEFINE_STATIC(H5T_path_t);
+
+/* Datatype ID class */
+static const H5I_class_t H5I_DATATYPE_CLS[1] = {{
+ H5I_DATATYPE, /* ID class value */
+ 0, /* Class flags */
+ 8, /* # of reserved IDs for class */
+ (H5I_free_t)H5T_close /* Callback routine for closing objects of this class */
+}};
+
+/* Flag indicating "top" of interface has been initialized */
+static hbool_t H5T_top_package_initialize_s = FALSE;
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_init
+ *
+ * Purpose: Initialize the interface from some other package.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_init(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__init_inf
+ *
+ * Purpose: Initialize the +/- Infinity floating-poing values for type
+ * conversion.
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 22, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T__init_inf(void)
+{
+ H5T_t *dst_p; /* Datatype type operate on */
+ H5T_atomic_t *dst; /* Datatype's atomic info */
+ uint8_t *d; /* Pointer to value to set */
+ size_t half_size; /* Half the type size */
+ size_t u; /* Local index value */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the float datatype */
+ if(NULL == (dst_p = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ dst = &dst_p->shared->u.atomic;
+
+ /* Check that we can re-order the bytes correctly */
+ if(H5T_ORDER_LE != H5T_native_order_g && H5T_ORDER_BE != H5T_native_order_g)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+
+ /* +Inf */
+ d = (uint8_t *)&H5T_NATIVE_FLOAT_POS_INF_g;
+ H5T__bit_set(d, dst->u.f.sign, (size_t)1, FALSE);
+ H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, TRUE);
+ H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, FALSE);
+
+ /* Swap the bytes if the machine architecture is big-endian */
+ if (H5T_ORDER_BE == H5T_native_order_g) {
+ half_size = dst_p->shared->size / 2;
+ for(u = 0; u < half_size; u++) {
+ uint8_t tmp = d[dst_p->shared->size - (u + 1)];
+ d[dst_p->shared->size - (u + 1)] = d[u];
+ d[u] = tmp;
+ } /* end for */
+ } /* end if */
+
+ /* -Inf */
+ d = (uint8_t *)&H5T_NATIVE_FLOAT_NEG_INF_g;
+ H5T__bit_set(d, dst->u.f.sign, (size_t)1, TRUE);
+ H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, TRUE);
+ H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, FALSE);
+
+ /* Swap the bytes if the machine architecture is big-endian */
+ if(H5T_ORDER_BE == H5T_native_order_g) {
+ half_size = dst_p->shared->size / 2;
+ for(u = 0; u < half_size; u++) {
+ uint8_t tmp = d[dst_p->shared->size - (u + 1)];
+ d[dst_p->shared->size - (u + 1)] = d[u];
+ d[u] = tmp;
+ } /* end for */
+ } /* end if */
+
+ /* Get the double datatype */
+ if(NULL == (dst_p = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ dst = &dst_p->shared->u.atomic;
+
+ /* Check that we can re-order the bytes correctly */
+ if(H5T_ORDER_LE != H5T_native_order_g && H5T_ORDER_BE != H5T_native_order_g)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+
+ /* +Inf */
+ d = (uint8_t *)&H5T_NATIVE_DOUBLE_POS_INF_g;
+ H5T__bit_set(d, dst->u.f.sign, (size_t)1, FALSE);
+ H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, TRUE);
+ H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, FALSE);
+
+ /* Swap the bytes if the machine architecture is big-endian */
+ if(H5T_ORDER_BE == H5T_native_order_g) {
+ half_size = dst_p->shared->size / 2;
+ for(u = 0; u < half_size; u++) {
+ uint8_t tmp = d[dst_p->shared->size - (u + 1)];
+ d[dst_p->shared->size - (u + 1)] = d[u];
+ d[u] = tmp;
+ } /* end for */
+ } /* end if */
+
+ /* -Inf */
+ d = (uint8_t *)&H5T_NATIVE_DOUBLE_NEG_INF_g;
+ H5T__bit_set(d, dst->u.f.sign, (size_t)1, TRUE);
+ H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, TRUE);
+ H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, FALSE);
+
+ /* Swap the bytes if the machine architecture is big-endian */
+ if(H5T_ORDER_BE == H5T_native_order_g) {
+ half_size = dst_p->shared->size / 2;
+ for(u = 0; u < half_size; u++) {
+ uint8_t tmp = d[dst_p->shared->size - (u + 1)];
+ d[dst_p->shared->size - (u + 1)] = d[u];
+ d[u] = tmp;
+ } /* end for */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__init_inf() */
+
+
+/*--------------------------------------------------------------------------
+NAME
+ H5T__init_package -- Initialize interface-specific information
+USAGE
+ herr__t H5T_init_package()
+RETURNS
+ Non-negative on success/Negative on failure
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t
+H5T__init_package(void)
+{
+ H5T_t *native_schar=NULL; /* Datatype structure for native signed char */
+ H5T_t *native_uchar=NULL; /* Datatype structure for native unsigned char */
+ H5T_t *native_short=NULL; /* Datatype structure for native short */
+ H5T_t *native_ushort=NULL; /* Datatype structure for native unsigned short */
+ H5T_t *native_int=NULL; /* Datatype structure for native int */
+ H5T_t *native_uint=NULL; /* Datatype structure for native unsigned int */
+ H5T_t *native_long=NULL; /* Datatype structure for native long */
+ H5T_t *native_ulong=NULL; /* Datatype structure for native unsigned long */
+ H5T_t *native_llong=NULL; /* Datatype structure for native long long */
+ H5T_t *native_ullong=NULL; /* Datatype structure for native unsigned long long */
+ H5T_t *native_float=NULL; /* Datatype structure for native float */
+ H5T_t *native_double=NULL; /* Datatype structure for native double */
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ H5T_t *native_ldouble=NULL; /* Datatype structure for native long double */
+#endif
+ H5T_t *std_u8le=NULL; /* Datatype structure for unsigned 8-bit little-endian integer */
+ H5T_t *std_u8be=NULL; /* Datatype structure for unsigned 8-bit big-endian integer */
+ H5T_t *std_u16le=NULL; /* Datatype structure for unsigned 16-bit little-endian integer */
+ H5T_t *std_u16be=NULL; /* Datatype structure for unsigned 16-bit big-endian integer */
+ H5T_t *std_u32le=NULL; /* Datatype structure for unsigned 32-bit little-endian integer */
+ H5T_t *std_u32be=NULL; /* Datatype structure for unsigned 32-bit big-endian integer */
+ H5T_t *std_u64le=NULL; /* Datatype structure for unsigned 64-bit little-endian integer */
+ H5T_t *std_u64be=NULL; /* Datatype structure for unsigned 64-bit big-endian integer */
+ H5T_t *dt = NULL;
+ H5T_t *fixedpt=NULL; /* Datatype structure for native int */
+ H5T_t *floatpt=NULL; /* Datatype structure for native float */
+ H5T_t *string=NULL; /* Datatype structure for C string */
+ H5T_t *bitfield=NULL; /* Datatype structure for bitfield */
+ H5T_t *compound=NULL; /* Datatype structure for compound objects */
+ H5T_t *enum_type=NULL; /* Datatype structure for enum objects */
+ H5T_t *vlen=NULL; /* Datatype structure for vlen objects */
+ H5T_t *array=NULL; /* Datatype structure for array objects */
+ H5T_t *objref=NULL; /* Datatype structure for object reference objects */
+ hsize_t dim[1]={1}; /* Dimension info for array datatype */
+ herr_t status;
+ unsigned copied_dtype=1; /* Flag to indicate whether datatype was copied or allocated (for error cleanup) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Initialize the atom group for the file IDs */
+ if(H5I_register_type(H5I_DATATYPE_CLS) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Make certain there aren't too many classes of datatypes defined */
+ /* Only 16 (numbered 0-15) are supported in the current file format */
+ HDcompile_assert(H5T_NCLASSES < 16);
+
+ /*
+ * Initialize pre-defined native datatypes from code generated during
+ * the library configuration by H5detect.
+ */
+ if(H5T__init_native() < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize interface")
+
+ /* Get the atomic datatype structures needed by the initialization code below */
+ if(NULL == (native_schar = (H5T_t *)H5I_object(H5T_NATIVE_SCHAR_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_uchar = (H5T_t *)H5I_object(H5T_NATIVE_UCHAR_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_short = (H5T_t *)H5I_object(H5T_NATIVE_SHORT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_ushort = (H5T_t *)H5I_object(H5T_NATIVE_USHORT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_int = (H5T_t *)H5I_object(H5T_NATIVE_INT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_uint = (H5T_t *)H5I_object(H5T_NATIVE_UINT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_long = (H5T_t *)H5I_object(H5T_NATIVE_LONG_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_ulong = (H5T_t *)H5I_object(H5T_NATIVE_ULONG_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_llong = (H5T_t *)H5I_object(H5T_NATIVE_LLONG_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_ullong = (H5T_t *)H5I_object(H5T_NATIVE_ULLONG_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_float = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(NULL == (native_double = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ if(NULL == (native_ldouble = (H5T_t *)H5I_object(H5T_NATIVE_LDOUBLE_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+#endif
+
+ /*------------------------------------------------------------
+ * Derived native types
+ *------------------------------------------------------------
+ */
+
+ /* 1-byte bit field */
+ H5T_INIT_TYPE(BITFIELD,H5T_NATIVE_B8_g,COPY,native_uint,SET,1)
+
+ /* 2-byte bit field */
+ H5T_INIT_TYPE(BITFIELD,H5T_NATIVE_B16_g,COPY,native_uint,SET,2)
+
+ /* 4-byte bit field */
+ H5T_INIT_TYPE(BITFIELD,H5T_NATIVE_B32_g,COPY,native_uint,SET,4)
+
+ /* 8-byte bit field */
+ H5T_INIT_TYPE(BITFIELD,H5T_NATIVE_B64_g,COPY,native_uint,SET,8)
+
+ /* haddr_t */
+ H5T_INIT_TYPE(OFFSET,H5T_NATIVE_HADDR_g,COPY,native_uint,SET,sizeof(haddr_t))
+
+ /* hsize_t */
+ H5T_INIT_TYPE(OFFSET,H5T_NATIVE_HSIZE_g,COPY,native_uint,SET,sizeof(hsize_t))
+
+ /* hssize_t */
+ H5T_INIT_TYPE(OFFSET,H5T_NATIVE_HSSIZE_g,COPY,native_int,SET,sizeof(hssize_t))
+
+ /* herr_t */
+ H5T_INIT_TYPE(OFFSET,H5T_NATIVE_HERR_g,COPY,native_int,SET,sizeof(herr_t))
+
+ /* hbool_t */
+ H5T_INIT_TYPE(OFFSET,H5T_NATIVE_HBOOL_g,COPY,native_uint,SET,sizeof(hbool_t))
+
+ /*------------------------------------------------------------
+ * IEEE Types
+ *------------------------------------------------------------
+ */
+
+ /* IEEE 4-byte little-endian float */
+ H5T_INIT_TYPE(FLOATLE,H5T_IEEE_F32LE_g,COPY,native_double,SET,4)
+
+ /* IEEE 4-byte big-endian float */
+ H5T_INIT_TYPE(FLOATBE,H5T_IEEE_F32BE_g,COPY,native_double,SET,4)
+
+ /* IEEE 8-byte little-endian float */
+ H5T_INIT_TYPE(DOUBLELE,H5T_IEEE_F64LE_g,COPY,native_double,SET,8)
+
+ /* IEEE 8-byte big-endian float */
+ H5T_INIT_TYPE(DOUBLEBE,H5T_IEEE_F64BE_g,COPY,native_double,SET,8)
+
+ /*------------------------------------------------------------
+ * VAX Types
+ *------------------------------------------------------------
+ */
+
+ /* VAX 4-byte float */
+ H5T_INIT_TYPE(FLOATVAX,H5T_VAX_F32_g,COPY,native_double,SET,4)
+
+ /* VAX 8-byte double */
+ H5T_INIT_TYPE(DOUBLEVAX,H5T_VAX_F64_g,COPY,native_double,SET,8)
+
+ /*------------------------------------------------------------
+ * C99 types
+ *------------------------------------------------------------
+ */
+
+ /* 1-byte little-endian (endianness is irrelevant) signed integer */
+ H5T_INIT_TYPE(SINTLE,H5T_STD_I8LE_g,COPY,native_int,SET,1)
+
+ /* 1-byte big-endian (endianness is irrelevant) signed integer */
+ H5T_INIT_TYPE(SINTBE,H5T_STD_I8BE_g,COPY,native_int,SET,1)
+
+ /* 2-byte little-endian signed integer */
+ H5T_INIT_TYPE(SINTLE,H5T_STD_I16LE_g,COPY,native_int,SET,2)
+
+ /* 2-byte big-endian signed integer */
+ H5T_INIT_TYPE(SINTBE,H5T_STD_I16BE_g,COPY,native_int,SET,2)
+
+ /* 4-byte little-endian signed integer */
+ H5T_INIT_TYPE(SINTLE,H5T_STD_I32LE_g,COPY,native_int,SET,4)
+
+ /* 4-byte big-endian signed integer */
+ H5T_INIT_TYPE(SINTBE,H5T_STD_I32BE_g,COPY,native_int,SET,4)
+
+ /* 8-byte little-endian signed integer */
+ H5T_INIT_TYPE(SINTLE,H5T_STD_I64LE_g,COPY,native_int,SET,8)
+
+ /* 8-byte big-endian signed integer */
+ H5T_INIT_TYPE(SINTBE,H5T_STD_I64BE_g,COPY,native_int,SET,8)
+
+ /* 1-byte little-endian (endianness is irrelevant) unsigned integer */
+ H5T_INIT_TYPE(UINTLE,H5T_STD_U8LE_g,COPY,native_uint,SET,1)
+ std_u8le=dt; /* Keep type for later */
+
+ /* 1-byte big-endian (endianness is irrelevant) unsigned integer */
+ H5T_INIT_TYPE(UINTBE,H5T_STD_U8BE_g,COPY,native_uint,SET,1)
+ std_u8be=dt; /* Keep type for later */
+
+ /* 2-byte little-endian unsigned integer */
+ H5T_INIT_TYPE(UINTLE,H5T_STD_U16LE_g,COPY,native_uint,SET,2)
+ std_u16le=dt; /* Keep type for later */
+
+ /* 2-byte big-endian unsigned integer */
+ H5T_INIT_TYPE(UINTBE,H5T_STD_U16BE_g,COPY,native_uint,SET,2)
+ std_u16be=dt; /* Keep type for later */
+
+ /* 4-byte little-endian unsigned integer */
+ H5T_INIT_TYPE(UINTLE,H5T_STD_U32LE_g,COPY,native_uint,SET,4)
+ std_u32le=dt; /* Keep type for later */
+
+ /* 4-byte big-endian unsigned integer */
+ H5T_INIT_TYPE(UINTBE,H5T_STD_U32BE_g,COPY,native_uint,SET,4)
+ std_u32be=dt; /* Keep type for later */
+
+ /* 8-byte little-endian unsigned integer */
+ H5T_INIT_TYPE(UINTLE,H5T_STD_U64LE_g,COPY,native_uint,SET,8)
+ std_u64le=dt; /* Keep type for later */
+
+ /* 8-byte big-endian unsigned integer */
+ H5T_INIT_TYPE(UINTBE,H5T_STD_U64BE_g,COPY,native_uint,SET,8)
+ std_u64be=dt; /* Keep type for later */
+
+ /*------------------------------------------------------------
+ * Native, Little- & Big-endian bitfields
+ *------------------------------------------------------------
+ */
+
+ /* little-endian (order is irrelevant) 8-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B8LE_g, COPY, std_u8le, NOSET, -)
+ bitfield=dt; /* Keep type for later */
+
+ /* big-endian (order is irrelevant) 8-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B8BE_g, COPY, std_u8be, NOSET, -)
+
+ /* Little-endian 16-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B16LE_g, COPY, std_u16le, NOSET, -)
+
+ /* Big-endian 16-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B16BE_g, COPY, std_u16be, NOSET, -)
+
+ /* Little-endian 32-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B32LE_g, COPY, std_u32le, NOSET, -)
+
+ /* Big-endian 32-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B32BE_g, COPY, std_u32be, NOSET, -)
+
+ /* Little-endian 64-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B64LE_g, COPY, std_u64le, NOSET, -)
+
+ /* Big-endian 64-bit bitfield */
+ H5T_INIT_TYPE(BITFIELD, H5T_STD_B64BE_g, COPY, std_u64be, NOSET, -)
+
+ /*------------------------------------------------------------
+ * The Unix architecture for dates and times.
+ *------------------------------------------------------------
+ */
+
+ /* Little-endian 32-bit UNIX time_t */
+ H5T_INIT_TYPE(TIME, H5T_UNIX_D32LE_g, COPY, std_u32le, NOSET, -)
+
+ /* Big-endian 32-bit UNIX time_t */
+ H5T_INIT_TYPE(TIME, H5T_UNIX_D32BE_g, COPY, std_u32be, NOSET, -)
+
+ /* Little-endian 64-bit UNIX time_t */
+ H5T_INIT_TYPE(TIME, H5T_UNIX_D64LE_g, COPY, std_u64le, NOSET, -)
+
+ /* Big-endian 64-bit UNIX time_t */
+ H5T_INIT_TYPE(TIME, H5T_UNIX_D64BE_g, COPY, std_u64be, NOSET, -)
+
+
+ /* Indicate that the types that are created from here down are allocated
+ * H5FL_ALLOC(), not copied with H5T_copy()
+ */
+ copied_dtype = FALSE;
+
+ /* Opaque data */
+ H5T_INIT_TYPE(OPAQ, H5T_NATIVE_OPAQUE_g, ALLOC, -, SET, 1)
+
+ /*------------------------------------------------------------
+ * The `C' architecture
+ *------------------------------------------------------------
+ */
+
+ /* One-byte character string */
+ H5T_INIT_TYPE(CSTRING, H5T_C_S1_g, ALLOC, -, SET, 1)
+ string = dt; /* Keep type for later */
+
+ /*------------------------------------------------------------
+ * The `Fortran' architecture
+ *------------------------------------------------------------
+ */
+
+ /* One-byte character string */
+ H5T_INIT_TYPE(FORSTRING, H5T_FORTRAN_S1_g, ALLOC, -, SET, 1)
+
+ /*------------------------------------------------------------
+ * Reference types
+ *------------------------------------------------------------
+ */
+
+ /* Object reference (i.e. object header address in file) */
+ H5T_INIT_TYPE(OBJREF, H5T_STD_REF_OBJ_g, ALLOC, -, SET, H5R_OBJ_REF_BUF_SIZE)
+ objref = dt; /* Keep type for later */
+
+ /* Dataset Region reference (i.e. selection inside a dataset) */
+ H5T_INIT_TYPE(REGREF, H5T_STD_REF_DSETREG_g, ALLOC, -, SET, H5R_DSET_REG_REF_BUF_SIZE)
+
+ /*
+ * Register conversion functions beginning with the most general and
+ * ending with the most specific.
+ */
+ fixedpt = native_int;
+ floatpt = native_float;
+ if (NULL == (compound = H5T__create(H5T_COMPOUND, (size_t)1)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if (NULL == (enum_type = H5T__create(H5T_ENUM, (size_t)1)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if (NULL == (vlen = H5T__vlen_create(native_int)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if (NULL == (array = H5T__array_create(native_int, 1, dim)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ status = 0;
+
+ status |= H5T_register(H5T_PERS_SOFT, "i_i", fixedpt, fixedpt, H5T__conv_i_i, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "i_f", fixedpt, floatpt, H5T__conv_i_f, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "f_f", floatpt, floatpt, H5T__conv_f_f, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "f_i", floatpt, fixedpt, H5T__conv_f_i, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "s_s", string, string, H5T__conv_s_s, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "b_b", bitfield, bitfield, H5T__conv_b_b, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "ibo", fixedpt, fixedpt, H5T__conv_order, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "ibo(opt)", fixedpt, fixedpt, H5T__conv_order_opt, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "fbo", floatpt, floatpt, H5T__conv_order, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "fbo(opt)", floatpt, floatpt, H5T__conv_order_opt, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "struct(no-opt)", compound, compound, H5T__conv_struct, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "struct(opt)", compound, compound, H5T__conv_struct_opt, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "enum", enum_type, enum_type, H5T__conv_enum, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "enum_i", enum_type, fixedpt, H5T__conv_enum_numeric, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "enum_f", enum_type, floatpt, H5T__conv_enum_numeric, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "vlen", vlen, vlen, H5T__conv_vlen, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "array", array, array, H5T__conv_array, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_SOFT, "objref", objref, objref, H5T__conv_order_opt, H5AC_noio_dxpl_id, FALSE);
+
+ /*
+ * Native conversions should be listed last since we can use hardware to
+ * perform the conversion. We list the odd types like `llong', `long',
+ * and `short' before the usual types like `int' and `char' so that when
+ * diagnostics are printed we favor the usual names over the odd names
+ * when two or more types are the same size.
+ */
+
+ /* floating point */
+ status |= H5T_register(H5T_PERS_HARD, "flt_dbl", native_float, native_double, H5T__conv_float_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_flt", native_double, native_float, H5T__conv_double_float, H5AC_noio_dxpl_id, FALSE);
+#if H5_SIZEOF_LONG_DOUBLE != 0
+ status |= H5T_register(H5T_PERS_HARD, "flt_ldbl", native_float, native_ldouble, H5T__conv_float_ldouble, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_ldbl", native_double, native_ldouble, H5T__conv_double_ldouble, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_flt", native_ldouble, native_float, H5T__conv_ldouble_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_dbl", native_ldouble, native_double, H5T__conv_ldouble_double, H5AC_noio_dxpl_id, FALSE);
+#endif /* H5_SIZEOF_LONG_DOUBLE != 0 */
+
+ /* from long long */
+ status |= H5T_register(H5T_PERS_HARD, "llong_ullong", native_llong, native_ullong, H5T__conv_llong_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_llong", native_ullong, native_llong, H5T__conv_ullong_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_long", native_llong, native_long, H5T__conv_llong_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_ulong", native_llong, native_ulong, H5T__conv_llong_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_long", native_ullong, native_long, H5T__conv_ullong_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_ulong", native_ullong, native_ulong, H5T__conv_ullong_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_short", native_llong, native_short, H5T__conv_llong_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_ushort", native_llong, native_ushort, H5T__conv_llong_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_short", native_ullong, native_short, H5T__conv_ullong_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_ushort", native_ullong, native_ushort, H5T__conv_ullong_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_int", native_llong, native_int, H5T__conv_llong_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_uint", native_llong, native_uint, H5T__conv_llong_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_int", native_ullong, native_int, H5T__conv_ullong_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_uint", native_ullong, native_uint, H5T__conv_ullong_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_schar", native_llong, native_schar, H5T__conv_llong_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_uchar", native_llong, native_uchar, H5T__conv_llong_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_schar", native_ullong, native_schar, H5T__conv_ullong_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_uchar", native_ullong, native_uchar, H5T__conv_ullong_uchar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From long */
+ status |= H5T_register(H5T_PERS_HARD, "long_llong", native_long, native_llong, H5T__conv_long_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_ullong", native_long, native_ullong, H5T__conv_long_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_llong", native_ulong, native_llong, H5T__conv_ulong_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_ullong", native_ulong, native_ullong, H5T__conv_ulong_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_ulong", native_long, native_ulong, H5T__conv_long_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_long", native_ulong, native_long, H5T__conv_ulong_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_short", native_long, native_short, H5T__conv_long_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_ushort", native_long, native_ushort, H5T__conv_long_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_short", native_ulong, native_short, H5T__conv_ulong_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_ushort", native_ulong, native_ushort, H5T__conv_ulong_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_int", native_long, native_int, H5T__conv_long_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_uint", native_long, native_uint, H5T__conv_long_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_int", native_ulong, native_int, H5T__conv_ulong_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_uint", native_ulong, native_uint, H5T__conv_ulong_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_schar", native_long, native_schar, H5T__conv_long_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_uchar", native_long, native_uchar, H5T__conv_long_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_schar", native_ulong, native_schar, H5T__conv_ulong_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_uchar", native_ulong, native_uchar, H5T__conv_ulong_uchar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From short */
+ status |= H5T_register(H5T_PERS_HARD, "short_llong", native_short, native_llong, H5T__conv_short_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_ullong", native_short, native_ullong, H5T__conv_short_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_llong", native_ushort, native_llong, H5T__conv_ushort_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_ullong", native_ushort, native_ullong, H5T__conv_ushort_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_long", native_short, native_long, H5T__conv_short_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_ulong", native_short, native_ulong, H5T__conv_short_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_long", native_ushort, native_long, H5T__conv_ushort_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_ulong", native_ushort, native_ulong, H5T__conv_ushort_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_ushort", native_short, native_ushort, H5T__conv_short_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_short", native_ushort, native_short, H5T__conv_ushort_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_int", native_short, native_int, H5T__conv_short_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_uint", native_short, native_uint, H5T__conv_short_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_int", native_ushort, native_int, H5T__conv_ushort_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_uint", native_ushort, native_uint, H5T__conv_ushort_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_schar", native_short, native_schar, H5T__conv_short_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_uchar", native_short, native_uchar, H5T__conv_short_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_schar", native_ushort, native_schar, H5T__conv_ushort_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_uchar", native_ushort, native_uchar, H5T__conv_ushort_uchar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From int */
+ status |= H5T_register(H5T_PERS_HARD, "int_llong", native_int, native_llong, H5T__conv_int_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_ullong", native_int, native_ullong, H5T__conv_int_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_llong", native_uint, native_llong, H5T__conv_uint_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_ullong", native_uint, native_ullong, H5T__conv_uint_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_long", native_int, native_long, H5T__conv_int_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_ulong", native_int, native_ulong, H5T__conv_int_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_long", native_uint, native_long, H5T__conv_uint_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_ulong", native_uint, native_ulong, H5T__conv_uint_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_short", native_int, native_short, H5T__conv_int_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_ushort", native_int, native_ushort, H5T__conv_int_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_short", native_uint, native_short, H5T__conv_uint_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_ushort", native_uint, native_ushort, H5T__conv_uint_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_uint", native_int, native_uint, H5T__conv_int_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_int", native_uint, native_int, H5T__conv_uint_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_schar", native_int, native_schar, H5T__conv_int_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_uchar", native_int, native_uchar, H5T__conv_int_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_schar", native_uint, native_schar, H5T__conv_uint_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_uchar", native_uint, native_uchar, H5T__conv_uint_uchar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From char */
+ status |= H5T_register(H5T_PERS_HARD, "schar_llong", native_schar, native_llong, H5T__conv_schar_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_ullong", native_schar, native_ullong, H5T__conv_schar_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_llong", native_uchar, native_llong, H5T__conv_uchar_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_ullong", native_uchar, native_ullong, H5T__conv_uchar_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_long", native_schar, native_long, H5T__conv_schar_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_ulong", native_schar, native_ulong, H5T__conv_schar_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_long", native_uchar, native_long, H5T__conv_uchar_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_ulong", native_uchar, native_ulong, H5T__conv_uchar_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_short", native_schar, native_short, H5T__conv_schar_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_ushort", native_schar, native_ushort, H5T__conv_schar_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_short", native_uchar, native_short, H5T__conv_uchar_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_ushort", native_uchar, native_ushort, H5T__conv_uchar_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_int", native_schar, native_int, H5T__conv_schar_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_uint", native_schar, native_uint, H5T__conv_schar_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_int", native_uchar, native_int, H5T__conv_uchar_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_uint", native_uchar, native_uint, H5T__conv_uchar_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_uchar", native_schar, native_uchar, H5T__conv_schar_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_schar", native_uchar, native_schar, H5T__conv_uchar_schar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From char to floats */
+ status |= H5T_register(H5T_PERS_HARD, "schar_flt", native_schar, native_float, H5T__conv_schar_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_dbl", native_schar, native_double, H5T__conv_schar_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "schar_ldbl", native_schar, native_ldouble, H5T__conv_schar_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From unsigned char to floats */
+ status |= H5T_register(H5T_PERS_HARD, "uchar_flt", native_uchar, native_float, H5T__conv_uchar_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_dbl", native_uchar, native_double, H5T__conv_uchar_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uchar_ldbl", native_uchar, native_ldouble, H5T__conv_uchar_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From short to floats */
+ status |= H5T_register(H5T_PERS_HARD, "short_flt", native_short, native_float, H5T__conv_short_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_dbl", native_short, native_double, H5T__conv_short_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "short_ldbl", native_short, native_ldouble, H5T__conv_short_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From unsigned short to floats */
+ status |= H5T_register(H5T_PERS_HARD, "ushort_flt", native_ushort, native_float, H5T__conv_ushort_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_dbl", native_ushort, native_double, H5T__conv_ushort_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ushort_ldbl", native_ushort, native_ldouble, H5T__conv_ushort_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From int to floats */
+ status |= H5T_register(H5T_PERS_HARD, "int_flt", native_int, native_float, H5T__conv_int_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_dbl", native_int, native_double, H5T__conv_int_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "int_ldbl", native_int, native_ldouble, H5T__conv_int_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From unsigned int to floats */
+ status |= H5T_register(H5T_PERS_HARD, "uint_flt", native_uint, native_float, H5T__conv_uint_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_dbl", native_uint, native_double, H5T__conv_uint_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "uint_ldbl", native_uint, native_ldouble, H5T__conv_uint_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From long to floats */
+ status |= H5T_register(H5T_PERS_HARD, "long_flt", native_long, native_float, H5T__conv_long_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_dbl", native_long, native_double, H5T__conv_long_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "long_ldbl", native_long, native_ldouble, H5T__conv_long_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From unsigned long to floats */
+ status |= H5T_register(H5T_PERS_HARD, "ulong_flt", native_ulong, native_float, H5T__conv_ulong_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_dbl", native_ulong, native_double, H5T__conv_ulong_double, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ulong_ldbl", native_ulong, native_ldouble, H5T__conv_ulong_ldouble, H5AC_noio_dxpl_id, FALSE);
+
+ /* From long long to floats */
+ status |= H5T_register(H5T_PERS_HARD, "llong_flt", native_llong, native_float, H5T__conv_llong_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "llong_dbl", native_llong, native_double, H5T__conv_llong_double, H5AC_noio_dxpl_id, FALSE);
+#ifdef H5T_CONV_INTERNAL_LLONG_LDOUBLE
+ status |= H5T_register(H5T_PERS_HARD, "llong_ldbl", native_llong, native_ldouble, H5T__conv_llong_ldouble, H5AC_noio_dxpl_id, FALSE);
+#endif /* H5T_CONV_INTERNAL_LLONG_LDOUBLE */
+
+ /* From unsigned long long to floats */
+ status |= H5T_register(H5T_PERS_HARD, "ullong_flt", native_ullong, native_float, H5T__conv_ullong_float, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ullong_dbl", native_ullong, native_double, H5T__conv_ullong_double, H5AC_noio_dxpl_id, FALSE);
+#ifdef H5T_CONV_INTERNAL_ULLONG_LDOUBLE
+ status |= H5T_register(H5T_PERS_HARD, "ullong_ldbl", native_ullong, native_ldouble, H5T__conv_ullong_ldouble, H5AC_noio_dxpl_id, FALSE);
+#endif /* H5T_CONV_INTERNAL_ULLONG_LDOUBLE */
+
+ /* From floats to char */
+ status |= H5T_register(H5T_PERS_HARD, "flt_schar", native_float, native_schar, H5T__conv_float_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_schar", native_double, native_schar, H5T__conv_double_schar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_schar", native_ldouble, native_schar, H5T__conv_ldouble_schar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to unsigned char */
+ status |= H5T_register(H5T_PERS_HARD, "flt_uchar", native_float, native_uchar, H5T__conv_float_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_uchar", native_double, native_uchar, H5T__conv_double_uchar, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_uchar", native_ldouble, native_uchar, H5T__conv_ldouble_uchar, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to short */
+ status |= H5T_register(H5T_PERS_HARD, "flt_short", native_float, native_short, H5T__conv_float_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_short", native_double, native_short, H5T__conv_double_short, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_short", native_ldouble, native_short, H5T__conv_ldouble_short, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to unsigned short */
+ status |= H5T_register(H5T_PERS_HARD, "flt_ushort", native_float, native_ushort, H5T__conv_float_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_ushort", native_double, native_ushort, H5T__conv_double_ushort, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_ushort", native_ldouble, native_ushort, H5T__conv_ldouble_ushort, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to int */
+ status |= H5T_register(H5T_PERS_HARD, "flt_int", native_float, native_int, H5T__conv_float_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_int", native_double, native_int, H5T__conv_double_int, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_int", native_ldouble, native_int, H5T__conv_ldouble_int, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to unsigned int */
+ status |= H5T_register(H5T_PERS_HARD, "flt_uint", native_float, native_uint, H5T__conv_float_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_uint", native_double, native_uint, H5T__conv_double_uint, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_uint", native_ldouble, native_uint, H5T__conv_ldouble_uint, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to long */
+ status |= H5T_register(H5T_PERS_HARD, "flt_long", native_float, native_long, H5T__conv_float_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_long", native_double, native_long, H5T__conv_double_long, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_long", native_ldouble, native_long, H5T__conv_ldouble_long, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to unsigned long */
+ status |= H5T_register(H5T_PERS_HARD, "flt_ulong", native_float, native_ulong, H5T__conv_float_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_ulong", native_double, native_ulong, H5T__conv_double_ulong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_ulong", native_ldouble, native_ulong, H5T__conv_ldouble_ulong, H5AC_noio_dxpl_id, FALSE);
+
+ /* From floats to long long */
+ status |= H5T_register(H5T_PERS_HARD, "flt_llong", native_float, native_llong, H5T__conv_float_llong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_llong", native_double, native_llong, H5T__conv_double_llong, H5AC_noio_dxpl_id, FALSE);
+#ifdef H5T_CONV_INTERNAL_LDOUBLE_LLONG
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_llong", native_ldouble, native_llong, H5T__conv_ldouble_llong, H5AC_noio_dxpl_id, FALSE);
+#endif /* H5T_CONV_INTERNAL_LDOUBLE_LLONG */
+
+ /* From floats to unsigned long long */
+ status |= H5T_register(H5T_PERS_HARD, "flt_ullong", native_float, native_ullong, H5T__conv_float_ullong, H5AC_noio_dxpl_id, FALSE);
+ status |= H5T_register(H5T_PERS_HARD, "dbl_ullong", native_double, native_ullong, H5T__conv_double_ullong, H5AC_noio_dxpl_id, FALSE);
+#if H5T_CONV_INTERNAL_LDOUBLE_ULLONG
+ status |= H5T_register(H5T_PERS_HARD, "ldbl_ullong", native_ldouble, native_ullong, H5T__conv_ldouble_ullong, H5AC_noio_dxpl_id, FALSE);
+#endif /* H5T_CONV_INTERNAL_LDOUBLE_ULLONG */
+
+ /*
+ * The special no-op conversion is the fastest, so we list it last. The
+ * data types we use are not important as long as the source and
+ * destination are equal.
+ */
+ status |= H5T_register(H5T_PERS_HARD, "no-op", native_int, native_int, H5T__conv_noop, H5AC_noio_dxpl_id, FALSE);
+
+ /* Initialize the +/- Infinity values for floating-point types */
+ status |= H5T__init_inf();
+
+ if(status < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to register conversion function(s)")
+
+ /* Register datatype creation property class properties here. See similar
+ * code in H5D__init_package(), etc. for example.
+ */
+
+ /* Only register the default property list if it hasn't been created yet */
+ if(H5P_LST_DATATYPE_CREATE_ID_g == (-1)) {
+ /* ========== Datatype Creation Property Class Initialization ============*/
+ HDassert(H5P_CLS_DATATYPE_CREATE_g != NULL);
+
+ /* Register the default datatype creation property list */
+ if((H5P_LST_DATATYPE_CREATE_ID_g = H5P_create_id(H5P_CLS_DATATYPE_CREATE_g, FALSE)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't insert property into class")
+ } /* end if */
+
+ /* Mark "top" of interface as initialized, too */
+ H5T_top_package_initialize_s = TRUE;
+
+done:
+ /* General cleanup */
+ if(compound != NULL)
+ H5T_close(compound);
+ if(enum_type != NULL)
+ H5T_close(enum_type);
+ if(vlen != NULL)
+ H5T_close(vlen);
+ if(array != NULL)
+ H5T_close(array);
+
+ /* Error cleanup */
+ if(ret_value < 0) {
+ if(dt) {
+ /* Check if we should call H5T_close or H5FL_FREE */
+ if(copied_dtype)
+ H5T_close(dt);
+ else {
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+ dt = H5FL_FREE(H5T_t, dt);
+ } /* end else */
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__unlock_cb
+ *
+ * Purpose: Clear the immutable flag for a datatype. This function is
+ * called when the library is closing in order to unlock all
+ * registered datatypes and thus make them free-able.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, April 27, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5T__unlock_cb(void *_dt, hid_t H5_ATTR_UNUSED id, void *_udata)
+{
+ H5T_t *dt = (H5T_t *)_dt;
+ int *n = (int *)_udata;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(dt && dt->shared);
+
+ if(H5T_STATE_IMMUTABLE==dt->shared->state) {
+ dt->shared->state = H5T_STATE_RDONLY;
+
+ (*n)++;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T__unlock_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_top_term_package
+ *
+ * Purpose: Close the "top" of the interface, releasing IDs, etc.
+ *
+ * Return: Success: Positive if any action might have caused a
+ * change in some other interface; zero otherwise.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_top_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5T_top_package_initialize_s) {
+ /* Unregister all conversion functions */
+ if(H5T_g.path) {
+ int i, nprint = 0;
+
+ for(i = 0; i < H5T_g.npaths; i++) {
+ H5T_path_t *path;
+
+ path = H5T_g.path[i];
+ HDassert(path);
+ if(path->func) {
+ H5T__print_stats(path, &nprint/*in,out*/);
+ path->cdata.command = H5T_CONV_FREE;
+ if((path->func)((hid_t)FAIL, (hid_t)FAIL, &(path->cdata), (size_t)0,
+ (size_t)0, (size_t)0, NULL, NULL,H5AC_noio_dxpl_id) < 0) {
+#ifdef H5T_DEBUG
+ if (H5DEBUG(T)) {
+ fprintf(H5DEBUG(T), "H5T: conversion function "
+ "0x%08lx failed to free private data for "
+ "%s (ignored)\n",
+ (unsigned long)(path->func), path->name);
+ } /* end if */
+#endif
+ H5E_clear_stack(NULL); /*ignore the error*/
+ } /* end if */
+ } /* end if */
+
+ if(path->src)
+ H5T_close(path->src);
+ if(path->dst)
+ H5T_close(path->dst);
+ path = H5FL_FREE(H5T_path_t, path);
+ H5T_g.path[i] = NULL;
+ } /* end for */
+
+ /* Clear conversion tables */
+ H5T_g.path = (H5T_path_t **)H5MM_xfree(H5T_g.path);
+ H5T_g.npaths = 0;
+ H5T_g.apaths = 0;
+ H5T_g.soft = (H5T_soft_t *)H5MM_xfree(H5T_g.soft);
+ H5T_g.nsoft = 0;
+ H5T_g.asoft = 0;
+
+ n++;
+ } /* end if */
+
+ /* Unlock all datatypes, then free them */
+ /* note that we are ignoring the return value from H5I_iterate() */
+ /* Also note that we are incrementing 'n' in the callback */
+ H5I_iterate(H5I_DATATYPE, H5T__unlock_cb, &n, FALSE);
+
+ /* Release all datatype IDs */
+ if(H5I_nmembers(H5I_DATATYPE) > 0) {
+ (void)H5I_clear_type(H5I_DATATYPE, FALSE, FALSE);
+ n++; /*H5I*/
+ } /* end if */
+
+ /* Reset all the datatype IDs */
+ if(H5T_IEEE_F32BE_g > 0) {
+ H5T_IEEE_F32BE_g = FAIL;
+ H5T_IEEE_F32LE_g = FAIL;
+ H5T_IEEE_F64BE_g = FAIL;
+ H5T_IEEE_F64LE_g = FAIL;
+
+ H5T_STD_I8BE_g = FAIL;
+ H5T_STD_I8LE_g = FAIL;
+ H5T_STD_I16BE_g = FAIL;
+ H5T_STD_I16LE_g = FAIL;
+ H5T_STD_I32BE_g = FAIL;
+ H5T_STD_I32LE_g = FAIL;
+ H5T_STD_I64BE_g = FAIL;
+ H5T_STD_I64LE_g = FAIL;
+ H5T_STD_U8BE_g = FAIL;
+ H5T_STD_U8LE_g = FAIL;
+ H5T_STD_U16BE_g = FAIL;
+ H5T_STD_U16LE_g = FAIL;
+ H5T_STD_U32BE_g = FAIL;
+ H5T_STD_U32LE_g = FAIL;
+ H5T_STD_U64BE_g = FAIL;
+ H5T_STD_U64LE_g = FAIL;
+ H5T_STD_B8BE_g = FAIL;
+ H5T_STD_B8LE_g = FAIL;
+ H5T_STD_B16BE_g = FAIL;
+ H5T_STD_B16LE_g = FAIL;
+ H5T_STD_B32BE_g = FAIL;
+ H5T_STD_B32LE_g = FAIL;
+ H5T_STD_B64BE_g = FAIL;
+ H5T_STD_B64LE_g = FAIL;
+ H5T_STD_REF_OBJ_g = FAIL;
+ H5T_STD_REF_DSETREG_g = FAIL;
+
+ H5T_UNIX_D32BE_g = FAIL;
+ H5T_UNIX_D32LE_g = FAIL;
+ H5T_UNIX_D64BE_g = FAIL;
+ H5T_UNIX_D64LE_g = FAIL;
+
+ H5T_C_S1_g = FAIL;
+
+ H5T_FORTRAN_S1_g = FAIL;
+
+ H5T_NATIVE_SCHAR_g = FAIL;
+ H5T_NATIVE_UCHAR_g = FAIL;
+ H5T_NATIVE_SHORT_g = FAIL;
+ H5T_NATIVE_USHORT_g = FAIL;
+ H5T_NATIVE_INT_g = FAIL;
+ H5T_NATIVE_UINT_g = FAIL;
+ H5T_NATIVE_LONG_g = FAIL;
+ H5T_NATIVE_ULONG_g = FAIL;
+ H5T_NATIVE_LLONG_g = FAIL;
+ H5T_NATIVE_ULLONG_g = FAIL;
+ H5T_NATIVE_FLOAT_g = FAIL;
+ H5T_NATIVE_DOUBLE_g = FAIL;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ H5T_NATIVE_LDOUBLE_g = FAIL;
+#endif
+ H5T_NATIVE_B8_g = FAIL;
+ H5T_NATIVE_B16_g = FAIL;
+ H5T_NATIVE_B32_g = FAIL;
+ H5T_NATIVE_B64_g = FAIL;
+ H5T_NATIVE_OPAQUE_g = FAIL;
+ H5T_NATIVE_HADDR_g = FAIL;
+ H5T_NATIVE_HSIZE_g = FAIL;
+ H5T_NATIVE_HSSIZE_g = FAIL;
+ H5T_NATIVE_HERR_g = FAIL;
+ H5T_NATIVE_HBOOL_g = FAIL;
+
+ H5T_NATIVE_INT8_g = FAIL;
+ H5T_NATIVE_UINT8_g = FAIL;
+ H5T_NATIVE_INT_LEAST8_g = FAIL;
+ H5T_NATIVE_UINT_LEAST8_g = FAIL;
+ H5T_NATIVE_INT_FAST8_g = FAIL;
+ H5T_NATIVE_UINT_FAST8_g = FAIL;
+
+ H5T_NATIVE_INT16_g = FAIL;
+ H5T_NATIVE_UINT16_g = FAIL;
+ H5T_NATIVE_INT_LEAST16_g = FAIL;
+ H5T_NATIVE_UINT_LEAST16_g = FAIL;
+ H5T_NATIVE_INT_FAST16_g = FAIL;
+ H5T_NATIVE_UINT_FAST16_g = FAIL;
+
+ H5T_NATIVE_INT32_g = FAIL;
+ H5T_NATIVE_UINT32_g = FAIL;
+ H5T_NATIVE_INT_LEAST32_g = FAIL;
+ H5T_NATIVE_UINT_LEAST32_g = FAIL;
+ H5T_NATIVE_INT_FAST32_g = FAIL;
+ H5T_NATIVE_UINT_FAST32_g = FAIL;
+
+ H5T_NATIVE_INT64_g = FAIL;
+ H5T_NATIVE_UINT64_g = FAIL;
+ H5T_NATIVE_INT_LEAST64_g = FAIL;
+ H5T_NATIVE_UINT_LEAST64_g = FAIL;
+ H5T_NATIVE_INT_FAST64_g = FAIL;
+ H5T_NATIVE_UINT_FAST64_g = FAIL;
+
+ n++;
+ } /* end if */
+
+ /* Mark "top" of interface as closed */
+ if(0 == n)
+ H5T_top_package_initialize_s = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5T_top_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_term_package
+ *
+ * Purpose: Close this interface.
+ *
+ * Note: Finishes shutting down the interface, after
+ * H5T_top_term_package() is called
+ *
+ * Return: Success: Positive if any action might have caused a
+ * change in some other interface; zero
+ * otherwise.
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 20, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+ /* Sanity check */
+ HDassert(0 == H5I_nmembers(H5I_DATATYPE));
+ HDassert(FALSE == H5T_top_package_initialize_s);
+
+ /* Destroy the datatype object id group */
+ n += (H5I_dec_type_ref(H5I_DATATYPE) > 0);
+
+ /* Mark interface as closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5T_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcreate
+ *
+ * Purpose: Create a new type and initialize it to reasonable values.
+ * The type is a member of type class TYPE and is SIZE bytes.
+ *
+ * Return: Success: A new type identifier.
+ *
+ * Failure: Negative
+ *
+ * Errors:
+ * ARGS BADVALUE Invalid size.
+ * DATATYPE CANTINIT Can't create type.
+ * DATATYPE CANTREGISTER Can't register datatype atom.
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 5, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tcreate(H5T_class_t type, size_t size)
+{
+ H5T_t *dt = NULL; /* New datatype constructed */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "Ttz", type, size);
+
+ /* check args. We support string (fixed-size or variable-length) now. */
+ if(size <= 0 && size != H5T_VARIABLE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "size must be positive")
+
+ /* create the type */
+ if(NULL == (dt = H5T__create(type, size)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to create type")
+
+ /* Get an ID for the datatype */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype ID")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcreate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcopy
+ *
+ * Purpose: Copies a datatype. The resulting datatype is not locked.
+ * The datatype should be closed when no longer needed by
+ * calling H5Tclose().
+ *
+ * Return: Success: The ID of a new datatype.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 4 Jun 1998
+ * The returned type is always transient and unlocked. If the TYPE_ID
+ * argument is a dataset instead of a datatype then this function
+ * returns a transient, modifiable datatype which is a copy of the
+ * dataset's datatype.
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tcopy(hid_t type_id)
+{
+ H5T_t *dt; /* Pointer to the datatype to copy */
+ H5T_t *new_dt = NULL;
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", type_id);
+
+ switch(H5I_get_type(type_id)) {
+ case H5I_DATATYPE:
+ /* The argument is a datatype handle */
+ if(NULL == (dt = (H5T_t *)H5I_object(type_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ break;
+
+ case H5I_DATASET:
+ {
+ H5D_t *dset; /* Dataset for datatype */
+
+ /* The argument is a dataset handle */
+ if(NULL == (dset = (H5D_t *)H5I_object(type_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+ if(NULL == (dt = H5D_typeof(dset)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get the dataset datatype")
+ }
+ break;
+
+ case H5I_UNINIT:
+ case H5I_BADID:
+ case H5I_FILE:
+ case H5I_GROUP:
+ case H5I_DATASPACE:
+ case H5I_ATTR:
+ case H5I_REFERENCE:
+ case H5I_VFL:
+ case H5I_GENPROP_CLS:
+ case H5I_GENPROP_LST:
+ case H5I_ERROR_CLASS:
+ case H5I_ERROR_MSG:
+ case H5I_ERROR_STACK:
+ case H5I_NTYPES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype or dataset")
+ } /* end switch */
+
+ /* Copy datatype */
+ if(NULL == (new_dt = H5T_copy(dt, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy");
+
+ /* Atomize result */
+ if((ret_value = H5I_register(H5I_DATATYPE, new_dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype atom")
+
+done:
+ if(ret_value < 0)
+ if(new_dt && H5T_close(new_dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "unable to release datatype info")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcopy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tclose
+ *
+ * Purpose: Frees a datatype and all associated memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tclose(hid_t type_id)
+{
+ H5T_t *dt; /* Pointer to datatype to close */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_IMMUTABLE == dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "immutable datatype")
+
+ /* When the reference count reaches zero the resources are freed */
+ if(H5I_dec_app_ref(type_id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "problem freeing id")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tclose() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tequal
+ *
+ * Purpose: Determines if two datatypes are equal.
+ *
+ * Return: Success: TRUE if equal, FALSE if unequal
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 10, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tequal(hid_t type1_id, hid_t type2_id)
+{
+ const H5T_t *dt1; /* Pointer to first datatype */
+ const H5T_t *dt2; /* Pointer to second datatype */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "ii", type1_id, type2_id);
+
+ /* check args */
+ if(NULL == (dt1 = (H5T_t *)H5I_object_verify(type1_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(NULL == (dt2 = (H5T_t *)H5I_object_verify(type2_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ ret_value = (0 == H5T_cmp(dt1, dt2, FALSE)) ? TRUE : FALSE;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tequal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tlock
+ *
+ * Purpose: Locks a type, making it read only and non-destructable. This
+ * is normally done by the library for predefined datatypes so
+ * the application doesn't inadvertently change or delete a
+ * predefined type.
+ *
+ * Once a datatype is locked it can never be unlocked unless
+ * the entire library is closed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 1 Jun 1998
+ * It is illegal to lock a named datatype since we must allow named
+ * types to be closed (to release file resources) but locking a type
+ * prevents that.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tlock(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype to operate on */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_NAMED==dt->shared->state || H5T_STATE_OPEN==dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to lock named datatype")
+
+ if(H5T_lock(dt, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to lock transient datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tlock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_class
+ *
+ * Purpose: Returns the datatype class identifier for datatype TYPE_ID.
+ *
+ * Return: Success: One of the non-negative datatype class
+ * constants.
+ *
+ * Failure: H5T_NO_CLASS (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_class_t
+H5Tget_class(hid_t type_id)
+{
+ H5T_t *dt; /* Pointer to datatype */
+ H5T_class_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5T_NO_CLASS)
+ H5TRACE1("Tt", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NO_CLASS, "not a datatype")
+
+ /* Set return value */
+ ret_value = H5T_get_class(dt, FALSE);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_class
+ *
+ * Purpose: Returns the data type class identifier for a datatype ptr.
+ *
+ * Return: Success: One of the non-negative data type class
+ * constants.
+ *
+ * Failure: H5T_NO_CLASS (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ * Modifications:
+ * Broke out from H5Tget_class - QAK - 6/4/99
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_class_t
+H5T_get_class(const H5T_t *dt, htri_t internal)
+{
+ H5T_class_t ret_value = H5T_NO_CLASS; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5T_NO_CLASS)
+
+ HDassert(dt);
+
+ /* Externally, a VL string is a string; internally, a VL string is a VL. */
+ if(internal) {
+ ret_value=dt->shared->type;
+ } else {
+ if(H5T_IS_VL_STRING(dt->shared))
+ ret_value=H5T_STRING;
+ else
+ ret_value=dt->shared->type;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tdetect_class
+ *
+ * Purpose: Check whether a datatype contains (or is) a certain type of
+ * datatype.
+ *
+ * Return: TRUE (1) or FALSE (0) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, November 29, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tdetect_class(hid_t type, H5T_class_t cls)
+{
+ H5T_t *dt; /* Datatype to query */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "iTt", type, cls);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NO_CLASS, "not a datatype")
+ if(!(cls > H5T_NO_CLASS && cls < H5T_NCLASSES))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NO_CLASS, "not a datatype class")
+
+ /* Set return value */
+ if((ret_value = H5T_detect_class(dt, cls, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, H5T_NO_CLASS, "can't get datatype class")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tdetect_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_detect_class
+ *
+ * Purpose: Check whether a datatype contains (or is) a certain type of
+ * datatype.
+ *
+ * Return: TRUE (1) or FALSE (0) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, November 29, 2000
+ *
+ * Modifications:
+ * Raymond Lu
+ * 4 December 2009
+ * Added a flag as a parameter to indicate whether the caller is
+ * H5Tdetect_class. I also added the check for VL string type
+ * just like the public function. Because we want to tell users
+ * VL string is a string type but we treat it as a VL type
+ * internally, H5T_detect_class needs to know where the caller
+ * is from.
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_detect_class(const H5T_t *dt, H5T_class_t cls, hbool_t from_api)
+{
+ unsigned i;
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+ HDassert(cls > H5T_NO_CLASS && cls < H5T_NCLASSES);
+
+ /* Consider VL string as a string for API, as a VL for internal use. */
+ /* (note that this check must be performed before checking if the VL
+ * string belongs to the H5T_VLEN class, which would otherwise return
+ * true. -QAK)
+ */
+ if(from_api && H5T_IS_VL_STRING(dt->shared))
+ HGOTO_DONE(H5T_STRING == cls);
+
+ /* Check if this type is the correct type */
+ if(dt->shared->type == cls)
+ HGOTO_DONE(TRUE);
+
+ /* check for types that might have the correct type as a component */
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ htri_t nested_ret; /* Return value from nested call */
+
+ /* Check if this field's type is the correct type */
+ if(dt->shared->u.compnd.memb[i].type->shared->type == cls)
+ HGOTO_DONE(TRUE);
+
+ /* Recurse if it's VL, compound, enum or array */
+ if(H5T_IS_COMPLEX(dt->shared->u.compnd.memb[i].type->shared->type))
+ if((nested_ret = H5T_detect_class(dt->shared->u.compnd.memb[i].type, cls, from_api)) != FALSE)
+ HGOTO_DONE(nested_ret);
+ } /* end for */
+ break;
+
+ case H5T_ARRAY:
+ case H5T_VLEN:
+ case H5T_ENUM:
+ HGOTO_DONE(H5T_detect_class(dt->shared->parent, cls, from_api));
+ break;
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_NCLASSES:
+ default:
+ break;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_detect_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tis_variable_str
+ *
+ * Purpose: Check whether a datatype is a variable-length string
+ *
+ * Return: TRUE (1) or FALSE (0) on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * November 4, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tis_variable_str(hid_t dtype_id)
+{
+ H5T_t *dt; /* Datatype to query */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", dtype_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(dtype_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Set return value */
+ if((ret_value = H5T_is_variable_str(dt)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "can't determine if datatype is VL-string")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tis_variable_str() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_variable_str
+ *
+ * Purpose: Check whether a datatype is a variable-length string
+ *
+ * Return: TRUE (1) or FALSE (0) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_is_variable_str(const H5T_t *dt)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(H5T_IS_VL_STRING(dt->shared))
+} /* end H5T_is_variable_str() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_size
+ *
+ * Purpose: Determines the total size of a datatype in bytes.
+ *
+ * Return: Success: Size of the datatype in bytes. The size of
+ * datatype is the size of an instance of that
+ * datatype.
+ *
+ * Failure: 0 (valid datatypes are never zero size)
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5Tget_size(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype to query */
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE1("z", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype")
+
+ /* size */
+ ret_value = H5T_GET_SIZE(dt);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_size
+ *
+ * Purpose: Sets the total size in bytes for a datatype (this operation
+ * is not permitted on reference datatypes). If the size is
+ * decreased so that the significant bits of the datatype
+ * extend beyond the edge of the new size, then the `offset'
+ * property is decreased toward zero. If the `offset' becomes
+ * zero and the significant bits of the datatype still hang
+ * over the edge of the new size, then the number of significant
+ * bits is decreased.
+ *
+ * Adjusting the size of an H5T_STRING automatically sets the
+ * precision to 8*size.
+ *
+ * All datatypes have a positive size.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_size(hid_t type_id, size_t size)
+{
+ H5T_t *dt; /* Datatype to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", type_id, size);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "datatype is read-only")
+ if(size <= 0 && size != H5T_VARIABLE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "size must be positive")
+ if(size == H5T_VARIABLE && !H5T_IS_STRING(dt->shared))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "only strings may be variable length")
+ if(H5T_ENUM == dt->shared->type && dt->shared->u.enumer.nmembs > 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not allowed after members are defined")
+ if(H5T_REFERENCE == dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not defined for this datatype")
+
+ /* Modify the datatype */
+ if(H5T_set_size(dt, size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to set size for datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_super
+ *
+ * Purpose: Returns the type from which TYPE is derived. In the case of
+ * an enumeration type the return value is an integer type.
+ *
+ * Return: Success: Type ID for base datatype.
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tget_super(hid_t type)
+{
+ H5T_t *dt; /* Datatype to query */
+ H5T_t *super = NULL; /* Supertype */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", type);
+
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(NULL == (super = H5T_get_super(dt)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "not a datatype")
+ if((ret_value = H5I_register(H5I_DATATYPE, super, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register parent datatype")
+
+done:
+ if(ret_value < 0)
+ if(super && H5T_close(super) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "unable to release super datatype info")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_super() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_super
+ *
+ * Purpose: Private function for H5Tget_super. Returns the type from
+ * which TYPE is derived. In the case of an enumeration type
+ * the return value is an integer type.
+ *
+ * Return: Success: Data type for base data type.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * October 9, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T_get_super(const H5T_t *dt)
+{
+ H5T_t *ret_value=NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(dt);
+
+ if (!dt->shared->parent)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "not a derived data type");
+ if (NULL==(ret_value=H5T_copy(dt->shared->parent, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy parent data type");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_register
+ *
+ * Purpose: Register a hard or soft conversion function for a data type
+ * conversion path. The path is specified by the source and
+ * destination data types SRC_ID and DST_ID (for soft functions
+ * only the class of these types is important). If FUNC is a
+ * hard function then it replaces any previous path; if it's a
+ * soft function then it replaces all existing paths to which it
+ * applies and is used for any new path to which it applies as
+ * long as that path doesn't have a hard function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_register(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst,
+ H5T_conv_t func, hid_t dxpl_id, hbool_t api_call)
+{
+ hid_t tmp_sid=-1, tmp_did=-1;/*temporary data type IDs */
+ H5T_path_t *old_path=NULL; /*existing conversion path */
+ H5T_path_t *new_path=NULL; /*new conversion path */
+ H5T_cdata_t cdata; /*temporary conversion data */
+ int nprint=0; /*number of paths shut down */
+ int i; /*counter */
+ herr_t ret_value=SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(src);
+ HDassert(dst);
+ HDassert(func);
+ HDassert(H5T_PERS_HARD==pers || H5T_PERS_SOFT==pers);
+ HDassert(name && *name);
+
+ if(H5T_PERS_HARD == pers) {
+ /* Only bother to register the path if it's not a no-op path (for this machine) */
+ if(H5T_cmp(src, dst, FALSE)) {
+ /* Locate or create a new conversion path */
+ if(NULL == (new_path = H5T_path_find(src, dst, name, func, dxpl_id, api_call)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to locate/allocate conversion path")
+
+ /*
+ * Notify all other functions to recalculate private data since some
+ * functions might cache a list of conversion functions. For
+ * instance, the compound type converter caches a list of conversion
+ * functions for the members, so adding a new function should cause
+ * the list to be recalculated to use the new function.
+ */
+ for(i = 0; i < H5T_g.npaths; i++)
+ if(new_path != H5T_g.path[i])
+ H5T_g.path[i]->cdata.recalc = TRUE;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Add function to end of soft list */
+ if((size_t)H5T_g.nsoft >= H5T_g.asoft) {
+ size_t na = MAX(32, 2 * H5T_g.asoft);
+ H5T_soft_t *x;
+
+ if(NULL == (x = (H5T_soft_t *)H5MM_realloc(H5T_g.soft, na * sizeof(H5T_soft_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ H5T_g.asoft = na;
+ H5T_g.soft = x;
+ } /* end if */
+ HDstrncpy(H5T_g.soft[H5T_g.nsoft].name, name, (size_t)H5T_NAMELEN);
+ H5T_g.soft[H5T_g.nsoft].name[H5T_NAMELEN - 1] = '\0';
+ H5T_g.soft[H5T_g.nsoft].src = src->shared->type;
+ H5T_g.soft[H5T_g.nsoft].dst = dst->shared->type;
+ H5T_g.soft[H5T_g.nsoft].func = func;
+ H5T_g.nsoft++;
+
+ /*
+ * Any existing path (except the no-op path) to which this new soft
+ * conversion function applies should be replaced by a new path that
+ * uses this function.
+ */
+ for (i=1; i<H5T_g.npaths; i++) {
+ old_path = H5T_g.path[i];
+ HDassert(old_path);
+
+ /* Does the new soft conversion function apply to this path? */
+ if (old_path->is_hard ||
+ old_path->src->shared->type!=src->shared->type ||
+ old_path->dst->shared->type!=dst->shared->type) {
+ continue;
+ }
+ if((tmp_sid = H5I_register(H5I_DATATYPE, H5T_copy(old_path->src, H5T_COPY_ALL), FALSE)) < 0 ||
+ (tmp_did = H5I_register(H5I_DATATYPE, H5T_copy(old_path->dst, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register data types for conv query")
+ HDmemset(&cdata, 0, sizeof cdata);
+ cdata.command = H5T_CONV_INIT;
+ if((func)(tmp_sid, tmp_did, &cdata, (size_t)0, (size_t)0, (size_t)0,
+ NULL, NULL, dxpl_id) < 0) {
+ H5I_dec_ref(tmp_sid);
+ H5I_dec_ref(tmp_did);
+ tmp_sid = tmp_did = -1;
+ H5E_clear_stack(NULL);
+ continue;
+ } /* end if */
+
+ /* Create a new conversion path */
+ if(NULL == (new_path = H5FL_CALLOC(H5T_path_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ HDstrncpy(new_path->name, name, (size_t)H5T_NAMELEN);
+ new_path->name[H5T_NAMELEN - 1] = '\0';
+ if(NULL == (new_path->src = H5T_copy(old_path->src, H5T_COPY_ALL)) ||
+ NULL == (new_path->dst=H5T_copy(old_path->dst, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy data types")
+ new_path->func = func;
+ new_path->is_hard = FALSE;
+ new_path->cdata = cdata;
+
+ /* Replace previous path */
+ H5T_g.path[i] = new_path;
+ new_path = NULL; /*so we don't free it on error*/
+
+ /* Free old path */
+ H5T__print_stats(old_path, &nprint);
+ old_path->cdata.command = H5T_CONV_FREE;
+ if ((old_path->func)(tmp_sid, tmp_did, &(old_path->cdata),
+ (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id)<0) {
+#ifdef H5T_DEBUG
+ if (H5DEBUG(T)) {
+ fprintf (H5DEBUG(T), "H5T: conversion function 0x%08lx "
+ "failed to free private data for %s (ignored)\n",
+ (unsigned long)(old_path->func), old_path->name);
+ }
+#endif
+ } /* end if */
+ H5T_close(old_path->src);
+ H5T_close(old_path->dst);
+ old_path = H5FL_FREE(H5T_path_t, old_path);
+
+ /* Release temporary atoms */
+ H5I_dec_ref(tmp_sid);
+ H5I_dec_ref(tmp_did);
+ tmp_sid = tmp_did = -1;
+
+ /* We don't care about any failures during the freeing process */
+ H5E_clear_stack(NULL);
+ } /* end for */
+ } /* end else */
+
+done:
+ if(ret_value < 0) {
+ if(new_path) {
+ if(new_path->src)
+ H5T_close(new_path->src);
+ if(new_path->dst)
+ H5T_close(new_path->dst);
+ new_path = H5FL_FREE(H5T_path_t, new_path);
+ } /* end if */
+ if(tmp_sid >= 0)
+ H5I_dec_ref(tmp_sid);
+ if(tmp_did >= 0)
+ H5I_dec_ref(tmp_did);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_register() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tregister
+ *
+ * Purpose: Register a hard or soft conversion function for a data type
+ * conversion path. The path is specified by the source and
+ * destination data types SRC_ID and DST_ID (for soft functions
+ * only the class of these types is important). If FUNC is a
+ * hard function then it replaces any previous path; if it's a
+ * soft function then it replaces all existing paths to which it
+ * applies and is used for any new path to which it applies as
+ * long as that path doesn't have a hard function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tregister(H5T_pers_t pers, const char *name, hid_t src_id, hid_t dst_id,
+ H5T_conv_t func)
+{
+ H5T_t *src; /*source data type descriptor */
+ H5T_t *dst; /*destination data type desc */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "Te*siix", pers, name, src_id, dst_id, func);
+
+ /* Check args */
+ if(H5T_PERS_HARD != pers && H5T_PERS_SOFT != pers)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid function persistence")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "conversion must have a name for debugging")
+ if(NULL == (src = (H5T_t *)H5I_object_verify(src_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(NULL == (dst = (H5T_t *)H5I_object_verify(dst_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(!func)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no conversion function specified")
+
+ /* Go register the function */
+ if(H5T_register(pers, name, src, dst, func, H5AC_noio_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't register conversion function")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_unregister
+ *
+ * Purpose: Removes conversion paths that match the specified criteria.
+ * All arguments are optional. Missing arguments are wild cards.
+ * The special no-op path cannot be removed.
+ *
+ * Return: Succeess: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 13, 1998
+ *
+ * Modifications:
+ * Adapted to non-API function - QAK, 11/17/99
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_unregister(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst,
+ H5T_conv_t func, hid_t dxpl_id)
+{
+ H5T_path_t *path = NULL; /*conversion path */
+ H5T_soft_t *soft = NULL; /*soft conversion information */
+ int nprint = 0; /*number of paths shut down */
+ int i; /*counter */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Remove matching entries from the soft list */
+ if(H5T_PERS_DONTCARE == pers || H5T_PERS_SOFT == pers) {
+ for(i = H5T_g.nsoft - 1; i >= 0; --i) {
+ soft = H5T_g.soft + i;
+ HDassert(soft);
+ if(name && *name && HDstrcmp(name, soft->name))
+ continue;
+ if(src && src->shared->type != soft->src)
+ continue;
+ if(dst && dst->shared->type != soft->dst)
+ continue;
+ if(func && func != soft->func)
+ continue;
+
+ HDmemmove(H5T_g.soft + i, H5T_g.soft + i + 1, (size_t)(H5T_g.nsoft - (i + 1)) * sizeof(H5T_soft_t));
+ --H5T_g.nsoft;
+ } /* end for */
+ } /* end if */
+
+ /* Remove matching conversion paths, except no-op path */
+ for(i = H5T_g.npaths - 1; i > 0; --i) {
+ path = H5T_g.path[i];
+ HDassert(path);
+
+ /* Not a match */
+ if(((H5T_PERS_SOFT == pers && path->is_hard) ||
+ (H5T_PERS_HARD == pers && !path->is_hard)) ||
+ (name && *name && HDstrcmp(name, path->name)) ||
+ (src && H5T_cmp(src, path->src, FALSE)) ||
+ (dst && H5T_cmp(dst, path->dst, FALSE)) ||
+ (func && func!=path->func)) {
+ /*
+ * Notify all other functions to recalculate private data since some
+ * functions might cache a list of conversion functions. For
+ * instance, the compound type converter caches a list of conversion
+ * functions for the members, so removing a function should cause
+ * the list to be recalculated to avoid the removed function.
+ */
+ path->cdata.recalc = TRUE;
+ } /* end if */
+ else {
+ /* Remove from table */
+ HDmemmove(H5T_g.path + i, H5T_g.path + i + 1, (size_t)(H5T_g.npaths - (i + 1)) * sizeof(H5T_path_t*));
+ --H5T_g.npaths;
+
+ /* Shut down path */
+ H5T__print_stats(path, &nprint);
+ path->cdata.command = H5T_CONV_FREE;
+ if((path->func)((hid_t)FAIL, (hid_t)FAIL, &(path->cdata),
+ (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id) < 0) {
+#ifdef H5T_DEBUG
+ if(H5DEBUG(T)) {
+ fprintf(H5DEBUG(T), "H5T: conversion function 0x%08lx failed "
+ "to free private data for %s (ignored)\n",
+ (unsigned long)(path->func), path->name);
+ }
+#endif
+ }
+ H5T_close(path->src);
+ H5T_close(path->dst);
+ path = H5FL_FREE(H5T_path_t, path);
+ H5E_clear_stack(NULL); /*ignore all shutdown errors*/
+ } /* end else */
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_unregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tunregister
+ *
+ * Purpose: Removes conversion paths that match the specified criteria.
+ * All arguments are optional. Missing arguments are wild cards.
+ * The special no-op path cannot be removed.
+ *
+ * Return: Succeess: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tunregister(H5T_pers_t pers, const char *name, hid_t src_id, hid_t dst_id,
+ H5T_conv_t func)
+{
+ H5T_t *src = NULL, *dst = NULL; /* Datatype descriptors */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "Te*siix", pers, name, src_id, dst_id, func);
+
+ /* Check arguments */
+ if(src_id > 0 && (NULL == (src = (H5T_t *)H5I_object_verify(src_id, H5I_DATATYPE))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "src is not a data type")
+ if(dst_id > 0 && (NULL == (dst = (H5T_t *)H5I_object_verify(dst_id, H5I_DATATYPE))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dst is not a data type")
+
+ if(H5T_unregister(pers, name, src, dst, func, H5AC_noio_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDELETE, FAIL, "internal unregister function failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tunregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tfind
+ *
+ * Purpose: Finds a conversion function that can handle a conversion from
+ * type SRC_ID to type DST_ID. The PCDATA argument is a pointer
+ * to a pointer to type conversion data which was created and
+ * initialized by the type conversion function of this path
+ * when the conversion function was installed on the path.
+ *
+ * Return: Success: A pointer to a suitable conversion function.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 13, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_conv_t
+H5Tfind(hid_t src_id, hid_t dst_id, H5T_cdata_t **pcdata)
+{
+ H5T_t *src, *dst;
+ H5T_path_t *path;
+ H5T_conv_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE3("x", "ii**x", src_id, dst_id, pcdata);
+
+ /* Check args */
+ if(NULL == (src = (H5T_t *)H5I_object_verify(src_id, H5I_DATATYPE)) ||
+ NULL == (dst = (H5T_t *)H5I_object_verify(dst_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+ if(!pcdata)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "no address to receive cdata pointer")
+
+ /* Find it */
+ if(NULL == (path = H5T_path_find(src, dst, NULL, NULL, H5AC_noio_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "conversion function not found")
+
+ if(pcdata)
+ *pcdata = &(path->cdata);
+
+ /* Set return value */
+ ret_value = path->func;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tfind() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcompiler_conv
+ *
+ * Purpose: Finds out whether the library's conversion function from
+ * type src_id to type dst_id is a compiler (hard) conversion.
+ * A hard conversion uses compiler's casting; a soft conversion
+ * uses the library's own conversion function.
+ *
+ * Return: TRUE: hard conversion.
+ * FALSE: soft conversion.
+ * FAIL: failed.
+ *
+ * Programmer: Raymond Lu
+ * Friday, Sept 2, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tcompiler_conv(hid_t src_id, hid_t dst_id)
+{
+ H5T_t *src, *dst;
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("t", "ii", src_id, dst_id);
+
+ /* Check args */
+ if(NULL == (src = (H5T_t *)H5I_object_verify(src_id, H5I_DATATYPE)) ||
+ NULL == (dst = (H5T_t *)H5I_object_verify(dst_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+
+ /* Find it */
+ if((ret_value = H5T_compiler_conv(src, dst)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "conversion function not found")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcompiler_conv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tconvert
+ *
+ * Purpose: Convert NELMTS elements from type SRC_ID to type DST_ID. The
+ * source elements are packed in BUF and on return the
+ * destination will be packed in BUF. That is, the conversion
+ * is performed in place. The optional background buffer is an
+ * array of NELMTS values of destination type which are merged
+ * with the converted values to fill in cracks (for instance,
+ * BACKGROUND might be an array of structs with the `a' and `b'
+ * fields already initialized and the conversion of BUF supplies
+ * the `c' and `d' field values). The PLIST_ID a dataset transfer
+ * property list which is passed to the conversion functions. (It's
+ * currently only used to pass along the VL datatype custom allocation
+ * information -QAK 7/1/99)
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 10, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tconvert(hid_t src_id, hid_t dst_id, size_t nelmts, void *buf,
+ void *background, hid_t dxpl_id)
+{
+ H5T_path_t *tpath; /*type conversion info */
+ H5T_t *src, *dst; /*unatomized types */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "iiz*x*xi", src_id, dst_id, nelmts, buf, background, dxpl_id);
+
+ /* Check args */
+ if(NULL == (src = (H5T_t *)H5I_object_verify(src_id, H5I_DATATYPE)) ||
+ NULL == (dst = (H5T_t *)H5I_object_verify(dst_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(H5P_DEFAULT == dxpl_id)
+ dxpl_id = H5P_DATASET_XFER_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not dataset transfer property list")
+
+ /* Find the conversion function */
+ if(NULL == (tpath = H5T_path_find(src, dst, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and dst data types")
+
+ if(H5T_convert(tpath, src_id, dst_id, nelmts, (size_t)0, (size_t)0, buf, background, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "data type conversion failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tconvert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tencode
+ *
+ * Purpose: Given an datatype ID, converts the object description into
+ * binary in a buffer.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tencode(hid_t obj_id, void *buf, size_t *nalloc)
+{
+ H5T_t *dtype;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x*z", obj_id, buf, nalloc);
+
+ /* Check argument and retrieve object */
+ if(NULL == (dtype = (H5T_t *)H5I_object_verify(obj_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(nalloc == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL pointer for buffer size")
+
+ /* Go encode the datatype */
+ if(H5T_encode(dtype, (unsigned char *)buf, nalloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tencode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tdecode
+ *
+ * Purpose: Decode a binary object description and return a new object
+ * handle.
+ *
+ * Return: Success: datatype ID(non-negative)
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ * Modification:Raymond Lu
+ * songyulu@hdfgroup.org
+ * 17 February 2011
+ * I changed the value for the APP_REF parameter of H5I_register
+ * from FALSE to TRUE.
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tdecode(const void *buf)
+{
+ H5T_t *dt;
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "*x", buf);
+
+ /* Check args */
+ if(buf == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "empty buffer")
+
+ /* Create datatype by decoding buffer */
+ if(NULL == (dt = H5T_decode((const unsigned char *)buf)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "can't decode object")
+
+ /* Register the type and return the ID */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register data type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tdecode() */
+
+/*-------------------------------------------------------------------------
+ * API functions are above; library-private functions are below...
+ *-------------------------------------------------------------------------
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_encode
+ *
+ * Purpose: Private function for H5Tencode. Converts an object
+ * description into binary in a buffer.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_encode(H5T_t *obj, unsigned char *buf, size_t *nalloc)
+{
+ size_t buf_size; /* Encoded size of datatype */
+ H5F_t *f = NULL; /* Fake file structure*/
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate "fake" file structure */
+ if(NULL == (f = H5F_fake_alloc((uint8_t)0)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "can't allocate fake file struct")
+
+ /* Find out the size of buffer needed */
+ if((buf_size = H5O_msg_raw_size(f, H5O_DTYPE_ID, TRUE, obj)) == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "can't find datatype size")
+
+ /* Don't encode if buffer size isn't big enough or buffer is empty */
+ if(!buf || *nalloc < (buf_size + 1 + 1))
+ *nalloc = buf_size + 1 + 1;
+ else {
+ /* Encode the type of the information */
+ *buf++ = H5O_DTYPE_ID;
+
+ /* Encode the version of the dataspace information */
+ *buf++ = H5T_ENCODE_VERSION;
+
+ /* Encode into user's buffer */
+ if(H5O_msg_encode(f, H5O_DTYPE_ID, TRUE, buf, obj) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTENCODE, FAIL, "can't encode object")
+ } /* end else */
+
+done:
+ /* Release fake file structure */
+ if(f && H5F_fake_free(f) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "unable to release fake file struct")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_decode
+ *
+ * Purpose: Private function for H5Tdecode. Reconstructs a binary
+ * description of datatype and returns a new object handle.
+ *
+ * Return: Success: datatype ID(non-negative)
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * July 14, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T_decode(const unsigned char *buf)
+{
+ H5F_t *f = NULL; /* Fake file structure*/
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate "fake" file structure */
+ if(NULL == (f = H5F_fake_alloc((uint8_t)0)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, NULL, "can't allocate fake file struct")
+
+ /* Decode the type of the information */
+ if(*buf++ != H5O_DTYPE_ID)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADMESG, NULL, "not an encoded datatype")
+
+ /* Decode the version of the datatype information */
+ if(*buf++ != H5T_ENCODE_VERSION)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_VERSION, NULL, "unknown version of encoded datatype")
+
+ /* Decode the serialized datatype message */
+ if(NULL == (ret_value = (H5T_t *)H5O_msg_decode(f, H5AC_noio_dxpl_id, NULL, H5O_DTYPE_ID, buf)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, NULL, "can't decode object")
+
+ /* Mark datatype as being in memory now */
+ if(H5T_set_loc(ret_value, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+done:
+ /* Release fake file structure */
+ if(f && H5F_fake_free(f) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, NULL, "unable to release fake file struct")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__create
+ *
+ * Purpose: Creates a new data type and initializes it to reasonable
+ * values. The new data type is SIZE bytes and an instance of
+ * the class TYPE.
+ *
+ * Return: Success: Pointer to the new type.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 5, 1997
+ *
+ * Modifications:
+ * Raymond Lu
+ * 19 May 2011
+ * We support fixed size or variable-length string now.
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T__create(H5T_class_t type, size_t size)
+{
+ H5T_t *dt = NULL;
+ H5T_t *ret_value = NULL;
+
+ FUNC_ENTER_PACKAGE
+
+ switch(type) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ {
+ H5T_t *origin_dt = NULL;
+
+ if(NULL == (origin_dt = (H5T_t *)H5I_object(H5T_C_S1)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, NULL, "can't get structure for string type")
+
+ /* Copy the default string datatype */
+ if(NULL == (dt = H5T_copy(origin_dt, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy");
+
+ /* Modify the datatype */
+ if(H5T_set_size(dt, size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to set size for string type")
+ }
+ break;
+
+ case H5T_BITFIELD:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, NULL, "type class is not appropriate - use H5Tcopy()")
+
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ if(NULL == (dt = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ dt->shared->type = type;
+
+ if(type == H5T_COMPOUND) {
+ dt->shared->u.compnd.packed=FALSE; /* Start out unpacked */
+ dt->shared->u.compnd.memb_size=0;
+ } /* end if */
+ else if(type == H5T_OPAQUE)
+ /* Initialize the tag in case it's not set later. A null tag will
+ * cause problems for later operations. */
+ dt->shared->u.opaque.tag = H5MM_strdup("");
+ break;
+
+ case H5T_ENUM:
+ {
+ hid_t subtype;
+ H5T_t *sub_t_obj;
+
+ if(sizeof(char) == size)
+ subtype = H5T_NATIVE_SCHAR_g;
+ else if(sizeof(short) == size)
+ subtype = H5T_NATIVE_SHORT_g;
+ else if(sizeof(int) == size)
+ subtype = H5T_NATIVE_INT_g;
+ else if(sizeof(long) == size)
+ subtype = H5T_NATIVE_LONG_g;
+#if H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG
+ else if(sizeof(long long) == size)
+ subtype = H5T_NATIVE_LLONG_g;
+#endif /* H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG */
+ else
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "no applicable native integer type")
+ if(NULL == (dt = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ dt->shared->type = type;
+ if(NULL == (sub_t_obj = (H5T_t *)H5I_object(subtype)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, NULL, "unable to get datatype object")
+ if(NULL == (dt->shared->parent = H5T_copy(sub_t_obj, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "unable to copy base datatype")
+ }
+ break;
+
+ case H5T_VLEN: /* Variable length datatype */
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, NULL, "base type required - use H5Tvlen_create()")
+
+ case H5T_ARRAY: /* Array datatype */
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, NULL, "base type required - use H5Tarray_create2()")
+
+ case H5T_NO_CLASS:
+ case H5T_REFERENCE:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, NULL, "unknown data type class")
+ } /* end switch */
+
+ /* Set the size except VL string */
+ if(H5T_STRING != type || H5T_VARIABLE != size)
+ dt->shared->size = size;
+
+ /* Set return value */
+ ret_value = dt;
+
+done:
+ if(NULL == ret_value) {
+ if(dt) {
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+ dt = H5FL_FREE(H5T_t, dt);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_copy
+ *
+ * Purpose: Copies datatype OLD_DT. The resulting data type is not
+ * locked and is a transient type.
+ *
+ * Return: Success: Pointer to a new copy of the OLD_DT argument.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, December 4, 1997
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 4 Jun 1998
+ * Added the METHOD argument. If it's H5T_COPY_TRANSIENT then the
+ * result will be an unlocked transient type. Otherwise if it's
+ * H5T_COPY_ALL then the result is a named type if the original is a
+ * named type, but the result is not opened. Finally, if it's
+ * H5T_COPY_REOPEN and the original type is a named type then the result
+ * is a named type and the type object header is opened again. The
+ * H5T_COPY_REOPEN method is used when returning a named type to the
+ * application.
+ *
+ * Robb Matzke, 22 Dec 1998
+ * Now able to copy enumeration data types.
+ *
+ * Robb Matzke, 20 May 1999
+ * Now able to copy opaque types.
+ *
+ * Pedro Vicente, <pvn@ncsa.uiuc.edu> 21 Sep 2002
+ * Added a deep copy of the symbol table entry
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T_copy(H5T_t *old_dt, H5T_copy_t method)
+{
+ H5T_t *new_dt = NULL, *tmp = NULL;
+ H5T_shared_t *reopened_fo = NULL;
+ unsigned i;
+ char *s;
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* check args */
+ HDassert(old_dt);
+
+ /* Allocate space */
+ if(NULL == (new_dt = H5FL_MALLOC(H5T_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+ if(NULL == (new_dt->shared = H5FL_MALLOC(H5T_shared_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+
+ /* Copy shared information (entry information is copied last) */
+ *(new_dt->shared) = *(old_dt->shared);
+
+ /* Check what sort of copy we are making */
+ switch (method) {
+ case H5T_COPY_TRANSIENT:
+ /*
+ * Return an unlocked transient type.
+ */
+ new_dt->shared->state = H5T_STATE_TRANSIENT;
+ break;
+
+ case H5T_COPY_ALL:
+ /*
+ * Return a transient type (locked or unlocked) or an unopened named
+ * type. Immutable transient types are degraded to read-only.
+ */
+ if(H5T_STATE_OPEN==old_dt->shared->state)
+ new_dt->shared->state = H5T_STATE_NAMED;
+ else if(H5T_STATE_IMMUTABLE==old_dt->shared->state)
+ new_dt->shared->state = H5T_STATE_RDONLY;
+ break;
+
+ case H5T_COPY_REOPEN:
+ /*
+ * Return a transient type (locked or unlocked) or an opened named
+ * type. Immutable transient types are degraded to read-only.
+ */
+ if(old_dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED) {
+ /* Check if the object is already open */
+ if(NULL == (reopened_fo = (H5T_shared_t *)H5FO_opened(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr))) {
+ /* Clear any errors from H5FO_opened() */
+ H5E_clear_stack(NULL);
+
+ /* Open named datatype again */
+ if(H5O_open(&old_dt->oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to reopen named data type");
+
+ /* Insert opened named datatype into opened object list for the file */
+ if(H5FO_insert(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr, new_dt->shared, FALSE)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, NULL, "can't insert datatype into list of open objects")
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINC, NULL, "can't increment object count")
+
+ new_dt->shared->fo_count = 1;
+ } /* end if */
+ else {
+ /* The object is already open. Free the H5T_shared_t struct
+ * we had been using and use the one that already exists.
+ * Not terribly efficient. */
+ new_dt->shared = H5FL_FREE(H5T_shared_t, new_dt->shared);
+ new_dt->shared = reopened_fo;
+
+ reopened_fo->fo_count++;
+
+ /* Check if the object has been opened through the top file yet */
+ if(H5FO_top_count(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr) == 0) {
+ /* Open the object through this top file */
+ if(H5O_open(&old_dt->oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to open object header")
+ } /* end if */
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINC, NULL, "can't increment object count")
+ } /* end else */
+ new_dt->shared->state = H5T_STATE_OPEN;
+ } else if(H5T_STATE_IMMUTABLE == old_dt->shared->state) {
+ new_dt->shared->state = H5T_STATE_RDONLY;
+ }
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, NULL, "invalid copy method type")
+ } /* end switch */
+
+ /* Update fields in the new struct, if we aren't sharing an already opened
+ * committed datatype */
+ if(!reopened_fo) {
+ /* Copy parent information */
+ if(old_dt->shared->parent)
+ new_dt->shared->parent = H5T_copy(old_dt->shared->parent, method);
+
+ switch(new_dt->shared->type) {
+ case H5T_COMPOUND:
+ {
+ ssize_t accum_change = 0; /* Amount of change in the offset of the fields */
+
+ /*
+ * Copy all member fields to new type, then overwrite the
+ * name and type fields of each new member with copied values.
+ * That is, H5T_copy() is a deep copy.
+ */
+ /* Only malloc if space has been allocated for members - NAF */
+ if(new_dt->shared->u.compnd.nalloc > 0) {
+ new_dt->shared->u.compnd.memb = (H5T_cmemb_t *)H5MM_malloc(new_dt->shared->u.compnd.nalloc *
+ sizeof(H5T_cmemb_t));
+ if (NULL==new_dt->shared->u.compnd.memb)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+
+ HDmemcpy(new_dt->shared->u.compnd.memb, old_dt->shared->u.compnd.memb,
+ new_dt->shared->u.compnd.nmembs * sizeof(H5T_cmemb_t));
+ } /* end if */
+
+ for(i = 0; i < new_dt->shared->u.compnd.nmembs; i++) {
+ unsigned j;
+ int old_match;
+
+ s = new_dt->shared->u.compnd.memb[i].name;
+ new_dt->shared->u.compnd.memb[i].name = H5MM_xstrdup(s);
+ tmp = H5T_copy (old_dt->shared->u.compnd.memb[i].type, method);
+ new_dt->shared->u.compnd.memb[i].type = tmp;
+ HDassert(tmp != NULL);
+
+ /* Range check against compound member's offset */
+ if ((accum_change < 0) && ((ssize_t) new_dt->shared->u.compnd.memb[i].offset < accum_change))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, NULL, "invalid field size in datatype");
+
+ /* Apply the accumulated size change to the offset of the field */
+ new_dt->shared->u.compnd.memb[i].offset += (size_t) accum_change;
+
+ if(old_dt->shared->u.compnd.sorted != H5T_SORT_VALUE) {
+ for(old_match = -1, j = 0; j < old_dt->shared->u.compnd.nmembs; j++) {
+ if(!HDstrcmp(new_dt->shared->u.compnd.memb[i].name, old_dt->shared->u.compnd.memb[j].name)) {
+ old_match = (int) j;
+ break;
+ } /* end if */
+ } /* end for */
+
+ /* check if we couldn't find a match */
+ if(old_match < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "fields in datatype corrupted");
+ } /* end if */
+ else
+ old_match = (int) i;
+
+ /* If the field changed size, add that change to the accumulated size change */
+ if(new_dt->shared->u.compnd.memb[i].type->shared->size != old_dt->shared->u.compnd.memb[old_match].type->shared->size) {
+ /* Adjust the size of the member */
+ new_dt->shared->u.compnd.memb[i].size = (old_dt->shared->u.compnd.memb[old_match].size*tmp->shared->size)/old_dt->shared->u.compnd.memb[old_match].type->shared->size;
+
+ accum_change += (ssize_t) (new_dt->shared->u.compnd.memb[i].type->shared->size - old_dt->shared->u.compnd.memb[old_match].type->shared->size);
+ } /* end if */
+ } /* end for */
+
+ /* Range check against datatype size */
+ if ((accum_change < 0) && ((ssize_t) new_dt->shared->size < accum_change))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, NULL, "invalid field size in datatype");
+
+ /* Apply the accumulated size change to the size of the compound struct */
+ new_dt->shared->size += (size_t) accum_change;
+ }
+ break;
+
+ case H5T_ENUM:
+ /*
+ * Copy all member fields to new type, then overwrite the name fields
+ * of each new member with copied values. That is, H5T_copy() is a
+ * deep copy.
+ */
+ new_dt->shared->u.enumer.name = (char **)H5MM_malloc(new_dt->shared->u.enumer.nalloc *
+ sizeof(char*));
+ new_dt->shared->u.enumer.value = (uint8_t *)H5MM_malloc(new_dt->shared->u.enumer.nalloc *
+ new_dt->shared->size);
+ if(NULL == new_dt->shared->u.enumer.value)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+ HDmemcpy(new_dt->shared->u.enumer.value, old_dt->shared->u.enumer.value,
+ new_dt->shared->u.enumer.nmembs * new_dt->shared->size);
+ for(i = 0; i < new_dt->shared->u.enumer.nmembs; i++) {
+ s = old_dt->shared->u.enumer.name[i];
+ new_dt->shared->u.enumer.name[i] = H5MM_xstrdup(s);
+ } /* end for */
+ break;
+
+ case H5T_VLEN:
+ case H5T_REFERENCE:
+ if(method == H5T_COPY_TRANSIENT || method == H5T_COPY_REOPEN) {
+ /* H5T_copy converts any type into a memory type */
+ if(H5T_set_loc(new_dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location");
+ } /* end if */
+ break;
+
+ case H5T_OPAQUE:
+ /*
+ * Copy the tag name.
+ */
+ new_dt->shared->u.opaque.tag = H5MM_xstrdup(new_dt->shared->u.opaque.tag);
+ break;
+
+ case H5T_ARRAY:
+ /* Re-compute the array's size, in case it's base type changed size */
+ new_dt->shared->size=new_dt->shared->u.array.nelem*new_dt->shared->parent->shared->size;
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_NCLASSES:
+ default:
+ break;
+ } /* end switch */
+ } /* end if */
+
+ /* Set the cached location & name path if the original type was a named
+ * type and the new type is also named.
+ */
+ if(H5O_loc_reset(&new_dt->oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, NULL, "unable to initialize location")
+ if(H5G_name_reset(&new_dt->path) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to reset path")
+
+ if(new_dt->shared->state == H5T_STATE_NAMED || new_dt->shared->state == H5T_STATE_OPEN) {
+ if(H5O_loc_copy(&(new_dt->oloc), &(old_dt->oloc), H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy object location")
+ if(H5G_name_copy(&(new_dt->path), &(old_dt->path), H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to copy path")
+ } /* end if */
+
+ /* Copy shared location information if the new type is named or if it is
+ * shared in the heap.
+ */
+ if((old_dt->sh_loc.type == H5O_SHARE_TYPE_SOHM || old_dt->sh_loc.type == H5O_SHARE_TYPE_HERE) ||
+ new_dt->shared->state == H5T_STATE_NAMED || new_dt->shared->state == H5T_STATE_OPEN) {
+ if(H5O_set_shared(&(new_dt->sh_loc), &(old_dt->sh_loc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy shared information")
+ } /* end if */
+ else
+ /* Reset shared component info */
+ H5O_msg_reset_share(H5O_DTYPE_ID, new_dt);
+
+ /* Set return value */
+ ret_value = new_dt;
+
+done:
+ if(ret_value == NULL) {
+ if(new_dt) {
+ if(new_dt->shared)
+ new_dt->shared = H5FL_FREE(H5T_shared_t, new_dt->shared);
+ new_dt = H5FL_FREE(H5T_t, new_dt);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_lock
+ *
+ * Purpose: Lock a transient data type making it read-only. If IMMUTABLE
+ * is set then the type cannot be closed except when the library
+ * itself closes.
+ *
+ * This function is a no-op if the type is not transient or if
+ * the type is already read-only or immutable.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_lock (H5T_t *dt, hbool_t immutable)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert (dt);
+
+ switch (dt->shared->state) {
+ case H5T_STATE_TRANSIENT:
+ dt->shared->state = immutable ? H5T_STATE_IMMUTABLE : H5T_STATE_RDONLY;
+ break;
+ case H5T_STATE_RDONLY:
+ if (immutable) dt->shared->state = H5T_STATE_IMMUTABLE;
+ break;
+ case H5T_STATE_IMMUTABLE:
+ case H5T_STATE_NAMED:
+ case H5T_STATE_OPEN:
+ /*void*/
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "invalid datatype state")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__alloc
+ *
+ * Purpose: Allocates a new H5T_t structure, initializing it correctly.
+ *
+ * Return: Pointer to new H5T_t on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 29, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T__alloc(void)
+{
+ H5T_t *dt = NULL; /* Pointer to datatype allocated */
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Allocate & initialize datatype wrapper info */
+ if(NULL == (dt = H5FL_CALLOC(H5T_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ H5O_loc_reset(&(dt->oloc));
+ H5G_name_reset(&(dt->path));
+ H5O_msg_reset_share(H5O_DTYPE_ID, dt);
+
+ /* Allocate & initialize shared datatype structure */
+ if(NULL == (dt->shared = H5FL_CALLOC(H5T_shared_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ dt->shared->version = H5O_DTYPE_VERSION_1;
+
+ /* Assign return value */
+ ret_value = dt;
+
+done:
+ if(ret_value == NULL)
+ if(dt) {
+ if(dt->shared)
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+ dt = H5FL_FREE(H5T_t, dt);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__free
+ *
+ * Purpose: Frees all memory associated with a datatype, but does not
+ * free the H5T_t or H5T_shared_t structures (which should
+ * be done in H5T_close).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, January 6, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__free(H5T_t *dt)
+{
+ unsigned i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dt && dt->shared);
+
+ /*
+ * If a named type is being closed then close the object header and
+ * remove from the list of open objects in the file.
+ */
+ if(H5T_STATE_OPEN == dt->shared->state) {
+ HDassert(dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED);
+ HDassert(H5F_addr_defined(dt->sh_loc.u.loc.oh_addr));
+ HDassert(H5F_addr_defined(dt->oloc.addr));
+
+ /* Remove the datatype from the list of opened objects in the file */
+ if(H5FO_top_decr(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+ if(H5FO_delete(dt->sh_loc.file, H5AC_ind_read_dxpl_id, dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "can't remove datatype from list of open objects")
+ if(H5O_close(&dt->oloc, NULL) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to close data type object header")
+ dt->shared->state = H5T_STATE_NAMED;
+ } /* end if */
+
+ /* Free the ID to name info */
+ H5G_name_free(&(dt->path));
+
+ /*
+ * Don't free locked datatypes.
+ */
+ if(H5T_STATE_IMMUTABLE==dt->shared->state)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to close immutable datatype")
+
+ /* Close the datatype */
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ dt->shared->u.compnd.memb[i].name = (char *)H5MM_xfree(dt->shared->u.compnd.memb[i].name);
+ H5T_close(dt->shared->u.compnd.memb[i].type);
+ } /* end for */
+ dt->shared->u.compnd.memb = (H5T_cmemb_t *)H5MM_xfree(dt->shared->u.compnd.memb);
+ dt->shared->u.compnd.nmembs = 0;
+ break;
+
+ case H5T_ENUM:
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++)
+ dt->shared->u.enumer.name[i] = (char *)H5MM_xfree(dt->shared->u.enumer.name[i]);
+ dt->shared->u.enumer.name = (char **)H5MM_xfree(dt->shared->u.enumer.name);
+ dt->shared->u.enumer.value = (uint8_t *)H5MM_xfree(dt->shared->u.enumer.value);
+ dt->shared->u.enumer.nmembs = 0;
+ break;
+
+ case H5T_OPAQUE:
+ dt->shared->u.opaque.tag = (char *)H5MM_xfree(dt->shared->u.opaque.tag);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_REFERENCE:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ break;
+ } /* end switch */
+ dt->shared->type = H5T_NO_CLASS;
+
+ /* Close the parent */
+ HDassert(dt->shared->parent != dt);
+ if(dt->shared->parent && H5T_close(dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "unable to close parent data type")
+ dt->shared->parent = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_close
+ *
+ * Purpose: Frees a data type and all associated memory. If the data
+ * type is locked then nothing happens.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_close(H5T_t *dt)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt && dt->shared);
+
+ if(dt->shared->state == H5T_STATE_OPEN)
+ dt->shared->fo_count--;
+
+ if(dt->shared->state != H5T_STATE_OPEN || dt->shared->fo_count == 0) {
+ /* Uncork cache entries with object address tag for named datatype only */
+ if(dt->shared->state == H5T_STATE_OPEN && dt->shared->fo_count == 0) {
+ hbool_t corked; /* Whether the named datatype is corked or not */
+
+ if(H5AC_cork(dt->oloc.file, dt->oloc.addr, H5AC__GET_CORKED, &corked) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status")
+ if(corked)
+ if(H5AC_cork(dt->oloc.file, dt->oloc.addr, H5AC__UNCORK, NULL) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTUNCORK, FAIL, "unable to uncork an object")
+ } /* end if */
+
+ if(H5T__free(dt) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free datatype");
+
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+ } /* end if */
+ else {
+ /*
+ * If a named type is being closed then close the object header and
+ * remove from the list of open objects in the file.
+ */
+ if(H5T_STATE_OPEN == dt->shared->state) {
+ HDassert(dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED);
+
+ /* Decrement the ref. count for this object in the top file */
+ if(H5FO_top_decr(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+
+ /* Check reference count for this object in the top file */
+ if(H5FO_top_count(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) == 0) {
+ /* Close object location for named datatype */
+ if(H5O_close(&dt->oloc, NULL) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to close")
+ } /* end if */
+ else
+ /* Free object location (i.e. "unhold" the file if appropriate)
+ */
+ if(H5O_loc_free(&(dt->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "problem attempting to free location")
+ } /* end if */
+
+ /* Free the group hier. path since we're not calling H5T__free() */
+ H5G_name_free(&(dt->path));
+ } /* end else */
+
+ /* Free the datatype struct */
+ dt = H5FL_FREE(H5T_t, dt);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_set_size
+ *
+ * Purpose: Sets the total size in bytes for a data type (this operation
+ * is not permitted on reference data types). If the size is
+ * decreased so that the significant bits of the data type
+ * extend beyond the edge of the new size, then the `offset'
+ * property is decreased toward zero. If the `offset' becomes
+ * zero and the significant bits of the data type still hang
+ * over the edge of the new size, then the number of significant
+ * bits is decreased.
+ *
+ * Adjusting the size of an H5T_STRING automatically sets the
+ * precision to 8*size.
+ *
+ * All data types have a positive size.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: nagative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 22, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_set_size(H5T_t *dt, size_t size)
+{
+ size_t prec, offset;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(size!=0);
+ HDassert(H5T_REFERENCE!=dt->shared->type);
+ HDassert(!(H5T_ENUM==dt->shared->type && 0==dt->shared->u.enumer.nmembs));
+
+ if (dt->shared->parent) {
+ if (H5T_set_size(dt->shared->parent, size)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to set size for parent data type");
+
+ /* Adjust size of datatype appropriately */
+ if(dt->shared->type==H5T_ARRAY)
+ dt->shared->size = dt->shared->parent->shared->size * dt->shared->u.array.nelem;
+ else if(dt->shared->type!=H5T_VLEN)
+ dt->shared->size = dt->shared->parent->shared->size;
+ } else {
+ if (H5T_IS_ATOMIC(dt->shared)) {
+ offset = dt->shared->u.atomic.offset;
+ prec = dt->shared->u.atomic.prec;
+
+ /* Decrement the offset and precision if necessary */
+ if (prec > 8*size)
+ offset = 0;
+ else
+ if (offset+prec > 8*size)
+ offset = 8 * size - prec;
+ if (prec > 8*size)
+ prec = 8 * size;
+ } else {
+ prec = offset = 0;
+ }
+
+ switch (dt->shared->type) {
+ case H5T_INTEGER:
+ case H5T_TIME:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ /* nothing to check */
+ break;
+
+ case H5T_COMPOUND:
+ /* If decreasing size, check the last member isn't being cut. */
+ if(size<dt->shared->size) {
+ int num_membs = 0;
+ unsigned i, max_index=0;
+ size_t memb_offset, max_offset=0;
+ size_t max_size;
+
+ if((num_membs = H5T_get_nmembers(dt))<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to get number of members");
+
+ if(num_membs) {
+ for(i=0; i<(unsigned)num_membs; i++) {
+ memb_offset = H5T_get_member_offset(dt, i);
+ if(memb_offset > max_offset) {
+ max_offset = memb_offset;
+ max_index = i;
+ }
+ }
+
+ max_size = H5T__get_member_size(dt, max_index);
+
+ if(size<(max_offset+max_size))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "size shrinking will cut off last member ");
+ }
+
+ /* Compound must not have been packed previously */
+ /* We will check if resizing changed the packed state of
+ * this type at the end of this function */
+ HDassert(!dt->shared->u.compnd.packed);
+ }
+
+ break;
+
+ case H5T_STRING:
+ /* Convert string to variable-length datatype */
+ if(size==H5T_VARIABLE) {
+ H5T_t *base = NULL; /* base data type */
+ H5T_cset_t tmp_cset; /* Temp. cset info */
+ H5T_str_t tmp_strpad; /* Temp. strpad info */
+
+ /* Get a copy of unsigned char type as the base/parent type */
+ if(NULL == (base = (H5T_t *)H5I_object(H5T_NATIVE_UCHAR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid base datatype");
+ dt->shared->parent=H5T_copy(base,H5T_COPY_ALL);
+
+ /* change this datatype into a VL string */
+ dt->shared->type = H5T_VLEN;
+
+ /*
+ * Force conversions (i.e. memory to memory conversions
+ * should duplicate data, not point to the same VL strings)
+ */
+ dt->shared->force_conv = TRUE;
+
+ /* Before we mess with the info in the union, extract the
+ * values we need */
+ tmp_cset=dt->shared->u.atomic.u.s.cset;
+ tmp_strpad=dt->shared->u.atomic.u.s.pad;
+
+ /* This is a string, not a sequence */
+ dt->shared->u.vlen.type = H5T_VLEN_STRING;
+
+ /* Set character set and padding information */
+ dt->shared->u.vlen.cset = tmp_cset;
+ dt->shared->u.vlen.pad = tmp_strpad;
+
+ /* Set up VL information */
+ if (H5T_set_loc(dt, NULL, H5T_LOC_MEMORY)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid datatype location");
+
+ } else {
+ prec = 8 * size;
+ offset = 0;
+ } /* end else */
+ break;
+
+ case H5T_FLOAT:
+ /*
+ * The sign, mantissa, and exponent fields should be adjusted
+ * first when decreasing the size of a floating point type.
+ */
+ if (dt->shared->u.atomic.u.f.sign >= prec+offset ||
+ dt->shared->u.atomic.u.f.epos + dt->shared->u.atomic.u.f.esize > prec+offset ||
+ dt->shared->u.atomic.u.f.mpos + dt->shared->u.atomic.u.f.msize > prec+offset) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "adjust sign, mantissa, and exponent fields first");
+ }
+ break;
+
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_REFERENCE:
+ HDassert("can't happen" && 0);
+ break;
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ HDassert("invalid type" && 0);
+ break;
+ default:
+ HDassert("not implemented yet" && 0);
+ break;
+ }
+
+ /* Commit (if we didn't convert this type to a VL string) */
+ if(dt->shared->type!=H5T_VLEN) {
+ dt->shared->size = size;
+ if (H5T_IS_ATOMIC(dt->shared)) {
+ dt->shared->u.atomic.offset = offset;
+ dt->shared->u.atomic.prec = prec;
+ }
+ } /* end if */
+
+ /* Check if the new compound type is packed */
+ if(dt->shared->type == H5T_COMPOUND)
+ H5T__update_packed(dt);
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_size
+ *
+ * Purpose: Determines the total size of a data type in bytes.
+ *
+ * Return: Success: Size of the data type in bytes. The size of
+ * the data type is the size of an instance of
+ * that data type.
+ *
+ * Failure: 0 (valid data types are never zero size)
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 9, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5T_get_size(const H5T_t *dt)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(dt);
+
+ FUNC_LEAVE_NOAPI(dt->shared->size)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_cmp
+ *
+ * Purpose: Compares two data types.
+ *
+ * Return: Success: 0 if DT1 and DT2 are equal.
+ * <0 if DT1 is less than DT2.
+ * >0 if DT1 is greater than DT2.
+ *
+ * Failure: 0, never fails
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 10, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_cmp(const H5T_t *dt1, const H5T_t *dt2, hbool_t superset)
+{
+ unsigned *idx1 = NULL, *idx2 = NULL;
+ size_t base_size;
+ hbool_t swapped;
+ unsigned u;
+ int tmp;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Sanity check */
+ HDassert(dt1);
+ HDassert(dt2);
+
+ /* the easy case */
+ if(dt1 == dt2)
+ HGOTO_DONE(0);
+
+ /* compare */
+ if(dt1->shared->type < dt2->shared->type)
+ HGOTO_DONE(-1);
+ if(dt1->shared->type > dt2->shared->type)
+ HGOTO_DONE(1);
+
+ if(dt1->shared->size < dt2->shared->size)
+ HGOTO_DONE(-1);
+ if(dt1->shared->size > dt2->shared->size)
+ HGOTO_DONE(1);
+
+ if(dt1->shared->parent && !dt2->shared->parent)
+ HGOTO_DONE(-1);
+ if(!dt1->shared->parent && dt2->shared->parent)
+ HGOTO_DONE(1);
+ if(dt1->shared->parent) {
+ tmp = H5T_cmp(dt1->shared->parent, dt2->shared->parent, superset);
+ if(tmp < 0)
+ HGOTO_DONE(-1);
+ if(tmp > 0)
+ HGOTO_DONE(1);
+ } /* end if */
+
+ switch(dt1->shared->type) {
+ case H5T_COMPOUND:
+ /*
+ * Compound data types...
+ */
+ if(dt1->shared->u.compnd.nmembs < dt2->shared->u.compnd.nmembs)
+ HGOTO_DONE(-1);
+ if(dt1->shared->u.compnd.nmembs > dt2->shared->u.compnd.nmembs)
+ HGOTO_DONE(1);
+
+ /* Build an index for each type so the names are sorted */
+ if(NULL == (idx1 = (unsigned *)H5MM_malloc(dt1->shared->u.compnd.nmembs * sizeof(unsigned))) ||
+ NULL == (idx2 = (unsigned *)H5MM_malloc(dt2->shared->u.compnd.nmembs * sizeof(unsigned))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed");
+ for(u = 0; u < dt1->shared->u.compnd.nmembs; u++)
+ idx1[u] = idx2[u] = u;
+ if(dt1->shared->u.enumer.nmembs > 1) {
+ int i;
+
+ for(i = (int) dt1->shared->u.compnd.nmembs - 1, swapped = TRUE; swapped && i >= 0; --i) {
+ int j;
+
+ for(j = 0, swapped=FALSE; j < i; j++)
+ if(HDstrcmp(dt1->shared->u.compnd.memb[idx1[j]].name,
+ dt1->shared->u.compnd.memb[idx1[j + 1]].name) > 0) {
+ unsigned tmp_idx = idx1[j];
+ idx1[j] = idx1[j + 1];
+ idx1[j + 1] = tmp_idx;
+ swapped = TRUE;
+ }
+ }
+ for(i = (int) dt2->shared->u.compnd.nmembs - 1, swapped = TRUE; swapped && i >= 0; --i) {
+ int j;
+
+ for(j = 0, swapped = FALSE; j<i; j++)
+ if(HDstrcmp(dt2->shared->u.compnd.memb[idx2[j]].name,
+ dt2->shared->u.compnd.memb[idx2[j + 1]].name) > 0) {
+ unsigned tmp_idx = idx2[j];
+ idx2[j] = idx2[j + 1];
+ idx2[j + 1] = tmp_idx;
+ swapped = TRUE;
+ }
+ }
+ } /* end if */
+
+#ifdef H5T_DEBUG
+ /* I don't quite trust the code above yet :-) --RPM */
+ for (u=0; u<dt1->shared->u.compnd.nmembs-1; u++) {
+ HDassert(HDstrcmp(dt1->shared->u.compnd.memb[idx1[u]].name,
+ dt1->shared->u.compnd.memb[idx1[u + 1]].name));
+ HDassert(HDstrcmp(dt2->shared->u.compnd.memb[idx2[u]].name,
+ dt2->shared->u.compnd.memb[idx2[u + 1]].name));
+ }
+#endif
+
+ /* Compare the members */
+ for (u=0; u<dt1->shared->u.compnd.nmembs; u++) {
+ tmp = HDstrcmp(dt1->shared->u.compnd.memb[idx1[u]].name,
+ dt2->shared->u.compnd.memb[idx2[u]].name);
+ if (tmp < 0)
+ HGOTO_DONE(-1);
+ if (tmp > 0)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.compnd.memb[idx1[u]].offset < dt2->shared->u.compnd.memb[idx2[u]].offset) HGOTO_DONE(-1);
+ if (dt1->shared->u.compnd.memb[idx1[u]].offset > dt2->shared->u.compnd.memb[idx2[u]].offset) HGOTO_DONE(1);
+
+ if (dt1->shared->u.compnd.memb[idx1[u]].size < dt2->shared->u.compnd.memb[idx2[u]].size) HGOTO_DONE(-1);
+ if (dt1->shared->u.compnd.memb[idx1[u]].size > dt2->shared->u.compnd.memb[idx2[u]].size) HGOTO_DONE(1);
+
+ tmp = H5T_cmp(dt1->shared->u.compnd.memb[idx1[u]].type,
+ dt2->shared->u.compnd.memb[idx2[u]].type, superset);
+ if (tmp < 0) HGOTO_DONE(-1);
+ if (tmp > 0) HGOTO_DONE(1);
+ }
+ break;
+
+ case H5T_ENUM:
+ /*
+ * Enumeration data types...
+ */
+
+ /* If we are doing a "superset" comparison, dt2 is allowed to have
+ * more members than dt1
+ */
+ if(superset) {
+ if (dt1->shared->u.enumer.nmembs > dt2->shared->u.enumer.nmembs)
+ HGOTO_DONE(1);
+ } /* end if */
+ else {
+ if (dt1->shared->u.enumer.nmembs < dt2->shared->u.enumer.nmembs)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.enumer.nmembs > dt2->shared->u.enumer.nmembs)
+ HGOTO_DONE(1);
+ } /* end else */
+
+ /* Build an index for each type so the names are sorted */
+ if(NULL == (idx1 = (unsigned *)H5MM_malloc(dt1->shared->u.enumer.nmembs * sizeof(unsigned))) ||
+ NULL == (idx2 = (unsigned *)H5MM_malloc(dt2->shared->u.enumer.nmembs * sizeof(unsigned))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed");
+ for (u=0; u<dt1->shared->u.enumer.nmembs; u++)
+ idx1[u] = u;
+ if(dt1->shared->u.enumer.nmembs > 1) {
+ int i;
+ for (i = (int) dt1->shared->u.enumer.nmembs - 1, swapped = TRUE; swapped && i >= 0; --i) {
+ int j;
+
+ for (j = 0, swapped = FALSE; j < i; j++)
+ if (HDstrcmp(dt1->shared->u.enumer.name[idx1[j]],
+ dt1->shared->u.enumer.name[idx1[j+1]]) > 0) {
+ unsigned tmp_idx = idx1[j];
+ idx1[j] = idx1[j+1];
+ idx1[j+1] = tmp_idx;
+ swapped = TRUE;
+ }
+ }
+ }
+ for (u=0; u<dt2->shared->u.enumer.nmembs; u++)
+ idx2[u] = u;
+ if(dt2->shared->u.enumer.nmembs > 1) {
+ int i;
+
+ for (i = (int) dt2->shared->u.enumer.nmembs - 1, swapped = TRUE; swapped && i >= 0; --i) {
+ int j;
+
+ for (j = 0, swapped = FALSE; j < i; j++)
+ if (HDstrcmp(dt2->shared->u.enumer.name[idx2[j]],
+ dt2->shared->u.enumer.name[idx2[j+1]]) > 0) {
+ unsigned tmp_idx = idx2[j];
+ idx2[j] = idx2[j+1];
+ idx2[j+1] = tmp_idx;
+ swapped = TRUE;
+ }
+ }
+ }
+
+#ifdef H5T_DEBUG
+ /* I don't quite trust the code above yet :-) --RPM */
+ for (u=0; u<dt1->shared->u.enumer.nmembs-1; u++) {
+ HDassert(HDstrcmp(dt1->shared->u.enumer.name[idx1[u]],
+ dt1->shared->u.enumer.name[idx1[u+1]]));
+ HDassert(HDstrcmp(dt2->shared->u.enumer.name[idx2[u]],
+ dt2->shared->u.enumer.name[idx2[u+1]]));
+ }
+#endif
+
+ /* Compare the members */
+ base_size = dt1->shared->parent->shared->size;
+ for (u=0; u<dt1->shared->u.enumer.nmembs; u++) {
+ unsigned idx = 0;
+
+ if(superset) {
+ unsigned lt = 0, rt; /* Final, left & right key indices */
+ int cmp = 1; /* Key comparison value */
+
+ /* If a superset is allowed, dt2 may have more members
+ * than dt1, so binary search for matching member name in
+ * dt2
+ */
+ rt = dt2->shared->u.enumer.nmembs;
+
+ while (lt < rt && cmp) {
+ idx = (lt + rt) / 2;
+
+ /* compare */
+ if ((cmp = HDstrcmp(dt1->shared->u.enumer.name[idx1[u]],
+ dt2->shared->u.enumer.name[idx2[idx]] ) ) < 0)
+ rt = idx;
+ else
+ lt = idx+1;
+ }
+ /* Leave, if we couldn't find match */
+ if (cmp)
+ HGOTO_DONE(-1);
+ } /* end if */
+ else {
+ /* Check for exact member name match when not doing
+ * "superset" comparison
+ */
+ tmp = HDstrcmp(dt1->shared->u.enumer.name[idx1[u]],
+ dt2->shared->u.enumer.name[idx2[u]]);
+ if (tmp<0) HGOTO_DONE(-1);
+ if (tmp>0) HGOTO_DONE(1);
+
+ /* Set index value appropriately */
+ idx = u;
+ } /* end else */
+
+ tmp = HDmemcmp(dt1->shared->u.enumer.value+idx1[u]*base_size,
+ dt2->shared->u.enumer.value+idx2[idx]*base_size,
+ base_size);
+ if (tmp<0) HGOTO_DONE(-1);
+ if (tmp>0) HGOTO_DONE(1);
+ }
+ break;
+
+ case H5T_VLEN:
+ HDassert(dt1->shared->u.vlen.type>H5T_VLEN_BADTYPE && dt1->shared->u.vlen.type<H5T_VLEN_MAXTYPE);
+ HDassert(dt2->shared->u.vlen.type>H5T_VLEN_BADTYPE && dt2->shared->u.vlen.type<H5T_VLEN_MAXTYPE);
+ HDassert(dt1->shared->u.vlen.loc>=H5T_LOC_BADLOC && dt1->shared->u.vlen.loc<H5T_LOC_MAXLOC);
+ HDassert(dt2->shared->u.vlen.loc>=H5T_LOC_BADLOC && dt2->shared->u.vlen.loc<H5T_LOC_MAXLOC);
+
+ /* Arbitrarily sort sequence VL datatypes before string VL datatypes */
+ if (dt1->shared->u.vlen.type==H5T_VLEN_SEQUENCE &&
+ dt2->shared->u.vlen.type==H5T_VLEN_STRING) {
+ HGOTO_DONE(-1);
+ } else if (dt1->shared->u.vlen.type==H5T_VLEN_STRING &&
+ dt2->shared->u.vlen.type==H5T_VLEN_SEQUENCE) {
+ HGOTO_DONE(1);
+ }
+ /* Arbitrarily sort VL datatypes in memory before disk */
+ if (dt1->shared->u.vlen.loc==H5T_LOC_MEMORY &&
+ dt2->shared->u.vlen.loc==H5T_LOC_DISK) {
+ HGOTO_DONE(-1);
+ } else if (dt1->shared->u.vlen.loc==H5T_LOC_DISK &&
+ dt2->shared->u.vlen.loc==H5T_LOC_MEMORY) {
+ HGOTO_DONE(1);
+ } else if (dt1->shared->u.vlen.loc==H5T_LOC_BADLOC &&
+ dt2->shared->u.vlen.loc!=H5T_LOC_BADLOC) {
+ HGOTO_DONE(1);
+ }
+
+ /* Don't allow VL types in different files to compare as equal */
+ if (dt1->shared->u.vlen.f < dt2->shared->u.vlen.f)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.vlen.f > dt2->shared->u.vlen.f)
+ HGOTO_DONE(1);
+ break;
+
+ case H5T_OPAQUE:
+ if(dt1->shared->u.opaque.tag && dt2->shared->u.opaque.tag)
+ HGOTO_DONE(HDstrcmp(dt1->shared->u.opaque.tag,dt2->shared->u.opaque.tag));
+ break;
+
+ case H5T_ARRAY:
+ if (dt1->shared->u.array.ndims < dt2->shared->u.array.ndims)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.array.ndims > dt2->shared->u.array.ndims)
+ HGOTO_DONE(1);
+
+ for (u=0; u<dt1->shared->u.array.ndims; u++) {
+ if (dt1->shared->u.array.dim[u] < dt2->shared->u.array.dim[u])
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.array.dim[u] > dt2->shared->u.array.dim[u])
+ HGOTO_DONE(1);
+ }
+
+ tmp = H5T_cmp(dt1->shared->parent, dt2->shared->parent, superset);
+ if (tmp < 0)
+ HGOTO_DONE(-1);
+ if (tmp > 0)
+ HGOTO_DONE(1);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_REFERENCE:
+ case H5T_NCLASSES:
+ default:
+ /*
+ * Atomic datatypes...
+ */
+ if (dt1->shared->u.atomic.order < dt2->shared->u.atomic.order) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.order > dt2->shared->u.atomic.order) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.prec < dt2->shared->u.atomic.prec) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.prec > dt2->shared->u.atomic.prec) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.offset < dt2->shared->u.atomic.offset) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.offset > dt2->shared->u.atomic.offset) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.lsb_pad < dt2->shared->u.atomic.lsb_pad) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.lsb_pad > dt2->shared->u.atomic.lsb_pad) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.msb_pad < dt2->shared->u.atomic.msb_pad) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.msb_pad > dt2->shared->u.atomic.msb_pad) HGOTO_DONE(1);
+
+ switch (dt1->shared->type) {
+ case H5T_INTEGER:
+ if (dt1->shared->u.atomic.u.i.sign < dt2->shared->u.atomic.u.i.sign)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.i.sign > dt2->shared->u.atomic.u.i.sign)
+ HGOTO_DONE(1);
+ break;
+
+ case H5T_FLOAT:
+ if (dt1->shared->u.atomic.u.f.sign < dt2->shared->u.atomic.u.f.sign)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.sign > dt2->shared->u.atomic.u.f.sign)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.epos < dt2->shared->u.atomic.u.f.epos)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.epos > dt2->shared->u.atomic.u.f.epos)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.esize < dt2->shared->u.atomic.u.f.esize) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.esize > dt2->shared->u.atomic.u.f.esize) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.ebias < dt2->shared->u.atomic.u.f.ebias) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.ebias > dt2->shared->u.atomic.u.f.ebias) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.mpos < dt2->shared->u.atomic.u.f.mpos)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.mpos > dt2->shared->u.atomic.u.f.mpos)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.msize < dt2->shared->u.atomic.u.f.msize) HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.msize > dt2->shared->u.atomic.u.f.msize) HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.norm < dt2->shared->u.atomic.u.f.norm)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.norm > dt2->shared->u.atomic.u.f.norm)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.f.pad < dt2->shared->u.atomic.u.f.pad)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.f.pad > dt2->shared->u.atomic.u.f.pad)
+ HGOTO_DONE(1);
+
+ break;
+
+ case H5T_TIME: /* order and precision are checked above */
+ /*void */
+ break;
+
+ case H5T_STRING:
+ if (dt1->shared->u.atomic.u.s.cset < dt2->shared->u.atomic.u.s.cset)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.s.cset > dt2->shared->u.atomic.u.s.cset)
+ HGOTO_DONE(1);
+
+ if (dt1->shared->u.atomic.u.s.pad < dt2->shared->u.atomic.u.s.pad)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.s.pad > dt2->shared->u.atomic.u.s.pad)
+ HGOTO_DONE(1);
+
+ break;
+
+ case H5T_BITFIELD:
+ /*void */
+ break;
+
+ case H5T_REFERENCE:
+ if (dt1->shared->u.atomic.u.r.rtype < dt2->shared->u.atomic.u.r.rtype)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.r.rtype > dt2->shared->u.atomic.u.r.rtype)
+ HGOTO_DONE(1);
+
+ switch(dt1->shared->u.atomic.u.r.rtype) {
+ case H5R_OBJECT:
+ if (dt1->shared->u.atomic.u.r.loc < dt2->shared->u.atomic.u.r.loc)
+ HGOTO_DONE(-1);
+ if (dt1->shared->u.atomic.u.r.loc > dt2->shared->u.atomic.u.r.loc)
+ HGOTO_DONE(1);
+ break;
+
+ case H5R_DATASET_REGION:
+ /* Does this need more to distinguish it? -QAK 11/30/98 */
+ /*void */
+ break;
+
+ case H5R_BADTYPE:
+ case H5R_MAXTYPE:
+ HDassert("invalid type" && 0);
+ break;
+ default:
+ HDassert("not implemented yet" && 0);
+ break;
+ }
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HDassert("not implemented yet" && 0);
+ break;
+ }
+ break;
+ } /* end switch */
+
+done:
+ if(NULL != idx1)
+ H5MM_xfree(idx1);
+ if(NULL != idx2)
+ H5MM_xfree(idx2);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_path_find
+ *
+ * Purpose: Finds the path which converts type SRC_ID to type DST_ID,
+ * creating a new path if necessary. If FUNC is non-zero then
+ * it is set as the hard conversion function for that path
+ * regardless of whether the path previously existed. Changing
+ * the conversion function of a path causes statistics to be
+ * reset to zero after printing them. The NAME is used only
+ * when creating a new path and is just for debugging.
+ *
+ * If SRC and DST are both null pointers then the special no-op
+ * conversion path is used. This path is always stored as the
+ * first path in the path table.
+ *
+ * Return: Success: Pointer to the path, valid until the path
+ * database is modified.
+ *
+ * Failure: NULL if the path does not exist and no
+ * function can be found to apply to the new
+ * path.
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 13, 1998
+ *
+ * Modifications:
+ * Added a parameter IS_API to indicate whether to an API
+ * function issued a call to this function. If a API
+ * function like H5Tregister() is calling this function to
+ * register a new hard conversion function, IS_API is TRUE
+ * and the old path is replaced. If a private function like
+ * H5T__init_package() is trying to register hard conversions,
+ * IS_API is FALSE and the old hard path is not replaced.
+ * Tuesday, Sept 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_path_t *
+H5T_path_find(const H5T_t *src, const H5T_t *dst, const char *name,
+ H5T_conv_t func, hid_t dxpl_id, hbool_t is_api)
+{
+ int lt, rt; /*left and right edges */
+ int md; /*middle */
+ int cmp; /*comparison result */
+ int old_npaths; /* Previous number of paths in table */
+ H5T_path_t *table = NULL; /*path existing in the table */
+ H5T_path_t *path = NULL; /*new path */
+ hid_t src_id = -1, dst_id = -1; /*src and dst type identifiers */
+ int i; /*counter */
+ int nprint = 0; /*lines of output printed */
+ H5T_path_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(src);
+ HDassert(src->shared);
+ HDassert(dst);
+ HDassert(dst->shared);
+
+ /*
+ * Make sure the first entry in the table is the no-op conversion path.
+ */
+ if(0 == H5T_g.npaths) {
+ if(NULL == (H5T_g.path = (H5T_path_t **)H5MM_malloc(128 * sizeof(H5T_path_t *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for type conversion path table")
+ H5T_g.apaths = 128;
+ if(NULL == (H5T_g.path[0] = H5FL_CALLOC(H5T_path_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for no-op conversion path")
+ HDsnprintf(H5T_g.path[0]->name, sizeof(H5T_g.path[0]->name), "no-op");
+ H5T_g.path[0]->func = H5T__conv_noop;
+ H5T_g.path[0]->cdata.command = H5T_CONV_INIT;
+ if(H5T__conv_noop((hid_t)FAIL, (hid_t)FAIL, &(H5T_g.path[0]->cdata), (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id) < 0) {
+#ifdef H5T_DEBUG
+ if(H5DEBUG(T))
+ fprintf(H5DEBUG(T), "H5T: unable to initialize no-op conversion function (ignored)\n");
+#endif
+ H5E_clear_stack(NULL); /*ignore the error*/
+ } /* end if */
+ H5T_g.path[0]->is_noop = TRUE;
+ H5T_g.npaths = 1;
+ } /* end if */
+
+ /*
+ * Find the conversion path. If source and destination types are equal
+ * then use entry[0], otherwise do a binary search over the
+ * remaining entries.
+ *
+ * Quincey Koziol, 2 July, 1999
+ * Only allow the no-op conversion to occur if no "force conversion" flags
+ * are set
+ */
+ if(src->shared->force_conv == FALSE && dst->shared->force_conv == FALSE && 0 == H5T_cmp(src, dst, TRUE)) {
+ table = H5T_g.path[0];
+ cmp = 0;
+ md = 0;
+ } /* end if */
+ else {
+ lt = md = 1;
+ rt = H5T_g.npaths;
+ cmp = -1;
+
+ while(cmp && lt < rt) {
+ md = (lt + rt) / 2;
+ HDassert(H5T_g.path[md]);
+ cmp = H5T_cmp(src, H5T_g.path[md]->src, FALSE);
+ if(0 == cmp)
+ cmp = H5T_cmp(dst, H5T_g.path[md]->dst, FALSE);
+ if(cmp < 0)
+ rt = md;
+ else if(cmp > 0)
+ lt = md + 1;
+ else
+ table = H5T_g.path[md];
+ } /* end while */
+ } /* end else */
+
+ /* Keep a record of the number of paths in the table, in case one of the
+ * initialization calls below (hard or soft) causes more entries to be
+ * added to the table - QAK, 1/26/02
+ */
+ old_npaths = H5T_g.npaths;
+
+ /*
+ * If we didn't find the path, if the caller is an API function specifying
+ * a new hard conversion function, or if the caller is a private function
+ * specifying a new hard conversion and the path is a soft conversion, then
+ * create a new path and add the new function to the path.
+ */
+ if(!table || (table && func && is_api) || (table && !table->is_hard && func && !is_api)) {
+ if(NULL == (path = H5FL_CALLOC(H5T_path_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for type conversion path")
+ if(name && *name) {
+ HDstrncpy(path->name, name, (size_t)H5T_NAMELEN);
+ path->name[H5T_NAMELEN - 1] = '\0';
+ } /* end if */
+ else
+ HDsnprintf(path->name, sizeof(path->name), "NONAME");
+ if(NULL == (path->src = H5T_copy(src, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy datatype for conversion path")
+ if(NULL == (path->dst = H5T_copy(dst, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy datatype for conversion path")
+ } /* end if */
+ else
+ path = table;
+
+ /*
+ * If a hard conversion function is specified and none is defined for the
+ * path, or the caller is an API function, or the caller is a private function but
+ * the existing path is a soft function, then add the new conversion to the path
+ * and initialize its conversion data.
+ */
+ if(func && (!table || (table && is_api) || (table && !table->is_hard && !is_api))) {
+ HDassert(path != table);
+ HDassert(NULL == path->func);
+ if(path->src && (src_id = H5I_register(H5I_DATATYPE, H5T_copy(path->src, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register source conversion type for query")
+ if(path->dst && (dst_id = H5I_register(H5I_DATATYPE, H5T_copy(path->dst, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register destination conversion type for query")
+ path->cdata.command = H5T_CONV_INIT;
+ if((func)(src_id, dst_id, &(path->cdata), (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to initialize conversion function")
+ if(src_id >= 0)
+ H5I_dec_ref(src_id);
+ if(dst_id >= 0)
+ H5I_dec_ref(dst_id);
+ src_id = dst_id = -1;
+ path->func = func;
+ path->is_hard = TRUE;
+ } /* end if */
+
+ /*
+ * If the path doesn't have a function by now (because it's a new path
+ * and the caller didn't supply a hard function) then scan the soft list
+ * for an applicable function and add it to the path. This can't happen
+ * for the no-op conversion path.
+ */
+ HDassert(path->func || (src && dst));
+ for(i = H5T_g.nsoft - 1; i >= 0 && !path->func; --i) {
+ if(src->shared->type != H5T_g.soft[i].src || dst->shared->type != H5T_g.soft[i].dst)
+ continue;
+ if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(path->src, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register src conversion type for query")
+ if((dst_id = H5I_register(H5I_DATATYPE, H5T_copy(path->dst, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, NULL, "unable to register dst conversion type for query")
+ path->cdata.command = H5T_CONV_INIT;
+ if((H5T_g.soft[i].func)(src_id, dst_id, &(path->cdata), (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id) < 0) {
+ HDmemset(&(path->cdata), 0, sizeof(H5T_cdata_t));
+ H5E_clear_stack(H5E_DEFAULT); /*ignore the error*/
+ } /* end if */
+ else {
+ HDstrncpy(path->name, H5T_g.soft[i].name, (size_t)H5T_NAMELEN);
+ path->name[H5T_NAMELEN - 1] = '\0';
+ path->func = H5T_g.soft[i].func;
+ path->is_hard = FALSE;
+ } /* end else */
+ H5I_dec_ref(src_id);
+ H5I_dec_ref(dst_id);
+ src_id = dst_id = -1;
+ } /* end for */
+ if(!path->func)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "no appropriate function for conversion path")
+
+ /* Check if paths were inserted into the table through a recursive call
+ * and re-compute the correct location for this path if so. - QAK, 1/26/02
+ */
+ if(old_npaths != H5T_g.npaths) {
+ lt = md = 1;
+ rt = H5T_g.npaths;
+ cmp = -1;
+
+ while(cmp && lt < rt) {
+ md = (lt + rt) / 2;
+ HDassert(H5T_g.path[md]);
+ cmp = H5T_cmp(src, H5T_g.path[md]->src, FALSE);
+ if(0 == cmp)
+ cmp = H5T_cmp(dst, H5T_g.path[md]->dst, FALSE);
+ if(cmp < 0)
+ rt = md;
+ else if(cmp > 0)
+ lt = md + 1;
+ else
+ table = H5T_g.path[md];
+ } /* end while */
+ } /* end if */
+
+ /* Replace an existing table entry or add a new entry */
+ if(table && path != table) {
+ HDassert(table == H5T_g.path[md]);
+ H5T__print_stats(table, &nprint/*in,out*/);
+ table->cdata.command = H5T_CONV_FREE;
+ if((table->func)((hid_t)FAIL, (hid_t)FAIL, &(table->cdata), (size_t)0, (size_t)0, (size_t)0, NULL, NULL, dxpl_id) < 0) {
+#ifdef H5T_DEBUG
+ if(H5DEBUG(T)) {
+ fprintf(H5DEBUG(T), "H5T: conversion function 0x%08lx free "
+ "failed for %s (ignored)\n",
+ (unsigned long)(path->func), path->name);
+ } /* end if */
+#endif
+ H5E_clear_stack(NULL); /*ignore the failure*/
+ } /* end if */
+ if(table->src)
+ H5T_close(table->src);
+ if(table->dst)
+ H5T_close(table->dst);
+ table = H5FL_FREE(H5T_path_t, table);
+ table = path;
+ H5T_g.path[md] = path;
+ } else if(path != table) {
+ HDassert(cmp);
+ if((size_t)H5T_g.npaths >= H5T_g.apaths) {
+ size_t na = MAX(128, 2 * H5T_g.apaths);
+ H5T_path_t **x;
+
+ if(NULL == (x = (H5T_path_t **)H5MM_realloc(H5T_g.path, na * sizeof(H5T_path_t*))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ H5T_g.apaths = na;
+ H5T_g.path = x;
+ } /* end if */
+ if(cmp > 0)
+ md++;
+ HDmemmove(H5T_g.path + md + 1, H5T_g.path + md, (size_t) (H5T_g.npaths - md) * sizeof(H5T_path_t*));
+ H5T_g.npaths++;
+ H5T_g.path[md] = path;
+ table = path;
+ } /* end else-if */
+
+ /* Set the flag to indicate both source and destination types are compound types
+ * for the optimization of data reading (in H5Dio.c). */
+ if(H5T_COMPOUND == H5T_get_class(src, TRUE) && H5T_COMPOUND == H5T_get_class(dst, TRUE))
+ path->are_compounds = TRUE;
+
+ /* Set return value */
+ ret_value = path;
+
+done:
+ if(!ret_value && path && path != table) {
+ if(path->src)
+ H5T_close(path->src);
+ if(path->dst)
+ H5T_close(path->dst);
+ path = H5FL_FREE(H5T_path_t, path);
+ } /* end if */
+ if(src_id >= 0)
+ H5I_dec_ref(src_id);
+ if(dst_id >= 0)
+ H5I_dec_ref(dst_id);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_path_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_path_noop
+ *
+ * Purpose: Is the path the special no-op path? The no-op function can be
+ * set by the application and there might be more than one no-op
+ * path in a multi-threaded application if one thread is using
+ * the no-op path when some other thread changes its definition.
+ *
+ * Return: TRUE/FALSE (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 8, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5T_path_noop(const H5T_path_t *p)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(p);
+
+ FUNC_LEAVE_NOAPI(p->is_noop || (p->is_hard && 0==H5T_cmp(p->src, p->dst, FALSE)))
+} /* end H5T_path_noop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_path_compound_subset
+ *
+ * Purpose: Checks if the source and destination types are both compound.
+ * Tells whether whether the source members are a subset of
+ * destination, and the order is the same, and no conversion
+ * is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ *
+ * Return: A pointer to the subset info struct in p, or NULL if there are
+ * no compounds. Points directly into the H5T_path_t structure.
+ *
+ * Programmer: Raymond Lu
+ * 8 June 2007
+ *
+ * Modifications: Neil Fortner
+ * 19 September 2008
+ * Changed return value to H5T_subset_info_t
+ * (to allow it to return copy_size)
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_subset_info_t *
+H5T_path_compound_subset(const H5T_path_t *p)
+{
+ H5T_subset_info_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(p);
+
+ if(p->are_compounds)
+ ret_value = H5T__conv_struct_subset(&(p->cdata));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_path_compound_subset */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_path_bkg
+ *
+ * Purpose: Get the "background" flag for the conversion path.
+ *
+ * Return: Background flag (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 8, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_bkg_t
+H5T_path_bkg(const H5T_path_t *p)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(p);
+
+ FUNC_LEAVE_NOAPI(p->cdata.need_bkg)
+} /* end H5T_path_bkg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_compiler_conv
+ *
+ * Purpose: Private function for H5Tcompiler_conv. Finds out whether the
+ * library's conversion function from type SRC to type DST
+ * is a hard conversion.
+ *
+ * Return: TRUE: hard conversion.
+ * FALSE: soft conversion.
+ * FAIL: function failed.
+ *
+ * Programmer: Raymond Lu
+ * Friday, Sept 2, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5T_compiler_conv(H5T_t *src, H5T_t *dst)
+{
+ H5T_path_t *path;
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Find it */
+ if (NULL==(path=H5T_path_find(src, dst, NULL, NULL, H5AC_noio_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "conversion function not found")
+
+ ret_value = (htri_t)path->is_hard;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_convert
+ *
+ * Purpose: Call a conversion function to convert from source to
+ * destination data type and accumulate timing statistics.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 15, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * The timers are updated only if H5T debugging is enabled at
+ * runtime in addition to compile time.
+ *
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *
+ * Quincey Koziol, 1999-07-01
+ * Added dataset transfer properties, to allow custom VL
+ * datatype allocation function to be passed down to VL
+ * conversion routine.
+ *
+ * Robb Matzke, 2000-05-17
+ * Added the BKG_STRIDE argument which gets passed to all the
+ * conversion functions. If BUF_STRIDE is non-zero then each
+ * data element is at a multiple of BUF_STRIDE bytes in BUF
+ * (on both input and output). If BKG_STRIDE is also set then
+ * the BKG buffer is used in such a way that temporary space
+ * for each element is aligned on a BKG_STRIDE byte boundary.
+ * If either BUF_STRIDE or BKG_STRIDE are zero then the BKG
+ * buffer will be accessed as though it were a packed array
+ * of destination datatype.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_convert(H5T_path_t *tpath, hid_t src_id, hid_t dst_id, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist)
+{
+#ifdef H5T_DEBUG
+ H5_timer_t timer;
+#endif
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+#ifdef H5T_DEBUG
+ if (H5DEBUG(T)) H5_timer_begin(&timer);
+#endif
+ tpath->cdata.command = H5T_CONV_CONV;
+ if ((tpath->func)(src_id, dst_id, &(tpath->cdata), nelmts, buf_stride,
+ bkg_stride, buf, bkg, dset_xfer_plist)<0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "data type conversion failed");
+#ifdef H5T_DEBUG
+ if (H5DEBUG(T)) {
+ H5_timer_end(&(tpath->stats.timer), &timer);
+ tpath->stats.ncalls++;
+ tpath->stats.nelmts += nelmts;
+ }
+#endif
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_oloc
+ *
+ * Purpose: Returns a pointer to the object location for a named datatype.
+ *
+ * Return: Success: Ptr directly into named datatype
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, June 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5O_loc_t *
+H5T_oloc(H5T_t *dt)
+{
+ H5O_loc_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(dt);
+
+ switch(dt->shared->state) {
+ case H5T_STATE_TRANSIENT:
+ case H5T_STATE_RDONLY:
+ case H5T_STATE_IMMUTABLE:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "not a named datatype")
+ case H5T_STATE_NAMED:
+ case H5T_STATE_OPEN:
+ HDassert(dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED);
+ ret_value = &dt->oloc;
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, NULL, "invalid datatype state")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_oloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_nameof
+ *
+ * Purpose: Returns a pointer to the path for a named datatype.
+ *
+ * Return: Success: Ptr directly into named datatype
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, September 12, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_name_t *
+H5T_nameof(H5T_t *dt)
+{
+ H5G_name_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(dt);
+
+ switch(dt->shared->state) {
+ case H5T_STATE_TRANSIENT:
+ case H5T_STATE_RDONLY:
+ case H5T_STATE_IMMUTABLE:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "not a named datatype")
+ case H5T_STATE_NAMED:
+ case H5T_STATE_OPEN:
+ ret_value = &(dt->path);
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, NULL, "invalid datatype state")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_nameof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_immutable
+ *
+ * Purpose: Check if a datatype is immutable.
+ *
+ * Return: TRUE
+ *
+ * FALSE
+ *
+ * Programmer: Raymond Lu
+ * Friday, Dec 7, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_is_immutable(const H5T_t *dt)
+{
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+
+ if(dt->shared->state == H5T_STATE_IMMUTABLE)
+ ret_value = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_named
+ *
+ * Purpose: Check if a datatype is named.
+ *
+ * Return: TRUE
+ *
+ * FALSE
+ *
+ * Programmer: Pedro Vicente
+ * Tuesday, Sep 3, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_is_named(const H5T_t *dt)
+{
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+
+ if(dt->shared->state == H5T_STATE_OPEN || dt->shared->state == H5T_STATE_NAMED)
+ ret_value = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_convert_committed_datatype
+ *
+ * Purpose: To convert the committed datatype "dt" to a transient embedded
+ * type if the file location associated with the committed datatype is
+ * different from the parameter "f".
+ * "f" is the file location where the dataset or attribute will be created.
+ *
+ * Notes: See HDFFV-9940
+ *
+ * Return: Success: non-negative
+ * Failure: negative
+ *
+ * Programmer: Vailin Choi; June 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_convert_committed_datatype(H5T_t *dt, H5F_t *f)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+ HDassert(f);
+
+ if(H5T_is_named(dt) && (dt->sh_loc.file != f)) {
+ HDassert(dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED);
+
+ H5O_msg_reset_share(H5O_DTYPE_ID, dt);
+ if(H5O_loc_free(&dt->oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to initialize location")
+ if(H5G_name_free(&dt->path) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to reset path")
+
+ dt->shared->state = H5T_STATE_TRANSIENT;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_convert_committed_datatype() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5T_get_ref_type
+ PURPOSE
+ Retrieves the type of reference for a datatype
+ USAGE
+ H5R_type_t H5Tget_ref_type(dt)
+ H5T_t *dt; IN: datatype pointer for the reference datatype
+
+ RETURNS
+ Success: A reference type defined in H5Rpublic.h
+ Failure: H5R_BADTYPE
+ DESCRIPTION
+ Given a reference datatype object, this function returns the reference type
+ of the datatype.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5R_type_t
+H5T_get_ref_type(const H5T_t *dt)
+{
+ H5R_type_t ret_value = H5R_BADTYPE;
+
+ FUNC_ENTER_NOAPI(H5R_BADTYPE)
+
+ HDassert(dt);
+
+ if(dt->shared->type==H5T_REFERENCE)
+ ret_value=dt->shared->u.atomic.u.r.rtype;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_ref_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_sensible
+ *
+ * Purpose: Determines if a data type is sensible to store on disk
+ * (i.e. not partially initialized)
+ *
+ * Return: Success: TRUE, FALSE
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 11, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_is_sensible(const H5T_t *dt)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ /* Only allow compound datatypes with at least one member to be stored on disk */
+ if(dt->shared->u.compnd.nmembs > 0)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+ break;
+
+ case H5T_ENUM:
+ /* Only allow enum datatypes with at least one member to be stored on disk */
+ if(dt->shared->u.enumer.nmembs > 0)
+ ret_value=TRUE;
+ else
+ ret_value=FALSE;
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ /* Assume all other datatype are sensible to store on disk */
+ ret_value=TRUE;
+ break;
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5T_set_loc
+ PURPOSE
+ Recursively mark any datatypes as on disk/in memory
+ USAGE
+ htri_t H5T_set_loc(dt,f,loc)
+ H5T_t *dt; IN/OUT: Pointer to the datatype to mark
+ H5F_t *f; IN: Pointer to the file the datatype is in
+ H5T_vlen_type_t loc IN: location of type
+
+ RETURNS
+ One of two values on success:
+ TRUE - If the location of any vlen types changed
+ FALSE - If the location of any vlen types is the same
+ <0 is returned on failure
+ DESCRIPTION
+ Recursively descends any VL or compound datatypes to mark all VL datatypes
+ as either on disk or in memory.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+htri_t
+H5T_set_loc(H5T_t *dt, H5F_t *f, H5T_loc_t loc)
+{
+ htri_t changed; /* Whether H5T_set_loc changed the type (even if the size didn't change) */
+ htri_t ret_value = 0; /* Indicate that success, but no location change */
+ unsigned i; /* Local index variable */
+ size_t old_size; /* Previous size of a field */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+ HDassert(loc>=H5T_LOC_BADLOC && loc<H5T_LOC_MAXLOC);
+
+ /* Datatypes can't change in size if the force_conv flag is not set */
+ if(dt->shared->force_conv) {
+ /* Check the datatype of this element */
+ switch(dt->shared->type) {
+ case H5T_ARRAY: /* Recurse on VL, compound and array base element type */
+ /* Recurse if it's VL, compound, enum or array */
+ /* (If the force_conv flag is _not_ set, the type cannot change in size, so don't recurse) */
+ if(dt->shared->parent->shared->force_conv && H5T_IS_COMPLEX(dt->shared->parent->shared->type)) {
+ /* Keep the old base element size for later */
+ old_size=dt->shared->parent->shared->size;
+
+ /* Mark the VL, compound or array type */
+ if((changed=H5T_set_loc(dt->shared->parent,f,loc))<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location");
+ if(changed>0)
+ ret_value=changed;
+
+ /* Check if the field changed size */
+ if(old_size != dt->shared->parent->shared->size) {
+ /* Adjust the size of the array */
+ dt->shared->size = dt->shared->u.array.nelem*dt->shared->parent->shared->size;
+ } /* end if */
+ } /* end if */
+ break;
+
+ case H5T_COMPOUND: /* Check each field and recurse on VL, compound and array type */
+ {
+ ssize_t accum_change = 0; /* Amount of change in the offset of the fields */
+
+ /* Sort the fields based on offsets */
+ H5T__sort_value(dt, NULL);
+
+ for (i=0; i<dt->shared->u.compnd.nmembs; i++) {
+ H5T_t *memb_type; /* Member's datatype pointer */
+
+ /* Range check against compound member's offset */
+ if ((accum_change < 0) && ((ssize_t) dt->shared->u.compnd.memb[i].offset < accum_change))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid field size in datatype");
+
+ /* Apply the accumulated size change to the offset of the field */
+ dt->shared->u.compnd.memb[i].offset += (size_t) accum_change;
+
+ /* Set the member type pointer (for convenience) */
+ memb_type=dt->shared->u.compnd.memb[i].type;
+
+ /* Recurse if it's VL, compound, enum or array */
+ /* (If the force_conv flag is _not_ set, the type cannot change in size, so don't recurse) */
+ if(memb_type->shared->force_conv && H5T_IS_COMPLEX(memb_type->shared->type)) {
+ /* Keep the old field size for later */
+ old_size=memb_type->shared->size;
+
+ /* Mark the VL, compound, enum or array type */
+ if((changed=H5T_set_loc(memb_type,f,loc))<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location");
+ if(changed>0)
+ ret_value=changed;
+
+ /* Check if the field changed size */
+ if(old_size != memb_type->shared->size) {
+ /* Adjust the size of the member */
+ dt->shared->u.compnd.memb[i].size = (dt->shared->u.compnd.memb[i].size*memb_type->shared->size)/old_size;
+
+ /* Add that change to the accumulated size change */
+ accum_change += (ssize_t) (memb_type->shared->size - old_size);
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ /* Range check against datatype size */
+ if ((accum_change < 0) && ((ssize_t) dt->shared->size < accum_change))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid field size in datatype");
+
+ /* Apply the accumulated size change to the datatype */
+ dt->shared->size += (size_t) accum_change;
+ }
+ break;
+
+ case H5T_VLEN: /* Recurse on the VL information if it's VL, compound or array, then free VL sequence */
+ /* Recurse if it's VL, compound, enum or array */
+ /* (If the force_conv flag is _not_ set, the type cannot change in size, so don't recurse) */
+ if(dt->shared->parent->shared->force_conv && H5T_IS_COMPLEX(dt->shared->parent->shared->type)) {
+ if((changed=H5T_set_loc(dt->shared->parent,f,loc))<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location");
+ if(changed>0)
+ ret_value=changed;
+ } /* end if */
+
+ /* Mark this VL sequence */
+ if((changed = H5T__vlen_set_loc(dt, f, loc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location");
+ if(changed>0)
+ ret_value=changed;
+ break;
+
+ case H5T_REFERENCE:
+ /* Only need to change location of object references */
+ if(dt->shared->u.atomic.u.r.rtype==H5R_OBJECT) {
+ /* Mark this reference */
+ if(loc!=dt->shared->u.atomic.u.r.loc) {
+ /* Set the location */
+ dt->shared->u.atomic.u.r.loc = loc;
+
+ /* Indicate that the location changed */
+ ret_value=TRUE;
+ } /* end if */
+ } /* end if */
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_ENUM:
+ case H5T_NCLASSES:
+ default:
+ break;
+ } /* end switch */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_set_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_relocatable
+ *
+ * Purpose: Check if a datatype will change between disk and memory.
+ *
+ * Notes: Currently, only variable-length and object references change
+ * between disk & memory (see cases where things are changed in
+ * the H5T_set_loc() code above).
+ *
+ * Return:
+ * One of two values on success:
+ * TRUE - If the location of any vlen types changed
+ * FALSE - If the location of any vlen types is the same
+ * <0 is returned on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 24, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_is_relocatable(const H5T_t *dt)
+{
+ htri_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(dt);
+
+ /* VL and reference datatypes are relocatable */
+ if(H5T_detect_class(dt, H5T_VLEN, FALSE) || H5T_detect_class(dt, H5T_REFERENCE, FALSE))
+ ret_value = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_is_relocatable() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_upgrade_version_cb
+ *
+ * Purpose: H5T__visit callback to Upgrade the version of a datatype
+ * (if there's any benefit to doing so)
+ *
+ * Note: The behavior below is tightly coupled with the "better"
+ * encodings for datatype messages in the datatype message
+ * encoding routine.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_upgrade_version_cb(H5T_t *dt, void *op_value)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(dt);
+ HDassert(op_value);
+
+ /* Special behavior for each type of datatype */
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ case H5T_ARRAY:
+ case H5T_ENUM:
+ /* These types benefit from "upgrading" their version */
+ if(*(unsigned *)op_value > dt->shared->version)
+ dt->shared->version = *(unsigned *)op_value;
+ break;
+
+ case H5T_VLEN:
+ if(dt->shared->parent->shared->version > dt->shared->version)
+ dt->shared->version = dt->shared->parent->shared->version;
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_NCLASSES:
+ default:
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_upgrade_version_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__upgrade_version
+ *
+ * Purpose: Upgrade the version of a datatype (if there's any benefit to
+ * doing so) and recursively apply to compound members and/or
+ * parent datatypes.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__upgrade_version(H5T_t *dt, unsigned new_version)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dt);
+
+ /* Iterate over entire datatype, upgrading the version of components, if it's useful */
+ if(H5T__visit(dt, (H5T_VISIT_SIMPLE | H5T_VISIT_COMPLEX_LAST), H5T_upgrade_version_cb, &new_version) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "iteration to upgrade datatype encoding version failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__upgrade_version() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_set_latest_version
+ *
+ * Purpose: Set the encoding for a datatype to the latest version.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_set_latest_version(H5T_t *dt)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(dt);
+
+ /* Upgrade the format version for the datatype to the latest */
+ if(H5T__upgrade_version(dt, H5O_DTYPE_VERSION_LATEST) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't upgrade datatype encoding")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_set_latest_version() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_patch_file
+ *
+ * Purpose: Patch the top-level file pointers contained in dt to point
+ * to f, if dt is a committed type. This is possible because
+ * the top-level file pointer can be closed out from under
+ * dt while dt is contained in the shared file's cache.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: Neil Fortner
+ * Thursday, July 14, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_patch_file(H5T_t *dt, H5F_t *f)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(dt);
+ HDassert(f);
+
+ if(H5T_STATE_OPEN == dt->shared->state || H5T_STATE_NAMED == dt->shared->state) {
+ dt->oloc.file = f;
+ dt->sh_loc.file = f;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_patch_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_patch_vlen_file
+ *
+ * Purpose: Patch the top-level file pointer contained in (dt->shared->u.vlen.f)
+ * to point to f. This is possible because
+ * the top-level file pointer can be closed out from under
+ * dt while dt is contained in the shared file's cache.
+ *
+ * Return: SUCCEED
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_patch_vlen_file(H5T_t *dt, H5F_t *f)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(dt);
+ HDassert(dt->shared);
+ HDassert(f);
+
+ if((dt->shared->type == H5T_VLEN) && dt->shared->u.vlen.f != f)
+ dt->shared->u.vlen.f = f;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_patch_vlen_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tflush
+ *
+ * Purpose: Flushes all buffers associated with a named datatype to disk.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * May 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tflush(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype for this operation */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(!H5T_is_named(dt))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a committed datatype")
+
+ /* To flush metadata and invoke flush callback if there is */
+ if(H5O_flush_common(&dt->oloc, type_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFLUSH, FAIL, "unable to flush datatype and object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Tflush */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Trefresh
+ *
+ * Purpose: Refreshes all buffers associated with a named datatype.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * July 21, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Trefresh(hid_t type_id)
+{
+ H5T_t * dt = NULL;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(!H5T_is_named(dt))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a committed datatype")
+
+ /* Call private function to refresh datatype object */
+ if ((H5O_refresh_metadata(type_id, dt->oloc, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTLOAD, FAIL, "unable to refresh datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Trefresh */
+
diff --git a/src/H5TS.c b/src/H5TS.c
new file mode 100644
index 0000000..a0ca134
--- /dev/null
+++ b/src/H5TS.c
@@ -0,0 +1,521 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* private headers */
+#include "H5private.h" /*library */
+#include "H5Eprivate.h" /*error handling */
+#include "H5MMprivate.h" /*memory management functions */
+
+#ifdef H5_HAVE_THREADSAFE
+
+/* Module specific data structures */
+
+/* cancelability structure */
+typedef struct H5TS_cancel_struct {
+ int previous_state;
+ unsigned int cancel_count;
+} H5TS_cancel_t;
+
+/* Global variable definitions */
+#ifdef H5_HAVE_WIN_THREADS
+H5TS_once_t H5TS_first_init_g;
+#else /* H5_HAVE_WIN_THREADS */
+H5TS_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT;
+#endif /* H5_HAVE_WIN_THREADS */
+H5TS_key_t H5TS_errstk_key_g;
+H5TS_key_t H5TS_funcstk_key_g;
+H5TS_key_t H5TS_cancel_key_g;
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_key_destructor
+ *
+ * USAGE
+ * H5TS_key_destructor()
+ *
+ * RETURNS
+ *
+ * DESCRIPTION
+ * Frees the memory for a key. Called by each thread as it exits.
+ * Currently all the thread-specific information for all keys are simple
+ * structures allocated with malloc, so we can free them all uniformly.
+ *
+ * PROGRAMMER: Quincey Koziol
+ * February 7, 2003
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+H5TS_key_destructor(void *key_val)
+{
+ /* Use HDfree here instead of H5MM_xfree(), to avoid calling the H5CS routines */
+ if(key_val != NULL)
+ HDfree(key_val);
+}
+
+
+#ifndef H5_HAVE_WIN_THREADS
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_pthread_first_thread_init
+ *
+ * USAGE
+ * H5TS_pthread_first_thread_init()
+ *
+ * RETURNS
+ *
+ * DESCRIPTION
+ * Initialization of global API lock, keys for per-thread error stacks and
+ * cancallability information. Called by the first thread that enters the
+ * library.
+ *
+ * PROGRAMMER: Chee Wai LEE
+ * May 2, 2000
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+H5TS_pthread_first_thread_init(void)
+{
+ H5_g.H5_libinit_g = FALSE; /* Library hasn't been initialized */
+ H5_g.H5_libterm_g = FALSE; /* Library isn't being shutdown */
+
+#ifdef H5_HAVE_WIN32_API
+# ifdef PTW32_STATIC_LIB
+ pthread_win32_process_attach_np();
+# endif
+#endif
+
+ /* initialize global API mutex lock */
+ pthread_mutex_init(&H5_g.init_lock.atomic_lock, NULL);
+ pthread_cond_init(&H5_g.init_lock.cond_var, NULL);
+ H5_g.init_lock.lock_count = 0;
+
+ /* initialize key for thread-specific error stacks */
+ pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor);
+
+ /* initialize key for thread-specific function stacks */
+ pthread_key_create(&H5TS_funcstk_key_g, H5TS_key_destructor);
+
+ /* initialize key for thread cancellability mechanism */
+ pthread_key_create(&H5TS_cancel_key_g, H5TS_key_destructor);
+}
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_mutex_lock
+ *
+ * USAGE
+ * H5TS_mutex_lock(&mutex_var)
+ *
+ * RETURNS
+ * 0 on success and non-zero on error.
+ *
+ * DESCRIPTION
+ * Recursive lock semantics for HDF5 (locking) -
+ * Multiple acquisition of a lock by a thread is permitted with a
+ * corresponding unlock operation required.
+ *
+ * PROGRAMMER: Chee Wai LEE
+ * May 2, 2000
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_mutex_lock(H5TS_mutex_t *mutex)
+{
+#ifdef H5_HAVE_WIN_THREADS
+ EnterCriticalSection( &mutex->CriticalSection);
+ return 0;
+#else /* H5_HAVE_WIN_THREADS */
+ herr_t ret_value = pthread_mutex_lock(&mutex->atomic_lock);
+
+ if (ret_value)
+ return ret_value;
+
+ if(mutex->lock_count && pthread_equal(HDpthread_self(), mutex->owner_thread)) {
+ /* already owned by self - increment count */
+ mutex->lock_count++;
+ } else {
+ /* if owned by other thread, wait for condition signal */
+ while(mutex->lock_count)
+ pthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock);
+
+ /* After we've received the signal, take ownership of the mutex */
+ mutex->owner_thread = HDpthread_self();
+ mutex->lock_count = 1;
+ }
+
+ return pthread_mutex_unlock(&mutex->atomic_lock);
+#endif /* H5_HAVE_WIN_THREADS */
+}
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_mutex_unlock
+ *
+ * USAGE
+ * H5TS_mutex_unlock(&mutex_var)
+ *
+ * RETURNS
+ * 0 on success and non-zero on error.
+ *
+ * DESCRIPTION
+ * Recursive lock semantics for HDF5 (unlocking) -
+ * Multiple acquisition of a lock by a thread is permitted with a
+ * corresponding unlock operation required.
+ *
+ * PROGRAMMER: Chee Wai LEE
+ * May 2, 2000
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_mutex_unlock(H5TS_mutex_t *mutex)
+{
+#ifdef H5_HAVE_WIN_THREADS
+ /* Releases ownership of the specified critical section object. */
+ LeaveCriticalSection(&mutex->CriticalSection);
+ return 0;
+#else /* H5_HAVE_WIN_THREADS */
+ herr_t ret_value = pthread_mutex_lock(&mutex->atomic_lock);
+
+ if(ret_value)
+ return ret_value;
+
+ mutex->lock_count--;
+
+ ret_value = pthread_mutex_unlock(&mutex->atomic_lock);
+
+ if(mutex->lock_count == 0) {
+ int err;
+
+ err = pthread_cond_signal(&mutex->cond_var);
+ if(err != 0)
+ ret_value = err;
+ } /* end if */
+
+ return ret_value;
+#endif /* H5_HAVE_WIN_THREADS */
+} /* H5TS_mutex_unlock */
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_cancel_count_inc
+ *
+ * USAGE
+ * H5TS_cancel_count_inc()
+ *
+ * RETURNS
+ * 0 on success non-zero error code on error.
+ *
+ * DESCRIPTION
+ * Creates a cancelation counter for a thread if it is the first time
+ * the thread is entering the library.
+ *
+ * if counter value is zero, then set cancelability type of the thread
+ * to PTHREAD_CANCEL_DISABLE as thread is entering the library and store
+ * the previous cancelability type into cancelation counter.
+ * Increase the counter value by 1.
+ *
+ * PROGRAMMER: Chee Wai LEE
+ * May 2, 2000
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_cancel_count_inc(void)
+{
+#ifdef H5_HAVE_WIN_THREADS
+ /* unsupported; just return 0 */
+ return SUCCEED;
+#else /* H5_HAVE_WIN_THREADS */
+ H5TS_cancel_t *cancel_counter;
+ herr_t ret_value = SUCCEED;
+
+ cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_g);
+
+ if (!cancel_counter) {
+ /*
+ * First time thread calls library - create new counter and associate
+ * with key.
+ *
+ * Don't use H5MM calls here since the destructor has to use HDfree in
+ * order to avoid codestack calls.
+ */
+ cancel_counter = (H5TS_cancel_t *)HDcalloc(1, sizeof(H5TS_cancel_t));
+
+ if (!cancel_counter) {
+ H5E_push_stack(NULL, "H5TS_cancel_count_inc", __FILE__, __LINE__,
+ H5E_ERR_CLS_g, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed");
+ return FAIL;
+ }
+
+ ret_value = pthread_setspecific(H5TS_cancel_key_g, (void *)cancel_counter);
+ }
+
+ if (cancel_counter->cancel_count == 0)
+ /* thread entering library */
+ ret_value = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
+ &cancel_counter->previous_state);
+
+ ++cancel_counter->cancel_count;
+
+ return ret_value;
+#endif /* H5_HAVE_WIN_THREADS */
+}
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_cancel_count_dec
+ *
+ * USAGE
+ * H5TS_cancel_count_dec()
+ *
+ * RETURNS
+ * 0 on success and a non-zero error code on error.
+ *
+ * DESCRIPTION
+ * If counter value is one, then set cancelability type of the thread
+ * to the previous cancelability type stored in the cancelation counter.
+ * (the thread is leaving the library).
+ *
+ * Decrement the counter value by 1.
+ *
+ * PROGRAMMER: Chee Wai LEE
+ * May 2, 2000
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_cancel_count_dec(void)
+{
+#ifdef H5_HAVE_WIN_THREADS
+ /* unsupported; will just return 0 */
+ return SUCCEED;
+#else /* H5_HAVE_WIN_THREADS */
+ register H5TS_cancel_t *cancel_counter;
+ herr_t ret_value = SUCCEED;
+
+ cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_g);
+
+ if (cancel_counter->cancel_count == 1)
+ ret_value = pthread_setcancelstate(cancel_counter->previous_state, NULL);
+
+ --cancel_counter->cancel_count;
+
+ return ret_value;
+#endif /* H5_HAVE_WIN_THREADS */
+}
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_process_enter
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-process setup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+H5_DLL BOOL CALLBACK
+H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
+{
+ BOOL ret_value = TRUE;
+
+ /* Initialize the critical section (can't fail) */
+ InitializeCriticalSection(&H5_g.init_lock.CriticalSection);
+
+ /* Set up thread local storage */
+ if(TLS_OUT_OF_INDEXES == (H5TS_errstk_key_g = TlsAlloc()))
+ ret_value = FALSE;
+
+#ifdef H5_HAVE_CODESTACK
+ if(TLS_OUT_OF_INDEXES == (H5TS_funcstk_key_g = TlsAlloc()))
+ ret_value = FALSE;
+#endif /* H5_HAVE_CODESTACK */
+
+ return ret_value;
+} /* H5TS_win32_process_enter() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_thread_enter
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-thread setup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_win32_thread_enter(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ /* Currently a placeholder function. TLS setup is performed
+ * elsewhere in the library.
+ *
+ * WARNING: Do NOT use C standard library functions here.
+ * CRT functions are not allowed in DllMain, which is where this code
+ * is used.
+ */
+
+ return ret_value;
+} /* H5TS_win32_thread_enter() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_process_exit
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-process cleanup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+void
+H5TS_win32_process_exit(void)
+{
+
+ /* Windows uses a different thread local storage mechanism which does
+ * not support auto-freeing like pthreads' keys.
+ *
+ * This function is currently registered via atexit() and is called
+ * AFTER H5_term_library().
+ */
+
+ /* Clean up critical section resources (can't fail) */
+ DeleteCriticalSection(&H5_g.init_lock.CriticalSection);
+
+ /* Clean up per-process thread local storage */
+ TlsFree(H5TS_errstk_key_g);
+
+#ifdef H5_HAVE_CODESTACK
+ TlsFree(H5TS_funcstk_key_g);
+#endif /* H5_HAVE_CODESTACK */
+
+ return;
+} /* H5TS_win32_process_exit() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+#ifdef H5_HAVE_WIN_THREADS
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_win32_thread_exit
+ *
+ * RETURNS
+ * SUCCEED/FAIL
+ *
+ * DESCRIPTION
+ * Per-thread cleanup on Windows when using Win32 threads.
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TS_win32_thread_exit(void)
+{
+ LPVOID lpvData;
+ herr_t ret_value = SUCCEED;
+
+ /* Windows uses a different thread local storage mechanism which does
+ * not support auto-freeing like pthreads' keys.
+ *
+ * WARNING: Do NOT use C standard library functions here.
+ * CRT functions are not allowed in DllMain, which is where this code
+ * is used.
+ */
+
+ /* Clean up per-thread thread local storage */
+ lpvData = TlsGetValue(H5TS_errstk_key_g);
+ if(lpvData)
+ LocalFree((HLOCAL)lpvData);
+
+#ifdef H5_HAVE_CODESTACK
+ lpvData = TlsGetValue(H5TS_funcstk_key_g);
+ if(lpvData)
+ LocalFree((HLOCAL)lpvData);
+#endif /* H5_HAVE_CODESTACK */
+
+ return ret_value;
+} /* H5TS_win32_thread_exit() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_create_thread
+ *
+ * RETURNS
+ * Thread identifier.
+ *
+ * DESCRIPTION
+ * Spawn off a new thread calling function 'func' with input 'udata'.
+ *
+ * PROGRAMMER: Mike McGreevy
+ * August 31, 2010
+ *
+ *--------------------------------------------------------------------------
+ */
+H5TS_thread_t
+H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata)
+{
+ H5TS_thread_t ret_value;
+
+#ifdef H5_HAVE_WIN_THREADS
+
+ /* When calling C runtime functions, you should use _beginthread or
+ * _beginthreadex instead of CreateThread. Threads created with
+ * CreateThread risk being killed in low-memory situations. Since we
+ * only create threads in our test code, this is unlikely to be an issue
+ * and we'll use the easier-to-deal-with CreateThread for now.
+ *
+ * NOTE: _beginthread() auto-recycles its handle when execution completes
+ * so you can't wait on it, making it unsuitable for the existing
+ * test code.
+ */
+ ret_value = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, udata, 0, NULL);
+
+#else /* H5_HAVE_WIN_THREADS */
+
+ pthread_create(&ret_value, attr, (void * (*)(void *))func, udata);
+
+#endif /* H5_HAVE_WIN_THREADS */
+
+ return ret_value;
+
+} /* H5TS_create_thread */
+
+#endif /* H5_HAVE_THREADSAFE */
diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h
new file mode 100644
index 0000000..e5c41af
--- /dev/null
+++ b/src/H5TSprivate.h
@@ -0,0 +1,129 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5TSprivate.h
+ * May 2 2000
+ * Chee Wai LEE
+ *
+ * Purpose: Private non-prototype header.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef H5TSprivate_H_
+#define H5TSprivate_H_
+
+/* Public headers needed by this file */
+#ifdef LATER
+#include "H5TSpublic.h" /*Public API prototypes */
+#endif /* LATER */
+
+#ifdef H5_HAVE_WIN_THREADS
+
+/* Library level data structures */
+
+/* Mutexes, Threads, and Attributes */
+typedef struct H5TS_mutex_struct {
+ CRITICAL_SECTION CriticalSection;
+} H5TS_mutex_t;
+typedef CRITICAL_SECTION H5TS_mutex_simple_t;
+typedef HANDLE H5TS_thread_t;
+typedef HANDLE H5TS_attr_t;
+typedef DWORD H5TS_key_t;
+typedef INIT_ONCE H5TS_once_t;
+
+/* Defines */
+/* not used on windows side, but need to be defined to something */
+#define H5TS_SCOPE_SYSTEM 0
+#define H5TS_SCOPE_PROCESS 0
+#define H5TS_CALL_CONV WINAPI
+
+/* Functions */
+#define H5TS_get_thread_local_value(key) TlsGetValue( key )
+#define H5TS_set_thread_local_value(key, value) TlsSetValue( key, value )
+#define H5TS_attr_init(attr_ptr) 0
+#define H5TS_attr_setscope(attr_ptr, scope) 0
+#define H5TS_attr_destroy(attr_ptr) 0
+#define H5TS_wait_for_thread(thread) WaitForSingleObject(thread, INFINITE)
+#define H5TS_mutex_init(mutex) InitializeCriticalSection(mutex)
+#define H5TS_mutex_lock_simple(mutex) EnterCriticalSection(mutex)
+#define H5TS_mutex_unlock_simple(mutex) LeaveCriticalSection(mutex)
+
+/* Functions called from DllMain */
+H5_DLL BOOL CALLBACK H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex);
+H5_DLL void H5TS_win32_process_exit(void);
+H5_DLL herr_t H5TS_win32_thread_enter(void);
+H5_DLL herr_t H5TS_win32_thread_exit(void);
+
+
+
+#else /* H5_HAVE_WIN_THREADS */
+
+/* Library level data structures */
+
+/* Mutexes, Threads, and Attributes */
+typedef struct H5TS_mutex_struct {
+ pthread_t owner_thread; /* current lock owner */
+ pthread_mutex_t atomic_lock; /* lock for atomicity of new mechanism */
+ pthread_cond_t cond_var; /* condition variable */
+ unsigned int lock_count;
+} H5TS_mutex_t;
+typedef pthread_t H5TS_thread_t;
+typedef pthread_attr_t H5TS_attr_t;
+typedef pthread_mutex_t H5TS_mutex_simple_t;
+typedef pthread_key_t H5TS_key_t;
+typedef pthread_once_t H5TS_once_t;
+
+/* Scope Definitions */
+#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM
+#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS
+#define H5TS_CALL_CONV /* unused - Windows only */
+
+/* Functions */
+#define H5TS_get_thread_local_value(key) pthread_getspecific( key )
+#define H5TS_set_thread_local_value(key, value) pthread_setspecific( key, value )
+#define H5TS_attr_init(attr_ptr) pthread_attr_init((attr_ptr))
+#define H5TS_attr_setscope(attr_ptr, scope) pthread_attr_setscope(attr_ptr, scope)
+#define H5TS_attr_destroy(attr_ptr) pthread_attr_destroy(attr_ptr)
+#define H5TS_wait_for_thread(thread) pthread_join(thread, NULL)
+#define H5TS_mutex_init(mutex) pthread_mutex_init(mutex, NULL)
+#define H5TS_mutex_lock_simple(mutex) pthread_mutex_lock(mutex)
+#define H5TS_mutex_unlock_simple(mutex) pthread_mutex_unlock(mutex)
+
+#endif /* H5_HAVE_WIN_THREADS */
+
+/* External global variables */
+extern H5TS_once_t H5TS_first_init_g;
+extern H5TS_key_t H5TS_errstk_key_g;
+extern H5TS_key_t H5TS_funcstk_key_g;
+
+#if defined c_plusplus || defined __cplusplus
+extern "C"
+{
+#endif /* c_plusplus || __cplusplus */
+
+H5_DLL void H5TS_pthread_first_thread_init(void);
+H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex);
+H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex);
+H5_DLL herr_t H5TS_cancel_count_inc(void);
+H5_DLL herr_t H5TS_cancel_count_dec(void);
+H5_DLL H5TS_thread_t H5TS_create_thread(void *(*func)(void *), H5TS_attr_t * attr, void *udata);
+
+#if defined c_plusplus || defined __cplusplus
+}
+#endif /* c_plusplus || __cplusplus */
+
+#endif /* H5TSprivate_H_ */
diff --git a/src/H5Tarray.c b/src/H5Tarray.c
new file mode 100644
index 0000000..beccfdb
--- /dev/null
+++ b/src/H5Tarray.c
@@ -0,0 +1,427 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for array datatypes in
+ * the H5T interface.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tarray_create2
+ *
+ * Purpose: Create a new array datatype based on the specified BASE_TYPE.
+ * The type is an array with NDIMS dimensionality and the size of the
+ * array is DIMS. The total member size should be relatively small.
+ * Array datatypes are currently limited to H5S_MAX_RANK number of
+ * dimensions and must have the number of dimensions set greater than
+ * 0. (i.e. 0 > ndims <= H5S_MAX_RANK) All dimensions sizes must be greater
+ * than 0 also.
+ *
+ * Return: Success: ID of new array datatype
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Oct 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tarray_create2(hid_t base_id, unsigned ndims, const hsize_t dim[/* ndims */])
+{
+ H5T_t *base; /* base datatype */
+ H5T_t *dt = NULL; /* new array datatype */
+ unsigned u; /* local index variable */
+ hid_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "iIu*h", base_id, ndims, dim);
+
+ /* Check args */
+ if(ndims < 1 || ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid dimensionality")
+ if(!dim)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no dimensions specified")
+ for(u = 0; u < ndims; u++)
+ if(!(dim[u] > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "zero-sized dimension specified")
+ if(NULL == (base = (H5T_t *)H5I_object_verify(base_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+
+ /* Create the array datatype */
+ if(NULL == (dt = H5T__array_create(base, ndims, dim)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to create datatype")
+
+ /* Atomize the type */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ if(ret_value < 0) {
+ if(dt && H5T_close(dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "can't release datatype")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tarray_create2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__array_create
+ *
+ * Purpose: Internal routine to create a new array data type based on the
+ * specified BASE_TYPE. The type is an array with NDIMS dimensionality
+ * and the size of the array is DIMS.
+ * Array datatypes are currently limited to H5S_MAX_RANK number
+ * of dimensions.
+ *
+ * Return: Success: ID of new array data type
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Oct 26, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T__array_create(H5T_t *base, unsigned ndims, const hsize_t dim[/* ndims */])
+{
+ unsigned u; /* Local index variable */
+ H5T_t *ret_value = NULL; /* New array data type */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(base);
+ HDassert(ndims <= H5S_MAX_RANK);
+ HDassert(dim);
+
+ /* Build new type */
+ if(NULL == (ret_value = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ ret_value->shared->type = H5T_ARRAY;
+
+ /* Copy the base type of the array */
+ if(NULL == (ret_value->shared->parent = H5T_copy(base, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "unable to copy base datatype")
+
+ /* Set the array parameters */
+ ret_value->shared->u.array.ndims = ndims;
+
+ /* Copy the array dimensions & compute the # of elements in the array */
+ for(u = 0, ret_value->shared->u.array.nelem = 1; u < ndims; u++) {
+ H5_CHECKED_ASSIGN(ret_value->shared->u.array.dim[u], size_t, dim[u], hsize_t);
+ ret_value->shared->u.array.nelem *= (size_t)dim[u];
+ } /* end for */
+
+ /* Set the array's size (number of elements * element datatype's size) */
+ ret_value->shared->size = ret_value->shared->parent->shared->size * ret_value->shared->u.array.nelem;
+
+ /* Set the "force conversion" flag if the base datatype indicates */
+ if(base->shared->force_conv == TRUE)
+ ret_value->shared->force_conv = TRUE;
+
+ /* Array datatypes need a later version of the datatype object header message */
+ ret_value->shared->version = MAX(base->shared->version, H5O_DTYPE_VERSION_2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__array_create */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_array_ndims
+ *
+ * Purpose: Query the number of dimensions for an array datatype.
+ *
+ * Return: Success: Number of dimensions of the array datatype
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_array_ndims(hid_t type_id)
+{
+ H5T_t *dt; /* pointer to array datatype */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(dt->shared->type != H5T_ARRAY)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an array datatype")
+
+ /* Retrieve the number of dimensions */
+ ret_value = H5T__get_array_ndims(dt);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_array_ndims */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__get_array_ndims
+ *
+ * Purpose: Private function for H5T__get_array_ndims. Query the number
+ * of dimensions for an array datatype.
+ *
+ * Return: Success: Number of dimensions of the array datatype
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * October 10, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T__get_array_ndims(const H5T_t *dt)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(dt);
+ HDassert(dt->shared->type == H5T_ARRAY);
+
+ /* Retrieve the number of dimensions */
+ FUNC_LEAVE_NOAPI((int)dt->shared->u.array.ndims)
+} /* end H5T__get_array_ndims */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_array_dims2
+ *
+ * Purpose: Query the sizes of dimensions for an array datatype.
+ *
+ * Return: Success: Number of dimensions of the array type
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_array_dims2(hid_t type_id, hsize_t dims[])
+{
+ H5T_t *dt; /* pointer to array data type */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("Is", "i*h", type_id, dims);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(dt->shared->type != H5T_ARRAY)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an array datatype")
+
+ /* Retrieve the sizes of the dimensions */
+ if((ret_value = H5T__get_array_dims(dt, dims)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unable to get dimension sizes")
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_array_dims2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__get_array_dims
+ *
+ * Purpose: Private function for H5T__get_array_dims. Query the sizes
+ * of dimensions for an array datatype.
+ *
+ * Return: Success: Number of dimensions of the array type
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * October 10, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T__get_array_dims(const H5T_t *dt, hsize_t dims[])
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(dt);
+ HDassert(dt->shared->type == H5T_ARRAY);
+
+ /* Retrieve the sizes of the dimensions */
+ if(dims)
+ for(u = 0; u < dt->shared->u.array.ndims; u++)
+ dims[u] = dt->shared->u.array.dim[u];
+
+ /* Pass along the array rank as the return value */
+ FUNC_LEAVE_NOAPI((int)dt->shared->u.array.ndims)
+} /* end H5T__get_array_dims */
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tarray_create1
+ *
+ * Purpose: Create a new array datatype based on the specified BASE_TYPE.
+ * The type is an array with NDIMS dimensionality and the size of the
+ * array is DIMS. The total member size should be relatively small.
+ * Array datatypes are currently limited to H5S_MAX_RANK number of
+ * dimensions and must have the number of dimensions set greater than
+ * 0. (i.e. 0 > ndims <= H5S_MAX_RANK) All dimensions sizes must be greater
+ * than 0 also.
+ *
+ * Return: Success: ID of new array datatype
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, Oct 26, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tarray_create1(hid_t base_id, int ndims, const hsize_t dim[/* ndims */],
+ const int H5_ATTR_UNUSED perm[/* ndims */])
+{
+ H5T_t *base; /* base datatype */
+ H5T_t *dt = NULL; /* new array datatype */
+ unsigned u; /* local index variable */
+ hid_t ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("i", "iIs*h*Is", base_id, ndims, dim, perm);
+
+ /* Check args */
+ if(ndims < 1 || ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid dimensionality")
+ if(!dim)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no dimensions specified")
+ for(u = 0; u < (unsigned)ndims; u++)
+ if(!(dim[u] > 0))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "zero-sized dimension specified")
+ if(NULL == (base = (H5T_t *)H5I_object_verify(base_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+
+ /* Create the array datatype */
+ if(NULL == (dt = H5T__array_create(base, (unsigned)ndims, dim)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to create datatype")
+
+ /* Atomize the type */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ if(ret_value < 0) {
+ if(dt && H5T_close(dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, FAIL, "can't release datatype")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tarray_create1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_array_dims1
+ *
+ * Purpose: Query the sizes of dimensions for an array datatype.
+ *
+ * Return: Success: Number of dimensions of the array type
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_array_dims1(hid_t type_id, hsize_t dims[], int H5_ATTR_UNUSED perm[])
+{
+ H5T_t *dt; /* Array datatype to query */
+ int ret_value; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Is", "i*h*Is", type_id, dims, perm);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object")
+ if(dt->shared->type != H5T_ARRAY)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an array datatype")
+
+ /* Retrieve the sizes of the dimensions */
+ if((ret_value = H5T__get_array_dims(dt, dims)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unable to get dimension sizes")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_array_dims1() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Tbit.c b/src/H5Tbit.c
new file mode 100644
index 0000000..12d1fd1
--- /dev/null
+++ b/src/H5Tbit.c
@@ -0,0 +1,712 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: Operations on bit vectors. A bit vector is an array of bytes
+ * with the least-significant bits in the first byte. That is,
+ * the bytes are in little-endian order.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Tpkg.h" /*data-type functions */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_copy
+ *
+ * Purpose: Copies bits from one vector to another.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 10, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5T__bit_copy(uint8_t *dst, size_t dst_offset, const uint8_t *src,
+ size_t src_offset, size_t size)
+{
+ size_t shift;
+ size_t mask_lo, mask_hi;
+ size_t s_idx, d_idx;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /*
+ * Normalize the offset to be a byte number and a bit offset within that
+ * byte.
+ */
+ s_idx = src_offset / 8;
+ d_idx = dst_offset / 8;
+ src_offset %= 8;
+ dst_offset %= 8;
+
+ /*
+ * Get things rolling. This means copying bits until we're aligned on a
+ * source byte. This the following example, five bits are copied to the
+ * destination.
+ *
+ * src[s_idx]
+ * +---------------+---------------+
+ * |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ * +---------------+---------------+
+ * ... : : : : : | | | | |
+ * ... v v v v v V V V V V
+ * ...+---------------+---------------+
+ * ...|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ * ...+---------------+---------------+
+ * dst[d_idx+1] dst[d_idx]
+ */
+ while(src_offset && size > 0) {
+ size_t nbits = MIN3(size, 8 - dst_offset, 8 - src_offset);
+ size_t mask = ((size_t)1 << nbits) - 1;
+
+ dst[d_idx] &= (uint8_t)~(mask << dst_offset);
+ dst[d_idx] = (uint8_t)(dst[d_idx] | (((src[s_idx] >> src_offset) & (uint8_t)mask) << dst_offset));
+
+ src_offset += nbits;
+ if(src_offset >= 8) {
+ s_idx++;
+ src_offset %= 8;
+ } /* end if */
+
+ dst_offset += nbits;
+ if(dst_offset >= 8) {
+ d_idx++;
+ dst_offset %= 8;
+ } /* end if */
+
+ size -= nbits;
+ } /* end while */
+
+ /*
+ * The middle bits. We are aligned on a source byte which needs to be
+ * copied to two (or one in the degenerate case) destination bytes.
+ *
+ * src[s_idx]
+ * +---------------+
+ * |7 6 5 4 3 2 1 0|
+ * +---------------+
+ * | | | | | | | |
+ * V V V V V V V V
+ * +---------------+---------------+
+ * |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ * +---------------+---------------+
+ * dst[d_idx+1] dst[d_idx]
+ *
+ *
+ * Calculate shifts and masks. See diagrams below. MASK_LO in this
+ * example is 0x1f (the low five bits) and MASK_HI is 0xe0 (the high three
+ * bits). SHIFT is three since the source must be shifted right three bits
+ * to line up with the destination.
+ */
+ shift = dst_offset;
+ mask_lo = ((size_t)1 << (8 - shift)) - 1;
+ mask_hi = (~mask_lo) & 0xff;
+
+ for(/*void*/; size > 8; size -= 8, d_idx++, s_idx++) {
+ if(shift) {
+ dst[d_idx + 0] &= (uint8_t)(~(mask_lo << shift));
+ dst[d_idx + 0] |= (uint8_t)((src[s_idx] & mask_lo) << shift);
+ dst[d_idx + 1] &= (uint8_t)(~(mask_hi >> (8 - shift)));
+ dst[d_idx + 1] |= (uint8_t)((src[s_idx] & mask_hi) >> (8 - shift));
+ } /* end if */
+ else
+ dst[d_idx] = src[s_idx];
+ } /* end for */
+
+ /* Finish up */
+ while(size > 0) {
+ size_t nbits = (size_t)MIN3 (size, 8 - dst_offset, 8 - src_offset);
+ size_t mask = ((size_t)1 << nbits) - 1;
+
+ dst[d_idx] &= (uint8_t)(~(mask << dst_offset));
+ dst[d_idx] = (uint8_t)(dst[d_idx] | (((src[s_idx] >> src_offset) & (uint8_t)mask) << dst_offset));
+
+ src_offset += nbits;
+ if(src_offset >= 8) {
+ s_idx++;
+ src_offset %= 8;
+ } /* end if */
+
+ dst_offset += nbits;
+ if(dst_offset >= 8) {
+ d_idx++;
+ dst_offset %= 8;
+ } /* end if */
+
+ size -= nbits;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5T__bit_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_shift
+ *
+ * Purpose: Simulation of hardware shifting. Shifts a bit vector
+ * in a way similar to shifting a variable value, like
+ * value <<= 3, or value >>= 16. SHIFT_DIST is positive for
+ * left shift, negative for right shift. The bit vector starts
+ * at OFFSET and is SIZE long. The caller has to make sure
+ * SIZE+OFFSET doesn't exceed the size of BUF.
+ *
+ * For example, if we have a bit sequence 00011100, offset=2,
+ * size=3, shift_dist=2, the result will be 00010000.
+ *
+ * Return: void
+ *
+ * Programmer: Raymond Lu
+ * Monday, April 12, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__bit_shift(uint8_t *buf, ssize_t shift_dist, size_t offset, size_t size)
+{
+ uint8_t tmp_buf[512]; /* Temporary buffer */
+ H5WB_t *wb = NULL; /* Wrapped buffer for temporary buffer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(buf);
+ HDassert(size);
+
+ if(shift_dist) {
+ size_t abs_shift_dist = (size_t)ABS(shift_dist);
+
+ if(abs_shift_dist >= size)
+ H5T__bit_set(buf, offset, size, 0);
+ else {
+ size_t buf_size = (size / 8) + 1; /* Size of shift buffer needed */
+ uint8_t *shift_buf; /* Pointer to shift buffer */
+
+ /* Wrap the local buffer for serialized header info */
+ if(NULL == (wb = H5WB_wrap(tmp_buf, sizeof(tmp_buf))))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough */
+ if(NULL == (shift_buf = (uint8_t *)H5WB_actual(wb, buf_size)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Shift vector by making copies */
+ if(shift_dist > 0) { /* left shift */
+ /* Copy part to be shifted to a temporary buffer */
+ H5T__bit_copy(shift_buf, (size_t)0, buf, offset, size - abs_shift_dist);
+
+ /* Copy it back to the original buffer */
+ H5T__bit_copy(buf, offset + abs_shift_dist, shift_buf, (size_t)0, size - abs_shift_dist);
+
+ /* Zero-set the left part*/
+ H5T__bit_set(buf, offset, abs_shift_dist, 0);
+ } /* end if */
+ else { /* right shift */
+ H5T__bit_copy(shift_buf, (size_t)0, buf, offset + abs_shift_dist, size - abs_shift_dist);
+ H5T__bit_copy(buf, offset, shift_buf, (size_t)0, size - abs_shift_dist);
+ H5T__bit_set(buf, offset + size - abs_shift_dist, abs_shift_dist, 0);
+ } /* end else */
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__bit_shift() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_get_d
+ *
+ * Purpose: Return a small bit sequence as a number. Bit vector starts
+ * at OFFSET and is SIZE bits long.
+ *
+ * Return: Success: The bit sequence interpretted as an unsigned
+ * integer.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 23, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+uint64_t
+H5T__bit_get_d(uint8_t *buf, size_t offset, size_t size)
+{
+ uint64_t val = 0;
+ size_t i, hs;
+ uint64_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(8 * sizeof(val) >= size);
+
+ H5T__bit_copy((uint8_t*)&val, (size_t)0, buf, offset, size);
+ switch(H5T_native_order_g) {
+ case H5T_ORDER_LE:
+ break;
+
+ case H5T_ORDER_BE:
+ for(i = 0, hs = sizeof(val) / 2; i < hs; i++) {
+ uint8_t tmp = ((uint8_t*)&val)[i];
+ ((uint8_t*)&val)[i] = ((uint8_t*)&val)[sizeof(val) - (i + 1)];
+ ((uint8_t*)&val)[sizeof(val) - (i + 1)] = tmp;
+ } /* end for */
+ break;
+
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_NONE:
+ case H5T_ORDER_MIXED:
+ default:
+ /* Unknown endianness. Bail out. */
+ HGOTO_DONE(UFAIL)
+ } /* end switch */
+
+ /* Set return value */
+ ret_value = val;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__bit_get_d() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_set_d
+ *
+ * Purpose: Sets part of a bit vector to the specified unsigned value.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 24, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5T__bit_set_d(uint8_t *buf, size_t offset, size_t size, uint64_t val)
+{
+ size_t i, hs;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(8 * sizeof(val) >= size);
+
+ switch(H5T_native_order_g) {
+ case H5T_ORDER_LE:
+ break;
+
+ case H5T_ORDER_BE:
+ for(i = 0, hs = sizeof(val) / 2; i < hs; i++) {
+ uint8_t tmp = ((uint8_t *)&val)[i];
+ ((uint8_t *)&val)[i] = ((uint8_t *)&val)[sizeof(val) - (i + 1)];
+ ((uint8_t *)&val)[sizeof(val) - (i + 1)] = tmp;
+ } /* end for */
+ break;
+
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_NONE:
+ case H5T_ORDER_MIXED:
+ default:
+ HDabort();
+ } /* end switch */
+
+ H5T__bit_copy(buf, offset, (uint8_t*)&val, (size_t)0, size);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5T__bit_set_d() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_set
+ *
+ * Purpose: Sets or clears bits in a contiguous region of a vector
+ * beginning at bit OFFSET and continuing for SIZE bits.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 10, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5T__bit_set(uint8_t *buf, size_t offset, size_t size, hbool_t value)
+{
+ int idx;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Normalize */
+ idx = (int)offset / 8;
+ offset %= 8;
+
+ /* The first partial byte */
+ if(size && offset % 8) {
+ size_t nbits = MIN(size, 8 - offset);
+ unsigned mask = ((unsigned)1 << nbits) - 1;
+
+ if(value)
+ buf[idx] = (uint8_t)(buf[idx] | (mask << offset));
+ else
+ buf[idx] &= (uint8_t)(~(mask << offset));
+
+ idx++;
+ size -= nbits;
+ } /* end if */
+
+ /* The middle bytes */
+ while(size >= 8) {
+ buf[idx++] = value ? 0xff : 0x00;
+ size -= 8;
+ } /* end while */
+
+ /* The last partial byte */
+ if(size) {
+ if(value)
+ buf[idx] |= (uint8_t)(((unsigned)1 << size) - 1);
+ else
+ buf[idx] &= (uint8_t)(~(((unsigned)1 << size) - 1));
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5T__bit_set() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_find
+ *
+ * Purpose: Finds the first bit with the specified VALUE within a region
+ * of a bit vector. The region begins at OFFSET and continues
+ * for SIZE bits, but the region can be searched from the least
+ * significat end toward the most significant end(H5T_BIT_LSB
+ * as DIRECTION), or from the most significant end to the least
+ * significant end(H5T_BIT_MSB as DIRECTION).
+ *
+ * Return: Success: The position of the bit found, relative to
+ * the offset.
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 10, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5T__bit_find(uint8_t *buf, size_t offset, size_t size, H5T_sdir_t direction,
+ hbool_t value)
+{
+ ssize_t base = (ssize_t)offset;
+ ssize_t idx, i;
+ size_t iu;
+ ssize_t ret_value = (-1); /* Return value */
+
+ /* Use FUNC_ENTER_PACKAGE_NOERR here to avoid performance issues */
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Some functions call this with value=TRUE */
+ HDassert(TRUE == 1);
+
+ switch(direction) {
+ case H5T_BIT_LSB:
+ /* Calculate index */
+ idx = (ssize_t)(offset / 8);
+ offset %= 8;
+
+ /* Beginning */
+ if(offset) {
+ for(iu = offset; iu < 8 && size > 0; iu++, size--)
+ if(value == (hbool_t)((buf[idx] >> iu) & 0x01))
+ HGOTO_DONE(8 * idx + (ssize_t)iu - base);
+
+ offset = 0;
+ idx++;
+ } /* end if */
+
+ /* Middle */
+ while(size >= 8) {
+ if((value ? 0x00 : 0xff) != buf[idx])
+ for(i = 0; i < 8; i++)
+ if(value == (hbool_t)((buf[idx] >> i) & 0x01))
+ HGOTO_DONE(8 * idx + i - base);
+
+ size -= 8;
+ idx++;
+ } /* end while */
+
+ /* End */
+ for(i = 0; i < (ssize_t)size; i++)
+ if(value == (hbool_t)((buf[idx] >> i) & 0x01))
+ HGOTO_DONE(8 * idx + i - base);
+ break;
+
+ case H5T_BIT_MSB:
+ /* Calculate index */
+ idx = (ssize_t)((offset + size - 1) / 8);
+ offset %= 8;
+
+ /* Beginning */
+ if(size > 8 - offset && (offset + size) % 8) {
+ for(iu = (offset + size) % 8; iu > 0; --iu, --size)
+ if(value == (hbool_t)((buf[idx] >> (iu - 1)) & 0x01))
+ HGOTO_DONE(8 * idx + (ssize_t)(iu - 1) - base);
+
+ --idx;
+ } /* end if */
+
+ /* Middle */
+ while(size >= 8) {
+ if((value ? 0x00 : 0xff) != buf[idx]) {
+ for(i = 7; i >= 0; --i)
+ if(value == (hbool_t)((buf[idx] >> i) & 0x01))
+ HGOTO_DONE(8 * idx + i - base);
+ } /* end if */
+
+ size -= 8;
+ --idx;
+ } /* end while */
+
+ /* End */
+ if(size > 0) {
+ for(iu = offset + size; iu > offset; --iu)
+ if(value == (hbool_t)((buf[idx] >> (iu - 1)) & 0x01))
+ HGOTO_DONE(8 * idx + (ssize_t)(iu - 1) - base);
+ } /* end if */
+ break;
+
+ default:
+ HDassert(0 && "Unknown bit search direction");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__bit_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_inc
+ *
+ * Purpose: Increment part of a bit field by adding 1. The bit field
+ * starts with bit position START and is SIZE bits long.
+ *
+ * Return: The carry-out value. TRUE if overflows, FALSE otherwise.
+ *
+ * Programmer: Robb Matzke
+ * Friday, June 26, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5T__bit_inc(uint8_t *buf, size_t start, size_t size)
+{
+ size_t idx = start / 8;
+ unsigned carry = 1;
+ unsigned acc, mask;
+
+ /* Use FUNC_ENTER_PACKAGE_NOERR here to avoid performance issues */
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(buf);
+
+ start %= 8;
+
+ /* The first partial byte */
+ if(start) {
+ if(size + start < 8)
+ mask = ((unsigned)1 << size) - 1;
+ else
+ mask = ((unsigned)1 << (8 - start)) - 1;
+ acc = ((unsigned)buf[idx] >> start) & mask;
+ acc++;
+ carry = acc & ((unsigned)1 << MIN(size, 8 - start));
+ buf[idx] &= (uint8_t)(~(mask << start));
+ buf[idx] = (uint8_t)(buf[idx] | ((acc & mask) << start));
+ size -= MIN(size, 8 - start);
+ start = 0;
+ idx++;
+ } /* end if */
+
+ /* The middle */
+ while(carry && size >= 8) {
+ acc = buf[idx];
+ acc++;
+ carry = acc & 0x100;
+ buf[idx] = acc & 0xff;
+ idx++;
+ size -= 8;
+ } /* end while */
+
+ /* The last bits */
+ if(carry && size > 0) {
+ mask = ((unsigned)1 << size) - 1;
+ acc = buf[idx] & mask;
+ acc++;
+ carry = acc & ((unsigned)1 << size);
+ buf[idx] &= (uint8_t)(~mask);
+ buf[idx] |= (uint8_t)(acc & mask);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(carry ? TRUE : FALSE)
+} /* end H5T__bit_inc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_dec
+ *
+ * Purpose: Decrement part of a bit field by substracting 1. The bit
+ * field starts with bit position START and is SIZE bits long.
+ *
+ * Return: The "borrow-in" value. It's TRUE if underflows, FALSE
+ * otherwise.
+ *
+ * Programmer: Raymond Lu
+ * March 17, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5T__bit_dec(uint8_t *buf, size_t start, size_t size)
+{
+ size_t idx = start / 8;
+ size_t pos = start % 8;
+ uint8_t tmp;
+ unsigned borrow = 0;
+
+ /* Use FUNC_ENTER_PACKAGE_NOERR here to avoid performance issues */
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(buf);
+ HDassert(size);
+
+ /* The first partial byte */
+ if((size + start - 1) / 8 > idx) { /*bit sequence doesn't end in the same byte as starts*/
+ /* Example: a sequence like 11000100 and start = 3. We substract 00001000 from
+ * it and get 10111100. If a sequence is 00000111, we do right shift for START
+ * bits and get 00000000. So we need to borrow from higher byte when we substract
+ * 00001000.
+ */
+ if(!(buf[idx] >> pos))
+ borrow = 1;
+ buf[idx] = (uint8_t)(buf[idx] - (1 << pos));
+ idx++;
+ size -= (8 - pos);
+
+ /* The middle bytes */
+ while(borrow && size >= 8) {
+ if(buf[idx])
+ borrow = 0;
+ buf[idx]--;
+
+ idx++;
+ size -= 8;
+ } /* end while */
+
+ /* The last partial byte */
+ if(borrow && size > 0) {
+ /* Similar to the first byte case, where sequence ends in the same byte as starts */
+ tmp = buf[idx];
+ buf[idx]--;
+ if((buf[idx] >> size) != tmp >> size)
+ buf[idx] = (uint8_t)(buf[idx] + (1 << size));
+ } /* end if */
+ } /* end if */
+ else { /* bit sequence ends in the same byte as starts */
+ /* Example: a sequence like 11000100 and pos=3, size=3. We substract 00001000
+ * and get 10111100. A bit is borrowed from 6th bit(buf[idx]>>6=00000010, tmp>>6=00000011,
+ * not equal). We need to put this bit back by increment 1000000.
+ */
+ tmp = buf[idx];
+ buf[idx] = (uint8_t)(buf[idx] - (1 << pos));
+ if((buf[idx] >> (pos + size)) != tmp >> (pos + size)) {
+ buf[idx] = (uint8_t)(buf[idx] + (1 << (pos + size)));
+ borrow = 1;
+ } /* end if */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(borrow ? TRUE : FALSE)
+} /* end H5T__bit_dec() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__bit_neg
+ *
+ * Purpose: negate part of a bit sequence. The bit
+ * field starts with bit position START and is SIZE bits long.
+ *
+ * Return: void
+ *
+ * Programmer: Raymond Lu
+ * March 19, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5T__bit_neg(uint8_t *buf, size_t start, size_t size)
+{
+ size_t idx = start / 8;
+ size_t pos = start % 8;
+ uint8_t tmp[1];
+
+ /* Use FUNC_ENTER_PACKAGE_NOERR here to avoid performance issues */
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(buf);
+ HDassert(size);
+
+ /* The first partial byte */
+ tmp[0] = (uint8_t)~buf[idx];
+
+ /* Simply copy the negated bit field back to the original byte */
+ if((size + start - 1) / 8 > idx) { /*bit sequence doesn't end in the same byte as starts*/
+ H5T__bit_copy(&(buf[idx]), pos, tmp, pos, (8-pos));
+ idx++;
+ size -= (8 - pos);
+
+ /* The middle bytes */
+ while(size >= 8) {
+ buf[idx] = (uint8_t)~(buf[idx]);
+ idx++;
+ size -= 8;
+ } /* end while */
+
+ /* The last partial byte */
+ if(size > 0) {
+ /* Similar to the first byte case, where sequence ends in the same byte as starts */
+ tmp[0] = (uint8_t)~buf[idx];
+ H5T__bit_copy(&(buf[idx]), (size_t)0, tmp, (size_t)0, size);
+ } /* end if */
+ } /* end if */
+ else /* bit sequence ends in the same byte as starts */
+ H5T__bit_copy(&(buf[idx]), pos, tmp, pos, size);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5T__bit_neg() */
+
diff --git a/src/H5Tcommit.c b/src/H5Tcommit.c
new file mode 100644
index 0000000..c28b508
--- /dev/null
+++ b/src/H5Tcommit.c
@@ -0,0 +1,854 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for committing datatypes
+ * to a file for the H5T interface.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static H5T_t *H5T_open_oid(const H5G_loc_t *loc, hid_t dxpl_id);
+
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcommit2
+ *
+ * Purpose: Save a transient datatype to a file and turn the type handle
+ * into a "named", immutable type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tcommit2(hid_t loc_id, const char *name, hid_t type_id, hid_t lcpl_id,
+ hid_t tcpl_id, hid_t tapl_id)
+{
+ H5G_loc_t loc; /* Location to create datatype */
+ H5T_t *type; /* Datatype for ID */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "i*siiii", loc_id, name, type_id, lcpl_id, tcpl_id, tapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == lcpl_id)
+ lcpl_id = H5P_LINK_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == tcpl_id)
+ tcpl_id = H5P_DATATYPE_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(tcpl_id, H5P_DATATYPE_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not datatype creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&tapl_id, H5P_CLS_TACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Commit the type */
+ if(H5T__commit_named(&loc, name, type, lcpl_id, tcpl_id, tapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to commit datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcommit2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__commit_named
+ *
+ * Purpose: Internal routine to save a transient datatype to a file and
+ * turn the type ID into a "named", immutable type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * April 5, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__commit_named(const H5G_loc_t *loc, const char *name, H5T_t *dt,
+ hid_t lcpl_id, hid_t tcpl_id, hid_t tapl_id, hid_t dxpl_id)
+{
+ H5O_obj_create_t ocrt_info; /* Information for object creation */
+ H5T_obj_create_t tcrt_info; /* Information for named datatype creation */
+ H5T_state_t old_state; /* The state of the datatype before H5T__commit. */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity checks */
+ HDassert(loc);
+ HDassert(name && *name);
+ HDassert(dt);
+ HDassert(lcpl_id != H5P_DEFAULT);
+ HDassert(tcpl_id != H5P_DEFAULT);
+ HDassert(tapl_id != H5P_DEFAULT);
+ HDassert(dxpl_id != H5P_DEFAULT);
+
+ /* Record the type's state so that we can revert to it if linking fails */
+ old_state = dt->shared->state;
+
+ /* Set up named datatype creation info */
+ tcrt_info.dt = dt;
+ tcrt_info.tcpl_id = tcpl_id;
+
+ /* Set up object creation information */
+ ocrt_info.obj_type = H5O_TYPE_NAMED_DATATYPE;
+ ocrt_info.crt_info = &tcrt_info;
+ ocrt_info.new_obj = NULL;
+
+ /* Create the new named datatype and link it to its parent group */
+ if(H5L_link_object(loc, name, &ocrt_info, lcpl_id, tapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to create and link to named datatype")
+ HDassert(ocrt_info.new_obj);
+
+done:
+ /* If the datatype was committed but something failed after that, we need
+ * to return it to the state it was in before it was committed.
+ */
+ if(ret_value < 0 && (NULL != ocrt_info.new_obj)) {
+ if(dt->shared->state == H5T_STATE_OPEN && dt->sh_loc.type == H5O_SHARE_TYPE_COMMITTED) {
+ /* Remove the datatype from the list of opened objects in the file */
+ if(H5FO_top_decr(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't decrement count for object")
+ if(H5FO_delete(dt->sh_loc.file, dxpl_id, dt->sh_loc.u.loc.oh_addr) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't remove dataset from list of open objects")
+
+ /* Close the datatype object */
+ if(H5O_close(&(dt->oloc), NULL) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to release object header")
+
+ /* Remove the datatype's object header from the file */
+ if(H5O_delete(dt->sh_loc.file, dxpl_id, dt->sh_loc.u.loc.oh_addr) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTDELETE, FAIL, "unable to delete object header")
+
+ /* Mark datatype as being back in memory */
+ if(H5T_set_loc(dt, dt->sh_loc.file, H5T_LOC_MEMORY))
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTDELETE, FAIL, "unable to return datatype to memory")
+ dt->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
+ dt->shared->state = old_state;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__commit_named() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcommit_anon
+ *
+ * Purpose: Save a transient datatype to a file and turn the type handle
+ * into a "named", immutable type.
+ *
+ * The resulting ID should be linked into the file with
+ * H5Olink or it will be deleted when closed.
+ *
+ * Note: Datatype access property list is unused currently, but is
+ * checked for sanity anyway.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Peter Cao
+ * May 17, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tcommit_anon(hid_t loc_id, hid_t type_id, hid_t tcpl_id, hid_t tapl_id)
+{
+ H5G_loc_t loc; /* Group location for location */
+ H5T_t *type = NULL; /* Datatype created */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iiii", loc_id, type_id, tcpl_id, tapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get correct property list */
+ if(H5P_DEFAULT == tcpl_id)
+ tcpl_id = H5P_DATATYPE_CREATE_DEFAULT;
+ else
+ if(TRUE != H5P_isa_class(tcpl_id, H5P_DATATYPE_CREATE))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not datatype creation property list")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&tapl_id, H5P_CLS_TACC, &dxpl_id, loc_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Commit the type */
+ if(H5T__commit(loc.oloc->file, type, tcpl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to commit datatype")
+
+ /* Release the datatype's object header */
+ {
+ H5O_loc_t *oloc; /* Object location for datatype */
+
+ /* Get the new committed datatype's object location */
+ if(NULL == (oloc = H5T_oloc(type)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to get object location of committed datatype")
+
+ /* Decrement refcount on committed datatype's object header in memory */
+ if(H5O_dec_rc_by_loc(oloc, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcommit_anon() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__commit
+ *
+ * Purpose: Commit a type, giving it a name and causing it to become
+ * immutable.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, June 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__commit(H5F_t *file, H5T_t *type, hid_t tcpl_id, hid_t dxpl_id)
+{
+ H5O_loc_t temp_oloc; /* Temporary object header location */
+ H5G_name_t temp_path; /* Temporary path */
+ hbool_t loc_init = FALSE; /* Have temp_oloc and temp_path been initialized? */
+ size_t dtype_size; /* Size of the datatype message */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(file);
+ HDassert(type);
+ HDassert(tcpl_id != H5P_DEFAULT);
+
+ /* Check if we are allowed to write to this file */
+ if(0 == (H5F_INTENT(file) & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "no write intent on file")
+
+ /*
+ * Check arguments. We cannot commit an immutable type because H5Tclose()
+ * normally fails on such types (try H5Tclose(H5T_NATIVE_INT)) but closing
+ * a named type should always succeed.
+ */
+ if(H5T_STATE_NAMED == type->shared->state || H5T_STATE_OPEN == type->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "datatype is already committed")
+ if(H5T_STATE_IMMUTABLE == type->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "datatype is immutable")
+
+ /* Check for a "sensible" datatype to store on disk */
+ if(H5T_is_sensible(type) <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "datatype is not sensible")
+
+ /* Mark datatype as being on disk now. This step changes the size of
+ * datatype as stored on disk.
+ */
+ if(H5T_set_loc(type, file, H5T_LOC_DISK) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype on disk")
+
+ /* Reset datatype location and path */
+ if(H5O_loc_reset(&temp_oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize location")
+ if(H5G_name_reset(&temp_path) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize path")
+ loc_init = TRUE;
+
+ /* Set the latest format, if requested */
+ if(H5F_USE_LATEST_FLAGS(file, H5F_LATEST_DATATYPE))
+ if(H5T_set_latest_version(type) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set latest version of datatype")
+
+ /* Calculate message size infomation, for creating object header */
+ dtype_size = H5O_msg_size_f(file, tcpl_id, H5O_DTYPE_ID, type, (size_t)0);
+ HDassert(dtype_size);
+
+ /*
+ * Create the object header and open it for write access. Insert the data
+ * type message and then give the object header a name.
+ */
+ if(H5O_create(file, dxpl_id, dtype_size, (size_t)1, tcpl_id, &temp_oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to create datatype object header")
+ if(H5O_msg_create(&temp_oloc, H5O_DTYPE_ID, H5O_MSG_FLAG_CONSTANT | H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to update type header message")
+
+ /* Copy the new object header's location into the datatype, taking ownership of it */
+ if(H5O_loc_copy(&(type->oloc), &temp_oloc, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy datatype location")
+ if(H5G_name_copy(&(type->path), &temp_path, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy datatype location")
+ loc_init = FALSE;
+
+ /* Set the shared info fields */
+ H5T_update_shared(type);
+ type->shared->state = H5T_STATE_OPEN;
+ type->shared->fo_count = 1;
+
+ /* Add datatype to the list of open objects in the file */
+ if(H5FO_top_incr(type->sh_loc.file, type->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINC, FAIL, "can't incr object ref. count")
+ if(H5FO_insert(type->sh_loc.file, type->sh_loc.u.loc.oh_addr, type->shared, TRUE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "can't insert datatype into list of open objects")
+
+ /* Mark datatype as being on memory again. Since this datatype may still be
+ * used in memory after committed to disk, change its size back as in memory.
+ */
+ if(H5T_set_loc(type, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "cannot mark datatype in memory")
+
+done:
+ if(ret_value < 0) {
+ if(loc_init) {
+ H5O_loc_free(&temp_oloc);
+ H5G_name_free(&temp_path);
+ } /* end if */
+ if((type->shared->state == H5T_STATE_TRANSIENT || type->shared->state == H5T_STATE_RDONLY) && (type->sh_loc.type == H5O_SHARE_TYPE_COMMITTED)) {
+ if(H5O_dec_rc_by_loc(&(type->oloc), dxpl_id) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+ if(H5O_close(&(type->oloc), NULL) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to release object header")
+ if(H5O_delete(file, dxpl_id, type->sh_loc.u.loc.oh_addr) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTDELETE, FAIL, "unable to delete object header")
+ type->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5T__commit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcommitted
+ *
+ * Purpose: Determines if a datatype is committed or not.
+ *
+ * Return: Success: TRUE if committed, FALSE otherwise.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tcommitted(hid_t type_id)
+{
+ H5T_t *type; /* Datatype to query */
+ htri_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "i", type_id);
+
+ /* Check arguments */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Set return value */
+ ret_value = H5T_committed(type);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcommitted() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_committed
+ *
+ * Purpose: Determines if a datatype is committed or not.
+ *
+ * Return: Success: TRUE if committed, FALSE otherwise.
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 24, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T_committed(const H5T_t *type)
+{
+ /* Use no-init for efficiency */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(type);
+
+ FUNC_LEAVE_NOAPI(H5T_STATE_OPEN == type->shared->state || H5T_STATE_NAMED == type->shared->state)
+} /* end H5T_committed() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_link
+ *
+ * Purpose: Adjust the link count for an object header by adding
+ * ADJUST to the link count.
+ *
+ * Return: Success: New link count
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 26, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_link(const H5T_t *type, int adjust, hid_t dxpl_id)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(type);
+ HDassert(type->sh_loc.type == H5O_SHARE_TYPE_COMMITTED);
+
+ /* Adjust the link count on the named datatype */
+ if((ret_value = H5O_link(&type->oloc, adjust, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_LINKCOUNT, FAIL, "unable to adjust named datatype link count")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_link() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Topen2
+ *
+ * Purpose: Opens a named datatype using a Datatype Access Property
+ * List.
+ *
+ * Return: Success: Object ID of the named datatype.
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Thursday July 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Topen2(hid_t loc_id, const char *name, hid_t tapl_id)
+{
+ H5T_t *type = NULL; /* Datatype opened in file */
+ H5G_loc_t loc; /* Group location of object to open */
+ H5G_name_t path; /* Datatype group hier. path */
+ H5O_loc_t oloc; /* Datatype object location */
+ H5O_type_t obj_type; /* Type of object at location */
+ H5G_loc_t type_loc; /* Group object for datatype */
+ hbool_t obj_found = FALSE; /* Object at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl to use to open datatype */
+ hid_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("i", "i*si", loc_id, name, tapl_id);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Verify access property list and get correct dxpl */
+ if(H5P_verify_apl_and_dxpl(&tapl_id, H5P_CLS_TACC, &dxpl_id, loc_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
+
+ /* Set up datatype location to fill in */
+ type_loc.oloc = &oloc;
+ type_loc.path = &path;
+ H5G_loc_reset(&type_loc);
+
+ /*
+ * Find the named datatype object header and read the datatype message
+ * from it.
+ */
+ if(H5G_loc_find(&loc, name, &type_loc/*out*/, tapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "not found")
+ obj_found = TRUE;
+
+ /* Check that the object found is the correct type */
+ if(H5O_obj_type(&oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get object type")
+ if(obj_type != H5O_TYPE_NAMED_DATATYPE)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a named datatype")
+
+ /* Open it */
+ if(NULL == (type = H5T_open(&type_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype")
+
+ /* Register the type and return the ID */
+ if((ret_value = H5I_register(H5I_DATATYPE, type, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register named datatype")
+
+done:
+ if(ret_value < 0) {
+ if(type != NULL)
+ H5T_close(type);
+ else {
+ if(obj_found && H5F_addr_defined(type_loc.oloc->addr))
+ H5G_loc_free(&type_loc);
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Topen2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_create_plist
+ *
+ * Purpose: Returns a copy of the datatype creation property list.
+ *
+ * Return: Success: ID for a copy of the datatype creation
+ * property list. The property list ID should be
+ * released by calling H5Pclose().
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tget_create_plist(hid_t dtype_id)
+{
+ H5T_t *type; /* Datatype object for ID */
+ H5P_genplist_t *tcpl_plist; /* Existing datatype creation propertty list */
+ hid_t new_tcpl_id = FAIL; /* New datatype creation property list */
+ herr_t status; /* Generic status value */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", dtype_id);
+
+ /* Check arguments */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(dtype_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Copy the default datatype creation property list */
+ if(NULL == (tcpl_plist = (H5P_genplist_t *)H5I_object(H5P_LST_DATATYPE_CREATE_ID_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get default creation property list")
+ if((new_tcpl_id = H5P_copy_plist(tcpl_plist, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to copy the creation property list")
+
+ /* Check if the datatype is committed */
+ if((status = H5T_committed(type)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't check whether datatype is committed")
+
+ /* Retrieve further information, if the datatype is committed */
+ if(status > 0) {
+ H5P_genplist_t *new_plist; /* New datatype creation property list */
+
+ /* Get property list object for new TCPL */
+ if(NULL == (new_plist = (H5P_genplist_t *)H5I_object(new_tcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Retrieve any object creation properties */
+ if(H5O_get_create_plist(&type->oloc, H5AC_ind_read_dxpl_id, new_plist) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get object creation info")
+ } /* end if */
+
+ /* Set the return value */
+ ret_value = new_tcpl_id;
+
+done:
+ if(ret_value < 0)
+ if(new_tcpl_id > 0)
+ if(H5I_dec_app_ref(new_tcpl_id) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "unable to close temporary object")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_create_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_open
+ *
+ * Purpose: Open a named datatype.
+ *
+ * Return: Success: Ptr to a new datatype.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Monday, June 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T_open(const H5G_loc_t *loc, hid_t dxpl_id)
+{
+ H5T_shared_t *shared_fo = NULL;
+ H5T_t *dt = NULL;
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(loc);
+
+ /* Check if datatype was already open */
+ if(NULL == (shared_fo = (H5T_shared_t *)H5FO_opened(loc->oloc->file, loc->oloc->addr))) {
+ /* Clear any errors from H5FO_opened() */
+ H5E_clear_stack(NULL);
+
+ /* Open the datatype object */
+ if(NULL == (dt = H5T_open_oid(loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "not found")
+
+ /* Add the datatype to the list of opened objects in the file */
+ if(H5FO_insert(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr, dt->shared, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, NULL, "can't insert datatype into list of open objects")
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINC, NULL, "can't increment object count")
+
+ /* Mark any datatypes as being in memory now */
+ if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ dt->shared->fo_count = 1;
+ } /* end if */
+ else {
+ if(NULL == (dt = H5FL_MALLOC(H5T_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate space for datatype")
+
+#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
+ /* Clear object location */
+ if(H5O_loc_reset(&(dt->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to reset location")
+
+ /* Clear path name */
+ if(H5G_name_reset(&(dt->path)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to reset path")
+#endif /* H5_USING_MEMCHECKER */
+
+ /* Shallow copy (take ownership) of the object location object */
+ if(H5O_loc_copy(&dt->oloc, loc->oloc, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy object location")
+
+ /* Shallow copy (take ownership) of the group hier. path */
+ if(H5G_name_copy(&(dt->path), loc->path, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy path")
+
+ /* Set the shared component info */
+ H5T_update_shared(dt);
+
+ /* Point to shared datatype info */
+ dt->shared = shared_fo;
+
+ /* Mark any datatypes as being in memory now */
+ if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ /* Increment ref. count on shared info */
+ shared_fo->fo_count++;
+
+ /* Check if the object has been opened through the top file yet */
+ if(H5FO_top_count(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) == 0) {
+ /* Open the object through this top file */
+ if(H5O_open(&(dt->oloc)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to open object header")
+ } /* end if */
+
+ /* Increment object count for the object in the top file */
+ if(H5FO_top_incr(dt->sh_loc.file, dt->sh_loc.u.loc.oh_addr) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINC, NULL, "can't increment object count")
+ } /* end else */
+
+ ret_value = dt;
+
+done:
+ if(ret_value == NULL) {
+ if(dt) {
+ if(shared_fo == NULL) /* Need to free shared fo */
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);
+
+ H5O_loc_free(&(dt->oloc));
+ H5G_name_free(&(dt->path));
+
+ dt = H5FL_FREE(H5T_t, dt);
+ } /* end if */
+
+ if(shared_fo)
+ shared_fo->fo_count--;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_open_oid
+ *
+ * Purpose: Open a named datatype.
+ *
+ * Return: Success: Ptr to a new datatype.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, March 17, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_t *
+H5T_open_oid(const H5G_loc_t *loc, hid_t dxpl_id)
+{
+ H5T_t *dt = NULL; /* Datatype from the file */
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(loc);
+
+ /* Open named datatype object in file */
+ if(H5O_open(loc->oloc) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, NULL, "unable to open named datatype")
+
+ /* Deserialize the datatype message into a datatype in memory */
+ if(NULL == (dt = (H5T_t *)H5O_msg_read(loc->oloc, H5O_DTYPE_ID, NULL, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to load type message from object header")
+
+ /* Mark the type as named and open */
+ dt->shared->state = H5T_STATE_OPEN;
+
+ /* Shallow copy (take ownership) of the object location object */
+ if(H5O_loc_copy(&dt->oloc, loc->oloc, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy object location")
+
+ /* Shallow copy (take ownership) of the group hier. path */
+ if(H5G_name_copy(&(dt->path), loc->path, H5_COPY_SHALLOW) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy path")
+
+ /* Set the shared component info */
+ H5T_update_shared(dt);
+
+ /* Set return value */
+ ret_value = dt;
+
+done:
+ if(ret_value == NULL)
+ if(dt == NULL)
+ H5O_close(loc->oloc, NULL);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_open_oid() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_update_shared
+ *
+ * Purpose: Update the shared location information from the object location
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 13, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_update_shared(H5T_t *dt)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(dt);
+
+ /* Set the shared location fields from the named datatype info */
+ H5O_UPDATE_SHARED(&(dt->sh_loc), H5O_SHARE_TYPE_COMMITTED, dt->oloc.file, H5O_DTYPE_ID, 0, dt->oloc.addr)
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5T_update_shared() */
+
diff --git a/src/H5Tcompound.c b/src/H5Tcompound.c
new file mode 100644
index 0000000..169c146
--- /dev/null
+++ b/src/H5Tcompound.c
@@ -0,0 +1,646 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for compound datatypes
+ * in the H5T interface.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5MMprivate.h" /*memory management */
+#include "H5Tpkg.h" /*data-type functions */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5T_pack(const H5T_t *dt);
+static htri_t H5T_is_packed(const H5T_t *dt);
+
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_offset
+ *
+ * Purpose: Returns the byte offset of the beginning of a member with
+ * respect to the beginning of the compound datatype datum.
+ *
+ * Return: Success: Byte offset.
+ *
+ * Failure: Zero. Zero is a valid offset, but this
+ * function will fail only if a call to
+ * H5Tget_member_dims() fails with the same
+ * arguments.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5Tget_member_offset(hid_t type_id, unsigned membno)
+{
+ H5T_t *dt; /* Datatype to query */
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE2("z", "iIu", type_id, membno);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a compound datatype")
+ if(membno >= dt->shared->u.compnd.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid member number")
+
+ /* Value */
+ ret_value = H5T_GET_MEMBER_OFFSET(dt->shared, membno);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_member_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_member_offset
+ *
+ * Purpose: Private function for H5Tget_member_offset. Returns the byte
+ * offset of the beginning of a member with respect to the
+ * beginning of the compound datatype datum.
+ *
+ * Return: Success: Byte offset.
+ *
+ * Failure: Zero. Zero is a valid offset, but this
+ * function will fail only if a call to
+ * H5Tget_member_dims() fails with the same
+ * arguments.
+ *
+ * Programmer: Raymond Lu
+ * October 8, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5T_get_member_offset(const H5T_t *dt, unsigned membno)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(dt);
+ HDassert(membno < dt->shared->u.compnd.nmembs);
+
+ FUNC_LEAVE_NOAPI(dt->shared->u.compnd.memb[membno].offset)
+} /* end H5T_get_member_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_class
+ *
+ * Purpose: Returns the datatype class of a member of a compound datatype.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: H5T_NO_CLASS
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 9, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_class_t
+H5Tget_member_class(hid_t type_id, unsigned membno)
+{
+ H5T_t *dt; /* Datatype to query */
+ H5T_class_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5T_NO_CLASS)
+ H5TRACE2("Tt", "iIu", type_id, membno);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NO_CLASS, "not a compound datatype")
+ if(membno >= dt->shared->u.compnd.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5T_NO_CLASS, "invalid member number")
+
+ /* Get the type's class. We have to use this function to get type class
+ * because of the concern of variable-length string.
+ */
+ ret_value = H5T_GET_CLASS(dt->shared->u.compnd.memb[membno].type->shared, FALSE);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_member_class() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_type
+ *
+ * Purpose: Returns the datatype of the specified member. The caller
+ * should invoke H5Tclose() to release resources associated with
+ * the type.
+ *
+ * Return: Success: An OID of a copy of the member datatype;
+ * modifying the returned datatype does not
+ * modify the member type.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tget_member_type(hid_t type_id, unsigned membno)
+{
+ H5T_t *dt; /* Datatype to query */
+ H5T_t *memb_dt = NULL; /* Member datatype */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "iIu", type_id, membno);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a compound datatype")
+ if(membno >= dt->shared->u.compnd.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid member number")
+ if(NULL == (memb_dt = H5T_get_member_type(dt, membno, H5T_COPY_REOPEN)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to retrieve member type")
+ if((ret_value = H5I_register(H5I_DATATYPE, memb_dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable register datatype atom")
+
+done:
+ if(ret_value < 0)
+ if(memb_dt && H5T_close(memb_dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "can't close datatype")
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_member_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_member_type
+ *
+ * Purpose: Private function for H5Tget_member_type. Returns the data
+ * type of the specified member.
+ *
+ * Return: Success: A copy of the member datatype;
+ * modifying the returned datatype does not
+ * modify the member type.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * October 8, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T_get_member_type(const H5T_t *dt, unsigned membno, H5T_copy_t method)
+{
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(dt);
+ HDassert(membno < dt->shared->u.compnd.nmembs);
+
+ /* Copy datatype into an atom */
+ if(NULL == (ret_value = H5T_copy(dt->shared->u.compnd.memb[membno].type, method)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy member datatype")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_member_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__get_member_size
+ *
+ * Purpose: Returns the size of the specified member.
+ *
+ * Return: Success: The size in bytes of the member's datatype.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * October 4, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5T__get_member_size(const H5T_t *dt, unsigned membno)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(dt);
+ HDassert(membno < dt->shared->u.compnd.nmembs);
+
+ FUNC_LEAVE_NOAPI(dt->shared->u.compnd.memb[membno].type->shared->size)
+} /* end H5T__get_member_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tinsert
+ *
+ * Purpose: Adds another member to the compound datatype PARENT_ID. The
+ * new member has a NAME which must be unique within the
+ * compound datatype. The OFFSET argument defines the start of
+ * the member in an instance of the compound datatype, and
+ * MEMBER_ID is the type of the new member.
+ *
+ * Return: Success: Non-negative, the PARENT_ID compound data
+ * type is modified to include a copy of the
+ * member type MEMBER_ID.
+ *
+ * Failure: Negative
+ *
+ * Errors:
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tinsert(hid_t parent_id, const char *name, size_t offset, hid_t member_id)
+{
+ H5T_t *parent; /* The compound parent datatype */
+ H5T_t *member; /* The member datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*szi", parent_id, name, offset, member_id);
+
+ /* Check args */
+ if(parent_id == member_id)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't insert compound datatype within itself")
+ if(NULL == (parent = (H5T_t *)H5I_object_verify(parent_id, H5I_DATATYPE)) || H5T_COMPOUND != parent->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a compound datatype")
+ if(H5T_STATE_TRANSIENT != parent->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "parent type read-only")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no member name")
+ if(NULL == (member = (H5T_t *)H5I_object_verify(member_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Insert */
+ if(H5T__insert(parent, name, offset, member) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "unable to insert member")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tinsert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tpack
+ *
+ * Purpose: Recursively removes padding from within a compound datatype
+ * to make it more efficient (space-wise) to store that data.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tpack(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_detect_class(dt, H5T_COMPOUND, TRUE) <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a compound datatype")
+
+ /* Pack */
+ if(H5T_pack(dt) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to pack compound datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tpack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__insert
+ *
+ * Purpose: Adds a new MEMBER to the compound datatype PARENT. The new
+ * member will have a NAME that is unique within PARENT and an
+ * instance of PARENT will have the member begin at byte offset
+ * OFFSET from the beginning.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__insert(H5T_t *parent, const char *name, size_t offset, const H5T_t *member)
+{
+ unsigned idx; /* Index of member to insert */
+ size_t total_size;
+ unsigned i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check args */
+ HDassert(parent && H5T_COMPOUND == parent->shared->type);
+ HDassert(H5T_STATE_TRANSIENT == parent->shared->state);
+ HDassert(member);
+ HDassert(name && *name);
+
+ /* Does NAME already exist in PARENT? */
+ for(i = 0; i < parent->shared->u.compnd.nmembs; i++)
+ if(!HDstrcmp(parent->shared->u.compnd.memb[i].name, name))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member name is not unique")
+
+ /* Does the new member overlap any existing member ? */
+ total_size = member->shared->size;
+ for(i = 0; i < parent->shared->u.compnd.nmembs; i++)
+ if((offset <= parent->shared->u.compnd.memb[i].offset &&
+ (offset + total_size) > parent->shared->u.compnd.memb[i].offset) ||
+ (parent->shared->u.compnd.memb[i].offset <= offset &&
+ (parent->shared->u.compnd.memb[i].offset +
+ parent->shared->u.compnd.memb[i].size) > offset))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member overlaps with another member")
+
+ /* Does the new member overlap the end of the compound type? */
+ if((offset + total_size) > parent->shared->size)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member extends past end of compound type")
+
+ /* Increase member array if necessary */
+ if(parent->shared->u.compnd.nmembs >= parent->shared->u.compnd.nalloc) {
+ unsigned na = MAX(1, parent->shared->u.compnd.nalloc * 2);
+ H5T_cmemb_t *x = (H5T_cmemb_t *)H5MM_realloc(parent->shared->u.compnd.memb, na * sizeof(H5T_cmemb_t));
+
+ if(!x)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ parent->shared->u.compnd.nalloc = na;
+ parent->shared->u.compnd.memb = x;
+ } /* end if */
+
+ /* Add member to end of member array */
+ idx = parent->shared->u.compnd.nmembs;
+ parent->shared->u.compnd.memb[idx].name = H5MM_xstrdup(name);
+ parent->shared->u.compnd.memb[idx].offset = offset;
+ parent->shared->u.compnd.memb[idx].size = total_size;
+ parent->shared->u.compnd.memb[idx].type = H5T_copy(member, H5T_COPY_ALL);
+
+ parent->shared->u.compnd.sorted = H5T_SORT_NONE;
+ parent->shared->u.compnd.nmembs++;
+ parent->shared->u.compnd.memb_size+=total_size;
+
+ /* It should not be possible to get this far if the type is already packed
+ * - the new member would overlap something */
+ HDassert(!(parent->shared->u.compnd.packed));
+
+ /* Determine if the compound datatype becomes packed */
+ H5T__update_packed(parent);
+
+ /* Set the "force conversion" flag if the field's datatype indicates */
+ if(member->shared->force_conv == TRUE)
+ parent->shared->force_conv = TRUE;
+
+ /* Check for member having a later version than the parent */
+ if(parent->shared->version < member->shared->version)
+ /* Upgrade parent datatype (and all other members also) */
+ /* (can't use a partial datatype and later versions of the format are
+ * more efficient, so might as well upgrade all members also... -QAK)
+ */
+ if(H5T__upgrade_version(parent, member->shared->version) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't upgrade member encoding version")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_pack
+ *
+ * Purpose: Recursively packs a compound datatype by removing padding
+ * bytes. This is done in place (that is, destructively).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_pack(const H5T_t *dt)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(dt);
+
+ if(H5T_detect_class(dt, H5T_COMPOUND, FALSE) > 0) {
+ /* If datatype has been packed, skip packing it and indicate success */
+ if(TRUE == H5T_is_packed(dt))
+ HGOTO_DONE(SUCCEED)
+
+ /* Check for packing unmodifiable datatype */
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "datatype is read-only")
+
+ if(dt->shared->parent) {
+ if (H5T_pack(dt->shared->parent) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to pack parent of datatype")
+
+ /* Adjust size of datatype appropriately */
+ if(dt->shared->type == H5T_ARRAY)
+ dt->shared->size = dt->shared->parent->shared->size * dt->shared->u.array.nelem;
+ else if(dt->shared->type != H5T_VLEN)
+ dt->shared->size = dt->shared->parent->shared->size;
+ } /* end if */
+ else if(dt->shared->type == H5T_COMPOUND) {
+ size_t offset; /* Offset of member */
+ unsigned i; /* Local index variable */
+
+ /* Recursively pack the members */
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ if(H5T_pack(dt->shared->u.compnd.memb[i].type) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to pack part of a compound datatype")
+
+ /* Update the member size */
+ dt->shared->u.compnd.memb[i].size = (dt->shared->u.compnd.memb[i].type)->shared->size;
+ } /* end for */
+
+ /* Remove padding between members */
+ if(H5T__sort_value(dt, NULL) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOMPARE, FAIL, "value sort failed")
+ for(i = 0, offset = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ dt->shared->u.compnd.memb[i].offset = offset;
+ offset += dt->shared->u.compnd.memb[i].size;
+ }
+
+ /* Change total size */
+ dt->shared->size = MAX(1, offset);
+
+ /* Mark the type as packed now */
+ dt->shared->u.compnd.packed = TRUE;
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_pack() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_is_packed
+ *
+ * Purpose: Checks whether a datatype which is compound (or has compound
+ * components) is packed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 11, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5T_is_packed(const H5T_t *dt)
+{
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(dt);
+
+ /* Go up the chain as far as possible */
+ while(dt->shared->parent)
+ dt = dt->shared->parent;
+
+ /* If this is a compound datatype, check if it is packed */
+ if(dt->shared->type == H5T_COMPOUND) {
+ ret_value = (htri_t)(dt->shared->u.compnd.packed);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_is_packed() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__update_packed
+ *
+ * Purpose: Checks whether a datatype which is compound became packed
+ * after recent changes. This function does not assume that
+ * the status of the "packed" field is correct, and sets
+ * this field to the correct value.
+ *
+ * Return: void
+ *
+ * Programmer: Neil Fortner
+ * Monday, October 19, 2009
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5T__update_packed(const H5T_t *dt)
+{
+ unsigned i; /* Index */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(dt);
+ HDassert(dt->shared->type == H5T_COMPOUND);
+
+ /* First check if all space is used in the "top level" type */
+ if(dt->shared->size == dt->shared->u.compnd.memb_size) {
+ /* Set the packed flag to TRUE */
+ dt->shared->u.compnd.packed = TRUE;
+
+ /* Now check if all members are packed */
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++)
+ if(!H5T_is_packed(dt->shared->u.compnd.memb[i].type)) {
+ dt->shared->u.compnd.packed = FALSE;
+ break;
+ } /* end if */
+ } /* end if */
+ else
+ dt->shared->u.compnd.packed = FALSE;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5T__update_packed() */
+
diff --git a/src/H5Tconv.c b/src/H5Tconv.c
new file mode 100644
index 0000000..84a997e
--- /dev/null
+++ b/src/H5Tconv.c
@@ -0,0 +1,9905 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: Datatype conversions for the H5T interface.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/*
+ * These macros are for the bodies of functions that convert buffers of one
+ * atomic type to another using hardware.
+ *
+ * They all start with `H5T_CONV_' and end with two letters that represent the
+ * source and destination types, respectively. The letters `s' and `S' refer to
+ * signed integers while the letters `u' and `U' refer to unsigned integers, and
+ * the letters `f' and `F' refer to floating-point values.
+ *
+ * The letter which is capitalized indicates that the corresponding type
+ * (source or destination) is at least as large as the other type.
+ *
+ * Certain conversions may experience overflow conditions which arise when the
+ * source value has a magnitude that cannot be represented by the destination
+ * type.
+ *
+ * Suffix Description
+ * ------ -----------
+ * sS: Signed integers to signed integers where the destination is
+ * at least as wide as the source. This case cannot generate
+ * overflows.
+ *
+ * sU: Signed integers to unsigned integers where the destination is
+ * at least as wide as the source. This case experiences
+ * overflows when the source value is negative.
+ *
+ * uS: Unsigned integers to signed integers where the destination is
+ * at least as wide as the source. This case can experience
+ * overflows when the source and destination are the same size.
+ *
+ * uU: Unsigned integers to unsigned integers where the destination
+ * is at least as wide as the source. Overflows are not
+ * possible in this case.
+ *
+ * Ss: Signed integers to signed integers where the source is at
+ * least as large as the destination. Overflows can occur when
+ * the destination is narrower than the source.
+ *
+ * Su: Signed integers to unsigned integers where the source is at
+ * least as large as the destination. Overflows occur when the
+ * source value is negative and can also occur if the
+ * destination is narrower than the source.
+ *
+ * Us: Unsigned integers to signed integers where the source is at
+ * least as large as the destination. Overflows can occur for
+ * all sizes.
+ *
+ * Uu: Unsigned integers to unsigned integers where the source is at
+ * least as large as the destination. Overflows can occur if the
+ * destination is narrower than the source.
+ *
+ * su: Conversion from signed integers to unsigned integers where
+ * the source and destination are the same size. Overflow occurs
+ * when the source value is negative.
+ *
+ * us: Conversion from unsigned integers to signed integers where
+ * the source and destination are the same size. Overflow
+ * occurs when the source magnitude is too large for the
+ * destination.
+ *
+ * fF: Floating-point values to floating-point values where the
+ * destination is at least as wide as the source. This case
+ * cannot generate overflows.
+ *
+ * Ff: Floating-point values to floating-point values the source is at
+ * least as large as the destination. Overflows can occur when
+ * the destination is narrower than the source.
+ *
+ * xF: Integers to float-point(float or double) values where the desination
+ * is at least as wide as the source. This case cannot generate
+ * overflows.
+ *
+ * Fx: Float-point(float or double) values to integer where the source is
+ * at least as wide as the destination. Overflow can occur
+ * when the source magnitude is too large for the destination.
+ *
+ * The macros take a subset of these arguments in the order listed here:
+ *
+ * CDATA: A pointer to the H5T_cdata_t structure that was passed to the
+ * conversion function.
+ *
+ * STYPE: The hid_t value for the source datatype.
+ *
+ * DTYPE: The hid_t value for the destination datatype.
+ *
+ * BUF: A pointer to the conversion buffer.
+ *
+ * NELMTS: The number of values to be converted.
+ *
+ * ST: The C name for source datatype (e.g., int)
+ *
+ * DT: The C name for the destination datatype (e.g., signed char)
+ *
+ * D_MIN: The minimum possible destination value. For unsigned
+ * destination types this should be zero. For signed
+ * destination types it's a negative value with a magnitude that
+ * is usually one greater than D_MAX. Source values which are
+ * smaller than D_MIN generate overflows.
+ *
+ * D_MAX: The maximum possible destination value. Source values which
+ * are larger than D_MAX generate overflows.
+ *
+ * The macros are implemented with a generic programming technique, similar
+ * to templates in C++. The macro which defines the "core" part of the
+ * conversion (which actually moves the data from the source to the destination)
+ * is invoked inside the H5T_CONV "template" macro by "gluing" it together,
+ * which allows the core conversion macro to be invoked as necessary.
+ *
+ * "Core" macros come in two flavors: one which calls the exception handling
+ * routine and one which doesn't (the "_NOEX" variant). The presence of the
+ * exception handling routine is detected before the loop over the values and
+ * the appropriate core routine loop is executed.
+ *
+ * The generic "core" macros are: (others are specific to particular conversion)
+ *
+ * Suffix Description
+ * ------ -----------
+ * xX: Generic Conversion where the destination is at least as
+ * wide as the source. This case cannot generate overflows.
+ *
+ * Xx: Generic signed conversion where the source is at least as large
+ * as the destination. Overflows can occur when the destination is
+ * narrower than the source.
+ *
+ * Ux: Generic conversion for the `Us', `Uu' & `us' cases
+ * Overflow occurs when the source magnitude is too large for the
+ * destination.
+ *
+ */
+#define H5T_CONV_xX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_xX_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ *(D) = (DT)(*(S)); \
+}
+
+/* Added a condition branch(else if (*(S) == (DT)(D_MAX))) which seems redundant.
+ * It handles a special situation when the source is "float" and assigned the value
+ * of "INT_MAX". A compiler may do roundup making this value "INT_MAX+1". However,
+ * when do comparison "if (*(S) > (DT)(D_MAX))", the compiler may consider them
+ * equal. In this case, do not return exception but make sure the maximum is assigned
+ * to the destination. SLU - 2005/06/29
+ */
+#define H5T_CONV_Xx_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (*(S) > (ST)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MAX); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else if (*(S) < (ST)(D_MIN)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MIN); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_Xx_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (*(S) > (ST)(D_MAX)) { \
+ *(D) = (DT)(D_MAX); \
+ } else if (*(S) < (ST)(D_MIN)) { \
+ *(D) = (DT)(D_MIN); \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_Ux_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (*(S) > (ST)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MAX); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_Ux_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (*(S) > (ST)(D_MAX)) { \
+ *(D) = (DT)(D_MAX); \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_sS(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)<=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_xX, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_sU_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (*(S) < 0) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = 0; \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_sU_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) < 0) \
+ *(D) = 0; \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_sU(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)<=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_sU, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+/* Define to 1 if overflow is possible during conversion, 0 otherwise
+ * Because destination is at least as wide as the source, this should only
+ * occur between types of equal size */
+#define H5T_CONV_uS_UCHAR_SHORT 0
+#define H5T_CONV_uS_UCHAR_INT 0
+#define H5T_CONV_uS_UCHAR_LONG 0
+#define H5T_CONV_uS_UCHAR_LLONG 0
+#if H5_SIZEOF_SHORT == H5_SIZEOF_INT
+ #define H5T_CONV_uS_USHORT_INT 1
+#else
+ #define H5T_CONV_uS_USHORT_INT 0
+#endif
+#define H5T_CONV_uS_USHORT_LONG 0
+#define H5T_CONV_uS_USHORT_LLONG 0
+#if H5_SIZEOF_INT == H5_SIZEOF_LONG
+ #define H5T_CONV_uS_UINT_LONG 1
+#else
+ #define H5T_CONV_uS_UINT_LONG 0
+#endif
+#define H5T_CONV_uS_UINT_LLONG 0
+#if H5_SIZEOF_LONG == H5_SIZEOF_LONG_LONG
+ #define H5T_CONV_uS_ULONG_LLONG 1
+#else
+ #define H5T_CONV_uS_ULONG_LLONG 0
+#endif
+
+/* Note. If an argument is stringified or concatenated, the prescan does not
+ * occur. To expand the macro, then stringify or concatenate its expansion,
+ * one macro must call another macro that does the stringification or
+ * concatenation. */
+#define H5T_CONV_uS_EVAL_TYPES(STYPE, DTYPE) \
+ H5_GLUE4(H5T_CONV_uS_, STYPE, _, DTYPE)
+
+/* Called if overflow is possible */
+#define H5T_CONV_uS_CORE_1(S, D, ST, DT, D_MIN, D_MAX) \
+ if (*(S) > (DT)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI,\
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler */ \
+ *(D) = (DT)(D_MAX); \
+ else if (except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, \
+ "can't handle conversion exception") \
+ /* if (except_ret==H5T_CONV_HANDLED): Fall through, user handled it */\
+ } else \
+ *(D) = (DT)(*(S));
+
+/* Called if no overflow is possible */
+#define H5T_CONV_uS_CORE_0(S, D, ST, DT, D_MIN, D_MAX) \
+ *(D) = (DT)(*(S));
+
+#define H5T_CONV_uS_CORE_I(over, S, D, ST, DT, D_MIN, D_MAX) \
+ H5_GLUE(H5T_CONV_uS_CORE_, over)(S, D, ST, DT, D_MIN, D_MAX)
+
+#define H5T_CONV_uS_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) { \
+ H5T_CONV_uS_CORE_I(H5T_CONV_uS_EVAL_TYPES(STYPE, DTYPE), \
+ S, D, ST, DT, D_MIN, D_MAX) \
+}
+
+/* Called if overflow is possible */
+#define H5T_CONV_uS_NOEX_CORE_1(S, D, ST, DT, D_MIN, D_MAX) \
+ if (*(S) > (DT)(D_MAX)) \
+ *(D) = (D_MAX); \
+ else \
+ *(D) = (DT)(*(S));
+
+/* Called if no overflow is possible */
+#define H5T_CONV_uS_NOEX_CORE_0(S, D, ST, DT, D_MIN, D_MAX) \
+ *(D) = (DT)(*(S));
+
+#define H5T_CONV_uS_NOEX_CORE_I(over, S, D, ST, DT, D_MIN, D_MAX) \
+ H5_GLUE(H5T_CONV_uS_NOEX_CORE_, over)(S, D, ST, DT, D_MIN, D_MAX)
+
+#define H5T_CONV_uS_NOEX_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) { \
+ H5T_CONV_uS_NOEX_CORE_I(H5T_CONV_uS_EVAL_TYPES(STYPE, DTYPE), \
+ S, D, ST, DT, D_MIN, D_MAX) \
+}
+
+#define H5T_CONV_uS(STYPE, DTYPE, ST, DT, D_MIN, D_MAX) { \
+ HDcompile_assert(sizeof(ST) <= sizeof(DT)); \
+ H5T_CONV(H5T_CONV_uS, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_uU(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)<=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_xX, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_Ss(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)>=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_Xx, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_Su_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) < 0) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = 0; \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else if (sizeof(ST)>sizeof(DT) && *(S) > (ST)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MAX); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_Su_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) < 0) \
+ *(D) = 0; \
+ else if (sizeof(ST)>sizeof(DT) && *(S) > (ST)(D_MAX)) \
+ *(D) = (DT)(D_MAX); \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_Su(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)>=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_Su, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_Us(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)>=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_Ux, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_Uu(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)>=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_Ux, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_su_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ /* Assumes memory format of unsigned & signed integers is same */ \
+ if(*(S) < 0) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = 0; \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_su_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ /* Assumes memory format of unsigned & signed integers is same */ \
+ if(*(S) < 0) \
+ *(D) = 0; \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_su(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)==sizeof(DT)); \
+ H5T_CONV(H5T_CONV_su, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_us_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ /* Assumes memory format of unsigned & signed integers is same */ \
+ if (*(S) > (ST)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MAX); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_us_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ /* Assumes memory format of unsigned & signed integers is same */ \
+ if(*(S) > (ST)(D_MAX)) \
+ *(D) = (DT)(D_MAX); \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_us(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)==sizeof(DT)); \
+ H5T_CONV(H5T_CONV_us, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_CONV_fF(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)<=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_xX, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+/* Same as H5T_CONV_Xx_CORE, except that instead of using D_MAX and D_MIN
+ * when an overflow occurs, use the 'float' infinity values.
+ */
+#define H5T_CONV_Ff_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) > (ST)(D_MAX)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (H5T_NATIVE_FLOAT_POS_INF_g); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else if (*(S) < (ST)(D_MIN)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (H5T_NATIVE_FLOAT_NEG_INF_g); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_Ff_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) > (ST)(D_MAX)) \
+ *(D) = (H5T_NATIVE_FLOAT_POS_INF_g); \
+ else if (*(S) < (ST)(D_MIN)) \
+ *(D) = (H5T_NATIVE_FLOAT_NEG_INF_g); \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_Ff(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ HDcompile_assert(sizeof(ST)>=sizeof(DT)); \
+ H5T_CONV(H5T_CONV_Ff, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \
+}
+
+#define H5T_HI_LO_BIT_SET(TYP, V, LO, HI) { \
+ unsigned count; \
+ unsigned char p; \
+ unsigned u; \
+ \
+ count = 0; \
+ for(u = 0; u < sizeof(TYP); u++) { \
+ count = (((unsigned)sizeof(TYP) - 1) - u) * 8; \
+ p = (unsigned char)((V) >> count); \
+ if(p > 0) { \
+ if(p & 0x80) \
+ count += 7; \
+ else if(p & 0x40) \
+ count += 6; \
+ else if(p & 0x20) \
+ count += 5; \
+ else if(p & 0x10) \
+ count += 4; \
+ else if(p & 0x08) \
+ count += 3; \
+ else if(p & 0x04) \
+ count += 2; \
+ else if(p & 0x02) \
+ count += 1; \
+ break; \
+ } /* end if */ \
+ } /* end for */ \
+ \
+ HI = count; \
+ \
+ count = 0; \
+ for(u = 0; u < sizeof(TYP); u++) { \
+ p = (unsigned char)((V) >> (u * 8)); \
+ if(p > 0) { \
+ count = u * 8; \
+ \
+ if(p & 0x01) \
+ ; \
+ else if(p & 0x02) \
+ count += 1; \
+ else if(p & 0x04) \
+ count += 2; \
+ else if(p & 0x08) \
+ count += 3; \
+ else if(p & 0x10) \
+ count += 4; \
+ else if(p & 0x20) \
+ count += 5; \
+ else if(p & 0x40) \
+ count += 6; \
+ else if(p & 0x80) \
+ count += 7; \
+ break; \
+ } /* end if */ \
+ } /* end for */ \
+ \
+ LO = count; \
+}
+
+#define H5T_CONV_xF_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if (sprec > dprec) { \
+ unsigned low_bit_pos, high_bit_pos; \
+ \
+ /* Detect high & low bits set in source */ \
+ H5T_HI_LO_BIT_SET(ST, *(S), low_bit_pos, high_bit_pos) \
+ \
+ /* Check for more bits of precision in src than available in dst */ \
+ if((high_bit_pos - low_bit_pos) >= dprec) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PRECISION, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(*(S)); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } \
+ else \
+ *(D) = (DT)(*(S)); \
+ } \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_xF_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_xF(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ H5T_CONV(H5T_CONV_xF, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \
+}
+
+/* Quincey added the condition branch (else if (*(S) != (ST)((DT)(*(S))))).
+ * It handles a special situation when the source is "float" and assigned the value
+ * of "INT_MAX". Compilers do roundup making this value "INT_MAX+1". This branch
+ * is to check that situation and return exception for some compilers, mainly GCC.
+ * The branch if (*(S) > (DT)(D_MAX) || (sprec < dprec && *(S) ==
+ * (ST)(D_MAX))) is for some compilers like Sun, HP, IBM, and SGI where under
+ * the same situation the "int" doesn't overflow. SLU - 2005/9/12
+ */
+#define H5T_CONV_Fx_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) > (ST)(D_MAX) || (sprec < dprec && *(S) == (ST)(D_MAX))) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MAX); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else if (*(S) < (ST)(D_MIN)) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(D_MIN); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } else if (*(S) != (ST)((DT)(*(S)))) { \
+ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_TRUNCATE, \
+ src_id, dst_id, S, D, cb_struct.user_data); \
+ if(except_ret == H5T_CONV_UNHANDLED) \
+ /* Let compiler convert if case is ignored by user handler*/ \
+ *(D) = (DT)(*(S)); \
+ else if(except_ret == H5T_CONV_ABORT) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \
+ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \
+ } \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+#define H5T_CONV_Fx_NOEX_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ if(*(S) > (ST)(D_MAX)) \
+ *(D) = (DT)(D_MAX); \
+ else if(*(S) < (ST)(D_MIN)) \
+ *(D) = (DT)(D_MIN); \
+ else \
+ *(D) = (DT)(*(S)); \
+}
+
+#define H5T_CONV_Fx(STYPE,DTYPE,ST,DT,D_MIN,D_MAX) { \
+ H5T_CONV(H5T_CONV_Fx, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \
+}
+
+/* Since all "no exception" cores do the same thing (assign the value in the
+ * source location to the destination location, using casting), use one "core"
+ * to do them all.
+ */
+#ifndef H5_WANT_DCONV_EXCEPTION
+#define H5T_CONV_NO_EXCEPT_CORE(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) { \
+ *(D) = (DT)(*(S)); \
+}
+#endif /* H5_WANT_DCONV_EXCEPTION */
+
+
+/* The main part of every integer hardware conversion macro */
+#define H5T_CONV(GUTS,STYPE,DTYPE,ST,DT,D_MIN,D_MAX,PREC) \
+{ \
+ herr_t ret_value=SUCCEED; /* Return value */ \
+ \
+ FUNC_ENTER_PACKAGE \
+ \
+{ \
+ size_t elmtno; /*element number */ \
+ H5T_CONV_DECL_PREC(PREC) /*declare precision variables, or not */ \
+ uint8_t *src_buf; /*'raw' source buffer */ \
+ uint8_t *dst_buf; /*'raw' destination buffer */ \
+ ST *src, *s; /*source buffer */ \
+ DT *dst, *d; /*destination buffer */ \
+ H5T_t *st, *dt; /*datatype descriptors */ \
+ ST src_aligned; /*source aligned type */ \
+ DT dst_aligned; /*destination aligned type */ \
+ hbool_t s_mv, d_mv; /*move data to align it? */ \
+ ssize_t s_stride, d_stride; /*src and dst strides */ \
+ size_t safe; /*how many elements are safe to process in each pass */ \
+ H5P_genplist_t *plist; /*Property list pointer */ \
+ H5T_conv_cb_t cb_struct; /*conversion callback structure */ \
+ \
+ switch (cdata->command) { \
+ case H5T_CONV_INIT: \
+ /* Sanity check and initialize statistics */ \
+ cdata->need_bkg = H5T_BKG_NO; \
+ if (NULL==(st=(H5T_t*)H5I_object(src_id)) || NULL==(dt=(H5T_t*)H5I_object(dst_id))) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, \
+ "unable to dereference datatype object ID") \
+ if (st->shared->size!=sizeof(ST) || dt->shared->size!=sizeof(DT)) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, \
+ "disagreement about datatype size") \
+ CI_ALLOC_PRIV \
+ break; \
+ \
+ case H5T_CONV_FREE: \
+ /* Print and free statistics */ \
+ CI_PRINT_STATS(STYPE,DTYPE); \
+ CI_FREE_PRIV \
+ break; \
+ \
+ case H5T_CONV_CONV: \
+ /* Initialize source & destination strides */ \
+ if (buf_stride) { \
+ HDassert(buf_stride >= sizeof(ST)); \
+ HDassert(buf_stride >= sizeof(DT)); \
+ s_stride = d_stride = (ssize_t)buf_stride; \
+ } else { \
+ s_stride = sizeof(ST); \
+ d_stride = sizeof(DT); \
+ } \
+ \
+ /* Is alignment required for source or dest? */ \
+ s_mv = H5T_NATIVE_##STYPE##_ALIGN_g>1 && \
+ ((size_t)buf%H5T_NATIVE_##STYPE##_ALIGN_g || \
+ /* Cray */ ((size_t)((ST*)buf)!=(size_t)buf) || \
+ (size_t)s_stride%H5T_NATIVE_##STYPE##_ALIGN_g); \
+ d_mv = H5T_NATIVE_##DTYPE##_ALIGN_g>1 && \
+ ((size_t)buf%H5T_NATIVE_##DTYPE##_ALIGN_g || \
+ /* Cray */ ((size_t)((DT*)buf)!=(size_t)buf) || \
+ (size_t)d_stride%H5T_NATIVE_##DTYPE##_ALIGN_g); \
+ CI_INC_SRC(s_mv) \
+ CI_INC_DST(d_mv) \
+ \
+ /* Get the plist structure */ \
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER))) \
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID") \
+ \
+ /* Get conversion exception callback property */ \
+ if(H5P_get(plist, H5D_XFER_CONV_CB_NAME, &cb_struct) < 0) \
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback") \
+ \
+ /* Get source and destination datatypes */ \
+ if(NULL == (st = (H5T_t *)H5I_object(src_id)) || NULL == (dt = (H5T_t *)H5I_object(dst_id))) \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to dereference datatype object ID") \
+ \
+ H5T_CONV_SET_PREC(PREC) /*init precision variables, or not */ \
+ \
+ /* The outer loop of the type conversion macro, controlling which */ \
+ /* direction the buffer is walked */ \
+ while (nelmts>0) { \
+ /* Check if we need to go backwards through the buffer */ \
+ if(d_stride>s_stride) { \
+ /* Compute the number of "safe" destination elements at */ \
+ /* the end of the buffer (Those which don't overlap with */ \
+ /* any source elements at the beginning of the buffer) */ \
+ safe = nelmts - (((nelmts * (size_t)s_stride) + (size_t)(d_stride - 1)) / (size_t)d_stride); \
+ \
+ /* If we're down to the last few elements, just wrap up */ \
+ /* with a "real" reverse copy */ \
+ if(safe<2) { \
+ src = (ST *)(src_buf = (uint8_t *)buf + (nelmts - 1) * (size_t)s_stride); \
+ dst = (DT *)(dst_buf = (uint8_t *)buf + (nelmts - 1) * (size_t)d_stride); \
+ s_stride = -s_stride; \
+ d_stride = -d_stride; \
+ \
+ safe=nelmts; \
+ } /* end if */ \
+ else { \
+ src = (ST *)(src_buf = (uint8_t *)buf + (nelmts - safe) * (size_t)s_stride); \
+ dst = (DT *)(dst_buf = (uint8_t *)buf + (nelmts - safe) * (size_t)d_stride); \
+ } /* end else */ \
+ } /* end if */ \
+ else { \
+ /* Single forward pass over all data */ \
+ src = (ST *)(src_buf = (uint8_t*)buf); \
+ dst = (DT *)(dst_buf = (uint8_t*)buf); \
+ safe=nelmts; \
+ } /* end else */ \
+ \
+ /* Perform loop over elements to convert */ \
+ if (s_mv && d_mv) { \
+ /* Alignment is required for both source and dest */ \
+ s = &src_aligned; \
+ H5T_CONV_LOOP_OUTER(PRE_SALIGN,PRE_DALIGN,POST_SALIGN,POST_DALIGN,GUTS,STYPE,DTYPE,s,d,ST,DT,D_MIN,D_MAX) \
+ } else if(s_mv) { \
+ /* Alignment is required only for source */ \
+ s = &src_aligned; \
+ H5T_CONV_LOOP_OUTER(PRE_SALIGN,PRE_DNOALIGN,POST_SALIGN,POST_DNOALIGN,GUTS,STYPE,DTYPE,s,dst,ST,DT,D_MIN,D_MAX) \
+ } else if(d_mv) { \
+ /* Alignment is required only for destination */ \
+ H5T_CONV_LOOP_OUTER(PRE_SNOALIGN,PRE_DALIGN,POST_SNOALIGN,POST_DALIGN,GUTS,STYPE,DTYPE,src,d,ST,DT,D_MIN,D_MAX) \
+ } else { \
+ /* Alignment is not required for both source and destination */ \
+ H5T_CONV_LOOP_OUTER(PRE_SNOALIGN,PRE_DNOALIGN,POST_SNOALIGN,POST_DNOALIGN,GUTS,STYPE,DTYPE,src,dst,ST,DT,D_MIN,D_MAX) \
+ } \
+ \
+ /* Decrement number of elements left to convert */ \
+ nelmts-=safe; \
+ } /* end while */ \
+ break; \
+ \
+ default: \
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, \
+ "unknown conversion command"); \
+ } \
+} \
+ \
+done: \
+ FUNC_LEAVE_NOAPI(ret_value) \
+}
+
+/* Declare the source & destination precision variables */
+#define H5T_CONV_DECL_PREC(PREC) H5_GLUE(H5T_CONV_DECL_PREC_, PREC)
+
+#define H5T_CONV_DECL_PREC_Y \
+ size_t sprec; /*source precision */ \
+ size_t dprec; /*destination precision */ \
+ H5T_class_t tclass; /*datatype's class */
+
+#define H5T_CONV_DECL_PREC_N /*no precision variables */
+
+/* Initialize the source & destination precision variables */
+#define H5T_CONV_SET_PREC(PREC) H5_GLUE(H5T_CONV_SET_PREC_, PREC)
+
+#define H5T_CONV_SET_PREC_Y \
+ /* Get source & destination precisions into a variable */ \
+ tclass = st->shared->type; \
+ HDassert(tclass == H5T_INTEGER || tclass == H5T_FLOAT); \
+ if(tclass == H5T_INTEGER) \
+ sprec = st->shared->u.atomic.prec; \
+ else \
+ sprec = 1 + st->shared->u.atomic.u.f.msize; \
+ tclass = dt->shared->type; \
+ HDassert(tclass == H5T_INTEGER || tclass == H5T_FLOAT); \
+ if(tclass == H5T_INTEGER) \
+ dprec = dt->shared->u.atomic.prec; \
+ else \
+ dprec = 1 + dt->shared->u.atomic.u.f.msize;
+
+#define H5T_CONV_SET_PREC_N /*don't init precision variables */
+
+/* Macro defining action on source data which needs to be aligned (before main action) */
+#define H5T_CONV_LOOP_PRE_SALIGN(ST) { \
+ HDmemcpy(&src_aligned, src, sizeof(ST)); \
+}
+
+/* Macro defining action on source data which doesn't need to be aligned (before main action) */
+#define H5T_CONV_LOOP_PRE_SNOALIGN(ST) { \
+}
+
+/* Macro defining action on destination data which needs to be aligned (before main action) */
+#define H5T_CONV_LOOP_PRE_DALIGN(DT) { \
+ d = &dst_aligned; \
+}
+
+/* Macro defining action on destination data which doesn't need to be aligned (before main action) */
+#define H5T_CONV_LOOP_PRE_DNOALIGN(DT) { \
+}
+
+/* Macro defining action on source data which needs to be aligned (after main action) */
+#define H5T_CONV_LOOP_POST_SALIGN(ST) { \
+}
+
+/* Macro defining action on source data which doesn't need to be aligned (after main action) */
+#define H5T_CONV_LOOP_POST_SNOALIGN(ST) { \
+}
+
+/* Macro defining action on destination data which needs to be aligned (after main action) */
+#define H5T_CONV_LOOP_POST_DALIGN(DT) { \
+ HDmemcpy(dst, &dst_aligned, sizeof(DT)); \
+}
+
+/* Macro defining action on destination data which doesn't need to be aligned (after main action) */
+#define H5T_CONV_LOOP_POST_DNOALIGN(DT) { \
+}
+
+/* The outer wrapper for the type conversion loop, to check for an exception handling routine */
+#define H5T_CONV_LOOP_OUTER(PRE_SALIGN_GUTS,PRE_DALIGN_GUTS,POST_SALIGN_GUTS,POST_DALIGN_GUTS,GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ if(cb_struct.func) { \
+ H5T_CONV_LOOP(PRE_SALIGN_GUTS,PRE_DALIGN_GUTS,POST_SALIGN_GUTS,POST_DALIGN_GUTS,GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ } \
+ else { \
+ H5T_CONV_LOOP(PRE_SALIGN_GUTS,PRE_DALIGN_GUTS,POST_SALIGN_GUTS,POST_DALIGN_GUTS,H5_GLUE(GUTS,_NOEX),STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ }
+
+/* The inner loop of the type conversion macro, actually converting the elements */
+#define H5T_CONV_LOOP(PRE_SALIGN_GUTS,PRE_DALIGN_GUTS,POST_SALIGN_GUTS,POST_DALIGN_GUTS,GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ for (elmtno=0; elmtno<safe; elmtno++) { \
+ /* Handle source pre-alignment */ \
+ H5_GLUE(H5T_CONV_LOOP_,PRE_SALIGN_GUTS)(ST) \
+ \
+ /* Handle destination pre-alignment */ \
+ H5_GLUE(H5T_CONV_LOOP_,PRE_DALIGN_GUTS)(DT) \
+ \
+ /* ... user-defined stuff here -- the conversion ... */ \
+ H5T_CONV_LOOP_GUTS(GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ \
+ /* Handle source post-alignment */ \
+ H5_GLUE(H5T_CONV_LOOP_,POST_SALIGN_GUTS)(ST) \
+ \
+ /* Handle destination post-alignment */ \
+ H5_GLUE(H5T_CONV_LOOP_,POST_DALIGN_GUTS)(DT) \
+ \
+ /* Advance pointers */ \
+ src_buf += s_stride; \
+ src = (ST *)src_buf; \
+ dst_buf += d_stride; \
+ dst = (DT *)dst_buf; \
+ }
+
+/* Macro to call the actual "guts" of the type conversion, or call the "no exception" guts */
+#ifdef H5_WANT_DCONV_EXCEPTION
+#define H5T_CONV_LOOP_GUTS(GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ /* ... user-defined stuff here -- the conversion ... */ \
+ H5_GLUE(GUTS,_CORE)(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX)
+#else /* H5_WANT_DCONV_EXCEPTION */
+#define H5T_CONV_LOOP_GUTS(GUTS,STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX) \
+ H5_GLUE(H5T_CONV_NO_EXCEPT,_CORE)(STYPE,DTYPE,S,D,ST,DT,D_MIN,D_MAX)
+#endif /* H5_WANT_DCONV_EXCEPTION */
+
+
+#ifdef H5T_DEBUG
+
+/* Print alignment statistics */
+# define CI_PRINT_STATS(STYPE,DTYPE) { \
+ if (H5DEBUG(T) && ((H5T_conv_hw_t *)cdata->priv)->s_aligned) { \
+ HDfprintf(H5DEBUG(T), \
+ " %Hu src elements aligned on %lu-byte boundaries\n", \
+ ((H5T_conv_hw_t *)cdata->priv)->s_aligned, \
+ (unsigned long)H5T_NATIVE_##STYPE##_ALIGN_g); \
+ } \
+ if (H5DEBUG(T) && ((H5T_conv_hw_t *)cdata->priv)->d_aligned) { \
+ HDfprintf(H5DEBUG(T), \
+ " %Hu dst elements aligned on %lu-byte boundaries\n", \
+ ((H5T_conv_hw_t *)cdata->priv)->d_aligned, \
+ (unsigned long)H5T_NATIVE_##DTYPE##_ALIGN_g); \
+ } \
+}
+
+/* Allocate private alignment structure for atomic types */
+# define CI_ALLOC_PRIV \
+ if (NULL==(cdata->priv=H5MM_calloc(sizeof(H5T_conv_hw_t)))) { \
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
+ "memory allocation failed"); \
+ }
+
+/* Free private alignment structure for atomic types */
+# define CI_FREE_PRIV \
+ if(cdata->priv!=NULL) \
+ cdata->priv = H5MM_xfree(cdata->priv);
+
+/* Increment source alignment counter */
+# define CI_INC_SRC(s) if (s) ((H5T_conv_hw_t *)cdata->priv)->s_aligned += nelmts;
+
+/* Increment destination alignment counter */
+# define CI_INC_DST(d) if (d) ((H5T_conv_hw_t *)cdata->priv)->d_aligned += nelmts;
+#else /* H5T_DEBUG */
+# define CI_PRINT_STATS(STYPE,DTYPE) /*void*/
+# define CI_ALLOC_PRIV cdata->priv=NULL;
+# define CI_FREE_PRIV /* void */
+# define CI_INC_SRC(s) /* void */
+# define CI_INC_DST(d) /* void */
+#endif /* H5T_DEBUG */
+
+/* Swap two elements (I & J) of an array using a temporary variable */
+#define H5_SWAP_BYTES(ARRAY,I,J) {uint8_t _tmp; _tmp=ARRAY[I]; ARRAY[I]=ARRAY[J]; ARRAY[J]=_tmp;}
+
+/* Minimum size of variable-length conversion buffer */
+#define H5T_VLEN_MIN_CONF_BUF_SIZE 4096
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Conversion data for H5T__conv_struct() */
+typedef struct H5T_conv_struct_t {
+ int *src2dst; /*mapping from src to dst member num */
+ hid_t *src_memb_id; /*source member type ID's */
+ hid_t *dst_memb_id; /*destination member type ID's */
+ H5T_path_t **memb_path; /*conversion path for each member */
+ H5T_subset_info_t subset_info; /*info related to compound subsets */
+ unsigned src_nmembs; /*needed by free function */
+} H5T_conv_struct_t;
+
+/* Conversion data for H5T__conv_enum() */
+typedef struct H5T_enum_struct_t {
+ int base; /*lowest `in' value */
+ unsigned length; /*num elements in arrays */
+ int *src2dst; /*map from src to dst index */
+} H5T_enum_struct_t;
+
+/* Conversion data for the hardware conversion functions */
+typedef struct H5T_conv_hw_t {
+ size_t s_aligned; /*number source elements aligned */
+ size_t d_aligned; /*number destination elements aligned*/
+} H5T_conv_hw_t;
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static herr_t H5T_reverse_order(uint8_t *rev, uint8_t *s, size_t size, H5T_order_t order);
+
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage pieces of vlen data */
+H5FL_BLK_DEFINE_STATIC(vlen_seq);
+
+/* Declare a free list to manage pieces of array data */
+H5FL_BLK_DEFINE_STATIC(array_seq);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_noop
+ *
+ * Purpose: The no-op conversion. The library knows about this
+ * conversion without it being registered.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 14, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_noop(hid_t H5_ATTR_UNUSED src_id, hid_t H5_ATTR_UNUSED dst_id, H5T_cdata_t *cdata,
+ size_t H5_ATTR_UNUSED nelmts, size_t H5_ATTR_UNUSED buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void H5_ATTR_UNUSED *buf,
+ void H5_ATTR_UNUSED *background, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_CONV:
+ /* Nothing to convert */
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_noop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_order_opt
+ *
+ * Purpose: Convert one type to another when byte order is the only
+ * difference. This is the optimized version of H5T__conv_order()
+ * for a handful of different sizes.
+ *
+ * Note: This is a soft conversion function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 25, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_order_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *background, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ uint8_t *buf = (uint8_t*)_buf;
+ H5T_t *src = NULL;
+ H5T_t *dst = NULL;
+ size_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /* Capability query */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(src->shared->size != dst->shared->size ||
+ 0 != src->shared->u.atomic.offset ||
+ 0 != dst->shared->u.atomic.offset)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ if((src->shared->type == H5T_REFERENCE && dst->shared->type != H5T_REFERENCE) ||
+ (dst->shared->type == H5T_REFERENCE && src->shared->type != H5T_REFERENCE))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ if(src->shared->type != H5T_REFERENCE &&
+ !((H5T_ORDER_BE == src->shared->u.atomic.order && H5T_ORDER_LE == dst->shared->u.atomic.order) ||
+ (H5T_ORDER_LE == src->shared->u.atomic.order && H5T_ORDER_BE == dst->shared->u.atomic.order)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ if(src->shared->size != 1 && src->shared->size != 2 && src->shared->size != 4 &&
+ src->shared->size != 8 && src->shared->size != 16)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ switch(src->shared->type) {
+ case H5T_INTEGER:
+ case H5T_BITFIELD:
+ case H5T_REFERENCE:
+ /* nothing to check */
+ break;
+
+ case H5T_FLOAT:
+ if(src->shared->u.atomic.u.f.sign != dst->shared->u.atomic.u.f.sign ||
+ src->shared->u.atomic.u.f.epos != dst->shared->u.atomic.u.f.epos ||
+ src->shared->u.atomic.u.f.esize != dst->shared->u.atomic.u.f.esize ||
+ src->shared->u.atomic.u.f.ebias != dst->shared->u.atomic.u.f.ebias ||
+ src->shared->u.atomic.u.f.mpos != dst->shared->u.atomic.u.f.mpos ||
+ src->shared->u.atomic.u.f.msize != dst->shared->u.atomic.u.f.msize ||
+ src->shared->u.atomic.u.f.norm != dst->shared->u.atomic.u.f.norm ||
+ src->shared->u.atomic.u.f.pad != dst->shared->u.atomic.u.f.pad)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ }
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_CONV:
+ /* The conversion */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Check for "no op" reference conversion */
+ if(src->shared->type == H5T_REFERENCE) {
+ /* Sanity check */
+ if(dst->shared->type != H5T_REFERENCE)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_REFERENCE datatype")
+
+ /* Check if we are on a little-endian machine (the order that
+ * the addresses in the file must be) and just get out now, there
+ * is no need to convert the object reference. Yes, this is
+ * icky and non-portable, but I can't think of a better way to
+ * support allowing the objno in the H5O_info_t struct and the
+ * hobj_ref_t type to be compared directly without introducing a
+ * "native" hobj_ref_t datatype and I think that would break a
+ * lot of existing programs. -QAK
+ */
+ if(H5T_native_order_g == H5T_ORDER_LE)
+ break;
+ } /* end if */
+
+ buf_stride = buf_stride ? buf_stride : src->shared->size;
+ switch(src->shared->size) {
+ case 1:
+ /*no-op*/
+ break;
+
+ case 2:
+ for(/*void*/; nelmts >= 20; nelmts -= 20) {
+ H5_SWAP_BYTES(buf, 0, 1); /* 0 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 1 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 2 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 3 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 4 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 5 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 6 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 7 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 8 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 9 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 10 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 11 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 12 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 13 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 14 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 15 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 16 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 17 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 18 */
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 1); /* 19 */
+ buf += buf_stride;
+ } /* end for */
+ for(i = 0; i < nelmts; i++, buf += buf_stride)
+ H5_SWAP_BYTES(buf, 0, 1);
+ break;
+
+ case 4:
+ for(/*void*/; nelmts >= 20; nelmts -= 20) {
+ H5_SWAP_BYTES(buf, 0, 3); /* 0 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 1 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 2 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 3 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 4 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 5 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 6 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 7 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 8 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 9 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 10 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 11 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 12 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 13 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 14 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 15 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 16 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 17 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 18 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 3); /* 19 */
+ H5_SWAP_BYTES(buf, 1, 2);
+ buf += buf_stride;
+ } /* end for */
+ for(i = 0; i < nelmts; i++, buf += buf_stride) {
+ H5_SWAP_BYTES(buf, 0, 3);
+ H5_SWAP_BYTES(buf, 1, 2);
+ } /* end for */
+ break;
+
+ case 8:
+ for(/*void*/; nelmts >= 10; nelmts -= 10) {
+ H5_SWAP_BYTES(buf, 0, 7); /* 0 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 1 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 2 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 3 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 4 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 5 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 6 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 7 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 8 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 7); /* 9 */
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ buf += buf_stride;
+ } /* end for */
+ for(i = 0; i < nelmts; i++, buf += buf_stride) {
+ H5_SWAP_BYTES(buf, 0, 7);
+ H5_SWAP_BYTES(buf, 1, 6);
+ H5_SWAP_BYTES(buf, 2, 5);
+ H5_SWAP_BYTES(buf, 3, 4);
+ } /* end for */
+ break;
+
+ case 16:
+ for(/*void*/; nelmts >= 10; nelmts -= 10) {
+ H5_SWAP_BYTES(buf, 0, 15); /* 0 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 1 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 2 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 3 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 4 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 5 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 6 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 7 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 8 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ H5_SWAP_BYTES(buf, 0, 15); /* 9 */
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ buf += buf_stride;
+ } /* end for */
+ for(i = 0; i < nelmts; i++, buf += buf_stride) {
+ H5_SWAP_BYTES(buf, 0, 15);
+ H5_SWAP_BYTES(buf, 1, 14);
+ H5_SWAP_BYTES(buf, 2, 13);
+ H5_SWAP_BYTES(buf, 3, 12);
+ H5_SWAP_BYTES(buf, 4, 11);
+ H5_SWAP_BYTES(buf, 5, 10);
+ H5_SWAP_BYTES(buf, 6, 9);
+ H5_SWAP_BYTES(buf, 7, 8);
+ } /* end for */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "invalid conversion size")
+ } /* end switch */
+ break;
+
+ case H5T_CONV_FREE:
+ /* Free private data */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_order_opt() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_order
+ *
+ * Purpose: Convert one type to another when byte order is the only
+ * difference.
+ *
+ * Note: This is a soft conversion function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, January 13, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * Added the `stride' argument. If its value is non-zero then we
+ * stride through memory converting one value at each location;
+ * otherwise we assume that the values should be packed.
+ *
+ * Robb Matzke, 1999-06-16
+ * Added support for bitfields.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_order(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *background, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ uint8_t *buf = (uint8_t*)_buf;
+ H5T_t *src = NULL;
+ H5T_t *dst = NULL;
+ size_t i;
+ size_t j, md;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /* Capability query */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) ||
+ NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(src->shared->size != dst->shared->size || 0 != src->shared->u.atomic.offset ||
+ 0 != dst->shared->u.atomic.offset ||
+ !((H5T_ORDER_BE == src->shared->u.atomic.order &&
+ H5T_ORDER_LE == dst->shared->u.atomic.order) ||
+ (H5T_ORDER_LE == src->shared->u.atomic.order &&
+ H5T_ORDER_BE == dst->shared->u.atomic.order)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ switch(src->shared->type) {
+ case H5T_INTEGER:
+ case H5T_BITFIELD:
+ /* nothing to check */
+ break;
+
+ case H5T_FLOAT:
+ if(src->shared->u.atomic.u.f.sign != dst->shared->u.atomic.u.f.sign ||
+ src->shared->u.atomic.u.f.epos != dst->shared->u.atomic.u.f.epos ||
+ src->shared->u.atomic.u.f.esize != dst->shared->u.atomic.u.f.esize ||
+ src->shared->u.atomic.u.f.ebias != dst->shared->u.atomic.u.f.ebias ||
+ src->shared->u.atomic.u.f.mpos != dst->shared->u.atomic.u.f.mpos ||
+ src->shared->u.atomic.u.f.msize != dst->shared->u.atomic.u.f.msize ||
+ src->shared->u.atomic.u.f.norm != dst->shared->u.atomic.u.f.norm ||
+ src->shared->u.atomic.u.f.pad != dst->shared->u.atomic.u.f.pad) {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ } /* end if */
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "conversion not supported")
+ } /* end switch */
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_CONV:
+ /* The conversion */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ buf_stride = buf_stride ? buf_stride : src->shared->size;
+ md = src->shared->size / 2;
+ for(i = 0; i < nelmts; i++, buf += buf_stride)
+ for(j = 0; j < md; j++)
+ H5_SWAP_BYTES(buf, j, src->shared->size - (j + 1));
+ break;
+
+ case H5T_CONV_FREE:
+ /* Free private data */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_b_b
+ *
+ * Purpose: Convert from one bitfield to any other bitfield.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 20, 1999
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_b_b(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *background, hid_t dxpl_id)
+{
+ uint8_t *buf = (uint8_t*)_buf;
+ H5T_t *src = NULL, *dst = NULL; /*source and dest datatypes */
+ ssize_t direction; /*direction of traversal */
+ size_t elmtno; /*element number */
+ size_t olap; /*num overlapping elements */
+ size_t half_size; /*1/2 of total size for swapping*/
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t dbuf[256]; /*temp destination buffer */
+ size_t msb_pad_offset; /*offset for dest MSB padding */
+ size_t i;
+ uint8_t *src_rev=NULL; /*order-reversed source buffer */
+ H5P_genplist_t *plist; /*property list pointer */
+ H5T_conv_cb_t cb_struct = {NULL, NULL}; /*conversion callback structure */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ hbool_t reverse; /*if reverse the order of destination */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /* Capability query */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) ||
+ NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_ORDER_LE != src->shared->u.atomic.order &&
+ H5T_ORDER_BE != src->shared->u.atomic.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(H5T_ORDER_LE != dst->shared->u.atomic.order &&
+ H5T_ORDER_BE != dst->shared->u.atomic.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if(src->shared->size == dst->shared->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if(src->shared->size >= dst->shared->size) {
+ double olap_d = HDceil((double)(dst->shared->size) /
+ (double)(src->shared->size - dst->shared->size));
+
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src->shared->size) /
+ (double)(dst->shared->size - src->shared->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts-1) * src->shared->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst->shared->size;
+ direction = -1;
+ }
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist, H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ /* Allocate space for order-reversed source buffer */
+ src_rev = (uint8_t *)H5MM_calloc(src->shared->size);
+
+ /* The conversion loop */
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if(direction > 0) {
+ s = sp;
+ d = elmtno < olap ? dbuf : dp;
+ } /* end if */
+ else {
+ s = sp;
+ d = (elmtno + olap) >= nelmts ? dbuf : dp;
+ } /* end else */
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if(d == dbuf)
+ HDassert((dp >= sp && dp < sp + src->shared->size) ||
+ (sp >= dp && sp < dp + dst->shared->size));
+ else
+ HDassert((dp < sp && dp + dst->shared->size<=sp) ||
+ (sp < dp && sp + src->shared->size<=dp));
+#endif
+
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if(H5T_ORDER_BE == src->shared->u.atomic.order) {
+ half_size = src->shared->size / 2;
+ for(i = 0; i < half_size; i++) {
+ uint8_t tmp = s[src->shared->size - (i + 1)];
+ s[src->shared->size - (i + 1)] = s[i];
+ s[i] = tmp;
+ } /* end for */
+ } /* end if */
+
+ /* Initiate these variables */
+ except_ret = H5T_CONV_UNHANDLED;
+ reverse = TRUE;
+
+ /*
+ * Copy the significant part of the value. If the source is larger
+ * than the destination then invoke the overflow function or copy
+ * as many bits as possible. Zero extra bits in the destination.
+ */
+ if(src->shared->u.atomic.prec > dst->shared->u.atomic.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ } /* end if */
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_copy(d, dst->shared->u.atomic.offset,
+ s, src->shared->u.atomic.offset, dst->shared->u.atomic.prec);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it*/
+ reverse = FALSE;
+ } else {
+ H5T__bit_copy(d, dst->shared->u.atomic.offset,
+ s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec);
+ H5T__bit_set(d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec,
+ dst->shared->u.atomic.prec-src->shared->u.atomic.prec, FALSE);
+ }
+
+ /*
+ * Fill the destination padding areas.
+ */
+ switch(dst->shared->u.atomic.lsb_pad) {
+ case H5T_PAD_ZERO:
+ H5T__bit_set(d, (size_t)0, dst->shared->u.atomic.offset, FALSE);
+ break;
+
+ case H5T_PAD_ONE:
+ H5T__bit_set(d, (size_t)0, dst->shared->u.atomic.offset, TRUE);
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported LSB padding")
+ } /* end switch */
+ msb_pad_offset = dst->shared->u.atomic.offset + dst->shared->u.atomic.prec;
+ switch(dst->shared->u.atomic.msb_pad) {
+ case H5T_PAD_ZERO:
+ H5T__bit_set(d, msb_pad_offset, 8 * dst->shared->size - msb_pad_offset, FALSE);
+ break;
+
+ case H5T_PAD_ONE:
+ H5T__bit_set(d, msb_pad_offset, 8 * dst->shared->size - msb_pad_offset, TRUE);
+ break;
+
+ case H5T_PAD_ERROR:
+ case H5T_PAD_BACKGROUND:
+ case H5T_NPAD:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported MSB padding")
+ } /* end switch */
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if(H5T_ORDER_BE == dst->shared->u.atomic.order && reverse) {
+ half_size = dst->shared->size / 2;
+ for(i = 0; i < half_size; i++) {
+ uint8_t tmp = d[dst->shared->size - (i + 1)];
+ d[dst->shared->size - (i + 1)] = d[i];
+ d[i] = tmp;
+ } /* end for */
+ } /* end if */
+
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if(d == dbuf)
+ HDmemcpy(dp, d, dst->shared->size);
+ if(buf_stride) {
+ sp += direction * (ssize_t)buf_stride; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
+ dp += direction * (ssize_t)buf_stride; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
+ } /* end if */
+ else {
+ sp += direction * (ssize_t)src->shared->size; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
+ dp += direction * (ssize_t)dst->shared->size; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
+ } /* end else */
+ } /* end for */
+
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ if(src_rev)
+ H5MM_free(src_rev);
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_b_b() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_conv_struct_free
+ *
+ * Purpose: Free the private data structure used by the compound
+ * conversion functions.
+ *
+ * Return: The result of H5MM_xfree(priv) (NULL)
+ *
+ * Programmer: Neil Fortner
+ * Wednesday, October 1, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_conv_struct_t *
+H5T_conv_struct_free(H5T_conv_struct_t *priv)
+{
+ int *src2dst = priv->src2dst;
+ hid_t *src_memb_id = priv->src_memb_id,
+ *dst_memb_id = priv->dst_memb_id;
+ unsigned i;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ for(i = 0; i < priv->src_nmembs; i++)
+ if(src2dst[i] >= 0) {
+ int status;
+
+ status = H5I_dec_ref(src_memb_id[i]);
+ HDassert(status >= 0);
+ status = H5I_dec_ref(dst_memb_id[src2dst[i]]);
+ HDassert(status >= 0);
+ } /* end if */
+
+ H5MM_xfree(src2dst);
+ H5MM_xfree(src_memb_id);
+ H5MM_xfree(dst_memb_id);
+ H5MM_xfree(priv->memb_path);
+
+ FUNC_LEAVE_NOAPI((H5T_conv_struct_t *)H5MM_xfree(priv))
+} /* end H5T_conv_struct_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_conv_struct_init
+ *
+ * Purpose: Initialize the `priv' field of `cdata' with conversion
+ * information that is relatively constant. If `priv' is
+ * already initialized then the member conversion functions
+ * are recalculated.
+ *
+ * Priv fields are indexed by source member number or
+ * destination member number depending on whether the field
+ * contains information about the source datatype or the
+ * destination datatype (fields that contains the same
+ * information for both source and destination are indexed by
+ * source member number). The src2dst[] priv array maps source
+ * member numbers to destination member numbers, but if the
+ * source member doesn't have a corresponding destination member
+ * then the src2dst[i]=-1.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 26, 1998
+ *
+ * Modifications:
+ * Raymond Lu, 3 May 2007
+ * Added the detection for a special optimization case when the
+ * source and destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; <-- TYPE1 A;
+ * TYPE2 B; <-- TYPE2 B;
+ * TYPE3 C; <-- TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_conv_struct_init(H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
+{
+ H5T_conv_struct_t *priv = (H5T_conv_struct_t*)(cdata->priv);
+ int *src2dst = NULL;
+ unsigned src_nmembs, dst_nmembs;
+ unsigned i, j;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ src_nmembs = src->shared->u.compnd.nmembs;
+ dst_nmembs = dst->shared->u.compnd.nmembs;
+
+ if(!priv) {
+ /*
+ * Allocate private data structure and arrays.
+ */
+ if(NULL == (priv = (H5T_conv_struct_t *)(cdata->priv=H5MM_calloc(sizeof(H5T_conv_struct_t)))) ||
+ NULL == (priv->src2dst = (int *)H5MM_malloc(src_nmembs * sizeof(int))) ||
+ NULL == (priv->src_memb_id = (hid_t *)H5MM_malloc(src_nmembs * sizeof(hid_t))) ||
+ NULL == (priv->dst_memb_id = (hid_t *)H5MM_malloc(dst_nmembs * sizeof(hid_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ src2dst = priv->src2dst;
+ priv->src_nmembs = src_nmembs;
+
+ /* The flag of special optimization to indicate if source members and destination
+ * members are a subset of each other. Initialize it to FALSE */
+ priv->subset_info.subset = H5T_SUBSET_FALSE;
+ priv->subset_info.copy_size = 0;
+
+ /*
+ * Insure that members are sorted.
+ */
+ H5T__sort_value(src, NULL);
+ H5T__sort_value(dst, NULL);
+
+ /*
+ * Build a mapping from source member number to destination member
+ * number. If some source member is not a destination member then that
+ * mapping element will be negative. Also create atoms for each
+ * source and destination member datatype so we can look up the
+ * member datatype conversion functions later.
+ */
+ for(i = 0; i < src_nmembs; i++) {
+ src2dst[i] = -1;
+ for(j = 0; j < dst_nmembs; j++) {
+ if(!HDstrcmp(src->shared->u.compnd.memb[i].name, dst->shared->u.compnd.memb[j].name)) {
+ H5_CHECKED_ASSIGN(src2dst[i], int, j, unsigned);
+ break;
+ } /* end if */
+ } /* end for */
+ if(src2dst[i] >= 0) {
+ hid_t tid;
+ H5T_t *type;
+
+ type = H5T_copy(src->shared->u.compnd.memb[i].type, H5T_COPY_ALL);
+ tid = H5I_register(H5I_DATATYPE, type, FALSE);
+ HDassert(tid >= 0);
+ priv->src_memb_id[i] = tid;
+
+ type = H5T_copy(dst->shared->u.compnd.memb[src2dst[i]].type, H5T_COPY_ALL);
+ tid = H5I_register(H5I_DATATYPE, type, FALSE);
+ HDassert(tid >= 0);
+ priv->dst_memb_id[src2dst[i]] = tid;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ else {
+ /* Restore sorted conditions for the datatypes */
+ /* (Required for the src2dst array to be valid) */
+ H5T__sort_value(src, NULL);
+ H5T__sort_value(dst, NULL);
+ } /* end else */
+
+ /*
+ * (Re)build the cache of member conversion functions and pointers to
+ * their cdata entries.
+ */
+ src2dst = priv->src2dst;
+ H5MM_xfree(priv->memb_path);
+ if(NULL == (priv->memb_path = (H5T_path_t **)H5MM_malloc(src->shared->u.compnd.nmembs * sizeof(H5T_path_t*))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ for(i = 0; i < src_nmembs; i++) {
+ if(src2dst[i] >= 0) {
+ H5T_path_t *tpath = H5T_path_find(src->shared->u.compnd.memb[i].type, dst->shared->u.compnd.memb[src2dst[i]].type, NULL, NULL, dxpl_id, FALSE);
+
+ if(NULL == (priv->memb_path[i] = tpath)) {
+ cdata->priv = H5T_conv_struct_free(priv);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unable to convert member datatype")
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ /* The compound conversion functions need a background buffer */
+ cdata->need_bkg = H5T_BKG_YES;
+
+ if(src_nmembs < dst_nmembs) {
+ priv->subset_info.subset = H5T_SUBSET_SRC;
+ for(i = 0; i < src_nmembs; i++) {
+ /* If any of source members doesn't have counterpart in the same
+ * order or there's conversion between members, don't do the
+ * optimization.
+ */
+ if(src2dst[i] != (int)i || (src->shared->u.compnd.memb[i].offset != dst->shared->u.compnd.memb[i].offset) || (priv->memb_path[i])->is_noop == FALSE) {
+ priv->subset_info.subset = H5T_SUBSET_FALSE;
+ break;
+ } /* end if */
+ } /* end for */
+ /* Compute the size of the data to be copied for each element. It
+ * may be smaller than either src or dst if there is extra space at
+ * the end of src.
+ */
+ if(priv->subset_info.subset == H5T_SUBSET_SRC)
+ priv->subset_info.copy_size = src->shared->u.compnd.memb[src_nmembs - 1].offset
+ + src->shared->u.compnd.memb[src_nmembs - 1].size;
+ } else if(dst_nmembs < src_nmembs) {
+ priv->subset_info.subset = H5T_SUBSET_DST;
+ for(i = 0; i < dst_nmembs; i++) {
+ /* If any of source members doesn't have counterpart in the same order or
+ * there's conversion between members, don't do the optimization. */
+ if(src2dst[i] != (int)i || (src->shared->u.compnd.memb[i].offset != dst->shared->u.compnd.memb[i].offset) || (priv->memb_path[i])->is_noop == FALSE) {
+ priv->subset_info.subset = H5T_SUBSET_FALSE;
+ break;
+ }
+ } /* end for */
+ /* Compute the size of the data to be copied for each element. It
+ * may be smaller than either src or dst if there is extra space at
+ * the end of dst.
+ */
+ if(priv->subset_info.subset == H5T_SUBSET_DST)
+ priv->subset_info.copy_size = dst->shared->u.compnd.memb[dst_nmembs-1].offset
+ + dst->shared->u.compnd.memb[dst_nmembs-1].size;
+ } else /* If the numbers of source and dest members are equal and no conversion is needed,
+ * the case should have been handled as noop earlier in H5Dio.c. */
+ {;}
+
+ cdata->recalc = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_conv_struct_init() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_struct_subset
+ *
+ * Purpose: A quick way to return a field in a struct private in this
+ * file. The flag SMEMBS_SUBSET indicates whether the source
+ * members are a subset of destination or the destination
+ * members are a subset of the source, and the order is the
+ * same, and no conversion is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ *
+ * Return: A pointer to the subset info struct in p. Points directly
+ * into the structure.
+ *
+ * Programmer: Raymond Lu
+ * 8 June 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_subset_info_t *
+H5T__conv_struct_subset(const H5T_cdata_t *cdata)
+{
+ H5T_conv_struct_t *priv = NULL;
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(cdata);
+ HDassert(cdata->priv);
+
+ priv = (H5T_conv_struct_t *)(cdata->priv);
+
+ FUNC_LEAVE_NOAPI((H5T_subset_info_t *) &priv->subset_info)
+} /* end H5T__conv_struct_subset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_struct
+ *
+ * Purpose: Converts between compound datatypes. This is a soft
+ * conversion function. The algorithm is basically:
+ *
+ * For each element do
+ * For I=1..NELMTS do
+ * If sizeof detination type <= sizeof source type then
+ * Convert member to destination type;
+ * Move member as far left as possible;
+ *
+ * For I=NELMTS..1 do
+ * If not destination type then
+ * Convert member to destination type;
+ * Move member to correct position in BKG
+ *
+ * Copy BKG to BUF
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 22, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_struct(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride, void *_buf, void *_bkg, hid_t dxpl_id)
+{
+ uint8_t *buf = (uint8_t *)_buf; /*cast for pointer arithmetic */
+ uint8_t *bkg = (uint8_t *)_bkg; /*background pointer arithmetic */
+ uint8_t *xbuf = buf, *xbkg = bkg; /*temp pointers into buf and bkg*/
+ H5T_t *src = NULL; /*source datatype */
+ H5T_t *dst = NULL; /*destination datatype */
+ int *src2dst = NULL; /*maps src member to dst member */
+ H5T_cmemb_t *src_memb = NULL; /*source struct member descript.*/
+ H5T_cmemb_t *dst_memb = NULL; /*destination struct memb desc. */
+ size_t offset; /*byte offset wrt struct */
+ ssize_t src_delta; /*source stride */
+ ssize_t bkg_delta; /*background stride */
+ size_t elmtno;
+ unsigned u; /*counters */
+ int i; /*counters */
+ H5T_conv_struct_t *priv = (H5T_conv_struct_t *)(cdata->priv);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * First, determine if this conversion function applies to the
+ * conversion path SRC_ID-->DST_ID. If not, return failure;
+ * otherwise initialize the `priv' field of `cdata' with information
+ * that remains (almost) constant for this conversion path.
+ */
+ if (NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_COMPOUND != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype")
+ if(H5T_COMPOUND != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype")
+
+ if(H5T_conv_struct_init(src, dst, cdata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data")
+ break;
+
+ case H5T_CONV_FREE:
+ /*
+ * Free the private conversion data.
+ */
+ cdata->priv = H5T_conv_struct_free(priv);
+ break;
+
+ case H5T_CONV_CONV:
+ /*
+ * Conversion.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ HDassert(priv);
+ HDassert(bkg && cdata->need_bkg);
+
+ if(cdata->recalc && H5T_conv_struct_init(src, dst, cdata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data")
+
+ /*
+ * Insure that members are sorted.
+ */
+ H5T__sort_value(src, NULL);
+ H5T__sort_value(dst, NULL);
+ src2dst = priv->src2dst;
+
+ /*
+ * Direction of conversion and striding through background.
+ */
+ if(buf_stride) {
+ H5_CHECKED_ASSIGN(src_delta, ssize_t, buf_stride, size_t);
+ if(!bkg_stride) {
+ H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
+ } /* end if */
+ else
+ H5_CHECKED_ASSIGN(bkg_delta, ssize_t, bkg_stride, size_t);
+ } /* end if */
+ else if(dst->shared->size <= src->shared->size) {
+ H5_CHECKED_ASSIGN(src_delta, ssize_t, src->shared->size, size_t);
+ H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
+ } /* end else-if */
+ else {
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ src_delta = -(ssize_t)src->shared->size;
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ bkg_delta = -(ssize_t)dst->shared->size;
+ xbuf += (nelmts - 1) * src->shared->size;
+ xbkg += (nelmts - 1) * dst->shared->size;
+ } /* end else */
+
+ /* Conversion loop... */
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ /*
+ * For each source member which will be present in the
+ * destination, convert the member to the destination type unless
+ * it is larger than the source type. Then move the member to the
+ * left-most unoccupied position in the buffer. This makes the
+ * data point as small as possible with all the free space on the
+ * right side.
+ */
+ for(u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
+ if(src2dst[u] < 0)
+ continue; /*subsetting*/
+ src_memb = src->shared->u.compnd.memb + u;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[u];
+
+ if(dst_memb->size <= src_memb->size) {
+ if(H5T_convert(priv->memb_path[u], priv->src_memb_id[u],
+ priv->dst_memb_id[src2dst[u]],
+ (size_t)1, (size_t)0, (size_t)0, /*no striding (packed array)*/
+ xbuf + src_memb->offset, xbkg + dst_memb->offset,
+ dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert compound datatype member")
+ HDmemmove(xbuf + offset, xbuf + src_memb->offset, dst_memb->size);
+ offset += dst_memb->size;
+ } /* end if */
+ else {
+ HDmemmove (xbuf+offset, xbuf+src_memb->offset,
+ src_memb->size);
+ offset += src_memb->size;
+ } /* end else */
+ } /* end for */
+
+ /*
+ * For each source member which will be present in the
+ * destination, convert the member to the destination type if it
+ * is larger than the source type (that is, has not been converted
+ * yet). Then copy the member to the destination offset in the
+ * background buffer.
+ */
+ H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
+ for(i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
+ if(src2dst[i] < 0)
+ continue; /*subsetting*/
+ src_memb = src->shared->u.compnd.memb + i;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[i];
+
+ if(dst_memb->size > src_memb->size) {
+ offset -= src_memb->size;
+ if(H5T_convert(priv->memb_path[i],
+ priv->src_memb_id[i], priv->dst_memb_id[src2dst[i]],
+ (size_t)1, (size_t)0, (size_t)0, /*no striding (packed array)*/
+ xbuf + offset, xbkg + dst_memb->offset,
+ dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert compound datatype member")
+ } /* end if */
+ else
+ offset -= dst_memb->size;
+ HDmemmove(xbkg + dst_memb->offset, xbuf + offset, dst_memb->size);
+ } /* end for */
+ HDassert(0 == offset);
+
+ /*
+ * Update pointers
+ */
+ xbuf += src_delta;
+ xbkg += bkg_delta;
+ } /* end for */
+
+ /* If the bkg_delta was set to -(dst->shared->size), make it positive now */
+ if(buf_stride == 0 && dst->shared->size > src->shared->size)
+ H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
+
+ /*
+ * Copy the background buffer back into the in-place conversion
+ * buffer.
+ */
+ for(xbuf = buf, xbkg = bkg, elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbuf, xbkg, dst->shared->size);
+ xbuf += buf_stride ? buf_stride : dst->shared->size;
+ xbkg += bkg_delta;
+ } /* end for */
+ break;
+
+ default:
+ /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_struct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_struct_opt
+ *
+ * Purpose: Converts between compound datatypes in a manner more
+ * efficient than the general-purpose H5T__conv_struct()
+ * function. This function isn't applicable if the destination
+ * is larger than the source type. This is a soft conversion
+ * function. The algorithm is basically:
+ *
+ * For each member of the struct
+ * If sizeof detination type <= sizeof source type then
+ * Convert member to destination type for all elements
+ * Move memb to BKG buffer for all elements
+ * Else
+ * Move member as far left as possible for all elements
+ *
+ * For each member of the struct (in reverse order)
+ * If not destination type then
+ * Convert member to destination type for all elements
+ * Move member to correct position in BKG for all elements
+ *
+ * Copy BKG to BUF for all elements
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 22, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is
+ * non-zero then convert one value at each memory location
+ * advancing BUF_STRIDE bytes each time; otherwise assume both
+ * source and destination values are packed.
+ *
+ * Robb Matzke, 1999-06-16
+ * If the source and destination data structs are the same size
+ * then we can convert on a field-by-field basis instead of an
+ * element by element basis. In other words, for all struct
+ * elements being converted by this function call, first convert
+ * all of the field1's, then all field2's, etc. This can
+ * drastically reduce the number of calls to H5T_convert() and
+ * thereby eliminate most of the conversion constant overhead.
+ *
+ * Robb Matzke, 2000-05-17
+ * Added the BKG_STRIDE argument to fix a design bug. If
+ * BUF_STRIDE and BKG_STRIDE are both non-zero then each
+ * data element converted will be placed temporarily at a
+ * multiple of BKG_STRIDE in the BKG buffer; otherwise the
+ * BKG buffer is assumed to be a packed array of destination
+ * datatype.
+ *
+ * Raymond Lu, 3 May 2007
+ * Optimize a special case when the source and destination members
+ * are a subset of each other, and the order is the same, and no
+ * conversion is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_struct_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t bkg_stride, void *_buf,
+ void *_bkg, hid_t dxpl_id)
+{
+ uint8_t *buf = (uint8_t *)_buf; /*cast for pointer arithmetic */
+ uint8_t *bkg = (uint8_t *)_bkg; /*background pointer arithmetic */
+ uint8_t *xbuf = NULL; /*temporary pointer into `buf' */
+ uint8_t *xbkg = NULL; /*temporary pointer into `bkg' */
+ H5T_t *src = NULL; /*source datatype */
+ H5T_t *dst = NULL; /*destination datatype */
+ int *src2dst = NULL; /*maps src member to dst member */
+ H5T_cmemb_t *src_memb = NULL; /*source struct member descript.*/
+ H5T_cmemb_t *dst_memb = NULL; /*destination struct memb desc. */
+ size_t offset; /*byte offset wrt struct */
+ size_t elmtno; /*element counter */
+ size_t copy_size; /*size of element for copying */
+ H5T_conv_struct_t *priv = NULL; /*private data */
+ hbool_t no_stride = FALSE; /*flag to indicate no stride */
+ unsigned u; /*counters */
+ int i; /*counters */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * First, determine if this conversion function applies to the
+ * conversion path SRC_ID-->DST_ID. If not, return failure;
+ * otherwise initialize the `priv' field of `cdata' with information
+ * that remains (almost) constant for this conversion path.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_COMPOUND != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype")
+ if(H5T_COMPOUND != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype")
+
+ /* Initialize data which is relatively constant */
+ if(H5T_conv_struct_init(src, dst, cdata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data")
+ priv = (H5T_conv_struct_t *)(cdata->priv);
+ src2dst = priv->src2dst;
+
+ /*
+ * If the destination type is not larger than the source type then
+ * this conversion function is guaranteed to work (provided all
+ * members can be converted also). Otherwise the determination is
+ * quite a bit more complicated. Essentially we have to make sure
+ * that there is always room in the source buffer to do the
+ * conversion of a member in place. This is basically the same pair
+ * of loops as in the actual conversion except it checks that there
+ * is room for each conversion instead of actually doing anything.
+ */
+ if(dst->shared->size > src->shared->size) {
+ for(u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
+ if(src2dst[u] < 0)
+ continue;
+ src_memb = src->shared->u.compnd.memb + u;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[u];
+ if(dst_memb->size > src_memb->size)
+ offset += src_memb->size;
+ } /* end for */
+ H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
+ for(i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
+ if(src2dst[i] < 0)
+ continue;
+ src_memb = src->shared->u.compnd.memb + i;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[i];
+ if(dst_memb->size > src_memb->size) {
+ offset -= src_memb->size;
+ if(dst_memb->size > src->shared->size-offset) {
+ cdata->priv = H5T_conv_struct_free(priv);
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "convertion is unsupported by this function")
+ } /* end if */
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ break;
+
+ case H5T_CONV_FREE:
+ /*
+ * Free the private conversion data.
+ */
+ cdata->priv = H5T_conv_struct_free((H5T_conv_struct_t *)(cdata->priv));
+ break;
+
+ case H5T_CONV_CONV:
+ /*
+ * Conversion.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Update cached data if necessary */
+ if(cdata->recalc && H5T_conv_struct_init(src, dst, cdata, dxpl_id)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data")
+ priv = (H5T_conv_struct_t *)(cdata->priv);
+ HDassert(priv);
+ src2dst = priv->src2dst;
+ HDassert(bkg && cdata->need_bkg);
+
+ /*
+ * Insure that members are sorted.
+ */
+ H5T__sort_value(src, NULL);
+ H5T__sort_value(dst, NULL);
+
+ /*
+ * Calculate strides. If BUF_STRIDE is non-zero then convert one
+ * data element at every BUF_STRIDE bytes through the main buffer
+ * (BUF), leaving the result of each conversion at the same
+ * location; otherwise assume the source and destination data are
+ * packed tightly based on src->shared->size and dst->shared->size. Also, if
+ * BUF_STRIDE and BKG_STRIDE are both non-zero then place
+ * background data into the BKG buffer at multiples of BKG_STRIDE;
+ * otherwise assume BKG buffer is the packed destination datatype.
+ */
+ if(!buf_stride || !bkg_stride)
+ bkg_stride = dst->shared->size;
+ if(!buf_stride) {
+ no_stride = TRUE;
+ buf_stride = src->shared->size;
+ } /* end if */
+
+ if(priv->subset_info.subset == H5T_SUBSET_SRC || priv->subset_info.subset == H5T_SUBSET_DST) {
+ /* If the optimization flag is set to indicate source members are a subset and
+ * in the top of the destination, simply copy the source members to background buffer.
+ */
+ xbuf = buf;
+ xbkg = bkg;
+ copy_size = priv->subset_info.copy_size;
+
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbkg, xbuf, copy_size);
+
+ /* Update pointers */
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ } /* end for */
+ } /* end if */
+ else {
+ /*
+ * For each member where the destination is not larger than the
+ * source, stride through all the elements converting only that member
+ * in each element and then copying the element to its final
+ * destination in the bkg buffer. Otherwise move the element as far
+ * left as possible in the buffer.
+ */
+ for(u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
+ if(src2dst[u] < 0)
+ continue; /*subsetting*/
+ src_memb = src->shared->u.compnd.memb + u;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[u];
+
+ if(dst_memb->size <= src_memb->size) {
+ xbuf = buf + src_memb->offset;
+ xbkg = bkg + dst_memb->offset;
+ if(H5T_convert(priv->memb_path[u], priv->src_memb_id[u],
+ priv->dst_memb_id[src2dst[u]], nelmts,
+ buf_stride, bkg_stride, xbuf, xbkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert compound datatype member")
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbkg, xbuf, dst_memb->size);
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ } /* end for */
+ } /* end if */
+ else {
+ for(xbuf = buf, elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbuf + offset, xbuf + src_memb->offset, src_memb->size);
+ xbuf += buf_stride;
+ } /* end for */
+ offset += src_memb->size;
+ } /* end else */
+ } /* end else */
+
+ /*
+ * Work from right to left, converting those members that weren't
+ * converted in the previous loop (those members where the destination
+ * is larger than the source) and them to their final position in the
+ * bkg buffer.
+ */
+ H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
+ for(i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
+ if(src2dst[i] < 0)
+ continue;
+ src_memb = src->shared->u.compnd.memb + i;
+ dst_memb = dst->shared->u.compnd.memb + src2dst[i];
+
+ if(dst_memb->size > src_memb->size) {
+ offset -= src_memb->size;
+ xbuf = buf + offset;
+ xbkg = bkg + dst_memb->offset;
+ if(H5T_convert(priv->memb_path[i], priv->src_memb_id[i],
+ priv->dst_memb_id[src2dst[i]], nelmts,
+ buf_stride, bkg_stride, xbuf, xbkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert compound datatype member")
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbkg, xbuf, dst_memb->size);
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ } /* end for */
+ } /* end if */
+ } /* end for */
+ } /* end else */
+
+ if(no_stride)
+ buf_stride = dst->shared->size;
+
+ /* Move background buffer into result buffer */
+ for(xbuf = buf, xbkg = bkg, elmtno = 0; elmtno < nelmts; elmtno++) {
+ HDmemmove(xbuf, xbkg, dst->shared->size);
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ } /* end for */
+ break;
+
+ default:
+ /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_struct_opt() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_conv_enum_init
+ *
+ * Purpose: Initialize information for H5T__conv_enum().
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_conv_enum_init(H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata)
+{
+ H5T_enum_struct_t *priv = NULL; /*private conversion data */
+ int n; /*src value cast as native int */
+ int domain[2] = {0, 0}; /*min and max source values */
+ int *map = NULL; /*map from src value to dst idx */
+ unsigned length; /*nelmts in map array */
+ unsigned i, j; /*counters */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ cdata->need_bkg = H5T_BKG_NO;
+ if(NULL == (priv = (H5T_enum_struct_t *)(cdata->priv = H5MM_calloc(sizeof(*priv)))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(0 == src->shared->u.enumer.nmembs)
+ HGOTO_DONE(SUCCEED);
+
+ /*
+ * Check that the source symbol names are a subset of the destination
+ * symbol names and build a map from source member index to destination
+ * member index.
+ */
+ H5T__sort_name(src, NULL);
+ H5T__sort_name(dst, NULL);
+ if(NULL == (priv->src2dst = (int *)H5MM_malloc(src->shared->u.enumer.nmembs * sizeof(int))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ for(i = 0, j = 0;
+ i < src->shared->u.enumer.nmembs && j < dst->shared->u.enumer.nmembs;
+ i++, j++) {
+ while(j < dst->shared->u.enumer.nmembs &&
+ HDstrcmp(src->shared->u.enumer.name[i], dst->shared->u.enumer.name[j]))
+ j++;
+ if(j >= dst->shared->u.enumer.nmembs)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "source type is not a subset of destination type")
+ priv->src2dst[i] = (int)j;
+ } /* end for */
+
+ /*
+ * The conversion function will use an O(log N) lookup method for each
+ * value converted. However, if all of the following constraints are met
+ * then we can build a perfect hash table and use an O(1) lookup method.
+ *
+ * A: The source datatype size matches one of our native datatype
+ * sizes.
+ *
+ * B: After casting the source value bit pattern to a native type
+ * the size of the range of values is less than 20% larger than
+ * the number of values.
+ *
+ * If this special case is met then we use the source bit pattern cast as
+ * a native integer type as an index into the `val2dst'. The values of
+ * that array are the index numbers in the destination type or negative
+ * if the entry is unused.
+ *
+ * (This optimized algorithm doesn't work when the byte orders are different.
+ * The code such as "n = *((int*)(src->shared->u.enumer.value+i*src->shared->size));"
+ * can change the value significantly. i.g. if the source value is big-endian 0x0000000f,
+ * executing the casting on little-endian machine will get a big number 0x0f000000.
+ * Then it can't meet the condition
+ * "if(src->shared->u.enumer.nmembs<2 || (double)length/src->shared->u.enumer.nmembs<1.2)"
+ * Because this is the optimized code, we won't fix it. It should still work in some
+ * situations. SLU - 2011/5/24)
+ */
+ if(1 == src->shared->size || sizeof(short) == src->shared->size || sizeof(int) == src->shared->size) {
+ for(i = 0; i < src->shared->u.enumer.nmembs; i++) {
+ if(1 == src->shared->size)
+ n = *((signed char *)(src->shared->u.enumer.value + i));
+ else if (sizeof(short) == src->shared->size)
+ n = *((short *)(src->shared->u.enumer.value + i * src->shared->size));
+ else
+ n = *((int *)(src->shared->u.enumer.value + i * src->shared->size));
+ if(0 == i) {
+ domain[0] = domain[1] = n;
+ } else {
+ domain[0] = MIN(domain[0], n);
+ domain[1] = MAX(domain[1], n);
+ }
+ } /* end for */
+
+ HDassert(domain[1] >= domain[0]);
+ length = (unsigned)(domain[1] - domain[0]) + 1;
+ if(src->shared->u.enumer.nmembs < 2 ||
+ (double)length / src->shared->u.enumer.nmembs < (double)(1.2f)) {
+ priv->base = domain[0];
+ priv->length = length;
+ if(NULL == (map = (int *)H5MM_malloc(length * sizeof(int))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ for(i = 0; i < length; i++)
+ map[i] = -1; /*entry unused*/
+ for(i = 0; i < src->shared->u.enumer.nmembs; i++) {
+ if(1 == src->shared->size)
+ n = *((signed char *)(src->shared->u.enumer.value + i));
+ else if(sizeof(short) == src->shared->size)
+ n = *((short *)(src->shared->u.enumer.value + i * src->shared->size));
+ else
+ n = *((int *)(src->shared->u.enumer.value + i * src->shared->size));
+ n -= priv->base;
+ HDassert(n >= 0 && (unsigned)n < priv->length);
+ HDassert(map[n] < 0);
+ map[n] = priv->src2dst[i];
+ } /* end for */
+
+ /*
+ * Replace original src2dst array with our new one. The original
+ * was indexed by source member number while the new one is
+ * indexed by source values.
+ */
+ H5MM_xfree(priv->src2dst);
+ priv->src2dst = map;
+ HGOTO_DONE(SUCCEED);
+ }
+ }
+
+ /* Sort source type by value and adjust src2dst[] appropriately */
+ H5T__sort_value(src, priv->src2dst);
+
+done:
+ if (ret_value<0 && priv) {
+ H5MM_xfree(priv->src2dst);
+ H5MM_xfree(priv);
+ cdata->priv = NULL;
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_enum
+ *
+ * Purpose: Converts one type of enumerated data to another.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_enum(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ uint8_t *buf = (uint8_t*)_buf; /*cast for pointer arithmetic */
+ H5T_t *src = NULL, *dst = NULL; /*src and dst datatypes */
+ uint8_t *s = NULL, *d = NULL; /*src and dst BUF pointers */
+ ssize_t src_delta, dst_delta; /*conversion strides */
+ int n; /*src value cast as native int */
+ H5T_enum_struct_t *priv = (H5T_enum_struct_t*)(cdata->priv);
+ H5P_genplist_t *plist; /*property list pointer */
+ H5T_conv_cb_t cb_struct; /*conversion callback structure */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ size_t i; /*counters */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * Determine if this conversion function applies to the conversion
+ * path SRC_ID->DST_ID. If not return failure; otherwise initialize
+ * the `priv' field of `cdata' with information about the underlying
+ * integer conversion.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_ENUM != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_ENUM datatype")
+ if(H5T_ENUM != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_ENUM datatype")
+
+ if(H5T_conv_enum_init(src, dst, cdata) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize private data")
+ break;
+
+ case H5T_CONV_FREE:
+#ifdef H5T_DEBUG
+ if (H5DEBUG(T)) {
+ fprintf(H5DEBUG(T), " Using %s mapping function%s\n",
+ priv->length?"O(1)":"O(log N)",
+ priv->length?"":", where N is the number of enum members");
+ }
+#endif
+ if (priv) {
+ H5MM_xfree(priv->src2dst);
+ H5MM_xfree(priv);
+ }
+ cdata->priv = NULL;
+ break;
+
+ case H5T_CONV_CONV:
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_ENUM != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_ENUM datatype")
+ if(H5T_ENUM != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_ENUM datatype")
+
+ /* priv->src2dst map was computed for certain sort keys. Make sure those same
+ * sort keys are used here during conversion. See H5T_conv_enum_init(). But
+ * we actually don't care about the source type's order when doing the O(1)
+ * conversion algorithm, which is turned on by non-zero priv->length */
+ H5T__sort_name(dst, NULL);
+ if(!priv->length)
+ H5T__sort_value(src, NULL);
+
+ /*
+ * Direction of conversion.
+ */
+ if(buf_stride) {
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ src_delta = dst_delta = (ssize_t)buf_stride;
+ s = d = buf;
+ } else if(dst->shared->size <= src->shared->size) {
+ H5_CHECKED_ASSIGN(src_delta, ssize_t, src->shared->size, size_t);
+ H5_CHECKED_ASSIGN(dst_delta, ssize_t, dst->shared->size, size_t);
+ s = d = buf;
+ } else {
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ src_delta = -(ssize_t)src->shared->size;
+ dst_delta = -(ssize_t)dst->shared->size;
+ s = buf + (nelmts - 1) * src->shared->size;
+ d = buf + (nelmts - 1) * dst->shared->size;
+ }
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist, H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ for(i = 0; i < nelmts; i++, s += src_delta, d += dst_delta) {
+ if(priv->length) {
+ /* Use O(1) lookup */
+ /* (The casting won't work when the byte orders are different. i.g. if the source value
+ * is big-endian 0x0000000f, the direct casting "n = *((int*)s);" will make it a big
+ * number 0x0f000000 on little-endian machine. But we won't fix it because it's an
+ * optimization code. Please also see the comment in the H5T_conv_enum_init() function.
+ * SLU - 2011/5/24)
+ */
+ if(1 == src->shared->size)
+ n = *((signed char*)s);
+ else if(sizeof(short) == src->shared->size)
+ n = *((short*)s);
+ else
+ n = *((int*)s);
+ n -= priv->base;
+ if(n < 0 || (unsigned)n >= priv->length || priv->src2dst[n] < 0) {
+ /*overflow*/
+ except_ret = H5T_CONV_UNHANDLED;
+ /*If user's exception handler is present, use it*/
+ if(cb_struct.func)
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ s, d, cb_struct.user_data);
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ HDmemset(d, 0xff, dst->shared->size);
+ else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ } else
+ HDmemcpy(d,
+ dst->shared->u.enumer.value + (unsigned)priv->src2dst[n] * dst->shared->size,
+ dst->shared->size);
+ } /* end if */
+ else {
+ /* Use O(log N) lookup */
+ unsigned lt = 0;
+ unsigned rt = src->shared->u.enumer.nmembs;
+ unsigned md = 0;
+ int cmp;
+
+ while(lt < rt) {
+ md = (lt + rt) / 2;
+ cmp = HDmemcmp(s, src->shared->u.enumer.value + md * src->shared->size,
+ src->shared->size);
+ if(cmp < 0)
+ rt = md;
+ else if(cmp > 0)
+ lt = md + 1;
+ else
+ break;
+ } /* end while */
+ if(lt >= rt) {
+ except_ret = H5T_CONV_UNHANDLED;
+ /*If user's exception handler is present, use it*/
+ if(cb_struct.func)
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src, d, cb_struct.user_data);
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ HDmemset(d, 0xff, dst->shared->size);
+ else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ } /* end if */
+ else {
+ HDassert(priv->src2dst[md] >= 0);
+ HDmemcpy(d,
+ dst->shared->u.enumer.value + (unsigned)priv->src2dst[md] * dst->shared->size,
+ dst->shared->size);
+ } /* end else */
+ } /* end else */
+ }
+
+ break;
+
+ default:
+ /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_enum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_enum_numeric
+ *
+ * Purpose: Converts enumerated data to a numeric type (integer or
+ * floating-point number). This function is registered into
+ * the conversion table twice in H5T_init_interface in H5T.c.
+ * Once for enum-integer conversion. Once for enum-float conversion.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * 12 October 2012
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_enum_numeric(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t H5_ATTR_UNUSED buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_t *src, *dst; /*src and dst datatypes */
+ H5T_t *src_parent; /*parent type for src */
+ hid_t src_parent_id = -1; /*ID for parent of the source */
+ H5T_path_t *tpath; /* Conversion information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * Determine if this conversion function applies to the conversion
+ * path SRC_ID->DST_ID. If not, return failure.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_ENUM != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "source type is not a H5T_ENUM datatype")
+ if(H5T_INTEGER != dst->shared->type && H5T_FLOAT != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "destination is not an integer type")
+
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ src_parent = src->shared->parent;
+
+ if(NULL == (tpath = H5T_path_find(src_parent, dst, NULL, NULL, dxpl_id, FALSE))) {
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype")
+ } else if(!H5T_path_noop(tpath)) {
+ if((src_parent_id = H5I_register(H5I_DATATYPE, H5T_copy(src_parent, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+
+ /* Convert the data */
+ if(H5T_convert(tpath, src_parent_id, dst_id, nelmts, buf_stride, bkg_stride, _buf, bkg, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ }
+ break;
+
+ default:
+ /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ /* Release the temporary datatype IDs used */
+ if(src_parent_id >= 0)
+ H5I_dec_ref(src_parent_id);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_enum_numeric() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_vlen
+ *
+ * Purpose: Converts between VL datatypes in memory and on disk.
+ * This is a soft conversion function. The algorithm is
+ * basically:
+ *
+ * For every VL struct in the main buffer:
+ * 1. Allocate space for temporary dst VL data (reuse buffer
+ * if possible)
+ * 2. Copy VL data from src buffer into dst buffer
+ * 3. Convert VL data into dst representation
+ * 4. Allocate buffer in dst heap
+ * 5. Free heap objects storing old data
+ * 6. Write dst VL data into dst heap
+ * 7. Store (heap ID or pointer) and length in main dst buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 26, 1999
+ *
+ * Modifications:
+ *
+ * Quincey Koziol, 2 July, 1999
+ * Enabled support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *
+ * Raymond Lu, 26 June, 2002
+ * Background buffer is used for freeing heap objects storing
+ * old data. At this moment, it only frees the first level of
+ * VL datatype. It doesn't handle nested VL datatypes.
+ *
+ * Raymond Lu, 8 November 2011
+ * I put a condition check to prevent the conversion of VL strings
+ * between ASCII and UTF8.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_vlen(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride, void *buf, void *bkg, hid_t dxpl_id)
+{
+ H5T_vlen_alloc_info_t _vl_alloc_info; /* VL allocation info buffer */
+ H5T_vlen_alloc_info_t *vl_alloc_info = &_vl_alloc_info; /* VL allocation info */
+ H5T_path_t *tpath = NULL; /* Type conversion path */
+ hbool_t noop_conv = FALSE; /* Flag to indicate a noop conversion */
+ hbool_t write_to_file = FALSE; /* Flag to indicate writing to file */
+ htri_t parent_is_vlen; /* Flag to indicate parent is vlen datatyp */
+ hid_t tsrc_id = -1, tdst_id = -1;/*temporary type atoms */
+ H5T_t *src = NULL; /*source datatype */
+ H5T_t *dst = NULL; /*destination datatype */
+ H5HG_t bg_hobjid, parent_hobjid;
+ uint8_t *s = NULL; /*source buffer */
+ uint8_t *d = NULL; /*destination buffer */
+ uint8_t *b = NULL; /*background buffer */
+ ssize_t s_stride, d_stride; /*src and dst strides */
+ ssize_t b_stride; /*bkg stride */
+ size_t safe; /*how many elements are safe to process in each pass */
+ size_t bg_seq_len = 0;
+ size_t src_base_size, dst_base_size;/*source & destination base size*/
+ void *conv_buf = NULL; /*temporary conversion buffer */
+ size_t conv_buf_size = 0; /*size of conversion buffer in bytes */
+ void *tmp_buf = NULL; /*temporary background buffer */
+ size_t tmp_buf_size = 0; /*size of temporary bkg buffer */
+ hbool_t nested = FALSE; /*flag of nested VL case */
+ size_t elmtno; /*element number counter */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * First, determine if this conversion function applies to the
+ * conversion path SRC_ID-->DST_ID. If not, return failure;
+ * otherwise initialize the `priv' field of `cdata' with
+ * information that remains (almost) constant for this
+ * conversion path.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_VLEN != src->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_VLEN datatype")
+ if(H5T_VLEN != dst->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_VLEN datatype")
+ if(H5T_VLEN_STRING == src->shared->u.vlen.type && H5T_VLEN_STRING == dst->shared->u.vlen.type) {
+ if((H5T_CSET_ASCII == src->shared->u.vlen.cset && H5T_CSET_UTF8 == dst->shared->u.vlen.cset)
+ || (H5T_CSET_ASCII == dst->shared->u.vlen.cset && H5T_CSET_UTF8 == src->shared->u.vlen.cset))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "The library doesn't convert between strings of ASCII and UTF")
+ }
+
+ /* Variable-length types don't need a background buffer */
+ cdata->need_bkg = H5T_BKG_NO;
+
+ break;
+
+ case H5T_CONV_FREE:
+ /* QAK - Nothing to do currently */
+ break;
+
+ case H5T_CONV_CONV:
+ /*
+ * Conversion.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Initialize source & destination strides */
+ if(buf_stride) {
+ HDassert(buf_stride >= src->shared->size);
+ HDassert(buf_stride >= dst->shared->size);
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ s_stride = d_stride = (ssize_t)buf_stride;
+ } /* end if */
+ else {
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ s_stride = (ssize_t)src->shared->size;
+ d_stride = (ssize_t)dst->shared->size;
+ } /* end else */
+ if(bkg) {
+ if(bkg_stride)
+ b_stride = (ssize_t)bkg_stride;
+ else
+ b_stride = d_stride;
+ } /* end if */
+ else
+ b_stride = 0;
+
+ /* Get the size of the base types in src & dst */
+ src_base_size = H5T_get_size(src->shared->parent);
+ dst_base_size = H5T_get_size(dst->shared->parent);
+
+ /* Set up conversion path for base elements */
+ if(NULL == (tpath = H5T_path_find(src->shared->parent, dst->shared->parent, NULL, NULL, dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatypes")
+ else if(!H5T_path_noop(tpath)) {
+ if((tsrc_id = H5I_register(H5I_DATATYPE, H5T_copy(src->shared->parent, H5T_COPY_ALL), FALSE)) < 0 ||
+ (tdst_id = H5I_register(H5I_DATATYPE, H5T_copy(dst->shared->parent, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+ } /* end else-if */
+ else
+ noop_conv = TRUE;
+
+ /* Check if we need a temporary buffer for this conversion */
+ if((parent_is_vlen = H5T_detect_class(dst->shared->parent, H5T_VLEN, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_SYSTEM, FAIL, "internal error when detecting variable-length class")
+ if(tpath->cdata.need_bkg || parent_is_vlen) {
+ /* Set up initial background buffer */
+ tmp_buf_size = MAX(src_base_size, dst_base_size);
+ if(NULL == (tmp_buf = H5FL_BLK_CALLOC(vlen_seq,tmp_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for type conversion")
+ } /* end if */
+
+ /* Get the allocation info */
+ if(H5T_vlen_get_alloc_info(dxpl_id, &vl_alloc_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve VL allocation info")
+
+ /* Set flags to indicate we are writing to or reading from the file */
+ if(dst->shared->u.vlen.f != NULL)
+ write_to_file = TRUE;
+
+ /* Set the flag for nested VL case */
+ if(write_to_file && parent_is_vlen && bkg != NULL)
+ nested = TRUE;
+
+ /* The outer loop of the type conversion macro, controlling which */
+ /* direction the buffer is walked */
+ while(nelmts > 0) {
+ /* Check if we need to go backwards through the buffer */
+ if(d_stride > s_stride) {
+ /* Sanity check */
+ HDassert(s_stride > 0);
+ HDassert(d_stride > 0);
+ HDassert(b_stride >= 0);
+
+ /* Compute the number of "safe" destination elements at */
+ /* the end of the buffer (Those which don't overlap with */
+ /* any source elements at the beginning of the buffer) */
+ safe = nelmts - (((nelmts * (size_t)s_stride) + ((size_t)d_stride - 1)) / (size_t)d_stride);
+
+ /* If we're down to the last few elements, just wrap up */
+ /* with a "real" reverse copy */
+ if(safe < 2) {
+ s = (uint8_t *)buf + (nelmts - 1) * (size_t)s_stride;
+ d = (uint8_t *)buf + (nelmts - 1) * (size_t)d_stride;
+ b = (uint8_t *)bkg + (nelmts - 1) * (size_t)b_stride;
+ s_stride = -s_stride;
+ d_stride = -d_stride;
+ b_stride = -b_stride;
+
+ safe = nelmts;
+ } /* end if */
+ else {
+ s = (uint8_t *)buf + (nelmts - safe) * (size_t)s_stride;
+ d = (uint8_t *)buf + (nelmts - safe) * (size_t)d_stride;
+ b = (uint8_t *)bkg + (nelmts - safe) * (size_t)b_stride;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Single forward pass over all data */
+ s = d = (uint8_t *)buf;
+ b = (uint8_t *)bkg;
+ safe = nelmts;
+ } /* end else */
+
+ for(elmtno = 0; elmtno < safe; elmtno++) {
+ /* Check for "nil" source sequence */
+ if((*(src->shared->u.vlen.isnull))(src->shared->u.vlen.f, s)) {
+ /* Write "nil" sequence to destination location */
+ if((*(dst->shared->u.vlen.setnull))(dst->shared->u.vlen.f, dxpl_id, d, b) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "can't set VL data to 'nil'")
+ } /* end if */
+ else {
+ ssize_t sseq_len; /* (signed) The number of elements in the current sequence*/
+ size_t seq_len; /* The number of elements in the current sequence*/
+
+ /* Get length of element sequences */
+ if((sseq_len = (*(src->shared->u.vlen.getlen))(s)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "incorrect length")
+ seq_len = (size_t)sseq_len;
+
+ /* If we are reading from memory and there is no conversion, just get the pointer to sequence */
+ if(write_to_file && noop_conv) {
+ /* Get direct pointer to sequence */
+ if(NULL == (conv_buf = (*(src->shared->u.vlen.getptr))(s)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid source pointer")
+ } /* end if */
+ else {
+ size_t src_size, dst_size; /*source & destination total size in bytes*/
+
+ src_size = seq_len * src_base_size;
+ dst_size = seq_len * dst_base_size;
+
+ /* Check if conversion buffer is large enough, resize if
+ * necessary. If the SEQ_LEN is 0, allocate a minimal size buffer.
+ */
+ if(!seq_len && !conv_buf) {
+ conv_buf_size = ((1 / H5T_VLEN_MIN_CONF_BUF_SIZE) + 1) * H5T_VLEN_MIN_CONF_BUF_SIZE;
+ if(NULL == (conv_buf = H5FL_BLK_CALLOC(vlen_seq, conv_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ }
+ else if(conv_buf_size < MAX(src_size, dst_size)) {
+ /* Only allocate conversion buffer in H5T_VLEN_MIN_CONF_BUF_SIZE increments */
+ conv_buf_size = ((MAX(src_size, dst_size) / H5T_VLEN_MIN_CONF_BUF_SIZE) + 1) * H5T_VLEN_MIN_CONF_BUF_SIZE;
+ if(NULL == (conv_buf = H5FL_BLK_REALLOC(vlen_seq, conv_buf, conv_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ HDmemset(conv_buf, 0, conv_buf_size);
+ } /* end if */
+
+ /* Read in VL sequence */
+ if((*(src->shared->u.vlen.read))(src->shared->u.vlen.f, dxpl_id, s, conv_buf, src_size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_READERROR, FAIL, "can't read VL data")
+ } /* end else */
+
+ if(!noop_conv) {
+ /* Check if temporary buffer is large enough, resize if necessary */
+ /* (Chain off the conversion buffer size) */
+ if(tmp_buf && tmp_buf_size < conv_buf_size) {
+ /* Set up initial background buffer */
+ tmp_buf_size = conv_buf_size;
+ if(NULL == (tmp_buf = H5FL_BLK_REALLOC(vlen_seq, tmp_buf, tmp_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ HDmemset(tmp_buf, 0, tmp_buf_size);
+ } /* end if */
+
+ /* If we are writing and there is a nested VL type, read
+ * the sequence into the background buffer */
+ if(nested) {
+ const uint8_t *tmp = b;
+
+ UINT32DECODE(tmp, bg_seq_len);
+ if(bg_seq_len > 0) {
+ if(tmp_buf_size < (bg_seq_len * MAX(src_base_size, dst_base_size))) {
+ tmp_buf_size = (bg_seq_len * MAX(src_base_size, dst_base_size));
+ if(NULL == (tmp_buf = H5FL_BLK_REALLOC(vlen_seq, tmp_buf, tmp_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ HDmemset(tmp_buf, 0, tmp_buf_size);
+ } /* end if */
+ H5F_addr_decode(dst->shared->u.vlen.f, &tmp, &(bg_hobjid.addr));
+ UINT32DECODE(tmp, bg_hobjid.idx);
+ if(NULL == H5HG_read(dst->shared->u.vlen.f, dxpl_id, &bg_hobjid, tmp_buf, NULL))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_READERROR, FAIL, "can't read VL sequence into background buffer")
+ } /* end if */
+
+ /* If the sequence gets shorter, pad out the original sequence with zeros */
+ if(bg_seq_len < seq_len)
+ HDmemset((uint8_t *)tmp_buf + dst_base_size * bg_seq_len, 0, (seq_len - bg_seq_len) * dst_base_size);
+ } /* end if */
+
+ /* Convert VL sequence */
+ if(H5T_convert(tpath, tsrc_id, tdst_id, seq_len, (size_t)0, (size_t)0, conv_buf, tmp_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ } /* end if */
+
+ /* Write sequence to destination location */
+ if((*(dst->shared->u.vlen.write))(dst->shared->u.vlen.f, dxpl_id, vl_alloc_info, d, conv_buf, b, seq_len, dst_base_size) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "can't write VL data")
+
+ if(!noop_conv) {
+ /* For nested VL case, free leftover heap objects from the deeper level if the length of new data elements is shorter than the old data elements.*/
+ if(nested && seq_len < bg_seq_len) {
+ size_t parent_seq_len;
+ const uint8_t *tmp;
+ size_t u;
+
+ /* TMP_P is reset each time in the loop because DST_BASE_SIZE may include some data in addition to VL info. - SLU */
+ for(u = seq_len; u < bg_seq_len; u++) {
+ tmp = (uint8_t *)tmp_buf + u * dst_base_size;
+ UINT32DECODE(tmp, parent_seq_len);
+ if(parent_seq_len > 0) {
+ H5F_addr_decode(dst->shared->u.vlen.f, &tmp, &(parent_hobjid.addr));
+ UINT32DECODE(tmp, parent_hobjid.idx);
+ if(H5HG_remove(dst->shared->u.vlen.f, dxpl_id, &parent_hobjid) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to remove heap object")
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ } /* end if */
+ } /* end else */
+
+ /* Advance pointers */
+ s += s_stride;
+ d += d_stride;
+ b += b_stride;
+ } /* end for */
+
+ /* Decrement number of elements left to convert */
+ nelmts -= safe;
+ } /* end while */
+
+ /* Release the temporary datatype IDs used */
+ if(tsrc_id >= 0)
+ H5I_dec_ref(tsrc_id);
+ if(tdst_id >= 0)
+ H5I_dec_ref(tdst_id);
+ break;
+
+ default: /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ /* If the conversion buffer doesn't need to be freed, reset its pointer */
+ if(write_to_file && noop_conv)
+ conv_buf = NULL;
+ /* Release the conversion buffer (always allocated, except on errors) */
+ if(conv_buf)
+ conv_buf = H5FL_BLK_FREE(vlen_seq, conv_buf);
+ /* Release the background buffer, if we have one */
+ if(tmp_buf)
+ tmp_buf = H5FL_BLK_FREE(vlen_seq, tmp_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_vlen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_array
+ *
+ * Purpose: Converts between array datatypes in memory and on disk.
+ * This is a soft conversion function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_array(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride, void *_buf,
+ void H5_ATTR_UNUSED *_bkg, hid_t dxpl_id)
+{
+ H5T_path_t *tpath; /* Type conversion path */
+ hid_t tsrc_id = -1, tdst_id = -1;/*temporary type atoms */
+ H5T_t *src = NULL; /*source datatype */
+ H5T_t *dst = NULL; /*destination datatype */
+ uint8_t *sp, *dp; /*source and dest traversal ptrs */
+ ssize_t src_delta, dst_delta; /*source & destination stride */
+ int direction; /*direction of traversal */
+ size_t elmtno; /*element number counter */
+ unsigned u; /* local index variable */
+ void *bkg_buf = NULL; /*temporary background buffer */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch (cdata->command) {
+ case H5T_CONV_INIT:
+ /*
+ * First, determine if this conversion function applies to the
+ * conversion path SRC_ID-->DST_ID. If not, return failure;
+ * otherwise initialize the `priv' field of `cdata' with
+ * information that remains (almost) constant for this
+ * conversion path.
+ */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ HDassert(H5T_ARRAY==src->shared->type);
+ HDassert(H5T_ARRAY==dst->shared->type);
+
+ /* Check the number and sizes of the dimensions */
+ if(src->shared->u.array.ndims != dst->shared->u.array.ndims)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "array datatypes do not have the same number of dimensions")
+ for(u = 0; u < src->shared->u.array.ndims; u++)
+ if(src->shared->u.array.dim[u] != dst->shared->u.array.dim[u])
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "array datatypes do not have the same sizes of dimensions")
+
+ /* Array datatypes don't need a background buffer */
+ cdata->need_bkg = H5T_BKG_NO;
+
+ break;
+
+ case H5T_CONV_FREE:
+ /* QAK - Nothing to do currently */
+ break;
+
+ case H5T_CONV_CONV:
+ /*
+ * Conversion.
+ */
+ if (NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /*
+ * Do we process the values from beginning to end or vice
+ * versa? Also, how many of the elements have the source and
+ * destination areas overlapping?
+ */
+ if(src->shared->size >= dst->shared->size || buf_stride > 0) {
+ sp = dp = (uint8_t*)_buf;
+ direction = 1;
+ } else {
+ sp = (uint8_t*)_buf + (nelmts - 1) *
+ (buf_stride ? buf_stride : src->shared->size);
+ dp = (uint8_t*)_buf + (nelmts - 1) *
+ (buf_stride ? buf_stride : dst->shared->size);
+ direction = -1;
+ }
+
+ /*
+ * Direction & size of buffer traversal.
+ */
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ src_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : src->shared->size);
+ dst_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : dst->shared->size);
+
+ /* Set up conversion path for base elements */
+ if(NULL == (tpath = H5T_path_find(src->shared->parent, dst->shared->parent, NULL, NULL, dxpl_id, FALSE))) {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatypes")
+ } else if (!H5T_path_noop(tpath)) {
+ if((tsrc_id = H5I_register(H5I_DATATYPE, H5T_copy(src->shared->parent, H5T_COPY_ALL), FALSE)) < 0 ||
+ (tdst_id = H5I_register(H5I_DATATYPE, H5T_copy(dst->shared->parent, H5T_COPY_ALL), FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion")
+ }
+
+ /* Check if we need a background buffer for this conversion */
+ if(tpath->cdata.need_bkg) {
+ size_t bkg_buf_size; /*size of background buffer in bytes */
+
+ /* Allocate background buffer */
+ bkg_buf_size = src->shared->u.array.nelem * MAX(src->shared->size, dst->shared->size);
+ if(NULL == (bkg_buf = H5FL_BLK_CALLOC(array_seq, bkg_buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
+ } /* end if */
+
+ /* Perform the actual conversion */
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ /* Copy the source array into the correct location for the destination */
+ HDmemmove(dp, sp, src->shared->size);
+
+ /* Convert array */
+ if(H5T_convert(tpath, tsrc_id, tdst_id, src->shared->u.array.nelem, (size_t)0, bkg_stride, dp, bkg_buf, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ /* Advance the source & destination pointers */
+ sp += src_delta;
+ dp += dst_delta;
+ } /* end for */
+
+ /* Release the temporary datatype IDs used */
+ if(tsrc_id >= 0)
+ H5I_dec_ref(tsrc_id);
+ if(tdst_id >= 0)
+ H5I_dec_ref(tdst_id);
+ break;
+
+ default: /* Some other command we don't know about yet.*/
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ /* Release the background buffer, if we have one */
+ if(bkg_buf)
+ bkg_buf = H5FL_BLK_FREE(array_seq, bkg_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_array() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_i_i
+ *
+ * Purpose: Convert one integer type to another. This is the catch-all
+ * function for integer conversions and is probably not
+ * particularly fast.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, June 10, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 7 Jul 1998
+ * Added overflow handling.
+ *
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *
+ * Raymond Lu
+ * Wednesday, April 21, 2004
+ * There is a new design for exception handling like overflow,
+ * which is passed in as a transfer property.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_i_i(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+ H5T_t *src = NULL; /*source datatype */
+ H5T_t *dst = NULL; /*destination datatype */
+ ssize_t src_delta, dst_delta; /*source & destination stride */
+ int direction; /*direction of traversal */
+ size_t elmtno; /*element number */
+ size_t half_size; /*half the type size */
+ size_t olap; /*num overlapping elements */
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t *src_rev=NULL; /*order-reversed source buffer */
+ uint8_t dbuf[64]; /*temp destination buffer */
+ size_t first;
+ ssize_t sfirst; /*a signed version of `first' */
+ size_t i; /*Local index variables */
+ H5P_genplist_t *plist; /*property list pointer */
+ H5T_conv_cb_t cb_struct={NULL, NULL}; /*conversion callback structure */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ hbool_t reverse; /*if reverse the order of destination */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_ORDER_LE != src->shared->u.atomic.order && H5T_ORDER_BE != src->shared->u.atomic.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(H5T_ORDER_LE != dst->shared->u.atomic.order && H5T_ORDER_BE != dst->shared->u.atomic.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(dst->shared->size > sizeof dbuf)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination size is too large")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if (src->shared->size==dst->shared->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if (src->shared->size>=dst->shared->size) {
+ double olap_d = HDceil((double)(dst->shared->size)/
+ (double)(src->shared->size-dst->shared->size));
+
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src->shared->size)/
+ (double)(dst->shared->size-src->shared->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts - 1) * src->shared->size;
+ dp = (uint8_t*)buf + (nelmts - 1) * dst->shared->size;
+ direction = -1;
+ }
+
+ /*
+ * Direction & size of buffer traversal.
+ */
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ src_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : src->shared->size);
+ dst_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : dst->shared->size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist,H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ /* Allocate space for order-reversed source buffer */
+ src_rev = (uint8_t*)H5MM_calloc(src->shared->size);
+
+ /* The conversion loop */
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if(direction > 0) {
+ s = sp;
+ d = elmtno < olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno + olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (d==dbuf) {
+ HDassert((dp>=sp && dp<sp+src->shared->size) || (sp>=dp && sp<dp+dst->shared->size));
+ } else {
+ HDassert((dp<sp && dp+dst->shared->size<=sp) || (sp<dp && sp+src->shared->size<=dp));
+ }
+#endif
+
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if (H5T_ORDER_BE==src->shared->u.atomic.order) {
+ half_size = src->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = s[src->shared->size-(i+1)];
+ s[src->shared->size-(i+1)] = s[i];
+ s[i] = tmp;
+ }
+ }
+
+ /*
+ * What is the bit number for the msb bit of S which is set? The
+ * bit number is relative to the significant part of the number.
+ */
+ sfirst = H5T__bit_find (s, src->shared->u.atomic.offset, src->shared->u.atomic.prec,
+ H5T_BIT_MSB, TRUE);
+ first = (size_t)sfirst;
+
+ /* Set these variables to default */
+ except_ret = H5T_CONV_UNHANDLED;
+ reverse = TRUE;
+
+ if (sfirst<0) {
+ /*
+ * The source has no bits set and must therefore be zero.
+ * Set the destination to zero.
+ */
+ H5T__bit_set (d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec, FALSE);
+
+ } else if (H5T_SGN_NONE==src->shared->u.atomic.u.i.sign &&
+ H5T_SGN_NONE==dst->shared->u.atomic.u.i.sign) {
+ /*
+ * Source and destination are both unsigned, but if the
+ * source has more precision bits than the destination then
+ * it's possible to overflow. When overflow occurs the
+ * destination will be set to the maximum possible value.
+ */
+ if (src->shared->u.atomic.prec <= dst->shared->u.atomic.prec) {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec,
+ dst->shared->u.atomic.prec-src->shared->u.atomic.prec, FALSE);
+ } else if (first>=dst->shared->u.atomic.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_set (d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec, TRUE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ dst->shared->u.atomic.prec);
+ }
+
+ } else if (H5T_SGN_2==src->shared->u.atomic.u.i.sign &&
+ H5T_SGN_NONE==dst->shared->u.atomic.u.i.sign) {
+ /*
+ * If the source is signed and the destination isn't then we
+ * can have overflow if the source contains more bits than
+ * the destination (destination is set to the maximum
+ * possible value) or overflow if the source is negative
+ * (destination is set to zero).
+ */
+ if (first+1 == src->shared->u.atomic.prec) {
+ /*overflow - source is negative*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_set (d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec, FALSE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else if (src->shared->u.atomic.prec < dst->shared->u.atomic.prec) {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec-1);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec-1,
+ (dst->shared->u.atomic.prec-src->shared->u.atomic.prec)+1, FALSE);
+ } else if (first>=dst->shared->u.atomic.prec) {
+ /*overflow - source is positive*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ H5T__bit_set (d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec, TRUE);
+ else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ dst->shared->u.atomic.prec);
+ }
+
+ } else if (H5T_SGN_NONE==src->shared->u.atomic.u.i.sign &&
+ H5T_SGN_2==dst->shared->u.atomic.u.i.sign) {
+ /*
+ * If the source is not signed but the destination is then
+ * overflow can occur in which case the destination is set to
+ * the largest possible value (all bits set except the msb).
+ */
+ if (first+1 >= dst->shared->u.atomic.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_set(d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec-1, TRUE);
+ H5T__bit_set(d, (dst->shared->u.atomic.offset + dst->shared->u.atomic.prec-1), (size_t)1, FALSE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else if (src->shared->u.atomic.prec<dst->shared->u.atomic.prec) {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec,
+ dst->shared->u.atomic.prec-src->shared->u.atomic.prec, FALSE);
+ } else {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ dst->shared->u.atomic.prec);
+ }
+ } else if (first+1 == src->shared->u.atomic.prec) {
+ /*
+ * Both the source and the destination are signed and the
+ * source value is negative. We could experience overflow
+ * if the destination isn't wide enough in which case the
+ * destination is set to a negative number with the largest
+ * possible magnitude.
+ */
+ ssize_t sfz = H5T__bit_find (s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec-1, H5T_BIT_MSB, FALSE);
+ size_t fz = (size_t)sfz;
+
+ if (sfz>=0 && fz+1>=dst->shared->u.atomic.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_set(d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec-1, FALSE);
+ H5T__bit_set(d, (dst->shared->u.atomic.offset + dst->shared->u.atomic.prec-1), (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else if (src->shared->u.atomic.prec<dst->shared->u.atomic.prec) {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset, src->shared->u.atomic.prec);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec, dst->shared->u.atomic.prec-src->shared->u.atomic.prec, TRUE);
+ } else {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset, dst->shared->u.atomic.prec);
+ }
+
+ } else {
+ /*
+ * Source and destination are both signed but the source
+ * value is positive. We could have an overflow in which
+ * case the destination is set to the largest possible
+ * positive value.
+ */
+ if (first+1>=dst->shared->u.atomic.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ H5T_reverse_order(src_rev, s, src->shared->size, src->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id, src_rev, d,
+ cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_set(d, dst->shared->u.atomic.offset, dst->shared->u.atomic.prec-1, TRUE);
+ H5T__bit_set(d, (dst->shared->u.atomic.offset + dst->shared->u.atomic.prec-1), (size_t)1, FALSE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED)
+ /*Don't reverse because user handles it already*/
+ reverse = FALSE;
+ } else if (src->shared->u.atomic.prec<dst->shared->u.atomic.prec) {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ src->shared->u.atomic.prec);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+src->shared->u.atomic.prec,
+ dst->shared->u.atomic.prec-src->shared->u.atomic.prec, FALSE);
+ } else {
+ H5T__bit_copy (d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
+ dst->shared->u.atomic.prec);
+ }
+ }
+
+ /*
+ * Set padding areas in destination.
+ */
+ if (dst->shared->u.atomic.offset>0) {
+ HDassert(H5T_PAD_ZERO==dst->shared->u.atomic.lsb_pad || H5T_PAD_ONE==dst->shared->u.atomic.lsb_pad);
+ H5T__bit_set(d, (size_t)0, dst->shared->u.atomic.offset, (hbool_t)(H5T_PAD_ONE==dst->shared->u.atomic.lsb_pad));
+ }
+ if (dst->shared->u.atomic.offset+dst->shared->u.atomic.prec!=8*dst->shared->size) {
+ HDassert(H5T_PAD_ZERO==dst->shared->u.atomic.msb_pad || H5T_PAD_ONE==dst->shared->u.atomic.msb_pad);
+ H5T__bit_set (d, dst->shared->u.atomic.offset+dst->shared->u.atomic.prec,
+ 8*dst->shared->size - (dst->shared->u.atomic.offset+ dst->shared->u.atomic.prec),
+ (hbool_t)(H5T_PAD_ONE==dst->shared->u.atomic.msb_pad));
+ }
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if (H5T_ORDER_BE==dst->shared->u.atomic.order && reverse) {
+ half_size = dst->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = d[dst->shared->size-(i+1)];
+ d[dst->shared->size-(i+1)] = d[i];
+ d[i] = tmp;
+ }
+ }
+
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if(d==dbuf)
+ HDmemcpy(dp, d, dst->shared->size);
+
+ /* Advance source & destination pointers by delta amounts */
+ sp += src_delta;
+ dp += dst_delta;
+ } /* end for */
+
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ if(src_rev)
+ H5MM_free(src_rev);
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_i_i() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_f_f
+ *
+ * Purpose: Convert one floating point type to another. This is a catch
+ * all for floating point conversions and is probably not
+ * particularly fast!
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 23, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 7 Jul 1998
+ * Added overflow handling.
+ *
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *
+ * Robb Matzke, 2001-02-02
+ * Oops, forgot to increment the exponent when rounding the
+ * significand resulted in a carry. Thanks to Guillaume Colin
+ * de Verdiere for finding this one!
+ *
+ * Raymond Lu, 2006-03-13
+ * Added support for VAX floating-point types.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_f_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+ /* Traversal-related variables */
+ H5T_t *src_p; /*source datatype */
+ H5T_t *dst_p; /*destination datatype */
+ H5T_atomic_t src; /*atomic source info */
+ H5T_atomic_t dst; /*atomic destination info */
+ ssize_t src_delta, dst_delta; /*source & destination stride */
+ int direction; /*forward or backward traversal */
+ size_t elmtno; /*element number */
+ size_t half_size; /*half the type size */
+ size_t tsize; /*type size for swapping bytes */
+ size_t olap; /*num overlapping elements */
+ ssize_t bitno = 0; /*bit number */
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t *src_rev = NULL; /*order-reversed source buffer */
+ uint8_t dbuf[64]; /*temp destination buffer */
+ uint8_t tmp1, tmp2; /*temp variables for swapping bytes*/
+
+ /* Conversion-related variables */
+ int64_t expo; /*exponent */
+ hssize_t expo_max; /*maximum possible dst exponent */
+ size_t msize = 0; /*useful size of mantissa in src*/
+ size_t mpos; /*offset to useful mant is src */
+ uint64_t sign; /*source sign bit value */
+ size_t mrsh; /*amount to right shift mantissa*/
+ hbool_t carry = FALSE; /*carry after rounding mantissa */
+ size_t i; /*miscellaneous counters */
+ size_t implied; /*destination implied bits */
+ hbool_t denormalized = FALSE; /*is either source or destination denormalized?*/
+ H5P_genplist_t *plist; /*property list pointer */
+ H5T_conv_cb_t cb_struct = {NULL, NULL}; /*conversion callback structure */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ hbool_t reverse; /*if reverse the order of destination */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ if(NULL == (src_p = (H5T_t *)H5I_object(src_id)) || NULL == (dst_p = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+ if(H5T_ORDER_LE != src.order && H5T_ORDER_BE != src.order && H5T_ORDER_VAX != src.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(H5T_ORDER_LE != dst.order && H5T_ORDER_BE != dst.order && H5T_ORDER_VAX != dst.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(dst_p->shared->size > sizeof(dbuf))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination size is too large")
+ if(8 * sizeof(expo) - 1 < src.u.f.esize || 8 * sizeof(expo) - 1 < dst.u.f.esize)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "exponent field is too large")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src_p = (H5T_t *)H5I_object(src_id)) || NULL == (dst_p = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+ expo_max = ((hssize_t)1 << dst.u.f.esize) - 1;
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if (src_p->shared->size==dst_p->shared->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if (src_p->shared->size>=dst_p->shared->size) {
+ double olap_d = HDceil((double)(dst_p->shared->size)/
+ (double)(src_p->shared->size-dst_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src_p->shared->size)/
+ (double)(dst_p->shared->size-src_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts-1) * src_p->shared->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst_p->shared->size;
+ direction = -1;
+ }
+
+ /*
+ * Direction & size of buffer traversal.
+ */
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(src_p->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst_p->shared->size, size_t, ssize_t);
+ src_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : src_p->shared->size);
+ dst_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : dst_p->shared->size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist,H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ /* Allocate space for order-reversed source buffer */
+ src_rev = (uint8_t*)H5MM_calloc(src_p->shared->size);
+
+ /* The conversion loop */
+ for (elmtno=0; elmtno<nelmts; elmtno++) {
+ /* Set these variables to default */
+ except_ret = H5T_CONV_UNHANDLED;
+ reverse = TRUE;
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if (direction>0) {
+ s = sp;
+ d = elmtno<olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno+olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (d==dbuf) {
+ HDassert((dp>=sp && dp<sp+src_p->shared->size) ||
+ (sp>=dp && sp<dp+dst_p->shared->size));
+ } else {
+ HDassert((dp<sp && dp+dst_p->shared->size<=sp) ||
+ (sp<dp && sp+src_p->shared->size<=dp));
+ }
+#endif
+
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if (H5T_ORDER_BE==src.order) {
+ half_size = src_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ tmp1 = s[src_p->shared->size-(i+1)];
+ s[src_p->shared->size-(i+1)] = s[i];
+ s[i] = tmp1;
+ }
+ } else if (H5T_ORDER_VAX==src.order) {
+ tsize = src_p->shared->size;
+ HDassert(0 == tsize % 2);
+
+ for (i = 0; i < tsize; i += 4) {
+ tmp1 = s[i];
+ tmp2 = s[i+1];
+
+ s[i] = s[(tsize-2)-i];
+ s[i+1] = s[(tsize-1)-i];
+
+ s[(tsize-2)-i] = tmp1;
+ s[(tsize-1)-i] = tmp2;
+ }
+ }
+
+ /*
+ * Find the sign bit value of the source.
+ */
+ sign = H5T__bit_get_d(s, src.u.f.sign, (size_t)1);
+
+ /*
+ * Check for special cases: +0, -0, +Inf, -Inf, NaN
+ */
+ if (H5T__bit_find (s, src.u.f.mpos, src.u.f.msize,
+ H5T_BIT_LSB, TRUE)<0) {
+ if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, TRUE)<0) {
+ /* +0 or -0 */
+ H5T__bit_copy (d, dst.u.f.sign, s, src.u.f.sign, (size_t)1);
+ H5T__bit_set (d, dst.u.f.epos, dst.u.f.esize, FALSE);
+ H5T__bit_set (d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ goto padding;
+ } else if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /* +Inf or -Inf */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ if(sign)
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ else
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_copy (d, dst.u.f.sign, s, src.u.f.sign, (size_t)1);
+ H5T__bit_set (d, dst.u.f.epos, dst.u.f.esize, TRUE);
+ H5T__bit_set (d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ /*If the destination no implied mantissa bit, we'll need to set
+ *the 1st bit of mantissa to 1. The Intel-Linux long double is
+ *this case.*/
+ if (H5T_NORM_NONE==dst.u.f.norm)
+ H5T__bit_set (d, dst.u.f.mpos+dst.u.f.msize-1, (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+
+ goto padding;
+ }
+ } else if (H5T_NORM_NONE==src.u.f.norm && H5T__bit_find (s, src.u.f.mpos, src.u.f.msize-1,
+ H5T_BIT_LSB, TRUE)<0 && H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /*This is a special case for the source of no implied mantissa bit.
+ *If the exponent bits are all 1s and only the 1st bit of mantissa
+ *is set to 1. It's infinity. The Intel-Linux "long double" is this case.*/
+ /* +Inf or -Inf */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ if(sign)
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ else
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ H5T__bit_copy (d, dst.u.f.sign, s, src.u.f.sign, (size_t)1);
+ H5T__bit_set (d, dst.u.f.epos, dst.u.f.esize, TRUE);
+ H5T__bit_set (d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ /*If the destination no implied mantissa bit, we'll need to set
+ *the 1st bit of mantissa to 1. The Intel-Linux long double is
+ *this case.*/
+ if (H5T_NORM_NONE==dst.u.f.norm)
+ H5T__bit_set (d, dst.u.f.mpos+dst.u.f.msize-1, (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+
+ goto padding;
+ /* Temporary solution to handle VAX special values.
+ * Note that even though we don't support VAX anymore, we
+ * still need to handle legacy VAX files so this code must
+ * remain in place.
+ */
+ } else if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /* NaN */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NAN,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ /* There are many NaN values, so we just set all bits of
+ * the significand. */
+ H5T__bit_copy (d, dst.u.f.sign, s, src.u.f.sign, (size_t)1);
+ H5T__bit_set (d, dst.u.f.epos, dst.u.f.esize, TRUE);
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+
+ goto padding;
+ }
+
+ /*
+ * Get the exponent as an unsigned quantity from the section of
+ * the source bit field where it's located. Don't worry about
+ * the exponent bias yet.
+ */
+ expo = (int64_t)H5T__bit_get_d(s, src.u.f.epos, src.u.f.esize);
+
+ if(expo==0)
+ denormalized=TRUE;
+
+ /*
+ * Set markers for the source mantissa, excluding the leading `1'
+ * (might be implied).
+ */
+ implied = 1;
+ mpos = src.u.f.mpos;
+ mrsh = 0;
+ if(0 == expo || H5T_NORM_NONE == src.u.f.norm) {
+ if((bitno = H5T__bit_find(s, src.u.f.mpos, src.u.f.msize, H5T_BIT_MSB, TRUE)) > 0) {
+ msize = (size_t)bitno;
+ } else if (0==bitno) {
+ msize = 1;
+ H5T__bit_set(s, src.u.f.mpos, (size_t)1, FALSE);
+ }
+ } else if (H5T_NORM_IMPLIED==src.u.f.norm) {
+ msize = src.u.f.msize;
+ } else {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "normalization method not implemented yet")
+ }
+
+ /*
+ * The sign for the destination is the same as the sign for the
+ * source in all cases.
+ */
+ H5T__bit_copy (d, dst.u.f.sign, s, src.u.f.sign, (size_t)1);
+
+ /*
+ * Calculate the true source exponent by adjusting according to
+ * the source exponent bias.
+ */
+ if (0==expo || H5T_NORM_NONE==src.u.f.norm) {
+ HDassert(bitno>=0);
+ expo -= (int64_t)((src.u.f.ebias - 1) + (src.u.f.msize - (size_t)bitno));
+ } else if (H5T_NORM_IMPLIED==src.u.f.norm) {
+ expo -= (int64_t)src.u.f.ebias;
+ } else {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "normalization method not implemented yet")
+ }
+
+ /*
+ * If the destination is not normalized then right shift the
+ * mantissa by one.
+ */
+ if (H5T_NORM_NONE==dst.u.f.norm)
+ mrsh++;
+
+ /*
+ * Calculate the destination exponent by adding the destination
+ * bias and clipping by the minimum and maximum possible
+ * destination exponent values.
+ */
+ expo += (int64_t)dst.u.f.ebias;
+
+ if (expo < -(hssize_t)(dst.u.f.msize)) {
+ /* The exponent is way too small. Result is zero. */
+ expo = 0;
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ msize = 0;
+ } else if (expo<=0) {
+ /*
+ * The exponent is too small to fit in the exponent field,
+ * but by shifting the mantissa to the right we can
+ * accomodate that value. The mantissa of course is no
+ * longer normalized.
+ */
+ mrsh += (size_t)(1 - expo);
+ expo = 0;
+ denormalized=TRUE;
+ } else if (expo>=expo_max) {
+ /*
+ * The exponent is too large to fit in the available region
+ * or it results in the maximum possible value. Use positive
+ * or negative infinity instead unless the application
+ * specifies something else. Before calling the overflow
+ * handler make sure the source buffer we hand it is in the
+ * original byte order.
+ */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ expo = expo_max;
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ msize = 0;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ reverse = FALSE;
+ goto next;
+ }
+ }
+
+ /*
+ * If the destination mantissa is smaller than the source
+ * mantissa then round the source mantissa. Rounding may cause a
+ * carry in which case the exponent has to be re-evaluated for
+ * overflow. That is, if `carry' is clear then the implied
+ * mantissa bit is `1', else it is `10' binary.
+ */
+ if (msize>0 && mrsh<=dst.u.f.msize && mrsh+msize>dst.u.f.msize) {
+ bitno = (ssize_t)(mrsh + msize - dst.u.f.msize);
+ HDassert(bitno >= 0 && (size_t)bitno <= msize);
+ /* If the 1st bit being cut off is set and source isn't denormalized.*/
+ if(H5T__bit_get_d(s, (mpos + (size_t)bitno) - 1, (size_t)1) && !denormalized) {
+ /* Don't do rounding if exponent is 111...110 and mantissa is 111...11.
+ * To do rounding and increment exponent in this case will create an infinity value.*/
+ if((H5T__bit_find(s, mpos + (size_t)bitno, msize - (size_t)bitno, H5T_BIT_LSB, FALSE) >= 0 || expo < expo_max - 1)) {
+ carry = H5T__bit_inc(s, mpos + (size_t)bitno - 1, 1 + msize - (size_t)bitno);
+ if(carry)
+ implied = 2;
+ }
+ } else if(H5T__bit_get_d(s, (mpos + (size_t)bitno) - 1, (size_t)1) && denormalized)
+ /* For either source or destination, denormalized value doesn't increment carry.*/
+ H5T__bit_inc(s, mpos + (size_t)bitno - 1, 1 + msize - (size_t)bitno);
+ }
+ else
+ carry = FALSE;
+
+ /*
+ * Write the mantissa to the destination
+ */
+ if (mrsh>dst.u.f.msize+1) {
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ } else if (mrsh==dst.u.f.msize+1) {
+ H5T__bit_set(d, dst.u.f.mpos+1, dst.u.f.msize-1, FALSE);
+ H5T__bit_set(d, dst.u.f.mpos, (size_t)1, TRUE);
+ } else if (mrsh==dst.u.f.msize) {
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ H5T__bit_set_d(d, dst.u.f.mpos, MIN(2, dst.u.f.msize), (hsize_t)implied);
+ } else {
+ if (mrsh>0) {
+ H5T__bit_set(d, dst.u.f.mpos+dst.u.f.msize-mrsh, mrsh,
+ FALSE);
+ H5T__bit_set_d(d, dst.u.f.mpos+dst.u.f.msize-mrsh, (size_t)2,
+ (hsize_t)implied);
+ }
+ if (mrsh+msize>=dst.u.f.msize) {
+ H5T__bit_copy(d, dst.u.f.mpos,
+ s, (mpos+msize+mrsh-dst.u.f.msize),
+ dst.u.f.msize-mrsh);
+ } else {
+ H5T__bit_copy(d, dst.u.f.mpos+dst.u.f.msize-(mrsh+msize),
+ s, mpos, msize);
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize-(mrsh+msize),
+ FALSE);
+ }
+ }
+
+ /* Write the exponent */
+ if (carry) {
+ expo++;
+ if (expo>=expo_max) {
+ /*
+ * The exponent is too large to fit in the available
+ * region or it results in the maximum possible value.
+ * Use positive or negative infinity instead unless the
+ * application specifies something else. Before
+ * calling the overflow handler make sure the source
+ * buffer we hand it is in the original byte order.
+ */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ expo = expo_max;
+ H5T__bit_set(d, dst.u.f.mpos, dst.u.f.msize, FALSE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ reverse = FALSE;
+ goto next;
+ }
+ }
+ }
+ /*reset CARRY*/
+ carry = FALSE;
+
+ H5_CHECK_OVERFLOW(expo,hssize_t,hsize_t);
+ H5T__bit_set_d(d, dst.u.f.epos, dst.u.f.esize, (hsize_t)expo);
+
+ padding:
+
+ /*
+ * Set external padding areas
+ */
+ if (dst.offset>0) {
+ HDassert(H5T_PAD_ZERO==dst.lsb_pad || H5T_PAD_ONE==dst.lsb_pad);
+ H5T__bit_set (d, (size_t)0, dst.offset, (hbool_t)(H5T_PAD_ONE==dst.lsb_pad));
+ }
+ if (dst.offset+dst.prec!=8*dst_p->shared->size) {
+ HDassert(H5T_PAD_ZERO==dst.msb_pad || H5T_PAD_ONE==dst.msb_pad);
+ H5T__bit_set (d, dst.offset+dst.prec, 8*dst_p->shared->size - (dst.offset+dst.prec),
+ (hbool_t)(H5T_PAD_ONE==dst.msb_pad));
+ }
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if (H5T_ORDER_BE==dst.order && reverse) {
+ half_size = dst_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = d[dst_p->shared->size-(i+1)];
+ d[dst_p->shared->size-(i+1)] = d[i];
+ d[i] = tmp;
+ }
+ } else if (H5T_ORDER_VAX==dst.order && reverse) {
+ tsize = dst_p->shared->size;
+ HDassert(0 == tsize % 2);
+
+ for (i = 0; i < tsize; i += 4) {
+ tmp1 = d[i];
+ tmp2 = d[i+1];
+
+ d[i] = d[(tsize-2)-i];
+ d[i+1] = d[(tsize-1)-i];
+
+ d[(tsize-2)-i] = tmp1;
+ d[(tsize-1)-i] = tmp2;
+ }
+ }
+
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ next:
+ if(d == dbuf)
+ HDmemcpy(dp, d, dst_p->shared->size);
+
+ /* Advance source & destination pointers by delta amounts */
+ sp += src_delta;
+ dp += dst_delta;
+ }
+
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ if(src_rev)
+ H5MM_free(src_rev);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_f_f() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_s_s
+ *
+ * Purpose: Convert one fixed-length string type to another.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *
+ * Raymond Lu, 8 November 2011
+ * I put a condition check to prevent the conversion of strings
+ * between ASCII and UTF8.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_s_s(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf,
+ void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_t *src=NULL; /*source datatype */
+ H5T_t *dst=NULL; /*destination datatype */
+ ssize_t src_delta, dst_delta; /*source & destination stride */
+ int direction; /*direction of traversal */
+ size_t elmtno; /*element number */
+ size_t olap; /*num overlapping elements */
+ size_t nchars=0; /*number of characters copied */
+ uint8_t *s, *sp, *d, *dp; /*src and dst traversal pointers*/
+ uint8_t *dbuf=NULL; /*temp buf for overlap convers. */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(8 * src->shared->size != src->shared->u.atomic.prec || 8 * dst->shared->size != dst->shared->u.atomic.prec)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad precision")
+ if(0 != src->shared->u.atomic.offset || 0 != dst->shared->u.atomic.offset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad offset")
+ if(H5T_CSET_ASCII != src->shared->u.atomic.u.s.cset && H5T_CSET_UTF8 != src->shared->u.atomic.u.s.cset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad source character set")
+ if(H5T_CSET_ASCII != dst->shared->u.atomic.u.s.cset && H5T_CSET_UTF8 != dst->shared->u.atomic.u.s.cset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad destination character set")
+ if((H5T_CSET_ASCII == src->shared->u.atomic.u.s.cset && H5T_CSET_UTF8 == dst->shared->u.atomic.u.s.cset)
+ || (H5T_CSET_ASCII == dst->shared->u.atomic.u.s.cset && H5T_CSET_UTF8 == src->shared->u.atomic.u.s.cset))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "The library doesn't convert between strings of ASCII and UTF")
+ if(src->shared->u.atomic.u.s.pad < 0 || src->shared->u.atomic.u.s.pad >= H5T_NSTR ||
+ dst->shared->u.atomic.u.s.pad < 0 || dst->shared->u.atomic.u.s.pad >= H5T_NSTR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad character padding")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src = (H5T_t *)H5I_object(src_id)) || NULL == (dst = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if (src->shared->size==dst->shared->size || buf_stride) {
+ /*
+ * When the source and destination are the same size we can do
+ * all the conversions in place.
+ */
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = 0;
+ } else if (src->shared->size>=dst->shared->size) {
+ double olapd = HDceil((double)(dst->shared->size)/
+ (double)(src->shared->size-dst->shared->size));
+ olap = (size_t)olapd;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olapd = HDceil((double)(src->shared->size)/
+ (double)(dst->shared->size-src->shared->size));
+ olap = (size_t)olapd;
+ sp = (uint8_t*)buf + (nelmts-1) * src->shared->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst->shared->size;
+ direction = -1;
+ }
+
+ /*
+ * Direction & size of buffer traversal.
+ */
+ H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
+ H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
+ src_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : src->shared->size);
+ dst_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : dst->shared->size);
+
+ /* Allocate the overlap buffer */
+ if(NULL == (dbuf = (uint8_t *)H5MM_malloc(dst->shared->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for string conversion")
+
+ /* The conversion loop. */
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if(direction > 0) {
+ s = sp;
+ d = elmtno < olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno + olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (src->shared->size==dst->shared->size || buf_stride) {
+ HDassert(s==d);
+ } else if (d==dbuf) {
+ HDassert((dp>=sp && dp<sp+src->shared->size) ||
+ (sp>=dp && sp<dp+dst->shared->size));
+ } else {
+ HDassert((dp<sp && dp+dst->shared->size<=sp) ||
+ (sp<dp && sp+src->shared->size<=dp));
+ }
+#endif
+
+ /* Copy characters from source to destination */
+ switch(src->shared->u.atomic.u.s.pad) {
+ case H5T_STR_NULLTERM:
+ for (nchars=0;
+ nchars<dst->shared->size && nchars<src->shared->size && s[nchars];
+ nchars++) {
+ d[nchars] = s[nchars];
+ }
+ break;
+
+ case H5T_STR_NULLPAD:
+ for (nchars=0;
+ nchars<dst->shared->size && nchars<src->shared->size && s[nchars];
+ nchars++) {
+ d[nchars] = s[nchars];
+ }
+ break;
+
+ case H5T_STR_SPACEPAD:
+ nchars = src->shared->size;
+ while (nchars>0 && ' '==s[nchars-1])
+ --nchars;
+ nchars = MIN(dst->shared->size, nchars);
+ if(d != s)
+ HDmemcpy(d, s, nchars);
+ break;
+
+ case H5T_STR_RESERVED_3:
+ case H5T_STR_RESERVED_4:
+ case H5T_STR_RESERVED_5:
+ case H5T_STR_RESERVED_6:
+ case H5T_STR_RESERVED_7:
+ case H5T_STR_RESERVED_8:
+ case H5T_STR_RESERVED_9:
+ case H5T_STR_RESERVED_10:
+ case H5T_STR_RESERVED_11:
+ case H5T_STR_RESERVED_12:
+ case H5T_STR_RESERVED_13:
+ case H5T_STR_RESERVED_14:
+ case H5T_STR_RESERVED_15:
+ case H5T_STR_ERROR:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "source string padding method not supported")
+ } /* end switch */
+
+ /* Terminate or pad the destination */
+ switch(dst->shared->u.atomic.u.s.pad) {
+ case H5T_STR_NULLTERM:
+ while(nchars < dst->shared->size)
+ d[nchars++] = '\0';
+ d[dst->shared->size - 1] = '\0';
+ break;
+
+ case H5T_STR_NULLPAD:
+ while(nchars < dst->shared->size)
+ d[nchars++] = '\0';
+ break;
+
+ case H5T_STR_SPACEPAD:
+ while(nchars < dst->shared->size)
+ d[nchars++] = ' ';
+ break;
+
+ case H5T_STR_RESERVED_3:
+ case H5T_STR_RESERVED_4:
+ case H5T_STR_RESERVED_5:
+ case H5T_STR_RESERVED_6:
+ case H5T_STR_RESERVED_7:
+ case H5T_STR_RESERVED_8:
+ case H5T_STR_RESERVED_9:
+ case H5T_STR_RESERVED_10:
+ case H5T_STR_RESERVED_11:
+ case H5T_STR_RESERVED_12:
+ case H5T_STR_RESERVED_13:
+ case H5T_STR_RESERVED_14:
+ case H5T_STR_RESERVED_15:
+ case H5T_STR_ERROR:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination string padding method not supported")
+ } /* end switch */
+
+ /*
+ * If we used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if(d == dbuf)
+ HDmemcpy(dp, d, dst->shared->size);
+
+ /* Advance source & destination pointers by delta amounts */
+ sp += src_delta;
+ dp += dst_delta;
+ } /* end for */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown converson command")
+ } /* end switch */
+
+done:
+ H5MM_xfree(dbuf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_s_s() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_uchar
+ *
+ * Purpose: Converts `signed char' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_su(SCHAR, UCHAR, signed char, unsigned char, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_schar
+ *
+ * Purpose: Converts `unsigned char' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_us(UCHAR, SCHAR, unsigned char, signed char, -, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_short
+ *
+ * Purpose: Converts `signed char' to `short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SCHAR, SHORT, signed char, short, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_ushort
+ *
+ * Purpose: Converts `signed char' to `unsigned short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SCHAR, USHORT, signed char, unsigned short, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_short
+ *
+ * Purpose: Converts `unsigned char' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UCHAR, SHORT, unsigned char, short, -, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_ushort
+ *
+ * Purpose: Converts `unsigned char' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UCHAR, USHORT, unsigned char, unsigned short, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_int
+ *
+ * Purpose: Converts `signed char' to `int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SCHAR, INT, signed char, int, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_uint
+ *
+ * Purpose: Converts `signed char' to `unsigned int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SCHAR, UINT, signed char, unsigned, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_int
+ *
+ * Purpose: Converts `unsigned char' to `int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UCHAR, INT, unsigned char, int, -, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_uint
+ *
+ * Purpose: Converts `unsigned char' to `unsigned int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UCHAR, UINT, unsigned char, unsigned, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_long
+ *
+ * Purpose: Converts `signed char' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SCHAR, LONG, signed char, long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_ulong
+ *
+ * Purpose: Converts `signed char' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SCHAR, ULONG, signed char, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_long
+ *
+ * Purpose: Converts `unsigned char' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UCHAR, LONG, unsigned char, long, -, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_ulong
+ *
+ * Purpose: Converts `unsigned char' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UCHAR, ULONG, unsigned char, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_llong
+ *
+ * Purpose: Converts `signed char' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SCHAR, LLONG, signed char, long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_ullong
+ *
+ * Purpose: Converts `signed char' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SCHAR, ULLONG, signed char, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_llong
+ *
+ * Purpose: Converts `unsigned char' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UCHAR, LLONG, unsigned char, long long, -, LLONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_ullong
+ *
+ * Purpose: Converts `unsigned char' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UCHAR, ULLONG, unsigned char, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_schar
+ *
+ * Purpose: Converts `short' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(SHORT, SCHAR, short, signed char, SCHAR_MIN, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_uchar
+ *
+ * Purpose: Converts `short' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(SHORT, UCHAR, short, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_schar
+ *
+ * Purpose: Converts `unsigned short' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(USHORT, SCHAR, unsigned short, signed char, -, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_uchar
+ *
+ * Purpose: Converts `unsigned short' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(USHORT, UCHAR, unsigned short, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_ushort
+ *
+ * Purpose: Converts `short' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_su(SHORT, USHORT, short, unsigned short, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_short
+ *
+ * Purpose: Converts `unsigned short' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_us(USHORT, SHORT, unsigned short, short, -, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_int
+ *
+ * Purpose: Converts `short' to `int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SHORT, INT, short, int, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_uint
+ *
+ * Purpose: Converts `short' to `unsigned int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SHORT, UINT, short, unsigned, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_int
+ *
+ * Purpose: Converts `unsigned short' to `int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(USHORT, INT, unsigned short, int, -, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_uint
+ *
+ * Purpose: Converts `unsigned short' to `unsigned int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(USHORT, UINT, unsigned short, unsigned, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_long
+ *
+ * Purpose: Converts `short' to `long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SHORT, LONG, short, long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_ulong
+ *
+ * Purpose: Converts `short' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SHORT, ULONG, short, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_long
+ *
+ * Purpose: Converts `unsigned short' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(USHORT, LONG, unsigned short, long, -, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_ulong
+ *
+ * Purpose: Converts `unsigned short' to `unsigned long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(USHORT, ULONG, unsigned short, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_llong
+ *
+ * Purpose: Converts `short' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(SHORT, LLONG, short, long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_ullong
+ *
+ * Purpose: Converts `short' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(SHORT, ULLONG, short, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_llong
+ *
+ * Purpose: Converts `unsigned short' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(USHORT, LLONG, unsigned short, long long, -, LLONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_ullong
+ *
+ * Purpose: Converts `unsigned short' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(USHORT, ULLONG, unsigned short, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_schar
+ *
+ * Purpose: Converts `int' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(INT, SCHAR, int, signed char, SCHAR_MIN, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_uchar
+ *
+ * Purpose: Converts `int' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(INT, UCHAR, int, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_schar
+ *
+ * Purpose: Converts `unsigned int' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(UINT, SCHAR, unsigned, signed char, -, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_uchar
+ *
+ * Purpose: Converts `unsigned int' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(UINT, UCHAR, unsigned, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_short
+ *
+ * Purpose: Converts `int' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(INT, SHORT, int, short, SHRT_MIN, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_ushort
+ *
+ * Purpose: Converts `int' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(INT, USHORT, int, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_short
+ *
+ * Purpose: Converts `unsigned int' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(UINT, SHORT, unsigned, short, -, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_ushort
+ *
+ * Purpose: Converts `unsigned int' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(UINT, USHORT, unsigned, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_uint
+ *
+ * Purpose: Converts `int' to `unsigned int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_su(INT, UINT, int, unsigned, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_int
+ *
+ * Purpose: Converts `unsigned int' to `int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_us(UINT, INT, unsigned, int, -, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_long
+ *
+ * Purpose: Converts `int' to `long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(INT, LONG, int, long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_ulong
+ *
+ * Purpose: Converts `int' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(INT, LONG, int, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_long
+ *
+ * Purpose: Converts `unsigned int' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UINT, LONG, unsigned, long, -, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_ulong
+ *
+ * Purpose: Converts `unsigned int' to `unsigned long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UINT, ULONG, unsigned, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_llong
+ *
+ * Purpose: Converts `int' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(INT, LLONG, int, long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_ullong
+ *
+ * Purpose: Converts `int' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(INT, ULLONG, int, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_llong
+ *
+ * Purpose: Converts `unsigned int' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(UINT, LLONG, unsigned, long long, -, LLONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_ullong
+ *
+ * Purpose: Converts `unsigned int' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(UINT, ULLONG, unsigned, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_schar
+ *
+ * Purpose: Converts `long' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LONG, SCHAR, long, signed char, SCHAR_MIN, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_uchar
+ *
+ * Purpose: Converts `long' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LONG, UCHAR, long, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_schar
+ *
+ * Purpose: Converts `unsigned long' to `signed char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULONG, SCHAR, unsigned long, signed char, -, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_uchar
+ *
+ * Purpose: Converts `unsigned long' to `unsigned char'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULONG, UCHAR, unsigned long, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_short
+ *
+ * Purpose: Converts `long' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LONG, SHORT, long, short, SHRT_MIN, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_ushort
+ *
+ * Purpose: Converts `long' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LONG, USHORT, long, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_short
+ *
+ * Purpose: Converts `unsigned long' to `short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULONG, SHORT, unsigned long, short, -, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_ushort
+ *
+ * Purpose: Converts `unsigned long' to `unsigned short'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULONG, USHORT, unsigned long, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_int
+ *
+ * Purpose: Converts `long' to `int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LONG, INT, long, int, INT_MIN, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_uint
+ *
+ * Purpose: Converts `long' to `unsigned int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LONG, UINT, long, unsigned, -, UINT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_int
+ *
+ * Purpose: Converts `unsigned long' to `int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULONG, INT, unsigned long, int, -, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_uint
+ *
+ * Purpose: Converts `unsigned long' to `unsigned int'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULONG, UINT, unsigned long, unsigned, -, UINT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_ulong
+ *
+ * Purpose: Converts `long' to `unsigned long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_su(LONG, ULONG, long, unsigned long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_long
+ *
+ * Purpose: Converts `unsigned long' to `long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_us(ULONG, LONG, unsigned long, long, -, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_llong
+ *
+ * Purpose: Converts `long' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sS(LONG, LLONG, long, long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_ullong
+ *
+ * Purpose: Converts `long' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_sU(LONG, ULLONG, long, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_llong
+ *
+ * Purpose: Converts `unsigned long' to `long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uS(ULONG, LLONG, unsigned long, long long, -, LLONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_ullong
+ *
+ * Purpose: Converts `unsigned long' to `unsigned long long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_uU(ULONG, ULLONG, unsigned long, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_schar
+ *
+ * Purpose: Converts `long long' to `signed char'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LLONG, SCHAR, long long, signed char, SCHAR_MIN, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_uchar
+ *
+ * Purpose: Converts `long long' to `unsigned char'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LLONG, UCHAR, long long, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_schar
+ *
+ * Purpose: Converts `unsigned long long' to `signed char'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULLONG, SCHAR, unsigned long long, signed char, -, SCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_uchar
+ *
+ * Purpose: Converts `unsigned long long' to `unsigned char'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULLONG, UCHAR, unsigned long long, unsigned char, -, UCHAR_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_short
+ *
+ * Purpose: Converts `long long' to `short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LLONG, SHORT, long long, short, SHRT_MIN, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_ushort
+ *
+ * Purpose: Converts `long long' to `unsigned short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LLONG, USHORT, long long, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_short
+ *
+ * Purpose: Converts `unsigned long long' to `short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULLONG, SHORT, unsigned long long, short, -, SHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_ushort
+ *
+ * Purpose: Converts `unsigned long long' to `unsigned short'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULLONG, USHORT, unsigned long long, unsigned short, -, USHRT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_int
+ *
+ * Purpose: Converts `long long' to `int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LLONG, INT, long long, int, INT_MIN, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_uint
+ *
+ * Purpose: Converts `long long' to `unsigned int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LLONG, UINT, long long, unsigned, -, UINT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_int
+ *
+ * Purpose: Converts `unsigned long long' to `int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULLONG, INT, unsigned long long, int, -, INT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_uint
+ *
+ * Purpose: Converts `unsigned long long' to `unsigned int'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_uint(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULLONG, UINT, unsigned long long, unsigned, -, UINT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_long
+ *
+ * Purpose: Converts `long long' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride,
+ void *buf, void H5_ATTR_UNUSED *bkg, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ss(LLONG, LONG, long long, long, LONG_MIN, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_ulong
+ *
+ * Purpose: Converts `long long' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Su(LLONG, ULONG, long long, unsigned long, -, ULONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_long
+ *
+ * Purpose: Converts `unsigned long long' to `long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_long(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Us(ULLONG, LONG, unsigned long long, long, -, LONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_ulong
+ *
+ * Purpose: Converts `unsigned long long' to `unsigned long'
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, November 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_ulong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Uu(ULLONG, ULONG, unsigned long long, unsigned long, -, ULONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_ullong
+ *
+ * Purpose: Converts `long long' to `unsigned long long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_ullong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_su(LLONG, ULLONG, long long, unsigned long long, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_llong
+ *
+ * Purpose: Converts `unsigned long long' to `long long'
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_llong(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_us(ULLONG, LLONG, unsigned long long, long long, -, LLONG_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_double
+ *
+ * Purpose: Convert native `float' to native `double' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 23, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_fF(FLOAT, DOUBLE, float, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_ldouble
+ *
+ * Purpose: Convert native `float' to native `long double' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, Feb 25, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5_SIZEOF_LONG_DOUBLE != 0
+herr_t
+H5T__conv_float_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_fF(FLOAT, LDOUBLE, float, long double, -, -);
+}
+#endif /* H5_SIZEOF_LONG_DOUBLE != 0 */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_float
+ *
+ * Purpose: Convert native `double' to native `float' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 23, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 7 Jul 1998
+ * Added overflow handling.
+ *
+ * Robb Matzke, 1999-06-16
+ * Added support for non-zero strides. If BUF_STRIDE is non-zero
+ * then convert one value at each memory location advancing
+ * BUF_STRIDE bytes each time; otherwise assume both source and
+ * destination values are packed.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ff(DOUBLE, FLOAT, double, float, -FLT_MAX, FLT_MAX);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_ldouble
+ *
+ * Purpose: Convert native `double' to native `long double' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, Feb 25, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5_SIZEOF_LONG_DOUBLE != 0
+herr_t
+H5T__conv_double_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_fF(DOUBLE, LDOUBLE, double, long double, -, -);
+}
+#endif /* H5_SIZEOF_LONG_DOUBLE != 0 */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_float
+ *
+ * Purpose: Convert native `long double' to native `float' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, Feb 25, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5_SIZEOF_LONG_DOUBLE != 0
+herr_t
+H5T__conv_ldouble_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ff(LDOUBLE, FLOAT, long double, float, -FLT_MAX, FLT_MAX);
+}
+#endif /* H5_SIZEOF_LONG_DOUBLE != 0 */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_double
+ *
+ * Purpose: Convert native `long double' to native `double' using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, Feb 25, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5_SIZEOF_LONG_DOUBLE != 0
+herr_t
+H5T__conv_ldouble_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_Ff(LDOUBLE, DOUBLE, long double, double, -DBL_MAX, DBL_MAX);
+}
+#endif /* H5_SIZEOF_LONG_DOUBLE != 0 */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_float
+ *
+ * Purpose: Convert native signed char to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SCHAR, FLOAT, signed char, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_double
+ *
+ * Purpose: Convert native signed char to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SCHAR, DOUBLE, signed char, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_schar_ldouble
+ *
+ * Purpose: Convert native signed char to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_schar_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SCHAR, LDOUBLE, signed char, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_float
+ *
+ * Purpose: Convert native unsigned char to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UCHAR, FLOAT, unsigned char, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_double
+ *
+ * Purpose: Convert native unsigned char to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UCHAR, DOUBLE, unsigned char, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uchar_ldouble
+ *
+ * Purpose: Convert native unsigned char to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uchar_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UCHAR, LDOUBLE, unsigned char, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_float
+ *
+ * Purpose: Convert native short to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SHORT, FLOAT, short, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_double
+ *
+ * Purpose: Convert native short to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SHORT, DOUBLE, short, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_short_ldouble
+ *
+ * Purpose: Convert native short to native long double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_short_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(SHORT, LDOUBLE, short, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_float
+ *
+ * Purpose: Convert native unsigned short to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(USHORT, FLOAT, unsigned short, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_double
+ *
+ * Purpose: Convert native unsigned short to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(USHORT, DOUBLE, unsigned short, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ushort_ldouble
+ *
+ * Purpose: Convert native unsigned short to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ushort_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(USHORT, LDOUBLE, unsigned short, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_float
+ *
+ * Purpose: Convert native integer to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(INT, FLOAT, int, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_double
+ *
+ * Purpose: Convert native integer to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(INT, DOUBLE, int, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_int_ldouble
+ *
+ * Purpose: Convert native integer to native long double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_int_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(INT, LDOUBLE, int, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_float
+ *
+ * Purpose: Convert native unsigned integer to native float using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UINT, FLOAT, unsigned int, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_double
+ *
+ * Purpose: Convert native unsigned integer to native double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UINT, DOUBLE, unsigned int, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_uint_ldouble
+ *
+ * Purpose: Convert native unsigned integer to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_uint_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(UINT, LDOUBLE, unsigned int, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_float
+ *
+ * Purpose: Convert native long to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LONG, FLOAT, long, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_double
+ *
+ * Purpose: Convert native long to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LONG, DOUBLE, long, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_long_ldouble
+ *
+ * Purpose: Convert native long to native long double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_long_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LONG, LDOUBLE, long, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_float
+ *
+ * Purpose: Convert native unsigned long to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULONG, FLOAT, unsigned long, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_double
+ *
+ * Purpose: Convert native unsigned long to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULONG, DOUBLE, unsigned long, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ulong_ldouble
+ *
+ * Purpose: Convert native unsigned long to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ulong_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULONG, LDOUBLE, unsigned long, long double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_float
+ *
+ * Purpose: Convert native long long to native float using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LLONG, FLOAT, long long, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_double
+ *
+ * Purpose: Convert native long long to native double using hardware.
+ * This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_llong_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LLONG, DOUBLE, long long, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_llong_ldouble
+ *
+ * Purpose: Convert native long long to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5T_CONV_INTERNAL_LLONG_LDOUBLE
+herr_t
+H5T__conv_llong_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(LLONG, LDOUBLE, long long, long double, -, -);
+}
+#endif /* H5T_CONV_INTERNAL_LLONG_LDOUBLE */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_float
+ *
+ * Purpose: Convert native unsigned long long to native float using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_float (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULLONG, FLOAT, unsigned long long, float, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_double
+ *
+ * Purpose: Convert native unsigned long long to native double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ullong_double (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULLONG, DOUBLE, unsigned long long, double, -, -);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ullong_ldouble
+ *
+ * Purpose: Convert native unsigned long long to native long double using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5T_CONV_INTERNAL_ULLONG_LDOUBLE
+herr_t
+H5T__conv_ullong_ldouble (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ H5T_CONV_xF(ULLONG, LDOUBLE, unsigned long long, long double, -, -);
+}
+#endif /*H5T_CONV_INTERNAL_ULLONG_LDOUBLE*/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_schar
+ *
+ * Purpose: Convert native float to native signed char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_schar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, SCHAR, float, signed char, SCHAR_MIN, SCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_uchar
+ *
+ * Purpose: Convert native float to native unsigned char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_uchar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, UCHAR, float, unsigned char, 0, UCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_schar
+ *
+ * Purpose: Convert native double to native signed char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_schar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, SCHAR, double, signed char, SCHAR_MIN, SCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_uchar
+ *
+ * Purpose: Convert native double to native unsigned char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_uchar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, UCHAR, double, unsigned char, 0, UCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_schar
+ *
+ * Purpose: Convert native long double to native signed char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_schar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, SCHAR, long double, signed char, SCHAR_MIN, SCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_uchar
+ *
+ * Purpose: Convert native long double to native unsigned char using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_uchar (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, UCHAR, long double, unsigned char, 0, UCHAR_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_short
+ *
+ * Purpose: Convert native float to native short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_short (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, SHORT, float, short, SHRT_MIN, SHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_ushort
+ *
+ * Purpose: Convert native float to native unsigned short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_ushort (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, USHORT, float, unsigned short, 0, USHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_short
+ *
+ * Purpose: Convert native double to native short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_short (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, SHORT, double, short, SHRT_MIN, SHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_ushort
+ *
+ * Purpose: Convert native double to native unsigned short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_ushort (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, USHORT, double, unsigned short, 0, USHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_short
+ *
+ * Purpose: Convert native long double to native short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_short (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, SHORT, long double, short, SHRT_MIN, SHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_ushort
+ *
+ * Purpose: Convert native long double to native unsigned short using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_ushort (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, USHORT, long double, unsigned short, 0, USHRT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_int
+ *
+ * Purpose: Convert native float to native int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_int (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, INT, float, int, INT_MIN, INT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_uint
+ *
+ * Purpose: Convert native float to native unsigned int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_uint (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, UINT, float, unsigned int, 0, UINT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_int
+ *
+ * Purpose: Convert native double to native int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_int (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, INT, double, int, INT_MIN, INT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_uint
+ *
+ * Purpose: Convert native double to native unsigned int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_uint (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, UINT, double, unsigned int, 0, UINT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_int
+ *
+ * Purpose: Convert native long double to native int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_int (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, INT, long double, int, INT_MIN, INT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_uint
+ *
+ * Purpose: Convert native long double to native unsigned int using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_uint (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, UINT, long double, unsigned int, 0, UINT_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_long
+ *
+ * Purpose: Convert native float to native long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_long (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, LONG, float, long, LONG_MIN, LONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_ulong
+ *
+ * Purpose: Convert native float to native unsigned long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_ulong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, ULONG, float, unsigned long, 0, ULONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_long
+ *
+ * Purpose: Convert native double to native long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_long (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, LONG, double, long, LONG_MIN, LONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_ulong
+ *
+ * Purpose: Convert native double to native unsigned long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_ulong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, ULONG, double, unsigned long, 0, ULONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_long
+ *
+ * Purpose: Convert native long double to native long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_long (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, LONG, long double, long, LONG_MIN, LONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_ulong
+ *
+ * Purpose: Convert native long double to native unsigned long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_ldouble_ulong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, ULONG, long double, unsigned long, 0, ULONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_llong
+ *
+ * Purpose: Convert native float to native long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_llong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, LLONG, float, long long, LLONG_MIN, LLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_float_ullong
+ *
+ * Purpose: Convert native float to native unsigned long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_float_ullong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(FLOAT, ULLONG, float, unsigned long long, 0, ULLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_llong
+ *
+ * Purpose: Convert native double to native long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_llong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, LLONG, double, long long, LLONG_MIN, LLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_double_ullong
+ *
+ * Purpose: Convert native double to native unsigned long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, November 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_double_ullong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(DOUBLE, ULLONG, double, unsigned long long, 0, ULLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_llong
+ *
+ * Purpose: Convert native long double to native long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5T_CONV_INTERNAL_LDOUBLE_LLONG
+herr_t
+H5T__conv_ldouble_llong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t H5_ATTR_UNUSED dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, LLONG, long double, long long, LLONG_MIN, LLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+#endif /*H5T_CONV_INTERNAL_LDOUBLE_LLONG*/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_ldouble_ullong
+ *
+ * Purpose: Convert native long double to native unsigned long long using
+ * hardware. This is a fast special case.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Tuesday, Febuary 1, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#if H5T_CONV_INTERNAL_LDOUBLE_ULLONG
+herr_t
+H5T__conv_ldouble_ullong (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+H5_GCC_DIAG_OFF(float-equal)
+ H5T_CONV_Fx(LDOUBLE, ULLONG, long double, unsigned long long, 0, ULLONG_MAX);
+H5_GCC_DIAG_ON(float-equal)
+}
+#endif /*H5T_CONV_INTERNAL_LDOUBLE_ULLONG*/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_f_i
+ *
+ * Purpose: Convert one floating-point type to an integer. This is
+ * the catch-all function for float-integer conversions and
+ * is probably not particularly fast.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Wednesday, Jan 21, 2004
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Wednesday, April 21, 2004
+ * There is a new design for exception handling like overflow,
+ * which is passed in as a transfer property.
+ *
+ * Raymond Lu
+ * Monday, March 13, 2006
+ * Added support for VAX floating-point types.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_f_i(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+ /* Traversal-related variables */
+ H5T_t *src_p; /*source datatype */
+ H5T_t *dst_p; /*destination datatype */
+ H5T_atomic_t src; /*atomic source info */
+ H5T_atomic_t dst; /*atomic destination info */
+ int direction; /*forward or backward traversal */
+ size_t elmtno; /*element number */
+ size_t half_size; /*half the type size */
+ size_t tsize; /*type size for swapping bytes */
+ size_t olap; /*num overlapping elements */
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t *src_rev=NULL; /*order-reversed source buffer */
+ uint8_t dbuf[64]; /*temp destination buffer */
+ uint8_t tmp1, tmp2; /*temp variables for swapping bytes*/
+
+ /* Conversion-related variables */
+ hssize_t expo; /*source exponent */
+ hssize_t sign; /*source sign bit value */
+ uint8_t *int_buf=NULL; /*buffer for temporary value */
+ size_t buf_size; /*buffer size for temporary value */
+ size_t i; /*miscellaneous counters */
+ size_t first; /*first bit(MSB) in an integer */
+ ssize_t sfirst; /*a signed version of `first' */
+ H5P_genplist_t *plist; /*Property list pointer */
+ H5T_conv_cb_t cb_struct={NULL, NULL}; /*conversion callback structure */
+ hbool_t truncated; /*if fraction value is dropped */
+ hbool_t reverse; /*if reverse order of destination at the end */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ if(NULL == (src_p = (H5T_t*)H5I_object(src_id)) || NULL == (dst_p = (H5T_t*)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+ if(H5T_ORDER_LE != src.order && H5T_ORDER_BE != src.order && H5T_ORDER_VAX != src.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(dst_p->shared->size > sizeof(dbuf))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination size is too large")
+ if(8 * sizeof(expo) - 1 < src.u.f.esize)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "exponent field is too large")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src_p = (H5T_t*)H5I_object(src_id)) || NULL == (dst_p = (H5T_t*)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if(src_p->shared->size==dst_p->shared->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if (src_p->shared->size>=dst_p->shared->size) {
+ double olap_d = HDceil((double)(dst_p->shared->size)/
+ (double)(src_p->shared->size-dst_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src_p->shared->size)/
+ (double)(dst_p->shared->size-src_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts-1) * src_p->shared->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst_p->shared->size;
+ direction = -1;
+ }
+
+ /* Allocate enough space for the buffer holding temporary
+ * converted value
+ */
+ buf_size = (size_t) (HDpow((double)2.0f, (double)src.u.f.esize) / 8 + 1);
+ int_buf = (uint8_t*)H5MM_calloc(buf_size);
+
+ /* Get the plist structure. Do I need to close it? */
+ if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist, H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ /* Allocate space for order-reversed source buffer */
+ src_rev = (uint8_t*)H5MM_calloc(src_p->shared->size);
+
+ /* The conversion loop */
+ for(elmtno = 0; elmtno < nelmts; elmtno++) {
+ /* Set these variables to default */
+ except_ret = H5T_CONV_UNHANDLED;
+ truncated = FALSE;
+ reverse = TRUE;
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if(direction > 0) {
+ s = sp;
+ d = elmtno<olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno+olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (d==dbuf) {
+ HDassert((dp>=sp && dp<sp+src_p->shared->size) ||
+ (sp>=dp && sp<dp+dst_p->shared->size));
+ } else {
+ HDassert((dp<sp && dp+dst_p->shared->size<=sp) ||
+ (sp<dp && sp+src_p->shared->size<=dp));
+ }
+#endif
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if (H5T_ORDER_BE==src.order) {
+ half_size = src_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ tmp1 = s[src_p->shared->size-(i+1)];
+ s[src_p->shared->size-(i+1)] = s[i];
+ s[i] = tmp1;
+ }
+ } else if (H5T_ORDER_VAX==src.order) {
+ tsize = src_p->shared->size;
+ HDassert(0 == tsize % 2);
+
+ for (i = 0; i < tsize; i += 4) {
+ tmp1 = s[i];
+ tmp2 = s[i+1];
+
+ s[i] = s[(tsize-2)-i];
+ s[i+1] = s[(tsize-1)-i];
+
+ s[(tsize-2)-i] = tmp1;
+ s[(tsize-1)-i] = tmp2;
+ }
+ }
+
+ /*zero-set all destination bits*/
+ H5T__bit_set (d, dst.offset, dst.prec, FALSE);
+
+ /*
+ * Find the sign bit value of the source.
+ */
+ sign = (hssize_t) H5T__bit_get_d(s, src.u.f.sign, (size_t)1);
+
+ /*
+ * Check for special cases: +0, -0, +Inf, -Inf, NaN
+ */
+ if (H5T__bit_find (s, src.u.f.mpos, src.u.f.msize,
+ H5T_BIT_LSB, TRUE)<0) {
+ if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, TRUE)<0) {
+ /* +0 or -0 */
+ /* Set all bits to zero */
+ goto padding;
+ } else if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /* +Infinity or -Infinity */
+ if(sign) { /* -Infinity */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ if (H5T_SGN_2==dst.u.i.sign)
+ H5T__bit_set (d, dst.prec-1, (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ } else { /* +Infinity */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ if (H5T_SGN_NONE==dst.u.i.sign)
+ H5T__bit_set (d, dst.offset, dst.prec, TRUE);
+ else if (H5T_SGN_2==dst.u.i.sign)
+ H5T__bit_set (d, dst.offset, dst.prec-1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ }
+ goto padding;
+ }
+ } else if (H5T_NORM_NONE==src.u.f.norm && H5T__bit_find (s, src.u.f.mpos, src.u.f.msize-1,
+ H5T_BIT_LSB, TRUE)<0 && H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /*This is a special case for the source of no implied mantissa bit.
+ *If the exponent bits are all 1s and only the 1st bit of mantissa
+ *is set to 1. It's infinity. The Intel-Linux "long double" is this case.*/
+ /* +Infinity or -Infinity */
+ if(sign) { /* -Infinity */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ if (H5T_SGN_2==dst.u.i.sign)
+ H5T__bit_set (d, dst.prec-1, (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ } else { /* +Infinity */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PINF,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ if (H5T_SGN_NONE==dst.u.i.sign)
+ H5T__bit_set (d, dst.offset, dst.prec, TRUE);
+ else if (H5T_SGN_2==dst.u.i.sign)
+ H5T__bit_set (d, dst.offset, dst.prec-1, TRUE);
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ }
+ goto padding;
+ } else if (H5T__bit_find (s, src.u.f.epos, src.u.f.esize,
+ H5T_BIT_LSB, FALSE)<0) {
+ /* NaN */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_NAN,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ /*Just set all bits to zero.*/
+ goto padding;
+ } else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+
+ goto padding;
+ }
+
+ /*
+ * Get the exponent as an unsigned quantity from the section of
+ * the source bit field where it's located. Not expecting
+ * exponent to be greater than the maximal value of hssize_t.
+ */
+ expo = (hssize_t) H5T__bit_get_d(s, src.u.f.epos, src.u.f.esize);
+
+ /*
+ * Calculate the true source exponent by adjusting according to
+ * the source exponent bias.
+ */
+ if (0==expo || H5T_NORM_NONE==src.u.f.norm) {
+ expo -= (hssize_t) (src.u.f.ebias-1);
+ } else if (H5T_NORM_IMPLIED==src.u.f.norm) {
+ expo -= (hssize_t) src.u.f.ebias;
+ } else {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "normalization method not implemented yet")
+ }
+
+ /*
+ * Get the mantissa as bit vector from the section of
+ * the source bit field where it's located.
+ * Keep the little-endian order in the buffer.
+ * A sequence 0x01020304 will be like in the buffer,
+ * 04 03 02 01
+ * | | | |
+ * V V V V
+ * buf[0] buf[1] buf[2] buf[3]
+ */
+ H5T__bit_copy(int_buf, (size_t)0, s, src.u.f.mpos, src.u.f.msize);
+
+ /*
+ * Restore the implicit bit for mantissa if it's implied.
+ * Equivalent to mantissa |= (hsize_t)1<<src.u.f.msize.
+ */
+ if(H5T_NORM_IMPLIED == src.u.f.norm)
+ H5T__bit_inc(int_buf, src.u.f.msize, 8 * buf_size - src.u.f.msize);
+
+ /*
+ * Shift mantissa part by exponent minus mantissa size(right shift),
+ * or by mantissa size minus exponent(left shift). Example: Sequence
+ * 10...010111, expo=20, expo-msize=-3. Right-shift the sequence, we get
+ * 00010...10. The last three bits were dropped.
+ */
+ H5T__bit_shift(int_buf, expo - (ssize_t)src.u.f.msize, (size_t)0, buf_size * 8);
+
+ /*
+ * If expo is less than mantissa size, the frantional value is dropped off
+ * during conversion. Set exception type to be "truncate"
+ */
+ if ((size_t)expo < src.u.f.msize && cb_struct.func)
+ truncated = TRUE;
+
+ /*
+ * What is the bit position for the most significant bit(MSB) of S
+ * which is set? This is checked before converted to negative
+ * integer.
+ */
+ sfirst = H5T__bit_find(int_buf, (size_t)0, 8 * buf_size, H5T_BIT_MSB, TRUE);
+ first = (size_t)sfirst;
+
+ if(sfirst < 0) {
+ /*
+ * The source has no bits set and must therefore be zero.
+ * Set the destination to zero - nothing to do.
+ */
+ } else if (H5T_SGN_NONE==dst.u.i.sign) { /*destination is unsigned*/
+ /*
+ * Destination is unsigned. Library's default way: If the source value
+ * is greater than the maximal destination value then it overflows, the
+ * destination will be set to the maximum possible value. When the
+ * source is negative, underflow happens. Set the destination to be
+ * zero(do nothing). If user's exception handler is set, call it and
+ * let user handle it.
+ */
+ if(sign) { /*source is negative*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ }
+ }
+ } else { /*source is positive*/
+ if (first>=dst.prec) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ H5T__bit_set (d, dst.offset, dst.prec, TRUE);
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ } else if (first <dst.prec) {
+ if(truncated && cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_TRUNCATE,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ /*copy source value into it if case is ignored by user handler*/
+ H5T__bit_copy (d, dst.offset, int_buf, (size_t)0, first+1);
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ }
+ }
+ } else if (H5T_SGN_2==dst.u.i.sign) { /*Destination is signed*/
+ if(sign) { /*source is negative*/
+ if(first < dst.prec-1) {
+ if(truncated && cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_TRUNCATE,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) { /*If this case ignored by user handler*/
+ /*Convert to integer representation. Equivalent to ~(value - 1).*/
+ H5T__bit_dec(int_buf, (size_t)0, 8 * buf_size);
+ H5T__bit_neg(int_buf, (size_t)0, 8 * buf_size);
+
+ /*copy source value into destination*/
+ H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, dst.prec-1);
+ H5T__bit_set(d, (dst.offset + dst.prec-1), (size_t)1, TRUE);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ }
+ } else {
+ /* if underflows and no callback, do nothing except turn on
+ * the sign bit because 0x80...00 is the biggest negative value.
+ */
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_LOW,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ H5T__bit_set(d, (dst.offset + dst.prec-1), (size_t)1, TRUE);
+ else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ }
+ }
+ } else { /*source is positive*/
+ if (first >= dst.prec-1) {
+ /*overflow*/
+ if(cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED)
+ H5T__bit_set(d, dst.offset, dst.prec-1, TRUE);
+ else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ }
+ } else if(first < dst.prec-1) {
+ if(truncated && cb_struct.func) { /*If user's exception handler is present, use it*/
+ /*reverse order first*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order);
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_TRUNCATE,
+ src_id, dst_id, src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ /*copy source value into it if case is ignored by user handler*/
+ H5T__bit_copy (d, dst.offset, int_buf, (size_t)0, first+1);
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ /*No need to reverse the order of destination because user handles it*/
+ reverse = FALSE;
+ goto next;
+ }
+ }
+ }
+ }
+
+ padding:
+ /*
+ * Set padding areas in destination.
+ */
+ if (dst.offset>0) {
+ HDassert(H5T_PAD_ZERO==dst.lsb_pad || H5T_PAD_ONE==dst.lsb_pad);
+ H5T__bit_set(d, (size_t)0, dst.offset, (hbool_t)(H5T_PAD_ONE==dst.lsb_pad));
+ }
+ if (dst.offset+dst.prec!=8*dst_p->shared->size) {
+ HDassert(H5T_PAD_ZERO==dst.msb_pad || H5T_PAD_ONE==dst.msb_pad);
+ H5T__bit_set(d, dst.offset+dst.prec,
+ 8*dst_p->shared->size - (dst.offset+ dst.prec),
+ (hbool_t)(H5T_PAD_ONE==dst.msb_pad));
+ }
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if (H5T_ORDER_BE==dst.order && reverse) {
+ half_size = dst_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ tmp1 = d[dst_p->shared->size-(i+1)];
+ d[dst_p->shared->size-(i+1)] = d[i];
+ d[i] = tmp1;
+ }
+ }
+
+ next:
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if (d==dbuf)
+ HDmemcpy (dp, d, dst_p->shared->size);
+ if (buf_stride) {
+ sp += direction * (ssize_t) buf_stride;
+ dp += direction * (ssize_t) buf_stride;
+ } else {
+ sp += direction * (ssize_t) src_p->shared->size;
+ dp += direction * (ssize_t) dst_p->shared->size;
+ }
+
+ HDmemset(int_buf, 0, buf_size);
+ }
+
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ if(int_buf)
+ H5MM_xfree(int_buf);
+ if(src_rev)
+ H5MM_free(src_rev);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_f_i() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__conv_i_f
+ *
+ * Purpose: Convert one integer type to a floating-point type. This is
+ * the catch-all function for integer-float conversions and
+ * is probably not particularly fast.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * Friday, Feb 6, 2004
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * Wednesday, April 21, 2004
+ * There is a new design for exception handling like overflow,
+ * which is passed in as a transfer property.
+ *
+ * Raymond Lu
+ * Monday, March 13, 2006
+ * Added support for VAX floating-point types.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__conv_i_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, void H5_ATTR_UNUSED *bkg,
+ hid_t dxpl_id)
+{
+ /* Traversal-related variables */
+ H5T_t *src_p; /*source datatype */
+ H5T_t *dst_p; /*destination datatype */
+ H5T_atomic_t src; /*atomic source info */
+ H5T_atomic_t dst; /*atomic destination info */
+ int direction; /*forward or backward traversal */
+ size_t elmtno; /*element number */
+ size_t half_size; /*half the type size */
+ size_t tsize; /*type size for swapping bytes */
+ size_t olap; /*num overlapping elements */
+ uint8_t *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
+ uint8_t *src_rev = NULL; /*order-reversed source buffer */
+ uint8_t dbuf[64]; /*temp destination buffer */
+ uint8_t tmp1, tmp2; /*temp variables for swapping bytes*/
+
+ /* Conversion-related variables */
+ hsize_t expo; /*destination exponent */
+ hsize_t expo_max; /*maximal possible exponent value */
+ size_t sign; /*source sign bit value */
+ hbool_t is_max_neg; /*source is maximal negative value*/
+ hbool_t do_round; /*whether there is roundup */
+ uint8_t *int_buf = NULL; /*buffer for temporary value */
+ size_t buf_size; /*buffer size for temporary value */
+ size_t i; /*miscellaneous counters */
+ size_t first; /*first bit(MSB) in an integer */
+ ssize_t sfirst; /*a signed version of `first' */
+ H5P_genplist_t *plist; /*Property list pointer */
+ H5T_conv_cb_t cb_struct = {NULL, NULL}; /*conversion callback structure */
+ H5T_conv_ret_t except_ret; /*return of callback function */
+ hbool_t reverse; /*if reverse the order of destination */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ switch(cdata->command) {
+ case H5T_CONV_INIT:
+ if(NULL == (src_p = (H5T_t *)H5I_object(src_id)) || NULL == (dst_p = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+ if(H5T_ORDER_LE != dst.order && H5T_ORDER_BE != dst.order && H5T_ORDER_VAX != dst.order)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order")
+ if(dst_p->shared->size > sizeof(dbuf))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "destination size is too large")
+ if(8 * sizeof(expo) - 1 < src.u.f.esize)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "exponent field is too large")
+ cdata->need_bkg = H5T_BKG_NO;
+ break;
+
+ case H5T_CONV_FREE:
+ break;
+
+ case H5T_CONV_CONV:
+ /* Get the datatypes */
+ if(NULL == (src_p = (H5T_t *)H5I_object(src_id)) || NULL == (dst_p = (H5T_t *)H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ src = src_p->shared->u.atomic;
+ dst = dst_p->shared->u.atomic;
+
+ /*
+ * Do we process the values from beginning to end or vice versa? Also,
+ * how many of the elements have the source and destination areas
+ * overlapping?
+ */
+ if (src_p->shared->size==dst_p->shared->size || buf_stride) {
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ olap = nelmts;
+ } else if (src_p->shared->size>=dst_p->shared->size) {
+ double olap_d = HDceil((double)(dst_p->shared->size)/
+ (double)(src_p->shared->size-dst_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = dp = (uint8_t*)buf;
+ direction = 1;
+ } else {
+ double olap_d = HDceil((double)(src_p->shared->size)/
+ (double)(dst_p->shared->size-src_p->shared->size));
+ olap = (size_t)olap_d;
+ sp = (uint8_t*)buf + (nelmts-1) * src_p->shared->size;
+ dp = (uint8_t*)buf + (nelmts-1) * dst_p->shared->size;
+ direction = -1;
+ }
+
+ /* Allocate enough space for the buffer holding temporary
+ * converted value
+ */
+ buf_size = (src.prec > dst.u.f.msize ? src.prec : dst.u.f.msize)/8 + 1;
+ int_buf = (uint8_t*)H5MM_calloc(buf_size);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find property list for ID")
+
+ /* Get conversion exception callback property */
+ if(H5P_get(plist,H5D_XFER_CONV_CB_NAME, &cb_struct) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback")
+
+ /* Allocate space for order-reversed source buffer */
+ src_rev = (uint8_t*)H5MM_calloc(src_p->shared->size);
+
+ /* The conversion loop */
+ for (elmtno=0; elmtno<nelmts; elmtno++) {
+ /* Set these variables to default */
+ except_ret = H5T_CONV_UNHANDLED;
+ reverse = TRUE;
+
+ /* Make sure these variables are reset to 0. */
+ sign = 0; /*source sign bit value */
+ is_max_neg = 0; /*source is maximal negative value*/
+ do_round = 0; /*whether there is roundup */
+ sfirst = 0;
+
+ /*
+ * If the source and destination buffers overlap then use a
+ * temporary buffer for the destination.
+ */
+ if (direction>0) {
+ s = sp;
+ d = elmtno<olap ? dbuf : dp;
+ } else {
+ s = sp;
+ d = elmtno+olap >= nelmts ? dbuf : dp;
+ }
+#ifndef NDEBUG
+ /* I don't quite trust the overlap calculations yet --rpm */
+ if (d==dbuf) {
+ HDassert((dp>=sp && dp<sp+src_p->shared->size) ||
+ (sp>=dp && sp<dp+dst_p->shared->size));
+ } else {
+ HDassert((dp<sp && dp+dst_p->shared->size<=sp) ||
+ (sp<dp && sp+src_p->shared->size<=dp));
+ }
+#endif
+
+ /*
+ * Put the data in little endian order so our loops aren't so
+ * complicated. We'll do all the conversion stuff assuming
+ * little endian and then we'll fix the order at the end.
+ */
+ if (H5T_ORDER_BE==src.order) {
+ half_size = src_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ tmp1 = s[src_p->shared->size-(i+1)];
+ s[src_p->shared->size-(i+1)] = s[i];
+ s[i] = tmp1;
+ }
+ }
+
+ /*zero-set all destination bits*/
+ H5T__bit_set (d, dst.offset, dst.prec, FALSE);
+
+ /* Copy source into a temporary buffer */
+ H5T__bit_copy(int_buf, (size_t)0, s, src.offset, src.prec);
+
+ /*
+ * Find the sign bit value of the source.
+ */
+ if(H5T_SGN_2 == src.u.i.sign)
+ sign = (size_t)H5T__bit_get_d(int_buf, src.prec - 1, (size_t)1);
+
+ /*
+ * What is the bit position(starting from 0 as first one) for the most significant
+ * bit(MSB) of S which is set?
+ */
+ if(H5T_SGN_2 == src.u.i.sign) {
+ sfirst = H5T__bit_find(int_buf, (size_t)0, src.prec - 1, H5T_BIT_MSB, TRUE);
+ if(sign && sfirst < 0)
+ /* The case 0x80...00, which is negative with maximal value */
+ is_max_neg = 1;
+ } else if(H5T_SGN_NONE == src.u.i.sign)
+ sfirst = H5T__bit_find(int_buf, (size_t)0, src.prec, H5T_BIT_MSB, TRUE);
+
+ /* Handle special cases here. Integer is zero */
+ if(!sign && sfirst < 0)
+ goto padding;
+
+ /*
+ * Convert source integer if it's negative
+ */
+ if(H5T_SGN_2 == src.u.i.sign && sign) {
+ if(!is_max_neg) {
+ /* Equivalent to ~(i - 1) */
+ H5T__bit_dec(int_buf, (size_t)0, buf_size * 8);
+ H5T__bit_neg(int_buf, (size_t)0, buf_size * 8);
+ sfirst = H5T__bit_find(int_buf, (size_t)0, src.prec - 1, H5T_BIT_MSB, TRUE);
+ } else {
+ /* If it's maximal negative number 0x80...000, treat it as if it overflowed
+ * (create a carry) to help conversion. i.e. a character type number 0x80
+ * is treated as 0x100.
+ */
+ sfirst = (ssize_t)(src.prec - 1);
+ is_max_neg = 0;
+ }
+ if(sfirst < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "zero bit not found")
+
+ /* Sign bit has been negated if bit vector isn't 0x80...00. Set all bits in front of
+ * sign bit to 0 in the temporary buffer because they're all negated from the previous
+ * step. */
+ H5T__bit_set(int_buf, src.prec, (buf_size * 8) - src.prec, 0);
+
+ /* Set sign bit in destination */
+ H5T__bit_set_d(d, dst.u.f.sign, (size_t)1, (hsize_t)sign);
+ } /* end if */
+
+ first = (size_t)sfirst;
+
+ /*
+ * Calculate the true destination exponent by adjusting according to
+ * the destination exponent bias. Implied and non-implied normalization
+ * should be the same.
+ */
+ if (H5T_NORM_NONE==dst.u.f.norm || H5T_NORM_IMPLIED==dst.u.f.norm) {
+ expo = first + dst.u.f.ebias;
+ } else {
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "normalization method not implemented yet")
+ }
+
+ /* Handle mantissa part here */
+ if (H5T_NORM_IMPLIED==dst.u.f.norm) {
+ /* Imply first bit */
+ H5T__bit_set(int_buf, first, (size_t)1, 0);
+ } else if (H5T_NORM_NONE==dst.u.f.norm) {
+ first++;
+ }
+
+ /* Roundup for mantissa */
+ if(first > dst.u.f.msize) {
+ /* If the bit sequence is bigger than the mantissa part, there'll be some
+ * precision loss. Let user's handler deal with the case if it's present
+ */
+ if(cb_struct.func) {
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_PRECISION, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+ }
+
+ if(except_ret == H5T_CONV_HANDLED) {
+ reverse = FALSE;
+ goto padding;
+ } else if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+
+ /* If user's exception handler does deal with it, we do it by dropping off the
+ * extra bits at the end and do rounding. If we have .50...0(decimal) after radix
+ * point, we do roundup when the least significant digit before radix is odd, we do
+ * rounddown if it's even.
+ */
+
+ /* Check 1st dropoff bit, see if it's set. */
+ if(H5T__bit_get_d(int_buf, ((first - dst.u.f.msize) - 1), (size_t)1)) {
+ /* Check all bits after 1st dropoff bit, see if any of them is set. */
+ if(((first - dst.u.f.msize) - 1) > 0 && H5T__bit_get_d(int_buf, (size_t)0, ((first - dst.u.f.msize) - 1)))
+ do_round = 1;
+ else { /* The .50...0 case */
+ /* Check if the least significant bit is odd. */
+ if(H5T__bit_get_d(int_buf, (first - dst.u.f.msize), (size_t)1))
+ do_round = 1;
+ }
+ }
+
+ /* Right shift to drop off extra bits */
+ H5T__bit_shift(int_buf, (ssize_t)(dst.u.f.msize - first), (size_t)0, buf_size * 8);
+
+ if(do_round) {
+ H5T__bit_inc(int_buf, (size_t)0, buf_size * 8);
+ do_round = 0;
+
+ /* If integer is like 0x0ff...fff and we need to round up the
+ * last f, we get 0x100...000. Treat this special case here.
+ */
+ if(H5T__bit_get_d(int_buf, dst.u.f.msize, (size_t)1)) {
+ if (H5T_NORM_IMPLIED==dst.u.f.norm) {
+ /* The bit at this 1's position was impled already, so this
+ * number should be 0x200...000. We need to increment the
+ * exponent in this case.
+ */
+ expo++;
+ } else if (H5T_NORM_NONE==dst.u.f.norm) {
+ /* Right shift 1 bit to let the carried 1 fit in the mantissa,
+ * and increment exponent by 1.
+ */
+ H5T__bit_shift(int_buf, (ssize_t)-1, (size_t)0, buf_size * 8);
+ expo++;
+ }
+ }
+ }
+ } else {
+ /* The bit sequence can fit mantissa part. Left shift to fit in from high-order of
+ * bit position. */
+ H5T__bit_shift(int_buf, (ssize_t)(dst.u.f.msize - first), (size_t)0, dst.u.f.msize);
+ }
+
+
+ /* Check if the exponent is too big */
+ expo_max = (hsize_t) (HDpow((double)2.0f, (double)dst.u.f.esize) - 1);
+
+ if(expo > expo_max) { /*overflows*/
+ if(cb_struct.func) { /*user's exception handler. Reverse back source order*/
+ H5T_reverse_order(src_rev, s, src_p->shared->size, src_p->shared->u.atomic.order); /*reverse order first*/
+ except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, src_id, dst_id,
+ src_rev, d, cb_struct.user_data);
+
+ if(except_ret == H5T_CONV_ABORT)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception")
+ else if(except_ret == H5T_CONV_HANDLED) {
+ reverse = FALSE;
+ goto padding;
+ }
+ } else {
+ /*make destination infinity by setting exponent to maximal number and
+ *mantissa to zero.*/
+ expo = expo_max;
+ HDmemset(int_buf, 0, buf_size);
+ }
+ }
+
+ if(except_ret == H5T_CONV_UNHANDLED) {
+ /* Set exponent in destination */
+ H5T__bit_set_d(d, dst.u.f.epos, dst.u.f.esize, expo);
+
+ /* Copy mantissa into destination */
+ H5T__bit_copy(d, dst.u.f.mpos, int_buf, (size_t)0, (buf_size * 8) > dst.u.f.msize ? dst.u.f.msize : buf_size * 8);
+ }
+
+ padding:
+ /*
+ * Set padding areas in destination.
+ */
+ if(dst.offset > 0) {
+ HDassert(H5T_PAD_ZERO == dst.lsb_pad || H5T_PAD_ONE == dst.lsb_pad);
+ H5T__bit_set(d, (size_t)0, dst.offset, (hbool_t)(H5T_PAD_ONE==dst.lsb_pad));
+ }
+ if(dst.offset + dst.prec != 8 * dst_p->shared->size) {
+ HDassert(H5T_PAD_ZERO == dst.msb_pad || H5T_PAD_ONE == dst.msb_pad);
+ H5T__bit_set(d, dst.offset + dst.prec,
+ 8 * dst_p->shared->size - (dst.offset + dst.prec),
+ (hbool_t)(H5T_PAD_ONE == dst.msb_pad));
+ }
+
+ /*
+ * Put the destination in the correct byte order. See note at
+ * beginning of loop.
+ */
+ if (H5T_ORDER_BE==dst.order && reverse) {
+ half_size = dst_p->shared->size/2;
+ for (i=0; i<half_size; i++) {
+ uint8_t tmp = d[dst_p->shared->size-(i+1)];
+ d[dst_p->shared->size-(i+1)] = d[i];
+ d[i] = tmp;
+ }
+ } else if (H5T_ORDER_VAX==dst.order && reverse) {
+ tsize = dst_p->shared->size;
+ HDassert(0 == tsize % 2);
+
+ for (i = 0; i < tsize; i += 4) {
+ tmp1 = d[i];
+ tmp2 = d[i+1];
+
+ d[i] = d[(tsize-2)-i];
+ d[i+1] = d[(tsize-1)-i];
+
+ d[(tsize-2)-i] = tmp1;
+ d[(tsize-1)-i] = tmp2;
+ }
+ }
+
+ /*
+ * If we had used a temporary buffer for the destination then we
+ * should copy the value to the true destination buffer.
+ */
+ if (d==dbuf)
+ HDmemcpy (dp, d, dst_p->shared->size);
+ if (buf_stride) {
+ sp += direction * (ssize_t) buf_stride;
+ dp += direction * (ssize_t) buf_stride;
+ } else {
+ sp += direction * (ssize_t) src_p->shared->size;
+ dp += direction * (ssize_t) dst_p->shared->size;
+ }
+
+ HDmemset(int_buf, 0, buf_size);
+ }
+
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command")
+ } /* end switch */
+
+done:
+ if(int_buf)
+ H5MM_xfree(int_buf);
+ if(src_rev)
+ H5MM_free(src_rev);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__conv_i_f() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_reverse_order
+ *
+ * Purpose: Internal assisting function to reverse the order of
+ * a sequence of byte when it's big endian or VAX order.
+ * The byte sequence simulates the endian order.
+ *
+ * Return: Success: A pointer to the reversed byte sequence
+ *
+ * Failure: Null
+ *
+ * Programmer: Raymond Lu
+ * April 26, 2004
+ *
+ * Modifications:
+ *
+ * Raymond Lu
+ * March 13, 2006
+ * Add support for VAX floating-point types.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_reverse_order(uint8_t *rev, uint8_t *s, size_t size, H5T_order_t order)
+{
+ size_t i;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(s);
+ HDassert(size);
+
+ if (H5T_ORDER_VAX == order) {
+ for (i = 0; i < size; i += 2) {
+ rev[i] = s[(size - 2) - i];
+ rev[i + 1] = s[(size - 1) - i];
+ }
+ } else if (H5T_ORDER_BE == order) {
+ for (i=0; i<size; i++)
+ rev[size-(i+1)] = s[i];
+ } else {
+ for (i=0; i<size; i++)
+ rev[i] = s[i];
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
diff --git a/src/H5Tcset.c b/src/H5Tcset.c
new file mode 100644
index 0000000..186e598
--- /dev/null
+++ b/src/H5Tcset.c
@@ -0,0 +1,124 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the character set (cset) for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5Tpkg.h" /*data-type functions */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_cset
+ *
+ * Purpose: HDF5 is able to distinguish between character sets of
+ * different nationalities and to convert between them to the
+ * extent possible.
+ *
+ * Return: Success: The character set of a string type.
+ *
+ * Failure: H5T_CSET_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_cset_t
+H5Tget_cset(hid_t type_id)
+{
+ H5T_t *dt;
+ H5T_cset_t ret_value;
+
+ FUNC_ENTER_API(H5T_CSET_ERROR)
+ H5TRACE1("Tc", "i", type_id);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_CSET_ERROR, "not a data type")
+ while (dt->shared->parent && !H5T_IS_STRING(dt->shared))
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_STRING(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, H5T_CSET_ERROR, "operation not defined for data type class")
+
+ /* result */
+ if(H5T_IS_FIXED_STRING(dt->shared))
+ ret_value = dt->shared->u.atomic.u.s.cset;
+ else
+ ret_value = dt->shared->u.vlen.cset;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_cset
+ *
+ * Purpose: HDF5 is able to distinguish between character sets of
+ * different nationalities and to convert between them to the
+ * extent possible.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_cset(hid_t type_id, H5T_cset_t cset)
+{
+ H5T_t *dt;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTc", type_id, cset);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "data type is read-only")
+ if (cset < H5T_CSET_ASCII || cset >= H5T_NCSET)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "illegal character set type")
+ while (dt->shared->parent && !H5T_IS_STRING(dt->shared))
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_STRING(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for data type class")
+
+ /* Commit */
+ if(H5T_IS_FIXED_STRING(dt->shared))
+ dt->shared->u.atomic.u.s.cset = cset;
+ else
+ dt->shared->u.vlen.cset = cset;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
diff --git a/src/H5Tdbg.c b/src/H5Tdbg.c
new file mode 100644
index 0000000..f434543
--- /dev/null
+++ b/src/H5Tdbg.c
@@ -0,0 +1,442 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Tdbg.c
+ * Jul 19 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Dump debugging information about a datatype
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__print_stats
+ *
+ * Purpose: Print statistics about a conversion path. Statistics are
+ * printed only if all the following conditions are true:
+ *
+ * 1. The library was compiled with H5T_DEBUG defined.
+ * 2. Data type debugging is turned on at run time.
+ * 3. The path was called at least one time.
+ *
+ * The optional NPRINT argument keeps track of the number of
+ * conversions paths for which statistics have been shown. If
+ * its value is zero then table headers are printed before the
+ * first line of output.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__print_stats(H5T_path_t H5_ATTR_UNUSED * path, int H5_ATTR_UNUSED * nprint/*in,out*/)
+{
+#ifdef H5T_DEBUG
+ hsize_t nbytes;
+ char bandwidth[32];
+#endif
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+#ifdef H5T_DEBUG
+ if(H5DEBUG(T) && path->stats.ncalls > 0) {
+ if(nprint && 0 == (*nprint)++) {
+ HDfprintf(H5DEBUG(T), "H5T: type conversion statistics:\n");
+ HDfprintf(H5DEBUG(T), " %-16s %10s %10s %8s %8s %8s %10s\n",
+ "Conversion", "Elmts", "Calls", "User",
+ "System", "Elapsed", "Bandwidth");
+ HDfprintf(H5DEBUG(T), " %-16s %10s %10s %8s %8s %8s %10s\n",
+ "----------", "-----", "-----", "----",
+ "------", "-------", "---------");
+ }
+ if(path->src && path->dst)
+ nbytes = MAX(H5T_get_size(path->src), H5T_get_size(path->dst));
+ else if(path->src)
+ nbytes = H5T_get_size(path->src);
+ else if(path->dst)
+ nbytes = H5T_get_size(path->dst);
+ else
+ nbytes = 0;
+ nbytes *= path->stats.nelmts;
+ H5_bandwidth(bandwidth, (double)nbytes, path->stats.timer.etime);
+ HDfprintf(H5DEBUG(T), " %-16s %10Hd %10d %8.2f %8.2f %8.2f %10s\n",
+ path->name,
+ path->stats.nelmts,
+ path->stats.ncalls,
+ path->stats.timer.utime,
+ path->stats.timer.stime,
+ path->stats.timer.etime,
+ bandwidth);
+ }
+#endif
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T__print_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_debug
+ *
+ * Purpose: Prints information about a data type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_debug(const H5T_t *dt, FILE *stream)
+{
+ const char *s1 = "", *s2 = "";
+ unsigned i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(stream);
+
+ switch(dt->shared->type) {
+ case H5T_NO_CLASS:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "no class");
+ break;
+
+ case H5T_INTEGER:
+ s1 = "int";
+ break;
+
+ case H5T_FLOAT:
+ s1 = "float";
+ break;
+
+ case H5T_TIME:
+ s1 = "time";
+ break;
+
+ case H5T_STRING:
+ s1 = "str";
+ break;
+
+ case H5T_BITFIELD:
+ s1 = "bits";
+ break;
+
+ case H5T_OPAQUE:
+ s1 = "opaque";
+ break;
+
+ case H5T_COMPOUND:
+ s1 = "struct";
+ break;
+
+ case H5T_ENUM:
+ s1 = "enum";
+ break;
+
+ case H5T_VLEN:
+ if(H5T_IS_VL_STRING(dt->shared))
+ s1 = "str";
+ else
+ s1 = "vlen";
+ break;
+
+ case H5T_REFERENCE:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ s1 = "";
+ break;
+ } /* end switch */
+
+ switch(dt->shared->state) {
+ case H5T_STATE_TRANSIENT:
+ s2 = "[transient]";
+ break;
+
+ case H5T_STATE_RDONLY:
+ s2 = "[constant]";
+ break;
+
+ case H5T_STATE_IMMUTABLE:
+ s2 = "[predefined]";
+ break;
+
+ case H5T_STATE_NAMED:
+ s2 = "[named,closed]";
+ break;
+
+ case H5T_STATE_OPEN:
+ s2 = "[named,open]";
+ break;
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+
+ fprintf(stream, "%s%s {nbytes=%lu", s1, s2, (unsigned long)(dt->shared->size));
+
+ if(H5T_IS_ATOMIC(dt->shared)) {
+ uint64_t tmp;
+
+ switch(dt->shared->u.atomic.order) {
+ case H5T_ORDER_ERROR:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "order error");
+ break;
+
+ case H5T_ORDER_BE:
+ s1 = "BE";
+ break;
+
+ case H5T_ORDER_LE:
+ s1 = "LE";
+ break;
+
+ case H5T_ORDER_VAX:
+ s1 = "VAX";
+ break;
+
+ case H5T_ORDER_NONE:
+ s1 = "NONE";
+ break;
+
+ case H5T_ORDER_MIXED:
+ default:
+ s1 = "order?";
+ break;
+ } /* end switch */
+
+ fprintf(stream, ", %s", s1);
+
+ if(dt->shared->u.atomic.offset)
+ fprintf(stream, ", offset=%lu",
+ (unsigned long) (dt->shared->u.atomic.offset));
+ if(dt->shared->u.atomic.prec != 8 * dt->shared->size)
+ fprintf(stream, ", prec=%lu",
+ (unsigned long) (dt->shared->u.atomic.prec));
+ switch(dt->shared->type) {
+ case H5T_NO_CLASS:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "no class");
+ break;
+
+ case H5T_INTEGER:
+ switch(dt->shared->u.atomic.u.i.sign) {
+ case H5T_SGN_ERROR:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "sign error");
+ break;
+
+ case H5T_SGN_NONE:
+ s1 = "unsigned";
+ break;
+
+ case H5T_SGN_2:
+ s1 = NULL;
+ break;
+
+ case H5T_NSGN:
+ default:
+ s1 = "sign?";
+ break;
+
+ } /* end switch */
+ if(s1)
+ fprintf(stream, ", %s", s1);
+ break;
+
+ case H5T_FLOAT:
+ switch(dt->shared->u.atomic.u.f.norm) {
+ case H5T_NORM_ERROR:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "norm error");
+ break;
+
+ case H5T_NORM_IMPLIED:
+ s1 = "implied";
+ break;
+
+ case H5T_NORM_MSBSET:
+ s1 = "msbset";
+ break;
+
+ case H5T_NORM_NONE:
+ s1 = "no-norm";
+ break;
+
+ default:
+ s1 = "norm?";
+ break;
+ } /* end switch */
+
+ fprintf(stream, ", sign=%lu+1",
+ (unsigned long)(dt->shared->u.atomic.u.f.sign));
+ fprintf(stream, ", mant=%lu+%lu (%s)",
+ (unsigned long)(dt->shared->u.atomic.u.f.mpos),
+ (unsigned long)(dt->shared->u.atomic.u.f.msize), s1);
+ fprintf(stream, ", exp=%lu+%lu",
+ (unsigned long)(dt->shared->u.atomic.u.f.epos),
+ (unsigned long)(dt->shared->u.atomic.u.f.esize));
+ tmp = dt->shared->u.atomic.u.f.ebias >> 32;
+ if(tmp) {
+ size_t hi = (size_t)tmp;
+ size_t lo = (size_t)(dt->shared->u.atomic.u.f.ebias & 0xffffffff);
+ fprintf(stream, " bias=0x%08lx%08lx",
+ (unsigned long)hi, (unsigned long)lo);
+ } else {
+ size_t lo = (size_t)(dt->shared->u.atomic.u.f.ebias & 0xffffffff);
+ fprintf(stream, " bias=0x%08lx", (unsigned long)lo);
+ }
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ /* No additional info */
+ break;
+ } /* end switch */
+ } else if(H5T_COMPOUND == dt->shared->type) {
+ /* Compound data type */
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++) {
+ fprintf(stream, "\n\"%s\" @%lu",
+ dt->shared->u.compnd.memb[i].name,
+ (unsigned long)(dt->shared->u.compnd.memb[i].offset));
+ fprintf(stream, " ");
+ H5T_debug(dt->shared->u.compnd.memb[i].type, stream);
+ } /* end for */
+ fprintf(stream, "\n");
+ } else if(H5T_VLEN == dt->shared->type) {
+ switch(dt->shared->u.vlen.loc) {
+ case H5T_LOC_BADLOC:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "invalid datatype location");
+ break;
+
+ case H5T_LOC_MEMORY:
+ fprintf(stream, ", loc=memory");
+ break;
+
+ case H5T_LOC_DISK:
+ fprintf(stream, ", loc=disk");
+ break;
+
+ case H5T_LOC_MAXLOC:
+ default:
+ fprintf(stream, ", loc=UNKNOWN");
+ break;
+ } /* end switch */
+
+ if(H5T_IS_VL_STRING(dt->shared))
+ /* Variable length string datatype */
+ fprintf(stream, ", variable-length");
+ else {
+ /* Variable length sequence datatype */
+ fprintf(stream, " VLEN ");
+ H5T_debug(dt->shared->parent, stream);
+ fprintf(stream, "\n");
+ } /* end else */
+ } else if(H5T_ENUM == dt->shared->type) {
+ size_t base_size;
+
+ /* Enumeration data type */
+ fprintf(stream, " ");
+ H5T_debug(dt->shared->parent, stream);
+ base_size = dt->shared->parent->shared->size;
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++) {
+ size_t k;
+
+ fprintf(stream, "\n\"%s\" = 0x", dt->shared->u.enumer.name[i]);
+ for(k = 0; k < base_size; k++)
+ fprintf(stream, "%02lx",
+ (unsigned long)(dt->shared->u.enumer.value + (i * base_size) + k));
+ } /* end for */
+ fprintf(stream, "\n");
+ } else if(H5T_OPAQUE == dt->shared->type) {
+ fprintf(stream, ", tag=\"%s\"", dt->shared->u.opaque.tag);
+ } else {
+ /* Unknown */
+ fprintf(stream, "unknown class %d\n", (int)(dt->shared->type));
+ }
+ fprintf(stream, "}");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_debug() */
+
diff --git a/src/H5Tdeprec.c b/src/H5Tdeprec.c
new file mode 100644
index 0000000..c506ec1
--- /dev/null
+++ b/src/H5Tdeprec.c
@@ -0,0 +1,205 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Tdeprec.c
+ * April 5 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Deprecated functions from the H5T interface. These
+ * functions are here for compatibility purposes and may be
+ * removed in the future. Applications should switch to the
+ * newer APIs.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FOprivate.h" /* File objects */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Ppublic.h" /* Property Lists */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tcommit1
+ *
+ * Purpose: Save a transient datatype to a file and turn the type handle
+ * into a named, immutable type.
+ *
+ * Note: Deprecated in favor of H5Tcommit2
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Monday, June 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tcommit1(hid_t loc_id, const char *name, hid_t type_id)
+{
+ H5G_loc_t loc; /* Location to create datatype */
+ H5T_t *type; /* Datatype for ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*si", loc_id, name, type_id);
+
+ /* Check arguments */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Commit the datatype to the file, using default property list values */
+ if(H5T__commit_named(&loc, name, type, H5P_LINK_CREATE_DEFAULT,
+ H5P_DATATYPE_CREATE_DEFAULT, H5P_DATATYPE_ACCESS_DEFAULT, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to commit datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tcommit1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Topen1
+ *
+ * Purpose: Opens a named datatype.
+ *
+ * Note: Deprecated in favor of H5Topen2
+ *
+ * Return: Success: Object ID of the named datatype.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, June 1, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Topen1(hid_t loc_id, const char *name)
+{
+ H5T_t *type = NULL;
+ H5G_loc_t loc;
+ H5G_name_t path; /* Datatype group hier. path */
+ H5O_loc_t oloc; /* Datatype object location */
+ H5O_type_t obj_type; /* Type of object at location */
+ H5G_loc_t type_loc; /* Group object for datatype */
+ hbool_t obj_found = FALSE; /* Object at 'name' found */
+ hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl to use to open datatype */
+ hid_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "i*s", loc_id, name);
+
+ /* Check args */
+ if(H5G_loc(loc_id, &loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+
+ /* Set up datatype location to fill in */
+ type_loc.oloc = &oloc;
+ type_loc.path = &path;
+ H5G_loc_reset(&type_loc);
+
+ /*
+ * Find the named datatype object header and read the datatype message
+ * from it.
+ */
+ if(H5G_loc_find(&loc, name, &type_loc/*out*/, H5P_DEFAULT, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "not found")
+ obj_found = TRUE;
+
+ /* Check that the object found is the correct type */
+ if(H5O_obj_type(&oloc, &obj_type, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get object type")
+ if(obj_type != H5O_TYPE_NAMED_DATATYPE)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a named datatype")
+
+ /* Open it */
+ if((type = H5T_open(&type_loc, dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype")
+
+ /* Register the type and return the ID */
+ if((ret_value = H5I_register(H5I_DATATYPE, type, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register named datatype")
+
+done:
+ if(ret_value < 0) {
+ if(type != NULL)
+ H5T_close(type);
+ else {
+ if(obj_found && H5F_addr_defined(type_loc.oloc->addr))
+ H5G_loc_free(&type_loc);
+ } /* end else */
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Topen1() */
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
diff --git a/src/H5Tenum.c b/src/H5Tenum.c
new file mode 100644
index 0000000..f5263ed
--- /dev/null
+++ b/src/H5Tenum.c
@@ -0,0 +1,582 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for enumerated datatypes
+ * in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5MMprivate.h" /*memory management */
+#include "H5Tpkg.h" /*data-type functions */
+
+/* Static local functions */
+static char *H5T_enum_nameof(const H5T_t *dt, const void *value, char *name/*out*/,
+ size_t size);
+static herr_t H5T_enum_valueof(const H5T_t *dt, const char *name,
+ void *value/*out*/);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tenum_create
+ *
+ * Purpose: Create a new enumeration data type based on the specified
+ * TYPE, which must be an integer type.
+ *
+ * Return: Success: ID of new enumeration data type
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, December 22, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tenum_create(hid_t parent_id)
+{
+ H5T_t *parent = NULL; /*base integer data type */
+ H5T_t *dt = NULL; /*new enumeration data type */
+ hid_t ret_value; /*return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", parent_id);
+
+ /* Check args */
+ if(NULL == (parent = (H5T_t *)H5I_object_verify(parent_id, H5I_DATATYPE)) || H5T_INTEGER != parent->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an integer data type")
+
+ /* Build new type */
+ if(NULL == (dt = H5T__enum_create(parent)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "cannot create enum type")
+ /* Atomize the type */
+ if ((ret_value=H5I_register(H5I_DATATYPE, dt, TRUE))<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register data type atom")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__enum_create
+ *
+ * Purpose: Private function for H5Tenum_create. Create a new
+ * enumeration data type based on the specified
+ * TYPE, which must be an integer type.
+ *
+ * Return: Success: new enumeration data type
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * October 9, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T__enum_create(const H5T_t *parent)
+{
+ H5T_t *ret_value = NULL; /* New enumeration data type */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(parent);
+
+ /* Build new type */
+ if(NULL == (ret_value = H5T__alloc()))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ ret_value->shared->type = H5T_ENUM;
+ ret_value->shared->parent = H5T_copy(parent, H5T_COPY_ALL);
+ HDassert(ret_value->shared->parent);
+ ret_value->shared->size = ret_value->shared->parent->shared->size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tenum_insert
+ *
+ * Purpose: Insert a new enumeration data type member into an enumeration
+ * type. TYPE is the enumeration type, NAME is the name of the
+ * new member, and VALUE points to the value of the new member.
+ * The NAME and VALUE must both be unique within the TYPE. VALUE
+ * points to data which is of the data type defined when the
+ * enumeration type was created.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tenum_insert(hid_t type, const char *name, const void *value)
+{
+ H5T_t *dt=NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*s*x", type, name, value);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(H5T_ENUM != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
+ if (!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+ if (!value)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value specified")
+
+ /* Do work */
+ if(H5T__enum_insert(dt, name, value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert new enumeration member")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__enum_insert
+ *
+ * Purpose: Insert a new member having a NAME and VALUE into an
+ * enumeration data TYPE. The NAME and VALUE must both be
+ * unique. The VALUE points to data of the data type defined for
+ * the enumeration base type.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__enum_insert(const H5T_t *dt, const char *name, const void *value)
+{
+ unsigned i;
+ char **names=NULL;
+ uint8_t *values=NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dt);
+ HDassert(name && *name);
+ HDassert(value);
+
+ /* The name and value had better not already exist */
+ for (i=0; i<dt->shared->u.enumer.nmembs; i++) {
+ if (!HDstrcmp(dt->shared->u.enumer.name[i], name))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "name redefinition")
+ if (!HDmemcmp(dt->shared->u.enumer.value+i*dt->shared->size, value, dt->shared->size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "value redefinition")
+ }
+
+ /* Increase table sizes */
+ if(dt->shared->u.enumer.nmembs >= dt->shared->u.enumer.nalloc) {
+ unsigned n = MAX(32, 2*dt->shared->u.enumer.nalloc);
+
+ if(NULL == (names = (char **)H5MM_realloc(dt->shared->u.enumer.name, n * sizeof(char *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ dt->shared->u.enumer.name = names;
+
+ if(NULL == (values = (uint8_t *)H5MM_realloc(dt->shared->u.enumer.value, n * dt->shared->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ dt->shared->u.enumer.value = values;
+ dt->shared->u.enumer.nalloc = n;
+ }
+
+ /* Insert new member at end of member arrays */
+ dt->shared->u.enumer.sorted = H5T_SORT_NONE;
+ i = dt->shared->u.enumer.nmembs++;
+ dt->shared->u.enumer.name[i] = H5MM_xstrdup(name);
+ HDmemcpy(dt->shared->u.enumer.value+i*dt->shared->size, value, dt->shared->size);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_value
+ *
+ * Purpose: Return the value for an enumeration data type member.
+ *
+ * Return: Success: non-negative with the member value copied
+ * into the memory pointed to by VALUE.
+ *
+ * Failure: negative, VALUE memory is undefined.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, December 23, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tget_member_value(hid_t type, unsigned membno, void *value/*out*/)
+{
+ H5T_t *dt=NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iIux", type, membno, value);
+
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(H5T_ENUM != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not defined for data type class")
+ if (membno>=dt->shared->u.enumer.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid member number")
+ if (!value)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null value buffer")
+
+ if(H5T__get_member_value(dt, membno, value) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get member value")
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__get_member_value
+ *
+ * Purpose: Private function for H5T__get_member_value. Return the
+ * value for an enumeration data type member.
+ *
+ * Return: Success: non-negative with the member value copied
+ * into the memory pointed to by VALUE.
+ *
+ * Failure: negative, VALUE memory is undefined.
+ *
+ * Programmer: Raymond Lu
+ * October 9, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__get_member_value(const H5T_t *dt, unsigned membno, void *value/*out*/)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ HDassert(dt);
+ HDassert(value);
+
+ HDmemcpy(value, dt->shared->u.enumer.value + membno*dt->shared->size, dt->shared->size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tenum_nameof
+ *
+ * Purpose: Finds the symbol name that corresponds to the specified VALUE
+ * of an enumeration data type TYPE. At most SIZE characters of
+ * the symbol name are copied into the NAME buffer. If the
+ * entire symbol anem and null terminator do not fit in the NAME
+ * buffer then as many characters as possible are copied (not
+ * null terminated) and the function fails.
+ *
+ * Return: Success: Non-negative.
+ *
+ * Failure: Negative, first character of NAME is set to
+ * null if SIZE allows it.
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tenum_nameof(hid_t type, const void *value, char *name/*out*/, size_t size)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "i*xxz", type, value, name, size);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(H5T_ENUM != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
+ if (!value)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value supplied")
+ if (!name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name buffer supplied")
+
+ if (NULL==H5T_enum_nameof(dt, value, name, size))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "nameof query failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_enum_nameof
+ *
+ * Purpose: Finds the symbol name that corresponds the the specified
+ * VALUE of an enumeration data type DT. At most SIZE characters
+ * of the symbol name are copied into the NAME buffer. If the
+ * entire symbol name and null terminator do not fit in the NAME
+ * buffer then as many characters as possible are copied and the
+ * function returns failure.
+ *
+ * If NAME is the null pointer and SIZE is zero then enough
+ * space is allocated to hold the result and a pointer to that
+ * memory is returned.
+ *
+ * Return: Success: Pointer to NAME
+ *
+ * Failure: NULL, name[0] is set to null.
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * Wednesday, Febuary 9, 2005
+ * Made a copy of original datatype and do sorting and search
+ * on that copy, to protect the original order of members.
+ *-------------------------------------------------------------------------
+ */
+static char *
+H5T_enum_nameof(const H5T_t *dt, const void *value, char *name/*out*/, size_t size)
+{
+ H5T_t *copied_dt = NULL; /* Do sorting in copied datatype */
+ unsigned lt, md = 0, rt; /* Indices for binary search */
+ int cmp = (-1); /* Comparison result */
+ hbool_t alloc_name = FALSE; /* Whether name has been allocated */
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(dt && H5T_ENUM == dt->shared->type);
+ HDassert(value);
+ HDassert(name || 0 == size);
+
+ if(name && size > 0)
+ *name = '\0';
+
+ /* Sanity check */
+ if(dt->shared->u.enumer.nmembs == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "datatype has no members")
+
+ /* Do a binary search over the values to find the correct one. Do sorting
+ * and search on the copied datatype to protect the original order. */
+ if(NULL == (copied_dt = H5T_copy(dt, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy data type")
+ if(H5T__sort_value(copied_dt, NULL) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOMPARE, NULL, "value sort failed")
+
+ lt = 0;
+ rt = copied_dt->shared->u.enumer.nmembs;
+ while(lt < rt) {
+ md = (lt + rt) / 2;
+ cmp = HDmemcmp(value, copied_dt->shared->u.enumer.value + md * copied_dt->shared->size, copied_dt->shared->size);
+ if(cmp < 0)
+ rt = md;
+ else if(cmp > 0)
+ lt = md + 1;
+ else
+ break;
+ } /* end while */
+
+ /* Value was not yet defined. This fixes bug # 774, 2002/06/05 EIP */
+ if(cmp != 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "value is currently not defined")
+
+ /* Save result name */
+ if(!name) {
+ if(NULL == (name = (char *)H5MM_malloc(
+ HDstrlen(copied_dt->shared->u.enumer.name[md]) + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+ alloc_name = TRUE;
+ } /* end if */
+ HDstrncpy(name, copied_dt->shared->u.enumer.name[md], size);
+ if(HDstrlen(copied_dt->shared->u.enumer.name[md]) >= size)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, NULL, "name has been truncated")
+
+ /* Set return value */
+ ret_value = name;
+
+done:
+ if(copied_dt)
+ if(H5T_close(copied_dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, NULL, "unable to close data type");
+ if(!ret_value && alloc_name)
+ H5MM_free(name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_enum_nameof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tenum_valueof
+ *
+ * Purpose: Finds the value that corresponds to the specified NAME f an
+ * enumeration TYPE. The VALUE argument should be at least as
+ * large as the value of H5Tget_size(type) in order to hold the
+ * result.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * Wednesday, Febuary 9, 2005
+ * Made a copy of original datatype and do sorting and search
+ * on that copy, to protect the original order of members.
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tenum_valueof(hid_t type, const char *name, void *value/*out*/)
+{
+ H5T_t *dt;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*sx", type, name, value);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if(H5T_ENUM != dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
+ if(!value)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value buffer")
+
+ if(H5T_enum_valueof(dt, name, value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "valueof query failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Tenum_valueof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_enum_valueof
+ *
+ * Purpose: Finds the value that corresponds the the specified symbol
+ * NAME of an enumeration data type DT and copy it to the VALUE
+ * result buffer. The VALUE should be allocated by the caller to
+ * be large enough for the result.
+ *
+ * Return: Success: Non-negative, value stored in VALUE.
+ *
+ * Failure: Negative, VALUE is undefined.
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ * Raymond Lu
+ * Wednesday, Febuary 9, 2005
+ * Made a copy of original datatype and do sorting and search
+ * on that copy, to protect the original order of members.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_enum_valueof(const H5T_t *dt, const char *name, void *value/*out*/)
+{
+ unsigned lt, md=0, rt; /*indices for binary search */
+ int cmp=(-1); /*comparison result */
+ H5T_t *copied_dt = NULL; /*do sorting in copied datatype */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check args */
+ HDassert(dt && H5T_ENUM==dt->shared->type);
+ HDassert(name && *name);
+ HDassert(value);
+
+ /* Sanity check */
+ if (dt->shared->u.enumer.nmembs == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "datatype has no members")
+
+ /* Do a binary search over the names to find the correct one. Do sorting
+ * and search on the copied datatype to protect the original order. */
+ if (NULL==(copied_dt=H5T_copy(dt, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy data type");
+ if(H5T__sort_name(copied_dt, NULL) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOMPARE, FAIL, "value sort failed")
+
+ lt = 0;
+ rt = copied_dt->shared->u.enumer.nmembs;
+
+ while (lt<rt) {
+ md = (lt+rt)/2;
+ cmp = HDstrcmp(name, copied_dt->shared->u.enumer.name[md]);
+ if (cmp<0) {
+ rt = md;
+ } else if (cmp>0) {
+ lt = md+1;
+ } else {
+ break;
+ }
+ }
+ /* Value was not yet defined. This fixes bug # 774, 2002/06/05 EIP */
+ if (cmp!=0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "string doesn't exist in the enumeration type")
+
+ HDmemcpy(value, copied_dt->shared->u.enumer.value+md*copied_dt->shared->size, copied_dt->shared->size);
+
+done:
+ if(copied_dt)
+ if(H5T_close(copied_dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "unable to close data type")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Tfields.c b/src/H5Tfields.c
new file mode 100644
index 0000000..be62d85
--- /dev/null
+++ b/src/H5Tfields.c
@@ -0,0 +1,486 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains commond functionality for fields in
+ * enumerated & compound datatypes in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5MMprivate.h" /*memory management */
+#include "H5Tpkg.h" /*data-type functions */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_nmembers
+ *
+ * Purpose: Determines how many members TYPE_ID has. The type must be
+ * either a compound datatype or an enumeration datatype.
+ *
+ * Return: Success: Number of members defined in the datatype.
+ *
+ * Failure: Negative
+ *
+ * Errors:
+ *
+ * Programmer: Robb Matzke
+ * Monday, December 8, 1997
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with enumeration datatypes.
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_nmembers(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype to query */
+ int ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("Is", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ if((ret_value = H5T_get_nmembers(dt)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "cannot return member number")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_nmembers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_nmembers
+ *
+ * Purpose: Private function for H5Tget_nmembers. Determines how many
+ * members DTYPE has. The type must be either a compound data
+ * type or an enumeration datatype.
+ *
+ * Return: Success: Number of members defined in the datatype.
+ *
+ * Failure: Negative
+ *
+ * Errors:
+ *
+ * Programmer: Raymond Lu
+ * October 8, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_get_nmembers(const H5T_t *dt)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(dt);
+
+ if(H5T_COMPOUND == dt->shared->type)
+ ret_value = (int)dt->shared->u.compnd.nmembs;
+ else if(H5T_ENUM == dt->shared->type)
+ ret_value = (int)dt->shared->u.enumer.nmembs;
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "operation not supported for type class")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_nmembers() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_name
+ *
+ * Purpose: Returns the name of a member of a compound or enumeration
+ * datatype. Members are stored in no particular order with
+ * numbers 0 through N-1 where N is the value returned by
+ * H5Tget_nmembers().
+ *
+ * Return: Success: Ptr to a string allocated with malloc(). The
+ * caller is responsible for freeing the string.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with enumeration datatypes.
+ *-------------------------------------------------------------------------
+ */
+char *
+H5Tget_member_name(hid_t type_id, unsigned membno)
+{
+ H5T_t *dt = NULL;
+ char *ret_value;
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE2("*s", "iIu", type_id, membno);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a datatype")
+
+ if(NULL == (ret_value = H5T__get_member_name(dt, membno)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to get member name")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__get_member_name
+ *
+ * Purpose: Private function for H5Tget_member_name. Returns the name
+ * of a member of a compound or enumeration datatype. Members
+ * are stored in no particular order with numbers 0 through
+ * N-1 where N is the value returned by H5Tget_nmembers().
+ *
+ * Return: Success: Ptr to a string allocated with malloc(). The
+ * caller is responsible for freeing the string.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Raymond Lu
+ * October 9, 2002
+ *
+ * Modifications:
+ *-------------------------------------------------------------------------
+ */
+char *
+H5T__get_member_name(H5T_t const *dt, unsigned membno)
+{
+ char *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ HDassert(dt);
+
+ switch (dt->shared->type) {
+ case H5T_COMPOUND:
+ if (membno>=dt->shared->u.compnd.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid member number")
+ ret_value = H5MM_xstrdup(dt->shared->u.compnd.memb[membno].name);
+ break;
+
+ case H5T_ENUM:
+ if (membno>=dt->shared->u.enumer.nmembs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid member number")
+ ret_value = H5MM_xstrdup(dt->shared->u.enumer.name[membno]);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "operation not supported for type class")
+ } /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_member_index
+ *
+ * Purpose: Returns the index of a member in a compound or enumeration
+ * datatype by given name.Members are stored in no particular
+ * order with numbers 0 through N-1 where N is the value
+ * returned by H5Tget_nmembers().
+ *
+ * Return: Success: index of the member if exists.
+ * Failure: -1.
+ *
+ * Programmer: Raymond Lu
+ * Thursday, April 4, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_member_index(hid_t type_id, const char *name)
+{
+ H5T_t *dt = NULL;
+ int ret_value=FAIL;
+ unsigned i;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("Is", "i*s", type_id, name);
+
+ /* Check arguments */
+ HDassert(name);
+ if(NULL == (dt = (H5T_t*)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Locate member by name */
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ for(i = 0; i < dt->shared->u.compnd.nmembs; i++)
+ if(!HDstrcmp(dt->shared->u.compnd.memb[i].name, name))
+ HGOTO_DONE((int)i)
+ break;
+ case H5T_ENUM:
+ for(i = 0; i < dt->shared->u.enumer.nmembs; i++)
+ if(!HDstrcmp(dt->shared->u.enumer.name[i], name))
+ HGOTO_DONE((int)i)
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "operation not supported for this type")
+ } /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_member_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__sort_value
+ *
+ * Purpose: Sorts the members of a compound datatype by their offsets;
+ * sorts the members of an enum type by their values. This even
+ * works for locked datatypes since it doesn't change the value
+ * of the type. MAP is an optional parallel integer array which
+ * is also swapped along with members of DT.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__sort_value(const H5T_t *dt, int *map)
+{
+ unsigned nmembs; /* Number of members for datatype */
+ size_t size;
+ hbool_t swapped; /* Whether we've swapped fields */
+ uint8_t tbuf[32];
+ unsigned i, j; /* Local index variables */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(H5T_COMPOUND == dt->shared->type || H5T_ENUM == dt->shared->type);
+
+ /* Use a bubble sort because we can short circuit */
+ if(H5T_COMPOUND == dt->shared->type) {
+ if(H5T_SORT_VALUE != dt->shared->u.compnd.sorted) {
+ dt->shared->u.compnd.sorted = H5T_SORT_VALUE;
+ nmembs = dt->shared->u.compnd.nmembs;
+ for(i = nmembs - 1, swapped = TRUE; i > 0 && swapped; --i) {
+ for(j = 0, swapped = FALSE; j < i; j++) {
+ if(dt->shared->u.compnd.memb[j].offset > dt->shared->u.compnd.memb[j + 1].offset) {
+ H5T_cmemb_t tmp = dt->shared->u.compnd.memb[j];
+ dt->shared->u.compnd.memb[j] = dt->shared->u.compnd.memb[j + 1];
+ dt->shared->u.compnd.memb[j + 1] = tmp;
+ if(map) {
+ int x = map[j];
+
+ map[j] = map[j + 1];
+ map[j + 1] = x;
+ } /* end if */
+ swapped = TRUE;
+ } /* end if */
+ } /* end for */
+ } /* end for */
+#ifndef NDEBUG
+ /* I never trust a sort :-) -RPM */
+ for(i = 0; i < (nmembs - 1); i++)
+ HDassert(dt->shared->u.compnd.memb[i].offset < dt->shared->u.compnd.memb[i + 1].offset);
+#endif
+ } /* end if */
+ } else if(H5T_ENUM == dt->shared->type) {
+ if(H5T_SORT_VALUE != dt->shared->u.enumer.sorted) {
+ dt->shared->u.enumer.sorted = H5T_SORT_VALUE;
+ nmembs = dt->shared->u.enumer.nmembs;
+ size = dt->shared->size;
+ HDassert(size <= sizeof(tbuf));
+ for(i = (nmembs - 1), swapped = TRUE; i > 0 && swapped; --i) {
+ for(j = 0, swapped = FALSE; j < i; j++) {
+ if(HDmemcmp(dt->shared->u.enumer.value + (j * size), dt->shared->u.enumer.value + ((j + 1) * size), size) > 0) {
+ /* Swap names */
+ char *tmp = dt->shared->u.enumer.name[j];
+ dt->shared->u.enumer.name[j] = dt->shared->u.enumer.name[j + 1];
+ dt->shared->u.enumer.name[j + 1] = tmp;
+
+ /* Swap values */
+ HDmemcpy(tbuf, dt->shared->u.enumer.value + (j * size), size);
+ HDmemcpy(dt->shared->u.enumer.value + (j * size),
+ dt->shared->u.enumer.value + ((j + 1) * size), size);
+ HDmemcpy(dt->shared->u.enumer.value + ((j + 1) * size), tbuf, size);
+
+ /* Swap map */
+ if(map) {
+ int x = map[j];
+
+ map[j] = map[j + 1];
+ map[j + 1] = x;
+ } /* end if */
+
+ swapped = TRUE;
+ } /* end if */
+ } /* end for */
+ } /* end for */
+#ifndef NDEBUG
+ /* I never trust a sort :-) -RPM */
+ for(i = 0; i < (nmembs - 1); i++)
+ HDassert(HDmemcmp(dt->shared->u.enumer.value + (i * size), dt->shared->u.enumer.value + ((i + 1) * size), size) < 0);
+#endif
+ } /* end if */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__sort_value() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__sort_name
+ *
+ * Purpose: Sorts members of a compound or enumeration datatype by their
+ * names. This even works for locked datatypes since it doesn't
+ * change the value of the types.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Monday, January 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__sort_name(const H5T_t *dt, int *map)
+{
+ unsigned i, j, nmembs;
+ size_t size;
+ hbool_t swapped;
+ uint8_t tbuf[32];
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(H5T_COMPOUND==dt->shared->type || H5T_ENUM==dt->shared->type);
+
+ /* Use a bubble sort because we can short circuit */
+ if (H5T_COMPOUND==dt->shared->type) {
+ if (H5T_SORT_NAME!=dt->shared->u.compnd.sorted) {
+ dt->shared->u.compnd.sorted = H5T_SORT_NAME;
+ nmembs = dt->shared->u.compnd.nmembs;
+ for (i=nmembs-1, swapped=TRUE; i>0 && swapped; --i) {
+ for (j=0, swapped=FALSE; j<i; j++) {
+ if (HDstrcmp(dt->shared->u.compnd.memb[j].name,
+ dt->shared->u.compnd.memb[j+1].name)>0) {
+ H5T_cmemb_t tmp = dt->shared->u.compnd.memb[j];
+ dt->shared->u.compnd.memb[j] = dt->shared->u.compnd.memb[j+1];
+ dt->shared->u.compnd.memb[j+1] = tmp;
+ swapped = TRUE;
+ if (map) {
+ int x = map[j];
+ map[j] = map[j+1];
+ map[j+1] = x;
+ }
+ }
+ }
+ }
+#ifndef NDEBUG
+ /* I never trust a sort :-) -RPM */
+ for (i=0; i<nmembs-1; i++) {
+ HDassert(HDstrcmp(dt->shared->u.compnd.memb[i].name,
+ dt->shared->u.compnd.memb[i+1].name)<0);
+ }
+#endif
+ }
+ } else if (H5T_ENUM==dt->shared->type) {
+ if (H5T_SORT_NAME!=dt->shared->u.enumer.sorted) {
+ dt->shared->u.enumer.sorted = H5T_SORT_NAME;
+ nmembs = dt->shared->u.enumer.nmembs;
+ size = dt->shared->size;
+ HDassert(size<=sizeof(tbuf));
+ for (i=nmembs-1, swapped=TRUE; i>0 && swapped; --i) {
+ for (j=0, swapped=FALSE; j<i; j++) {
+ if (HDstrcmp(dt->shared->u.enumer.name[j],
+ dt->shared->u.enumer.name[j+1])>0) {
+ /* Swap names */
+ char *tmp = dt->shared->u.enumer.name[j];
+ dt->shared->u.enumer.name[j] = dt->shared->u.enumer.name[j+1];
+ dt->shared->u.enumer.name[j+1] = tmp;
+
+ /* Swap values */
+ HDmemcpy(tbuf, dt->shared->u.enumer.value+j*size, size);
+ HDmemcpy(dt->shared->u.enumer.value+j*size,
+ dt->shared->u.enumer.value+(j+1)*size, size);
+ HDmemcpy(dt->shared->u.enumer.value+(j+1)*size, tbuf, size);
+
+ /* Swap map */
+ if (map) {
+ int x = map[j];
+ map[j] = map[j+1];
+ map[j+1] = x;
+ }
+
+ swapped = TRUE;
+ }
+ }
+ }
+#ifndef NDEBUG
+ /* I never trust a sort :-) -RPM */
+ for (i=0; i<nmembs-1; i++)
+ HDassert(HDstrcmp(dt->shared->u.enumer.name[i], dt->shared->u.enumer.name[i+1])<0);
+#endif
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
diff --git a/src/H5Tfixed.c b/src/H5Tfixed.c
new file mode 100644
index 0000000..bc1d84d
--- /dev/null
+++ b/src/H5Tfixed.c
@@ -0,0 +1,153 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for fixed-point (i.e.
+ * integer) datatypes in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5Tpkg.h" /*data-type functions */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_sign
+ *
+ * Purpose: Retrieves the sign type for an integer type.
+ *
+ * Return: Success: The sign type.
+ *
+ * Failure: H5T_SGN_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived datatypes.
+ *-------------------------------------------------------------------------
+ */
+H5T_sign_t
+H5Tget_sign(hid_t type_id)
+{
+ H5T_t *dt = NULL;
+ H5T_sign_t ret_value;
+
+ FUNC_ENTER_API(H5T_SGN_ERROR)
+ H5TRACE1("Ts", "i", type_id);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_SGN_ERROR, "not an integer datatype")
+
+ ret_value = H5T_get_sign(dt);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_sign
+ *
+ * Purpose: Private function for H5Tget_sign. Retrieves the sign type
+ * for an integer type.
+ *
+ * Return: Success: The sign type.
+ *
+ * Failure: H5T_SGN_ERROR (Negative)
+ *
+ * Programmer: Raymond Lu
+ * October 8, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_sign_t
+H5T_get_sign(H5T_t const *dt)
+{
+ H5T_sign_t ret_value = H5T_SGN_ERROR; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5T_SGN_ERROR)
+
+ HDassert(dt);
+
+ /* Defer to parent */
+ while(dt->shared->parent)
+ dt = dt->shared->parent;
+
+ /* Check args */
+ if (H5T_INTEGER!=dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5T_SGN_ERROR, "operation not defined for datatype class")
+
+ /* Sign */
+ ret_value = dt->shared->u.atomic.u.i.sign;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_sign
+ *
+ * Purpose: Sets the sign property for an integer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_sign(hid_t type_id, H5T_sign_t sign)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTs", type_id, sign);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an integer datatype")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "datatype is read-only")
+ if (sign < H5T_SGN_NONE || sign >= H5T_NSGN)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "illegal sign type")
+ if (H5T_ENUM==dt->shared->type && dt->shared->u.enumer.nmembs>0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not allowed after members are defined")
+ while (dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if (H5T_INTEGER!=dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not defined for datatype class")
+
+ /* Commit */
+ dt->shared->u.atomic.u.i.sign = sign;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
diff --git a/src/H5Tfloat.c b/src/H5Tfloat.c
new file mode 100644
index 0000000..85e8f30
--- /dev/null
+++ b/src/H5Tfloat.c
@@ -0,0 +1,396 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for floating-point
+ * datatypes in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /*generic functions */
+#include "H5Eprivate.h" /*error handling */
+#include "H5Iprivate.h" /*ID functions */
+#include "H5Tpkg.h" /*data-type functions */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_fields
+ *
+ * Purpose: Returns information about the locations of the various bit
+ * fields of a floating point datatype. The field positions
+ * are bit positions in the significant region of the datatype.
+ * Bits are numbered with the least significant bit number zero.
+ *
+ * Any (or even all) of the arguments can be null pointers.
+ *
+ * Return: Success: Non-negative, field locations and sizes are
+ * returned through the arguments.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tget_fields(hid_t type_id, size_t *spos/*out*/, size_t *epos/*out*/,
+size_t *esize/*out*/, size_t *mpos/*out*/, size_t *msize/*out*/)
+{
+ H5T_t *dt; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "ixxxxx", type_id, spos, epos, esize, mpos, msize);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "operation not defined for datatype class")
+
+ /* Get values */
+ if(spos)
+ *spos = dt->shared->u.atomic.u.f.sign;
+ if(epos)
+ *epos = dt->shared->u.atomic.u.f.epos;
+ if(esize)
+ *esize = dt->shared->u.atomic.u.f.esize;
+ if(mpos)
+ *mpos = dt->shared->u.atomic.u.f.mpos;
+ if(msize)
+ *msize = dt->shared->u.atomic.u.f.msize;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_fields() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_fields
+ *
+ * Purpose: Sets the locations and sizes of the various floating point
+ * bit fields. The field positions are bit positions in the
+ * significant region of the datatype. Bits are numbered with
+ * the least significant bit number zero.
+ *
+ * Fields are not allowed to extend beyond the number of bits of
+ * precision, nor are they allowed to overlap with one another.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_fields(hid_t type_id, size_t spos, size_t epos, size_t esize,
+ size_t mpos, size_t msize)
+{
+ H5T_t *dt; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE6("e", "izzzzz", type_id, spos, epos, esize, mpos, msize);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "datatype is read-only")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "operation not defined for datatype class")
+ if(epos + esize > dt->shared->u.atomic.prec)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "exponent bit field size/location is invalid")
+ if(mpos + msize > dt->shared->u.atomic.prec)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "mantissa bit field size/location is invalid")
+ if(spos >= dt->shared->u.atomic.prec)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sign location is not valid")
+
+ /* Check for overlap */
+ if(spos >= epos && spos < epos + esize)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sign bit appears within exponent field")
+ if(spos >= mpos && spos < mpos + msize)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "sign bit appears within mantissa field")
+ if((mpos < epos && mpos + msize > epos) || (epos < mpos && epos + esize > mpos))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "exponent and mantissa fields overlap")
+
+ /* Commit */
+ dt->shared->u.atomic.u.f.sign = spos;
+ dt->shared->u.atomic.u.f.epos = epos;
+ dt->shared->u.atomic.u.f.mpos = mpos;
+ dt->shared->u.atomic.u.f.esize = esize;
+ dt->shared->u.atomic.u.f.msize = msize;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_fields() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_ebias
+ *
+ * Purpose: Retrieves the exponent bias of a floating-point type.
+ *
+ * Return: Success: The bias
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5Tget_ebias(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype */
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(0)
+ H5TRACE1("z", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, 0, "operation not defined for datatype class")
+
+ /* bias */
+ H5_CHECKED_ASSIGN(ret_value, size_t, dt->shared->u.atomic.u.f.ebias, uint64_t);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_ebias() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_ebias
+ *
+ * Purpose: Sets the exponent bias of a floating-point type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_ebias(hid_t type_id, size_t ebias)
+{
+ H5T_t *dt; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", type_id, ebias);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "datatype is read-only")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "operation not defined for datatype class")
+
+ /* Commit */
+ dt->shared->u.atomic.u.f.ebias = ebias;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_ebias() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_norm
+ *
+ * Purpose: Returns the mantisssa normalization of a floating-point data
+ * type.
+ *
+ * Return: Success: Normalization ID
+ *
+ * Failure: H5T_NORM_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_norm_t
+H5Tget_norm(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype */
+ H5T_norm_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5T_NORM_ERROR)
+ H5TRACE1("Tn", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NORM_ERROR, "not a datatype")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, H5T_NORM_ERROR, "operation not defined for datatype class")
+
+ /* norm */
+ ret_value = dt->shared->u.atomic.u.f.norm;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_norm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_norm
+ *
+ * Purpose: Sets the mantissa normalization method for a floating point
+ * datatype.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_norm(hid_t type_id, H5T_norm_t norm)
+{
+ H5T_t *dt; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTn", type_id, norm);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "datatype is read-only")
+ if(norm < H5T_NORM_IMPLIED || norm > H5T_NORM_NONE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "illegal normalization")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "operation not defined for datatype class")
+
+ /* Commit */
+ dt->shared->u.atomic.u.f.norm = norm;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_norm() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_inpad
+ *
+ * Purpose: If any internal bits of a floating point type are unused
+ * (that is, those significant bits which are not part of the
+ * sign, exponent, or mantissa) then they will be filled
+ * according to the value of this property.
+ *
+ * Return: Success: The internal padding type.
+ *
+ * Failure: H5T_PAD_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_pad_t
+H5Tget_inpad(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype */
+ H5T_pad_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5T_PAD_ERROR)
+ H5TRACE1("Tp", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_PAD_ERROR, "not a datatype")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, H5T_PAD_ERROR, "operation not defined for datatype class")
+
+ /* pad */
+ ret_value = dt->shared->u.atomic.u.f.pad;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_inpad() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_inpad
+ *
+ * Purpose: If any internal bits of a floating point type are unused
+ * (that is, those significant bits which are not part of the
+ * sign, exponent, or mantissa) then they will be filled
+ * according to the value of this property.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_inpad(hid_t type_id, H5T_pad_t pad)
+{
+ H5T_t *dt; /* Datatype */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTp", type_id, pad);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "datatype is read-only")
+ if(pad < H5T_PAD_ZERO || pad >= H5T_NPAD)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "illegal internal pad type")
+ while(dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if(H5T_FLOAT != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "operation not defined for datatype class")
+
+ /* Commit */
+ dt->shared->u.atomic.u.f.pad = pad;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_inpad() */
+
diff --git a/src/H5Tmodule.h b/src/H5Tmodule.h
new file mode 100644
index 0000000..d2ab08c
--- /dev/null
+++ b/src/H5Tmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5T package. Including this header means that the source file
+ * is part of the H5T package.
+ */
+#ifndef _H5Tmodule_H
+#define _H5Tmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5T_MODULE
+#define H5_MY_PKG H5T
+#define H5_MY_PKG_ERR H5E_DATATYPE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Tmodule_H */
+
diff --git a/src/H5Tnative.c b/src/H5Tnative.c
new file mode 100644
index 0000000..6304500
--- /dev/null
+++ b/src/H5Tnative.c
@@ -0,0 +1,911 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for querying
+ * a "native" datatype for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Tpkg.h" /* Datatypes */
+
+/* Static local functions */
+static H5T_t *H5T_get_native_type(H5T_t *dt, H5T_direction_t direction,
+ size_t *struct_align, size_t *offset, size_t *comp_size);
+static H5T_t *H5T_get_native_integer(size_t prec, H5T_sign_t sign, H5T_direction_t direction,
+ size_t *struct_align, size_t *offset, size_t *comp_size);
+static H5T_t *H5T_get_native_float(size_t size, H5T_direction_t direction,
+ size_t *struct_align, size_t *offset, size_t *comp_size);
+static H5T_t* H5T_get_native_bitfield(size_t prec, H5T_direction_t direction,
+ size_t *struct_align, size_t *offset, size_t *comp_size);
+static herr_t H5T_cmp_offset(size_t *comp_size, size_t *offset, size_t elem_size,
+ size_t nelems, size_t align, size_t *struct_align);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_native_type
+ *
+ * Purpose: High-level API to return the native type of a datatype.
+ * The native type is chosen by matching the size and class of
+ * querried datatype from the following native premitive
+ * datatypes:
+ * H5T_NATIVE_CHAR H5T_NATIVE_UCHAR
+ * H5T_NATIVE_SHORT H5T_NATIVE_USHORT
+ * H5T_NATIVE_INT H5T_NATIVE_UINT
+ * H5T_NATIVE_LONG H5T_NATIVE_ULONG
+ * H5T_NATIVE_LLONG H5T_NATIVE_ULLONG
+ *
+ * H5T_NATIVE_FLOAT
+ * H5T_NATIVE_DOUBLE
+ * H5T_NATIVE_LDOUBLE
+ *
+ * Compound, array, enum, and VL types all choose among these
+ * types for theire members. Time, Bifield, Opaque, Reference
+ * types are only copy out.
+ *
+ * Return: Success: Returns the native data type if successful.
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * Oct 3, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tget_native_type(hid_t type_id, H5T_direction_t direction)
+{
+ H5T_t *dt; /* Datatype to create native datatype from */
+ H5T_t *new_dt=NULL; /* Datatype for native datatype created */
+ size_t comp_size=0; /* Compound datatype's size */
+ hid_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("i", "iTd", type_id, direction);
+
+ /* check argument */
+ if(NULL==(dt=(H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+
+ if(direction!=H5T_DIR_DEFAULT && direction!=H5T_DIR_ASCEND
+ && direction!=H5T_DIR_DESCEND)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not valid direction value")
+
+ if((new_dt = H5T_get_native_type(dt, direction, NULL, NULL, &comp_size))==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "cannot retrieve native type")
+
+ if((ret_value=H5I_register(H5I_DATATYPE, new_dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register data type")
+
+done:
+ /* Error cleanup */
+ if(ret_value<0) {
+ if(new_dt)
+ if(H5T_close(new_dt)<0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+ } /* end if */
+
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_native_type
+ *
+ * Purpose: Returns the native type of a datatype.
+ *
+ * Return: Success: Returns the native data type if successful.
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * Oct 3, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_t *
+H5T_get_native_type(H5T_t *dtype, H5T_direction_t direction, size_t *struct_align, size_t *offset, size_t *comp_size)
+{
+ H5T_t *dt; /* Datatype to make native */
+ H5T_t *super_type; /* Super type of VL, array and enum datatypes */
+ H5T_t *nat_super_type; /* Native form of VL, array & enum super datatype */
+ H5T_t *new_type = NULL; /* New native datatype */
+ H5T_t *memb_type = NULL; /* Datatype of member */
+ H5T_t **memb_list = NULL; /* List of compound member IDs */
+ size_t *memb_offset = NULL; /* List of member offsets in compound type, including member size and alignment */
+ char **comp_mname = NULL; /* List of member names in compound type */
+ char *memb_name = NULL; /* Enum's member name */
+ void *memb_value = NULL; /* Enum's member value */
+ void *tmp_memb_value = NULL; /* Enum's member value */
+ hsize_t *dims = NULL; /* Dimension sizes for array */
+ H5T_class_t h5_class; /* Class of datatype to make native */
+ size_t size; /* Size of datatype to make native */
+ size_t prec; /* Precision of datatype to make native */
+ int snmemb; /* Number of members in compound & enum types */
+ unsigned nmemb = 0; /* Number of members in compound & enum types */
+ unsigned u; /* Local index variable */
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(dtype);
+
+ if(H5T_NO_CLASS == (h5_class = H5T_get_class(dtype, FALSE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a valid class")
+
+ if(0 == (size = H5T_get_size(dtype)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a valid size")
+
+ switch(h5_class) {
+ case H5T_INTEGER:
+ {
+ H5T_sign_t sign; /* Signedness of integer type */
+
+ if(H5T_SGN_ERROR == (sign = H5T_get_sign(dtype)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a valid signess")
+
+ prec = dtype->shared->u.atomic.prec;
+
+ if(NULL == (ret_value = H5T_get_native_integer(prec, sign, direction, struct_align, offset, comp_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve integer type")
+ } /* end case */
+ break;
+
+ case H5T_FLOAT:
+ if(NULL == (ret_value = H5T_get_native_float(size, direction, struct_align, offset, comp_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve float type")
+
+ break;
+
+ case H5T_STRING:
+ if(NULL == (ret_value = H5T_copy(dtype, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve float type")
+
+ if(H5T_IS_VL_STRING(dtype->shared)) {
+ /* Update size, offset and compound alignment for parent. */
+ if(H5T_cmp_offset(comp_size, offset, sizeof(char *), (size_t)1, H5T_POINTER_COMP_ALIGN_g, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+ } /* end if */
+ else {
+ /* Update size, offset and compound alignment for parent. */
+ if(H5T_cmp_offset(comp_size, offset, sizeof(char), size, H5T_NATIVE_SCHAR_COMP_ALIGN_g, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+ } /* end else */
+ break;
+
+ /* The time type will be supported in the future. Simply return "not supported"
+ * message for now.*/
+ case H5T_TIME:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "time type is not supported yet")
+
+ case H5T_BITFIELD:
+ {
+ prec = dtype->shared->u.atomic.prec;
+
+ if(NULL == (ret_value = H5T_get_native_bitfield(prec, direction, struct_align, offset, comp_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve integer for bitfield type")
+ } /* end case */
+ break;
+
+ case H5T_OPAQUE:
+ if(NULL == (ret_value = H5T_copy(dtype, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve float type")
+
+ /* Update size, offset and compound alignment for parent. */
+ if(H5T_cmp_offset(comp_size, offset, sizeof(char), size, H5T_NATIVE_SCHAR_COMP_ALIGN_g, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+ break;
+
+ case H5T_REFERENCE:
+ {
+ size_t align;
+ size_t ref_size;
+ int not_equal;
+
+ if(NULL == (ret_value = H5T_copy(dtype, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve float type")
+
+ /* Decide if the data type is object or dataset region reference. */
+ if(NULL == (dt = (H5T_t *)H5I_object(H5T_STD_REF_OBJ_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+ not_equal = H5T_cmp(ret_value, dt, FALSE);
+
+ /* Update size, offset and compound alignment for parent. */
+ if(!not_equal) {
+ align = H5T_HOBJREF_COMP_ALIGN_g;
+ ref_size = sizeof(hobj_ref_t);
+ } /* end if */
+ else {
+ align = H5T_HDSETREGREF_COMP_ALIGN_g;
+ ref_size = sizeof(hdset_reg_ref_t);
+ } /* end else */
+
+ if(H5T_cmp_offset(comp_size, offset, ref_size, (size_t)1, align, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+ } /* end case */
+ break;
+
+ case H5T_COMPOUND:
+ {
+ size_t children_size = 0;/* Total size of compound members */
+ size_t children_st_align = 0; /* The max alignment among compound members. This'll be the compound alignment */
+
+ if((snmemb = H5T_get_nmembers(dtype)) <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "compound data type doesn't have any member")
+ H5_CHECKED_ASSIGN(nmemb, unsigned, snmemb, int);
+
+ if(NULL == (memb_list = (H5T_t **)H5MM_calloc(nmemb * sizeof(H5T_t *))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+ if(NULL == (memb_offset = (size_t *)H5MM_calloc(nmemb * sizeof(size_t))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+ if(NULL == (comp_mname = (char **)H5MM_calloc(nmemb * sizeof(char *))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+
+ /* Construct child compound type and retrieve a list of their IDs, offsets, total size, and alignment for compound type. */
+ for(u = 0; u < nmemb; u++) {
+ if(NULL == (memb_type = H5T_get_member_type(dtype, u, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "member type retrieval failed")
+
+ if(NULL == (comp_mname[u] = H5T__get_member_name(dtype, u)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "member type retrieval failed")
+
+ if(NULL == (memb_list[u] = H5T_get_native_type(memb_type, direction, &children_st_align, &(memb_offset[u]), &children_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "member identifier retrieval failed")
+
+ if(H5T_close(memb_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot close datatype")
+ } /* end for */
+
+ /* The alignment for whole compound type */
+ if(children_st_align && children_size % children_st_align)
+ children_size += children_st_align - (children_size % children_st_align);
+
+ /* Construct new compound type based on native type */
+ if(NULL == (new_type = H5T__create(H5T_COMPOUND, children_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot create a compound type")
+
+ /* Insert members for the new compound type */
+ for(u = 0; u < nmemb; u++)
+ if(H5T__insert(new_type, comp_mname[u], memb_offset[u], memb_list[u]) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot insert member to compound datatype")
+
+ /* Update size, offset and compound alignment for parent in the case of
+ * nested compound type. The alignment for a compound type as one field in
+ * a compound type is the biggest compound alignment among all its members.
+ * e.g. in the structure
+ * typedef struct s1 {
+ * char c;
+ * int i;
+ * s2 st;
+ * unsigned long long l;
+ * } s1;
+ * typedef struct s2 {
+ * short c2;
+ * long l2;
+ * long long ll2;
+ * } s2;
+ * The alignment for ST in S1 is the biggest structure alignment of all the
+ * members of S2, which is probably the LL2 of 'long long'. -SLU 2010/4/28
+ */
+ if(H5T_cmp_offset(comp_size, offset, children_size, (size_t)1, children_st_align,
+ struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+ /* Close member data type */
+ for(u = 0; u < nmemb; u++) {
+ if(H5T_close(memb_list[u]) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot close datatype")
+
+ /* Free member names in list */
+ comp_mname[u] = (char *)H5MM_xfree(comp_mname[u]);
+ } /* end for */
+
+ /* Free lists for members */
+ memb_list = (H5T_t **)H5MM_xfree(memb_list);
+ memb_offset = (size_t *)H5MM_xfree(memb_offset);
+ comp_mname = (char **)H5MM_xfree(comp_mname);
+
+ ret_value = new_type;
+ } /* end case */
+ break;
+
+ case H5T_ENUM:
+ {
+ H5T_path_t *tpath; /* Type conversion info */
+ hid_t super_type_id, nat_super_type_id;
+
+ /* Don't need to do anything special for alignment, offset since the ENUM type usually is integer. */
+
+ /* Retrieve base type for enumerated type */
+ if(NULL == (super_type = H5T_get_super(dtype)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to get base type for enumerate type")
+ if(NULL == (nat_super_type = H5T_get_native_type(super_type, direction, struct_align, offset, comp_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "base native type retrieval failed")
+
+ if((super_type_id = H5I_register(H5I_DATATYPE, super_type, FALSE)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot register datatype")
+ if((nat_super_type_id = H5I_register(H5I_DATATYPE, nat_super_type, FALSE)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot register datatype")
+
+ /* Allocate room for the enum values */
+ if(NULL == (tmp_memb_value = H5MM_calloc(H5T_get_size(super_type))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+ if(NULL == (memb_value = H5MM_calloc(H5T_get_size(nat_super_type))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+
+ /* Construct new enum type based on native type */
+ if(NULL == (new_type = H5T__enum_create(nat_super_type)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to create enum type")
+
+ /* Find the conversion function */
+ if(NULL == (tpath = H5T_path_find(super_type, nat_super_type, NULL, NULL, H5AC_noio_dxpl_id, FALSE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to convert between src and dst data types")
+
+ /* Retrieve member info and insert members into new enum type */
+ if((snmemb = H5T_get_nmembers(dtype)) <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "enumerate data type doesn't have any member")
+ H5_CHECKED_ASSIGN(nmemb, unsigned, snmemb, int);
+ for(u = 0; u < nmemb; u++) {
+ if(NULL == (memb_name = H5T__get_member_name(dtype, u)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot get member name")
+ if(H5T__get_member_value(dtype, u, tmp_memb_value) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot get member value")
+ HDmemcpy(memb_value, tmp_memb_value, H5T_get_size(super_type));
+
+ if(H5T_convert(tpath, super_type_id, nat_super_type_id, (size_t)1, (size_t)0, (size_t)0, memb_value, NULL, H5AC_noio_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot get member value")
+
+ if(H5T__enum_insert(new_type, memb_name, memb_value) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot insert member")
+ memb_name = (char *)H5MM_xfree(memb_name);
+ }
+ memb_value = H5MM_xfree(memb_value);
+ tmp_memb_value = H5MM_xfree(tmp_memb_value);
+
+ /* Close base type */
+ if(H5I_dec_app_ref(nat_super_type_id) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot close datatype")
+ /* Close super type */
+ if(H5I_dec_app_ref(super_type_id) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot close datatype")
+
+ ret_value = new_type;
+ } /* end case */
+ break;
+
+ case H5T_ARRAY:
+ {
+ int sarray_rank; /* Array's rank */
+ unsigned array_rank; /* Array's rank */
+ hsize_t nelems = 1;
+ size_t super_offset = 0;
+ size_t super_size = 0;
+ size_t super_align = 0;
+
+ /* Retrieve dimension information for array data type */
+ if((sarray_rank = H5T__get_array_ndims(dtype)) <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot get dimension rank")
+ H5_CHECKED_ASSIGN(array_rank, unsigned, sarray_rank, int);
+ if(NULL == (dims = (hsize_t*)H5MM_malloc(array_rank * sizeof(hsize_t))))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot allocate memory")
+ if(H5T__get_array_dims(dtype, dims) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot get dimension size")
+
+ /* Retrieve base type for array type */
+ if(NULL == (super_type = H5T_get_super(dtype)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to get parent type for array type")
+ if(NULL == (nat_super_type = H5T_get_native_type(super_type, direction, &super_align,
+ &super_offset, &super_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "parent native type retrieval failed")
+
+ /* Close super type */
+ if(H5T_close(super_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CLOSEERROR, NULL, "cannot close datatype")
+
+ /* Create a new array type based on native type */
+ if(NULL == (new_type = H5T__array_create(nat_super_type, array_rank, dims)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to create array type")
+
+ /* Close base type */
+ if(H5T_close(nat_super_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CLOSEERROR, NULL, "cannot close datatype")
+
+ for(u = 0; u < array_rank; u++)
+ nelems *= dims[u];
+ H5_CHECK_OVERFLOW(nelems, hsize_t, size_t);
+ if(H5T_cmp_offset(comp_size, offset, super_size, (size_t)nelems, super_align, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+ dims = (hsize_t *)H5MM_xfree(dims);
+
+ ret_value = new_type;
+ } /* end case */
+ break;
+
+ case H5T_VLEN:
+ {
+ size_t vl_align = 0;
+ size_t vl_size = 0;
+ size_t super_size = 0;
+
+ /* Retrieve base type for array type */
+ if(NULL == (super_type = H5T_get_super(dtype)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to get parent type for VL type")
+ /* Don't need alignment, offset information if this VL isn't a field of compound type. If it
+ * is, go to a few steps below to compute the information directly. */
+ if(NULL == (nat_super_type = H5T_get_native_type(super_type, direction, NULL, NULL, &super_size)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "parent native type retrieval failed")
+
+ /* Close super type */
+ if(H5T_close(super_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CLOSEERROR, NULL, "cannot close datatype")
+
+ /* Create a new array type based on native type */
+ if(NULL == (new_type = H5T__vlen_create(nat_super_type)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unable to create VL type")
+
+ /* Close base type */
+ if(H5T_close(nat_super_type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_CLOSEERROR, NULL, "cannot close datatype")
+
+ /* Update size, offset and compound alignment for parent compound type directly. */
+ vl_align = H5T_HVL_COMP_ALIGN_g;
+ vl_size = sizeof(hvl_t);
+
+ if(H5T_cmp_offset(comp_size, offset, vl_size, (size_t)1, vl_align, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+ ret_value = new_type;
+ } /* end case */
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "data type doesn't match any native type")
+ } /* end switch */
+
+done:
+ /* Error cleanup */
+ if(NULL == ret_value) {
+ if(new_type)
+ if(H5T_close(new_type) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, NULL, "unable to release datatype")
+
+ /* Free lists for members */
+ if(memb_list) {
+ for(u = 0; u < nmemb; u++)
+ if(memb_list[u] && H5T_close(memb_list[u]) < 0)
+ HDONE_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot close datatype")
+
+ memb_list = (H5T_t **)H5MM_xfree(memb_list);
+ } /* end if */
+ memb_offset = (size_t *)H5MM_xfree(memb_offset);
+ if(comp_mname) {
+ for(u = 0; u < nmemb; u++)
+ if(comp_mname[u])
+ H5MM_xfree(comp_mname[u]);
+ comp_mname = (char **)H5MM_xfree(comp_mname);
+ } /* end if */
+ memb_name = (char *)H5MM_xfree(memb_name);
+ memb_value = H5MM_xfree(memb_value);
+ tmp_memb_value = H5MM_xfree(tmp_memb_value);
+ dims = (hsize_t *)H5MM_xfree(dims);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_native_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_native_integer
+ *
+ * Purpose: Returns the native integer type of a datatype.
+ *
+ * Return: Success: Returns the native data type if successful.
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * Oct 3, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_t *
+H5T_get_native_integer(size_t prec, H5T_sign_t sign, H5T_direction_t direction,
+ size_t *struct_align, size_t *offset, size_t *comp_size)
+{
+ H5T_t *dt; /* Appropriate native datatype to copy */
+ hid_t tid = (-1); /* Datatype ID of appropriate native datatype */
+ size_t align = 0; /* Alignment necessary for native datatype */
+ size_t native_size = 0; /* Datatype size of the native type */
+ enum match_type { /* The different kinds of integers we can match */
+ H5T_NATIVE_INT_MATCH_CHAR,
+ H5T_NATIVE_INT_MATCH_SHORT,
+ H5T_NATIVE_INT_MATCH_INT,
+ H5T_NATIVE_INT_MATCH_LONG,
+ H5T_NATIVE_INT_MATCH_LLONG,
+ H5T_NATIVE_INT_MATCH_UNKNOWN
+ } match = H5T_NATIVE_INT_MATCH_UNKNOWN;
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(direction == H5T_DIR_DEFAULT || direction == H5T_DIR_ASCEND) {
+ if(prec <= H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_SCHAR_g))) {
+ match = H5T_NATIVE_INT_MATCH_CHAR;
+ native_size = sizeof(char);
+ } else if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_SHORT_g))) {
+ match = H5T_NATIVE_INT_MATCH_SHORT;
+ native_size = sizeof(short);
+ } else if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_INT_g))) {
+ match = H5T_NATIVE_INT_MATCH_INT;
+ native_size = sizeof(int);
+ } else if(prec <= H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_LONG_g))) {
+ match = H5T_NATIVE_INT_MATCH_LONG;
+ native_size = sizeof(long);
+ } else if(prec <= H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_LLONG_g))) {
+ match = H5T_NATIVE_INT_MATCH_LLONG;
+ native_size = sizeof(long long);
+ } else { /* If no native type matches the querried datatype, simply choose the type of biggest size. */
+ match = H5T_NATIVE_INT_MATCH_LLONG;
+ native_size = sizeof(long long);
+ }
+ } else if(direction == H5T_DIR_DESCEND) {
+ if(prec > H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_LONG_g))) {
+ match = H5T_NATIVE_INT_MATCH_LLONG;
+ native_size = sizeof(long long);
+ } else if(prec > H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_INT_g))) {
+ match = H5T_NATIVE_INT_MATCH_LONG;
+ native_size = sizeof(long);
+ } else if(prec > H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_SHORT_g))) {
+ match = H5T_NATIVE_INT_MATCH_INT;
+ native_size = sizeof(int);
+ } else if(prec > H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_SCHAR_g))) {
+ match = H5T_NATIVE_INT_MATCH_SHORT;
+ native_size = sizeof(short);
+ } else {
+ match = H5T_NATIVE_INT_MATCH_CHAR;
+ native_size = sizeof(char);
+ }
+ }
+
+ /* Set the appropriate native datatype information */
+ switch(match) {
+ case H5T_NATIVE_INT_MATCH_CHAR:
+ if(sign == H5T_SGN_2)
+ tid = H5T_NATIVE_SCHAR;
+ else
+ tid = H5T_NATIVE_UCHAR;
+
+ align = H5T_NATIVE_SCHAR_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_INT_MATCH_SHORT:
+ if(sign == H5T_SGN_2)
+ tid = H5T_NATIVE_SHORT;
+ else
+ tid = H5T_NATIVE_USHORT;
+ align = H5T_NATIVE_SHORT_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_INT_MATCH_INT:
+ if(sign == H5T_SGN_2)
+ tid = H5T_NATIVE_INT;
+ else
+ tid = H5T_NATIVE_UINT;
+
+ align = H5T_NATIVE_INT_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_INT_MATCH_LONG:
+ if(sign == H5T_SGN_2)
+ tid = H5T_NATIVE_LONG;
+ else
+ tid = H5T_NATIVE_ULONG;
+
+ align = H5T_NATIVE_LONG_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_INT_MATCH_LLONG:
+ if(sign == H5T_SGN_2)
+ tid = H5T_NATIVE_LLONG;
+ else
+ tid = H5T_NATIVE_ULLONG;
+
+ align = H5T_NATIVE_LLONG_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_INT_MATCH_UNKNOWN:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "Unknown native integer match")
+ } /* end switch */
+
+ /* Create new native type */
+ HDassert(tid >= 0);
+ if(NULL == (dt = (H5T_t *)H5I_object(tid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+
+ if(NULL == (ret_value = H5T_copy(dt, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot copy type")
+
+ /* compute size and offset of compound type member. */
+ if(H5T_cmp_offset(comp_size, offset, native_size, (size_t)1, align, struct_align) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_native_integer() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_native_float
+ *
+ * Purpose: Returns the native floatt type of a datatype.
+ *
+ * Return: Success: Returns the native data type if successful.
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * Oct 3, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_t*
+H5T_get_native_float(size_t size, H5T_direction_t direction, size_t *struct_align, size_t *offset, size_t *comp_size)
+{
+ H5T_t *dt=NULL; /* Appropriate native datatype to copy */
+ hid_t tid=(-1); /* Datatype ID of appropriate native datatype */
+ size_t align=0; /* Alignment necessary for native datatype */
+ size_t native_size=0; /* Datatype size of the native type */
+ enum match_type { /* The different kinds of floating point types we can match */
+ H5T_NATIVE_FLOAT_MATCH_FLOAT,
+ H5T_NATIVE_FLOAT_MATCH_DOUBLE,
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ H5T_NATIVE_FLOAT_MATCH_LDOUBLE,
+#endif
+ H5T_NATIVE_FLOAT_MATCH_UNKNOWN
+ } match=H5T_NATIVE_FLOAT_MATCH_UNKNOWN;
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(size>0);
+
+ if(direction == H5T_DIR_DEFAULT || direction == H5T_DIR_ASCEND) {
+ if(size<=sizeof(float)) {
+ match=H5T_NATIVE_FLOAT_MATCH_FLOAT;
+ native_size = sizeof(float);
+ }
+ else if(size<=sizeof(double)) {
+ match=H5T_NATIVE_FLOAT_MATCH_DOUBLE;
+ native_size = sizeof(double);
+ }
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ else if(size<=sizeof(long double)) {
+ match=H5T_NATIVE_FLOAT_MATCH_LDOUBLE;
+ native_size = sizeof(long double);
+ }
+#endif
+ else { /* If not match, return the biggest datatype */
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ match=H5T_NATIVE_FLOAT_MATCH_LDOUBLE;
+ native_size = sizeof(long double);
+#else
+ match=H5T_NATIVE_FLOAT_MATCH_DOUBLE;
+ native_size = sizeof(double);
+#endif
+ }
+ } else {
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ if(size>sizeof(double)) {
+ match=H5T_NATIVE_FLOAT_MATCH_LDOUBLE;
+ native_size = sizeof(long double);
+ }
+ else if(size>sizeof(float)) {
+ match=H5T_NATIVE_FLOAT_MATCH_DOUBLE;
+ native_size = sizeof(double);
+ }
+ else {
+ match=H5T_NATIVE_FLOAT_MATCH_FLOAT;
+ native_size = sizeof(float);
+ }
+#else
+ if(size>sizeof(float)) {
+ match=H5T_NATIVE_FLOAT_MATCH_DOUBLE;
+ native_size = sizeof(double);
+ }
+ else {
+ match=H5T_NATIVE_FLOAT_MATCH_FLOAT;
+ native_size = sizeof(float);
+ }
+#endif
+ }
+
+ /* Set the appropriate native floating point information */
+ switch(match) {
+ case H5T_NATIVE_FLOAT_MATCH_FLOAT:
+ tid = H5T_NATIVE_FLOAT;
+ align = H5T_NATIVE_FLOAT_COMP_ALIGN_g;
+ break;
+
+ case H5T_NATIVE_FLOAT_MATCH_DOUBLE:
+ tid = H5T_NATIVE_DOUBLE;
+ align = H5T_NATIVE_DOUBLE_COMP_ALIGN_g;
+ break;
+
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ case H5T_NATIVE_FLOAT_MATCH_LDOUBLE:
+ tid = H5T_NATIVE_LDOUBLE;
+ align = H5T_NATIVE_LDOUBLE_COMP_ALIGN_g;
+ break;
+#endif
+ case H5T_NATIVE_FLOAT_MATCH_UNKNOWN:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "Unknown native floating-point match")
+ } /* end switch */
+
+ /* Create new native type */
+ HDassert(tid>=0);
+ if(NULL==(dt=(H5T_t *)H5I_object(tid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+ if((ret_value=H5T_copy(dt, H5T_COPY_TRANSIENT))==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot retrieve float type")
+
+ /* compute offset of compound type member. */
+ if(H5T_cmp_offset(comp_size, offset, native_size, (size_t)1, align, struct_align)<0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_native_bitfield
+ *
+ * Purpose: Returns the native bitfield type of a datatype. Bitfield
+ * is similar to unsigned integer.
+ *
+ * Return: Success: Returns the native data type if successful.
+ *
+ * Failure: negative
+ *
+ * Programmer: Raymond Lu
+ * 1 December 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5T_t*
+H5T_get_native_bitfield(size_t prec, H5T_direction_t direction, size_t *struct_align,
+ size_t *offset, size_t *comp_size)
+{
+ H5T_t *dt; /* Appropriate native datatype to copy */
+ hid_t tid=(-1); /* Datatype ID of appropriate native datatype */
+ size_t align=0; /* Alignment necessary for native datatype */
+ size_t native_size=0; /* Datatype size of the native type */
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(direction == H5T_DIR_DEFAULT || direction == H5T_DIR_ASCEND) {
+ if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B8_g))) {
+ tid = H5T_NATIVE_B8;
+ native_size = 1;
+ align = H5T_NATIVE_UINT8_ALIGN_g;
+ } else if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B16_g))) {
+ tid = H5T_NATIVE_B16;
+ native_size = 2;
+ align = H5T_NATIVE_UINT16_ALIGN_g;
+ } else if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B32_g))) {
+ tid = H5T_NATIVE_B32;
+ native_size = 4;
+ align = H5T_NATIVE_UINT32_ALIGN_g;
+ } else if(prec<=H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B64_g))) {
+ tid = H5T_NATIVE_B64;
+ native_size = 8;
+ align = H5T_NATIVE_UINT64_ALIGN_g;
+ } else { /* If no native type matches the querried datatype, simply choose the type of biggest size. */
+ tid = H5T_NATIVE_B64;
+ native_size = 8;
+ align = H5T_NATIVE_UINT64_ALIGN_g;
+ }
+ } else if(direction == H5T_DIR_DESCEND) {
+ if(prec>H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B32_g))) {
+ tid = H5T_NATIVE_B64;
+ native_size = 8;
+ align = H5T_NATIVE_UINT64_ALIGN_g;
+ } else if(prec>H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B16_g))) {
+ tid = H5T_NATIVE_B32;
+ native_size = 4;
+ align = H5T_NATIVE_UINT32_ALIGN_g;
+ } else if(prec>H5T_get_precision((H5T_t *)H5I_object(H5T_NATIVE_B8_g))) {
+ tid = H5T_NATIVE_B16;
+ native_size = 2;
+ align = H5T_NATIVE_UINT16_ALIGN_g;
+ } else {
+ tid = H5T_NATIVE_B8;
+ native_size = 1;
+ align = H5T_NATIVE_UINT8_ALIGN_g;
+ }
+ }
+
+ /* Create new native type */
+ HDassert(tid>=0);
+ if(NULL==(dt=(H5T_t *)H5I_object(tid)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+
+ if((ret_value=H5T_copy(dt, H5T_COPY_TRANSIENT))==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot copy type")
+
+ /* compute size and offset of compound type member. */
+ if(H5T_cmp_offset(comp_size, offset, native_size, (size_t)1, align, struct_align)<0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "cannot compute compound offset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_cmp_offset
+ *
+ * Purpose: This function is only for convenience. It computes the
+ * compound type size, offset of the member being considered
+ * and the alignment for the whole compound type.
+ *
+ * Return: Success: Non-negative value.
+ *
+ * Failure: Negative value.
+ *
+ * Programmer: Raymond Lu
+ * December 10, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_cmp_offset(size_t *comp_size, size_t *offset, size_t elem_size,
+ size_t nelems, size_t align, size_t *struct_align)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(offset && comp_size) {
+ if(align>1 && *comp_size%align) {
+ /* Add alignment value */
+ *offset = *comp_size + (align - *comp_size%align);
+ *comp_size += (align - *comp_size%align);
+ } else
+ *offset = *comp_size;
+
+ /* compute size of compound type member. */
+ *comp_size += nelems*elem_size;
+ }
+
+ if(struct_align && *struct_align < align)
+ *struct_align = align;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Toffset.c b/src/H5Toffset.c
new file mode 100644
index 0000000..668e730
--- /dev/null
+++ b/src/H5Toffset.c
@@ -0,0 +1,274 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the datatype offset for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+/* Static local functions */
+static herr_t H5T_set_offset(const H5T_t *dt, size_t offset);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_offset
+ *
+ * Purpose: Retrieves the bit offset of the first significant bit. The
+ * signficant bits of an atomic datum can be offset from the
+ * beginning of the memory for that datum by an amount of
+ * padding. The `offset' property specifies the number of bits
+ * of padding that appear to the "right of" the value. That is,
+ * if we have a 32-bit datum with 16-bits of precision having
+ * the value 0x1122 then it will be layed out in memory as (from
+ * small byte address toward larger byte addresses):
+ *
+ * Big Big Little Little
+ * Endian Endian Endian Endian
+ * offset=0 offset=16 offset=0 offset=16
+ *
+ * 0: [ pad] [0x11] [0x22] [ pad]
+ * 1: [ pad] [0x22] [0x11] [ pad]
+ * 2: [0x11] [ pad] [ pad] [0x22]
+ * 3: [0x22] [ pad] [ pad] [0x11]
+ *
+ * Return: Success: The offset (non-negative)
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Tget_offset(hid_t type_id)
+{
+ H5T_t *dt;
+ int ret_value;
+
+ FUNC_ENTER_API(-1)
+ H5TRACE1("Is", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an atomic data type")
+
+ /* Get offset */
+ if((ret_value = H5T_get_offset(dt)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "cant't get offset for specified datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_offset
+ *
+ * Purpose: Retrieves the bit offset of the first significant bit. The
+ * signficant bits of an atomic datum can be offset from the
+ * beginning of the memory for that datum by an amount of
+ * padding. The `offset' property specifies the number of bits
+ * of padding that appear to the "right of" the value. That is,
+ * if we have a 32-bit datum with 16-bits of precision having
+ * the value 0x1122 then it will be layed out in memory as (from
+ * small byte address toward larger byte addresses):
+ *
+ * Big Big Little Little
+ * Endian Endian Endian Endian
+ * offset=0 offset=16 offset=0 offset=16
+ *
+ * 0: [ pad] [0x11] [0x22] [ pad]
+ * 1: [ pad] [0x22] [0x11] [ pad]
+ * 2: [0x11] [ pad] [ pad] [0x22]
+ * 3: [0x22] [ pad] [ pad] [0x11]
+ *
+ * Return: Success: The offset (non-negative)
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5T_get_offset(const H5T_t *dt)
+{
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_NOAPI(-1)
+
+ /* Defer to parent*/
+ while(dt->shared->parent)
+ dt = dt->shared->parent;
+ if(!H5T_IS_ATOMIC(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for specified data type")
+
+ /* Offset */
+ ret_value = (int)dt->shared->u.atomic.offset;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_offset
+ *
+ * Purpose: Sets the bit offset of the first significant bit. The
+ * signficant bits of an atomic datum can be offset from the
+ * beginning of the memory for that datum by an amount of
+ * padding. The `offset' property specifies the number of bits
+ * of padding that appear to the "right of" the value. That is,
+ * if we have a 32-bit datum with 16-bits of precision having
+ * the value 0x1122 then it will be layed out in memory as (from
+ * small byte address toward larger byte addresses):
+ *
+ * Big Big Little Little
+ * Endian Endian Endian Endian
+ * offset=0 offset=16 offset=0 offset=16
+ *
+ * 0: [ pad] [0x11] [0x22] [ pad]
+ * 1: [ pad] [0x22] [0x11] [ pad]
+ * 2: [0x11] [ pad] [ pad] [0x22]
+ * 3: [0x22] [ pad] [ pad] [0x11]
+ *
+ * If the offset is incremented then the total size is
+ * incremented also if necessary to prevent significant bits of
+ * the value from hanging over the edge of the data type.
+ *
+ * The offset of an H5T_STRING cannot be set to anything but
+ * zero.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Moved real work to a private function.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_offset(hid_t type_id, size_t offset)
+{
+ H5T_t *dt;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", type_id, offset);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an atomic data type")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "data type is read-only")
+ if (H5T_STRING == dt->shared->type && offset != 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offset must be zero for this type")
+ if (H5T_ENUM==dt->shared->type && dt->shared->u.enumer.nmembs>0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not allowed after members are defined")
+ if (H5T_COMPOUND==dt->shared->type || H5T_REFERENCE==dt->shared->type || H5T_OPAQUE==dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for this datatype")
+
+ /* Do the real work */
+ if (H5T_set_offset(dt, offset)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to set offset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_set_offset
+ *
+ * Purpose: Sets the bit offset of the first significant bit. The
+ * signficant bits of an atomic datum can be offset from the
+ * beginning of the memory for that datum by an amount of
+ * padding. The `offset' property specifies the number of bits
+ * of padding that appear to the "right of" the value. That is,
+ * if we have a 32-bit datum with 16-bits of precision having
+ * the value 0x1122 then it will be layed out in memory as (from
+ * small byte address toward larger byte addresses):
+ *
+ * Big Big Little Little
+ * Endian Endian Endian Endian
+ * offset=0 offset=16 offset=0 offset=16
+ *
+ * 0: [ pad] [0x11] [0x22] [ pad]
+ * 1: [ pad] [0x22] [0x11] [ pad]
+ * 2: [0x11] [ pad] [ pad] [0x22]
+ * 3: [0x22] [ pad] [ pad] [0x11]
+ *
+ * If the offset is incremented then the total size is
+ * incremented also if necessary to prevent significant bits of
+ * the value from hanging over the edge of the data type.
+ *
+ * The offset of an H5T_STRING cannot be set to anything but
+ * zero.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_set_offset(const H5T_t *dt, size_t offset)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(H5T_STRING!=dt->shared->type || 0==offset);
+ HDassert(H5T_REFERENCE!=dt->shared->type);
+ HDassert(H5T_OPAQUE!=dt->shared->type);
+ HDassert(H5T_COMPOUND!=dt->shared->type);
+ HDassert(!(H5T_ENUM==dt->shared->type && 0==dt->shared->u.enumer.nmembs));
+
+ if (dt->shared->parent) {
+ if (H5T_set_offset(dt->shared->parent, offset)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to set offset for base type")
+
+ /* Adjust size of datatype appropriately */
+ if(dt->shared->type==H5T_ARRAY)
+ dt->shared->size = dt->shared->parent->shared->size * dt->shared->u.array.nelem;
+ else if(dt->shared->type!=H5T_VLEN)
+ dt->shared->size = dt->shared->parent->shared->size;
+ } else {
+ if (offset+dt->shared->u.atomic.prec > 8*dt->shared->size)
+ dt->shared->size = (offset + dt->shared->u.atomic.prec + 7) / 8;
+ dt->shared->u.atomic.offset = offset;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Toh.c b/src/H5Toh.c
new file mode 100644
index 0000000..01cefe1
--- /dev/null
+++ b/src/H5Toh.c
@@ -0,0 +1,233 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5O_FRIEND /*suppress error about including H5Opkg */
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Opkg.h" /* Object headers */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static htri_t H5O_dtype_isa(H5O_t *loc);
+static hid_t H5O_dtype_open(const H5G_loc_t *obj_loc, hid_t lapl_id,
+ hid_t dxpl_id, hbool_t app_ref);
+static void *H5O_dtype_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc,
+ hid_t dxpl_id);
+static H5O_loc_t *H5O_dtype_get_oloc(hid_t obj_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* This message derives from H5O object class */
+const H5O_obj_class_t H5O_OBJ_DATATYPE[1] = {{
+ H5O_TYPE_NAMED_DATATYPE, /* object type */
+ "named datatype", /* object name, for debugging */
+ NULL, /* get 'copy file' user data */
+ NULL, /* free 'copy file' user data */
+ H5O_dtype_isa, /* "isa" */
+ H5O_dtype_open, /* open an object of this class */
+ H5O_dtype_create, /* create an object of this class */
+ H5O_dtype_get_oloc, /* get an object header location for an object */
+ NULL, /* get the index & heap info for an object */
+ NULL /* flush an opened object of this class */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_isa
+ *
+ * Purpose: Determines if an object has the requisite messages for being
+ * a datatype.
+ *
+ * Return: Success: TRUE if the required data type messages are
+ * present; FALSE otherwise.
+ *
+ * Failure: FAIL if the existence of certain messages
+ * cannot be determined.
+ *
+ * Programmer: Robb Matzke
+ * Monday, November 2, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5O_dtype_isa(struct H5O_t *oh)
+{
+ htri_t ret_value = FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(oh);
+
+ if((ret_value = H5O_msg_exists_oh(oh, H5O_DTYPE_ID)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to read object header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_isa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_open
+ *
+ * Purpose: Open a datatype at a particular location
+ *
+ * Return: Success: Open object identifier
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hid_t
+H5O_dtype_open(const H5G_loc_t *obj_loc, hid_t H5_ATTR_UNUSED lapl_id, hid_t dxpl_id, hbool_t app_ref)
+{
+ H5T_t *type = NULL; /* Datatype opened */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(obj_loc);
+
+ /* Open the datatype */
+ if(NULL == (type = H5T_open(obj_loc, dxpl_id)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open datatype")
+
+ /* Register an ID for the datatype */
+ if((ret_value = H5I_register(H5I_DATATYPE, type, app_ref)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ if(ret_value < 0)
+ if(type && H5T_close(type) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to release datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_create
+ *
+ * Purpose: Create a named datatype in a file
+ *
+ * Return: Success: Pointer to the named datatype data structure
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, April 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_dtype_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ H5T_obj_create_t *crt_info = (H5T_obj_create_t *)_crt_info; /* Named datatype creation parameters */
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(crt_info);
+ HDassert(obj_loc);
+
+ /* Commit the type to the file */
+ if(H5T__commit(f, crt_info->dt, crt_info->tcpl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to commit datatype")
+
+ /* Set up the new named datatype's location */
+ if(NULL == (obj_loc->oloc = H5T_oloc(crt_info->dt)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get object location of named datatype")
+ if(NULL == (obj_loc->path = H5T_nameof(crt_info->dt)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get path of named datatype")
+
+ /* Set the return value */
+ ret_value = crt_info->dt;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_dtype_get_oloc
+ *
+ * Purpose: Retrieve the object header location for an open object
+ *
+ * Return: Success: Pointer to object header location
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Monday, November 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_loc_t *
+H5O_dtype_get_oloc(hid_t obj_id)
+{
+ H5T_t *type; /* Datatype opened */
+ H5O_loc_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get the datatype */
+ if(NULL == (type = (H5T_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADATOM, NULL, "couldn't get object from ID")
+
+ /* Get the datatype's object header location */
+ if(NULL == (ret_value = H5T_oloc(type)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_dtype_get_oloc() */
+
diff --git a/src/H5Topaque.c b/src/H5Topaque.c
new file mode 100644
index 0000000..4e8f1d4
--- /dev/null
+++ b/src/H5Topaque.c
@@ -0,0 +1,115 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for opaque
+ * datatypes in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_tag
+ *
+ * Purpose: Tag an opaque datatype with a unique ASCII identifier.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 20, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_tag(hid_t type_id, const char *tag)
+{
+ H5T_t *dt=NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*s", type_id, tag);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "data type is read-only")
+ while (dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if (H5T_OPAQUE!=dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an opaque data type")
+ if (!tag)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no tag")
+ if (HDstrlen(tag) >= H5T_OPAQUE_TAG_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "tag too long")
+
+ /* Commit */
+ H5MM_xfree(dt->shared->u.opaque.tag);
+ dt->shared->u.opaque.tag = H5MM_strdup(tag);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_tag
+ *
+ * Purpose: Get tha tag associated with an opaque datatype.
+ *
+ * Return: A pointer to an allocated string. The caller should free
+ * the string. NULL is returned for errors.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 20, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5Tget_tag(hid_t type_id)
+{
+ H5T_t *dt=NULL;
+ char *ret_value;
+
+ FUNC_ENTER_API(NULL)
+ H5TRACE1("*s", "i", type_id);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data type")
+ while (dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if (H5T_OPAQUE != dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "operation not defined for data type class")
+
+ /* result */
+ if (NULL==(ret_value=H5MM_strdup(dt->shared->u.opaque.tag)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
diff --git a/src/H5Torder.c b/src/H5Torder.c
new file mode 100644
index 0000000..877316d
--- /dev/null
+++ b/src/H5Torder.c
@@ -0,0 +1,283 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the datatype byte order for the H5T interface.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5T_set_order(H5T_t *dtype, H5T_order_t order);
+
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_order
+ *
+ * Purpose: Returns the byte order of a datatype.
+ *
+ * Return: Success: A byte order constant. If the type is compound
+ * and its members have mixed orders, this function
+ * returns H5T_ORDER_MIXED.
+ * Failure: H5T_ORDER_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_order_t
+H5Tget_order(hid_t type_id)
+{
+ H5T_t *dt; /* Datatype to query */
+ H5T_order_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(H5T_ORDER_ERROR)
+ H5TRACE1("To", "i", type_id);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, H5T_ORDER_ERROR, "not a datatype")
+
+ /* Get order */
+ if(H5T_ORDER_ERROR == (ret_value = H5T_get_order(dt)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, H5T_ORDER_ERROR, "cant't get order for specified datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_order
+ *
+ * Purpose: Returns the byte order of a datatype.
+ *
+ * Return: Success: A byte order constant
+ * Failure: H5T_ORDER_ERROR (Negative)
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_order_t
+H5T_get_order(const H5T_t *dtype)
+{
+ H5T_order_t ret_value = H5T_ORDER_NONE; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5T_ORDER_ERROR)
+
+ /* Defer to parent */
+ while(dtype->shared->parent)
+ dtype = dtype->shared->parent;
+
+ /* Set order for atomic type. */
+ if(H5T_IS_ATOMIC(dtype->shared))
+ ret_value = dtype->shared->u.atomic.order;
+ else {
+ /* Check for compound datatype */
+ if(H5T_COMPOUND == dtype->shared->type) {
+ H5T_order_t memb_order = H5T_ORDER_NONE;
+ int nmemb; /* Number of members in compound & enum types */
+ int i; /* Local index variable */
+
+ /* Retrieve the number of members */
+ if((nmemb = H5T_get_nmembers(dtype)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_ORDER_ERROR, "can't get number of members from compound data type")
+
+ /* Get order for each compound member type. */
+ for(i = 0; i < nmemb; i++) {
+ /* Get order for member */
+ if((memb_order = H5T_get_order(dtype->shared->u.compnd.memb[i].type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, H5T_ORDER_ERROR, "can't get order for compound member")
+
+ /* Ignore the H5T_ORDER_NONE, write down the first non H5T_ORDER_NONE order. */
+ if(memb_order != H5T_ORDER_NONE && ret_value == H5T_ORDER_NONE)
+ ret_value = memb_order;
+
+ /* If the orders are mixed, stop the loop and report it.
+ * (H5T_ORDER_NONE is ignored)
+ */
+ if(memb_order != H5T_ORDER_NONE && ret_value != H5T_ORDER_NONE
+ && memb_order != ret_value) {
+ ret_value = H5T_ORDER_MIXED;
+ break;
+ } /* end if */
+ } /* end for */
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_order
+ *
+ * Purpose: Sets the byte order for a datatype.
+ *
+ * Notes: There are some restrictions on this operation:
+ * 1. For enum type, members shouldn't be defined yet.
+ * 2. H5T_ORDER_NONE only works for reference and fixed-length
+ * string.
+ * 3. For opaque type, the order will be ignored.
+ * 4. For compound type, all restrictions above apply to the
+ * members.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_order(hid_t type_id, H5T_order_t order)
+{
+ H5T_t *dt; /* Datatype to modify */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTo", type_id, order);
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype")
+ if(order < H5T_ORDER_LE || order > H5T_ORDER_NONE || order == H5T_ORDER_MIXED)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "illegal byte order")
+ if(H5T_STATE_TRANSIENT != dt->shared->state)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype is read-only")
+
+ /* Call internal routine to set the order */
+ if(H5T_set_order(dt, order) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "can't set order")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tset_order() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_set_order
+ *
+ * Purpose: Private function to set the byte order for a datatype.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_set_order(H5T_t *dtype, H5T_order_t order)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(H5T_ENUM == dtype->shared->type && dtype->shared->u.enumer.nmembs > 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "operation not allowed after enum members are defined")
+
+ /* For derived data type, defer to parent */
+ while(dtype->shared->parent)
+ dtype = dtype->shared->parent;
+
+ /* Check for setting order on inappropriate datatype */
+ if(order == H5T_ORDER_NONE && !(H5T_REFERENCE == dtype->shared->type ||
+ H5T_OPAQUE == dtype->shared->type || H5T_IS_FIXED_STRING(dtype->shared)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "illegal byte order for type")
+
+ /* For atomic data type */
+ if(H5T_IS_ATOMIC(dtype->shared))
+ dtype->shared->u.atomic.order = order;
+ else {
+ /* Check for compound datatype */
+ if(H5T_COMPOUND == dtype->shared->type) {
+ int nmemb; /* Number of members in type */
+ int i; /* Local index variable */
+
+ /* Retrieve the number of fields in the compound datatype */
+ if((nmemb = H5T_get_nmembers(dtype)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get number of members from compound data type")
+
+ /* Check for uninitialized compound datatype */
+ if(nmemb == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNINITIALIZED, FAIL, "no member is in the compound data type")
+
+ /* Loop through all fields of compound type, setting the order */
+ for(i = 0; i < nmemb; i++)
+ if(H5T_set_order(dtype->shared->u.compnd.memb[i].type, order) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set order for compound member")
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_set_order() */
+
diff --git a/src/H5Tpad.c b/src/H5Tpad.c
new file mode 100644
index 0000000..c96f42a
--- /dev/null
+++ b/src/H5Tpad.c
@@ -0,0 +1,121 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the datatype padding for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_pad
+ *
+ * Purpose: Gets the least significant pad type and the most significant
+ * pad type and returns their values through the LSB and MSB
+ * arguments, either of which may be the null pointer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tget_pad(hid_t type_id, H5T_pad_t *lsb/*out*/, H5T_pad_t *msb/*out*/)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ixx", type_id, lsb, msb);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ while (dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_ATOMIC(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for specified data type")
+
+ /* Get values */
+ if (lsb)
+ *lsb = dt->shared->u.atomic.lsb_pad;
+ if (msb)
+ *msb = dt->shared->u.atomic.msb_pad;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_pad
+ *
+ * Purpose: Sets the LSB and MSB pad types.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works with derived data types.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_pad(hid_t type_id, H5T_pad_t lsb, H5T_pad_t msb)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "iTpTp", type_id, lsb, msb);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "data type is read-only")
+ if (lsb < H5T_PAD_ZERO || lsb >= H5T_NPAD || msb < H5T_PAD_ZERO || msb >= H5T_NPAD)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pad type")
+ if (H5T_ENUM==dt->shared->type && dt->shared->u.enumer.nmembs>0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not allowed after members are defined")
+ while (dt->shared->parent)
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_ATOMIC(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for specified data type")
+
+ /* Commit */
+ dt->shared->u.atomic.lsb_pad = lsb;
+ dt->shared->u.atomic.msb_pad = msb;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
diff --git a/src/H5Tpkg.h b/src/H5Tpkg.h
new file mode 100644
index 0000000..d075127
--- /dev/null
+++ b/src/H5Tpkg.h
@@ -0,0 +1,1323 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, December 8, 1997
+ *
+ * Purpose: This file contains declarations which are visible only within
+ * the H5T package. Source files outside the H5T package should
+ * include H5Tprivate.h instead.
+ */
+#if !(defined H5T_FRIEND || defined H5T_MODULE)
+#error "Do not include this file outside the H5T package!"
+#endif
+
+#ifndef _H5Tpkg_H
+#define _H5Tpkg_H
+
+/*
+ * Define this to enable debugging.
+ */
+#ifdef NDEBUG
+# undef H5T_DEBUG
+#endif
+
+/* Get package's private header */
+#include "H5Tprivate.h"
+
+/* Other private headers needed by this file */
+#include "H5Fprivate.h" /* Files */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Oprivate.h" /* Object headers */
+
+/* Other public headers needed by this file */
+#include "H5Spublic.h" /* Dataspace functions */
+
+/* Length of debugging name buffer */
+#define H5T_NAMELEN 32
+
+/* Macro to ease detecting "complex" datatypes (i.e. those with base types or fields) */
+#define H5T_IS_COMPLEX(t) ((t) == H5T_COMPOUND || (t) == H5T_ENUM || (t) == H5T_VLEN || (t) == H5T_ARRAY)
+
+/* Macro to ease detecting fixed "string" datatypes */
+#define H5T_IS_FIXED_STRING(dt) (H5T_STRING == (dt)->type)
+
+/* Macro to ease detecting variable-length "string" datatypes */
+#define H5T_IS_VL_STRING(dt) (H5T_VLEN == (dt)->type && H5T_VLEN_STRING == (dt)->u.vlen.type)
+
+/* Macro to ease detecting fixed or variable-length "string" datatypes */
+#define H5T_IS_STRING(dt) (H5T_IS_FIXED_STRING(dt) || H5T_IS_VL_STRING(dt))
+
+/* Macro to ease detecting atomic datatypes */
+#define H5T_IS_ATOMIC(dt) (!(H5T_IS_COMPLEX((dt)->type) || (dt)->type == H5T_OPAQUE))
+
+/* Macro to ease retrieving class of shared datatype */
+/* (Externally, a VL string is a string; internally, a VL string is a VL. Lie
+ * to the user if they have a VL string and tell them it's in the string
+ * class)
+ */
+#define H5T_GET_CLASS(shared, internal) ((internal) ? (shared)->type : (H5T_IS_VL_STRING(shared) ? H5T_STRING : (shared)->type))
+
+
+/*
+ * Datatype encoding versions
+ */
+
+/* This is the version to create all datatypes which don't contain
+ * array datatypes (atomic types, compound datatypes without array fields,
+ * vlen sequences of objects which aren't arrays, etc.) or VAX byte-ordered
+ * objects.
+ */
+#define H5O_DTYPE_VERSION_1 1
+
+/* This is the version to create all datatypes which contain H5T_ARRAY
+ * class objects (array definitely, potentially compound & vlen sequences also),
+ * but not VAX byte-ordered objects.
+ */
+#define H5O_DTYPE_VERSION_2 2
+
+/* This is the version to create all datatypes which contain VAX byte-ordered
+ * objects (floating-point types, currently).
+ */
+/* This version also packs compound & enum field names without padding */
+/* This version also encodes the member offset of compound fields more efficiently */
+/* This version also encodes array types more efficiently */
+#define H5O_DTYPE_VERSION_3 3
+
+/* The latest version of the format. Look through the 'encode helper' routine
+ * and 'size' callback for places to change when updating this. */
+#define H5O_DTYPE_VERSION_LATEST H5O_DTYPE_VERSION_3
+
+
+/* Flags for visiting datatype */
+#define H5T_VISIT_COMPLEX_FIRST 0x01 /* Visit complex datatype before visiting member/parent datatypes */
+#define H5T_VISIT_COMPLEX_LAST 0x02 /* Visit complex datatype after visiting member/parent datatypes */
+ /* (setting both flags will mean visiting complex type twice) */
+#define H5T_VISIT_SIMPLE 0x04 /* Visit simple datatypes (at all) */
+ /* (setting H5T_VISIT_SIMPLE and _not_ setting either H5T_VISIT_COMPLEX_FIRST or H5T_VISIT_COMPLEX_LAST will mean visiting _only_ "simple" "leafs" in the "tree" */
+ /* (_not_ setting H5T_VISIT_SIMPLE and setting either H5T_VISIT_COMPLEX_FIRST or H5T_VISIT_COMPLEX_LAST will mean visiting all nodes _except_ "simple" "leafs" in the "tree" */
+
+
+/* Define an internal macro for converting long long to long double. Mac OS 10.4 gives some
+ * incorrect conversions. */
+#if (H5_WANT_DATA_ACCURACY && defined(H5_LLONG_TO_LDOUBLE_CORRECT)) || (!H5_WANT_DATA_ACCURACY)
+#define H5T_CONV_INTERNAL_LLONG_LDOUBLE 1
+#endif
+
+/* Define an internal macro for converting unsigned long long to long double. SGI compilers give
+ * some incorect conversion. 64-bit Solaris does different rounding. Windows Visual Studio 6 does
+ * not support unsigned long long. For FreeBSD(sleipnir), the last 2 bytes of mantissa are lost when
+ * compiler tries to do the conversion. For Cygwin, compiler doesn't do rounding correctly.
+ * Mac OS 10.4 gives some incorrect result. */
+#if (H5_WANT_DATA_ACCURACY && defined(H5_LLONG_TO_LDOUBLE_CORRECT)) || (!H5_WANT_DATA_ACCURACY)
+#define H5T_CONV_INTERNAL_ULLONG_LDOUBLE 1
+#endif
+
+/* Define an internal macro for converting long double to long long. SGI compilers give some incorrect
+ * conversions. Mac OS 10.4 gives incorrect conversions. HP-UX 11.00 compiler generates floating exception.
+ * The hard conversion on Windows .NET 2003 has a bug and gives wrong exception value. */
+#if (H5_WANT_DATA_ACCURACY && defined(H5_LDOUBLE_TO_LLONG_ACCURATE)) || \
+ (!H5_WANT_DATA_ACCURACY)
+#define H5T_CONV_INTERNAL_LDOUBLE_LLONG 1
+#endif
+
+/* Define an internal macro for converting long double to unsigned long long. SGI compilers give some
+ * incorrect conversions. Mac OS 10.4 gives incorrect conversions. HP-UX 11.00 compiler generates
+ * floating exception. */
+#if (H5_WANT_DATA_ACCURACY && defined(H5_LDOUBLE_TO_LLONG_ACCURATE)) || \
+ (!H5_WANT_DATA_ACCURACY)
+#define H5T_CONV_INTERNAL_LDOUBLE_ULLONG 1
+#else
+#define H5T_CONV_INTERNAL_LDOUBLE_ULLONG 0
+#endif
+
+/* Statistics about a conversion function */
+struct H5T_stats_t {
+ unsigned ncalls; /*num calls to conversion function */
+ hsize_t nelmts; /*total data points converted */
+ H5_timer_t timer; /*total time for conversion */
+};
+
+/* The datatype conversion database */
+struct H5T_path_t {
+ char name[H5T_NAMELEN]; /*name for debugging only */
+ H5T_t *src; /*source datatype */
+ H5T_t *dst; /*destination datatype */
+ H5T_conv_t func; /*data conversion function */
+ hbool_t is_hard; /*is it a hard function? */
+ hbool_t is_noop; /*is it the noop conversion? */
+ hbool_t are_compounds; /*are source and dest both compounds?*/
+ H5T_stats_t stats; /*statistics for the conversion */
+ H5T_cdata_t cdata; /*data for this function */
+};
+
+typedef struct H5T_atomic_t {
+ H5T_order_t order; /*byte order */
+ size_t prec; /*precision in bits */
+ size_t offset; /*bit position of lsb of value */
+ H5T_pad_t lsb_pad;/*type of lsb padding */
+ H5T_pad_t msb_pad;/*type of msb padding */
+ union {
+ struct {
+ H5T_sign_t sign; /*type of integer sign */
+ } i; /*integer; integer types */
+
+ struct {
+ size_t sign; /*bit position of sign bit */
+ size_t epos; /*position of lsb of exponent */
+ size_t esize; /*size of exponent in bits */
+ uint64_t ebias; /*exponent bias */
+ size_t mpos; /*position of lsb of mantissa */
+ size_t msize; /*size of mantissa */
+ H5T_norm_t norm; /*normalization */
+ H5T_pad_t pad; /*type of padding for internal bits */
+ } f; /*floating-point types */
+
+ struct {
+ H5T_cset_t cset; /*character set */
+ H5T_str_t pad; /*space or null padding of extra bytes */
+ } s; /*string types */
+
+ struct {
+ H5R_type_t rtype; /*type of reference stored */
+ H5T_loc_t loc; /* Location of data in buffer */
+ } r; /*reference types */
+ } u;
+} H5T_atomic_t;
+
+/* How members are sorted for compound or enum datatypes */
+typedef enum H5T_sort_t {
+ H5T_SORT_NONE = 0, /*not sorted */
+ H5T_SORT_NAME = 1, /*sorted by member name */
+ H5T_SORT_VALUE = 2 /*sorted by memb offset or enum value*/
+} H5T_sort_t;
+
+/* A compound datatype member */
+typedef struct H5T_cmemb_t {
+ char *name; /*name of this member */
+ size_t offset; /*offset from beginning of struct */
+ size_t size; /*size of this member */
+ struct H5T_t *type; /*type of this member */
+} H5T_cmemb_t;
+
+/* A compound datatype */
+typedef struct H5T_compnd_t {
+ unsigned nalloc; /*num entries allocated in MEMB array*/
+ unsigned nmembs; /*number of members defined in struct*/
+ H5T_sort_t sorted; /*how are members sorted? */
+ hbool_t packed; /*are members packed together? */
+ H5T_cmemb_t *memb; /*array of struct members */
+ size_t memb_size; /*total of all member sizes */
+} H5T_compnd_t;
+
+/* An enumeration datatype */
+typedef struct H5T_enum_t {
+ unsigned nalloc; /*num entries allocated */
+ unsigned nmembs; /*number of members defined in enum */
+ H5T_sort_t sorted; /*how are members sorted? */
+ uint8_t *value; /*array of values */
+ char **name; /*array of symbol names */
+} H5T_enum_t;
+
+/* VL function pointers */
+typedef ssize_t (*H5T_vlen_getlenfunc_t)(const void *vl_addr);
+typedef void * (*H5T_vlen_getptrfunc_t)(void *vl_addr);
+typedef htri_t (*H5T_vlen_isnullfunc_t)(const H5F_t *f, void *vl_addr);
+typedef herr_t (*H5T_vlen_readfunc_t)(H5F_t *f, hid_t dxpl_id, void *_vl, void *buf, size_t len);
+typedef herr_t (*H5T_vlen_writefunc_t)(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *buf, void *_bg, size_t seq_len, size_t base_size);
+typedef herr_t (*H5T_vlen_setnullfunc_t)(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg);
+
+/* VL types */
+typedef enum {
+ H5T_VLEN_BADTYPE = -1, /* invalid VL Type */
+ H5T_VLEN_SEQUENCE = 0, /* VL sequence */
+ H5T_VLEN_STRING, /* VL string */
+ H5T_VLEN_MAXTYPE /* highest type (Invalid as true type) */
+} H5T_vlen_type_t;
+
+/* A VL datatype */
+typedef struct H5T_vlen_t {
+ H5T_vlen_type_t type; /* Type of VL data in buffer */
+ H5T_loc_t loc; /* Location of VL data in buffer */
+ H5T_cset_t cset; /* For VL string. character set */
+ H5T_str_t pad; /* For VL string. space or null padding of
+ * extra bytes */
+ H5F_t *f; /* File ID (if VL data is on disk) */
+ H5T_vlen_getptrfunc_t getptr; /* Function to get VL sequence pointer */
+ H5T_vlen_getlenfunc_t getlen; /* Function to get VL sequence size (in element units, not bytes) */
+ H5T_vlen_isnullfunc_t isnull; /* Function to check if VL value is NIL */
+ H5T_vlen_readfunc_t read; /* Function to read VL sequence into buffer */
+ H5T_vlen_writefunc_t write; /* Function to write VL sequence from buffer */
+ H5T_vlen_setnullfunc_t setnull; /* Function to set a VL value to NIL */
+} H5T_vlen_t;
+
+/* An opaque datatype */
+typedef struct H5T_opaque_t {
+ char *tag; /*short type description string */
+} H5T_opaque_t;
+
+/* An array datatype */
+typedef struct H5T_array_t {
+ size_t nelem; /* total number of elements in array */
+ unsigned ndims; /* member dimensionality */
+ size_t dim[H5S_MAX_RANK]; /* size in each dimension */
+} H5T_array_t;
+
+typedef enum H5T_state_t {
+ H5T_STATE_TRANSIENT, /*type is a modifiable, closable transient */
+ H5T_STATE_RDONLY, /*transient, not modifiable, closable */
+ H5T_STATE_IMMUTABLE, /*transient, not modifiable, not closable */
+ H5T_STATE_NAMED, /*named constant, not open */
+ H5T_STATE_OPEN /*named constant, open object header */
+} H5T_state_t;
+
+ /* This struct is shared between all occurances of an open named type */
+typedef struct H5T_shared_t {
+ hsize_t fo_count; /* number of references to this file object */
+ H5T_state_t state; /*current state of the type */
+ H5T_class_t type; /*which class of type is this? */
+ size_t size; /*total size of an instance of this type */
+ unsigned version; /* Version of object header message to encode this object with */
+ hbool_t force_conv;/* Set if this type always needs to be converted and H5T__conv_noop cannot be called */
+ struct H5T_t *parent;/*parent type for derived datatypes */
+ union {
+ H5T_atomic_t atomic; /* an atomic datatype */
+ H5T_compnd_t compnd; /* a compound datatype (struct) */
+ H5T_enum_t enumer; /* an enumeration type (enum) */
+ H5T_vlen_t vlen; /* a variable-length datatype */
+ H5T_opaque_t opaque; /* an opaque datatype */
+ H5T_array_t array; /* an array datatype */
+ } u;
+} H5T_shared_t;
+
+struct H5T_t {
+ H5O_shared_t sh_loc; /* Shared message info (must be first) */
+
+ H5T_shared_t *shared; /* all other information */
+ H5O_loc_t oloc; /* Object location, if the type is a named type */
+ H5G_name_t path; /* group hier. path if the type is a named type */
+};
+
+/* The master list of soft conversion functions */
+typedef struct H5T_soft_t {
+ char name[H5T_NAMELEN]; /*name for debugging only */
+ H5T_class_t src; /*source datatype class */
+ H5T_class_t dst; /*destination datatype class */
+ H5T_conv_t func; /*the conversion function */
+} H5T_soft_t;
+
+/* Bit search direction */
+typedef enum H5T_sdir_t {
+ H5T_BIT_LSB, /*search lsb toward msb */
+ H5T_BIT_MSB /*search msb toward lsb */
+} H5T_sdir_t;
+
+/* Typedef for named datatype creation operation */
+typedef struct {
+ H5T_t *dt; /* Datatype to commit */
+ hid_t tcpl_id; /* Named datatype creation property list */
+} H5T_obj_create_t;
+
+/* Typedef for datatype iteration operations */
+typedef herr_t (*H5T_operator_t)(H5T_t *dt, void *op_data/*in,out*/);
+
+/*
+ * Alignment information for native types. A value of N indicates that the
+ * data must be aligned on an address ADDR such that 0 == ADDR mod N. When
+ * N=1 no alignment is required; N=0 implies that alignment constraints were
+ * not calculated. These alignment info is only for H5Tget_native_type.
+ * These values are used for structure alignment.
+ */
+H5_DLLVAR size_t H5T_NATIVE_SCHAR_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_SHORT_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_LONG_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_LLONG_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_FLOAT_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_DOUBLE_COMP_ALIGN_g;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+H5_DLLVAR size_t H5T_NATIVE_LDOUBLE_COMP_ALIGN_g;
+#endif
+
+H5_DLLVAR size_t H5T_POINTER_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_HVL_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_HOBJREF_COMP_ALIGN_g;
+H5_DLLVAR size_t H5T_HDSETREGREF_COMP_ALIGN_g;
+
+/*
+ * Alignment information for native types. A value of N indicates that the
+ * data must be aligned on an address ADDR such that 0 == ADDR mod N. When
+ * N=1 no alignment is required; N=0 implies that alignment constraints were
+ * not calculated.
+ */
+H5_DLLVAR size_t H5T_NATIVE_SCHAR_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UCHAR_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_SHORT_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_USHORT_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_LONG_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_ULONG_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_LLONG_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_ULLONG_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_FLOAT_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_DOUBLE_ALIGN_g;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+H5_DLLVAR size_t H5T_NATIVE_LDOUBLE_ALIGN_g;
+#endif
+
+/* C9x alignment constraints */
+H5_DLLVAR size_t H5T_NATIVE_INT8_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT8_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_LEAST8_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_LEAST8_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_FAST8_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_FAST8_ALIGN_g;
+
+H5_DLLVAR size_t H5T_NATIVE_INT16_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT16_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_LEAST16_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_LEAST16_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_FAST16_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_FAST16_ALIGN_g;
+
+H5_DLLVAR size_t H5T_NATIVE_INT32_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT32_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_LEAST32_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_LEAST32_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_FAST32_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_FAST32_ALIGN_g;
+
+H5_DLLVAR size_t H5T_NATIVE_INT64_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT64_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_LEAST64_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_LEAST64_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_INT_FAST64_ALIGN_g;
+H5_DLLVAR size_t H5T_NATIVE_UINT_FAST64_ALIGN_g;
+
+/* Useful floating-point values for conversion routines */
+/* (+/- Inf for all floating-point types) */
+H5_DLLVAR float H5T_NATIVE_FLOAT_POS_INF_g;
+H5_DLLVAR float H5T_NATIVE_FLOAT_NEG_INF_g;
+H5_DLLVAR double H5T_NATIVE_DOUBLE_POS_INF_g;
+H5_DLLVAR double H5T_NATIVE_DOUBLE_NEG_INF_g;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+H5_DLLVAR double H5T_NATIVE_LDOUBLE_POS_INF_g;
+H5_DLLVAR double H5T_NATIVE_LDOUBLE_NEG_INF_g;
+#endif
+
+/* Declare extern the free lists for H5T_t's and H5T_shared_t's */
+H5FL_EXTERN(H5T_t);
+H5FL_EXTERN(H5T_shared_t);
+
+/* Common functions */
+H5_DLL herr_t H5T__init_native(void);
+H5_DLL H5T_t *H5T__create(H5T_class_t type, size_t size);
+H5_DLL herr_t H5T__commit(H5F_t *file, H5T_t *type, hid_t tcpl_id, hid_t dxpl_id);
+H5_DLL herr_t H5T__commit_named(const H5G_loc_t *loc, const char *name,
+ H5T_t *dt, hid_t lcpl_id, hid_t tcpl_id, hid_t tapl_id, hid_t dxpl_id);
+H5_DLL H5T_t *H5T__alloc(void);
+H5_DLL herr_t H5T__free(H5T_t *dt);
+H5_DLL herr_t H5T__visit(H5T_t *dt, unsigned visit_flags, H5T_operator_t op,
+ void *op_value);
+H5_DLL herr_t H5T__upgrade_version(H5T_t *dt, unsigned new_version);
+
+/* Conversion functions */
+H5_DLL herr_t H5T__conv_noop(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_order(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_order_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_struct(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_struct_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_enum(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_enum_numeric(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_vlen(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_array(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_i_i(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_f_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_f_i(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_i_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_s_s(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_b_b(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *_buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_schar_uchar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_schar(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_short(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_ushort(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride,
+ size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_short_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_int_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_long_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+H5_DLL herr_t H5T__conv_llong_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_schar_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uchar_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_short_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ushort_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_int_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_uint_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_long_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ulong_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_llong_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_float(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_double(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ullong_ldouble(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_float_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_double_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_schar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_uchar(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_short(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_ushort(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_int(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_uint(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_long(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_ulong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_llong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T__conv_ldouble_ullong(hid_t src_id, hid_t dst_id,
+ H5T_cdata_t *cdata, size_t nelmts,
+ size_t buf_stride, size_t bkg_stride,
+ void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+
+/* Bit twiddling functions */
+H5_DLL void H5T__bit_copy(uint8_t *dst, size_t dst_offset, const uint8_t *src,
+ size_t src_offset, size_t size);
+H5_DLL herr_t H5T__bit_shift(uint8_t *buf, ssize_t shift_dist, size_t offset, size_t size);
+H5_DLL void H5T__bit_set(uint8_t *buf, size_t offset, size_t size,
+ hbool_t value);
+H5_DLL uint64_t H5T__bit_get_d(uint8_t *buf, size_t offset, size_t size);
+H5_DLL void H5T__bit_set_d(uint8_t *buf, size_t offset, size_t size,
+ uint64_t val);
+H5_DLL ssize_t H5T__bit_find(uint8_t *buf, size_t offset, size_t size,
+ H5T_sdir_t direction, hbool_t value);
+H5_DLL hbool_t H5T__bit_inc(uint8_t *buf, size_t start, size_t size);
+H5_DLL hbool_t H5T__bit_dec(uint8_t *buf, size_t start, size_t size);
+H5_DLL void H5T__bit_neg(uint8_t *buf, size_t start, size_t size);
+
+/* VL functions */
+H5_DLL H5T_t * H5T__vlen_create(const H5T_t *base);
+H5_DLL htri_t H5T__vlen_set_loc(const H5T_t *dt, H5F_t *f, H5T_loc_t loc);
+
+/* Array functions */
+H5_DLL H5T_t *H5T__array_create(H5T_t *base, unsigned ndims, const hsize_t dim[/* ndims */]);
+H5_DLL int H5T__get_array_ndims(const H5T_t *dt);
+H5_DLL int H5T__get_array_dims(const H5T_t *dt, hsize_t dims[]);
+
+/* Compound functions */
+H5_DLL herr_t H5T__insert(H5T_t *parent, const char *name, size_t offset,
+ const H5T_t *member);
+H5_DLL size_t H5T__get_member_size(const H5T_t *dt, unsigned membno);
+H5_DLL void H5T__update_packed(const H5T_t *dt);
+H5_DLL H5T_subset_info_t *H5T__conv_struct_subset(const H5T_cdata_t *cdata);
+
+/* Enumerated type functions */
+H5_DLL H5T_t *H5T__enum_create(const H5T_t *parent);
+H5_DLL herr_t H5T__enum_insert(const H5T_t *dt, const char *name, const void *value);
+H5_DLL herr_t H5T__get_member_value(const H5T_t *dt, unsigned membno, void *value);
+
+/* Field functions (for both compound & enumerated types) */
+H5_DLL char *H5T__get_member_name(H5T_t const *dt, unsigned membno);
+H5_DLL herr_t H5T__sort_value(const H5T_t *dt, int *map);
+H5_DLL herr_t H5T__sort_name(const H5T_t *dt, int *map);
+
+/* Debugging functions */
+H5_DLL herr_t H5T__print_stats(H5T_path_t *path, int *nprint/*in,out*/);
+
+#endif /* _H5Tpkg_H */
+
diff --git a/src/H5Tprecis.c b/src/H5Tprecis.c
new file mode 100644
index 0000000..59bac8b
--- /dev/null
+++ b/src/H5Tprecis.c
@@ -0,0 +1,286 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the datatype precision for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+/* Static local functions */
+static herr_t H5T_set_precision(const H5T_t *dt, size_t prec);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_precision
+ *
+ * Purpose: Gets the precision of a datatype. The precision is
+ * the number of significant bits which, unless padding is
+ * present, is 8 times larger than the value returned by
+ * H5Tget_size().
+ *
+ * Return: Success: Number of significant bits
+ *
+ * Failure: 0 (all atomic types have at least one
+ * significant bit)
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5Tget_precision(hid_t type_id)
+{
+ H5T_t *dt;
+ size_t ret_value;
+
+ FUNC_ENTER_API(0)
+ H5TRACE1("z", "i", type_id);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a datatype")
+
+ /* Get precision */
+ if((ret_value = H5T_get_precision(dt)) == 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, 0, "cant't get precision for specified datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tget_precision() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_get_precision
+ *
+ * Purpose: Gets the precision of a datatype. The precision is
+ * the number of significant bits which, unless padding is
+ * present, is 8 times larger than the value returned by
+ * H5Tget_size().
+ *
+ * Return: Success: Number of significant bits
+ * Failure: 0 (all atomic types have at least one
+ * significant bit)
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, October 17, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5T_get_precision(const H5T_t *dt)
+{
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Defer to parent*/
+ while(dt->shared->parent)
+ dt = dt->shared->parent;
+ if(!H5T_IS_ATOMIC(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, 0, "operation not defined for specified datatype")
+
+ /* Precision */
+ ret_value = dt->shared->u.atomic.prec;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_get_precision() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_precision
+ *
+ * Purpose: Sets the precision of a datatype. The precision is
+ * the number of significant bits which, unless padding is
+ * present, is 8 times larger than the value returned by
+ * H5Tget_size().
+ *
+ * If the precision is increased then the offset is decreased
+ * and then the size is increased to insure that significant
+ * bits do not "hang over" the edge of the datatype.
+ *
+ * The precision property of strings is read-only.
+ *
+ * When decreasing the precision of a floating point type, set
+ * the locations and sizes of the sign, mantissa, and exponent
+ * fields first.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Moved real work to a private function.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_precision(hid_t type_id, size_t prec)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iz", type_id, prec);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "datatype is read-only")
+ if (prec == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "precision must be positive")
+ if (H5T_ENUM==dt->shared->type && dt->shared->u.enumer.nmembs>0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "operation not allowed after members are defined")
+ if (H5T_STRING==dt->shared->type)
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "precision for this type is read-only")
+ if (H5T_COMPOUND==dt->shared->type || H5T_OPAQUE==dt->shared->type)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for specified datatype")
+
+ /* Do the work */
+ if (H5T_set_precision(dt, prec)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "unable to set precision")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_set_precision
+ *
+ * Purpose: Sets the precision of a datatype. The precision is
+ * the number of significant bits which, unless padding is
+ * present, is 8 times larger than the value returned by
+ * H5Tget_size().
+ *
+ * If the precision is increased then the offset is decreased
+ * and then the size is increased to insure that significant
+ * bits do not "hang over" the edge of the datatype.
+ *
+ * The precision property of strings is read-only.
+ *
+ * When decreasing the precision of a floating point type, set
+ * the locations and sizes of the sign, mantissa, and exponent
+ * fields first.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, January 7, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_set_precision(const H5T_t *dt, size_t prec)
+{
+ size_t offset, size;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(dt);
+ HDassert(prec>0);
+ HDassert(H5T_OPAQUE!=dt->shared->type);
+ HDassert(H5T_COMPOUND!=dt->shared->type);
+ HDassert(H5T_STRING!=dt->shared->type);
+ HDassert(!(H5T_ENUM==dt->shared->type && 0==dt->shared->u.enumer.nmembs));
+
+ if (dt->shared->parent) {
+ if (H5T_set_precision(dt->shared->parent, prec)<0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "unable to set precision for base type")
+
+ /* Adjust size of datatype appropriately */
+ if(dt->shared->type==H5T_ARRAY)
+ dt->shared->size = dt->shared->parent->shared->size * dt->shared->u.array.nelem;
+ else if(dt->shared->type!=H5T_VLEN)
+ dt->shared->size = dt->shared->parent->shared->size;
+ } else {
+ if (H5T_IS_ATOMIC(dt->shared)) {
+ /* Adjust the offset and size */
+ offset = dt->shared->u.atomic.offset;
+ size = dt->shared->size;
+ if (prec > 8*size)
+ offset = 0;
+ else if (offset+prec > 8 * size)
+ offset = 8 * size - prec;
+ if (prec > 8*size)
+ size = (prec+7) / 8;
+
+ /* Check that things are still kosher */
+ switch (dt->shared->type) {
+ case H5T_INTEGER:
+ case H5T_TIME:
+ case H5T_BITFIELD:
+ /* nothing to check */
+ break;
+
+ case H5T_FLOAT:
+ /*
+ * The sign, mantissa, and exponent fields should be adjusted
+ * first when decreasing the precision of a floating point
+ * type.
+ */
+ if (dt->shared->u.atomic.u.f.sign >= prec+offset ||
+ dt->shared->u.atomic.u.f.epos + dt->shared->u.atomic.u.f.esize > prec+offset ||
+ dt->shared->u.atomic.u.f.mpos + dt->shared->u.atomic.u.f.msize > prec+offset)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "adjust sign, mantissa, and exponent fields first")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_STRING:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "operation not defined for datatype class")
+ } /* end switch */
+
+ /* Commit */
+ dt->shared->size = size;
+ dt->shared->u.atomic.offset = offset;
+ dt->shared->u.atomic.prec = prec;
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not defined for specified datatype")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Tprivate.h b/src/H5Tprivate.h
new file mode 100644
index 0000000..f2da62e
--- /dev/null
+++ b/src/H5Tprivate.h
@@ -0,0 +1,165 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5T module
+ */
+#ifndef _H5Tprivate_H
+#define _H5Tprivate_H
+
+/* Get package's public header */
+#include "H5Tpublic.h"
+
+/* Other public headers needed by this file */
+#include "H5MMpublic.h" /* Memory management */
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Gprivate.h" /* Groups */
+#include "H5Rprivate.h" /* References */
+
+/* Macro for size of temporary buffers to contain a single element */
+#define H5T_ELEM_BUF_SIZE 256
+
+/* If the module using this macro is allowed access to the private variables, access them directly */
+#ifdef H5T_MODULE
+#define H5T_GET_SIZE(T) ((T)->shared->size)
+#define H5T_GET_SHARED(T) ((T)->shared)
+#define H5T_GET_MEMBER_OFFSET(T, I) ((T)->u.compnd.memb[I].offset)
+#define H5T_GET_MEMBER_SIZE(T, I) ((T)->u.compnd.memb[I].shared->size)
+#else /* H5T_MODULE */
+#define H5T_GET_SIZE(T) (H5T_get_size(T))
+#define H5T_GET_SHARED(T) (H5T_get_shared(T))
+#define H5T_GET_MEMBER_OFFSET(T, I) (H5T_get_member_offset((T), (I)))
+#define H5T_GET_MEMBER_SIZE(T, I) (H5T_get_member_size((T), (I)))
+#endif /* H5T_MODULE */
+
+/* Forward references of package typedefs (declared in H5Tpkg.h) */
+typedef struct H5T_t H5T_t;
+typedef struct H5T_stats_t H5T_stats_t;
+typedef struct H5T_path_t H5T_path_t;
+
+/* How to copy a datatype */
+typedef enum H5T_copy_t {
+ H5T_COPY_TRANSIENT,
+ H5T_COPY_ALL,
+ H5T_COPY_REOPEN
+} H5T_copy_t;
+
+/* Location of datatype information */
+typedef enum {
+ H5T_LOC_BADLOC = 0, /* invalid datatype location */
+ H5T_LOC_MEMORY, /* data stored in memory */
+ H5T_LOC_DISK, /* data stored on disk */
+ H5T_LOC_MAXLOC /* highest value (Invalid as true value) */
+} H5T_loc_t;
+
+/* VL allocation information */
+typedef struct {
+ H5MM_allocate_t alloc_func; /* Allocation function */
+ void *alloc_info; /* Allocation information */
+ H5MM_free_t free_func; /* Free function */
+ void *free_info; /* Free information */
+} H5T_vlen_alloc_info_t;
+
+/* Structure for conversion callback property */
+typedef struct H5T_conv_cb_t {
+ H5T_conv_except_func_t func;
+ void* user_data;
+} H5T_conv_cb_t;
+
+/* Values for the optimization of compound data reading and writing. They indicate
+ * whether the fields of the source and destination are subset of each other and
+ * there is no conversion needed.
+ */
+typedef enum {
+ H5T_SUBSET_BADVALUE = -1, /* Invalid value */
+ H5T_SUBSET_FALSE = 0, /* Source and destination aren't subset of each other */
+ H5T_SUBSET_SRC, /* Source is the subset of dest and no conversion is needed */
+ H5T_SUBSET_DST, /* Dest is the subset of source and no conversion is needed */
+ H5T_SUBSET_CAP /* Must be the last value */
+} H5T_subset_t;
+
+typedef struct H5T_subset_info_t {
+ H5T_subset_t subset; /* See above */
+ size_t copy_size; /* Size in bytes, to copy for each element */
+} H5T_subset_info_t;
+
+/* Forward declarations for prototype arguments */
+struct H5O_t;
+
+/* The native endianess of the platform */
+H5_DLLVAR H5T_order_t H5T_native_order_g;
+
+/* Private functions */
+H5_DLL herr_t H5T_init(void);
+H5_DLL H5T_t *H5T_copy(H5T_t *old_dt, H5T_copy_t method);
+H5_DLL herr_t H5T_lock(H5T_t *dt, hbool_t immutable);
+H5_DLL herr_t H5T_close(H5T_t *dt);
+H5_DLL H5T_t *H5T_get_super(const H5T_t *dt);
+H5_DLL H5T_class_t H5T_get_class(const H5T_t *dt, htri_t internal);
+H5_DLL htri_t H5T_detect_class(const H5T_t *dt, H5T_class_t cls, hbool_t from_api);
+H5_DLL size_t H5T_get_size(const H5T_t *dt);
+H5_DLL int H5T_cmp(const H5T_t *dt1, const H5T_t *dt2, hbool_t superset);
+H5_DLL herr_t H5T_encode(H5T_t *obj, unsigned char *buf, size_t *nalloc);
+H5_DLL H5T_t *H5T_decode(const unsigned char *buf);
+H5_DLL herr_t H5T_debug(const H5T_t *dt, FILE * stream);
+H5_DLL struct H5O_loc_t *H5T_oloc(H5T_t *dt);
+H5_DLL H5G_name_t *H5T_nameof(H5T_t *dt);
+H5_DLL htri_t H5T_is_immutable(const H5T_t *dt);
+H5_DLL htri_t H5T_is_named(const H5T_t *dt);
+H5_DLL herr_t H5T_convert_committed_datatype(H5T_t *dt, H5F_t *f);
+H5_DLL htri_t H5T_is_relocatable(const H5T_t *dt);
+H5_DLL H5T_path_t *H5T_path_find(const H5T_t *src, const H5T_t *dst,
+ const char *name, H5T_conv_t func, hid_t dxpl_id, hbool_t is_api);
+H5_DLL hbool_t H5T_path_noop(const H5T_path_t *p);
+H5_DLL H5T_bkg_t H5T_path_bkg(const H5T_path_t *p);
+H5_DLL H5T_subset_info_t *H5T_path_compound_subset(const H5T_path_t *p);
+H5_DLL herr_t H5T_convert(H5T_path_t *tpath, hid_t src_id, hid_t dst_id,
+ size_t nelmts, size_t buf_stride, size_t bkg_stride, void *buf, void *bkg,
+ hid_t dset_xfer_plist);
+H5_DLL herr_t H5T_vlen_reclaim(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, void *_op_data);
+H5_DLL herr_t H5T_vlen_reclaim_elmt(void *elem, H5T_t *dt, hid_t dxpl_id);
+H5_DLL herr_t H5T_vlen_get_alloc_info(hid_t dxpl_id, H5T_vlen_alloc_info_t **vl_alloc_info);
+H5_DLL htri_t H5T_set_loc(H5T_t *dt, H5F_t *f, H5T_loc_t loc);
+H5_DLL htri_t H5T_is_sensible(const H5T_t *dt);
+H5_DLL uint32_t H5T_hash(H5F_t * file, const H5T_t *dt);
+H5_DLL herr_t H5T_set_latest_version(H5T_t *dt);
+H5_DLL herr_t H5T_patch_file(H5T_t *dt, H5F_t *f);
+H5_DLL herr_t H5T_patch_vlen_file(H5T_t *dt, H5F_t *f);
+H5_DLL htri_t H5T_is_variable_str(const H5T_t *dt);
+
+/* Reference specific functions */
+H5_DLL H5R_type_t H5T_get_ref_type(const H5T_t *dt);
+
+/* Operations on named datatypes */
+H5_DLL H5T_t *H5T_open(const H5G_loc_t *loc, hid_t dxpl_id);
+H5_DLL htri_t H5T_committed(const H5T_t *type);
+H5_DLL int H5T_link(const H5T_t *type, int adjust, hid_t dxpl_id);
+H5_DLL herr_t H5T_update_shared(H5T_t *type);
+
+/* Field functions (for both compound & enumerated types) */
+H5_DLL int H5T_get_nmembers(const H5T_t *dt);
+H5_DLL H5T_t *H5T_get_member_type(const H5T_t *dt, unsigned membno, H5T_copy_t method);
+H5_DLL size_t H5T_get_member_offset(const H5T_t *dt, unsigned membno);
+
+/* Atomic functions */
+H5_DLL H5T_order_t H5T_get_order(const H5T_t *dt);
+H5_DLL size_t H5T_get_precision(const H5T_t *dt);
+H5_DLL int H5T_get_offset(const H5T_t *dt);
+
+/* Fixed-point functions */
+H5_DLL H5T_sign_t H5T_get_sign(H5T_t const *dt);
+
+#endif /* _H5Tprivate_H */
+
diff --git a/src/H5Tpublic.h b/src/H5Tpublic.h
new file mode 100644
index 0000000..fc3e4ee
--- /dev/null
+++ b/src/H5Tpublic.h
@@ -0,0 +1,621 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the H5T module.
+ */
+#ifndef _H5Tpublic_H
+#define _H5Tpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+#include "H5Ipublic.h"
+
+#define HOFFSET(S,M) (offsetof(S,M))
+
+/* These are the various classes of datatypes */
+/* If this goes over 16 types (0-15), the file format will need to change) */
+typedef enum H5T_class_t {
+ H5T_NO_CLASS = -1, /*error */
+ H5T_INTEGER = 0, /*integer types */
+ H5T_FLOAT = 1, /*floating-point types */
+ H5T_TIME = 2, /*date and time types */
+ H5T_STRING = 3, /*character string types */
+ H5T_BITFIELD = 4, /*bit field types */
+ H5T_OPAQUE = 5, /*opaque types */
+ H5T_COMPOUND = 6, /*compound types */
+ H5T_REFERENCE = 7, /*reference types */
+ H5T_ENUM = 8, /*enumeration types */
+ H5T_VLEN = 9, /*Variable-Length types */
+ H5T_ARRAY = 10, /*Array types */
+
+ H5T_NCLASSES /*this must be last */
+} H5T_class_t;
+
+/* Byte orders */
+typedef enum H5T_order_t {
+ H5T_ORDER_ERROR = -1, /*error */
+ H5T_ORDER_LE = 0, /*little endian */
+ H5T_ORDER_BE = 1, /*bit endian */
+ H5T_ORDER_VAX = 2, /*VAX mixed endian */
+ H5T_ORDER_MIXED = 3, /*Compound type with mixed member orders */
+ H5T_ORDER_NONE = 4 /*no particular order (strings, bits,..) */
+ /*H5T_ORDER_NONE must be last */
+} H5T_order_t;
+
+/* Types of integer sign schemes */
+typedef enum H5T_sign_t {
+ H5T_SGN_ERROR = -1, /*error */
+ H5T_SGN_NONE = 0, /*this is an unsigned type */
+ H5T_SGN_2 = 1, /*two's complement */
+
+ H5T_NSGN = 2 /*this must be last! */
+} H5T_sign_t;
+
+/* Floating-point normalization schemes */
+typedef enum H5T_norm_t {
+ H5T_NORM_ERROR = -1, /*error */
+ H5T_NORM_IMPLIED = 0, /*msb of mantissa isn't stored, always 1 */
+ H5T_NORM_MSBSET = 1, /*msb of mantissa is always 1 */
+ H5T_NORM_NONE = 2 /*not normalized */
+ /*H5T_NORM_NONE must be last */
+} H5T_norm_t;
+
+/*
+ * Character set to use for text strings. Do not change these values since
+ * they appear in HDF5 files!
+ */
+typedef enum H5T_cset_t {
+ H5T_CSET_ERROR = -1, /*error */
+ H5T_CSET_ASCII = 0, /*US ASCII */
+ H5T_CSET_UTF8 = 1, /*UTF-8 Unicode encoding */
+ H5T_CSET_RESERVED_2 = 2, /*reserved for later use */
+ H5T_CSET_RESERVED_3 = 3, /*reserved for later use */
+ H5T_CSET_RESERVED_4 = 4, /*reserved for later use */
+ H5T_CSET_RESERVED_5 = 5, /*reserved for later use */
+ H5T_CSET_RESERVED_6 = 6, /*reserved for later use */
+ H5T_CSET_RESERVED_7 = 7, /*reserved for later use */
+ H5T_CSET_RESERVED_8 = 8, /*reserved for later use */
+ H5T_CSET_RESERVED_9 = 9, /*reserved for later use */
+ H5T_CSET_RESERVED_10 = 10, /*reserved for later use */
+ H5T_CSET_RESERVED_11 = 11, /*reserved for later use */
+ H5T_CSET_RESERVED_12 = 12, /*reserved for later use */
+ H5T_CSET_RESERVED_13 = 13, /*reserved for later use */
+ H5T_CSET_RESERVED_14 = 14, /*reserved for later use */
+ H5T_CSET_RESERVED_15 = 15 /*reserved for later use */
+} H5T_cset_t;
+#define H5T_NCSET H5T_CSET_RESERVED_2 /*Number of character sets actually defined */
+
+/*
+ * Type of padding to use in character strings. Do not change these values
+ * since they appear in HDF5 files!
+ */
+typedef enum H5T_str_t {
+ H5T_STR_ERROR = -1, /*error */
+ H5T_STR_NULLTERM = 0, /*null terminate like in C */
+ H5T_STR_NULLPAD = 1, /*pad with nulls */
+ H5T_STR_SPACEPAD = 2, /*pad with spaces like in Fortran */
+ H5T_STR_RESERVED_3 = 3, /*reserved for later use */
+ H5T_STR_RESERVED_4 = 4, /*reserved for later use */
+ H5T_STR_RESERVED_5 = 5, /*reserved for later use */
+ H5T_STR_RESERVED_6 = 6, /*reserved for later use */
+ H5T_STR_RESERVED_7 = 7, /*reserved for later use */
+ H5T_STR_RESERVED_8 = 8, /*reserved for later use */
+ H5T_STR_RESERVED_9 = 9, /*reserved for later use */
+ H5T_STR_RESERVED_10 = 10, /*reserved for later use */
+ H5T_STR_RESERVED_11 = 11, /*reserved for later use */
+ H5T_STR_RESERVED_12 = 12, /*reserved for later use */
+ H5T_STR_RESERVED_13 = 13, /*reserved for later use */
+ H5T_STR_RESERVED_14 = 14, /*reserved for later use */
+ H5T_STR_RESERVED_15 = 15 /*reserved for later use */
+} H5T_str_t;
+#define H5T_NSTR H5T_STR_RESERVED_3 /*num H5T_str_t types actually defined */
+
+/* Type of padding to use in other atomic types */
+typedef enum H5T_pad_t {
+ H5T_PAD_ERROR = -1, /*error */
+ H5T_PAD_ZERO = 0, /*always set to zero */
+ H5T_PAD_ONE = 1, /*always set to one */
+ H5T_PAD_BACKGROUND = 2, /*set to background value */
+
+ H5T_NPAD = 3 /*THIS MUST BE LAST */
+} H5T_pad_t;
+
+/* Commands sent to conversion functions */
+typedef enum H5T_cmd_t {
+ H5T_CONV_INIT = 0, /*query and/or initialize private data */
+ H5T_CONV_CONV = 1, /*convert data from source to dest datatype */
+ H5T_CONV_FREE = 2 /*function is being removed from path */
+} H5T_cmd_t;
+
+/* How is the `bkg' buffer used by the conversion function? */
+typedef enum H5T_bkg_t {
+ H5T_BKG_NO = 0, /*background buffer is not needed, send NULL */
+ H5T_BKG_TEMP = 1, /*bkg buffer used as temp storage only */
+ H5T_BKG_YES = 2 /*init bkg buf with data before conversion */
+} H5T_bkg_t;
+
+/* Type conversion client data */
+typedef struct H5T_cdata_t {
+ H5T_cmd_t command;/*what should the conversion function do? */
+ H5T_bkg_t need_bkg;/*is the background buffer needed? */
+ hbool_t recalc; /*recalculate private data */
+ void *priv; /*private data */
+} H5T_cdata_t;
+
+/* Conversion function persistence */
+typedef enum H5T_pers_t {
+ H5T_PERS_DONTCARE = -1, /*wild card */
+ H5T_PERS_HARD = 0, /*hard conversion function */
+ H5T_PERS_SOFT = 1 /*soft conversion function */
+} H5T_pers_t;
+
+/* The order to retrieve atomic native datatype */
+typedef enum H5T_direction_t {
+ H5T_DIR_DEFAULT = 0, /*default direction is inscendent */
+ H5T_DIR_ASCEND = 1, /*in inscendent order */
+ H5T_DIR_DESCEND = 2 /*in descendent order */
+} H5T_direction_t;
+
+/* The exception type passed into the conversion callback function */
+typedef enum H5T_conv_except_t {
+ H5T_CONV_EXCEPT_RANGE_HI = 0, /*source value is greater than destination's range */
+ H5T_CONV_EXCEPT_RANGE_LOW = 1, /*source value is less than destination's range */
+ H5T_CONV_EXCEPT_PRECISION = 2, /*source value loses precision in destination */
+ H5T_CONV_EXCEPT_TRUNCATE = 3, /*source value is truncated in destination */
+ H5T_CONV_EXCEPT_PINF = 4, /*source value is positive infinity(floating number) */
+ H5T_CONV_EXCEPT_NINF = 5, /*source value is negative infinity(floating number) */
+ H5T_CONV_EXCEPT_NAN = 6 /*source value is NaN(floating number) */
+} H5T_conv_except_t;
+
+/* The return value from conversion callback function H5T_conv_except_func_t */
+typedef enum H5T_conv_ret_t {
+ H5T_CONV_ABORT = -1, /*abort conversion */
+ H5T_CONV_UNHANDLED = 0, /*callback function failed to handle the exception */
+ H5T_CONV_HANDLED = 1 /*callback function handled the exception successfully */
+} H5T_conv_ret_t;
+
+/* Variable Length Datatype struct in memory */
+/* (This is only used for VL sequences, not VL strings, which are stored in char *'s) */
+typedef struct {
+ size_t len; /* Length of VL data (in base type units) */
+ void *p; /* Pointer to VL data */
+} hvl_t;
+
+/* Variable Length String information */
+#define H5T_VARIABLE ((size_t)(-1)) /* Indicate that a string is variable length (null-terminated in C, instead of fixed length) */
+
+/* Opaque information */
+#define H5T_OPAQUE_TAG_MAX 256 /* Maximum length of an opaque tag */
+ /* This could be raised without too much difficulty */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* All datatype conversion functions are... */
+typedef herr_t (*H5T_conv_t) (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
+ size_t nelmts, size_t buf_stride, size_t bkg_stride, void *buf,
+ void *bkg, hid_t dset_xfer_plist);
+
+/* Exception handler. If an exception like overflow happenes during conversion,
+ * this function is called if it's registered through H5Pset_type_conv_cb.
+ */
+typedef H5T_conv_ret_t (*H5T_conv_except_func_t)(H5T_conv_except_t except_type,
+ hid_t src_id, hid_t dst_id, void *src_buf, void *dst_buf, void *user_data);
+
+/* When this header is included from a private header, don't make calls to H5open() */
+#undef H5OPEN
+#ifndef _H5private_H
+#define H5OPEN H5open(),
+#else /* _H5private_H */
+#define H5OPEN
+#endif /* _H5private_H */
+
+/*
+ * The IEEE floating point types in various byte orders.
+ */
+#define H5T_IEEE_F32BE (H5OPEN H5T_IEEE_F32BE_g)
+#define H5T_IEEE_F32LE (H5OPEN H5T_IEEE_F32LE_g)
+#define H5T_IEEE_F64BE (H5OPEN H5T_IEEE_F64BE_g)
+#define H5T_IEEE_F64LE (H5OPEN H5T_IEEE_F64LE_g)
+H5_DLLVAR hid_t H5T_IEEE_F32BE_g;
+H5_DLLVAR hid_t H5T_IEEE_F32LE_g;
+H5_DLLVAR hid_t H5T_IEEE_F64BE_g;
+H5_DLLVAR hid_t H5T_IEEE_F64LE_g;
+
+/*
+ * These are "standard" types. For instance, signed (2's complement) and
+ * unsigned integers of various sizes and byte orders.
+ */
+#define H5T_STD_I8BE (H5OPEN H5T_STD_I8BE_g)
+#define H5T_STD_I8LE (H5OPEN H5T_STD_I8LE_g)
+#define H5T_STD_I16BE (H5OPEN H5T_STD_I16BE_g)
+#define H5T_STD_I16LE (H5OPEN H5T_STD_I16LE_g)
+#define H5T_STD_I32BE (H5OPEN H5T_STD_I32BE_g)
+#define H5T_STD_I32LE (H5OPEN H5T_STD_I32LE_g)
+#define H5T_STD_I64BE (H5OPEN H5T_STD_I64BE_g)
+#define H5T_STD_I64LE (H5OPEN H5T_STD_I64LE_g)
+#define H5T_STD_U8BE (H5OPEN H5T_STD_U8BE_g)
+#define H5T_STD_U8LE (H5OPEN H5T_STD_U8LE_g)
+#define H5T_STD_U16BE (H5OPEN H5T_STD_U16BE_g)
+#define H5T_STD_U16LE (H5OPEN H5T_STD_U16LE_g)
+#define H5T_STD_U32BE (H5OPEN H5T_STD_U32BE_g)
+#define H5T_STD_U32LE (H5OPEN H5T_STD_U32LE_g)
+#define H5T_STD_U64BE (H5OPEN H5T_STD_U64BE_g)
+#define H5T_STD_U64LE (H5OPEN H5T_STD_U64LE_g)
+#define H5T_STD_B8BE (H5OPEN H5T_STD_B8BE_g)
+#define H5T_STD_B8LE (H5OPEN H5T_STD_B8LE_g)
+#define H5T_STD_B16BE (H5OPEN H5T_STD_B16BE_g)
+#define H5T_STD_B16LE (H5OPEN H5T_STD_B16LE_g)
+#define H5T_STD_B32BE (H5OPEN H5T_STD_B32BE_g)
+#define H5T_STD_B32LE (H5OPEN H5T_STD_B32LE_g)
+#define H5T_STD_B64BE (H5OPEN H5T_STD_B64BE_g)
+#define H5T_STD_B64LE (H5OPEN H5T_STD_B64LE_g)
+#define H5T_STD_REF_OBJ (H5OPEN H5T_STD_REF_OBJ_g)
+#define H5T_STD_REF_DSETREG (H5OPEN H5T_STD_REF_DSETREG_g)
+H5_DLLVAR hid_t H5T_STD_I8BE_g;
+H5_DLLVAR hid_t H5T_STD_I8LE_g;
+H5_DLLVAR hid_t H5T_STD_I16BE_g;
+H5_DLLVAR hid_t H5T_STD_I16LE_g;
+H5_DLLVAR hid_t H5T_STD_I32BE_g;
+H5_DLLVAR hid_t H5T_STD_I32LE_g;
+H5_DLLVAR hid_t H5T_STD_I64BE_g;
+H5_DLLVAR hid_t H5T_STD_I64LE_g;
+H5_DLLVAR hid_t H5T_STD_U8BE_g;
+H5_DLLVAR hid_t H5T_STD_U8LE_g;
+H5_DLLVAR hid_t H5T_STD_U16BE_g;
+H5_DLLVAR hid_t H5T_STD_U16LE_g;
+H5_DLLVAR hid_t H5T_STD_U32BE_g;
+H5_DLLVAR hid_t H5T_STD_U32LE_g;
+H5_DLLVAR hid_t H5T_STD_U64BE_g;
+H5_DLLVAR hid_t H5T_STD_U64LE_g;
+H5_DLLVAR hid_t H5T_STD_B8BE_g;
+H5_DLLVAR hid_t H5T_STD_B8LE_g;
+H5_DLLVAR hid_t H5T_STD_B16BE_g;
+H5_DLLVAR hid_t H5T_STD_B16LE_g;
+H5_DLLVAR hid_t H5T_STD_B32BE_g;
+H5_DLLVAR hid_t H5T_STD_B32LE_g;
+H5_DLLVAR hid_t H5T_STD_B64BE_g;
+H5_DLLVAR hid_t H5T_STD_B64LE_g;
+H5_DLLVAR hid_t H5T_STD_REF_OBJ_g;
+H5_DLLVAR hid_t H5T_STD_REF_DSETREG_g;
+
+/*
+ * Types which are particular to Unix.
+ */
+#define H5T_UNIX_D32BE (H5OPEN H5T_UNIX_D32BE_g)
+#define H5T_UNIX_D32LE (H5OPEN H5T_UNIX_D32LE_g)
+#define H5T_UNIX_D64BE (H5OPEN H5T_UNIX_D64BE_g)
+#define H5T_UNIX_D64LE (H5OPEN H5T_UNIX_D64LE_g)
+H5_DLLVAR hid_t H5T_UNIX_D32BE_g;
+H5_DLLVAR hid_t H5T_UNIX_D32LE_g;
+H5_DLLVAR hid_t H5T_UNIX_D64BE_g;
+H5_DLLVAR hid_t H5T_UNIX_D64LE_g;
+
+/*
+ * Types particular to the C language. String types use `bytes' instead
+ * of `bits' as their size.
+ */
+#define H5T_C_S1 (H5OPEN H5T_C_S1_g)
+H5_DLLVAR hid_t H5T_C_S1_g;
+
+/*
+ * Types particular to Fortran.
+ */
+#define H5T_FORTRAN_S1 (H5OPEN H5T_FORTRAN_S1_g)
+H5_DLLVAR hid_t H5T_FORTRAN_S1_g;
+
+/*
+ * These types are for Intel CPU's. They are little endian with IEEE
+ * floating point.
+ */
+#define H5T_INTEL_I8 H5T_STD_I8LE
+#define H5T_INTEL_I16 H5T_STD_I16LE
+#define H5T_INTEL_I32 H5T_STD_I32LE
+#define H5T_INTEL_I64 H5T_STD_I64LE
+#define H5T_INTEL_U8 H5T_STD_U8LE
+#define H5T_INTEL_U16 H5T_STD_U16LE
+#define H5T_INTEL_U32 H5T_STD_U32LE
+#define H5T_INTEL_U64 H5T_STD_U64LE
+#define H5T_INTEL_B8 H5T_STD_B8LE
+#define H5T_INTEL_B16 H5T_STD_B16LE
+#define H5T_INTEL_B32 H5T_STD_B32LE
+#define H5T_INTEL_B64 H5T_STD_B64LE
+#define H5T_INTEL_F32 H5T_IEEE_F32LE
+#define H5T_INTEL_F64 H5T_IEEE_F64LE
+
+/*
+ * These types are for DEC Alpha CPU's. They are little endian with IEEE
+ * floating point.
+ */
+#define H5T_ALPHA_I8 H5T_STD_I8LE
+#define H5T_ALPHA_I16 H5T_STD_I16LE
+#define H5T_ALPHA_I32 H5T_STD_I32LE
+#define H5T_ALPHA_I64 H5T_STD_I64LE
+#define H5T_ALPHA_U8 H5T_STD_U8LE
+#define H5T_ALPHA_U16 H5T_STD_U16LE
+#define H5T_ALPHA_U32 H5T_STD_U32LE
+#define H5T_ALPHA_U64 H5T_STD_U64LE
+#define H5T_ALPHA_B8 H5T_STD_B8LE
+#define H5T_ALPHA_B16 H5T_STD_B16LE
+#define H5T_ALPHA_B32 H5T_STD_B32LE
+#define H5T_ALPHA_B64 H5T_STD_B64LE
+#define H5T_ALPHA_F32 H5T_IEEE_F32LE
+#define H5T_ALPHA_F64 H5T_IEEE_F64LE
+
+/*
+ * These types are for MIPS cpu's commonly used in SGI systems. They are big
+ * endian with IEEE floating point.
+ */
+#define H5T_MIPS_I8 H5T_STD_I8BE
+#define H5T_MIPS_I16 H5T_STD_I16BE
+#define H5T_MIPS_I32 H5T_STD_I32BE
+#define H5T_MIPS_I64 H5T_STD_I64BE
+#define H5T_MIPS_U8 H5T_STD_U8BE
+#define H5T_MIPS_U16 H5T_STD_U16BE
+#define H5T_MIPS_U32 H5T_STD_U32BE
+#define H5T_MIPS_U64 H5T_STD_U64BE
+#define H5T_MIPS_B8 H5T_STD_B8BE
+#define H5T_MIPS_B16 H5T_STD_B16BE
+#define H5T_MIPS_B32 H5T_STD_B32BE
+#define H5T_MIPS_B64 H5T_STD_B64BE
+#define H5T_MIPS_F32 H5T_IEEE_F32BE
+#define H5T_MIPS_F64 H5T_IEEE_F64BE
+
+/*
+ * The VAX floating point types (i.e. in VAX byte order)
+ */
+#define H5T_VAX_F32 (H5OPEN H5T_VAX_F32_g)
+#define H5T_VAX_F64 (H5OPEN H5T_VAX_F64_g)
+H5_DLLVAR hid_t H5T_VAX_F32_g;
+H5_DLLVAR hid_t H5T_VAX_F64_g;
+
+/*
+ * The predefined native types. These are the types detected by H5detect and
+ * they violate the naming scheme a little. Instead of a class name,
+ * precision and byte order as the last component, they have a C-like type
+ * name. If the type begins with `U' then it is the unsigned version of the
+ * integer type; other integer types are signed. The type LLONG corresponds
+ * to C's `long long' and LDOUBLE is `long double' (these types might be the
+ * same as `LONG' and `DOUBLE' respectively).
+ */
+#define H5T_NATIVE_CHAR (CHAR_MIN?H5T_NATIVE_SCHAR:H5T_NATIVE_UCHAR)
+#define H5T_NATIVE_SCHAR (H5OPEN H5T_NATIVE_SCHAR_g)
+#define H5T_NATIVE_UCHAR (H5OPEN H5T_NATIVE_UCHAR_g)
+#define H5T_NATIVE_SHORT (H5OPEN H5T_NATIVE_SHORT_g)
+#define H5T_NATIVE_USHORT (H5OPEN H5T_NATIVE_USHORT_g)
+#define H5T_NATIVE_INT (H5OPEN H5T_NATIVE_INT_g)
+#define H5T_NATIVE_UINT (H5OPEN H5T_NATIVE_UINT_g)
+#define H5T_NATIVE_LONG (H5OPEN H5T_NATIVE_LONG_g)
+#define H5T_NATIVE_ULONG (H5OPEN H5T_NATIVE_ULONG_g)
+#define H5T_NATIVE_LLONG (H5OPEN H5T_NATIVE_LLONG_g)
+#define H5T_NATIVE_ULLONG (H5OPEN H5T_NATIVE_ULLONG_g)
+#define H5T_NATIVE_FLOAT (H5OPEN H5T_NATIVE_FLOAT_g)
+#define H5T_NATIVE_DOUBLE (H5OPEN H5T_NATIVE_DOUBLE_g)
+#if H5_SIZEOF_LONG_DOUBLE !=0
+#define H5T_NATIVE_LDOUBLE (H5OPEN H5T_NATIVE_LDOUBLE_g)
+#endif
+#define H5T_NATIVE_B8 (H5OPEN H5T_NATIVE_B8_g)
+#define H5T_NATIVE_B16 (H5OPEN H5T_NATIVE_B16_g)
+#define H5T_NATIVE_B32 (H5OPEN H5T_NATIVE_B32_g)
+#define H5T_NATIVE_B64 (H5OPEN H5T_NATIVE_B64_g)
+#define H5T_NATIVE_OPAQUE (H5OPEN H5T_NATIVE_OPAQUE_g)
+#define H5T_NATIVE_HADDR (H5OPEN H5T_NATIVE_HADDR_g)
+#define H5T_NATIVE_HSIZE (H5OPEN H5T_NATIVE_HSIZE_g)
+#define H5T_NATIVE_HSSIZE (H5OPEN H5T_NATIVE_HSSIZE_g)
+#define H5T_NATIVE_HERR (H5OPEN H5T_NATIVE_HERR_g)
+#define H5T_NATIVE_HBOOL (H5OPEN H5T_NATIVE_HBOOL_g)
+H5_DLLVAR hid_t H5T_NATIVE_SCHAR_g;
+H5_DLLVAR hid_t H5T_NATIVE_UCHAR_g;
+H5_DLLVAR hid_t H5T_NATIVE_SHORT_g;
+H5_DLLVAR hid_t H5T_NATIVE_USHORT_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_g;
+H5_DLLVAR hid_t H5T_NATIVE_LONG_g;
+H5_DLLVAR hid_t H5T_NATIVE_ULONG_g;
+H5_DLLVAR hid_t H5T_NATIVE_LLONG_g;
+H5_DLLVAR hid_t H5T_NATIVE_ULLONG_g;
+H5_DLLVAR hid_t H5T_NATIVE_FLOAT_g;
+H5_DLLVAR hid_t H5T_NATIVE_DOUBLE_g;
+#if H5_SIZEOF_LONG_DOUBLE !=0
+H5_DLLVAR hid_t H5T_NATIVE_LDOUBLE_g;
+#endif
+H5_DLLVAR hid_t H5T_NATIVE_B8_g;
+H5_DLLVAR hid_t H5T_NATIVE_B16_g;
+H5_DLLVAR hid_t H5T_NATIVE_B32_g;
+H5_DLLVAR hid_t H5T_NATIVE_B64_g;
+H5_DLLVAR hid_t H5T_NATIVE_OPAQUE_g;
+H5_DLLVAR hid_t H5T_NATIVE_HADDR_g;
+H5_DLLVAR hid_t H5T_NATIVE_HSIZE_g;
+H5_DLLVAR hid_t H5T_NATIVE_HSSIZE_g;
+H5_DLLVAR hid_t H5T_NATIVE_HERR_g;
+H5_DLLVAR hid_t H5T_NATIVE_HBOOL_g;
+
+/* C9x integer types */
+#define H5T_NATIVE_INT8 (H5OPEN H5T_NATIVE_INT8_g)
+#define H5T_NATIVE_UINT8 (H5OPEN H5T_NATIVE_UINT8_g)
+#define H5T_NATIVE_INT_LEAST8 (H5OPEN H5T_NATIVE_INT_LEAST8_g)
+#define H5T_NATIVE_UINT_LEAST8 (H5OPEN H5T_NATIVE_UINT_LEAST8_g)
+#define H5T_NATIVE_INT_FAST8 (H5OPEN H5T_NATIVE_INT_FAST8_g)
+#define H5T_NATIVE_UINT_FAST8 (H5OPEN H5T_NATIVE_UINT_FAST8_g)
+H5_DLLVAR hid_t H5T_NATIVE_INT8_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT8_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_LEAST8_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_LEAST8_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_FAST8_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_FAST8_g;
+
+#define H5T_NATIVE_INT16 (H5OPEN H5T_NATIVE_INT16_g)
+#define H5T_NATIVE_UINT16 (H5OPEN H5T_NATIVE_UINT16_g)
+#define H5T_NATIVE_INT_LEAST16 (H5OPEN H5T_NATIVE_INT_LEAST16_g)
+#define H5T_NATIVE_UINT_LEAST16 (H5OPEN H5T_NATIVE_UINT_LEAST16_g)
+#define H5T_NATIVE_INT_FAST16 (H5OPEN H5T_NATIVE_INT_FAST16_g)
+#define H5T_NATIVE_UINT_FAST16 (H5OPEN H5T_NATIVE_UINT_FAST16_g)
+H5_DLLVAR hid_t H5T_NATIVE_INT16_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT16_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_LEAST16_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_LEAST16_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_FAST16_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_FAST16_g;
+
+#define H5T_NATIVE_INT32 (H5OPEN H5T_NATIVE_INT32_g)
+#define H5T_NATIVE_UINT32 (H5OPEN H5T_NATIVE_UINT32_g)
+#define H5T_NATIVE_INT_LEAST32 (H5OPEN H5T_NATIVE_INT_LEAST32_g)
+#define H5T_NATIVE_UINT_LEAST32 (H5OPEN H5T_NATIVE_UINT_LEAST32_g)
+#define H5T_NATIVE_INT_FAST32 (H5OPEN H5T_NATIVE_INT_FAST32_g)
+#define H5T_NATIVE_UINT_FAST32 (H5OPEN H5T_NATIVE_UINT_FAST32_g)
+H5_DLLVAR hid_t H5T_NATIVE_INT32_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT32_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_LEAST32_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_LEAST32_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_FAST32_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_FAST32_g;
+
+#define H5T_NATIVE_INT64 (H5OPEN H5T_NATIVE_INT64_g)
+#define H5T_NATIVE_UINT64 (H5OPEN H5T_NATIVE_UINT64_g)
+#define H5T_NATIVE_INT_LEAST64 (H5OPEN H5T_NATIVE_INT_LEAST64_g)
+#define H5T_NATIVE_UINT_LEAST64 (H5OPEN H5T_NATIVE_UINT_LEAST64_g)
+#define H5T_NATIVE_INT_FAST64 (H5OPEN H5T_NATIVE_INT_FAST64_g)
+#define H5T_NATIVE_UINT_FAST64 (H5OPEN H5T_NATIVE_UINT_FAST64_g)
+H5_DLLVAR hid_t H5T_NATIVE_INT64_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT64_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_LEAST64_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_LEAST64_g;
+H5_DLLVAR hid_t H5T_NATIVE_INT_FAST64_g;
+H5_DLLVAR hid_t H5T_NATIVE_UINT_FAST64_g;
+
+/* Operations defined on all datatypes */
+H5_DLL hid_t H5Tcreate(H5T_class_t type, size_t size);
+H5_DLL hid_t H5Tcopy(hid_t type_id);
+H5_DLL herr_t H5Tclose(hid_t type_id);
+H5_DLL htri_t H5Tequal(hid_t type1_id, hid_t type2_id);
+H5_DLL herr_t H5Tlock(hid_t type_id);
+H5_DLL herr_t H5Tcommit2(hid_t loc_id, const char *name, hid_t type_id,
+ hid_t lcpl_id, hid_t tcpl_id, hid_t tapl_id);
+H5_DLL hid_t H5Topen2(hid_t loc_id, const char *name, hid_t tapl_id);
+H5_DLL herr_t H5Tcommit_anon(hid_t loc_id, hid_t type_id, hid_t tcpl_id, hid_t tapl_id);
+H5_DLL hid_t H5Tget_create_plist(hid_t type_id);
+H5_DLL htri_t H5Tcommitted(hid_t type_id);
+H5_DLL herr_t H5Tencode(hid_t obj_id, void *buf, size_t *nalloc);
+H5_DLL hid_t H5Tdecode(const void *buf);
+H5_DLL herr_t H5Tflush(hid_t type_id);
+H5_DLL herr_t H5Trefresh(hid_t type_id);
+
+/* Operations defined on compound datatypes */
+H5_DLL herr_t H5Tinsert(hid_t parent_id, const char *name, size_t offset,
+ hid_t member_id);
+H5_DLL herr_t H5Tpack(hid_t type_id);
+
+/* Operations defined on enumeration datatypes */
+H5_DLL hid_t H5Tenum_create(hid_t base_id);
+H5_DLL herr_t H5Tenum_insert(hid_t type, const char *name, const void *value);
+H5_DLL herr_t H5Tenum_nameof(hid_t type, const void *value, char *name/*out*/,
+ size_t size);
+H5_DLL herr_t H5Tenum_valueof(hid_t type, const char *name,
+ void *value/*out*/);
+
+/* Operations defined on variable-length datatypes */
+H5_DLL hid_t H5Tvlen_create(hid_t base_id);
+
+/* Operations defined on array datatypes */
+H5_DLL hid_t H5Tarray_create2(hid_t base_id, unsigned ndims,
+ const hsize_t dim[/* ndims */]);
+H5_DLL int H5Tget_array_ndims(hid_t type_id);
+H5_DLL int H5Tget_array_dims2(hid_t type_id, hsize_t dims[]);
+
+/* Operations defined on opaque datatypes */
+H5_DLL herr_t H5Tset_tag(hid_t type, const char *tag);
+H5_DLL char *H5Tget_tag(hid_t type);
+
+/* Querying property values */
+H5_DLL hid_t H5Tget_super(hid_t type);
+H5_DLL H5T_class_t H5Tget_class(hid_t type_id);
+H5_DLL htri_t H5Tdetect_class(hid_t type_id, H5T_class_t cls);
+H5_DLL size_t H5Tget_size(hid_t type_id);
+H5_DLL H5T_order_t H5Tget_order(hid_t type_id);
+H5_DLL size_t H5Tget_precision(hid_t type_id);
+H5_DLL int H5Tget_offset(hid_t type_id);
+H5_DLL herr_t H5Tget_pad(hid_t type_id, H5T_pad_t *lsb/*out*/,
+ H5T_pad_t *msb/*out*/);
+H5_DLL H5T_sign_t H5Tget_sign(hid_t type_id);
+H5_DLL herr_t H5Tget_fields(hid_t type_id, size_t *spos/*out*/,
+ size_t *epos/*out*/, size_t *esize/*out*/,
+ size_t *mpos/*out*/, size_t *msize/*out*/);
+H5_DLL size_t H5Tget_ebias(hid_t type_id);
+H5_DLL H5T_norm_t H5Tget_norm(hid_t type_id);
+H5_DLL H5T_pad_t H5Tget_inpad(hid_t type_id);
+H5_DLL H5T_str_t H5Tget_strpad(hid_t type_id);
+H5_DLL int H5Tget_nmembers(hid_t type_id);
+H5_DLL char *H5Tget_member_name(hid_t type_id, unsigned membno);
+H5_DLL int H5Tget_member_index(hid_t type_id, const char *name);
+H5_DLL size_t H5Tget_member_offset(hid_t type_id, unsigned membno);
+H5_DLL H5T_class_t H5Tget_member_class(hid_t type_id, unsigned membno);
+H5_DLL hid_t H5Tget_member_type(hid_t type_id, unsigned membno);
+H5_DLL herr_t H5Tget_member_value(hid_t type_id, unsigned membno, void *value/*out*/);
+H5_DLL H5T_cset_t H5Tget_cset(hid_t type_id);
+H5_DLL htri_t H5Tis_variable_str(hid_t type_id);
+H5_DLL hid_t H5Tget_native_type(hid_t type_id, H5T_direction_t direction);
+
+/* Setting property values */
+H5_DLL herr_t H5Tset_size(hid_t type_id, size_t size);
+H5_DLL herr_t H5Tset_order(hid_t type_id, H5T_order_t order);
+H5_DLL herr_t H5Tset_precision(hid_t type_id, size_t prec);
+H5_DLL herr_t H5Tset_offset(hid_t type_id, size_t offset);
+H5_DLL herr_t H5Tset_pad(hid_t type_id, H5T_pad_t lsb, H5T_pad_t msb);
+H5_DLL herr_t H5Tset_sign(hid_t type_id, H5T_sign_t sign);
+H5_DLL herr_t H5Tset_fields(hid_t type_id, size_t spos, size_t epos,
+ size_t esize, size_t mpos, size_t msize);
+H5_DLL herr_t H5Tset_ebias(hid_t type_id, size_t ebias);
+H5_DLL herr_t H5Tset_norm(hid_t type_id, H5T_norm_t norm);
+H5_DLL herr_t H5Tset_inpad(hid_t type_id, H5T_pad_t pad);
+H5_DLL herr_t H5Tset_cset(hid_t type_id, H5T_cset_t cset);
+H5_DLL herr_t H5Tset_strpad(hid_t type_id, H5T_str_t strpad);
+
+/* Type conversion database */
+H5_DLL herr_t H5Tregister(H5T_pers_t pers, const char *name, hid_t src_id,
+ hid_t dst_id, H5T_conv_t func);
+H5_DLL herr_t H5Tunregister(H5T_pers_t pers, const char *name, hid_t src_id,
+ hid_t dst_id, H5T_conv_t func);
+H5_DLL H5T_conv_t H5Tfind(hid_t src_id, hid_t dst_id, H5T_cdata_t **pcdata);
+H5_DLL htri_t H5Tcompiler_conv(hid_t src_id, hid_t dst_id);
+H5_DLL herr_t H5Tconvert(hid_t src_id, hid_t dst_id, size_t nelmts,
+ void *buf, void *background, hid_t plist_id);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/* Macros */
+
+
+/* Typedefs */
+
+
+/* Function prototypes */
+H5_DLL herr_t H5Tcommit1(hid_t loc_id, const char *name, hid_t type_id);
+H5_DLL hid_t H5Topen1(hid_t loc_id, const char *name);
+H5_DLL hid_t H5Tarray_create1(hid_t base_id, int ndims,
+ const hsize_t dim[/* ndims */],
+ const int perm[/* ndims */]);
+H5_DLL int H5Tget_array_dims1(hid_t type_id, hsize_t dims[], int perm[]);
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5Tpublic_H */
+
diff --git a/src/H5Tstrpad.c b/src/H5Tstrpad.c
new file mode 100644
index 0000000..fa084f1
--- /dev/null
+++ b/src/H5Tstrpad.c
@@ -0,0 +1,137 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for setting & querying
+ * the datatype string padding for the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tget_strpad
+ *
+ * Purpose: The method used to store character strings differs with the
+ * programming language: C usually null terminates strings while
+ * Fortran left-justifies and space-pads strings. This property
+ * defines the storage mechanism for the string.
+ *
+ * Return: Success: The character set of a string type.
+ *
+ * Failure: H5T_STR_ERROR (Negative)
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_str_t
+H5Tget_strpad(hid_t type_id)
+{
+ H5T_t *dt = NULL;
+ H5T_str_t ret_value;
+
+ FUNC_ENTER_API(H5T_STR_ERROR)
+ H5TRACE1("Tz", "i", type_id);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_STR_ERROR, "not a datatype")
+ while (dt->shared->parent && !H5T_IS_STRING(dt->shared))
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_STRING(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, H5T_STR_ERROR, "operation not defined for datatype class")
+
+ /* result */
+ if(H5T_IS_FIXED_STRING(dt->shared))
+ ret_value = dt->shared->u.atomic.u.s.pad;
+ else
+ ret_value = dt->shared->u.vlen.pad;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tset_strpad
+ *
+ * Purpose: The method used to store character strings differs with the
+ * programming language: C usually null terminates strings while
+ * Fortran left-justifies and space-pads strings. This property
+ * defines the storage mechanism for the string.
+ *
+ * When converting from a long string to a short string if the
+ * short string is H5T_STR_NULLPAD or H5T_STR_SPACEPAD then the
+ * string is simply truncated; otherwise if the short string is
+ * H5T_STR_NULLTERM it will be truncated and a null terminator
+ * is appended.
+ *
+ * When converting from a short string to a long string, the
+ * long string is padded on the end by appending nulls or
+ * spaces.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, January 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 22 Dec 1998
+ * Also works for derived datatypes.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Tset_strpad(hid_t type_id, H5T_str_t strpad)
+{
+ H5T_t *dt = NULL;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "iTz", type_id, strpad);
+
+ /* Check args */
+ if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id,H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+ if (H5T_STATE_TRANSIENT!=dt->shared->state)
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTINIT, FAIL, "datatype is read-only")
+ if (strpad < H5T_STR_NULLTERM || strpad >= H5T_NSTR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "illegal string pad type")
+ while (dt->shared->parent && !H5T_IS_STRING(dt->shared))
+ dt = dt->shared->parent; /*defer to parent*/
+ if (!H5T_IS_STRING(dt->shared))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "operation not defined for datatype class")
+
+ /* Commit */
+ if(H5T_IS_FIXED_STRING(dt->shared))
+ dt->shared->u.atomic.u.s.pad = strpad;
+ else
+ dt->shared->u.vlen.pad = strpad;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
diff --git a/src/H5Tvisit.c b/src/H5Tvisit.c
new file mode 100644
index 0000000..c706dee
--- /dev/null
+++ b/src/H5Tvisit.c
@@ -0,0 +1,166 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains most of the "core" functionality of
+ * the H5T interface, including the API initialization code, etc.
+ * Many routines that are infrequently used, or are specialized for
+ * one particular datatype class are in another module.
+ */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Tvisit.c
+ * Jul 19 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Visit all the components of a datatype
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Tpkg.h" /* Datatypes */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__visit
+ *
+ * Purpose: Visit a datatype and all it's members and/or parents, making
+ * a callback for each.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 19, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T__visit(H5T_t *dt, unsigned visit_flags, H5T_operator_t op, void *op_value)
+{
+ hbool_t is_complex; /* Flag indicating current datatype is "complex" */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dt);
+ HDassert(op);
+
+ /* Check for complex datatype */
+ is_complex = H5T_IS_COMPLEX(dt->shared->type);
+
+ /* If the callback is to be made on the datatype first, do that */
+ if(is_complex && (visit_flags & H5T_VISIT_COMPLEX_FIRST))
+ if(op(dt, op_value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "operator callback failed")
+
+ /* Make callback for each member/child, if requested */
+ switch(dt->shared->type) {
+ case H5T_COMPOUND:
+ {
+ unsigned u; /* Local index variable */
+
+ /* Visit each member of the compound datatype */
+ for(u = 0; u < dt->shared->u.compnd.nmembs; u++)
+ if(H5T__visit(dt->shared->u.compnd.memb[u].type, visit_flags, op, op_value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "can't visit member datatype")
+ } /* end case */
+ break;
+
+ case H5T_ARRAY:
+ case H5T_VLEN:
+ case H5T_ENUM:
+ /* Visit parent type */
+ if(H5T__visit(dt->shared->parent, visit_flags, op, op_value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "can't visit parent datatype")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ /* Not real values */
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "operation not defined for datatype class")
+ break;
+
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ default:
+ /* Visit "simple" datatypes here */
+ if(visit_flags & H5T_VISIT_SIMPLE)
+ if(op(dt, op_value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "operator callback failed")
+ break;
+ } /* end switch */
+
+ /* If the callback is to be made on the datatype last, do that */
+ if(is_complex && (visit_flags & H5T_VISIT_COMPLEX_LAST))
+ if(op(dt, op_value) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADITER, FAIL, "operator callback failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__visit() */
+
diff --git a/src/H5Tvlen.c b/src/H5Tvlen.c
new file mode 100644
index 0000000..00e61e5
--- /dev/null
+++ b/src/H5Tvlen.c
@@ -0,0 +1,1259 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Module Info: This module contains the functionality for variable-length
+ * datatypes in the H5T interface.
+ */
+
+#include "H5Tmodule.h" /* This source code file is part of the H5T module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HGprivate.h" /* Global Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tpkg.h" /* Datatypes */
+
+/* Local functions */
+static herr_t H5T_vlen_reclaim_recurse(void *elem, const H5T_t *dt, H5MM_free_t free_func, void *free_info);
+static ssize_t H5T_vlen_seq_mem_getlen(const void *_vl);
+static void * H5T_vlen_seq_mem_getptr(void *_vl);
+static htri_t H5T_vlen_seq_mem_isnull(const H5F_t *f, void *_vl);
+static herr_t H5T_vlen_seq_mem_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len);
+static herr_t H5T_vlen_seq_mem_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size);
+static herr_t H5T_vlen_seq_mem_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg);
+static ssize_t H5T_vlen_str_mem_getlen(const void *_vl);
+static void * H5T_vlen_str_mem_getptr(void *_vl);
+static htri_t H5T_vlen_str_mem_isnull(const H5F_t *f, void *_vl);
+static herr_t H5T_vlen_str_mem_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len);
+static herr_t H5T_vlen_str_mem_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size);
+static herr_t H5T_vlen_str_mem_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg);
+static ssize_t H5T_vlen_disk_getlen(const void *_vl);
+static void * H5T_vlen_disk_getptr(void *_vl);
+static htri_t H5T_vlen_disk_isnull(const H5F_t *f, void *_vl);
+static herr_t H5T_vlen_disk_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len);
+static herr_t H5T_vlen_disk_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size);
+static herr_t H5T_vlen_disk_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg);
+
+/* Local variables */
+
+/* Default settings for variable-length allocation routines */
+static H5T_vlen_alloc_info_t H5T_vlen_def_vl_alloc_info ={
+ H5D_VLEN_ALLOC,
+ H5D_VLEN_ALLOC_INFO,
+ H5D_VLEN_FREE,
+ H5D_VLEN_FREE_INFO
+};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Tvlen_create
+ *
+ * Purpose: Create a new variable-length datatype based on the specified
+ * BASE_TYPE.
+ *
+ * Return: Success: ID of new VL datatype
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, May 20, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5Tvlen_create(hid_t base_id)
+{
+ H5T_t *base = NULL; /*base datatype */
+ H5T_t *dt = NULL; /*new datatype */
+ hid_t ret_value; /*return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("i", "i", base_id);
+
+ /* Check args */
+ if(NULL == (base = (H5T_t *)H5I_object_verify(base_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype")
+
+ /* Create up VL datatype */
+ if((dt = H5T__vlen_create(base)) == NULL)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid VL location")
+
+ /* Atomize the type */
+ if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Tvlen_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__vlen_create
+ *
+ * Purpose: Create a new variable-length datatype based on the specified
+ * BASE_TYPE.
+ *
+ * Return: Success: new VL datatype
+ *
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 20, 2001
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_t *
+H5T__vlen_create(const H5T_t *base)
+{
+ H5T_t *dt = NULL; /* New VL datatype */
+ H5T_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Check args */
+ HDassert(base);
+
+ /* Build new type */
+ if(NULL == (dt = H5T__alloc()))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, NULL, "memory allocation failed")
+ dt->shared->type = H5T_VLEN;
+
+ /*
+ * Force conversions (i.e. memory to memory conversions should duplicate
+ * data, not point to the same VL sequences)
+ */
+ dt->shared->force_conv = TRUE;
+ if(NULL == (dt->shared->parent = H5T_copy(base, H5T_COPY_ALL)))
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy base datatype")
+
+ /* Inherit encoding version from base type */
+ dt->shared->version = base->shared->version;
+
+ /* This is a sequence, not a string */
+ dt->shared->u.vlen.type = H5T_VLEN_SEQUENCE;
+
+ /* Set up VL information */
+ if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location")
+
+ /* Set return value */
+ ret_value = dt;
+
+done:
+ if(!ret_value)
+ if(dt && H5T_close(dt) < 0)
+ HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, NULL, "unable to release datatype info")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__vlen_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T__vlen_set_loc
+ *
+ * Purpose: Sets the location of a VL datatype to be either on disk or in memory
+ *
+ * Return:
+ * One of two values on success:
+ * TRUE - If the location of any vlen types changed
+ * FALSE - If the location of any vlen types is the same
+ * <0 is returned on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, June 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5T__vlen_set_loc(const H5T_t *dt, H5F_t *f, H5T_loc_t loc)
+{
+ htri_t ret_value = FALSE; /* Indicate success, but no location change */
+
+ FUNC_ENTER_PACKAGE
+
+ /* check parameters */
+ HDassert(dt);
+ HDassert(loc >= H5T_LOC_BADLOC && loc < H5T_LOC_MAXLOC);
+
+ /* Only change the location if it's different */
+ if(loc != dt->shared->u.vlen.loc || f != dt->shared->u.vlen.f) {
+ switch(loc) {
+ case H5T_LOC_MEMORY: /* Memory based VL datatype */
+ HDassert(NULL == f);
+
+ /* Mark this type as being stored in memory */
+ dt->shared->u.vlen.loc = H5T_LOC_MEMORY;
+
+ if(dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) {
+ /* size in memory, disk size is different */
+ dt->shared->size = sizeof(hvl_t);
+
+ /* Set up the function pointers to access the VL sequence in memory */
+ dt->shared->u.vlen.getlen = H5T_vlen_seq_mem_getlen;
+ dt->shared->u.vlen.getptr = H5T_vlen_seq_mem_getptr;
+ dt->shared->u.vlen.isnull = H5T_vlen_seq_mem_isnull;
+ dt->shared->u.vlen.read = H5T_vlen_seq_mem_read;
+ dt->shared->u.vlen.write = H5T_vlen_seq_mem_write;
+ dt->shared->u.vlen.setnull = H5T_vlen_seq_mem_setnull;
+ } else if(dt->shared->u.vlen.type == H5T_VLEN_STRING) {
+ /* size in memory, disk size is different */
+ dt->shared->size = sizeof(char *);
+
+ /* Set up the function pointers to access the VL string in memory */
+ dt->shared->u.vlen.getlen = H5T_vlen_str_mem_getlen;
+ dt->shared->u.vlen.getptr = H5T_vlen_str_mem_getptr;
+ dt->shared->u.vlen.isnull = H5T_vlen_str_mem_isnull;
+ dt->shared->u.vlen.read = H5T_vlen_str_mem_read;
+ dt->shared->u.vlen.write = H5T_vlen_str_mem_write;
+ dt->shared->u.vlen.setnull = H5T_vlen_str_mem_setnull;
+ } else {
+ HDassert(0 && "Invalid VL type");
+ }
+
+ /* Reset file ID (since this VL is in memory) */
+ dt->shared->u.vlen.f = NULL;
+ break;
+
+ case H5T_LOC_DISK: /* Disk based VL datatype */
+ HDassert(f);
+
+ /* Mark this type as being stored on disk */
+ dt->shared->u.vlen.loc = H5T_LOC_DISK;
+
+ /*
+ * Size of element on disk is 4 bytes for the length, plus the size
+ * of an address in this file, plus 4 bytes for the size of a heap
+ * ID. Memory size is different
+ */
+ dt->shared->size = 4 + (size_t)H5F_SIZEOF_ADDR(f) + 4;
+
+ /* Set up the function pointers to access the VL information on disk */
+ /* VL sequences and VL strings are stored identically on disk, so use the same functions */
+ dt->shared->u.vlen.getlen = H5T_vlen_disk_getlen;
+ dt->shared->u.vlen.getptr = H5T_vlen_disk_getptr;
+ dt->shared->u.vlen.isnull = H5T_vlen_disk_isnull;
+ dt->shared->u.vlen.read = H5T_vlen_disk_read;
+ dt->shared->u.vlen.write = H5T_vlen_disk_write;
+ dt->shared->u.vlen.setnull = H5T_vlen_disk_setnull;
+
+ /* Set file ID (since this VL is on disk) */
+ dt->shared->u.vlen.f = f;
+ break;
+
+ case H5T_LOC_BADLOC:
+ /* Allow undefined location. In H5Odtype.c, H5O_dtype_decode sets undefined
+ * location for VL type and leaves it for the caller to decide.
+ */
+ break;
+
+ case H5T_LOC_MAXLOC:
+ /* MAXLOC is invalid */
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype location")
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+ /* Indicate that the location changed */
+ ret_value = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T__vlen_set_loc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_getlen
+ *
+ * Purpose: Retrieves the length of a memory based VL element.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5T_vlen_seq_mem_getlen(const void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */
+#else
+ hvl_t vl; /* User's hvl_t information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters, return result */
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(vl);
+
+ FUNC_LEAVE_NOAPI((ssize_t)vl->len)
+#else
+ HDassert(_vl);
+ HDmemcpy(&vl, _vl, sizeof(hvl_t));
+
+ FUNC_LEAVE_NOAPI((ssize_t)vl.len)
+#endif
+} /* end H5T_vlen_seq_mem_getlen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_getptr
+ *
+ * Purpose: Retrieves the pointer for a memory based VL element.
+ *
+ * Return: Non-NULL on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, June 12, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5T_vlen_seq_mem_getptr(void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */
+#else
+ hvl_t vl; /* User's hvl_t information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters, return result */
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(vl);
+
+ FUNC_LEAVE_NOAPI(vl->p)
+#else
+ HDassert(_vl);
+ HDmemcpy(&vl, _vl, sizeof(hvl_t));
+
+ FUNC_LEAVE_NOAPI(vl.p)
+#endif
+} /* end H5T_vlen_seq_mem_getptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_isnull
+ *
+ * Purpose: Checks if a memory sequence is the "null" sequence
+ *
+ * Return: TRUE/FALSE on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5T_vlen_seq_mem_isnull(const H5F_t H5_ATTR_UNUSED *f, void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */
+#else
+ hvl_t vl; /* User's hvl_t information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters, return result */
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(vl);
+
+ FUNC_LEAVE_NOAPI((vl->len==0 || vl->p==NULL) ? TRUE : FALSE)
+#else
+ HDassert(_vl);
+ HDmemcpy(&vl, _vl, sizeof(hvl_t));
+
+ FUNC_LEAVE_NOAPI((vl.len==0 || vl.p==NULL) ? TRUE : FALSE)
+#endif
+} /* end H5T_vlen_seq_mem_isnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_read
+ *
+ * Purpose: "Reads" the memory based VL sequence into a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_seq_mem_read(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void *buf, size_t len)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */
+#else
+ hvl_t vl; /* User's hvl_t information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters, copy data */
+ HDassert(buf);
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(vl && vl->p);
+
+ HDmemcpy(buf,vl->p,len);
+#else
+ HDassert(_vl);
+ HDmemcpy(&vl, _vl, sizeof(hvl_t));
+ HDassert(vl.p);
+
+ HDmemcpy(buf,vl.p,len);
+#endif
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_vlen_seq_mem_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_write
+ *
+ * Purpose: "Writes" the memory based VL sequence from a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_seq_mem_write(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size)
+{
+ hvl_t vl; /* Temporary hvl_t to use during operation */
+ size_t len;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check parameters */
+ HDassert(_vl);
+ HDassert(buf);
+
+ if(seq_len!=0) {
+ len=seq_len*base_size;
+
+ /* Use the user's memory allocation routine is one is defined */
+ if(vl_alloc_info->alloc_func!=NULL) {
+ if(NULL==(vl.p=(vl_alloc_info->alloc_func)(len,vl_alloc_info->alloc_info)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data")
+ } /* end if */
+ else { /* Default to system malloc */
+ if(NULL == (vl.p = HDmalloc(len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data")
+ } /* end else */
+
+ /* Copy the data into the newly allocated buffer */
+ HDmemcpy(vl.p,buf,len);
+
+ } /* end if */
+ else
+ vl.p=NULL;
+
+ /* Set the sequence length */
+ vl.len=seq_len;
+
+ /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
+ HDmemcpy(_vl,&vl,sizeof(hvl_t));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_seq_mem_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_seq_mem_setnull
+ *
+ * Purpose: Sets a VL info object in memory to the "nil" value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_seq_mem_setnull(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void H5_ATTR_UNUSED *_bg)
+{
+ hvl_t vl; /* Temporary hvl_t to use during operation */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+ HDassert(_vl);
+
+ /* Set the "nil" hvl_t */
+ vl.len=0;
+ vl.p=NULL;
+
+ /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
+ HDmemcpy(_vl,&vl,sizeof(hvl_t));
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_vlen_seq_mem_setnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_getlen
+ *
+ * Purpose: Retrieves the length of a memory based VL string.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5T_vlen_str_mem_getlen(const void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ const char *s=*(const char * const *)_vl; /* Pointer to the user's string information */
+#else
+ const char *s; /* Pointer to the user's string information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(s);
+#else
+ HDassert(_vl);
+ HDmemcpy(&s, _vl, sizeof(char *));
+#endif
+
+ FUNC_LEAVE_NOAPI((ssize_t)HDstrlen(s))
+} /* end H5T_vlen_str_mem_getlen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_getptr
+ *
+ * Purpose: Retrieves the pointer for a memory based VL string.
+ *
+ * Return: Non-NULL on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, June 12, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5T_vlen_str_mem_getptr(void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ char *s=*(char **)_vl; /* Pointer to the user's string information */
+#else
+ char *s; /* Pointer to the user's string information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(s);
+#else
+ HDassert(_vl);
+ HDmemcpy(&s, _vl, sizeof(char *));
+#endif
+
+ FUNC_LEAVE_NOAPI(s)
+} /* end H5T_vlen_str_mem_getptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_isnull
+ *
+ * Purpose: Checks if a memory string is a NULL pointer
+ *
+ * Return: TRUE/FALSE on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5T_vlen_str_mem_isnull(const H5F_t H5_ATTR_UNUSED *f, void *_vl)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ char *s=*(char **)_vl; /* Pointer to the user's string information */
+#else
+ char *s; /* Pointer to the user's string information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifndef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDmemcpy(&s, _vl, sizeof(char *));
+#endif
+
+ FUNC_LEAVE_NOAPI(s==NULL ? TRUE : FALSE)
+} /* end H5T_vlen_str_mem_isnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_read
+ *
+ * Purpose: "Reads" the memory based VL string into a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_str_mem_read(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void *buf, size_t len)
+{
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ char *s=*(char **)_vl; /* Pointer to the user's string information */
+#else
+ char *s; /* Pointer to the user's string information */
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(len>0) {
+ /* check parameters */
+ HDassert(buf);
+#ifdef H5_NO_ALIGNMENT_RESTRICTIONS
+ HDassert(s);
+#else
+ HDassert(_vl);
+ HDmemcpy(&s, _vl, sizeof(char *));
+#endif
+
+ HDmemcpy(buf,s,len);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5T_vlen_str_mem_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_write
+ *
+ * Purpose: "Writes" the memory based VL string from a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_str_mem_write(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size)
+{
+ char *t; /* Pointer to temporary buffer allocated */
+ size_t len; /* Maximum length of the string to copy */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check parameters */
+ HDassert(buf);
+
+ /* Use the user's memory allocation routine if one is defined */
+ if(vl_alloc_info->alloc_func!=NULL) {
+ if(NULL==(t = (char *)(vl_alloc_info->alloc_func)((seq_len+1)*base_size,vl_alloc_info->alloc_info)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data")
+ } /* end if */
+ else { /* Default to system malloc */
+ if(NULL == (t = (char *)HDmalloc((seq_len + 1) * base_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data")
+ } /* end else */
+
+ len=(seq_len*base_size);
+ HDmemcpy(t,buf,len);
+ t[len]='\0';
+
+ /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
+ HDmemcpy(_vl,&t,sizeof(char *));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value) /*lint !e429 The pointer in 't' has been copied */
+} /* end H5T_vlen_str_mem_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_str_mem_setnull
+ *
+ * Purpose: Sets a VL info object in memory to the "null" value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_str_mem_setnull(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void H5_ATTR_UNUSED *_bg)
+{
+ char *t=NULL; /* Pointer to temporary buffer allocated */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
+ HDmemcpy(_vl,&t,sizeof(char *));
+
+ FUNC_LEAVE_NOAPI(SUCCEED) /*lint !e429 The pointer in 't' has been copied */
+} /* end H5T_vlen_str_mem_setnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_getlen
+ *
+ * Purpose: Retrieves the length of a disk based VL element.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5T_vlen_disk_getlen(const void *_vl)
+{
+ const uint8_t *vl=(const uint8_t *)_vl; /* Pointer to the disk VL information */
+ size_t seq_len = 0; /* Sequence length */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+ HDassert(vl);
+
+ UINT32DECODE(vl, seq_len);
+
+ FUNC_LEAVE_NOAPI((ssize_t)seq_len)
+} /* end H5T_vlen_disk_getlen() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_getptr
+ *
+ * Purpose: Retrieves the pointer to a disk based VL element.
+ *
+ * Return: Non-NULL on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, June 12, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5T_vlen_disk_getptr(void H5_ATTR_UNUSED *vl)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+ HDassert(vl);
+
+ FUNC_LEAVE_NOAPI(NULL)
+} /* end H5T_vlen_disk_getptr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_isnull
+ *
+ * Purpose: Checks if a disk VL info object is the "nil" object
+ *
+ * Return: TRUE/FALSE on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5T_vlen_disk_isnull(const H5F_t *f, void *_vl)
+{
+ uint8_t *vl = (uint8_t *)_vl; /* Pointer to the disk VL information */
+ haddr_t addr; /* Sequence's heap address */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check parameters */
+ HDassert(vl);
+
+ /* Skip the sequence's length */
+ vl += 4;
+
+ /* Get the heap address */
+ H5F_addr_decode(f, (const uint8_t **)&vl, &addr);
+
+ FUNC_LEAVE_NOAPI(addr == 0 ? TRUE : FALSE)
+} /* end H5T_vlen_disk_isnull() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_read
+ *
+ * Purpose: Reads the disk based VL element into a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_disk_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *buf, size_t H5_ATTR_UNUSED len)
+{
+ uint8_t *vl=(uint8_t *)_vl; /* Pointer to the user's hvl_t information */
+ H5HG_t hobjid;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check parameters */
+ HDassert(vl);
+ HDassert(buf);
+ HDassert(f);
+
+ /* Skip the length of the sequence */
+ vl += 4;
+
+ /* Get the heap information */
+ H5F_addr_decode(f,(const uint8_t **)&vl,&(hobjid.addr));
+ UINT32DECODE(vl,hobjid.idx);
+
+ /* Check if this sequence actually has any data */
+ if(hobjid.addr>0) {
+ /* Read the VL information from disk */
+ if(H5HG_read(f,dxpl_id,&hobjid,buf, NULL)==NULL)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_READERROR, FAIL, "Unable to read VL information")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_disk_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_write
+ *
+ * Purpose: Writes the disk based VL element from a buffer
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, June 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_disk_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t H5_ATTR_UNUSED *vl_alloc_info,
+ void *_vl, void *buf, void *_bg, size_t seq_len, size_t base_size)
+{
+ uint8_t *vl = (uint8_t *)_vl; /*Pointer to the user's hvl_t information*/
+ uint8_t *bg = (uint8_t *)_bg; /*Pointer to the old data hvl_t */
+ H5HG_t hobjid; /* New VL sequence's heap ID */
+ size_t len; /* Size of new sequence on disk (in bytes) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check parameters */
+ HDassert(vl);
+ HDassert(seq_len == 0 || buf);
+ HDassert(f);
+
+ /* Free heap object for old data. */
+ if(bg!=NULL) {
+ H5HG_t bg_hobjid; /* "Background" VL info sequence's ID info */
+
+ /* Skip the length of the sequence and heap object ID from background data. */
+ bg += 4;
+
+ /* Get heap information */
+ H5F_addr_decode(f, (const uint8_t **)&bg, &(bg_hobjid.addr));
+ UINT32DECODE(bg, bg_hobjid.idx);
+
+ /* Free heap object for old data */
+ if(bg_hobjid.addr > 0) {
+ /* Free heap object */
+ if(H5HG_remove(f, dxpl_id, &bg_hobjid) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to remove heap object")
+ } /* end if */
+ } /* end if */
+
+ /* Set the length of the sequence */
+ UINT32ENCODE(vl, seq_len);
+
+ /* Write the VL information to disk (allocates space also) */
+ len = (seq_len*base_size);
+ if(H5HG_insert(f, dxpl_id, len, buf, &hobjid) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to write VL information")
+
+ /* Encode the heap information */
+ H5F_addr_encode(f, &vl, hobjid.addr);
+ UINT32ENCODE(vl, hobjid.idx);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_disk_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_disk_setnull
+ *
+ * Purpose: Sets a VL info object on disk to the "nil" value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, November 8, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5T_vlen_disk_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg)
+{
+ uint8_t *vl = (uint8_t *)_vl; /*Pointer to the user's hvl_t information*/
+ uint8_t *bg = (uint8_t *)_bg; /*Pointer to the old data hvl_t */
+ uint32_t seq_len = 0; /* Sequence length */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check parameters */
+ HDassert(f);
+ HDassert(vl);
+
+ /* Free heap object for old data. */
+ if(bg != NULL) {
+ H5HG_t bg_hobjid; /* "Background" VL info sequence's ID info */
+
+ /* Skip the length of the sequence and heap object ID from background data. */
+ bg += 4;
+
+ /* Get heap information */
+ H5F_addr_decode(f, (const uint8_t **)&bg, &(bg_hobjid.addr));
+ UINT32DECODE(bg, bg_hobjid.idx);
+
+ /* Free heap object for old data */
+ if(bg_hobjid.addr > 0) {
+ /* Free heap object */
+ if(H5HG_remove(f, dxpl_id, &bg_hobjid) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to remove heap object")
+ } /* end if */
+ } /* end if */
+
+ /* Set the length of the sequence */
+ UINT32ENCODE(vl, seq_len);
+
+ /* Encode the "nil" heap pointer information */
+ H5F_addr_encode(f, &vl, (haddr_t)0);
+ UINT32ENCODE(vl, 0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_disk_setnull() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5T_vlen_reclaim_recurse
+ PURPOSE
+ Internal recursive routine to free VL datatypes
+ USAGE
+ herr_t H5T_vlen_reclaim(elem,dt)
+ void *elem; IN/OUT: Pointer to the dataset element
+ H5T_t *dt; IN: Datatype of dataset element
+
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ Frees any dynamic memory used by VL datatypes in the current dataset
+ element. Performs a recursive depth-first traversal of all compound
+ datatypes to free all VL datatype information allocated by any field.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5T_vlen_reclaim_recurse(void *elem, const H5T_t *dt, H5MM_free_t free_func, void *free_info)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(elem);
+ HDassert(dt);
+
+ /* Check the datatype of this element */
+ switch(dt->shared->type) {
+ case H5T_ARRAY:
+ /* Recurse on each element, if the array's base type is array, VL, enum or compound */
+ if(H5T_IS_COMPLEX(dt->shared->parent->shared->type)) {
+ void *off; /* offset of field */
+
+ /* Calculate the offset member and recurse on it */
+ for(u = 0; u < dt->shared->u.array.nelem; u++) {
+ off = ((uint8_t *)elem) + u * (dt->shared->parent->shared->size);
+ if(H5T_vlen_reclaim_recurse(off, dt->shared->parent, free_func, free_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free array element")
+ } /* end for */
+ } /* end if */
+ break;
+
+ case H5T_COMPOUND:
+ /* Check each field and recurse on VL, compound, enum or array ones */
+ for(u = 0; u < dt->shared->u.compnd.nmembs; u++) {
+ /* Recurse if it's VL, compound, enum or array */
+ if(H5T_IS_COMPLEX(dt->shared->u.compnd.memb[u].type->shared->type)) {
+ void *off; /* offset of field */
+
+ /* Calculate the offset member and recurse on it */
+ off = ((uint8_t *)elem) + dt->shared->u.compnd.memb[u].offset;
+ if(H5T_vlen_reclaim_recurse(off, dt->shared->u.compnd.memb[u].type, free_func, free_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free compound field")
+ } /* end if */
+ } /* end for */
+ break;
+
+ case H5T_VLEN:
+ /* Recurse on the VL information if it's VL, compound, enum or array, then free VL sequence */
+ if(dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) {
+ hvl_t *vl = (hvl_t *)elem; /* Temp. ptr to the vl info */
+
+ /* Check if there is anything actually in this sequence */
+ if(vl->len!=0) {
+ /* Recurse if it's VL, array, enum or compound */
+ if(H5T_IS_COMPLEX(dt->shared->parent->shared->type)) {
+ void *off; /* offset of field */
+
+ /* Calculate the offset of each array element and recurse on it */
+ while(vl->len > 0) {
+ off = ((uint8_t *)vl->p) + (vl->len - 1) * dt->shared->parent->shared->size;
+ if(H5T_vlen_reclaim_recurse(off, dt->shared->parent, free_func, free_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free VL element")
+ vl->len--;
+ } /* end while */
+ } /* end if */
+
+ /* Free the VL sequence */
+ if(free_func != NULL)
+ (*free_func)(vl->p, free_info);
+ else
+ HDfree(vl->p);
+ } /* end if */
+ } else if(dt->shared->u.vlen.type == H5T_VLEN_STRING) {
+ /* Free the VL string */
+ if(free_func != NULL)
+ (*free_func)(*(char **)elem, free_info);
+ else
+ HDfree(*(char **)elem);
+ } else {
+ HDassert(0 && "Invalid VL type");
+ } /* end else */
+ break;
+
+ /* Don't do anything for simple types */
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ break;
+
+ /* Should never have these values */
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype class")
+ break;
+
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_reclaim_recurse() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5T_vlen_reclaim
+ PURPOSE
+ Default method to reclaim any VL data for a buffer element
+ USAGE
+ herr_t H5T_vlen_reclaim(elem,type_id,ndim,point,op_data)
+ void *elem; IN/OUT: Pointer to the dataset element
+ hid_t type_id; IN: Datatype of dataset element
+ unsigned ndim; IN: Number of dimensions in dataspace
+ hsize_t *point; IN: Coordinate location of element in dataspace
+ void *op_data IN: Operator data
+
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ Frees any dynamic memory used by VL datatypes in the current dataset
+ element. Recursively descends compound datatypes to free all VL datatype
+ information allocated by any field.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5T_vlen_reclaim(void *elem, hid_t type_id, unsigned H5_ATTR_UNUSED ndim, const hsize_t H5_ATTR_UNUSED *point, void *op_data)
+{
+ H5T_vlen_alloc_info_t *vl_alloc_info = (H5T_vlen_alloc_info_t *)op_data; /* VL allocation info from iterator */
+ H5T_t *dt;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(elem);
+ HDassert(vl_alloc_info);
+ HDassert(H5I_DATATYPE == H5I_get_type(type_id));
+
+ /* Check args */
+ if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Pull the free function and free info pointer out of the op_data and call the recurse datatype free function */
+ if(H5T_vlen_reclaim_recurse(elem, dt, vl_alloc_info->free_func, vl_alloc_info->free_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't reclaim vlen elements")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_reclaim() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5T_vlen_get_alloc_info
+ PURPOSE
+ Retrieve allocation info for VL datatypes
+ USAGE
+ herr_t H5T_vlen_get_alloc_info(dxpl_id,vl_alloc_info)
+ hid_t dxpl_id; IN: Data transfer property list to query
+ H5T_vlen_alloc_info_t *vl_alloc_info; IN/OUT: Pointer to VL allocation information to fill
+
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ Retrieve the VL allocation functions and information from a dataset
+ transfer property list.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ The VL_ALLOC_INFO pointer should point at already allocated memory to place
+ non-default property list info. If a default property list is used, the
+ VL_ALLOC_INFO pointer will be changed to point at the default information.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5T_vlen_get_alloc_info(hid_t dxpl_id, H5T_vlen_alloc_info_t **vl_alloc_info)
+{
+ H5P_genplist_t *plist; /* DX property list */
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(H5I_GENPROP_LST == H5I_get_type(dxpl_id));
+ HDassert(vl_alloc_info);
+
+ /* Check for the default DXPL */
+ if(dxpl_id==H5P_DATASET_XFER_DEFAULT)
+ *vl_alloc_info=&H5T_vlen_def_vl_alloc_info;
+ else {
+ /* Check args */
+ if(NULL == (plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list")
+
+ /* Get the allocation functions & information */
+ if (H5P_get(plist,H5D_XFER_VLEN_ALLOC_NAME,&(*vl_alloc_info)->alloc_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if (H5P_get(plist,H5D_XFER_VLEN_ALLOC_INFO_NAME,&(*vl_alloc_info)->alloc_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if (H5P_get(plist,H5D_XFER_VLEN_FREE_NAME,&(*vl_alloc_info)->free_func) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ if (H5P_get(plist,H5D_XFER_VLEN_FREE_INFO_NAME,&(*vl_alloc_info)->free_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5T_vlen_get_alloc_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5T_vlen_reclaim_elmt
+ *
+ * Purpose: Alternative method to reclaim any VL data for a buffer element.
+ *
+ * Use this function when the datatype is already available, but
+ * the allocation info is needed from the dxpl_id before jumping
+ * into recursion.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * May 11, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5T_vlen_reclaim_elmt(void *elem, H5T_t *dt, hid_t dxpl_id)
+{
+ H5T_vlen_alloc_info_t _vl_alloc_info; /* VL allocation info buffer */
+ H5T_vlen_alloc_info_t *vl_alloc_info = &_vl_alloc_info; /* VL allocation info */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ HDassert(dt);
+ HDassert(elem);
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get VL allocation info */
+ if(H5T_vlen_get_alloc_info(dxpl_id, &vl_alloc_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve VL allocation info")
+
+ /* Recurse on buffer to free dynamic fields */
+ if(H5T_vlen_reclaim_recurse(elem, dt, vl_alloc_info->free_func, vl_alloc_info->free_info) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't reclaim vlen elements")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5T_vlen_reclaim_elmt */
+
diff --git a/src/H5UC.c b/src/H5UC.c
new file mode 100644
index 0000000..2277818
--- /dev/null
+++ b/src/H5UC.c
@@ -0,0 +1,128 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Reference counting buffer algorithms.
+ *
+ * These are used for various internal buffers which are shared.
+ *
+ * The module used to be H5RC, but changed to H5UC because of
+ * conflicting requirement for the use of H5RC.
+ *
+ */
+
+
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5UCprivate.h" /* Reference-counted buffers */
+
+/* Private typedefs & structs */
+
+/* Declare a free list to manage the H5UC_t struct */
+H5FL_DEFINE_STATIC(H5UC_t);
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5UC_create
+ PURPOSE
+ Create a reference counted object
+ USAGE
+ H5UC_t *H5UC_create(o,free)
+ const void *o; IN: Object to initialize ref-counted object with
+ H5UC_free_func_t free; IN: Function to call when ref-count drop to zero
+
+ RETURNS
+ Returns a pointer to a new ref-counted object on success, NULL on failure.
+ DESCRIPTION
+ Create a reference counted object. The object is not duplicated, it is
+ assumed to be owned by the reference counted object now and will be freed
+ with the 'free' function when the reference count drops to zero.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+H5UC_t *
+H5UC_create(void *o, H5UC_free_func_t free_func)
+{
+ H5UC_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Sanity check */
+ HDassert(o);
+ HDassert(free_func);
+
+ /* Allocate ref-counted string structure */
+ if(NULL == (ret_value = H5FL_MALLOC(H5UC_t)))
+ HGOTO_ERROR(H5E_RS,H5E_NOSPACE,NULL,"memory allocation failed")
+
+ /* Set the internal fields */
+ ret_value->o = o;
+ ret_value->n = 1;
+ ret_value->free_func = free_func;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5UC_create() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5UC_decr
+ PURPOSE
+ Decrement the reference count for a ref-counted object
+ USAGE
+ herr_t H5UC_decr(rc)
+ H5UC_t *rc; IN: Ref-counted object to decrement count for
+
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ Decrements the reference count for a ref-counted object, calling the
+ object's free function if ref-count drops to zero.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5UC_decr(H5UC_t *rc)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(rc);
+ HDassert(rc->o);
+ HDassert(rc->n > 0);
+ HDassert(rc->free_func);
+
+ /* Decrement reference count */
+ rc->n--;
+
+ /* Check if we should delete this object now */
+ if(rc->n == 0) {
+ if((rc->free_func)(rc->o) < 0) {
+ rc = H5FL_FREE(H5UC_t, rc);
+ HGOTO_ERROR(H5E_RS, H5E_CANTFREE, FAIL, "memory release failed")
+ } /* end if */
+ rc = H5FL_FREE(H5UC_t, rc);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5UC_decr() */
+
diff --git a/src/H5UCprivate.h b/src/H5UCprivate.h
new file mode 100644
index 0000000..c451f31
--- /dev/null
+++ b/src/H5UCprivate.h
@@ -0,0 +1,64 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains private information about the H5UC module
+ * The module used to be H5RC, but changed to H5UC because of
+ * conflicting requirement for the use of H5RC.
+ */
+
+#ifndef _H5UCprivate_H
+#define _H5UCprivate_H
+
+/**************************************/
+/* Public headers needed by this file */
+/**************************************/
+#ifdef LATER
+#include "H5UCpublic.h"
+#endif /* LATER */
+
+/***************************************/
+/* Private headers needed by this file */
+/***************************************/
+#include "H5private.h"
+
+/************/
+/* Typedefs */
+/************/
+
+/* Typedef for function to release object when reference count drops to zero */
+typedef herr_t (*H5UC_free_func_t)(void *o);
+
+/* Typedef for reference counted objects */
+typedef struct H5UC_t {
+ void *o; /* Object to be reference counted */
+ size_t n; /* Reference count of number of pointers sharing object */
+ H5UC_free_func_t free_func; /* Function to free object */
+} H5UC_t;
+
+/**********/
+/* Macros */
+/**********/
+#define H5UC_INC(rc) ((rc)->n++)
+#define H5UC_DEC(rc) (H5UC_decr(rc))
+#define H5UC_GET_OBJ(rc) ((rc)->o)
+
+/********************/
+/* Private routines */
+/********************/
+H5_DLL H5UC_t *H5UC_create(void *s, H5UC_free_func_t free_func);
+H5_DLL herr_t H5UC_decr(H5UC_t *rc);
+
+#endif /* _H5RSprivate_H */
+
+
diff --git a/src/H5VM.c b/src/H5VM.c
new file mode 100644
index 0000000..4c0b837
--- /dev/null
+++ b/src/H5VM.c
@@ -0,0 +1,1755 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, October 10, 1997
+ */
+
+
+#include "H5private.h"
+#include "H5Eprivate.h"
+#include "H5Oprivate.h"
+#include "H5VMprivate.h"
+
+/* Local typedefs */
+typedef struct H5VM_memcpy_ud_t {
+ unsigned char *dst; /* Pointer to destination buffer */
+ const unsigned char *src; /* Pointer to source buffer */
+} H5VM_memcpy_ud_t;
+
+/* Local macros */
+#define H5VM_HYPER_NDIMS H5O_LAYOUT_NDIMS
+
+/* Local prototypes */
+static void
+H5VM_stride_optimize1(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
+ const hsize_t *size, hsize_t *stride1);
+static void
+H5VM_stride_optimize2(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
+ const hsize_t *size, hsize_t *stride1, hsize_t *stride2);
+#ifdef LATER
+static void
+H5VM_stride_copy2(hsize_t nelmts, hsize_t elmt_size,
+ unsigned dst_n, const hsize_t *dst_size, const ssize_t *dst_stride, void *_dst,
+ unsigned src_n, const hsize_t *src_size, const ssize_t *src_stride, const void *_src);
+#endif /* LATER */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_optimize1
+ *
+ * Purpose: Given a stride vector which references elements of the
+ * specified size, optimize the dimensionality, the stride
+ * vector, and the element size to minimize the dimensionality
+ * and the number of memory accesses.
+ *
+ * All arguments are passed by reference and their values may be
+ * modified by this function.
+ *
+ * Return: None
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5VM_stride_optimize1(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
+ const hsize_t *size, hsize_t *stride1)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * This has to be true because if we optimize the dimensionality down to
+ * zero we still must make one reference.
+ */
+ HDassert(1 == H5VM_vector_reduce_product(0, NULL));
+
+ /*
+ * Combine adjacent memory accesses
+ */
+ while (*np && stride1[*np-1]>0 &&
+ (hsize_t)(stride1[*np-1])==*elmt_size) {
+ *elmt_size *= size[*np-1];
+ if (--*np)
+ stride1[*np-1] += size[*np] * stride1[*np];
+ }
+
+ FUNC_LEAVE_NOAPI_VOID
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_optimize2
+ *
+ * Purpose: Given two stride vectors which reference elements of the
+ * specified size, optimize the dimensionality, the stride
+ * vectors, and the element size to minimize the dimensionality
+ * and the number of memory accesses.
+ *
+ * All arguments are passed by reference and their values may be
+ * modified by this function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ * Unrolled loops for common cases
+ * Quincey Koziol
+ * ?, ? ?, 2001?
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5VM_stride_optimize2(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
+ const hsize_t *size, hsize_t *stride1, hsize_t *stride2)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * This has to be true because if we optimize the dimensionality down to
+ * zero we still must make one reference.
+ */
+ HDassert(1 == H5VM_vector_reduce_product(0, NULL));
+ HDassert(*elmt_size>0);
+
+ /*
+ * Combine adjacent memory accesses
+ */
+
+ /* Unroll loop for common cases */
+ switch(*np) {
+ case 1: /* For 0-D datasets (dunno if this ever gets used...) */
+ if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
+ *elmt_size *= size[0];
+ --*np; /* *np decrements to a value of 0 now */
+ } /* end if */
+ break;
+
+ case 2: /* For 1-D datasets */
+ if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
+ *elmt_size *= size[1];
+ --*np; /* *np decrements to a value of 1 now */
+ stride1[0] += size[1] * stride1[1];
+ stride2[0] += size[1] * stride2[1];
+
+ if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
+ *elmt_size *= size[0];
+ --*np; /* *np decrements to a value of 0 now */
+ } /* end if */
+ } /* end if */
+ break;
+
+ case 3: /* For 2-D datasets */
+ if(stride1[2] == *elmt_size && stride2[2] == *elmt_size) {
+ *elmt_size *= size[2];
+ --*np; /* *np decrements to a value of 2 now */
+ stride1[1] += size[2] * stride1[2];
+ stride2[1] += size[2] * stride2[2];
+
+ if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
+ *elmt_size *= size[1];
+ --*np; /* *np decrements to a value of 1 now */
+ stride1[0] += size[1] * stride1[1];
+ stride2[0] += size[1] * stride2[1];
+
+ if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
+ *elmt_size *= size[0];
+ --*np; /* *np decrements to a value of 0 now */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ break;
+
+ case 4: /* For 3-D datasets */
+ if(stride1[3] == *elmt_size && stride2[3] == *elmt_size) {
+ *elmt_size *= size[3];
+ --*np; /* *np decrements to a value of 3 now */
+ stride1[2] += size[3] * stride1[3];
+ stride2[2] += size[3] * stride2[3];
+
+ if(stride1[2] == *elmt_size && stride2[2] == *elmt_size) {
+ *elmt_size *= size[2];
+ --*np; /* *np decrements to a value of 2 now */
+ stride1[1] += size[2] * stride1[2];
+ stride2[1] += size[2] * stride2[2];
+
+ if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
+ *elmt_size *= size[1];
+ --*np; /* *np decrements to a value of 1 now */
+ stride1[0] += size[1] * stride1[1];
+ stride2[0] += size[1] * stride2[1];
+
+ if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
+ *elmt_size *= size[0];
+ --*np; /* *np decrements to a value of 0 now */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ } /* end if */
+ break;
+
+ default:
+ while (*np &&
+ stride1[*np-1] == *elmt_size &&
+ stride2[*np-1] == *elmt_size) {
+ *elmt_size *= size[*np-1];
+ if (--*np) {
+ stride1[*np-1] += size[*np] * stride1[*np];
+ stride2[*np-1] += size[*np] * stride2[*np];
+ }
+ }
+ break;
+ } /* end switch */
+
+ FUNC_LEAVE_NOAPI_VOID
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_hyper_stride
+ *
+ * Purpose: Given a description of a hyperslab, this function returns
+ * (through STRIDE[]) the byte strides appropriate for accessing
+ * all bytes of the hyperslab and the byte offset where the
+ * striding will begin. The SIZE can be passed to the various
+ * stride functions.
+ *
+ * The dimensionality of the whole array, the hyperslab, and the
+ * returned stride array is N. The whole array dimensions are
+ * TOTAL_SIZE and the hyperslab is at offset OFFSET and has
+ * dimensions SIZE.
+ *
+ * The stride and starting point returned will cause the
+ * hyperslab elements to be referenced in C order.
+ *
+ * Return: Success: Byte offset from beginning of array to start
+ * of striding.
+ *
+ * Failure: abort() -- should never fail
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ * Unrolled loops for common cases
+ * Quincey Koziol
+ * ?, ? ?, 2001?
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5VM_hyper_stride(unsigned n, const hsize_t *size,
+ const hsize_t *total_size, const hsize_t *offset,
+ hsize_t *stride/*out*/)
+{
+ hsize_t skip; /*starting point byte offset */
+ hsize_t acc; /*accumulator */
+ int i; /*counter */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(size);
+ HDassert(total_size);
+ HDassert(stride);
+
+ /* init */
+ HDassert(n>0);
+ stride[n-1] = 1;
+ skip = offset ? offset[n-1] : 0;
+
+ switch(n) {
+ case 2: /* 1-D dataset */
+ HDassert(total_size[1]>=size[1]);
+ stride[0] = total_size[1]-size[1]; /*overflow checked*/
+ acc = total_size[1];
+ skip += acc * (offset ? offset[0] : 0);
+ break;
+
+ case 3: /* 2-D dataset */
+ HDassert(total_size[2]>=size[2]);
+ stride[1] = total_size[2]-size[2]; /*overflow checked*/
+ acc = total_size[2];
+ skip += acc * (offset ? (hsize_t)offset[1] : 0);
+
+ HDassert(total_size[1]>=size[1]);
+ stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/
+ acc *= total_size[1];
+ skip += acc * (offset ? (hsize_t)offset[0] : 0);
+ break;
+
+ case 4: /* 3-D dataset */
+ HDassert(total_size[3]>=size[3]);
+ stride[2] = total_size[3]-size[3]; /*overflow checked*/
+ acc = total_size[3];
+ skip += acc * (offset ? (hsize_t)offset[2] : 0);
+
+ HDassert(total_size[2]>=size[2]);
+ stride[1] = acc * (total_size[2] - size[2]); /*overflow checked*/
+ acc *= total_size[2];
+ skip += acc * (offset ? (hsize_t)offset[1] : 0);
+
+ HDassert(total_size[1]>=size[1]);
+ stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/
+ acc *= total_size[1];
+ skip += acc * (offset ? (hsize_t)offset[0] : 0);
+ break;
+
+ default:
+ /* others */
+ for (i=(int)(n-2), acc=1; i>=0; --i) {
+ HDassert(total_size[i+1]>=size[i+1]);
+ stride[i] = acc * (total_size[i+1] - size[i+1]); /*overflow checked*/
+ acc *= total_size[i+1];
+ skip += acc * (offset ? (hsize_t)offset[i] : 0);
+ }
+ break;
+ } /* end switch */
+
+ /* Set return value */
+ ret_value=skip;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_hyper_eq
+ *
+ * Purpose: Determines whether two hyperslabs are equal. This function
+ * assumes that both hyperslabs are relative to the same array,
+ * for if not, they could not possibly be equal.
+ *
+ * Return: Success: TRUE if the hyperslabs are equal (that is,
+ * both refer to exactly the same elements of an
+ * array)
+ *
+ * FALSE otherwise.
+ *
+ * Failure: TRUE the rank is zero or if both hyperslabs
+ * are of zero size.
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 17, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5VM_hyper_eq(unsigned n,
+ const hsize_t *offset1, const hsize_t *size1,
+ const hsize_t *offset2, const hsize_t *size2)
+{
+ hsize_t nelmts1 = 1, nelmts2 = 1;
+ unsigned i;
+ htri_t ret_value=TRUE; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (n == 0) HGOTO_DONE(TRUE)
+
+ for (i=0; i<n; i++) {
+ if ((offset1 ? offset1[i] : 0) != (offset2 ? offset2[i] : 0))
+ HGOTO_DONE(FALSE)
+ if ((size1 ? size1[i] : 0) != (size2 ? size2[i] : 0))
+ HGOTO_DONE(FALSE)
+ if (0 == (nelmts1 *= (size1 ? size1[i] : 0)))
+ HGOTO_DONE(FALSE)
+ if (0 == (nelmts2 *= (size2 ? size2[i] : 0)))
+ HGOTO_DONE(FALSE)
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_hyper_fill
+ *
+ * Purpose: Similar to memset() except it operates on hyperslabs...
+ *
+ * Fills a hyperslab of array BUF with some value VAL. BUF
+ * is treated like a C-order array with N dimensions where the
+ * size of each dimension is TOTAL_SIZE[]. The hyperslab which
+ * will be filled with VAL begins at byte offset OFFSET[] from
+ * the minimum corner of BUF and continues for SIZE[] bytes in
+ * each dimension.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_hyper_fill(unsigned n, const hsize_t *_size,
+ const hsize_t *total_size, const hsize_t *offset, void *_dst,
+ unsigned fill_value)
+{
+ uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic */
+ hsize_t size[H5VM_HYPER_NDIMS]; /*a modifiable copy of _size */
+ hsize_t dst_stride[H5VM_HYPER_NDIMS]; /*destination stride info */
+ hsize_t dst_start; /*byte offset to start of stride*/
+ hsize_t elmt_size = 1; /*bytes per element */
+ herr_t ret_value; /*function return status */
+#ifndef NDEBUG
+ unsigned u;
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(n > 0 && n <= H5VM_HYPER_NDIMS);
+ HDassert(_size);
+ HDassert(total_size);
+ HDassert(dst);
+#ifndef NDEBUG
+ for (u = 0; u < n; u++) {
+ HDassert(_size[u] > 0);
+ HDassert(total_size[u] > 0);
+ }
+#endif
+
+ /* Copy the size vector so we can modify it */
+ H5VM_vector_cpy(n, size, _size);
+
+ /* Compute an optimal destination stride vector */
+ dst_start = H5VM_hyper_stride(n, size, total_size, offset, dst_stride);
+ H5VM_stride_optimize1(&n, &elmt_size, size, dst_stride);
+
+ /* Copy */
+ ret_value = H5VM_stride_fill(n, elmt_size, size, dst_stride, dst+dst_start,
+ fill_value);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_hyper_copy
+ *
+ * Purpose: Copies a hyperslab from the source to the destination.
+ *
+ * A hyperslab is a logically contiguous region of
+ * multi-dimensional size SIZE of an array whose dimensionality
+ * is N and whose total size is DST_TOTAL_SIZE or SRC_TOTAL_SIZE.
+ * The minimum corner of the hyperslab begins at a
+ * multi-dimensional offset from the minimum corner of the DST
+ * (destination) or SRC (source) array. The sizes and offsets
+ * are assumed to be in C order, that is, the first size/offset
+ * varies the slowest while the last varies the fastest in the
+ * mapping from N-dimensional space to linear space. This
+ * function assumes that the array elements are single bytes (if
+ * your array has multi-byte elements then add an additional
+ * dimension whose size is that of your element).
+ *
+ * The SRC and DST array may be the same array, but the results
+ * are undefined if the source hyperslab overlaps the
+ * destination hyperslab.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ * Unrolled loops for common cases
+ * Quincey Koziol
+ * ?, ? ?, 2001?
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_hyper_copy(unsigned n, const hsize_t *_size,
+
+ /*destination*/
+ const hsize_t *dst_size, const hsize_t *dst_offset,
+ void *_dst,
+
+ /*source*/
+ const hsize_t *src_size, const hsize_t *src_offset,
+ const void *_src)
+{
+ const uint8_t *src = (const uint8_t*)_src; /*cast for ptr arithmtc */
+ uint8_t *dst = (uint8_t*) _dst; /*cast for ptr arithmtc */
+ hsize_t size[H5VM_HYPER_NDIMS]; /*a modifiable _size */
+ hsize_t src_stride[H5VM_HYPER_NDIMS]; /*source stride info */
+ hsize_t dst_stride[H5VM_HYPER_NDIMS]; /*dest stride info */
+ hsize_t dst_start, src_start; /*offset to start at */
+ hsize_t elmt_size = 1; /*element size in bytes */
+ herr_t ret_value; /*return status */
+#ifndef NDEBUG
+ unsigned u;
+#endif
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(n > 0 && n <= H5VM_HYPER_NDIMS);
+ HDassert(_size);
+ HDassert(dst_size);
+ HDassert(src_size);
+ HDassert(dst);
+ HDassert(src);
+#ifndef NDEBUG
+ for (u = 0; u < n; u++) {
+ HDassert(_size[u] > 0);
+ HDassert(dst_size[u] > 0);
+ HDassert(src_size[u] > 0);
+ }
+#endif
+
+ /* Copy the size vector so we can modify it */
+ H5VM_vector_cpy(n, size, _size);
+
+ /* Compute stride vectors for source and destination */
+#ifdef NO_INLINED_CODE
+ dst_start = H5VM_hyper_stride(n, size, dst_size, dst_offset, dst_stride);
+ src_start = H5VM_hyper_stride(n, size, src_size, src_offset, src_stride);
+#else /* NO_INLINED_CODE */
+ /* in-line version of two calls to H5VM_hyper_stride() */
+ {
+ hsize_t dst_acc; /*accumulator */
+ hsize_t src_acc; /*accumulator */
+ int ii; /*counter */
+
+ /* init */
+ HDassert(n>0);
+ dst_stride[n-1] = 1;
+ src_stride[n-1] = 1;
+ dst_start = dst_offset ? dst_offset[n-1] : 0;
+ src_start = src_offset ? src_offset[n-1] : 0;
+
+ /* Unroll loop for common cases */
+ switch(n) {
+ case 2:
+ HDassert(dst_size[1]>=size[1]);
+ HDassert(src_size[1]>=size[1]);
+ dst_stride[0] = dst_size[1] - size[1]; /*overflow checked*/
+ src_stride[0] = src_size[1] - size[1]; /*overflow checked*/
+ dst_acc = dst_size[1];
+ src_acc = src_size[1];
+ dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
+ src_start += src_acc * (src_offset ? src_offset[0] : 0);
+ break;
+
+ case 3:
+ HDassert(dst_size[2]>=size[2]);
+ HDassert(src_size[2]>=size[2]);
+ dst_stride[1] = dst_size[2] - size[2]; /*overflow checked*/
+ src_stride[1] = src_size[2] - size[2]; /*overflow checked*/
+ dst_acc = dst_size[2];
+ src_acc = src_size[2];
+ dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0);
+ src_start += src_acc * (src_offset ? src_offset[1] : 0);
+
+ HDassert(dst_size[1]>=size[1]);
+ HDassert(src_size[1]>=size[1]);
+ dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/
+ src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/
+ dst_acc *= dst_size[1];
+ src_acc *= src_size[1];
+ dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
+ src_start += src_acc * (src_offset ? src_offset[0] : 0);
+ break;
+
+ case 4:
+ HDassert(dst_size[3]>=size[3]);
+ HDassert(src_size[3]>=size[3]);
+ dst_stride[2] = dst_size[3] - size[3]; /*overflow checked*/
+ src_stride[2] = src_size[3] - size[3]; /*overflow checked*/
+ dst_acc = dst_size[3];
+ src_acc = src_size[3];
+ dst_start += dst_acc * (dst_offset ? dst_offset[2] : 0);
+ src_start += src_acc * (src_offset ? src_offset[2] : 0);
+
+ HDassert(dst_size[2]>=size[2]);
+ HDassert(src_size[2]>=size[2]);
+ dst_stride[1] = dst_acc * (dst_size[2] - size[2]); /*overflow checked*/
+ src_stride[1] = src_acc * (src_size[2] - size[2]); /*overflow checked*/
+ dst_acc *= dst_size[2];
+ src_acc *= src_size[2];
+ dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0);
+ src_start += src_acc * (src_offset ? src_offset[1] : 0);
+
+ HDassert(dst_size[1]>=size[1]);
+ HDassert(src_size[1]>=size[1]);
+ dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/
+ src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/
+ dst_acc *= dst_size[1];
+ src_acc *= src_size[1];
+ dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
+ src_start += src_acc * (src_offset ? src_offset[0] : 0);
+ break;
+
+ default:
+ /* others */
+ for (ii=(int)(n-2), dst_acc=1, src_acc=1; ii>=0; --ii) {
+ HDassert(dst_size[ii+1]>=size[ii+1]);
+ HDassert(src_size[ii+1]>=size[ii+1]);
+ dst_stride[ii] = dst_acc * (dst_size[ii+1] - size[ii+1]); /*overflow checked*/
+ src_stride[ii] = src_acc * (src_size[ii+1] - size[ii+1]); /*overflow checked*/
+ dst_acc *= dst_size[ii+1];
+ src_acc *= src_size[ii+1];
+ dst_start += dst_acc * (dst_offset ? dst_offset[ii] : 0);
+ src_start += src_acc * (src_offset ? src_offset[ii] : 0);
+ }
+ break;
+ } /* end switch */
+ }
+#endif /* NO_INLINED_CODE */
+
+ /* Optimize the strides as a pair */
+ H5VM_stride_optimize2(&n, &elmt_size, size, dst_stride, src_stride);
+
+ /* Perform the copy in terms of stride */
+ ret_value = H5VM_stride_copy(n, elmt_size, size,
+ dst_stride, dst+dst_start, src_stride, src+src_start);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_fill
+ *
+ * Purpose: Fills all bytes of a hyperslab with the same value using
+ * memset().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_stride_fill(unsigned n, hsize_t elmt_size, const hsize_t *size,
+ const hsize_t *stride, void *_dst, unsigned fill_value)
+{
+ uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic */
+ hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */
+ hsize_t nelmts; /*number of elements to fill */
+ hsize_t i; /*counter */
+ int j; /*counter */
+ hbool_t carry; /*subtraction carray value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(elmt_size < SIZET_MAX);
+
+ H5VM_vector_cpy(n, idx, size);
+ nelmts = H5VM_vector_reduce_product(n, size);
+ for (i=0; i<nelmts; i++) {
+ /* Copy an element */
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemset(dst, (int)fill_value, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+
+ /* Decrement indices and advance pointer */
+ for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
+ dst += stride[j];
+
+ if (--idx[j])
+ carry = FALSE;
+ else {
+ HDassert(size);
+ idx[j] = size[j];
+ } /* end else */
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_copy
+ *
+ * Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays
+ * DST and SRC while copying bytes from SRC to DST. This
+ * function minimizes the number of calls to memcpy() by
+ * combining various strides, but it will never touch memory
+ * outside the hyperslab defined by the strides.
+ *
+ * Note: If the src_stride is all zero and elmt_size is one, then it's
+ * probably more efficient to use H5VM_stride_fill() instead.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_stride_copy(unsigned n, hsize_t elmt_size, const hsize_t *size,
+ const hsize_t *dst_stride, void *_dst,
+ const hsize_t *src_stride, const void *_src)
+{
+ uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic*/
+ const uint8_t *src = (const uint8_t*) _src; /*cast for ptr arithmetic*/
+ hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */
+ hsize_t nelmts; /*num elements to copy */
+ hsize_t i; /*counter */
+ int j; /*counters */
+ hbool_t carry; /*carray for subtraction*/
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(elmt_size<SIZET_MAX);
+
+ if (n) {
+ H5VM_vector_cpy(n, idx, size);
+ nelmts = H5VM_vector_reduce_product(n, size);
+ for (i=0; i<nelmts; i++) {
+
+ /* Copy an element */
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+
+ /* Decrement indices and advance pointers */
+ for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
+ src += src_stride[j];
+ dst += dst_stride[j];
+
+ if (--idx[j])
+ carry = FALSE;
+ else {
+ HDassert(size);
+ idx[j] = size[j];
+ }
+ }
+ }
+ } else {
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemcpy (dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_copy_s
+ *
+ * Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays
+ * DST and SRC while copying bytes from SRC to DST. This
+ * function minimizes the number of calls to memcpy() by
+ * combining various strides, but it will never touch memory
+ * outside the hyperslab defined by the strides.
+ *
+ * Note: If the src_stride is all zero and elmt_size is one, then it's
+ * probably more efficient to use H5VM_stride_fill() instead.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_stride_copy_s(unsigned n, hsize_t elmt_size, const hsize_t *size,
+ const hssize_t *dst_stride, void *_dst,
+ const hssize_t *src_stride, const void *_src)
+{
+ uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic*/
+ const uint8_t *src = (const uint8_t*) _src; /*cast for ptr arithmetic*/
+ hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */
+ hsize_t nelmts; /*num elements to copy */
+ hsize_t i; /*counter */
+ int j; /*counters */
+ hbool_t carry; /*carray for subtraction*/
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(elmt_size<SIZET_MAX);
+
+ if (n) {
+ H5VM_vector_cpy(n, idx, size);
+ nelmts = H5VM_vector_reduce_product(n, size);
+ for (i=0; i<nelmts; i++) {
+
+ /* Copy an element */
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+
+ /* Decrement indices and advance pointers */
+ for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
+ src += src_stride[j];
+ dst += dst_stride[j];
+
+ if (--idx[j])
+ carry = FALSE;
+ else {
+ HDassert(size);
+ idx[j] = size[j];
+ }
+ }
+ }
+ } else {
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemcpy (dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+}
+
+#ifdef LATER
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_stride_copy2
+ *
+ * Purpose: Similar to H5VM_stride_copy() except the source and
+ * destination each have their own dimensionality and size and
+ * we copy exactly NELMTS elements each of size ELMT_SIZE. The
+ * size counters wrap if NELMTS is more than a size counter.
+ *
+ * Return: None
+ *
+ * Programmer: Robb Matzke
+ * Saturday, October 11, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5VM_stride_copy2(hsize_t nelmts, hsize_t elmt_size,
+
+ /* destination */
+ unsigned dst_n, const hsize_t *dst_size,
+ const hsize_t *dst_stride,
+ void *_dst,
+
+ /* source */
+ unsigned src_n, const hsize_t *src_size,
+ const hsize_t *src_stride,
+ const void *_src)
+{
+ uint8_t *dst = (uint8_t *) _dst;
+ const uint8_t *src = (const uint8_t *) _src;
+ hsize_t dst_idx[H5VM_HYPER_NDIMS];
+ hsize_t src_idx[H5VM_HYPER_NDIMS];
+ hsize_t i; /* Local index variable */
+ int j; /* Local index variable */
+ hbool_t carry;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(elmt_size < SIZET_MAX);
+ HDassert(dst_n>0);
+ HDassert(src_n>0);
+
+ H5VM_vector_cpy(dst_n, dst_idx, dst_size);
+ H5VM_vector_cpy(src_n, src_idx, src_size);
+
+ for (i=0; i<nelmts; i++) {
+
+ /* Copy an element */
+ H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
+ HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
+
+ /* Decrement indices and advance pointers */
+ for (j=(int)(dst_n-1), carry=TRUE; j>=0 && carry; --j) {
+ dst += dst_stride[j];
+ if (--dst_idx[j])
+ carry = FALSE;
+ else {
+ HDassert(dst_size);
+ dst_idx[j] = dst_size[j];
+ } /* end else */
+ }
+ for (j=(int)(src_n-1), carry=TRUE; j>=0 && carry; --j) {
+ src += src_stride[j];
+ if (--src_idx[j])
+ carry = FALSE;
+ else {
+ HDassert(src_size);
+ src_idx[j] = src_size[j];
+ } /* end else */
+ }
+ }
+
+ FUNC_LEAVE_NOAPI_VOID
+}
+#endif /* LATER */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_fill
+ *
+ * Purpose: Fills all bytes of an array with the same value using
+ * memset(). Increases amount copied by power of two until the
+ * halfway point is crossed, then copies the rest in one swoop.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 18, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_array_fill(void *_dst, const void *src, size_t size, size_t count)
+{
+ size_t copy_size; /* size of the buffer to copy */
+ size_t copy_items; /* number of items currently copying*/
+ size_t items_left; /* number of items left to copy */
+ uint8_t *dst=(uint8_t*)_dst;/* alias for pointer arithmetic */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(dst);
+ HDassert(src);
+ HDassert(size < SIZET_MAX && size > 0);
+ HDassert(count < SIZET_MAX && count > 0);
+
+ HDmemcpy(dst, src, size); /* copy first item */
+
+ /* Initialize counters, etc. while compensating for first element copied */
+ copy_size = size;
+ copy_items = 1;
+ items_left = count - 1;
+ dst += size;
+
+ /* copy until we've copied at least half of the items */
+ while (items_left >= copy_items)
+ {
+ HDmemcpy(dst, _dst, copy_size); /* copy the current chunk */
+ dst += copy_size; /* move the offset for the next chunk */
+ items_left -= copy_items; /* decrement the number of items left */
+
+ copy_size *= 2; /* increase the size of the chunk to copy */
+ copy_items *= 2; /* increase the count of items we are copying */
+ } /* end while */
+ if (items_left > 0) /* if there are any items left to copy */
+ HDmemcpy(dst, _dst, items_left * size);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5VM_array_fill() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_down
+ *
+ * Purpose: Given a set of dimension sizes, calculate the size of each
+ * "down" slice. This is the size of the dimensions for all the
+ * dimensions below the current one, which is used for indexing
+ * offsets in this dimension.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 28, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_array_down(unsigned n, const hsize_t *total_size, hsize_t *down)
+{
+ hsize_t acc; /*accumulator */
+ int i; /*counter */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(total_size);
+ HDassert(down);
+
+ /* Build the sizes of each dimension in the array */
+ /* (From fastest to slowest) */
+ for(i=(int)(n-1),acc=1; i>=0; i--) {
+ down[i]=acc;
+ acc *= total_size[i];
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5VM_array_down() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_offset_pre
+ *
+ * Purpose: Given a coordinate description of a location in an array, this
+ * function returns the byte offset of the coordinate.
+ *
+ * The dimensionality of the whole array, and the offset is N.
+ * The whole array dimensions are TOTAL_SIZE and the coordinate
+ * is at offset OFFSET.
+ *
+ * Return: Success: Byte offset from beginning of array to element offset
+ * Failure: abort() -- should never fail
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 22, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5VM_array_offset_pre(unsigned n, const hsize_t *acc, const hsize_t *offset)
+{
+ unsigned u; /* Local index variable */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(acc);
+ HDassert(offset);
+
+ /* Compute offset in array */
+ for(u = 0, ret_value = 0; u < n; u++)
+ ret_value += acc[u] * offset[u];
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5VM_array_offset_pre() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_offset
+ *
+ * Purpose: Given a coordinate description of a location in an array, this
+ * function returns the byte offset of the coordinate.
+ *
+ * The dimensionality of the whole array, and the offset is N.
+ * The whole array dimensions are TOTAL_SIZE and the coordinate
+ * is at offset OFFSET.
+ *
+ * Return: Success: Byte offset from beginning of array to element offset
+ * Failure: abort() -- should never fail
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, June 22, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5VM_array_offset(unsigned n, const hsize_t *total_size, const hsize_t *offset)
+{
+ hsize_t acc_arr[H5VM_HYPER_NDIMS]; /* Accumulated size of down dimensions */
+ hsize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI((HDabort(), 0)) /*lint !e527 Don't worry about unreachable statement */
+
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(total_size);
+ HDassert(offset);
+
+ /* Build the sizes of each dimension in the array */
+ if(H5VM_array_down(n,total_size,acc_arr)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, UFAIL, "can't compute down sizes")
+
+ /* Set return value */
+ ret_value=H5VM_array_offset_pre(n,acc_arr,offset);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5VM_array_offset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_calc_pre
+ *
+ * Purpose: Given a linear offset in an array, the dimensions of that
+ * array and the pre-computed 'down' (accumulator) sizes, this
+ * function computes the coordinates of that offset in the array.
+ *
+ * The dimensionality of the whole array, and the coordinates is N.
+ * The array dimensions are TOTAL_SIZE and the coordinates
+ * are returned in COORD. The linear offset is in OFFSET.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, July 16, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *down,
+ hsize_t *coords)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(coords);
+
+ /* Compute the coordinates from the offset */
+ for(u = 0; u < n; u++) {
+ coords[u] = offset / down[u];
+ offset %= down[u];
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5VM_array_calc_pre() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_array_calc
+ *
+ * Purpose: Given a linear offset in an array and the dimensions of that
+ * array, this function computes the coordinates of that offset
+ * in the array.
+ *
+ * The dimensionality of the whole array, and the coordinates is N.
+ * The array dimensions are TOTAL_SIZE and the coordinates
+ * are returned in COORD. The linear offset is in OFFSET.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, April 16, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5VM_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *coords)
+{
+ hsize_t idx[H5VM_HYPER_NDIMS]; /* Size of each dimension in bytes */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(n <= H5VM_HYPER_NDIMS);
+ HDassert(total_size);
+ HDassert(coords);
+
+ /* Build the sizes of each dimension in the array */
+ if(H5VM_array_down(n, total_size, idx) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute down sizes")
+
+ /* Compute the coordinates from the offset */
+ if(H5VM_array_calc_pre(offset, n, idx, coords) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute coordinates")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5VM_array_calc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_chunk_index
+ *
+ * Purpose: Given a coordinate offset (COORD), the size of each chunk
+ * (CHUNK), the number of chunks in each dimension (NCHUNKS)
+ * and the number of dimensions of all of these (NDIMS), calculate
+ * a "chunk index" for the chunk that the coordinate offset is
+ * located in.
+ *
+ * The chunk index starts at 0 and increases according to the
+ * fastest changing dimension, then the next fastest, etc.
+ *
+ * For example, with a 3x5 chunk size and 6 chunks in the fastest
+ * changing dimension and 3 chunks in the slowest changing
+ * dimension, the chunk indices are as follows:
+ *
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 0 | 1 | 2 | 3 | 4 | 5 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 6 | 7 | 8 | 9 | 10 | 11 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 12 | 13 | 14 | 15 | 16 | 17 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ *
+ * The chunk index is placed in the CHUNK_IDX location for return
+ * from this function
+ *
+ * Return: Chunk index on success (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 21, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5VM_chunk_index(unsigned ndims, const hsize_t *coord, const uint32_t *chunk,
+ const hsize_t *down_nchunks)
+{
+ hsize_t scaled_coord[H5VM_HYPER_NDIMS]; /* Scaled, coordinates, in terms of chunks */
+ hsize_t chunk_idx; /* Chunk index computed */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(ndims <= H5VM_HYPER_NDIMS);
+ HDassert(coord);
+ HDassert(chunk);
+ HDassert(down_nchunks);
+
+ /* Defer to H5VM_chunk_index_scaled */
+ chunk_idx = H5VM_chunk_index_scaled(ndims, coord, chunk, down_nchunks, scaled_coord);
+
+ FUNC_LEAVE_NOAPI(chunk_idx)
+} /* end H5VM_chunk_index() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_chunk_scaled
+ *
+ * Purpose: Compute the scaled coordinates for a chunk offset
+ *
+ * Return: <none>
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, November 19, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5VM_chunk_scaled(unsigned ndims, const hsize_t *coord, const uint32_t *chunk,
+ hsize_t *scaled)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(ndims <= H5VM_HYPER_NDIMS);
+ HDassert(coord);
+ HDassert(chunk);
+ HDassert(scaled);
+
+ /* Compute the scaled coordinates for actual coordinates */
+ /* (Note that the 'scaled' array is an 'OUT' parameter) */
+ for(u = 0; u < ndims; u++)
+ scaled[u] = coord[u] / chunk[u];
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5VM_chunk_scaled() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_chunk_index_scaled
+ *
+ * Purpose: Given a coordinate offset (COORD), the size of each chunk
+ * (CHUNK), the number of chunks in each dimension (NCHUNKS)
+ * and the number of dimensions of all of these (NDIMS), calculate
+ * a "chunk index" for the chunk that the coordinate offset is
+ * located in.
+ *
+ * The chunk index starts at 0 and increases according to the
+ * fastest changing dimension, then the next fastest, etc.
+ *
+ * For example, with a 3x5 chunk size and 6 chunks in the fastest
+ * changing dimension and 3 chunks in the slowest changing
+ * dimension, the chunk indices are as follows:
+ *
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 0 | 1 | 2 | 3 | 4 | 5 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 6 | 7 | 8 | 9 | 10 | 11 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ * | | | | | | |
+ * | 12 | 13 | 14 | 15 | 16 | 17 |
+ * | | | | | | |
+ * +-----+-----+-----+-----+-----+-----+
+ *
+ * The chunk index is placed in the CHUNK_IDX location for return
+ * from this function
+ *
+ * Note: This routine is identical to H5VM_chunk_index(), except for
+ * caching the scaled information. Make changes in both places.
+ *
+ * Return: Chunk index on success (can't fail)
+ *
+ * Programmer: Vailin Choi
+ * Monday, February 9, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+H5VM_chunk_index_scaled(unsigned ndims, const hsize_t *coord, const uint32_t *chunk,
+ const hsize_t *down_nchunks, hsize_t *scaled)
+{
+ hsize_t chunk_idx; /* Computed chunk index */
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(ndims <= H5VM_HYPER_NDIMS);
+ HDassert(coord);
+ HDassert(chunk);
+ HDassert(down_nchunks);
+ HDassert(scaled);
+
+ /* Compute the scaled coordinates for actual coordinates */
+ /* (Note that the 'scaled' array is an 'OUT' parameter) */
+ for(u = 0; u < ndims; u++)
+ scaled[u] = coord[u] / chunk[u];
+
+ /* Compute the chunk index */
+ chunk_idx = H5VM_array_offset_pre(ndims, down_nchunks, scaled); /*lint !e772 scaled_coord will always be initialized */
+
+ FUNC_LEAVE_NOAPI(chunk_idx)
+} /* end H5VM_chunk_index_scaled() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_opvv
+ *
+ * Purpose: Perform an operation on a source & destination sequences
+ * of offset/length pairs. Each set of sequnces has an array
+ * of lengths, an array of offsets, the maximum number of
+ * sequences and the current sequence to start at in the sequence.
+ *
+ * There may be different numbers of bytes in the source and
+ * destination sequences, the operation stops when either the
+ * source or destination sequence runs out of information.
+ *
+ * Note: The algorithm in this routine is [basically] the same as for
+ * H5VM_memcpyvv(). Changes should be made to both!
+ *
+ * Return: Non-negative # of bytes operated on, on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, September 30, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5VM_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[],
+ hsize_t dst_off_arr[],
+ size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[],
+ hsize_t src_off_arr[],
+ H5VM_opvv_func_t op, void *op_data)
+{
+ hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */
+ hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */
+ size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */
+ hsize_t tmp_dst_off, tmp_src_off; /* Temporary source and destination offset values */
+ size_t tmp_dst_len, tmp_src_len; /* Temporary source and destination length values */
+ size_t acc_len; /* Accumulated length of sequences */
+ ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(dst_curr_seq);
+ HDassert(*dst_curr_seq < dst_max_nseq);
+ HDassert(dst_len_arr);
+ HDassert(dst_off_arr);
+ HDassert(src_curr_seq);
+ HDassert(*src_curr_seq < src_max_nseq);
+ HDassert(src_len_arr);
+ HDassert(src_off_arr);
+ HDassert(op);
+
+ /* Set initial offset & length pointers */
+ dst_len_ptr = dst_len_arr + *dst_curr_seq;
+ dst_off_ptr = dst_off_arr + *dst_curr_seq;
+ src_len_ptr = src_len_arr + *src_curr_seq;
+ src_off_ptr = src_off_arr + *src_curr_seq;
+
+ /* Get temporary source & destination sequence offsets & lengths */
+ tmp_dst_len = *dst_len_ptr;
+ tmp_dst_off = *dst_off_ptr;
+ tmp_src_len = *src_len_ptr;
+ tmp_src_off = *src_off_ptr;
+
+ /* Compute maximum offset pointer values */
+ max_dst_off_ptr = dst_off_arr + dst_max_nseq;
+ max_src_off_ptr = src_off_arr + src_max_nseq;
+
+/* Work through the sequences */
+/* (Choose smallest sequence available initially) */
+
+ /* Source sequence is less than destination sequence */
+ if(tmp_src_len < tmp_dst_len) {
+src_smaller:
+ acc_len = 0;
+ do {
+ /* Make operator callback */
+ if((*op)(tmp_dst_off, tmp_src_off, tmp_src_len, op_data) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation")
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_src_len;
+
+ /* Update destination length */
+ tmp_dst_off += tmp_src_len;
+ tmp_dst_len -= tmp_src_len;
+
+ /* Advance source offset & check for being finished */
+ src_off_ptr++;
+ if(src_off_ptr >= max_src_off_ptr) {
+ /* Roll accumulated changes into appropriate counters */
+ *dst_off_ptr = tmp_dst_off;
+ *dst_len_ptr = tmp_dst_len;
+
+ /* Done with sequences */
+ goto finished;
+ } /* end if */
+ tmp_src_off = *src_off_ptr;
+
+ /* Update source information */
+ src_len_ptr++;
+ tmp_src_len = *src_len_ptr;
+ } while(tmp_src_len < tmp_dst_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_dst_len < tmp_src_len)
+ goto dst_smaller;
+ else
+ goto equal;
+ } /* end if */
+ /* Destination sequence is less than source sequence */
+ else if(tmp_dst_len < tmp_src_len) {
+dst_smaller:
+ acc_len = 0;
+ do {
+ /* Make operator callback */
+ if((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation")
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_dst_len;
+
+ /* Update source length */
+ tmp_src_off += tmp_dst_len;
+ tmp_src_len -= tmp_dst_len;
+
+ /* Advance destination offset & check for being finished */
+ dst_off_ptr++;
+ if(dst_off_ptr >= max_dst_off_ptr) {
+ /* Roll accumulated changes into appropriate counters */
+ *src_off_ptr = tmp_src_off;
+ *src_len_ptr = tmp_src_len;
+
+ /* Done with sequences */
+ goto finished;
+ } /* end if */
+ tmp_dst_off = *dst_off_ptr;
+
+ /* Update destination information */
+ dst_len_ptr++;
+ tmp_dst_len = *dst_len_ptr;
+ } while(tmp_dst_len < tmp_src_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_src_len < tmp_dst_len)
+ goto src_smaller;
+ else
+ goto equal;
+ } /* end else-if */
+ /* Destination sequence and source sequence are same length */
+ else {
+equal:
+ acc_len = 0;
+ do {
+ /* Make operator callback */
+ if((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation")
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_dst_len;
+
+ /* Advance source & destination offset & check for being finished */
+ src_off_ptr++;
+ dst_off_ptr++;
+ if(src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr)
+ /* Done with sequences */
+ goto finished;
+ tmp_src_off = *src_off_ptr;
+ tmp_dst_off = *dst_off_ptr;
+
+ /* Update source information */
+ src_len_ptr++;
+ tmp_src_len = *src_len_ptr;
+
+ /* Update destination information */
+ dst_len_ptr++;
+ tmp_dst_len = *dst_len_ptr;
+ } while(tmp_dst_len == tmp_src_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_dst_len < tmp_src_len)
+ goto dst_smaller;
+ else
+ goto src_smaller;
+ } /* end else */
+
+finished:
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Update current sequence vectors */
+ *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr);
+ *src_curr_seq = (size_t)(src_off_ptr - src_off_arr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5VM_opvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_memcpyvv
+ *
+ * Purpose: Given source and destination buffers in memory (SRC & DST)
+ * copy sequences of from the source buffer into the destination
+ * buffer. Each set of sequnces has an array of lengths, an
+ * array of offsets, the maximum number of sequences and the
+ * current sequence to start at in the sequence.
+ *
+ * There may be different numbers of bytes in the source and
+ * destination sequences, data copying stops when either the
+ * source or destination buffer runs out of sequence information.
+ *
+ * Note: The algorithm in this routine is [basically] the same as for
+ * H5VM_opvv(). Changes should be made to both!
+ *
+ * Return: Non-negative # of bytes copied on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 2, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5VM_memcpyvv(void *_dst,
+ size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], hsize_t dst_off_arr[],
+ const void *_src,
+ size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], hsize_t src_off_arr[])
+{
+ unsigned char *dst; /* Destination buffer pointer */
+ const unsigned char *src; /* Source buffer pointer */
+ hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */
+ hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */
+ size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */
+ size_t tmp_dst_len; /* Temporary dest. length value */
+ size_t tmp_src_len; /* Temporary source length value */
+ size_t acc_len; /* Accumulated length of sequences */
+ ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(_dst);
+ HDassert(dst_curr_seq);
+ HDassert(*dst_curr_seq < dst_max_nseq);
+ HDassert(dst_len_arr);
+ HDassert(dst_off_arr);
+ HDassert(_src);
+ HDassert(src_curr_seq);
+ HDassert(*src_curr_seq < src_max_nseq);
+ HDassert(src_len_arr);
+ HDassert(src_off_arr);
+
+ /* Set initial offset & length pointers */
+ dst_len_ptr = dst_len_arr + *dst_curr_seq;
+ dst_off_ptr = dst_off_arr + *dst_curr_seq;
+ src_len_ptr = src_len_arr + *src_curr_seq;
+ src_off_ptr = src_off_arr + *src_curr_seq;
+
+ /* Get temporary source & destination sequence lengths */
+ tmp_dst_len = *dst_len_ptr;
+ tmp_src_len = *src_len_ptr;
+
+ /* Compute maximum offset pointer values */
+ max_dst_off_ptr = dst_off_arr + dst_max_nseq;
+ max_src_off_ptr = src_off_arr + src_max_nseq;
+
+ /* Compute buffer offsets */
+ dst = (unsigned char *)_dst + *dst_off_ptr;
+ src = (const unsigned char *)_src + *src_off_ptr;
+
+/* Work through the sequences */
+/* (Choose smallest sequence available initially) */
+
+ /* Source sequence is less than destination sequence */
+ if(tmp_src_len < tmp_dst_len) {
+src_smaller:
+ acc_len = 0;
+ do {
+ /* Copy data */
+ HDmemcpy(dst, src, tmp_src_len);
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_src_len;
+
+ /* Update destination length */
+ tmp_dst_len -= tmp_src_len;
+
+ /* Advance source offset & check for being finished */
+ src_off_ptr++;
+ if(src_off_ptr >= max_src_off_ptr) {
+ /* Roll accumulated changes into appropriate counters */
+ *dst_off_ptr += acc_len;
+ *dst_len_ptr = tmp_dst_len;
+
+ /* Done with sequences */
+ goto finished;
+ } /* end if */
+
+ /* Update destination pointer */
+ dst += tmp_src_len;
+
+ /* Update source information */
+ src_len_ptr++;
+ tmp_src_len = *src_len_ptr;
+ src = (const unsigned char *)_src + *src_off_ptr;
+ } while(tmp_src_len < tmp_dst_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_dst_len < tmp_src_len)
+ goto dst_smaller;
+ else
+ goto equal;
+ } /* end if */
+ /* Destination sequence is less than source sequence */
+ else if(tmp_dst_len < tmp_src_len) {
+dst_smaller:
+ acc_len = 0;
+ do {
+ /* Copy data */
+ HDmemcpy(dst, src, tmp_dst_len);
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_dst_len;
+
+ /* Update source length */
+ tmp_src_len -= tmp_dst_len;
+
+ /* Advance destination offset & check for being finished */
+ dst_off_ptr++;
+ if(dst_off_ptr >= max_dst_off_ptr) {
+ /* Roll accumulated changes into appropriate counters */
+ *src_off_ptr += acc_len;
+ *src_len_ptr = tmp_src_len;
+
+ /* Done with sequences */
+ goto finished;
+ } /* end if */
+
+ /* Update source pointer */
+ src += tmp_dst_len;
+
+ /* Update destination information */
+ dst_len_ptr++;
+ tmp_dst_len = *dst_len_ptr;
+ dst = (unsigned char *)_dst + *dst_off_ptr;
+ } while(tmp_dst_len < tmp_src_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_src_len < tmp_dst_len)
+ goto src_smaller;
+ else
+ goto equal;
+ } /* end else-if */
+ /* Destination sequence and source sequence are same length */
+ else {
+equal:
+ acc_len = 0;
+ do {
+ /* Copy data */
+ HDmemcpy(dst, src, tmp_dst_len);
+
+ /* Accumulate number of bytes copied */
+ acc_len += tmp_dst_len;
+
+ /* Advance source & destination offset & check for being finished */
+ src_off_ptr++;
+ dst_off_ptr++;
+ if(src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr)
+ /* Done with sequences */
+ goto finished;
+
+ /* Update source information */
+ src_len_ptr++;
+ tmp_src_len = *src_len_ptr;
+ src = (const unsigned char *)_src + *src_off_ptr;
+
+ /* Update destination information */
+ dst_len_ptr++;
+ tmp_dst_len = *dst_len_ptr;
+ dst = (unsigned char *)_dst + *dst_off_ptr;
+ } while(tmp_dst_len == tmp_src_len);
+
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Transition to next state */
+ if(tmp_dst_len < tmp_src_len)
+ goto dst_smaller;
+ else
+ goto src_smaller;
+ } /* end else */
+
+finished:
+ /* Roll accumulated sequence lengths into return value */
+ ret_value += (ssize_t)acc_len;
+
+ /* Update current sequence vectors */
+ *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr);
+ *src_curr_seq = (size_t)(src_off_ptr - src_off_arr);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5VM_memcpyvv() */
+
diff --git a/src/H5VMprivate.h b/src/H5VMprivate.h
new file mode 100644
index 0000000..4d71b29
--- /dev/null
+++ b/src/H5VMprivate.h
@@ -0,0 +1,550 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, October 10, 1997
+ */
+#ifndef H5VMprivate_H
+#define H5VMprivate_H
+
+/* Private headers needed by this file */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+
+/* Vector-Vector sequence operation callback */
+typedef herr_t (*H5VM_opvv_func_t)(hsize_t dst_off, hsize_t src_off,
+ size_t len, void *udata);
+
+/* Vector comparison functions like Fortran66 comparison operators */
+#define H5VM_vector_eq_s(N,V1,V2) (H5VM_vector_cmp_s (N, V1, V2)==0)
+#define H5VM_vector_lt_s(N,V1,V2) (H5VM_vector_cmp_s (N, V1, V2)<0)
+#define H5VM_vector_gt_s(N,V1,V2) (H5VM_vector_cmp_s (N, V1, V2)>0)
+#define H5VM_vector_le_s(N,V1,V2) (H5VM_vector_cmp_s (N, V1, V2)<=0)
+#define H5VM_vector_ge_s(N,V1,V2) (H5VM_vector_cmp_s (N, V1, V2)>=0)
+#define H5VM_vector_eq_u(N,V1,V2) (H5VM_vector_cmp_u (N, V1, V2)==0)
+#define H5VM_vector_lt_u(N,V1,V2) (H5VM_vector_cmp_u (N, V1, V2)<0)
+#define H5VM_vector_gt_u(N,V1,V2) (H5VM_vector_cmp_u (N, V1, V2)>0)
+#define H5VM_vector_le_u(N,V1,V2) (H5VM_vector_cmp_u (N, V1, V2)<=0)
+#define H5VM_vector_ge_u(N,V1,V2) (H5VM_vector_cmp_u (N, V1, V2)>=0)
+
+/* Other functions */
+#define H5VM_vector_cpy(N,DST,SRC) { \
+ HDassert(sizeof(*(DST))==sizeof(*(SRC))); \
+ if (SRC) HDmemcpy (DST, SRC, (N)*sizeof(*(DST))); \
+ else HDmemset (DST, 0, (N)*sizeof(*(DST))); \
+}
+
+#define H5VM_vector_zero(N,DST) HDmemset(DST,0,(N)*sizeof(*(DST)))
+
+/* Given a coordinate offset array (COORDS) of type TYPE, move the unlimited
+ * dimension (UNLIM_DIM) value to offset 0, sliding any intermediate values down
+ * one position. */
+#define H5VM_swizzle_coords(TYPE,COORDS,UNLIM_DIM) { \
+ /* COORDS must be an array of type TYPE */ \
+ HDassert(sizeof(COORDS[0]) == sizeof(TYPE)); \
+ \
+ /* Nothing to do when unlimited dimension is at position 0 */ \
+ if(0 != (UNLIM_DIM)) { \
+ TYPE _tmp = (COORDS)[UNLIM_DIM]; \
+ \
+ HDmemmove(&(COORDS)[1], &(COORDS)[0], sizeof(TYPE) * (UNLIM_DIM)); \
+ (COORDS)[0] = _tmp; \
+ } /* end if */ \
+}
+
+/* Given a coordinate offset array (COORDS) of type TYPE, move the value at
+ * offset 0 to offset of the unlimied dimension (UNLIM_DIM), sliding any
+ * intermediate values up one position. Undoes the "swizzle_coords" operation.
+ */
+#define H5VM_unswizzle_coords(TYPE,COORDS,UNLIM_DIM) { \
+ /* COORDS must be an array of type TYPE */ \
+ HDassert(sizeof(COORDS[0]) == sizeof(TYPE)); \
+ \
+ /* Nothing to do when unlimited dimension is at position 0 */ \
+ if(0 != (UNLIM_DIM)) { \
+ TYPE _tmp = (COORDS)[0]; \
+ \
+ HDmemmove(&(COORDS)[0], &(COORDS)[1], sizeof(TYPE) * (UNLIM_DIM)); \
+ (COORDS)[UNLIM_DIM] = _tmp; \
+ } /* end if */ \
+}
+
+/* A null pointer is equivalent to a zero vector */
+#define H5VM_ZERO NULL
+
+H5_DLL hsize_t H5VM_hyper_stride(unsigned n, const hsize_t *size,
+ const hsize_t *total_size,
+ const hsize_t *offset,
+ hsize_t *stride);
+H5_DLL htri_t H5VM_hyper_eq(unsigned n, const hsize_t *offset1,
+ const hsize_t *size1, const hsize_t *offset2,
+ const hsize_t *size2);
+H5_DLL herr_t H5VM_hyper_fill(unsigned n, const hsize_t *_size,
+ const hsize_t *total_size,
+ const hsize_t *offset, void *_dst,
+ unsigned fill_value);
+H5_DLL herr_t H5VM_hyper_copy(unsigned n, const hsize_t *size,
+ const hsize_t *dst_total_size,
+ const hsize_t *dst_offset, void *_dst,
+ const hsize_t *src_total_size,
+ const hsize_t *src_offset, const void *_src);
+H5_DLL herr_t H5VM_stride_fill(unsigned n, hsize_t elmt_size, const hsize_t *size,
+ const hsize_t *stride, void *_dst,
+ unsigned fill_value);
+H5_DLL herr_t H5VM_stride_copy(unsigned n, hsize_t elmt_size, const hsize_t *_size,
+ const hsize_t *dst_stride, void *_dst,
+ const hsize_t *src_stride, const void *_src);
+H5_DLL herr_t H5VM_stride_copy_s(unsigned n, hsize_t elmt_size, const hsize_t *_size,
+ const hssize_t *dst_stride, void *_dst,
+ const hssize_t *src_stride, const void *_src);
+H5_DLL herr_t H5VM_array_fill(void *_dst, const void *src, size_t size,
+ size_t count);
+H5_DLL herr_t H5VM_array_down(unsigned n, const hsize_t *total_size,
+ hsize_t *down);
+H5_DLL hsize_t H5VM_array_offset_pre(unsigned n,
+ const hsize_t *acc, const hsize_t *offset);
+H5_DLL hsize_t H5VM_array_offset(unsigned n, const hsize_t *total_size,
+ const hsize_t *offset);
+H5_DLL herr_t H5VM_array_calc_pre(hsize_t offset, unsigned n,
+ const hsize_t *down, hsize_t *coords);
+H5_DLL herr_t H5VM_array_calc(hsize_t offset, unsigned n,
+ const hsize_t *total_size, hsize_t *coords);
+H5_DLL hsize_t H5VM_chunk_index(unsigned ndims, const hsize_t *coord,
+ const uint32_t *chunk, const hsize_t *down_nchunks);
+H5_DLL void H5VM_chunk_scaled(unsigned ndims, const hsize_t *coord,
+ const uint32_t *chunk, hsize_t *scaled);
+H5_DLL hsize_t H5VM_chunk_index_scaled(unsigned ndims, const hsize_t *coord,
+ const uint32_t *chunk, const hsize_t *down_nchunks, hsize_t *scaled);
+H5_DLL ssize_t H5VM_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[],
+ hsize_t dst_off_arr[],
+ size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[],
+ hsize_t src_off_arr[],
+ H5VM_opvv_func_t op, void *op_data);
+H5_DLL ssize_t H5VM_memcpyvv(void *_dst,
+ size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], hsize_t dst_off_arr[],
+ const void *_src,
+ size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], hsize_t src_off_arr[]);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_reduce_product
+ *
+ * Purpose: Product reduction of a vector. Vector elements and return
+ * value are size_t because we usually want the number of
+ * elements in an array and array dimensions are always of type
+ * size_t.
+ *
+ * Return: Success: Product of elements
+ *
+ * Failure: 1 if N is zero
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE hsize_t H5_ATTR_UNUSED
+H5VM_vector_reduce_product(unsigned n, const hsize_t *v)
+{
+ hsize_t ret_value = 1;
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (n && !v) HGOTO_DONE(0)
+ while (n--) ret_value *= *v++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_zerop_u
+ *
+ * Purpose: Determines if all elements of a vector are zero.
+ *
+ * Return: Success: TRUE if all elements are zero,
+ * FALSE otherwise
+ *
+ * Failure: TRUE if N is zero
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE htri_t H5_ATTR_UNUSED
+H5VM_vector_zerop_u(int n, const hsize_t *v)
+{
+ htri_t ret_value=TRUE; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (!v)
+ HGOTO_DONE(TRUE)
+ while (n--)
+ if (*v++)
+ HGOTO_DONE(FALSE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_zerop_s
+ *
+ * Purpose: Determines if all elements of a vector are zero.
+ *
+ * Return: Success: TRUE if all elements are zero,
+ * FALSE otherwise
+ *
+ * Failure: TRUE if N is zero
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE htri_t H5_ATTR_UNUSED
+H5VM_vector_zerop_s(int n, const hssize_t *v)
+{
+ htri_t ret_value=TRUE; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (!v)
+ HGOTO_DONE(TRUE)
+ while (n--)
+ if (*v++)
+ HGOTO_DONE(FALSE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_cmp_u
+ *
+ * Purpose: Compares two vectors of the same size and determines if V1 is
+ * lexicographically less than, equal, or greater than V2.
+ *
+ * Return: Success: -1 if V1 is less than V2
+ * 0 if they are equal
+ * 1 if V1 is greater than V2
+ *
+ * Failure: 0 if N is zero
+ *
+ * Programmer: Robb Matzke
+ * Friday, October 10, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE int H5_ATTR_UNUSED
+H5VM_vector_cmp_u (unsigned n, const hsize_t *v1, const hsize_t *v2)
+{
+ int ret_value=0; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (v1 == v2) HGOTO_DONE(0)
+ if (v1 == NULL) HGOTO_DONE(-1)
+ if (v2 == NULL) HGOTO_DONE(1)
+ while (n--) {
+ if (*v1 < *v2) HGOTO_DONE(-1)
+ if (*v1 > *v2) HGOTO_DONE(1)
+ v1++;
+ v2++;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_cmp_s
+ *
+ * Purpose: Compares two vectors of the same size and determines if V1 is
+ * lexicographically less than, equal, or greater than V2.
+ *
+ * Return: Success: -1 if V1 is less than V2
+ * 0 if they are equal
+ * 1 if V1 is greater than V2
+ *
+ * Failure: 0 if N is zero
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, April 8, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE int H5_ATTR_UNUSED
+H5VM_vector_cmp_s (unsigned n, const hssize_t *v1, const hssize_t *v2)
+{
+ int ret_value=0; /* Return value */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (v1 == v2) HGOTO_DONE(0)
+ if (v1 == NULL) HGOTO_DONE(-1)
+ if (v2 == NULL) HGOTO_DONE(1)
+ while (n--) {
+ if (*v1 < *v2) HGOTO_DONE(-1)
+ if (*v1 > *v2) HGOTO_DONE(1)
+ v1++;
+ v2++;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_vector_inc
+ *
+ * Purpose: Increments V1 by V2
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Monday, October 13, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE void H5_ATTR_UNUSED
+H5VM_vector_inc(int n, hsize_t *v1, const hsize_t *v2)
+{
+ while (n--) *v1++ += *v2++;
+}
+
+/* Lookup table for general log2(n) routine */
+static const unsigned char LogTable256[] =
+{
+ 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_log2_gen
+ *
+ * Purpose: Determines the log base two of a number (i.e. log2(n)).
+ * (i.e. the highest bit set in a number)
+ *
+ * Note: This is from the "Bit Twiddling Hacks" at:
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
+ *
+ * The version on the web-site is for 32-bit quantities and this
+ * version has been extended for 64-bit quantities.
+ *
+ * Return: log2(n) (always - no failure condition)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, March 6, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE unsigned H5_ATTR_UNUSED
+H5VM_log2_gen(uint64_t n)
+{
+ unsigned r; /* r will be log2(n) */
+ register unsigned int t, tt, ttt; /* temporaries */
+
+ if((ttt = (unsigned)(n >> 32)))
+ if((tt = (unsigned)(n >> 48)))
+ r = (t = (unsigned)(n >> 56)) ? 56 + (unsigned)LogTable256[t] : 48 + (unsigned)LogTable256[tt & 0xFF];
+ else
+ r = (t = (unsigned)(n >> 40)) ? 40 + (unsigned)LogTable256[t] : 32 + (unsigned)LogTable256[ttt & 0xFF];
+ else
+ if((tt = (unsigned)(n >> 16)))
+ r = (t = (unsigned)(n >> 24)) ? 24 + (unsigned)LogTable256[t] : 16 + (unsigned)LogTable256[tt & 0xFF];
+ else
+ /* Added 'uint8_t' cast to pacify PGCC compiler */
+ r = (t = (unsigned)(n >> 8)) ? 8 + (unsigned)LogTable256[t] : (unsigned)LogTable256[(uint8_t)n];
+
+ return(r);
+} /* H5VM_log2_gen() */
+
+
+/* Lookup table for specialized log2(n) of power of two routine */
+static const unsigned MultiplyDeBruijnBitPosition[32] =
+{
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_log2_of2
+ *
+ * Purpose: Determines the log base two of a number (i.e. log2(n)).
+ * (i.e. the highest bit set in a number)
+ *
+ * Note: **N must be a power of two** and is limited to 32-bit quantities.
+ *
+ * This is from the "Bit Twiddling Hacks" at:
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
+ *
+ * Return: log2(n) (always - no failure condition)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, Febraury 27, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE H5_ATTR_PURE unsigned
+H5VM_log2_of2(uint32_t n)
+{
+#ifndef NDEBUG
+ HDassert(POWER_OF_TWO(n));
+#endif /* NDEBUG */
+ return(MultiplyDeBruijnBitPosition[(n * (uint32_t)0x077CB531UL) >> 27]);
+} /* H5VM_log2_of2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_power2up
+ *
+ * Purpose: Round up a number to the next power of 2
+ *
+ * Return: Return the number which is a power of 2
+ *
+ * Programmer: Vailin Choi; Nov 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE H5_ATTR_CONST hsize_t
+H5VM_power2up(hsize_t n)
+{
+ hsize_t ret_value = 1; /* Return value */
+
+ while(ret_value < n)
+ ret_value <<= 1;
+
+ return(ret_value);
+} /* H5VM_power2up */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_limit_enc_size
+ *
+ * Purpose: Determine the # of bytes needed to encode values within a
+ * range from 0 to a given limit
+ *
+ * Return: Number of bytes needed
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 13, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE unsigned H5_ATTR_UNUSED
+H5VM_limit_enc_size(uint64_t limit)
+{
+ return (H5VM_log2_gen(limit) / 8) + 1;
+} /* end H5VM_limit_enc_size() */
+
+static const unsigned char H5VM_bit_set_g[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+static const unsigned char H5VM_bit_clear_g[8] = {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_bit_get
+ *
+ * Purpose: Determine the value of the n'th bit in a buffer.
+ *
+ * Note: No range checking on <offset> is performed!
+ *
+ * Note #2: Bits are sequentially stored in the buffer, starting with bit
+ * offset 0 in the first byte's high-bit position, proceeding down
+ * to bit offset 7 in the first byte's low-bit position, then to
+ * bit offset 8 in the second byte's high-bit position, etc.
+ *
+ * Return: TRUE/FALSE
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 25, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE hbool_t H5_ATTR_UNUSED
+H5VM_bit_get(const unsigned char *buf, size_t offset)
+{
+ /* Test the appropriate bit in the buffer */
+ return (hbool_t)((buf[offset / 8] & (H5VM_bit_set_g[offset % 8])) ? TRUE : FALSE);
+} /* end H5VM_bit_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VM_bit_set
+ *
+ * Purpose: Set/reset the n'th bit in a buffer.
+ *
+ * Note: No range checking on <offset> is performed!
+ *
+ * Note #2: Bits are sequentially stored in the buffer, starting with bit
+ * offset 0 in the first byte's high-bit position, proceeding down
+ * to bit offset 7 in the first byte's low-bit position, then to
+ * bit offset 8 in the second byte's high-bit position, etc.
+ *
+ * Return: None
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 25, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5_INLINE void H5_ATTR_UNUSED
+H5VM_bit_set(unsigned char *buf, size_t offset, hbool_t val)
+{
+ /* Set/reset the appropriate bit in the buffer */
+ if(val)
+ buf[offset / 8] |= H5VM_bit_set_g[offset % 8];
+ else
+ buf[offset / 8] &= H5VM_bit_clear_g[offset % 8];
+} /* end H5VM_bit_set() */
+
+#endif /* H5VMprivate_H */
+
diff --git a/src/H5WB.c b/src/H5WB.c
new file mode 100644
index 0000000..8a85a3a
--- /dev/null
+++ b/src/H5WB.c
@@ -0,0 +1,289 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5WB.c
+ * Jun 26 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implements the "wrapped buffer" code for wrapping
+ * an existing [staticly sized] buffer, in order to
+ * avoid lots of memory allocation calls.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+/* Typedef for buffer wrapper */
+struct H5WB_t {
+ void *wrapped_buf; /* Pointer to wrapped buffer */
+ size_t wrapped_size; /* Size of wrapped buffer */
+ void *actual_buf; /* Pointer to actual buffer */
+ size_t actual_size; /* Size of actual buffer used */
+ size_t alloc_size; /* Size of actual buffer allocated */
+};
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Declare a free list to manage the H5WB_t struct */
+H5FL_DEFINE_STATIC(H5WB_t);
+
+/* Declare a free list to manage the extra buffer information */
+H5FL_BLK_DEFINE_STATIC(extra_buf);
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5WB_wrap
+ *
+ * Purpose: Wraps an existing [possibly static] buffer
+ *
+ * Return: Pointer to buffer wrapper info on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 26 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+H5WB_t *
+H5WB_wrap(void *buf, size_t buf_size)
+{
+ H5WB_t *wb = NULL; /* Wrapped buffer info */
+ H5WB_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(buf);
+ HDassert(buf_size);
+
+ /* Create wrapped buffer info */
+ if(NULL == (wb = H5FL_MALLOC(H5WB_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for wrapped buffer info")
+
+ /* Wrap buffer given */
+ wb->wrapped_buf = buf;
+ wb->wrapped_size = buf_size;
+
+ /* No actual buffer yet */
+ wb->actual_buf = NULL;
+ wb->actual_size = 0;
+ wb->alloc_size = 0;
+
+ /* Set the return value */
+ ret_value = wb;
+
+done:
+ /* Release resources on error */
+ if(!ret_value && wb)
+ wb = H5FL_FREE(H5WB_t, wb);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5WB_wrap() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5WB_actual
+ *
+ * Purpose: Get the pointer to an "actual" buffer, of at least a certain
+ * size.
+ *
+ * Return: Pointer to buffer pointer on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 26 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5WB_actual(H5WB_t *wb, size_t need)
+{
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(wb);
+ HDassert(wb->wrapped_buf);
+
+ /* Check for previously allocated buffer */
+ if(wb->actual_buf && wb->actual_buf != wb->wrapped_buf) {
+ /* Sanity check */
+ HDassert(wb->actual_size > wb->wrapped_size);
+
+ /* Check if we can re-use existing buffer */
+ if(need <= wb->alloc_size)
+ HGOTO_DONE(wb->actual_buf)
+ /* Can't re-use existing buffer, free it and proceed */
+ else
+ wb->actual_buf = H5FL_BLK_FREE(extra_buf, wb->actual_buf);
+ } /* end if */
+
+ /* Check if size needed can be fulfilled with wrapped buffer */
+ if(need > wb->wrapped_size) {
+ /* Need to allocate new buffer */
+ if(NULL == (wb->actual_buf = H5FL_BLK_MALLOC(extra_buf, need)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Remember size of buffer allocated */
+ wb->alloc_size = need;
+ } /* end if */
+ else {
+ /* Don't have to allocate a new buffer, use the wrapped one */
+ wb->actual_buf = wb->wrapped_buf;
+ wb->alloc_size = 0;
+ } /* end else */
+
+ /* Set the return value */
+ ret_value = wb->actual_buf;
+
+done:
+ /* Remember size of buffer used, if we were successful */
+ if(ret_value)
+ wb->actual_size = need;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5WB_actual() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5WB_actual_clear
+ *
+ * Purpose: Get the pointer to an "actual" buffer, of at least a certain
+ * size. Also, clear actual buffer to zeros.
+ *
+ * Return: Pointer to buffer pointer on success
+ * NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 26 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5WB_actual_clear(H5WB_t *wb, size_t need)
+{
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(wb);
+ HDassert(wb->wrapped_buf);
+
+ /* Get a pointer to an actual buffer */
+ if(NULL == (ret_value = H5WB_actual(wb, need)))
+ HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear the buffer */
+ HDmemset(ret_value, 0, need);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5WB_actual_clear() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5WB_unwrap
+ *
+ * Purpose: "unwrap" a wrapped buffer, releasing all resources used
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jun 26 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5WB_unwrap(H5WB_t *wb)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(wb);
+ HDassert(wb->wrapped_buf);
+
+ /* Release any extra buffers allocated */
+ if(wb->actual_buf && wb->actual_buf != wb->wrapped_buf) {
+ /* Sanity check */
+ HDassert(wb->actual_size > wb->wrapped_size);
+
+ wb->actual_buf = H5FL_BLK_FREE(extra_buf, wb->actual_buf);
+ } /* end if */
+
+ /* Release the buffer wrapper info */
+ wb = H5FL_FREE(H5WB_t, wb);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5WB_unwrap() */
+
diff --git a/src/H5WBprivate.h b/src/H5WBprivate.h
new file mode 100644
index 0000000..4460808
--- /dev/null
+++ b/src/H5WBprivate.h
@@ -0,0 +1,62 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5WBprivate.h
+ * Jun 26 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Private header for library accessible wrapped buffer routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5WBprivate_H
+#define _H5WBprivate_H
+
+/* Include package's public header */
+/* #include "H5WBpublic.h" */
+
+/* Private headers needed by this file */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Wrapped buffer info (forward decl - defined in H5WB.c) */
+typedef struct H5WB_t H5WB_t;
+
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+
+/* General routines for wrapped buffer operations */
+H5_DLL H5WB_t *H5WB_wrap(void *buf, size_t buf_size);
+H5_DLL void *H5WB_actual(H5WB_t *wb, size_t need);
+H5_DLL void *H5WB_actual_clear(H5WB_t *wb, size_t need);
+H5_DLL herr_t H5WB_unwrap(H5WB_t *wb);
+
+#endif /* _H5WBprivate_H */
+
diff --git a/src/H5Z.c b/src/H5Z.c
new file mode 100644
index 0000000..ef34d7c
--- /dev/null
+++ b/src/H5Z.c
@@ -0,0 +1,1717 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5PLprivate.h" /* Plugins */
+#include "H5Sprivate.h" /* Dataspace functions */
+#include "H5Zpkg.h" /* Data filters */
+
+#ifdef H5_HAVE_SZLIB_H
+# include "szlib.h"
+#endif
+
+/* Local typedefs */
+#ifdef H5Z_DEBUG
+typedef struct H5Z_stats_t {
+ struct {
+ hsize_t total; /*total number of bytes processed */
+ hsize_t errors; /*bytes of total attributable to errors */
+ H5_timer_t timer; /*execution time including errors */
+ } stats[2]; /*0=output, 1=input */
+} H5Z_stats_t;
+#endif /* H5Z_DEBUG */
+
+typedef struct H5Z_object_t {
+ H5Z_filter_t filter_id; /* ID of the filter we're looking for */
+ htri_t found; /* Whether we find an object using the filter */
+} H5Z_object_t;
+
+/* Enumerated type for dataset creation prelude callbacks */
+typedef enum {
+ H5Z_PRELUDE_CAN_APPLY, /* Call "can apply" callback */
+ H5Z_PRELUDE_SET_LOCAL /* Call "set local" callback */
+} H5Z_prelude_type_t;
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Local variables */
+static size_t H5Z_table_alloc_g = 0;
+static size_t H5Z_table_used_g = 0;
+static H5Z_class2_t *H5Z_table_g = NULL;
+#ifdef H5Z_DEBUG
+static H5Z_stats_t *H5Z_stat_table_g = NULL;
+#endif /* H5Z_DEBUG */
+
+/* Local functions */
+static int H5Z_find_idx(H5Z_filter_t id);
+static int H5Z__check_unregister_dset_cb(void *obj_ptr, hid_t obj_id, void *key);
+static int H5Z__check_unregister_group_cb(void *obj_ptr, hid_t obj_id, void *key);
+static int H5Z__flush_file_cb(void *obj_ptr, hid_t obj_id, void *key);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z__init_package
+ *
+ * Purpose: Initializes the data filter layer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z__init_package(void)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Internal filters */
+ if(H5Z_register(H5Z_SHUFFLE) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register shuffle filter")
+ if(H5Z_register(H5Z_FLETCHER32) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register fletcher32 filter")
+ if(H5Z_register(H5Z_NBIT) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register nbit filter")
+ if(H5Z_register(H5Z_SCALEOFFSET) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register scaleoffset filter")
+
+ /* External filters */
+#ifdef H5_HAVE_FILTER_DEFLATE
+ if(H5Z_register(H5Z_DEFLATE) < 0)
+ HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register deflate filter")
+#endif /* H5_HAVE_FILTER_DEFLATE */
+#ifdef H5_HAVE_FILTER_SZIP
+ H5Z_SZIP->encoder_present = SZ_encoder_enabled();
+ if(H5Z_register(H5Z_SZIP) < 0)
+ HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register szip filter")
+#endif /* H5_HAVE_FILTER_SZIP */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_term_package
+ *
+ * Purpose: Terminate the H5Z layer.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5Z_term_package(void)
+{
+ int n = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(H5_PKG_INIT_VAR) {
+#ifdef H5Z_DEBUG
+ char comment[16], bandwidth[32];
+ int dir, nprint = 0;
+ size_t i;
+
+ if(H5DEBUG(Z)) {
+ for(i = 0; i < H5Z_table_used_g; i++) {
+ for(dir = 0; dir<2; dir++) {
+ if(0 == H5Z_stat_table_g[i].stats[dir].total)
+ continue;
+
+ if(0 == nprint++) {
+ /* Print column headers */
+ HDfprintf(H5DEBUG(Z), "H5Z: filter statistics "
+ "accumulated over life of library:\n");
+ HDfprintf(H5DEBUG(Z),
+ " %-16s %10s %10s %8s %8s %8s %10s\n",
+ "Filter", "Total", "Errors", "User",
+ "System", "Elapsed", "Bandwidth");
+ HDfprintf(H5DEBUG(Z),
+ " %-16s %10s %10s %8s %8s %8s %10s\n",
+ "------", "-----", "------", "----",
+ "------", "-------", "---------");
+ } /* end if */
+
+ /* Truncate the comment to fit in the field */
+ HDstrncpy(comment, H5Z_table_g[i].name, sizeof comment);
+ comment[sizeof(comment) - 1] = '\0';
+
+ /*
+ * Format bandwidth to have four significant digits and
+ * units of `B/s', `kB/s', `MB/s', `GB/s', or `TB/s' or
+ * the word `Inf' if the elapsed time is zero.
+ */
+ H5_bandwidth(bandwidth,
+ (double)(H5Z_stat_table_g[i].stats[dir].total),
+ H5Z_stat_table_g[i].stats[dir].timer.etime);
+
+ /* Print the statistics */
+ HDfprintf(H5DEBUG(Z),
+ " %s%-15s %10Hd %10Hd %8.2f %8.2f %8.2f "
+ "%10s\n", dir?"<":">", comment,
+ H5Z_stat_table_g[i].stats[dir].total,
+ H5Z_stat_table_g[i].stats[dir].errors,
+ H5Z_stat_table_g[i].stats[dir].timer.utime,
+ H5Z_stat_table_g[i].stats[dir].timer.stime,
+ H5Z_stat_table_g[i].stats[dir].timer.etime,
+ bandwidth);
+ } /* end for */
+ } /* end for */
+ } /* end if */
+#endif /* H5Z_DEBUG */
+ /* Free the table of filters */
+ if(H5Z_table_g) {
+ H5Z_table_g = (H5Z_class2_t *)H5MM_xfree(H5Z_table_g);
+#ifdef H5Z_DEBUG
+ H5Z_stat_table_g = (H5Z_stats_t *)H5MM_xfree(H5Z_stat_table_g);
+#endif /* H5Z_DEBUG */
+ H5Z_table_used_g = H5Z_table_alloc_g = 0;
+
+ n++;
+ } /* end if */
+
+ /* Mark interface as closed */
+ if(0 == n)
+ H5_PKG_INIT_VAR = FALSE;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(n)
+} /* end H5Z_term_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Zregister
+ *
+ * Purpose: This function registers new filter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ * Modifications:
+ * Changed to pass in H5Z_class_t struct
+ * Quincey Koziol, April 5, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Zregister(const void *cls)
+{
+ const H5Z_class2_t *cls_real = (const H5Z_class2_t *) cls; /* "Real" class pointer */
+ H5Z_class2_t cls_new; /* Translated class struct */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "*x", cls);
+
+ /* Check args */
+ if (cls_real==NULL)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter class")
+
+ /* Check H5Z_class_t version number; this is where a function to convert
+ * from an outdated version should be called.
+ *
+ * If the version number is invalid, we assume that the target of cls is the
+ * old style "H5Z_class1_t" structure, which did not contain a version
+ * field. In this structure, the first field is the id. Since both version
+ * and id are integers they will have the same value, and since id must be
+ * at least 256, there should be no overlap and the version of the struct
+ * can be determined by the value of the first field.
+ */
+ if(cls_real->version != H5Z_CLASS_T_VERS) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ /* Assume it is an old "H5Z_class1_t" instead */
+ const H5Z_class1_t *cls_old = (const H5Z_class1_t *) cls;
+
+ /* Translate to new H5Z_class2_t */
+ cls_new.version = H5Z_CLASS_T_VERS;
+ cls_new.id = cls_old->id;
+ cls_new.encoder_present = 1;
+ cls_new.decoder_present = 1;
+ cls_new.name = cls_old->name;
+ cls_new.can_apply = cls_old->can_apply;
+ cls_new.set_local = cls_old->set_local;
+ cls_new.filter = cls_old->filter;
+
+ /* Set cls_real to point to the translated structure */
+ cls_real = &cls_new;
+
+#else /* H5_NO_DEPRECATED_SYMBOLS */
+ /* Deprecated symbols not allowed, throw an error */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5Z_class_t version number");
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+ } /* end if */
+
+ if (cls_real->id<0 || cls_real->id>H5Z_FILTER_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number")
+ if (cls_real->id<H5Z_FILTER_RESERVED)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters")
+ if (cls_real->filter==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no filter function specified")
+
+ /* Do it */
+ if (H5Z_register (cls_real)<0)
+ HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_register
+ *
+ * Purpose: Same as the public version except this one allows filters
+ * to be set for predefined method numbers <H5Z_FILTER_RESERVED
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_register (const H5Z_class2_t *cls)
+{
+ size_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(cls);
+ HDassert(cls->id >= 0 && cls->id <= H5Z_FILTER_MAX);
+
+ /* Is the filter already registered? */
+ for(i = 0; i < H5Z_table_used_g; i++)
+ if(H5Z_table_g[i].id == cls->id)
+ break;
+
+ /* Filter not already registered */
+ if(i >= H5Z_table_used_g) {
+ if(H5Z_table_used_g >= H5Z_table_alloc_g) {
+ size_t n = MAX(H5Z_MAX_NFILTERS, 2*H5Z_table_alloc_g);
+ H5Z_class2_t *table = (H5Z_class2_t *)H5MM_realloc(H5Z_table_g, n * sizeof(H5Z_class2_t));
+#ifdef H5Z_DEBUG
+ H5Z_stats_t *stat_table = (H5Z_stats_t *)H5MM_realloc(H5Z_stat_table_g, n * sizeof(H5Z_stats_t));
+#endif /* H5Z_DEBUG */
+ if(!table)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter table")
+ H5Z_table_g = table;
+#ifdef H5Z_DEBUG
+ if(!stat_table)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter statistics table")
+ H5Z_stat_table_g = stat_table;
+#endif /* H5Z_DEBUG */
+ H5Z_table_alloc_g = n;
+ } /* end if */
+
+ /* Initialize */
+ i = H5Z_table_used_g++;
+ HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class2_t));
+#ifdef H5Z_DEBUG
+ HDmemset(H5Z_stat_table_g+i, 0, sizeof(H5Z_stats_t));
+#endif /* H5Z_DEBUG */
+ } /* end if */
+ /* Filter already registered */
+ else {
+ /* Replace old contents */
+ HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class2_t));
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Zunregister
+ *
+ * Purpose: This function unregisters a filter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 14, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Zunregister(H5Z_filter_t id)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "Zf", id);
+
+ /* Check args */
+ if(id < 0 || id > H5Z_FILTER_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number")
+ if(id < H5Z_FILTER_RESERVED)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters")
+
+ /* Do it */
+ if(H5Z_unregister(id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to unregister filter")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Zunregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_unregister
+ *
+ * Purpose: Same as the public version except this one allows filters
+ * to be unset for predefined method numbers <H5Z_FILTER_RESERVED
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 14, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_unregister(H5Z_filter_t filter_id)
+{
+ size_t filter_index; /* Local index variable for filter */
+ H5Z_object_t object;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(filter_id>=0 && filter_id<=H5Z_FILTER_MAX);
+
+ /* Is the filter already registered? */
+ for (filter_index=0; filter_index<H5Z_table_used_g; filter_index++)
+ if (H5Z_table_g[filter_index].id==filter_id)
+ break;
+
+ /* Fail if filter not found */
+ if (filter_index>=H5Z_table_used_g)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter is not registered")
+
+ /* Initialize the structure object for iteration */
+ object.filter_id = filter_id;
+ object.found = FALSE;
+
+ /* Iterate through all opened datasets, returns a failure if any of them uses the filter */
+ if(H5I_iterate(H5I_DATASET, H5Z__check_unregister_dset_cb, &object, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed")
+
+ if(object.found)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, "can't unregister filter because a dataset is still using it")
+
+ /* Iterate through all opened groups, returns a failure if any of them uses the filter */
+ if(H5I_iterate(H5I_GROUP, H5Z__check_unregister_group_cb, &object, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed")
+
+ if(object.found)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, "can't unregister filter because a group is still using it")
+
+ /* Iterate through all opened files and flush them */
+ if(H5I_iterate(H5I_FILE, H5Z__flush_file_cb, NULL, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed")
+
+ /* Remove filter from table */
+ /* Don't worry about shrinking table size (for now) */
+ HDmemmove(&H5Z_table_g[filter_index],&H5Z_table_g[filter_index+1],sizeof(H5Z_class2_t)*((H5Z_table_used_g-1)-filter_index));
+#ifdef H5Z_DEBUG
+ HDmemmove(&H5Z_stat_table_g[filter_index],&H5Z_stat_table_g[filter_index+1],sizeof(H5Z_stats_t)*((H5Z_table_used_g-1)-filter_index));
+#endif /* H5Z_DEBUG */
+ H5Z_table_used_g--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_unregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z__check_unregister
+ *
+ * Purpose: Check if an object uses the filter to be unregistered.
+ *
+ * Return: TRUE if the object uses the filter.
+ * FALSE if not, NEGATIVE on error.
+ *
+ * Programmer: Quincey Koziol
+ * 11 May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5Z__check_unregister(hid_t ocpl_id, H5Z_filter_t filter_id)
+{
+ H5P_genplist_t *plist; /* Property list */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Get the plist structure of object creation */
+ if(NULL == (plist = H5P_object_verify(ocpl_id, H5P_OBJECT_CREATE)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Check if the object creation property list uses the filter */
+ if((ret_value = H5P_filter_in_pline(plist, filter_id)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z__check_unregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z__check_unregister_group_cb
+ *
+ * Purpose: The callback function for H5Z_unregister. It iterates
+ * through all opened objects. If the object is a dataset
+ * or a group and it uses the filter to be unregistered, the
+ * function returns TRUE.
+ *
+ * Return: TRUE if the object uses the filter.
+ * FALSE otherwise.
+ *
+ * Programmer: Raymond Lu
+ * 6 May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5Z__check_unregister_group_cb(void *obj_ptr, hid_t H5_ATTR_UNUSED obj_id, void *key)
+{
+ hid_t ocpl_id = -1;
+ H5Z_object_t *object = (H5Z_object_t *)key;
+ htri_t filter_in_pline = FALSE;
+ int ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(obj_ptr);
+
+ /* Get the group creation property */
+ if((ocpl_id = H5G_get_create_plist((H5G_t *)obj_ptr)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get group creation property list")
+
+ /* Check if the filter is in the group creation property list */
+ if((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline")
+
+ /* H5I_iterate expects TRUE to stop the loop over objects. Stop the loop and
+ * let H5Z_unregister return failure.
+ */
+ if(filter_in_pline) {
+ object->found = TRUE;
+ ret_value = TRUE;
+ } /* end if */
+
+done:
+ if(ocpl_id > 0)
+ if(H5I_dec_app_ref(ocpl_id) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z__check_unregister_group_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z__check_unregister_dset_cb
+ *
+ * Purpose: The callback function for H5Z_unregister. It iterates
+ * through all opened objects. If the object is a dataset
+ * or a group and it uses the filter to be unregistered, the
+ * function returns TRUE.
+ *
+ * Return: TRUE if the object uses the filter.
+ * FALSE otherwise.
+ *
+ * Programmer: Raymond Lu
+ * 6 May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5Z__check_unregister_dset_cb(void *obj_ptr, hid_t H5_ATTR_UNUSED obj_id, void *key)
+{
+ hid_t ocpl_id = -1;
+ H5Z_object_t *object = (H5Z_object_t *)key;
+ htri_t filter_in_pline = FALSE;
+ int ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(obj_ptr);
+
+ /* Get the dataset creation property */
+ if((ocpl_id = H5D_get_create_plist((H5D_t *)obj_ptr)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get dataset creation property list")
+
+ /* Check if the filter is in the dataset creation property list */
+ if((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline")
+
+ /* H5I_iterate expects TRUE to stop the loop over objects. Stop the loop and
+ * let H5Z_unregister return failure.
+ */
+ if(filter_in_pline) {
+ object->found = TRUE;
+ ret_value = TRUE;
+ } /* end if */
+
+done:
+ if(ocpl_id > 0)
+ if(H5I_dec_app_ref(ocpl_id) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z__check_unregister_dset_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z__flush_file_cb
+ *
+ * Purpose: The callback function for H5Z_unregister. It iterates
+ * through all opened files and flush them.
+ *
+ * Return: FALSE if finishes flushing and moves on
+ * FAIL if there is an error
+ *
+ * Programmer: Raymond Lu
+ * 6 May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5Z__flush_file_cb(void *obj_ptr, hid_t H5_ATTR_UNUSED obj_id, void H5_ATTR_UNUSED *key)
+{
+ int ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(obj_ptr);
+
+ /* Call the flush routine for mounted file hierarchies. Do a global flush
+ * if the file is opened for write */
+ if(H5F_ACC_RDWR & H5F_INTENT((H5F_t *)obj_ptr)) {
+ if(H5F_flush_mounts((H5F_t *)obj_ptr, H5AC_ind_read_dxpl_id, H5AC_rawdata_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFLUSH, FAIL, "unable to flush file hierarchy")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z__flush_file_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Zfilter_avail
+ *
+ * Purpose: Check if a filter is available
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, November 14, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Zfilter_avail(H5Z_filter_t id)
+{
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("t", "Zf", id);
+
+ /* Check args */
+ if(id<0 || id>H5Z_FILTER_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number")
+
+ if((ret_value = H5Z_filter_avail(id)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "unable to check the availability of the filter")
+ else if(ret_value == FALSE) {
+ const H5Z_class2_t *filter_info;
+
+ if(NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, (int)id)))
+ ret_value = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Zfilter_avail() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_avail
+ *
+ * Purpose: Private function to check if a filter is available
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 13 February 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Z_filter_avail(H5Z_filter_t id)
+{
+ size_t i; /* Local index variable */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Is the filter already registered? */
+ for(i = 0; i < H5Z_table_used_g; i++)
+ if(H5Z_table_g[i].id == id)
+ HGOTO_DONE(TRUE)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_filter_avail() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_prelude_callback
+ *
+ * Purpose: Makes a dataset creation "prelude" callback for the "can_apply"
+ * or "set_local" routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 4, 2003
+ *
+ * Notes:
+ * The chunk dimensions are used to create a dataspace, instead
+ * of passing in the dataset's dataspace, since the chunk
+ * dimensions are what the I/O filter will actually see
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id,
+ hid_t space_id, H5Z_prelude_type_t prelude_type)
+{
+ H5Z_class2_t *fclass; /* Individual filter information */
+ size_t u; /* Local index variable */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(pline->nused > 0);
+
+ /* Iterate over filters */
+ for(u = 0; u < pline->nused; u++) {
+ /* Get filter information */
+ if(NULL == (fclass = H5Z_find(pline->filter[u].id))) {
+ /* Ignore errors from optional filters */
+ if(pline->filter[u].flags & H5Z_FLAG_OPTIONAL)
+ H5E_clear_stack(NULL);
+ else
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "required filter was not located")
+ } /* end if */
+ else {
+ /* Make correct callback */
+ switch(prelude_type) {
+ case H5Z_PRELUDE_CAN_APPLY:
+ /* Check if filter is configured to be able to encode */
+ if(!fclass->encoder_present)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOENCODER, FAIL, "Filter present but encoding is disabled.");
+
+
+ /* Check if there is a "can apply" callback */
+ if(fclass->can_apply) {
+ /* Make callback to filter's "can apply" function */
+ htri_t status = (fclass->can_apply)(dcpl_id, type_id, space_id);
+
+ /* Indicate error during filter callback */
+ if(status < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "error during user callback")
+
+ /* Indicate filter can't apply to this combination of parameters.
+ * If the filter is NOT optional, returns failure. */
+ if(status == FALSE && !(pline->filter[u].flags & H5Z_FLAG_OPTIONAL))
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "filter parameters not appropriate")
+ } /* end if */
+ break;
+
+ case H5Z_PRELUDE_SET_LOCAL:
+ /* Check if there is a "set local" callback */
+ if(fclass->set_local) {
+ /* Make callback to filter's "set local" function */
+ if((fclass->set_local)(dcpl_id, type_id, space_id) < 0)
+ /* Indicate error during filter callback */
+ HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "error during user callback")
+ } /* end if */
+ break;
+
+ default:
+ HDassert("invalid prelude type" && 0);
+ } /* end switch */
+ } /* end else */
+ } /* end for */
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_prelude_callback() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_prepare_prelude_callback_dcpl
+ *
+ * Purpose: Prepares to make a dataset creation "prelude" callback
+ * for the "can_apply" or "set_local" routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 4, 2003
+ *
+ * Notes:
+ * The chunk dimensions are used to create a dataspace, instead
+ * of passing in the dataset's dataspace, since the chunk
+ * dimensions are what the I/O filter will actually see
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_prepare_prelude_callback_dcpl(hid_t dcpl_id, hid_t type_id, H5Z_prelude_type_t prelude_type)
+{
+ hid_t space_id = -1; /* ID for dataspace describing chunk */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(H5I_GENPROP_LST == H5I_get_type(dcpl_id));
+ HDassert(H5I_DATATYPE == H5I_get_type(type_id));
+
+ /* Check if the property list is non-default */
+ if(dcpl_id != H5P_DATASET_CREATE_DEFAULT) {
+ H5P_genplist_t *dc_plist; /* Dataset creation property list object */
+ H5O_layout_t dcpl_layout; /* Dataset's layout information */
+
+ /* Get dataset creation property list object */
+ if(NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dcpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list")
+
+ /* Peek at the layout information */
+ if(H5P_peek(dc_plist, H5D_CRT_LAYOUT_NAME, &dcpl_layout) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve layout")
+
+ /* Check if the dataset is chunked */
+ if(H5D_CHUNKED == dcpl_layout.type) {
+ H5O_pline_t dcpl_pline; /* Object's I/O pipeline information */
+
+ /* Get I/O pipeline information */
+ if(H5P_peek(dc_plist, H5O_CRT_PIPELINE_NAME, &dcpl_pline) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve pipeline filter")
+
+ /* Check if the chunks have filters */
+ if(dcpl_pline.nused > 0) {
+ hsize_t chunk_dims[H5O_LAYOUT_NDIMS]; /* Size of chunk dimensions */
+ H5S_t *space; /* Dataspace describing chunk */
+ size_t u; /* Local index variable */
+
+ /* Create a data space for a chunk & set the extent */
+ for(u = 0; u < dcpl_layout.u.chunk.ndims; u++)
+ chunk_dims[u] = dcpl_layout.u.chunk.dim[u];
+ if(NULL == (space = H5S_create_simple(dcpl_layout.u.chunk.ndims, chunk_dims, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace")
+
+ /* Get ID for dataspace to pass to filter routines */
+ if((space_id = H5I_register(H5I_DATASPACE, space, FALSE)) < 0) {
+ (void)H5S_close(space);
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID")
+ } /* end if */
+
+ /* Make the callbacks */
+ if(H5Z_prelude_callback(&dcpl_pline, dcpl_id, type_id, space_id, prelude_type) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter")
+ } /* end if */
+ } /* end if */
+ } /* end if */
+
+done:
+ if(space_id > 0 && H5I_dec_ref(space_id) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, "unable to close dataspace")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_prepare_prelude_callback_dcpl() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_can_apply
+ *
+ * Purpose: Checks if all the filters defined in the dataset creation
+ * property list can be applied to a particular combination of
+ * datatype and dataspace for a dataset.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, April 3, 2003
+ *
+ * Notes:
+ * The chunk dimensions are used to create a dataspace, instead
+ * of passing in the dataset's dataspace, since the chunk
+ * dimensions are what the I/O filter will actually see
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_can_apply(hid_t dcpl_id, hid_t type_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Make "can apply" callbacks for filters in pipeline */
+ if(H5Z_prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_CAN_APPLY) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_can_apply() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local
+ *
+ * Purpose: Makes callbacks to modify dataset creation list property
+ * settings for filters on a new dataset, based on the datatype
+ * and dataspace of that dataset (chunk).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 4, 2003
+ *
+ * Notes:
+ * The chunk dimensions are used to create a dataspace, instead
+ * of passing in the dataset's dataspace, since the chunk
+ * dimensions are what the I/O filter will actually see
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_set_local(hid_t dcpl_id, hid_t type_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Make "set local" callbacks for filters in pipeline */
+ if(H5Z_prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_SET_LOCAL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_can_apply_direct
+ *
+ * Purpose: Checks if all the filters defined in the pipeline can be
+ * applied to an opaque byte stream (currently only a group).
+ * The pipeline is assumed to have at least one filter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, September 22, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_can_apply_direct(const H5O_pline_t *pline)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pline->nused > 0);
+
+ /* Make "can apply" callbacks for filters in pipeline */
+ if(H5Z_prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_CAN_APPLY) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_can_apply_direct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local_direct
+ *
+ * Purpose: Makes callbacks to modify local settings for filters on a
+ * new opaque object. The pipeline is assumed to have at
+ * least one filter.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, September 22, 2009
+ *
+ * Notes:
+ * This callback will almost certainly not do anything
+ * useful, other than to make certain that the filter will
+ * accept opque data.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_set_local_direct(const H5O_pline_t *pline)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pline->nused > 0);
+
+ /* Make "set local" callbacks for filters in pipeline */
+ if(H5Z_prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_SET_LOCAL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local_direct() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_modify
+ *
+ * Purpose: Modify filter parameters for specified pipeline.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_modify(const H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags,
+ size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
+{
+ size_t idx; /* Index of filter in pipeline */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pline);
+ HDassert(filter >= 0 && filter <= H5Z_FILTER_MAX);
+ HDassert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK)));
+ HDassert(0 == cd_nelmts || cd_values);
+
+ /* Locate the filter in the pipeline */
+ for(idx = 0; idx < pline->nused; idx++)
+ if(pline->filter[idx].id == filter)
+ break;
+
+ /* Check if the filter was not already in the pipeline */
+ if(idx > pline->nused)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline")
+
+ /* Change parameters for filter */
+ pline->filter[idx].flags = flags;
+ pline->filter[idx].cd_nelmts = cd_nelmts;
+
+ /* Free any existing parameters */
+ if(pline->filter[idx].cd_values != NULL && pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
+ H5MM_xfree(pline->filter[idx].cd_values);
+
+ /* Set parameters */
+ if(cd_nelmts > 0) {
+ size_t i; /* Local index variable */
+
+ /* Allocate memory or point at internal buffer */
+ if(cd_nelmts > H5Z_COMMON_CD_VALUES) {
+ pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned));
+ if(NULL == pline->filter[idx].cd_values)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter parameters")
+ } /* end if */
+ else
+ pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
+
+ /* Copy client data values */
+ for(i = 0; i < cd_nelmts; i++)
+ pline->filter[idx].cd_values[i] = cd_values[i];
+ } /* end if */
+ else
+ pline->filter[idx].cd_values = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_modify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_append
+ *
+ * Purpose: Append another filter to the specified pipeline.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_append(H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags,
+ size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
+{
+ size_t idx;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pline);
+ HDassert(filter >= 0 && filter <= H5Z_FILTER_MAX);
+ HDassert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK)));
+ HDassert(0 == cd_nelmts || cd_values);
+
+ /*
+ * Check filter limit. We do it here for early warnings although we may
+ * decide to relax this restriction in the future.
+ */
+ if(pline->nused >= H5Z_MAX_NFILTERS)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "too many filters in pipeline")
+
+ /* Check for freshly allocated filter pipeline */
+ if(pline->version == 0)
+ pline->version = H5O_PLINE_VERSION_1;
+
+ /* Allocate additional space in the pipeline if it's full */
+ if(pline->nused >= pline->nalloc) {
+ H5O_pline_t x;
+ size_t n;
+
+ /* Each filter's data may be stored internally or may be
+ * a separate block of memory.
+ * For each filter, if cd_values points to the internal array
+ * _cd_values, the pointer will need to be updated when the
+ * filter struct is reallocated. Set these pointers to ~NULL
+ * so that we can reset them after reallocating the filters array.
+ */
+ for(n = 0; n < pline->nalloc; ++n)
+ if(pline->filter[n].cd_values == pline->filter[n]._cd_values)
+ pline->filter[n].cd_values = (unsigned *)((void *) ~((size_t)NULL));
+
+ x.nalloc = MAX(H5Z_MAX_NFILTERS, 2 * pline->nalloc);
+ x.filter = (H5Z_filter_info_t *)H5MM_realloc(pline->filter, x.nalloc * sizeof(x.filter[0]));
+ if(NULL == x.filter)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter pipeline")
+
+ /* Fix pointers in previous filters that need to point to their own
+ * internal data.
+ */
+ for(n = 0; n < pline->nalloc; ++n)
+ if(x.filter[n].cd_values == (void *) ~((size_t) NULL))
+ x.filter[n].cd_values = x.filter[n]._cd_values;
+
+ /* Point to newly allocated buffer */
+ pline->nalloc = x.nalloc;
+ pline->filter = x.filter;
+ } /* end if */
+
+ /* Add the new filter to the pipeline */
+ idx = pline->nused;
+ pline->filter[idx].id = filter;
+ pline->filter[idx].flags = flags;
+ pline->filter[idx].name = NULL; /*we'll pick it up later*/
+ pline->filter[idx].cd_nelmts = cd_nelmts;
+ if(cd_nelmts > 0) {
+ size_t i; /* Local index variable */
+
+ /* Allocate memory or point at internal buffer */
+ if(cd_nelmts > H5Z_COMMON_CD_VALUES) {
+ pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned));
+ if(NULL == pline->filter[idx].cd_values)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter")
+ } /* end if */
+ else
+ pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
+
+ /* Copy client data values */
+ for(i = 0; i < cd_nelmts; i++)
+ pline->filter[idx].cd_values[i] = cd_values[i];
+ } /* end if */
+ else
+ pline->filter[idx].cd_values = NULL;
+
+ pline->nused++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_append() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_find_idx
+ *
+ * Purpose: Given a filter ID return the offset in the global array
+ * that holds all the registered filters.
+ *
+ * Return: Success: Non-negative index of entry in global filter table.
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5Z_find_idx(H5Z_filter_t id)
+{
+ size_t i; /* Local index variable */
+ int ret_value=FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ for (i=0; i<H5Z_table_used_g; i++)
+ if (H5Z_table_g[i].id == id)
+ HGOTO_DONE((int)i)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_find_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_find
+ *
+ * Purpose: Given a filter ID return a pointer to a global struct that
+ * defines the filter.
+ *
+ * Return: Success: Ptr to entry in global filter table.
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 5, 1998
+ *
+ * Modifications:
+ * Use H5Z_find_idx now
+ * Quincey Koziol, April 5, 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_class2_t *
+H5Z_find(H5Z_filter_t id)
+{
+ int idx; /* Filter index in global table */
+ H5Z_class2_t *ret_value=NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Get the index in the global table */
+ if((idx=H5Z_find_idx(id))<0)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "required filter is not registered")
+
+ /* Set return value */
+ ret_value=H5Z_table_g+idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5Z_find() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_pipeline
+ *
+ * Purpose: Process data through the filter pipeline. The FLAGS argument
+ * is the filter invocation flags (definition flags come from
+ * the PLINE->filter[].flags). The filters are processed in
+ * definition order unless the H5Z_FLAG_REVERSE is set. The
+ * FILTER_MASK is a bit-mask to indicate which filters to skip
+ * and on exit will indicate which filters failed. Each
+ * filter has an index number in the pipeline and that index
+ * number is the filter's bit in the FILTER_MASK. NBYTES is the
+ * number of bytes of data to filter and on exit should be the
+ * number of resulting bytes while BUF_SIZE holds the total
+ * allocated size of the buffer, which is pointed to BUF.
+ *
+ * If the buffer must grow during processing of the pipeline
+ * then the pipeline function should free the original buffer
+ * and return a fresh buffer, adjusting BUF_SIZE accordingly.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_pipeline(const H5O_pline_t *pline, unsigned flags,
+ unsigned *filter_mask/*in,out*/, H5Z_EDC_t edc_read,
+ H5Z_cb_t cb_struct, size_t *nbytes/*in,out*/,
+ size_t *buf_size/*in,out*/, void **buf/*in,out*/)
+{
+ size_t i, idx, new_nbytes;
+ int fclass_idx; /* Index of filter class in global table */
+ H5Z_class2_t *fclass=NULL; /* Filter class pointer */
+#ifdef H5Z_DEBUG
+ H5Z_stats_t *fstats=NULL; /* Filter stats pointer */
+ H5_timer_t timer;
+#endif
+ unsigned failed = 0;
+ unsigned tmp_flags;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(0==(flags & ~((unsigned)H5Z_FLAG_INVMASK)));
+ HDassert(filter_mask);
+ HDassert(nbytes && *nbytes>0);
+ HDassert(buf_size && *buf_size>0);
+ HDassert(buf && *buf);
+ HDassert(!pline || pline->nused<H5Z_MAX_NFILTERS);
+
+ if (pline && (flags & H5Z_FLAG_REVERSE)) { /* Read */
+ for (i=pline->nused; i>0; --i) {
+ idx = i-1;
+
+ if (*filter_mask & ((unsigned)1<<idx)) {
+ failed |= (unsigned)1 << idx;
+ continue;/*filter excluded*/
+ }
+
+ /* If the filter isn't registered and the application doesn't
+ * indicate no plugin through HDF5_PRELOAD_PLUG (using the symbol "::"),
+ * try to load it dynamically and register it. Otherwise, return failure
+ */
+ if((fclass_idx = H5Z_find_idx(pline->filter[idx].id)) < 0) {
+ hbool_t issue_error = FALSE;
+ const H5Z_class2_t *filter_info;
+
+ /* Try loading the filter */
+ if(NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, (int)(pline->filter[idx].id)))) {
+ /* Register the filter we loaded */
+ if(H5Z_register(filter_info) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter")
+
+ /* Search in the table of registered filters again to find the dynamic filter just loaded and registered */
+ if((fclass_idx = H5Z_find_idx(pline->filter[idx].id)) < 0)
+ issue_error = TRUE;
+ } /* end if */
+ else
+ issue_error = TRUE;
+
+ /* Check for error */
+ if(issue_error) {
+ /* Print out the filter name to give more info. But the name is optional for
+ * the filter */
+ if(pline->filter[idx].name)
+ HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "required filter '%s' is not registered", pline->filter[idx].name)
+ else
+ HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "required filter (name unavailable) is not registered")
+ } /* end if */
+ } /* end if */
+
+ fclass=&H5Z_table_g[fclass_idx];
+#ifdef H5Z_DEBUG
+ fstats=&H5Z_stat_table_g[fclass_idx];
+ H5_timer_begin(&timer);
+#endif
+ tmp_flags=flags|(pline->filter[idx].flags);
+ tmp_flags|=(edc_read== H5Z_DISABLE_EDC) ? H5Z_FLAG_SKIP_EDC : 0;
+ new_nbytes = (fclass->filter)(tmp_flags, pline->filter[idx].cd_nelmts,
+ pline->filter[idx].cd_values, *nbytes, buf_size, buf);
+
+#ifdef H5Z_DEBUG
+ H5_timer_end(&(fstats->stats[1].timer), &timer);
+ fstats->stats[1].total += MAX(*nbytes, new_nbytes);
+ if (0==new_nbytes) fstats->stats[1].errors += *nbytes;
+#endif
+
+ if(0==new_nbytes) {
+ if((cb_struct.func && (H5Z_CB_FAIL==cb_struct.func(pline->filter[idx].id, *buf, *buf_size, cb_struct.op_data)))
+ || !cb_struct.func)
+ HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "filter returned failure during read")
+
+ *nbytes = *buf_size;
+ failed |= (unsigned)1 << idx;
+ H5E_clear_stack(NULL);
+ } else {
+ *nbytes = new_nbytes;
+ }
+ }
+ } else if (pline) { /* Write */
+ for (idx=0; idx<pline->nused; idx++) {
+ if (*filter_mask & ((unsigned)1<<idx)) {
+ failed |= (unsigned)1 << idx;
+ continue; /*filter excluded*/
+ }
+ if ((fclass_idx=H5Z_find_idx(pline->filter[idx].id))<0) {
+ /* Check if filter is optional -- If it isn't, then error */
+ if ((pline->filter[idx].flags & H5Z_FLAG_OPTIONAL) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "required filter is not registered")
+
+ failed |= (unsigned)1 << idx;
+ H5E_clear_stack(NULL);
+ continue; /*filter excluded*/
+ }
+ fclass=&H5Z_table_g[fclass_idx];
+#ifdef H5Z_DEBUG
+ fstats=&H5Z_stat_table_g[fclass_idx];
+ H5_timer_begin(&timer);
+#endif
+ new_nbytes = (fclass->filter)(flags|(pline->filter[idx].flags), pline->filter[idx].cd_nelmts,
+ pline->filter[idx].cd_values, *nbytes, buf_size, buf);
+#ifdef H5Z_DEBUG
+ H5_timer_end(&(fstats->stats[0].timer), &timer);
+ fstats->stats[0].total += MAX(*nbytes, new_nbytes);
+ if (0==new_nbytes) fstats->stats[0].errors += *nbytes;
+#endif
+ if(0==new_nbytes) {
+ if (0==(pline->filter[idx].flags & H5Z_FLAG_OPTIONAL)) {
+ if((cb_struct.func && (H5Z_CB_FAIL==cb_struct.func(pline->filter[idx].id, *buf, *nbytes, cb_struct.op_data)))
+ || !cb_struct.func)
+ HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "filter returned failure")
+
+ *nbytes = *buf_size;
+ }
+
+ failed |= (unsigned)1 << idx;
+ H5E_clear_stack(NULL);
+ } else {
+ *nbytes = new_nbytes;
+ }
+ }
+ }
+
+ *filter_mask = failed;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_info
+ *
+ * Purpose: Get pointer to filter info for pipeline
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, April 5, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_filter_info_t *
+H5Z_filter_info(const H5O_pline_t *pline, H5Z_filter_t filter)
+{
+ size_t idx; /* Index of filter in pipeline */
+ H5Z_filter_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(pline);
+ HDassert(filter>=0 && filter<=H5Z_FILTER_MAX);
+
+ /* Locate the filter in the pipeline */
+ for(idx=0; idx<pline->nused; idx++)
+ if(pline->filter[idx].id==filter)
+ break;
+
+ /* Check if the filter was not already in the pipeline */
+ if(idx>=pline->nused)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "filter not in pipeline")
+
+ /* Set return value */
+ ret_value=&pline->filter[idx];
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_filter_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_in_pline
+ *
+ * Purpose: Check wheter a filter is in the filter pipeline using the
+ * filter ID. This function is very similar to H5Z_filter_info
+ *
+ * Return: TRUE - found filter
+ * FALSE - not found
+ * FAIL - error
+ *
+ * Programmer: Raymond Lu
+ * 26 April 2013
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Z_filter_in_pline(const H5O_pline_t *pline, H5Z_filter_t filter)
+{
+ size_t idx; /* Index of filter in pipeline */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(pline);
+ HDassert(filter>=0 && filter<=H5Z_FILTER_MAX);
+
+ /* Locate the filter in the pipeline */
+ for(idx=0; idx<pline->nused; idx++)
+ if(pline->filter[idx].id==filter)
+ break;
+
+ /* Check if the filter was not already in the pipeline */
+ if(idx>=pline->nused)
+ ret_value = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_filter_in_pline() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_all_filters_avail
+ *
+ * Purpose: Verify that all the filters in a pipeline are currently
+ * available (i.e. registered)
+ *
+ * Return: Non-negative (TRUE/FALSE) on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, April 8, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Z_all_filters_avail(const H5O_pline_t *pline)
+{
+ size_t i,j; /* Local index variable */
+ htri_t ret_value=TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(pline);
+
+ /* Iterate through all the filters in pipeline */
+ for(i=0; i<pline->nused; i++) {
+
+ /* Look for each filter in the list of registered filters */
+ for(j=0; j<H5Z_table_used_g; j++)
+ if(H5Z_table_g[j].id==pline->filter[i].id)
+ break;
+
+ /* Check if we didn't find the filter */
+ if(j==H5Z_table_used_g)
+ HGOTO_DONE(FALSE)
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_all_filters_avail() */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_delete
+ *
+ * Purpose: Delete filter FILTER from pipeline PLINE;
+ * deletes all filters if FILTER is H5Z_FILTER_NONE
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Pedro Vicente
+ * Monday, January 26, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_delete(H5O_pline_t *pline, H5Z_filter_t filter)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ HDassert(pline);
+ HDassert(filter >= 0 && filter <= H5Z_FILTER_MAX);
+
+ /* if the pipeline has no filters, just return */
+ if(pline->nused==0)
+ HGOTO_DONE(SUCCEED)
+
+ /* Delete all filters */
+ if(H5Z_FILTER_ALL == filter) {
+ if(H5O_msg_reset(H5O_PLINE_ID, pline) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFREE, FAIL, "can't release pipeline info")
+ } /* end if */
+ /* Delete filter */
+ else {
+ size_t idx; /* Index of filter in pipeline */
+ hbool_t found = FALSE; /* Indicate filter was found in pipeline */
+
+ /* Locate the filter in the pipeline */
+ for(idx = 0; idx < pline->nused; idx++)
+ if(pline->filter[idx].id == filter) {
+ found = TRUE;
+ break;
+ } /* end if */
+
+ /* filter was not found in the pipeline */
+ if(!found)
+ HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline")
+
+ /* Free information for deleted filter */
+ if(pline->filter[idx].name && pline->filter[idx].name != pline->filter[idx]._name)
+ HDassert((HDstrlen(pline->filter[idx].name) + 1) > H5Z_COMMON_NAME_LEN);
+ if(pline->filter[idx].name != pline->filter[idx]._name)
+ pline->filter[idx].name = (char *)H5MM_xfree(pline->filter[idx].name);
+ if(pline->filter[idx].cd_values && pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
+ HDassert(pline->filter[idx].cd_nelmts > H5Z_COMMON_CD_VALUES);
+ if(pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
+ pline->filter[idx].cd_values = (unsigned *)H5MM_xfree(pline->filter[idx].cd_values);
+
+ /* Remove filter from pipeline array */
+ if((idx + 1) < pline->nused) {
+ /* Copy filters down & fix up any client data value arrays using internal storage */
+ for(; (idx + 1) < pline->nused; idx++) {
+ pline->filter[idx] = pline->filter[idx + 1];
+ if(pline->filter[idx].name && (HDstrlen(pline->filter[idx].name) + 1) <= H5Z_COMMON_NAME_LEN)
+ pline->filter[idx].name = pline->filter[idx]._name;
+ if(pline->filter[idx].cd_nelmts <= H5Z_COMMON_CD_VALUES)
+ pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
+ } /* end for */
+ } /* end if */
+
+ /* Decrement number of used filters */
+ pline->nused--;
+
+ /* Reset information for previous last filter in pipeline */
+ HDmemset(&pline->filter[pline->nused], 0, sizeof(H5Z_filter_info_t));
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Zget_filter_info
+ *
+ * Purpose: Gets information about a pipeline data filter and stores it
+ * in filter_config_flags.
+ *
+ * Return: zero on success / negative on failure
+ *
+ * Programmer: James Laird and Nat Furrer
+ * Monday, June 7, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Zget_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "Zf*Iu", filter, filter_config_flags);
+
+ /* Get the filter info */
+ if(H5Z_get_filter_info(filter, filter_config_flags) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "Filter info not retrieved")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Zget_filter_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_get_filter_info
+ *
+ * Purpose: Gets information about a pipeline data filter and stores it
+ * in filter_config_flags.
+ *
+ * Return: zero on success / negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, May 11, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_get_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags)
+{
+ H5Z_class2_t *fclass;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Look up the filter class info */
+ if(NULL == (fclass = H5Z_find(filter)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, FAIL, "Filter not defined")
+
+ /* Set the filter config flags for the application */
+ if(filter_config_flags != NULL) {
+ *filter_config_flags = 0;
+
+ if(fclass->encoder_present)
+ *filter_config_flags |= H5Z_FILTER_CONFIG_ENCODE_ENABLED;
+ if(fclass->decoder_present)
+ *filter_config_flags |= H5Z_FILTER_CONFIG_DECODE_ENABLED;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_get_filter_info() */
+
diff --git a/src/H5Zdeflate.c b/src/H5Zdeflate.c
new file mode 100644
index 0000000..34fdfec
--- /dev/null
+++ b/src/H5Zdeflate.c
@@ -0,0 +1,206 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, August 27, 1999
+ */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Zpkg.h" /* Data filters */
+
+#ifdef H5_HAVE_FILTER_DEFLATE
+
+#if defined(H5_HAVE_ZLIB_H) && !defined(H5_ZLIB_HEADER)
+# define H5_ZLIB_HEADER "zlib.h"
+#endif
+#if defined(H5_ZLIB_HEADER)
+# include H5_ZLIB_HEADER /* "zlib.h" */
+#endif
+
+/* Local function prototypes */
+static size_t H5Z_filter_deflate (unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf);
+
+/* This message derives from H5Z */
+const H5Z_class2_t H5Z_DEFLATE[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_DEFLATE, /* Filter id number */
+ 1, /* encoder_present flag (set to true) */
+ 1, /* decoder_present flag (set to true) */
+ "deflate", /* Filter name for debugging */
+ NULL, /* The "can apply" callback */
+ NULL, /* The "set local" callback */
+ H5Z_filter_deflate, /* The actual filter function */
+}};
+
+#define H5Z_DEFLATE_SIZE_ADJUST(s) (HDceil(((double)(s)) * (double)1.001f) + 12)
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_deflate
+ *
+ * Purpose: Implement an I/O filter around the 'deflate' algorithm in
+ * libz
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_deflate (unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes,
+ size_t *buf_size, void **buf)
+{
+ void *outbuf = NULL; /* Pointer to new buffer */
+ int status; /* Status from zlib operation */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Sanity check */
+ HDassert(*buf_size > 0);
+ HDassert(buf);
+ HDassert(*buf);
+
+ /* Check arguments */
+ if (cd_nelmts!=1 || cd_values[0]>9)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid deflate aggression level")
+
+ if (flags & H5Z_FLAG_REVERSE) {
+ /* Input; uncompress */
+ z_stream z_strm; /* zlib parameters */
+ size_t nalloc = *buf_size; /* Number of bytes for output (compressed) buffer */
+
+ /* Allocate space for the compressed buffer */
+ if (NULL==(outbuf = H5MM_malloc(nalloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for deflate uncompression")
+
+ /* Set the uncompression parameters */
+ HDmemset(&z_strm, 0, sizeof(z_strm));
+ z_strm.next_in = (Bytef *)*buf;
+ H5_CHECKED_ASSIGN(z_strm.avail_in, unsigned, nbytes, size_t);
+ z_strm.next_out = (Bytef *)outbuf;
+ H5_CHECKED_ASSIGN(z_strm.avail_out, unsigned, nalloc, size_t);
+
+ /* Initialize the uncompression routines */
+ if (Z_OK!=inflateInit(&z_strm))
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "inflateInit() failed")
+
+ /* Loop to uncompress the buffer */
+ do {
+ /* Uncompress some data */
+ status = inflate(&z_strm, Z_SYNC_FLUSH);
+
+ /* Check if we are done uncompressing data */
+ if (Z_STREAM_END==status)
+ break; /*done*/
+
+ /* Check for error */
+ if (Z_OK!=status) {
+ (void)inflateEnd(&z_strm);
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "inflate() failed")
+ }
+ else {
+ /* If we're not done and just ran out of buffer space, get more */
+ if(0 == z_strm.avail_out) {
+ void *new_outbuf; /* Pointer to new output buffer */
+
+ /* Allocate a buffer twice as big */
+ nalloc *= 2;
+ if(NULL == (new_outbuf = H5MM_realloc(outbuf, nalloc))) {
+ (void)inflateEnd(&z_strm);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for deflate uncompression")
+ } /* end if */
+ outbuf = new_outbuf;
+
+ /* Update pointers to buffer for next set of uncompressed data */
+ z_strm.next_out = (unsigned char*)outbuf + z_strm.total_out;
+ z_strm.avail_out = (uInt)(nalloc - z_strm.total_out);
+ } /* end if */
+ } /* end else */
+ } while(status==Z_OK);
+
+ /* Free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set return values */
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = nalloc;
+ ret_value = z_strm.total_out;
+
+ /* Finish uncompressing the stream */
+ (void)inflateEnd(&z_strm);
+ } /* end if */
+ else {
+ /*
+ * Output; compress but fail if the result would be larger than the
+ * input. The library doesn't provide in-place compression, so we
+ * must allocate a separate buffer for the result.
+ */
+ const Bytef *z_src = (const Bytef*)(*buf);
+ Bytef *z_dst; /*destination buffer */
+ uLongf z_dst_nbytes = (uLongf)H5Z_DEFLATE_SIZE_ADJUST(nbytes);
+ uLong z_src_nbytes = (uLong)nbytes;
+ int aggression; /* Compression aggression setting */
+
+ /* Set the compression aggression level */
+ H5_CHECKED_ASSIGN(aggression, int, cd_values[0], unsigned);
+
+ /* Allocate output (compressed) buffer */
+ if(NULL == (outbuf = H5MM_malloc(z_dst_nbytes)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "unable to allocate deflate destination buffer")
+ z_dst = (Bytef *)outbuf;
+
+ /* Perform compression from the source to the destination buffer */
+ status = compress2(z_dst, &z_dst_nbytes, z_src, z_src_nbytes, aggression);
+
+ /* Check for various zlib errors */
+ if(Z_BUF_ERROR == status)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "overflow")
+ else if(Z_MEM_ERROR == status)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "deflate memory error")
+ else if(Z_OK != status)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "other deflate error")
+ /* Successfully uncompressed the buffer */
+ else {
+ /* Free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set return values */
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = nbytes;
+ ret_value = z_dst_nbytes;
+ } /* end else */
+ } /* end else */
+
+done:
+ if(outbuf)
+ H5MM_xfree(outbuf);
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+#endif /* H5_HAVE_FILTER_DEFLATE */
+
diff --git a/src/H5Zfletcher32.c b/src/H5Zfletcher32.c
new file mode 100644
index 0000000..4cd77ef
--- /dev/null
+++ b/src/H5Zfletcher32.c
@@ -0,0 +1,164 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <slu@ncsa.uiuc.edu>
+ * Jan 3, 2003
+ */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Zpkg.h" /* Data filters */
+
+/* Local function prototypes */
+static size_t H5Z_filter_fletcher32 (unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf);
+
+/* This message derives from H5Z */
+const H5Z_class2_t H5Z_FLETCHER32[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_FLETCHER32, /* Filter id number */
+ 1, /* encoder_present flag (set to true) */
+ 1, /* decoder_present flag (set to true) */
+ "fletcher32", /* Filter name for debugging */
+ NULL, /* The "can apply" callback */
+ NULL, /* The "set local" callback */
+ H5Z_filter_fletcher32, /* The actual filter function */
+}};
+
+#define FLETCHER_LEN 4
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_fletcher32
+ *
+ * Purpose: Implement an I/O filter of Fletcher32 Checksum
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Raymond Lu
+ * Jan 3, 2003
+ *
+ * Modifications:
+ * Raymond Lu
+ * July 8, 2005
+ * There was a bug in the calculating code of the Fletcher32
+ * checksum in the library before v1.6.3. The checksum
+ * value wasn't consistent between big-endian and little-endian
+ * systems. This bug was fixed in Release 1.6.3. However,
+ * after fixing the bug, the checksum value is no longer the
+ * same as before on little-endian system. We'll check both
+ * the correct checksum and the wrong checksum to be consistent
+ * with Release 1.6.2 and before.
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_fletcher32 (unsigned flags, size_t H5_ATTR_UNUSED cd_nelmts, const unsigned H5_ATTR_UNUSED cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf)
+{
+ void *outbuf = NULL; /* Pointer to new buffer */
+ unsigned char *src = (unsigned char*)(*buf);
+ uint32_t fletcher; /* Checksum value */
+ uint32_t reversed_fletcher; /* Possible wrong checksum value */
+ uint8_t c[4];
+ uint8_t tmp;
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ HDassert(sizeof(uint32_t)>=4);
+
+ if (flags & H5Z_FLAG_REVERSE) { /* Read */
+ /* Do checksum if it's enabled for read; otherwise skip it
+ * to save performance. */
+ if (!(flags & H5Z_FLAG_SKIP_EDC)) {
+ unsigned char *tmp_src; /* Pointer to checksum in buffer */
+ size_t src_nbytes = nbytes; /* Original number of bytes */
+ uint32_t stored_fletcher; /* Stored checksum value */
+
+ /* Get the stored checksum */
+ src_nbytes -= FLETCHER_LEN;
+ tmp_src=src+src_nbytes;
+ UINT32DECODE(tmp_src, stored_fletcher);
+
+ /* Compute checksum (can't fail) */
+ fletcher = H5_checksum_fletcher32(src, src_nbytes);
+
+ /* The reversed checksum. There was a bug in the calculating code of
+ * the Fletcher32 checksum in the library before v1.6.3. The checksum
+ * value wasn't consistent between big-endian and little-endian systems.
+ * This bug was fixed in Release 1.6.3. However, after fixing the bug,
+ * the checksum value is no longer the same as before on little-endian
+ * system. We'll check both the correct checksum and the wrong
+ * checksum to be consistent with Release 1.6.2 and before.
+ */
+ HDmemcpy(c, &fletcher, (size_t)4);
+
+ tmp = c[1];
+ c[1] = c[0];
+ c[0] = tmp;
+
+ tmp = c[3];
+ c[3] = c[2];
+ c[2] = tmp;
+
+ HDmemcpy(&reversed_fletcher, c, (size_t)4);
+
+ /* Verify computed checksum matches stored checksum */
+ if(stored_fletcher != fletcher && stored_fletcher != reversed_fletcher)
+ HGOTO_ERROR(H5E_STORAGE, H5E_READERROR, 0, "data error detected by Fletcher32 checksum")
+ }
+
+ /* Set return values */
+ /* (Re-use the input buffer, just note that the size is smaller by the size of the checksum) */
+ ret_value = nbytes-FLETCHER_LEN;
+ } else { /* Write */
+ unsigned char *dst; /* Temporary pointer to destination buffer */
+
+ /* Compute checksum (can't fail) */
+ fletcher = H5_checksum_fletcher32(src, nbytes);
+
+ if (NULL == (outbuf = H5MM_malloc(nbytes + FLETCHER_LEN)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "unable to allocate Fletcher32 checksum destination buffer")
+
+ dst = (unsigned char *) outbuf;
+
+ /* Copy raw data */
+ HDmemcpy((void*)dst, (void*)(*buf), nbytes);
+
+ /* Append checksum to raw data for storage */
+ dst += nbytes;
+ UINT32ENCODE(dst, fletcher);
+
+ /* Free input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set return values */
+ *buf_size = nbytes + FLETCHER_LEN;
+ *buf = outbuf;
+ outbuf = NULL;
+ ret_value = *buf_size;
+ }
+
+done:
+ if(outbuf)
+ H5MM_xfree(outbuf);
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Zmodule.h b/src/H5Zmodule.h
new file mode 100644
index 0000000..97e158c
--- /dev/null
+++ b/src/H5Zmodule.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@hdfgroup.org>
+ * Saturday, September 12, 2015
+ *
+ * Purpose: This file contains declarations which define macros for the
+ * H5Z package. Including this header means that the source file
+ * is part of the H5Z package.
+ */
+#ifndef _H5Zmodule_H
+#define _H5Zmodule_H
+
+/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error
+ * reporting macros.
+ */
+#define H5Z_MODULE
+#define H5_MY_PKG H5Z
+#define H5_MY_PKG_ERR H5E_PLINE
+#define H5_MY_PKG_INIT YES
+
+#endif /* _H5Zmodule_H */
+
diff --git a/src/H5Znbit.c b/src/H5Znbit.c
new file mode 100644
index 0000000..373eb37
--- /dev/null
+++ b/src/H5Znbit.c
@@ -0,0 +1,1631 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property lists */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5Zpkg.h" /* Data filters */
+
+/* Struct of parameters needed for compressing/decompressing
+ * one nbit atomic datatype: integer or floating-point
+ */
+typedef struct {
+ unsigned size; /* size of datatype */
+ unsigned order; /* datatype endianness order */
+ unsigned precision; /* datatype precision */
+ unsigned offset; /* datatype offset */
+} parms_atomic;
+
+/* Local function prototypes */
+static htri_t H5Z_can_apply_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static herr_t H5Z_set_local_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static size_t H5Z_filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf);
+
+static void H5Z_calc_parms_nooptype(size_t *cd_values_actual_nparms);
+static void H5Z_calc_parms_atomic(size_t *cd_values_actual_nparms);
+static herr_t H5Z_calc_parms_array(const H5T_t *type, size_t *cd_values_actual_nparms);
+static herr_t H5Z_calc_parms_compound(const H5T_t *type, size_t *cd_values_actual_nparms);
+
+static herr_t H5Z_set_parms_nooptype(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[]);
+static herr_t H5Z_set_parms_atomic(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress);
+static herr_t H5Z_set_parms_array(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress);
+static herr_t H5Z_set_parms_compound(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress);
+
+static void H5Z_nbit_next_byte(size_t *j, size_t *buf_len);
+static void H5Z_nbit_decompress_one_byte(unsigned char *data, size_t data_offset,
+ unsigned k, unsigned begin_i, unsigned end_i, unsigned char *buffer, size_t *j,
+ size_t *buf_len, const parms_atomic *p, size_t datatype_len);
+static void H5Z_nbit_compress_one_byte(unsigned char *data, size_t data_offset, unsigned k, unsigned begin_i,
+ unsigned end_i, unsigned char *buffer, size_t *j, size_t *buf_len, const parms_atomic *p, size_t datatype_len);
+static void H5Z_nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, unsigned size);
+static void H5Z_nbit_decompress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const parms_atomic *p);
+static herr_t H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index);
+static herr_t H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index);
+static herr_t H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+ const unsigned parms[]);
+static void H5Z_nbit_compress_one_nooptype(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, unsigned size);
+static void H5Z_nbit_compress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const parms_atomic *p);
+static void H5Z_nbit_compress_one_array(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index);
+static void H5Z_nbit_compress_one_compound(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index);
+static void H5Z_nbit_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+ size_t *buffer_size, const unsigned parms[]);
+
+/* This message derives from H5Z */
+H5Z_class2_t H5Z_NBIT[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_NBIT, /* Filter id number */
+ 1, /* Assume encoder present: check before registering */
+ 1, /* decoder_present flag (set to true) */
+ "nbit", /* Filter name for debugging */
+ H5Z_can_apply_nbit, /* The "can apply" callback */
+ H5Z_set_local_nbit, /* The "set local" callback */
+ H5Z_filter_nbit, /* The actual filter function */
+}};
+
+/* Local macros */
+#define H5Z_NBIT_ATOMIC 1 /* Atomic datatype class: integer/floating-point */
+#define H5Z_NBIT_ARRAY 2 /* Array datatype class */
+#define H5Z_NBIT_COMPOUND 3 /* Compound datatype class */
+#define H5Z_NBIT_NOOPTYPE 4 /* Other datatype class: nbit does no compression */
+#define H5Z_NBIT_MAX_NPARMS 4096 /* Max number of parameters for filter */
+#define H5Z_NBIT_ORDER_LE 0 /* Little endian for datatype byte order */
+#define H5Z_NBIT_ORDER_BE 1 /* Big endian for datatype byte order */
+
+/* Local variables */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_can_apply_nbit
+ *
+ * Purpose: Check the parameters for nbit compression for validity and
+ * whether they fit a particular dataset.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, December 21, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5Z_can_apply_nbit(hid_t H5_ATTR_UNUSED dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id)
+{
+ const H5T_t *type; /* Datatype */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get datatype */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get datatype's class, for checking the "datatype class" */
+ if(H5T_get_class(type, TRUE) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")
+
+ /* Get datatype's size, for checking the "datatype size" */
+ if(H5T_get_size(type) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_can_apply_nbit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_calc_parms_nooptype
+ *
+ * Purpose: Calculate the number of parameters of array cd_values[]
+ * of datatype that is not integer, nor floating-point, nor
+ * compound, and nor array.
+ *
+ * Programmer: Xiaowen Wu
+ * Thursday, March 3, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_calc_parms_nooptype(size_t *cd_values_actual_nparms)
+{
+ /* Store datatype class code */
+ *cd_values_actual_nparms += 1;
+
+ /* Store datatype size */
+ *cd_values_actual_nparms += 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_calc_parms_atomic
+ *
+ * Purpose: Calculate the number of parameters of array cd_values[]
+ * of atomic datatype whose datatype class is integer
+ * or floating point
+ *
+ * Programmer: Xiaowen Wu
+ * Saturday, January 29, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_calc_parms_atomic(size_t *cd_values_actual_nparms)
+{
+ /* Store datatype class code */
+ *cd_values_actual_nparms += 1;
+
+ /* Store datatype size */
+ *cd_values_actual_nparms += 1;
+
+ /* Store datatype endianness */
+ *cd_values_actual_nparms += 1;
+
+ /* Store datatype's precision */
+ *cd_values_actual_nparms += 1;
+
+ /* Store datatype's offset */
+ *cd_values_actual_nparms += 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_calc_parms_array
+ *
+ * Purpose: Calculate the number of parameters of array cd_values[]
+ * for a given datatype identifier type_id
+ * if its datatype class is array datatype
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Wednesday, January 19, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_calc_parms_array(const H5T_t *type, size_t *cd_values_actual_nparms)
+{
+ H5T_t *dtype_base = NULL; /* Array datatype's base datatype */
+ H5T_class_t dtype_base_class; /* Array datatype's base datatype's class */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Store datatype class code */
+ *cd_values_actual_nparms += 1;
+
+ /* Store array datatype's size */
+ *cd_values_actual_nparms += 1;
+
+ /* Get array datatype's base datatype */
+ if(NULL == (dtype_base = H5T_get_super(type)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype")
+
+ /* Get base datatype's class */
+ if((dtype_base_class = H5T_get_class(dtype_base, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype class")
+
+ /* Calculate number of the rest parameters according to base datatype's class */
+ switch(dtype_base_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ H5Z_calc_parms_atomic(cd_values_actual_nparms);
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_calc_parms_array(dtype_base, cd_values_actual_nparms) == FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_calc_parms_compound(dtype_base, cd_values_actual_nparms) == FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ /* Other datatype classes: nbit does no compression */
+ H5Z_calc_parms_nooptype(cd_values_actual_nparms);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit received bad datatype")
+ break;
+ } /* end switch */
+
+done:
+ if(dtype_base)
+ if(H5T_close(dtype_base) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close base datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_calc_parms_array() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_calc_parms_compound
+ *
+ * Purpose: Calculate the number of parameters of array cd_values[]
+ * for a given datatype identifier type_id
+ * if its datatype class is compound datatype
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Wednesday, January 19, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_calc_parms_compound(const H5T_t *type, size_t *cd_values_actual_nparms)
+{
+ int nmembers; /* Compound datatype's number of members */
+ H5T_t *dtype_member = NULL; /* Compound datatype's member datatype */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Store compound datatype class code */
+ *cd_values_actual_nparms += 1;
+
+ /* Store compound datatype's size */
+ *cd_values_actual_nparms += 1;
+
+ /* Get number of members */
+ if((nmembers = H5T_get_nmembers(type)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype number of members")
+
+ /* Store number of members */
+ *cd_values_actual_nparms += 1;
+
+ /* For each member, calculate parameters */
+ for(u = 0; u < (unsigned)nmembers; u++) {
+ H5T_class_t dtype_member_class; /* Compound datatype's member datatype's class */
+
+ /* Get member datatype */
+ if(NULL == (dtype_member = H5T_get_member_type(type, u, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype")
+
+ /* Get member datatype's class */
+ if((dtype_member_class = H5T_get_class(dtype_member, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype class")
+
+ /* Store member offset */
+ *cd_values_actual_nparms += 1;
+
+ /* Calculate parameters according to member's datatype class */
+ switch(dtype_member_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ H5Z_calc_parms_atomic(cd_values_actual_nparms);
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_calc_parms_array(dtype_member, cd_values_actual_nparms) == FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_calc_parms_compound(dtype_member, cd_values_actual_nparms) == FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ /* Other datatype classes: nbit does no compression */
+ H5Z_calc_parms_nooptype(cd_values_actual_nparms);
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit received bad datatype")
+ break;
+ } /* end switch */
+
+ /* Close member datatype */
+ if(H5T_close(dtype_member) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close member datatype")
+ dtype_member = NULL;
+ } /* end for */
+
+done:
+ if(dtype_member)
+ if(H5T_close(dtype_member) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close member datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_calc_params_compound */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_parms_nooptype
+ *
+ * Purpose: Set the array cd_values[] for a given datatype identifier
+ * type_id if its datatype class is not integer, nor
+ * floating-point, nor array, nor compound, nor VL datatype,
+ * and nor VL string
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, April 5, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_parms_nooptype(const H5T_t *type, unsigned *cd_values_index, unsigned cd_values[])
+{
+ size_t dtype_size; /* No-op datatype's size (in bytes) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set datatype class code */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_NOOPTYPE;
+
+ /* Get datatype's size */
+ if((dtype_size = H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Set "local" parameter for datatype size */
+ H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_size;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_parms_nooptype() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_parms_atomic
+ *
+ * Purpose: Set the array cd_values[] for a given datatype identifier
+ * type_id if its datatype class is integer or floating point
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, January 11, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_parms_atomic(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress)
+{
+ H5T_order_t dtype_order; /* Atomic datatype's endianness order */
+ size_t dtype_size; /* Atomic datatype's size (in bytes) */
+ size_t dtype_precision; /* Atomic datatype's precision (in bits) */
+ int sdtype_offset; /* Atomic datatype's offset (in bits) */
+ unsigned dtype_offset; /* Atomic datatype's offset (in bits) */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set datatype class code */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_ATOMIC;
+
+ /* Get datatype's size */
+ if((dtype_size = H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Set "local" parameter for datatype size */
+ H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_size;
+
+ /* Get datatype's endianness order */
+ if((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+
+ /* Set "local" parameter for datatype endianness */
+ switch(dtype_order) {
+ case H5T_ORDER_LE: /* Little-endian byte order */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_ORDER_LE;
+ break;
+
+ case H5T_ORDER_BE: /* Big-endian byte order */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_ORDER_BE;
+ break;
+
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+ } /* end switch */
+
+ /* Get datatype's precision */
+ if((dtype_precision = H5T_get_precision(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype precision")
+
+ /* Get datatype's offset */
+ if((sdtype_offset = H5T_get_offset(type)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype offset")
+ dtype_offset = (unsigned)sdtype_offset;
+
+ /* Check values of precision and offset */
+ if(dtype_precision > dtype_size * 8 || (dtype_precision + dtype_offset) > dtype_size * 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset")
+
+ /* Set "local" parameter for datatype precision */
+ H5_CHECK_OVERFLOW(dtype_precision, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_precision;
+
+ /* Set "local" parameter for datatype offset */
+ cd_values[(*cd_values_index)++] = dtype_offset;
+
+ /* If before this point, there is no need to compress, check the need to
+ * compress at this point. If current datatype is not full-precision,
+ * flag need_not_compress should be set to FALSE.
+ */
+ if(*need_not_compress) /* so far no need to compress */
+ if(dtype_offset != 0 || dtype_precision != dtype_size * 8)
+ *need_not_compress = FALSE;
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_parms_atomic() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_parms_array
+ *
+ * Purpose: Set the array cd_values[] for a given datatype identifier
+ * type_id if its datatype class is array datatype
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, April 5, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_parms_array(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress)
+{
+ H5T_t *dtype_base = NULL; /* Array datatype's base datatype */
+ H5T_class_t dtype_base_class; /* Array datatype's base datatype's class */
+ size_t dtype_size; /* Array datatype's size (in bytes) */
+ htri_t is_vlstring; /* flag indicating if datatype is varible-length string */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set datatype class code */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_ARRAY;
+
+ /* Get array datatype's size */
+ if((dtype_size = H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Set "local" parameter for array datatype's size */
+ H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_size;
+
+ /* Get array datatype's base datatype */
+ if(NULL == (dtype_base = H5T_get_super(type)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype")
+
+ /* Get base datatype's class */
+ if((dtype_base_class = H5T_get_class(dtype_base, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype class")
+
+ /* Call appropriate function according to base datatype's class */
+ switch(dtype_base_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ if(H5Z_set_parms_atomic(dtype_base, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_set_parms_array(dtype_base, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_set_parms_compound(dtype_base, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_VLEN:
+ /* Check if base datatype is a variable-length string */
+ if((is_vlstring = H5T_is_variable_str(dtype_base)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot determine if datatype is a variable-length string")
+
+ /* base datatype of VL or VL-string is not supported */
+ if(dtype_base_class == H5T_VLEN || is_vlstring)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "datatype not supported by nbit")
+
+ if(H5Z_set_parms_nooptype(dtype_base, cd_values_index, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ if(H5Z_set_parms_nooptype(dtype_base, cd_values_index, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit received bad datatype")
+ break;
+ } /* end switch */
+
+done:
+ if(dtype_base)
+ if(H5T_close(dtype_base) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close base datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_parms_array() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_parms_compound
+ *
+ * Purpose: Set the array cd_values[] for a given datatype identifier
+ * type_id if its datatype class is compound datatype
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, April 5, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_parms_compound(const H5T_t *type, unsigned *cd_values_index,
+ unsigned cd_values[], hbool_t *need_not_compress)
+{
+ int snmembers; /* Compound datatype's number of members */
+ unsigned nmembers; /* Compound datatype's number of members */
+ H5T_t *dtype_member = NULL; /* Compound datatype's member datatype */
+ H5T_class_t dtype_member_class; /* Compound datatype's member datatype's class */
+ size_t dtype_member_offset; /* Compound datatype's current member datatype's offset (in bytes) */
+ size_t dtype_next_member_offset;/* Compound datatype's next member datatype's offset (in bytes) */
+ size_t dtype_size; /* Compound datatype's size (in bytes) */
+ htri_t is_vlstring; /* flag indicating if datatype is varible-length string */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Set "local" parameter for compound datatype class code */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_COMPOUND;
+
+ /* Get datatype's size */
+ if((dtype_size = H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Set "local" parameter for compound datatype size */
+ H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_size;
+
+ /* Get number of members */
+ if((snmembers = H5T_get_nmembers(type)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype number of members")
+ nmembers = (unsigned)snmembers;
+
+ /* Set "local" parameter for number of members */
+ cd_values[(*cd_values_index)++] = nmembers;
+
+ /* For each member, set parameters */
+ for(u = 0; u < nmembers; u++) {
+ /* Get member datatype */
+ if(NULL == (dtype_member = H5T_get_member_type(type, u, H5T_COPY_TRANSIENT)))
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype")
+
+ /* Get member datatype's class */
+ if((dtype_member_class = H5T_get_class(dtype_member, TRUE)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype class")
+
+ /* Get member offset, success if H5T_get_class() success */
+ dtype_member_offset = H5T_get_member_offset(type, u);
+
+ /* Set "local" parameter for member offset */
+ H5_CHECK_OVERFLOW(dtype_member_offset, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_member_offset;
+
+ /* Call appropriate function according to member's datatype class */
+ switch(dtype_member_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ if(H5Z_set_parms_atomic(dtype_member, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_set_parms_array(dtype_member, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_set_parms_compound(dtype_member, cd_values_index, cd_values, need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_VLEN:
+ /* Check if datatype is a variable-length string */
+ if((is_vlstring = H5T_is_variable_str(dtype_member)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot determine if datatype is a variable-length string")
+
+ /* Because for some no-op datatype (VL datatype and VL string datatype), its
+ * size can not be retrieved correctly by using function call H5T_get_size,
+ * special handling is needed for getting the size. Here the difference between
+ * adjacent member offset is used (if alignment is present, the result can be
+ * larger, but it does not affect the nbit filter's correctness).
+ */
+ if(dtype_member_class == H5T_VLEN || is_vlstring) {
+ /* Set datatype class code */
+ cd_values[(*cd_values_index)++] = H5Z_NBIT_NOOPTYPE;
+
+ if(u != nmembers - 1)
+ dtype_next_member_offset = H5T_get_member_offset(type, u + 1);
+ else /* current member is the last member */
+ dtype_next_member_offset = dtype_size;
+
+ /* Set "local" parameter for datatype size */
+ H5_CHECK_OVERFLOW(dtype_member_offset, size_t, unsigned);
+ H5_CHECK_OVERFLOW(dtype_next_member_offset, size_t, unsigned);
+ cd_values[(*cd_values_index)++] = (unsigned)dtype_next_member_offset - (unsigned)dtype_member_offset;
+ }
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ /* other datatype that nbit does no compression */
+ if(H5Z_set_parms_nooptype(dtype_member, cd_values_index, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit was passed bad datatype")
+ break;
+ } /* end switch */
+
+ /* Close member datatype */
+ if(H5T_close(dtype_member) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close member datatype")
+ dtype_member = NULL;
+ } /* end for */
+
+done:
+ if(dtype_member)
+ if(H5T_close(dtype_member) < 0)
+ HDONE_ERROR(H5E_PLINE, H5E_CLOSEERROR, FAIL, "Unable to close member datatype")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_params_compound */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local_nbit
+ *
+ * Purpose: Set the "local" dataset parameters for nbit compression.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Tuesday, January 11, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_local_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id)
+{
+ H5P_genplist_t *dcpl_plist; /* Property list pointer */
+ const H5T_t *type; /* Datatype */
+ const H5S_t *ds; /* Dataspace */
+ unsigned flags; /* Filter flags */
+ unsigned cd_values_index; /* Index of array cd_values */
+ size_t cd_values_actual_nparms; /* Number of parameters in array cd_values[] */
+ size_t cd_nelmts = H5Z_NBIT_USER_NPARMS; /* Number of filter parameters */
+ unsigned *cd_values = NULL; /* Filter parameters */
+ hssize_t npoints; /* Number of points in the dataspace */
+ H5T_class_t dtype_class; /* Datatype's class */
+ hbool_t need_not_compress; /* Flag if TRUE indicating no need to do nbit compression */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get datatype */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get datatype's class */
+ if((dtype_class = H5T_get_class(type, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")
+
+ /* Calculate how many parameters will fill the cd_values array
+ * First three parameters reserved for:
+ * 1. number of parameters in array cd_values
+ * 2. flag if TRUE indicating no need to do nbit compression
+ * 3. number of elements in the chunk
+ */
+ cd_values_actual_nparms = 3;
+ switch(dtype_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ H5Z_calc_parms_atomic(&cd_values_actual_nparms);
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_calc_parms_array(type, &cd_values_actual_nparms) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_calc_parms_compound(type, &cd_values_actual_nparms) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot compute parameters for datatype")
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ /* No need to calculate other datatypes at top level */
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit received bad datatype")
+ break;
+ } /* end switch */
+
+ /* Check if the number of parameters exceed what cd_values[] can store */
+ if(cd_values_actual_nparms > H5Z_NBIT_MAX_NPARMS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "datatype needs too many nbit parameters")
+
+ /* Allocate memory space for cd_values[] */
+ if(NULL == (cd_values = (unsigned *)H5MM_malloc(cd_values_actual_nparms * sizeof(unsigned))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for cd_values[]")
+
+ /* Get the plist structure */
+ if(NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get the filter's current parameters */
+ if(H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_NBIT, &flags, &cd_nelmts, cd_values, (size_t)0, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get nbit parameters")
+
+ /* Get dataspace */
+ if(NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Get total number of elements in the chunk */
+ if((npoints = H5S_GET_EXTENT_NPOINTS(ds)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get number of points in the dataspace")
+ HDassert(npoints);
+
+ /* Initialize index for cd_values array starting from the third entry */
+ cd_values_index = 2;
+
+ /* Set "local" parameter for number of elements in the chunk */
+ H5_CHECK_OVERFLOW(npoints, hssize_t, unsigned);
+ cd_values[cd_values_index++] = (unsigned)npoints;
+
+ /* Assume no need to compress now, will be changed to FALSE later if not */
+ need_not_compress = TRUE;
+
+ /* Call appropriate function according to the datatype class */
+ switch(dtype_class) {
+ case H5T_INTEGER:
+ case H5T_FLOAT:
+ if(H5Z_set_parms_atomic(type, &cd_values_index, cd_values, &need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_ARRAY:
+ if(H5Z_set_parms_array(type, &cd_values_index, cd_values, &need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_COMPOUND:
+ if(H5Z_set_parms_compound(type, &cd_values_index, cd_values, &need_not_compress) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit cannot set parameters for datatype")
+ break;
+
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ /* No need to set parameters for other datatypes at top level */
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_NCLASSES:
+ default:
+ /* Badness */
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "nbit received bad datatype")
+ break;
+ } /* end switch */
+
+ /* Check if calculation of parameters matches with setting of parameters */
+ HDassert(cd_values_actual_nparms == cd_values_index);
+
+ /* Finally set the first two entries of cd_values[] */
+ H5_CHECK_OVERFLOW(cd_values_actual_nparms, size_t, unsigned);
+ cd_values[0] = (unsigned)cd_values_actual_nparms;
+ cd_values[1] = (unsigned)need_not_compress;
+
+ /* Modify the filter's parameters for this dataset */
+ if(H5P_modify_filter(dcpl_plist, H5Z_FILTER_NBIT, flags, cd_values_actual_nparms, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local nbit parameters")
+
+done:
+ if(cd_values)
+ H5MM_xfree(cd_values);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local_nbit() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_nbit
+ *
+ * Purpose: Implement an I/O filter for storing packed nbit data
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Xiaowen Wu
+ * Friday, January 21, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf)
+{
+ unsigned char *outbuf; /* pointer to new output buffer */
+ size_t size_out = 0; /* size of output buffer */
+ unsigned d_nelmts = 0; /* number of elements in the chunk */
+ size_t ret_value = 0; /* return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments
+ * cd_values[0] stores actual number of parameters in cd_values[]
+ */
+ if(cd_nelmts != cd_values[0])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid nbit aggression level")
+
+ /* check if need to do nbit compress or decompress
+ * cd_values[1] stores the flag if true indicating no need to compress
+ */
+ if(cd_values[1])
+ HGOTO_DONE(*buf_size)
+
+ /* copy a filter parameter to d_nelmts */
+ d_nelmts = cd_values[2];
+
+ /* input; decompress */
+ if(flags & H5Z_FLAG_REVERSE) {
+ size_out = d_nelmts * cd_values[4]; /* cd_values[4] stores datatype size */
+
+ /* allocate memory space for decompressed buffer */
+ if(NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for nbit decompression")
+
+ /* decompress the buffer */
+ if(H5Z__nbit_decompress(outbuf, d_nelmts, (unsigned char *)*buf, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, 0, "can't decompress buffer")
+ } /* end if */
+ /* output; compress */
+ else {
+ HDassert(nbytes == d_nelmts * cd_values[4]);
+
+ size_out = nbytes;
+
+ /* allocate memory space for compressed buffer */
+ if(NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for nbit compression")
+
+ /* compress the buffer, size_out will be changed */
+ H5Z_nbit_compress((unsigned char *)*buf, d_nelmts, outbuf, &size_out, cd_values);
+ } /* end else */
+
+ /* free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* set return values */
+ *buf = outbuf;
+ *buf_size = size_out;
+ ret_value = size_out;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_filter_nbit() */
+
+/* ======== Nbit Algorithm ===============================================
+ * assume one byte has 8 bit
+ * assume padding bit is 0
+ * assume size of unsigned char is one byte
+ * assume one data item of certain datatype is stored continously in bytes
+ * atomic datatype is treated on byte basis
+ */
+
+static void
+H5Z_nbit_next_byte(size_t *j, size_t *buf_len)
+{
+ ++(*j);
+ *buf_len = 8 * sizeof(unsigned char);
+}
+
+static void
+H5Z_nbit_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k,
+ unsigned begin_i, unsigned end_i, unsigned char *buffer, size_t *j, size_t *buf_len,
+ const parms_atomic *p, size_t datatype_len)
+{
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ size_t dat_offset;
+ unsigned char val; /* value to be copied in each data byte */
+
+ /* initialize value and bits of unsigned char to be copied */
+ val = buffer[*j];
+ dat_offset = 0;
+
+ if(begin_i != end_i) { /* significant bits occupy >1 unsigned char */
+ if(k == begin_i)
+ dat_len = 8 - (datatype_len - p->precision - p->offset) % 8;
+ else if(k == end_i) {
+ dat_len = 8 - p->offset % 8;
+ dat_offset = 8 - dat_len;
+ }
+ else
+ dat_len = 8;
+ } else { /* all significant bits in one unsigned char */
+ dat_offset = p->offset % 8;
+ dat_len = p->precision;
+ }
+
+ if(*buf_len > dat_len) {
+ data[data_offset + k] = (unsigned char)(
+ ((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)(~0) << dat_len))) << dat_offset);
+ *buf_len -= dat_len;
+ } else {
+ data[data_offset + k] = (unsigned char)(
+ ((val & ~((unsigned)(~0) << *buf_len)) << (dat_len - *buf_len)) << dat_offset);
+ dat_len -= *buf_len;
+ H5Z_nbit_next_byte(j, buf_len);
+ if(dat_len == 0)
+ return;
+
+ val = buffer[*j];
+ data[data_offset + k] |= (unsigned char)(
+ ((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)(~0) << dat_len))) << dat_offset);
+ *buf_len -= dat_len;
+ }
+}
+
+static void
+H5Z_nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, unsigned size)
+{
+ unsigned i; /* index */
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ for(i = 0; i < size; i++) {
+ /* initialize value and bits of unsigned char to be copied */
+ val = buffer[*j];
+ dat_len = sizeof(unsigned char) * 8;
+
+ data[data_offset + i] = (unsigned char)(((val & ~((unsigned)(~0) << *buf_len)) << (dat_len - *buf_len)));
+ dat_len -= *buf_len;
+ H5Z_nbit_next_byte(j, buf_len);
+ if(dat_len == 0)
+ continue;
+
+ val = buffer[*j];
+ data[data_offset + i] |= (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)(~0) << dat_len)));
+ *buf_len -= dat_len;
+ }
+}
+
+static void
+H5Z_nbit_decompress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const parms_atomic *p)
+{
+ /* begin_i: the index of byte having first significant bit
+ end_i: the index of byte having last significant bit */
+ int k;
+ unsigned begin_i, end_i;
+ size_t datatype_len;
+
+ datatype_len = p->size * 8;
+
+ if(p->order == H5Z_NBIT_ORDER_LE) { /* little endian */
+ /* calculate begin_i and end_i */
+ if((p->precision + p->offset) % 8 != 0)
+ begin_i = (p->precision + p->offset) / 8;
+ else
+ begin_i = (p->precision + p->offset) / 8 - 1;
+ end_i = p->offset / 8;
+
+ for(k = (int)begin_i; k >= (int)end_i; k--)
+ H5Z_nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i,
+ buffer, j, buf_len, p, datatype_len);
+ }
+ else { /* big endian */
+ /* Sanity check */
+ HDassert(p->order == H5Z_NBIT_ORDER_BE);
+
+ /* calculate begin_i and end_i */
+ begin_i = ((unsigned)datatype_len - p->precision - p->offset) / 8;
+ if(p->offset % 8 != 0)
+ end_i = ((unsigned)datatype_len - p->offset) / 8;
+ else
+ end_i = ((unsigned)datatype_len - p->offset) / 8 - 1;
+
+ for(k = (int)begin_i; k <= (int)end_i; k++)
+ H5Z_nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i,
+ buffer, j, buf_len, p, datatype_len);
+ }
+}
+
+static herr_t
+H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index)
+{
+ unsigned i, total_size, base_class, base_size, n, begin_index;
+ parms_atomic p;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ total_size = parms[(*parms_index)++];
+ base_class = parms[(*parms_index)++];
+
+ switch(base_class) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = parms[(*parms_index)++];
+ p.order = parms[(*parms_index)++];
+ p.precision = parms[(*parms_index)++];
+ p.offset = parms[(*parms_index)++];
+
+ /* Check values of precision and offset */
+ if(p.precision > p.size * 8 || (p.precision + p.offset) > p.size * 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset")
+
+ n = total_size / p.size;
+ for(i = 0; i < n; i++)
+ H5Z_nbit_decompress_one_atomic(data, data_offset + i * p.size,
+ buffer, j, buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for(i = 0; i < n; i++) {
+ if(H5Z__nbit_decompress_one_array(data, data_offset + i * base_size,
+ buffer, j, buf_len, parms, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array")
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for(i = 0; i < n; i++) {
+ if(H5Z__nbit_decompress_one_compound(data, data_offset + i * base_size,
+ buffer, j, buf_len, parms, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound")
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
+ (*parms_index)++; /* skip size of no-op type */
+ H5Z_nbit_decompress_one_nooptype(data, data_offset, buffer, j, buf_len, total_size);
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+static herr_t
+H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index)
+{
+ unsigned i, nmembers, member_offset, member_class, member_size, used_size = 0, size;
+ parms_atomic p;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ size = parms[(*parms_index)++];
+ nmembers = parms[(*parms_index)++];
+
+ for(i = 0; i < nmembers; i++) {
+ member_offset = parms[(*parms_index)++];
+ member_class = parms[(*parms_index)++];
+
+ /* Check for overflow */
+ member_size = parms[*parms_index];
+ used_size += member_size;
+ if(used_size > size)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "compound member offset overflowed compound size")
+ switch(member_class) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = member_size;
+ /* Advance past member size */
+ (*parms_index)++;
+ p.order = parms[(*parms_index)++];
+ p.precision = parms[(*parms_index)++];
+ p.offset = parms[(*parms_index)++];
+
+ /* Check values of precision and offset */
+ if(p.precision > p.size * 8 || (p.precision + p.offset) > p.size * 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset")
+
+ H5Z_nbit_decompress_one_atomic(data, data_offset + member_offset,
+ buffer, j, buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ if(H5Z__nbit_decompress_one_array(data, data_offset + member_offset,
+ buffer, j, buf_len, parms, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array")
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ if(H5Z__nbit_decompress_one_compound(data, data_offset+member_offset,
+ buffer, j, buf_len, parms, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound")
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
+ /* Advance past member size */
+ (*parms_index)++;
+ H5Z_nbit_decompress_one_nooptype(data, data_offset+member_offset,
+ buffer, j, buf_len, member_size);
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+static herr_t
+H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+ const unsigned parms[])
+{
+ /* i: index of data, j: index of buffer,
+ buf_len: number of bits to be filled in current byte */
+ unsigned i;
+ size_t j, size;
+ size_t buf_len;
+ parms_atomic p;
+ unsigned parms_index; /* index in array parms used by compression/decompression functions */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* may not have to initialize to zeros */
+ HDmemset(data, 0, d_nelmts * parms[4]);
+
+ /* initialization before the loop */
+ j = 0;
+ buf_len = sizeof(unsigned char) * 8;
+
+ switch(parms[3]) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = parms[4];
+ p.order = parms[5];
+ p.precision = parms[6];
+ p.offset = parms[7];
+
+ /* Check values of precision and offset */
+ if(p.precision > p.size * 8 || (p.precision + p.offset) > p.size * 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset")
+
+ for(i = 0; i < d_nelmts; i++)
+ H5Z_nbit_decompress_one_atomic(data, i * p.size, buffer, &j, &buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ size = parms[4];
+ parms_index = 4; /* set the index before goto function call */
+ for(i = 0; i < d_nelmts; i++) {
+ if(H5Z__nbit_decompress_one_array(data, i * size, buffer, &j, &buf_len, parms, &parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array")
+ parms_index = 4;
+ }
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ size = parms[4];
+ parms_index = 4; /* set the index before goto function call */
+ for(i = 0; i < d_nelmts; i++) {
+ if(H5Z__nbit_decompress_one_compound(data, i * size, buffer, &j, &buf_len, parms, &parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound")
+ parms_index = 4;
+ }
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+static void
+H5Z_nbit_compress_one_byte(unsigned char *data, size_t data_offset, unsigned k,
+ unsigned begin_i, unsigned end_i, unsigned char *buffer, size_t *j, size_t *buf_len,
+ const parms_atomic *p, size_t datatype_len)
+{
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ /* initialize value and bits of unsigned char to be copied */
+ val = data[data_offset + k];
+ if(begin_i != end_i) { /* significant bits occupy >1 unsigned char */
+ if(k == begin_i)
+ dat_len = 8 - (datatype_len - p->precision - p->offset) % 8;
+ else if(k == end_i) {
+ dat_len = 8 - p->offset % 8;
+ val = (unsigned char)(val >> (8 - dat_len));
+ }
+ else
+ dat_len = 8;
+ } else { /* all significant bits in one unsigned char */
+ val = (unsigned char)(val >> (p->offset % 8));
+ dat_len = p->precision;
+ }
+
+ if(*buf_len > dat_len) {
+ buffer[*j] |= (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len));
+ *buf_len -= dat_len;
+ } else {
+ buffer[*j] |= (unsigned char)((unsigned)(val >> (dat_len - *buf_len)) & ~((unsigned)(~0) << *buf_len));
+ dat_len -= *buf_len;
+ H5Z_nbit_next_byte(j, buf_len);
+ if(dat_len == 0)
+ return;
+
+ buffer[*j] = (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len));
+ *buf_len -= dat_len;
+ }
+}
+
+static void
+H5Z_nbit_compress_one_nooptype(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, unsigned size)
+{
+ unsigned i; /* index */
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ for(i = 0; i < size; i++) {
+ /* initialize value and bits of unsigned char to be copied */
+ val = data[data_offset + i];
+ dat_len = sizeof(unsigned char) * 8;
+
+ buffer[*j] |= (unsigned char)((unsigned)(val >> (dat_len - *buf_len)) & ~((unsigned)(~0) << *buf_len));
+ dat_len -= *buf_len;
+ H5Z_nbit_next_byte(j, buf_len);
+ if(dat_len == 0)
+ continue;
+
+ buffer[*j] = (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len));
+ *buf_len -= dat_len;
+ }
+}
+
+static void
+H5Z_nbit_compress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const parms_atomic *p)
+{
+ /* begin_i: the index of byte having first significant bit
+ end_i: the index of byte having last significant bit */
+ int k;
+ unsigned begin_i, end_i;
+ size_t datatype_len;
+
+ datatype_len = p->size * 8;
+
+ if(p->order == H5Z_NBIT_ORDER_LE) { /* little endian */
+ /* calculate begin_i and end_i */
+ if((p->precision + p->offset) % 8 != 0)
+ begin_i = (p->precision + p->offset) / 8;
+ else
+ begin_i = (p->precision + p->offset) / 8 - 1;
+ end_i = p->offset / 8;
+
+ for(k = (int)begin_i; k >= (int)end_i; k--)
+ H5Z_nbit_compress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i,
+ buffer, j, buf_len, p, datatype_len);
+ }
+ else { /* big endian */
+ /* Sanity check */
+ HDassert(p->order == H5Z_NBIT_ORDER_BE);
+
+ /* calculate begin_i and end_i */
+ begin_i = ((unsigned)datatype_len - p->precision - p->offset) / 8;
+ if(p->offset % 8 != 0)
+ end_i = ((unsigned)datatype_len - p->offset) / 8;
+ else
+ end_i = ((unsigned)datatype_len - p->offset) / 8 - 1;
+
+ for(k = (int)begin_i; k <= (int)end_i; k++)
+ H5Z_nbit_compress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i,
+ buffer, j, buf_len, p, datatype_len);
+ }
+}
+
+static void
+H5Z_nbit_compress_one_array(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index)
+{
+ unsigned i, total_size, base_class, base_size, n, begin_index;
+ parms_atomic p;
+
+ total_size = parms[(*parms_index)++];
+ base_class = parms[(*parms_index)++];
+
+ switch(base_class) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = parms[(*parms_index)++];
+ p.order = parms[(*parms_index)++];
+ p.precision = parms[(*parms_index)++];
+ p.offset = parms[(*parms_index)++];
+ n = total_size / p.size;
+ for(i = 0; i < n; i++)
+ H5Z_nbit_compress_one_atomic(data, data_offset + i * p.size,
+ buffer, j, buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for(i = 0; i < n; i++) {
+ H5Z_nbit_compress_one_array(data, data_offset + i * base_size,
+ buffer, j, buf_len, parms, parms_index);
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for(i = 0; i < n; i++) {
+ H5Z_nbit_compress_one_compound(data, data_offset + i * base_size,
+ buffer, j, buf_len, parms, parms_index);
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
+ (*parms_index)++; /* skip size of no-op type */
+ H5Z_nbit_compress_one_nooptype(data, data_offset, buffer, j, buf_len, total_size);
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+}
+
+static void
+H5Z_nbit_compress_one_compound(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, const unsigned parms[],
+ unsigned *parms_index)
+{
+ unsigned i, nmembers, member_offset, member_class, size;
+ parms_atomic p;
+
+ (*parms_index)++; /* skip size of compound datatype */
+ nmembers = parms[(*parms_index)++];
+
+ for(i = 0; i < nmembers; i++) {
+ member_offset = parms[(*parms_index)++];
+ member_class = parms[(*parms_index)++];
+
+ switch(member_class) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = parms[(*parms_index)++];
+ p.order = parms[(*parms_index)++];
+ p.precision = parms[(*parms_index)++];
+ p.offset = parms[(*parms_index)++];
+ H5Z_nbit_compress_one_atomic(data, data_offset + member_offset,
+ buffer, j, buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ H5Z_nbit_compress_one_array(data, data_offset + member_offset,
+ buffer, j, buf_len, parms, parms_index);
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ H5Z_nbit_compress_one_compound(data, data_offset+member_offset,
+ buffer, j, buf_len, parms, parms_index);
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
+ size = parms[(*parms_index)++];
+ H5Z_nbit_compress_one_nooptype(data, data_offset+member_offset,
+ buffer, j, buf_len, size);
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+ }
+}
+
+static void
+H5Z_nbit_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+ size_t *buffer_size, const unsigned parms[])
+{
+ /* i: index of data, new_size: index of buffer,
+ buf_len: number of bits to be filled in current byte */
+ unsigned i;
+ size_t size;
+ size_t new_size = 0;
+ size_t buf_len;
+ parms_atomic p;
+ unsigned parms_index; /* index in array parms used by compression/decompression functions */
+
+ /* must initialize buffer to be zeros */
+ HDmemset(buffer, 0, *buffer_size);
+
+ /* initialization before the loop */
+ buf_len = sizeof(unsigned char) * 8;
+
+ switch(parms[3]) {
+ case H5Z_NBIT_ATOMIC:
+ p.size = parms[4];
+ p.order = parms[5];
+ p.precision = parms[6];
+ p.offset = parms[7];
+
+ for(i = 0; i < d_nelmts; i++)
+ H5Z_nbit_compress_one_atomic(data, i * p.size, buffer, &new_size, &buf_len, &p);
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ size = parms[4];
+ parms_index = 4;
+ for(i = 0; i < d_nelmts; i++) {
+ H5Z_nbit_compress_one_array(data, i * size, buffer, &new_size, &buf_len, parms, &parms_index);
+ parms_index = 4;
+ }
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+ size = parms[4];
+ parms_index = 4;
+ for(i = 0; i < d_nelmts; i++) {
+ H5Z_nbit_compress_one_compound(data, i * size, buffer, &new_size, &buf_len, parms, &parms_index);
+ parms_index = 4;
+ }
+ break;
+
+ default:
+ HDassert(0 && "This Should never be executed!");
+ } /* end switch */
+
+ /* Update the size to the new value after compression. If there are any bits hanging over in
+ * the last byte, increment the value by 1. */
+ *buffer_size = new_size + 1;
+}
+
diff --git a/src/H5Zpkg.h b/src/H5Zpkg.h
new file mode 100644
index 0000000..2aa17f2
--- /dev/null
+++ b/src/H5Zpkg.h
@@ -0,0 +1,55 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !(defined H5Z_FRIEND || defined H5Z_MODULE)
+#error "Do not include this file outside the H5Z package!"
+#endif
+
+#ifndef _H5Zpkg_H
+#define _H5Zpkg_H
+
+/* Include private header file */
+#include "H5Zprivate.h" /* Filter functions */
+
+/********************/
+/* Internal filters */
+/********************/
+
+/* Shuffle filter */
+H5_DLLVAR const H5Z_class2_t H5Z_SHUFFLE[1];
+
+/* Fletcher32 filter */
+H5_DLLVAR const H5Z_class2_t H5Z_FLETCHER32[1];
+
+/* n-bit filter */
+H5_DLLVAR H5Z_class2_t H5Z_NBIT[1];
+
+/* Scale/offset filter */
+H5_DLLVAR H5Z_class2_t H5Z_SCALEOFFSET[1];
+
+/********************/
+/* External filters */
+/********************/
+
+/* Deflate filter */
+#ifdef H5_HAVE_FILTER_DEFLATE
+H5_DLLVAR const H5Z_class2_t H5Z_DEFLATE[1];
+#endif /* H5_HAVE_FILTER_DEFLATE */
+
+/* szip filter */
+#ifdef H5_HAVE_FILTER_SZIP
+H5_DLLVAR H5Z_class2_t H5Z_SZIP[1];
+#endif /* H5_HAVE_FILTER_SZIP */
+
+#endif /* _H5Zpkg_H */
+
diff --git a/src/H5Zprivate.h b/src/H5Zprivate.h
new file mode 100644
index 0000000..fe182ad
--- /dev/null
+++ b/src/H5Zprivate.h
@@ -0,0 +1,109 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, April 16, 1998
+ */
+
+#ifndef _H5Zprivate_H
+#define _H5Zprivate_H
+
+/* Include package's public header */
+#include "H5Zpublic.h"
+
+/* Private headers needed by this file */
+#include "H5Tprivate.h" /* Datatypes */
+
+/**************************/
+/* Library Private Macros */
+/**************************/
+
+/* Special parameters for szip compression */
+/* [These are aliases for the similar definitions in szlib.h, which we can't
+ * include directly due to the duplication of various symbols with the zlib.h
+ * header file] */
+#define H5_SZIP_LSB_OPTION_MASK 8
+#define H5_SZIP_MSB_OPTION_MASK 16
+#define H5_SZIP_RAW_OPTION_MASK 128
+
+/* Common # of 'client data values' for filters */
+/* (avoids dynamic memory allocation in most cases) */
+#define H5Z_COMMON_CD_VALUES 4
+
+/* Common size of filter name */
+/* (avoids dynamic memory allocation in most cases) */
+#define H5Z_COMMON_NAME_LEN 12
+
+/****************************/
+/* Library Private Typedefs */
+/****************************/
+
+/* Structure to store information about each filter's parameters */
+typedef struct H5Z_filter_info_t {
+ H5Z_filter_t id; /*filter identification number */
+ unsigned flags; /*defn and invocation flags */
+ char _name[H5Z_COMMON_NAME_LEN]; /*internal filter name */
+ char *name; /*optional filter name */
+ size_t cd_nelmts; /*number of elements in cd_values[] */
+ unsigned _cd_values[H5Z_COMMON_CD_VALUES]; /*internal client data values */
+ unsigned *cd_values; /*client data values */
+} H5Z_filter_info_t;
+
+/*****************************/
+/* Library-private Variables */
+/*****************************/
+
+
+/***************************************/
+/* Library-private Function Prototypes */
+/***************************************/
+struct H5O_pline_t; /*forward decl*/
+
+/* Internal API routines */
+H5_DLL herr_t H5Z_init(void);
+H5_DLL herr_t H5Z_register(const H5Z_class2_t *cls);
+H5_DLL herr_t H5Z_append(struct H5O_pline_t *pline, H5Z_filter_t filter,
+ unsigned flags, size_t cd_nelmts, const unsigned int cd_values[]);
+H5_DLL herr_t H5Z_modify(const struct H5O_pline_t *pline, H5Z_filter_t filter,
+ unsigned flags, size_t cd_nelmts, const unsigned int cd_values[]);
+H5_DLL herr_t H5Z_pipeline(const struct H5O_pline_t *pline,
+ unsigned flags, unsigned *filter_mask/*in,out*/,
+ H5Z_EDC_t edc_read, H5Z_cb_t cb_struct,
+ size_t *nbytes/*in,out*/, size_t *buf_size/*in,out*/,
+ void **buf/*in,out*/);
+H5_DLL H5Z_class2_t *H5Z_find(H5Z_filter_t id);
+H5_DLL herr_t H5Z_can_apply(hid_t dcpl_id, hid_t type_id);
+H5_DLL herr_t H5Z_set_local(hid_t dcpl_id, hid_t type_id);
+H5_DLL herr_t H5Z_can_apply_direct(const struct H5O_pline_t *pline);
+H5_DLL herr_t H5Z_set_local_direct(const struct H5O_pline_t *pline);
+H5_DLL H5Z_filter_info_t *H5Z_filter_info(const struct H5O_pline_t *pline,
+ H5Z_filter_t filter);
+H5_DLL htri_t H5Z_filter_in_pline(const struct H5O_pline_t *pline, H5Z_filter_t filter);
+H5_DLL htri_t H5Z_all_filters_avail(const struct H5O_pline_t *pline);
+H5_DLL herr_t H5Z_unregister(H5Z_filter_t filter_id);
+H5_DLL htri_t H5Z_filter_avail(H5Z_filter_t id);
+H5_DLL herr_t H5Z_delete(struct H5O_pline_t *pline, H5Z_filter_t filter);
+H5_DLL herr_t H5Z_get_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags);
+
+/* Data Transform Functions */
+typedef struct H5Z_data_xform_t H5Z_data_xform_t; /* Defined in H5Ztrans.c */
+
+H5_DLL H5Z_data_xform_t *H5Z_xform_create(const char *expr);
+H5_DLL herr_t H5Z_xform_copy(H5Z_data_xform_t **data_xform_prop);
+H5_DLL herr_t H5Z_xform_destroy(H5Z_data_xform_t *data_xform_prop);
+H5_DLL herr_t H5Z_xform_eval(H5Z_data_xform_t *data_xform_prop, void *array,
+ size_t array_size, const H5T_t *buf_type);
+H5_DLL hbool_t H5Z_xform_noop(const H5Z_data_xform_t *data_xform_prop);
+H5_DLL const char *H5Z_xform_extract_xform_str(const H5Z_data_xform_t *data_xform_prop);
+
+#endif
diff --git a/src/H5Zpublic.h b/src/H5Zpublic.h
new file mode 100644
index 0000000..f6b313e
--- /dev/null
+++ b/src/H5Zpublic.h
@@ -0,0 +1,248 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, April 16, 1998
+ */
+
+#ifndef _H5Zpublic_H
+#define _H5Zpublic_H
+
+/* Public headers needed by this file */
+#include "H5public.h"
+
+/*
+ * Filter identifiers. Values 0 through 255 are for filters defined by the
+ * HDF5 library. Values 256 through 511 are available for testing new
+ * filters. Subsequent values should be obtained from the HDF5 development
+ * team at hdf5dev@ncsa.uiuc.edu. These values will never change because they
+ * appear in the HDF5 files.
+ */
+typedef int H5Z_filter_t;
+
+/* Filter IDs */
+#define H5Z_FILTER_ERROR (-1) /*no filter */
+#define H5Z_FILTER_NONE 0 /*reserved indefinitely */
+#define H5Z_FILTER_DEFLATE 1 /*deflation like gzip */
+#define H5Z_FILTER_SHUFFLE 2 /*shuffle the data */
+#define H5Z_FILTER_FLETCHER32 3 /*fletcher32 checksum of EDC */
+#define H5Z_FILTER_SZIP 4 /*szip compression */
+#define H5Z_FILTER_NBIT 5 /*nbit compression */
+#define H5Z_FILTER_SCALEOFFSET 6 /*scale+offset compression */
+#define H5Z_FILTER_RESERVED 256 /*filter ids below this value are reserved for library use */
+
+#define H5Z_FILTER_MAX 65535 /*maximum filter id */
+
+/* General macros */
+#define H5Z_FILTER_ALL 0 /* Symbol to remove all filters in H5Premove_filter */
+#define H5Z_MAX_NFILTERS 32 /* Maximum number of filters allowed in a pipeline */
+ /* (should probably be allowed to be an
+ * unlimited amount, but currently each
+ * filter uses a bit in a 32-bit field,
+ * so the format would have to be
+ * changed to accomodate that)
+ */
+
+/* Flags for filter definition (stored) */
+#define H5Z_FLAG_DEFMASK 0x00ff /*definition flag mask */
+#define H5Z_FLAG_MANDATORY 0x0000 /*filter is mandatory */
+#define H5Z_FLAG_OPTIONAL 0x0001 /*filter is optional */
+
+/* Additional flags for filter invocation (not stored) */
+#define H5Z_FLAG_INVMASK 0xff00 /*invocation flag mask */
+#define H5Z_FLAG_REVERSE 0x0100 /*reverse direction; read */
+#define H5Z_FLAG_SKIP_EDC 0x0200 /*skip EDC filters for read */
+
+/* Special parameters for szip compression */
+/* [These are aliases for the similar definitions in szlib.h, which we can't
+ * include directly due to the duplication of various symbols with the zlib.h
+ * header file] */
+#define H5_SZIP_ALLOW_K13_OPTION_MASK 1
+#define H5_SZIP_CHIP_OPTION_MASK 2
+#define H5_SZIP_EC_OPTION_MASK 4
+#define H5_SZIP_NN_OPTION_MASK 32
+#define H5_SZIP_MAX_PIXELS_PER_BLOCK 32
+
+/* Macros for the shuffle filter */
+#define H5Z_SHUFFLE_USER_NPARMS 0 /* Number of parameters that users can set */
+#define H5Z_SHUFFLE_TOTAL_NPARMS 1 /* Total number of parameters for filter */
+
+/* Macros for the szip filter */
+#define H5Z_SZIP_USER_NPARMS 2 /* Number of parameters that users can set */
+#define H5Z_SZIP_TOTAL_NPARMS 4 /* Total number of parameters for filter */
+#define H5Z_SZIP_PARM_MASK 0 /* "User" parameter for option mask */
+#define H5Z_SZIP_PARM_PPB 1 /* "User" parameter for pixels-per-block */
+#define H5Z_SZIP_PARM_BPP 2 /* "Local" parameter for bits-per-pixel */
+#define H5Z_SZIP_PARM_PPS 3 /* "Local" parameter for pixels-per-scanline */
+
+/* Macros for the nbit filter */
+#define H5Z_NBIT_USER_NPARMS 0 /* Number of parameters that users can set */
+
+/* Macros for the scale offset filter */
+#define H5Z_SCALEOFFSET_USER_NPARMS 2 /* Number of parameters that users can set */
+
+
+/* Special parameters for ScaleOffset filter*/
+#define H5Z_SO_INT_MINBITS_DEFAULT 0
+typedef enum H5Z_SO_scale_type_t {
+ H5Z_SO_FLOAT_DSCALE = 0,
+ H5Z_SO_FLOAT_ESCALE = 1,
+ H5Z_SO_INT = 2
+} H5Z_SO_scale_type_t;
+
+/* Current version of the H5Z_class_t struct */
+#define H5Z_CLASS_T_VERS (1)
+
+/* Values to decide if EDC is enabled for reading data */
+typedef enum H5Z_EDC_t {
+ H5Z_ERROR_EDC = -1, /* error value */
+ H5Z_DISABLE_EDC = 0,
+ H5Z_ENABLE_EDC = 1,
+ H5Z_NO_EDC = 2 /* must be the last */
+} H5Z_EDC_t;
+
+/* Bit flags for H5Zget_filter_info */
+#define H5Z_FILTER_CONFIG_ENCODE_ENABLED (0x0001)
+#define H5Z_FILTER_CONFIG_DECODE_ENABLED (0x0002)
+
+/* Return values for filter callback function */
+typedef enum H5Z_cb_return_t {
+ H5Z_CB_ERROR = -1,
+ H5Z_CB_FAIL = 0, /* I/O should fail if filter fails. */
+ H5Z_CB_CONT = 1, /* I/O continues if filter fails. */
+ H5Z_CB_NO = 2
+} H5Z_cb_return_t;
+
+/* Filter callback function definition */
+typedef H5Z_cb_return_t (*H5Z_filter_func_t)(H5Z_filter_t filter, void* buf,
+ size_t buf_size, void* op_data);
+
+/* Structure for filter callback property */
+typedef struct H5Z_cb_t {
+ H5Z_filter_func_t func;
+ void* op_data;
+} H5Z_cb_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Before a dataset gets created, the "can_apply" callbacks for any filters used
+ * in the dataset creation property list are called
+ * with the dataset's dataset creation property list, the dataset's datatype and
+ * a dataspace describing a chunk (for chunked dataset storage).
+ *
+ * The "can_apply" callback must determine if the combination of the dataset
+ * creation property list setting, the datatype and the dataspace represent a
+ * valid combination to apply this filter to. For example, some cases of
+ * invalid combinations may involve the filter not operating correctly on
+ * certain datatypes (or certain datatype sizes), or certain sizes of the chunk
+ * dataspace.
+ *
+ * The "can_apply" callback can be the NULL pointer, in which case, the library
+ * will assume that it can apply to any combination of dataset creation
+ * property list values, datatypes and dataspaces.
+ *
+ * The "can_apply" callback returns positive a valid combination, zero for an
+ * invalid combination and negative for an error.
+ */
+typedef htri_t (*H5Z_can_apply_func_t)(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+
+/*
+ * After the "can_apply" callbacks are checked for new datasets, the "set_local"
+ * callbacks for any filters used in the dataset creation property list are
+ * called. These callbacks receive the dataset's private copy of the dataset
+ * creation property list passed in to H5Dcreate (i.e. not the actual property
+ * list passed in to H5Dcreate) and the datatype ID passed in to H5Dcreate
+ * (which is not copied and should not be modified) and a dataspace describing
+ * the chunk (for chunked dataset storage) (which should also not be modified).
+ *
+ * The "set_local" callback must set any parameters that are specific to this
+ * dataset, based on the combination of the dataset creation property list
+ * values, the datatype and the dataspace. For example, some filters perform
+ * different actions based on different datatypes (or datatype sizes) or
+ * different number of dimensions or dataspace sizes.
+ *
+ * The "set_local" callback can be the NULL pointer, in which case, the library
+ * will assume that there are no dataset-specific settings for this filter.
+ *
+ * The "set_local" callback must return non-negative on success and negative
+ * for an error.
+ */
+typedef herr_t (*H5Z_set_local_func_t)(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+
+/*
+ * A filter gets definition flags and invocation flags (defined above), the
+ * client data array and size defined when the filter was added to the
+ * pipeline, the size in bytes of the data on which to operate, and pointers
+ * to a buffer and its allocated size.
+ *
+ * The filter should store the result in the supplied buffer if possible,
+ * otherwise it can allocate a new buffer, freeing the original. The
+ * allocated size of the new buffer should be returned through the BUF_SIZE
+ * pointer and the new buffer through the BUF pointer.
+ *
+ * The return value from the filter is the number of bytes in the output
+ * buffer. If an error occurs then the function should return zero and leave
+ * all pointer arguments unchanged.
+ */
+typedef size_t (*H5Z_func_t)(unsigned int flags, size_t cd_nelmts,
+ const unsigned int cd_values[], size_t nbytes,
+ size_t *buf_size, void **buf);
+
+/*
+ * The filter table maps filter identification numbers to structs that
+ * contain a pointers to the filter function and timing statistics.
+ */
+typedef struct H5Z_class2_t {
+ int version; /* Version number of the H5Z_class_t struct */
+ H5Z_filter_t id; /* Filter ID number */
+ unsigned encoder_present; /* Does this filter have an encoder? */
+ unsigned decoder_present; /* Does this filter have a decoder? */
+ const char *name; /* Comment for debugging */
+ H5Z_can_apply_func_t can_apply; /* The "can apply" callback for a filter */
+ H5Z_set_local_func_t set_local; /* The "set local" callback for a filter */
+ H5Z_func_t filter; /* The actual filter function */
+} H5Z_class2_t;
+
+H5_DLL herr_t H5Zregister(const void *cls);
+H5_DLL herr_t H5Zunregister(H5Z_filter_t id);
+H5_DLL htri_t H5Zfilter_avail(H5Z_filter_t id);
+H5_DLL herr_t H5Zget_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags);
+
+/* Symbols defined for compatibility with previous versions of the HDF5 API.
+ *
+ * Use of these symbols is deprecated.
+ */
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+
+/*
+ * The filter table maps filter identification numbers to structs that
+ * contain a pointers to the filter function and timing statistics.
+ */
+typedef struct H5Z_class1_t {
+ H5Z_filter_t id; /* Filter ID number */
+ const char *name; /* Comment for debugging */
+ H5Z_can_apply_func_t can_apply; /* The "can apply" callback for a filter */
+ H5Z_set_local_func_t set_local; /* The "set local" callback for a filter */
+ H5Z_func_t filter; /* The actual filter function */
+} H5Z_class1_t;
+
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/src/H5Zscaleoffset.c b/src/H5Zscaleoffset.c
new file mode 100644
index 0000000..b86d785
--- /dev/null
+++ b/src/H5Zscaleoffset.c
@@ -0,0 +1,1694 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5Zpkg.h" /* Data filters */
+
+/* Struct of parameters needed for compressing/decompressing one atomic datatype */
+typedef struct {
+ unsigned size; /* datatype size */
+ uint32_t minbits; /* minimum bits to compress one value of such datatype */
+ unsigned mem_order; /* current memory endianness order */
+} parms_atomic;
+
+enum H5Z_scaleoffset_t {t_bad=0, t_uchar=1, t_ushort, t_uint, t_ulong, t_ulong_long,
+ t_schar, t_short, t_int, t_long, t_long_long,
+ t_float, t_double};
+
+/* Local function prototypes */
+static htri_t H5Z_can_apply_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static enum H5Z_scaleoffset_t H5Z_scaleoffset_get_type(unsigned dtype_class,
+ unsigned dtype_size, unsigned dtype_sign);
+static herr_t H5Z_scaleoffset_set_parms_fillval(H5P_genplist_t *dcpl_plist,
+ H5T_t *type, enum H5Z_scaleoffset_t scale_type, unsigned cd_values[],
+ int need_convert, hid_t dxpl_id);
+static herr_t H5Z_set_local_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static size_t H5Z_filter_scaleoffset(unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf);
+static void H5Z_scaleoffset_convert(void *buf, unsigned d_nelmts, unsigned dtype_size);
+static H5_ATTR_CONST unsigned H5Z_scaleoffset_log2(unsigned long long num);
+static void H5Z_scaleoffset_precompress_i(void *data, unsigned d_nelmts,
+ enum H5Z_scaleoffset_t type, unsigned filavail, const unsigned cd_values[],
+ uint32_t *minbits, unsigned long long *minval);
+static void H5Z_scaleoffset_postdecompress_i(void *data, unsigned d_nelmts,
+ enum H5Z_scaleoffset_t type, unsigned filavail, const unsigned cd_values[],
+ uint32_t minbits, unsigned long long minval);
+static herr_t H5Z_scaleoffset_precompress_fd(void *data, unsigned d_nelmts,
+ enum H5Z_scaleoffset_t type, unsigned filavail, const unsigned cd_values[],
+ uint32_t *minbits, unsigned long long *minval, double D_val);
+static herr_t H5Z_scaleoffset_postdecompress_fd(void *data, unsigned d_nelmts,
+ enum H5Z_scaleoffset_t type, unsigned filavail, const unsigned cd_values[],
+ uint32_t minbits, unsigned long long minval, double D_val);
+static void H5Z_scaleoffset_next_byte(size_t *j, unsigned *buf_len);
+static void H5Z_scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset,
+ unsigned k, unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len,
+ parms_atomic p, unsigned dtype_len);
+static void H5Z_scaleoffset_compress_one_byte(unsigned char *data, size_t data_offset,
+ unsigned k, unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len,
+ parms_atomic p, unsigned dtype_len);
+static void H5Z_scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, unsigned *buf_len, parms_atomic p);
+static void H5Z_scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, unsigned *buf_len, parms_atomic p);
+static void H5Z_scaleoffset_decompress(unsigned char *data, unsigned d_nelmts,
+ unsigned char *buffer, parms_atomic p);
+static void H5Z_scaleoffset_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+ size_t buffer_size, parms_atomic p);
+
+/* This message derives from H5Z */
+H5Z_class2_t H5Z_SCALEOFFSET[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_SCALEOFFSET, /* Filter id number */
+ 1, /* Assume encoder present: check before registering */
+ 1, /* decoder_present flag (set to true) */
+ "scaleoffset", /* Filter name for debugging */
+ H5Z_can_apply_scaleoffset, /* The "can apply" callback */
+ H5Z_set_local_scaleoffset, /* The "set local" callback */
+ H5Z_filter_scaleoffset, /* The actual filter function */
+}};
+
+/* Local macros */
+#define H5Z_SCALEOFFSET_TOTAL_NPARMS 20 /* Total number of parameters for filter */
+#define H5Z_SCALEOFFSET_PARM_SCALETYPE 0 /* "User" parameter for scale type */
+#define H5Z_SCALEOFFSET_PARM_SCALEFACTOR 1 /* "User" parameter for scale factor */
+#define H5Z_SCALEOFFSET_PARM_NELMTS 2 /* "Local" parameter for number of elements in the chunk */
+#define H5Z_SCALEOFFSET_PARM_CLASS 3 /* "Local" parameter for datatype class */
+#define H5Z_SCALEOFFSET_PARM_SIZE 4 /* "Local" parameter for datatype size */
+#define H5Z_SCALEOFFSET_PARM_SIGN 5 /* "Local" parameter for integer datatype sign */
+#define H5Z_SCALEOFFSET_PARM_ORDER 6 /* "Local" parameter for datatype byte order */
+#define H5Z_SCALEOFFSET_PARM_FILAVAIL 7 /* "Local" parameter for dataset fill value existence */
+#define H5Z_SCALEOFFSET_PARM_FILVAL 8 /* "Local" parameter for start location to store dataset fill value */
+
+#define H5Z_SCALEOFFSET_CLS_INTEGER 0 /* Integer (datatype class) */
+#define H5Z_SCALEOFFSET_CLS_FLOAT 1 /* Floatig-point (datatype class) */
+
+#define H5Z_SCALEOFFSET_SGN_NONE 0 /* Unsigned integer type */
+#define H5Z_SCALEOFFSET_SGN_2 1 /* Two's complement signed integer type */
+
+#define H5Z_SCALEOFFSET_ORDER_LE 0 /* Little endian (datatype byte order) */
+#define H5Z_SCALEOFFSET_ORDER_BE 1 /* Big endian (datatype byte order) */
+
+#define H5Z_SCALEOFFSET_FILL_UNDEFINED 0 /* Fill value is not defined */
+#define H5Z_SCALEOFFSET_FILL_DEFINED 1 /* Fill value is defined */
+
+/* Store fill value in cd_values[] */
+#define H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \
+{ \
+ unsigned _i = H5Z_SCALEOFFSET_PARM_FILVAL; /* index into cd_values */ \
+ uint32_t _cd_value; /* Current cd_value */ \
+ char *_fv_p; /* Pointer to current byte in fill_val */ \
+ size_t _copy_size = 4; /* # of bytes to copy this iteration */ \
+ size_t _size_rem = sizeof(type); /* # of bytes left to copy to cd_values */ \
+ \
+ /* Store the fill value as the last entry in cd_values[] \
+ * Store byte by byte from least significant byte to most significant byte \
+ * Plenty of space left for the fill value (from index 8 to 19) \
+ * H5O_pline_encode will byte-swap each individual cd value, but we still \
+ * need to swap the cd values as a whole if we are on a BE machine. Note \
+ * that we need to make sure to put the data only in the lowest 4 bytes of \
+ * each, if sizeof(unsigned) > 4. \
+ */ \
+ if(H5T_native_order_g == H5T_ORDER_LE) { \
+ _fv_p = (char *)&(fill_val); \
+ /* Copy 4 bytes at a time to each cd value */ \
+ do { \
+ if(_size_rem < 4) { \
+ /* Amount left to copy is smaller than a cd_value, adjust copy \
+ * size and initialize cd_value as it will not be fully \
+ * overwritten */ \
+ _copy_size = _size_rem; \
+ _cd_value = (uint32_t)0; \
+ } /* end if */ \
+ \
+ /* Copy the value */ \
+ HDmemcpy(&_cd_value, _fv_p, _copy_size); \
+ (cd_values)[_i] = (unsigned)_cd_value; \
+ \
+ /* Next field */ \
+ _i++; \
+ _fv_p += _copy_size; \
+ _size_rem -= _copy_size; \
+ } while(_size_rem); \
+ } /* end if */ \
+ else { \
+ HDassert(H5T_native_order_g == H5T_ORDER_BE); \
+ \
+ /* Copy 4 bytes at a time to each cd value, but start at the end \
+ * (highest address) of fill_val */ \
+ _fv_p = ((char *)&(fill_val)) + sizeof(type) - MIN(4, _size_rem); \
+ while(_size_rem >= 4) { \
+ /* Copy the value */ \
+ HDmemcpy(&_cd_value, _fv_p, _copy_size); \
+ (cd_values)[_i] = (unsigned)_cd_value; \
+ \
+ /* Next field */ \
+ _i++; \
+ _size_rem -= 4; \
+ if(_size_rem >= 4) \
+ _fv_p -= 4; \
+ else \
+ _fv_p -= _size_rem; \
+ } /* end while */ \
+ \
+ HDassert(_fv_p == (char *)&(fill_val)); \
+ if(_size_rem) { \
+ /* Amount left to copy is smaller than a cd_value, initialize \
+ * _cd_value as it will not be fully overwritten and copy to the end \
+ * of _cd value as it is BE. */ \
+ _cd_value = (uint32_t)0; \
+ HDmemcpy((char *)&_cd_value + 4 - _size_rem, _fv_p, _size_rem); \
+ (cd_values)[_i] = (unsigned)_cd_value; \
+ } /* end if */ \
+ } /* end else */ \
+}
+
+/* Set the fill value parameter in cd_values[] for unsigned integer type */
+#define H5Z_scaleoffset_set_filval_1(type, dcpl_plist, dt, cd_values, need_convert, dxpl_id)\
+{ \
+ type fill_val; \
+ \
+ /* Get dataset fill value */ \
+ if(H5P_get_fill_value(dcpl_plist, dt, &fill_val, dxpl_id) < 0) \
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value") \
+ \
+ if(need_convert) \
+ H5Z_scaleoffset_convert(&fill_val, 1, sizeof(type)); \
+ \
+ H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \
+}
+
+/* Set the fill value parameter in cd_values[] for signed integer type */
+#define H5Z_scaleoffset_set_filval_2(type, dcpl_plist, dt, cd_values, need_convert, dxpl_id)\
+{ \
+ type fill_val; \
+ \
+ /* Get dataset fill value */ \
+ if(H5P_get_fill_value(dcpl_plist, dt, &fill_val, dxpl_id) < 0) \
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value") \
+ \
+ if(need_convert) \
+ H5Z_scaleoffset_convert(&fill_val, 1, sizeof(type)); \
+ \
+ H5Z_scaleoffset_save_filval(unsigned type, cd_values, fill_val) \
+}
+
+/* Set the fill value parameter in cd_values[] for character integer type */
+#define H5Z_scaleoffset_set_filval_3(type, dcpl_plist, dt, cd_values, need_convert, dxpl_id)\
+{ \
+ type fill_val; \
+ \
+ /* Get dataset fill value */ \
+ if(H5P_get_fill_value(dcpl_plist, dt, &fill_val, dxpl_id) < 0) \
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value") \
+ \
+ /* Store the fill value as the last entry in cd_values[] */ \
+ (cd_values)[H5Z_SCALEOFFSET_PARM_FILVAL] = (unsigned)((unsigned char)fill_val); \
+}
+
+/* Set the fill value parameter in cd_values[] for floating-point type */
+#define H5Z_scaleoffset_set_filval_4(type, dcpl_plist, dt, cd_values, need_convert, dxpl_id)\
+{ \
+ type fill_val; \
+ \
+ /* Get dataset fill value */ \
+ if(H5P_get_fill_value(dcpl_plist, dt, &fill_val, dxpl_id) < 0) \
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value") \
+ \
+ if(need_convert) \
+ H5Z_scaleoffset_convert(&fill_val, 1, sizeof(type)); \
+ \
+ H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \
+}
+
+/* Get the fill value for integer type */
+#define H5Z_scaleoffset_get_filval_1(type, cd_values, fill_val) \
+{ \
+ unsigned _i = H5Z_SCALEOFFSET_PARM_FILVAL; /* index into cd_values */ \
+ uint32_t _cd_value; /* Current cd_value */ \
+ char *_fv_p; /* Pointer to current byte in fill_val */ \
+ size_t _copy_size = 4; /* # of bytes to copy this iteration */ \
+ size_t _size_rem = sizeof(type); /* # of bytes left to copy to filval */ \
+ \
+ /* Retrieve the fill value from the last entry in cd_values[] \
+ * Store byte by byte from least significant byte to most significant byte \
+ * Plenty of space left for the fill value (from index 8 to 19) \
+ * H5O_pline_encode will byte-swap each individual cd value, but we still \
+ * need to swap the cd values as a whole if we are on a BE machine. Note \
+ * that we need to make sure to put the data only in the lowest 4 bytes of \
+ * each, if sizeof(unsigned) > 4. \
+ */ \
+ if(H5T_native_order_g == H5T_ORDER_LE) { \
+ _fv_p = (char *)&(fill_val); \
+ /* Copy 4 bytes at a time to each cd value */ \
+ do { \
+ if(_size_rem < 4) \
+ /* Amount left to copy is smaller than a cd_value, adjust copy \
+ * size and initialize cd_value as it will not be fully \
+ * overwritten */ \
+ _copy_size = _size_rem; \
+ \
+ /* Copy the value */ \
+ _cd_value = (uint32_t)(cd_values)[_i]; \
+ HDmemcpy(_fv_p, &_cd_value, _copy_size); \
+ \
+ /* Next field */ \
+ _i++; \
+ _fv_p += _copy_size; \
+ _size_rem -= _copy_size; \
+ } while(_size_rem); \
+ } /* end if */ \
+ else { \
+ HDassert(H5T_native_order_g == H5T_ORDER_BE); \
+ \
+ /* Copy 4 bytes at a time to each cd value, but start at the end \
+ * (highest address) of fill_val */ \
+ _fv_p = ((char *)&(fill_val)) + sizeof(type) - MIN(4, _size_rem); \
+ while(_size_rem >= 4) { \
+ /* Copy the value */ \
+ _cd_value = (uint32_t)(cd_values)[_i]; \
+ HDmemcpy(_fv_p, &_cd_value, _copy_size); \
+ \
+ /* Next field */ \
+ _i++; \
+ _size_rem -= 4; \
+ if(_size_rem >=4) \
+ _fv_p -= 4; \
+ else \
+ _fv_p -= _size_rem; \
+ } /* end while */ \
+ \
+ HDassert(_fv_p == (char *)&(fill_val)); \
+ if(_size_rem) { \
+ /* Amount left to copy is smaller than a cd_value, initialize \
+ * _cd_value as it will not be fully overwritten and copy to the end \
+ * of _cd value as it is BE. */ \
+ _cd_value = (uint32_t)(cd_values)[_i]; \
+ HDmemcpy(_fv_p, (char *)&_cd_value + 4 - _size_rem, _size_rem); \
+ } /* end if */ \
+ } /* end else */ \
+}
+
+/* Get the fill value for floating-point type */
+#define H5Z_scaleoffset_get_filval_2(type, cd_values, filval) \
+{ \
+ if(sizeof(type) <= sizeof(long long)) \
+ H5Z_scaleoffset_get_filval_1(type, cd_values, filval) \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Find maximum and minimum values of a buffer with fill value defined for integer type */
+#define H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min)\
+{ \
+ i = 0; while(i < d_nelmts && buf[i]== filval) i++; \
+ if(i < d_nelmts) min = max = buf[i]; \
+ for(; i < d_nelmts; i++) { \
+ if(buf[i] == filval) continue; /* ignore fill value */ \
+ if(buf[i] > max) max = buf[i]; \
+ if(buf[i] < min) min = buf[i]; \
+ } \
+}
+
+/* Find maximum and minimum values of a buffer with fill value undefined */
+#define H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min)\
+{ \
+ min = max = buf[0]; \
+ for(i = 0; i < d_nelmts; i++) { \
+ if(buf[i] > max) max = buf[i]; \
+ if(buf[i] < min) min = buf[i]; \
+ } \
+}
+
+/* Find maximum and minimum values of a buffer with fill value defined for floating-point type */
+#define H5Z_scaleoffset_max_min_3(i, d_nelmts, buf, filval, max, min, D_val) \
+{ \
+ i = 0; while(i < d_nelmts && HDfabs(buf[i] - filval) < HDpow(10.0f, -D_val)) i++; \
+ if(i < d_nelmts) min = max = buf[i]; \
+ for(; i < d_nelmts; i++) { \
+ if(HDfabs(buf[i] - filval) < HDpow(10.0f, -D_val)) \
+ continue; /* ignore fill value */ \
+ if(buf[i] > max) max = buf[i]; \
+ if(buf[i] < min) min = buf[i]; \
+ } \
+}
+
+/* Find minimum value of a buffer with fill value defined for integer type */
+#define H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min) \
+{ \
+ i = 0; while(i < d_nelmts && buf[i]== filval) i++; \
+ if(i < d_nelmts) min = buf[i]; \
+ for(; i < d_nelmts; i++) { \
+ if(buf[i] == filval) continue; /* ignore fill value */ \
+ if(buf[i] < min) min = buf[i]; \
+ } \
+}
+
+/* Find minimum value of a buffer with fill value undefined */
+#define H5Z_scaleoffset_min_2(i, d_nelmts, buf, min)\
+{ \
+ min = buf[0]; \
+ for(i = 0; i < d_nelmts; i++) \
+ if(buf[i] < min) min = buf[i]; \
+}
+
+/* Check and handle special situation for unsigned integer type */
+#define H5Z_scaleoffset_check_1(type, max, min, minbits) \
+{ \
+ if(max - min > (type)(~(type)0 - 2)) \
+ { *minbits = sizeof(type)*8; return; } \
+}
+
+/* Check and handle special situation for signed integer type */
+#define H5Z_scaleoffset_check_2(type, max, min, minbits) \
+{ \
+ if((unsigned type)(max - min) > (unsigned type)(~(unsigned type)0 - 2)) \
+ { *minbits = sizeof(type)*8; return; } \
+}
+
+/* Check and handle special situation for floating-point type */
+#define H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val) \
+{ \
+ if(sizeof(type) == sizeof(int)) { \
+ if(round_fun(max * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)) \
+ > pow_fun(2.0f, (type)(sizeof(int) * 8 - 1))) { \
+ *minbits = sizeof(int) * 8; \
+ goto done; \
+ } \
+ } else if(sizeof(type) == sizeof(long)) { \
+ if(round_fun(max * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)) \
+ > pow_fun(2.0f, (type)(sizeof(long) * 8 - 1))) { \
+ *minbits = sizeof(long) * 8; \
+ goto done; \
+ } \
+ } else if(sizeof(type) == sizeof(long long)) { \
+ if(round_fun(max * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)) \
+ > pow_fun(2.0f, (type)(sizeof(long long) * 8 - 1))) { \
+ *minbits = sizeof(long long) * 8; \
+ goto done; \
+ } \
+ } else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Precompress for unsigned integer type */
+#define H5Z_scaleoffset_precompress_1(type, data, d_nelmts, filavail, cd_values, minbits, minval)\
+{ \
+ type *buf = (type *)data, min = 0, max = 0, span, filval = 0; \
+ unsigned i; \
+ \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_1(type, cd_values, filval) \
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \
+ H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min) \
+ H5Z_scaleoffset_check_1(type, max, min, minbits) \
+ span = (type)(max - min + 1); \
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)(span+1)); \
+ } else /* minbits already set, only calculate min */ \
+ H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min) \
+ if(*minbits != sizeof(type)*8) /* change values if minbits != full precision */ \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((buf[i] == filval) ? (((type)1 << *minbits) - 1) : (buf[i] - min)); \
+ } else { /* fill value undefined */ \
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT ) { /* minbits not set yet, calculate max, min, and minbits */ \
+ H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min) \
+ H5Z_scaleoffset_check_1(type, max, min, minbits) \
+ span = (type)(max - min + 1); \
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)span); \
+ } else /* minbits already set, only calculate min */ \
+ H5Z_scaleoffset_min_2(i, d_nelmts, buf, min) \
+ if(*minbits != sizeof(type)*8) /* change values if minbits != full precision */ \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)(buf[i] - min); \
+ } \
+ *minval = min; \
+}
+
+/* Precompress for signed integer type */
+#define H5Z_scaleoffset_precompress_2(type, data, d_nelmts, filavail, cd_values, minbits, minval)\
+{ \
+ type *buf = (type *)data, min = 0, max = 0, filval = 0; \
+ unsigned type span; unsigned i; \
+ \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_1(type, cd_values, filval) \
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \
+ H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min) \
+ H5Z_scaleoffset_check_2(type, max, min, minbits) \
+ span = (unsigned type)(max - min + 1); \
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)(span + 1)); \
+ } else /* minbits already set, only calculate min */ \
+ H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min) \
+ if(*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((buf[i] == filval) ? (type)(((unsigned type)1 << *minbits) - 1) : (buf[i] - min)); \
+ } else { /* fill value undefined */ \
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT ) { /* minbits not set yet, calculate max, min, and minbits */\
+ H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min) \
+ H5Z_scaleoffset_check_2(type, max, min, minbits) \
+ span = (unsigned type)(max - min + 1); \
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)span); \
+ } else /* minbits already set, only calculate min */ \
+ H5Z_scaleoffset_min_2(i, d_nelmts, buf, min) \
+ if(*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)(buf[i] - min); \
+ } \
+ *minval = (unsigned long long)min; \
+}
+
+/* Modify values of data in precompression if fill value defined for floating-point type */
+#define H5Z_scaleoffset_modify_1(i, type, pow_fun, abs_fun, lround_fun, llround_fun, buf, d_nelmts, filval, minbits, min, D_val) \
+{ \
+ if(sizeof(type) == sizeof(int)) \
+ for(i = 0; i < d_nelmts; i++) { \
+ if(abs_fun(buf[i] - filval) < pow_fun(10.0f, (type)-D_val)) \
+ *(int *)&buf[i] = (int)(((unsigned int)1 << *minbits) - 1); \
+ else \
+ *(int *)&buf[i] = (int)lround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ } \
+ else if(sizeof(type) == sizeof(long)) \
+ for(i = 0; i < d_nelmts; i++) { \
+ if(abs_fun(buf[i] - filval) < pow_fun(10.0f, (type)-D_val)) \
+ *(long *)&buf[i] = (long)(((unsigned long)1 << *minbits) - 1); \
+ else \
+ *(long *)&buf[i] = lround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ } \
+ else if(sizeof(type) == sizeof(long long)) \
+ for(i = 0; i < d_nelmts; i++) { \
+ if(abs_fun(buf[i] - filval) < pow_fun(10.0f, (type)-D_val)) \
+ *(long long *)&buf[i] = (long long)(((unsigned long long)1 << *minbits) - 1); \
+ else \
+ *(long long *)&buf[i] = llround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ } \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Modify values of data in precompression if fill value undefined for floating-point type */
+#define H5Z_scaleoffset_modify_2(i, type, pow_fun, lround_fun, llround_fun, buf, d_nelmts, min, D_val) \
+{ \
+ if(sizeof(type) == sizeof(int)) \
+ for(i = 0; i < d_nelmts; i++) \
+ *(int *)&buf[i] = (int)lround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ else if(sizeof(type) == sizeof(long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ *(long *)&buf[i] = lround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ else if(sizeof(type) == sizeof(long long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ *(long long *)&buf[i] = llround_fun(buf[i] * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)); \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Save the minimum value for floating-point type */
+#define H5Z_scaleoffset_save_min(i, type, minval, min) \
+{ \
+ if(sizeof(type) <= sizeof(long long)) \
+ /* Save min value to corresponding position \
+ * byte-order will be swapped as appropriate, but be sure to \
+ * account for offset in BE if sizes differ \
+ */ \
+ if(H5T_native_order_g == H5T_ORDER_LE) \
+ HDmemcpy(minval, &min, sizeof(type)); \
+ else { \
+ HDassert(H5T_native_order_g == H5T_ORDER_BE); \
+ HDmemcpy(((char *)minval) + (sizeof(long long) - sizeof(type)), \
+ &min, sizeof(type)); \
+ } /* end else */ \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Precompress for floating-point type using variable-minimum-bits method */
+#define H5Z_scaleoffset_precompress_3(type, pow_fun, abs_fun, round_fun, lround_fun, llround_fun, data, d_nelmts, filavail, cd_values, \
+ minbits, minval, D_val) \
+{ \
+ type *buf = (type *)data, min = 0, max = 0, filval = 0; \
+ unsigned long long span; \
+ unsigned i; \
+ \
+ *minval = 0; \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_2(type, cd_values, filval) \
+ H5Z_scaleoffset_max_min_3(i, d_nelmts, buf, filval, max, min, D_val) \
+ H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val) \
+ span = (unsigned long long)(llround_fun(max * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)) + 1); \
+ *minbits = H5Z_scaleoffset_log2(span + 1); \
+ if(*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \
+ H5Z_scaleoffset_modify_1(i, type, pow_fun, abs_fun, lround_fun, llround_fun, buf, d_nelmts, filval, minbits, min, D_val) \
+ } else { /* fill value undefined */ \
+ H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min) \
+ H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val) \
+ span = (unsigned long long)(llround_fun(max * pow_fun(10.0f, (type)D_val) - min * pow_fun(10.0f, (type)D_val)) + 1); \
+ *minbits = H5Z_scaleoffset_log2(span); \
+ if(*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \
+ H5Z_scaleoffset_modify_2(i, type, pow_fun, lround_fun, llround_fun, buf, d_nelmts, min, D_val) \
+ } \
+ H5Z_scaleoffset_save_min(i, type, minval, min) \
+}
+
+/* Postdecompress for unsigned integer type */
+#define H5Z_scaleoffset_postdecompress_1(type, data, d_nelmts, filavail, cd_values, minbits, minval)\
+{ \
+ type *buf = (type *)data, filval = 0; unsigned i; \
+ \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_1(type, cd_values, filval) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((buf[i] == (((type)1 << minbits) - 1)) ? filval : (buf[i] + minval)); \
+ } else /* fill value undefined */ \
+ for(i = 0; i < d_nelmts; i++) buf[i] = (type)(buf[i] + (type)(minval)); \
+}
+
+/* Postdecompress for signed integer type */
+#define H5Z_scaleoffset_postdecompress_2(type, data, d_nelmts, filavail, cd_values, minbits, minval)\
+{ \
+ type *buf = (type *)data, filval = 0; \
+ unsigned i; \
+ \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_1(type, cd_values, filval) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)(((unsigned type)buf[i] == (((unsigned type)1 << minbits) - 1)) ? filval : (buf[i] + minval));\
+ } else /* fill value undefined */ \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)(buf[i] + (type)(minval)); \
+}
+
+/* Retrive minimum value of floating-point type */
+#define H5Z_scaleoffset_get_min(type, minval, min) \
+{ \
+ if(sizeof(type) <= sizeof(long long)) \
+ /* retrieve min value from corresponding position \
+ * byte-order has already been swapped as appropriate, but be sure to \
+ * account for offset in BE if sizes differ \
+ */ \
+ if(H5T_native_order_g == H5T_ORDER_LE) \
+ HDmemcpy(&min, &minval, sizeof(type)); \
+ else { \
+ HDassert(H5T_native_order_g == H5T_ORDER_BE); \
+ HDmemcpy(&min, ((char *)&minval) + (sizeof(long long) \
+ - sizeof(type)), sizeof(type)); \
+ } /* end else */ \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Modify values of data in postdecompression if fill value defined for floating-point type */
+#define H5Z_scaleoffset_modify_3(i, type, pow_fun, buf, d_nelmts, filval, minbits, min, D_val) \
+{ \
+ if(sizeof(type) == sizeof(int)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((*(int *)&buf[i] == (int)(((unsigned int)1 << minbits) - 1)) ? \
+ filval : (type)(*(int *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else if(sizeof(type) == sizeof(long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((*(long *)&buf[i] == (long)(((unsigned long)1 << minbits) - 1)) ? \
+ filval : (type)(*(long *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else if(sizeof(type) == sizeof(long long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = (type)((*(long long *)&buf[i] == (long long)(((unsigned long long)1 << minbits) - 1)) ? \
+ filval : (type)(*(long long *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Modify values of data in postdecompression if fill value undefined for floating-point type */
+#define H5Z_scaleoffset_modify_4(i, type, pow_fun, buf, d_nelmts, min, D_val) \
+{ \
+ if(sizeof(type)==sizeof(int)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = ((type)(*(int *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else if(sizeof(type)==sizeof(long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = ((type)(*(long *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else if(sizeof(type)==sizeof(long long)) \
+ for(i = 0; i < d_nelmts; i++) \
+ buf[i] = ((type)(*(long long *)&buf[i]) / pow_fun(10.0f, (type)D_val) + min); \
+ else \
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer dataype") \
+}
+
+/* Postdecompress for floating-point type using variable-minimum-bits method */
+#define H5Z_scaleoffset_postdecompress_3(type, pow_fun, data, d_nelmts, filavail, cd_values, \
+ minbits, minval, D_val) \
+{ \
+ type *buf = (type *)data, filval = 0, min = 0; \
+ unsigned i; \
+ \
+ H5Z_scaleoffset_get_min(type, minval, min) \
+ \
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \
+ H5Z_scaleoffset_get_filval_2(type, cd_values, filval) \
+ H5Z_scaleoffset_modify_3(i, type, pow_fun, buf, d_nelmts, filval, minbits, min, D_val) \
+ } else /* fill value undefined */ \
+ H5Z_scaleoffset_modify_4(i, type, pow_fun, buf, d_nelmts, min, D_val) \
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_can_apply_scaleoffset
+ *
+ * Purpose: Check the parameters for scaleoffset compression for
+ * validity and whether they fit a particular dataset.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Friday, February 4, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5Z_can_apply_scaleoffset(hid_t H5_ATTR_UNUSED dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id)
+{
+ const H5T_t *type; /* Datatype */
+ H5T_class_t dtype_class; /* Datatype's class */
+ H5T_order_t dtype_order; /* Datatype's endianness order */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get datatype */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get datatype's class, for checking the "datatype class" */
+ if((dtype_class = H5T_get_class(type, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")
+
+ /* Get datatype's size, for checking the "datatype size" */
+ if(H5T_get_size(type) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ if(dtype_class == H5T_INTEGER || dtype_class == H5T_FLOAT) {
+ /* Get datatype's endianness order */
+ if((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "can't retrieve datatype endianness order")
+
+ /* Range check datatype's endianness order */
+ if(dtype_order != H5T_ORDER_LE && dtype_order != H5T_ORDER_BE)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FALSE, "bad datatype endianness order")
+ } else
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FALSE, "datatype class not supported by scaleoffset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_can_apply_scaleoffset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_scaleoffset_get_type
+ *
+ * Purpose: Get the specific integer type based on datatype size and sign
+ * or floating-point type based on size
+ *
+ * Return: Success: id number of integer type
+ * Failure: 0
+ *
+ * Programmer: Xiaowen Wu
+ * Wednesday, April 13, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static enum H5Z_scaleoffset_t
+H5Z_scaleoffset_get_type(unsigned dtype_class, unsigned dtype_size, unsigned dtype_sign)
+{
+ enum H5Z_scaleoffset_t type = t_bad; /* integer type */
+ enum H5Z_scaleoffset_t ret_value = t_bad; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_INTEGER) {
+ if(dtype_sign==H5Z_SCALEOFFSET_SGN_NONE) { /* unsigned integer */
+ if (dtype_size == sizeof(unsigned char)) type = t_uchar;
+ else if(dtype_size == sizeof(unsigned short)) type = t_ushort;
+ else if(dtype_size == sizeof(unsigned int)) type = t_uint;
+ else if(dtype_size == sizeof(unsigned long)) type = t_ulong;
+#if H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG
+ else if(dtype_size == sizeof(unsigned long long)) type = t_ulong_long;
+#endif /* H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG */
+ else
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory dataype")
+ }
+
+ if(dtype_sign==H5Z_SCALEOFFSET_SGN_2) { /* signed integer */
+ if (dtype_size == sizeof(signed char)) type = t_schar;
+ else if(dtype_size == sizeof(short)) type = t_short;
+ else if(dtype_size == sizeof(int)) type = t_int;
+ else if(dtype_size == sizeof(long)) type = t_long;
+#if H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG
+ else if(dtype_size == sizeof(long long)) type = t_long_long;
+#endif /* H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG */
+ else
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory dataype")
+ }
+ }
+
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_FLOAT) {
+ if(dtype_size == sizeof(float)) type = t_float;
+ else if(dtype_size == sizeof(double)) type = t_double;
+ else
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory dataype")
+ }
+
+ /* Set return value */
+ ret_value = type;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_scaleoffset_set_parms_fillval
+ *
+ * Purpose: Get the fill value of the dataset and store in cd_values[]
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Monday, March 7, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_scaleoffset_set_parms_fillval(H5P_genplist_t *dcpl_plist,
+ H5T_t *type, enum H5Z_scaleoffset_t scale_type,
+ unsigned cd_values[], int need_convert, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(scale_type == t_uchar)
+ H5Z_scaleoffset_set_filval_3(unsigned char, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_ushort)
+ H5Z_scaleoffset_set_filval_1(unsigned short, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_uint)
+ H5Z_scaleoffset_set_filval_1(unsigned int, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_ulong)
+ H5Z_scaleoffset_set_filval_1(unsigned long, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_ulong_long)
+ H5Z_scaleoffset_set_filval_1(unsigned long long, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_schar)
+ H5Z_scaleoffset_set_filval_3(signed char, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_short)
+ H5Z_scaleoffset_set_filval_2(short, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_int)
+ H5Z_scaleoffset_set_filval_2(int, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_long)
+ H5Z_scaleoffset_set_filval_2(long, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_long_long)
+ H5Z_scaleoffset_set_filval_2(long long, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_float)
+ H5Z_scaleoffset_set_filval_4(float, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+ else if(scale_type == t_double)
+ H5Z_scaleoffset_set_filval_4(double, dcpl_plist, type, cd_values, need_convert, dxpl_id)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_scaleoffset_set_parms_fillval() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local_scaleoffset
+ *
+ * Purpose: Set the "local" dataset parameters for scaleoffset
+ * compression.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Xiaowen Wu
+ * Friday, February 4, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_local_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id)
+{
+ H5P_genplist_t *dcpl_plist; /* Property list pointer */
+ H5T_t *type; /* Datatype */
+ const H5S_t *ds; /* Dataspace */
+ unsigned flags; /* Filter flags */
+ size_t cd_nelmts = H5Z_SCALEOFFSET_USER_NPARMS; /* Number of filter parameters */
+ unsigned cd_values[H5Z_SCALEOFFSET_TOTAL_NPARMS]; /* Filter parameters */
+ hssize_t npoints; /* Number of points in the dataspace */
+ H5T_class_t dtype_class; /* Datatype's class */
+ H5T_order_t dtype_order; /* Datatype's endianness order */
+ size_t dtype_size; /* Datatype's size (in bytes) */
+ H5T_sign_t dtype_sign; /* Datatype's sign */
+ enum H5Z_scaleoffset_t scale_type; /* Specific datatype */
+ H5D_fill_value_t status; /* Status of fill value in property list */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Get the plist structure */
+ if(NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get datatype */
+ if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Initialize the parameters to a known state */
+ HDmemset(cd_values, 0, sizeof(cd_values));
+
+ /* Get the filter's current parameters */
+ if(H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SCALEOFFSET, &flags, &cd_nelmts, cd_values, (size_t)0, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get scaleoffset parameters")
+
+ /* Get dataspace */
+ if(NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Get total number of elements in the chunk */
+ if((npoints = H5S_GET_EXTENT_NPOINTS(ds)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get number of points in the dataspace")
+
+ /* Set "local" parameter for this dataset's number of elements */
+ H5_CHECKED_ASSIGN(cd_values[H5Z_SCALEOFFSET_PARM_NELMTS], unsigned, npoints, hssize_t);
+
+ /* Get datatype's class */
+ if((dtype_class = H5T_get_class(type, TRUE)) == H5T_NO_CLASS)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")
+
+ /* Set "local" parameter for datatype's class */
+ switch(dtype_class) {
+ case H5T_INTEGER:
+ cd_values[H5Z_SCALEOFFSET_PARM_CLASS] = H5Z_SCALEOFFSET_CLS_INTEGER;
+ break;
+
+ case H5T_FLOAT:
+ cd_values[H5Z_SCALEOFFSET_PARM_CLASS] = H5Z_SCALEOFFSET_CLS_FLOAT;
+ break;
+
+ case H5T_NO_CLASS:
+ case H5T_TIME:
+ case H5T_STRING:
+ case H5T_BITFIELD:
+ case H5T_OPAQUE:
+ case H5T_COMPOUND:
+ case H5T_REFERENCE:
+ case H5T_ENUM:
+ case H5T_VLEN:
+ case H5T_ARRAY:
+ case H5T_NCLASSES:
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "datatype class not supported by scaleoffset")
+ } /* end switch */
+
+ /* Get datatype's size */
+ if((dtype_size = H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Set "local" parameter for datatype size */
+ H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned);
+ cd_values[H5Z_SCALEOFFSET_PARM_SIZE] = (unsigned)dtype_size;
+
+ if(dtype_class == H5T_INTEGER) {
+ /* Get datatype's sign */
+ if((dtype_sign = H5T_get_sign(type)) == H5T_SGN_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype sign")
+
+ /* Set "local" parameter for integer datatype sign */
+ switch(dtype_sign) {
+ case H5T_SGN_NONE:
+ cd_values[H5Z_SCALEOFFSET_PARM_SIGN] = H5Z_SCALEOFFSET_SGN_NONE;
+ break;
+
+ case H5T_SGN_2:
+ cd_values[H5Z_SCALEOFFSET_PARM_SIGN] = H5Z_SCALEOFFSET_SGN_2;
+ break;
+
+ case H5T_SGN_ERROR:
+ case H5T_NSGN:
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad integer sign")
+ } /* end switch */
+ } /* end if */
+
+ /* Get datatype's endianness order */
+ if((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+
+ /* Set "local" parameter for datatype endianness */
+ switch(dtype_order) {
+ case H5T_ORDER_LE: /* Little-endian byte order */
+ cd_values[H5Z_SCALEOFFSET_PARM_ORDER] = H5Z_SCALEOFFSET_ORDER_LE;
+ break;
+
+ case H5T_ORDER_BE: /* Big-endian byte order */
+ cd_values[H5Z_SCALEOFFSET_PARM_ORDER] = H5Z_SCALEOFFSET_ORDER_BE;
+ break;
+
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+ } /* end switch */
+
+ /* Check whether fill value is defined for dataset */
+ if(H5P_fill_value_defined(dcpl_plist, &status) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to determine if fill value is defined")
+
+ /* Set local parameter for availability of fill value */
+ if(status == H5D_FILL_VALUE_UNDEFINED)
+ cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL] = H5Z_SCALEOFFSET_FILL_UNDEFINED;
+ else {
+ int need_convert = FALSE; /* Flag indicating convertion of byte order */
+
+ cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL] = H5Z_SCALEOFFSET_FILL_DEFINED;
+
+ /* Check if memory byte order matches dataset datatype byte order */
+ if(H5T_native_order_g != dtype_order)
+ need_convert = TRUE;
+
+ /* Before getting fill value, get its type */
+ if((scale_type = H5Z_scaleoffset_get_type(cd_values[H5Z_SCALEOFFSET_PARM_CLASS],
+ cd_values[H5Z_SCALEOFFSET_PARM_SIZE], cd_values[H5Z_SCALEOFFSET_PARM_SIGN])) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot use C integer datatype for cast")
+
+ /* Get dataset fill value and store in cd_values[] */
+ if(H5Z_scaleoffset_set_parms_fillval(dcpl_plist, type, scale_type, cd_values, need_convert, H5AC_noio_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "unable to set fill value")
+ } /* end else */
+
+ /* Modify the filter's parameters for this dataset */
+ if(H5P_modify_filter(dcpl_plist, H5Z_FILTER_SCALEOFFSET, flags, (size_t)H5Z_SCALEOFFSET_TOTAL_NPARMS, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local scaleoffset parameters")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local_scaleoffset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_scaleoffset
+ *
+ * Purpose: Implement an I/O filter for storing packed integer
+ * data using scale and offset method.
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Xiaowen Wu
+ * Monday, February 7, 2005
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_scaleoffset(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf)
+{
+ size_t ret_value = 0; /* return value */
+ size_t size_out = 0; /* size of output buffer */
+ unsigned d_nelmts = 0; /* number of data elements in the chunk */
+ unsigned dtype_class; /* datatype class */
+ unsigned dtype_sign; /* integer datatype sign */
+ unsigned filavail; /* flag indicating if fill value is defined or not */
+ H5Z_SO_scale_type_t scale_type = H5Z_SO_FLOAT_DSCALE;/* scale type */
+ int scale_factor = 0; /* scale factor */
+ double D_val = 0.0f; /* decimal scale factor */
+ uint32_t minbits = 0; /* minimum number of bits to store values */
+ unsigned long long minval= 0; /* minimum value of input buffer */
+ enum H5Z_scaleoffset_t type; /* memory type corresponding to dataset datatype */
+ int need_convert = FALSE; /* flag indicating convertion of byte order */
+ unsigned char *outbuf = NULL; /* pointer to new output buffer */
+ unsigned buf_offset = 21; /* buffer offset because of parameters stored in file */
+ unsigned i; /* index */
+ parms_atomic p; /* paramters needed for compress/decompress functions */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check arguments */
+ if(cd_nelmts != H5Z_SCALEOFFSET_TOTAL_NPARMS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scaleoffset number of paramters")
+
+ /* Check if memory byte order matches dataset datatype byte order */
+ switch(H5T_native_order_g) {
+ case H5T_ORDER_LE: /* memory is little-endian byte order */
+ if(cd_values[H5Z_SCALEOFFSET_PARM_ORDER] == H5Z_SCALEOFFSET_ORDER_BE)
+ need_convert = TRUE;
+ break;
+
+ case H5T_ORDER_BE: /* memory is big-endian byte order */
+ if(cd_values[H5Z_SCALEOFFSET_PARM_ORDER] == H5Z_SCALEOFFSET_ORDER_LE)
+ need_convert = TRUE;
+ break;
+
+ case H5T_ORDER_ERROR:
+ case H5T_ORDER_VAX:
+ case H5T_ORDER_MIXED:
+ case H5T_ORDER_NONE:
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "bad H5T_NATIVE_INT endianness order")
+ } /* end switch */
+
+ /* copy filter parameters to local variables */
+ d_nelmts = cd_values[H5Z_SCALEOFFSET_PARM_NELMTS];
+ dtype_class = cd_values[H5Z_SCALEOFFSET_PARM_CLASS];
+ dtype_sign = cd_values[H5Z_SCALEOFFSET_PARM_SIGN];
+ filavail = cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL];
+ scale_factor = (int)cd_values[H5Z_SCALEOFFSET_PARM_SCALEFACTOR];
+ scale_type = (H5Z_SO_scale_type_t)cd_values[H5Z_SCALEOFFSET_PARM_SCALETYPE];
+
+ /* check and assign proper values set by user to related parameters
+ * scale type can be H5Z_SO_FLOAT_DSCALE (0), H5Z_SO_FLOAT_ESCALE (1) or H5Z_SO_INT (other)
+ * H5Z_SO_FLOAT_DSCALE : floating-point type, variable-minimum-bits method,
+ * scale factor is decimal scale factor
+ * H5Z_SO_FLOAT_ESCALE : floating-point type, fixed-minimum-bits method,
+ * scale factor is the fixed minimum number of bits
+ * H5Z_SO_INT : integer type, scale_factor is minimum number of bits
+ */
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_FLOAT) { /* floating-point type */
+ if(scale_type!=H5Z_SO_FLOAT_DSCALE && scale_type!=H5Z_SO_FLOAT_ESCALE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scale type")
+ }
+
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_INTEGER) { /* integer type */
+ if(scale_type!=H5Z_SO_INT)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scale type")
+
+ /* if scale_factor is less than 0 for integer, library will reset it to 0
+ * in this case, library will calculate the minimum-bits
+ */
+ if(scale_factor < 0) scale_factor = 0;
+ }
+
+ /* fixed-minimum-bits method is not implemented and is forbidden */
+ if(scale_type==H5Z_SO_FLOAT_ESCALE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "E-scaling method not supported")
+
+ if(scale_type==H5Z_SO_FLOAT_DSCALE) { /* floating-point type, variable-minimum-bits */
+ D_val = (double)scale_factor;
+ } else { /* integer type, or floating-point type with fixed-minimum-bits method */
+ if(scale_factor > (int)(cd_values[H5Z_SCALEOFFSET_PARM_SIZE] * 8))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "minimum number of bits exceeds maximum")
+
+ /* no need to process data */
+ if(scale_factor == (int)(cd_values[H5Z_SCALEOFFSET_PARM_SIZE] * 8)) {
+ ret_value = *buf_size;
+ goto done;
+ }
+ minbits = (uint32_t)scale_factor;
+ }
+
+ /* prepare paramters to pass to compress/decompress functions */
+ p.size = cd_values[H5Z_SCALEOFFSET_PARM_SIZE];
+ p.mem_order = H5T_native_order_g;
+
+ /* input; decompress */
+ if (flags & H5Z_FLAG_REVERSE) {
+ /* retrieve values of minbits and minval from input compressed buffer
+ * retrieve them corresponding to how they are stored during compression
+ */
+ uint32_t minbits_mask = 0;
+ unsigned long long minval_mask = 0;
+ unsigned minval_size = 0;
+
+ minbits = 0;
+ for(i = 0; i < 4; i++) {
+ minbits_mask = ((unsigned char *)*buf)[i];
+ minbits_mask <<= i*8;
+ minbits |= minbits_mask;
+ }
+
+ /* retrieval of minval takes into consideration situation where sizeof
+ * unsigned long long (datatype of minval) may change from compression
+ * to decompression, only smaller size is used
+ */
+ minval_size = sizeof(unsigned long long) <= ((unsigned char *)*buf)[4] ?
+ sizeof(unsigned long long) : ((unsigned char *)*buf)[4];
+ minval = 0;
+ for(i = 0; i < minval_size; i++) {
+ minval_mask = ((unsigned char *)*buf)[5+i];
+ minval_mask <<= i*8;
+ minval |= minval_mask;
+ }
+
+ HDassert(minbits <= p.size * 8);
+ p.minbits = minbits;
+
+ /* calculate size of output buffer after decompression */
+ size_out = d_nelmts * p.size;
+
+ /* allocate memory space for decompressed buffer */
+ if(NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for scaleoffset decompression")
+
+ /* special case: minbits equal to full precision */
+ if(minbits == p.size * 8) {
+ HDmemcpy(outbuf, (unsigned char*)(*buf)+buf_offset, size_out);
+
+ /* convert to dataset datatype endianness order if needed */
+ if(need_convert)
+ H5Z_scaleoffset_convert(outbuf, d_nelmts, p.size);
+
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = size_out;
+ ret_value = size_out;
+ goto done;
+ }
+
+ /* decompress the buffer if minbits not equal to zero */
+ if(minbits != 0)
+ H5Z_scaleoffset_decompress(outbuf, d_nelmts, (unsigned char*)(*buf)+buf_offset, p);
+ else {
+ /* fill value is not defined and all data elements have the same value */
+ for(i = 0; i < size_out; i++) outbuf[i] = 0;
+ }
+
+ /* before postprocess, get memory type */
+ if((type = H5Z_scaleoffset_get_type(dtype_class, p.size, dtype_sign)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "cannot use C integer datatype for cast")
+
+ /* postprocess after decompression */
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_INTEGER)
+ H5Z_scaleoffset_postdecompress_i(outbuf, d_nelmts, type, filavail,
+ cd_values, minbits, minval);
+
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_FLOAT)
+ if(scale_type==0) { /* variable-minimum-bits method */
+ if(H5Z_scaleoffset_postdecompress_fd(outbuf, d_nelmts, type, filavail,
+ cd_values, minbits, minval, D_val)==FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "post-decompression failed")
+ }
+
+ /* after postprocess, convert to dataset datatype endianness order if needed */
+ if(need_convert)
+ H5Z_scaleoffset_convert(outbuf, d_nelmts, p.size);
+ }
+ /* output; compress */
+ else {
+ HDassert(nbytes == d_nelmts * p.size);
+
+ /* before preprocess, convert to memory endianness order if needed */
+ if(need_convert)
+ H5Z_scaleoffset_convert(*buf, d_nelmts, p.size);
+
+ /* before preprocess, get memory type */
+ if((type = H5Z_scaleoffset_get_type(dtype_class, p.size, dtype_sign))==0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "cannot use C integer datatype for cast")
+
+ /* preprocess before compression */
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_INTEGER)
+ H5Z_scaleoffset_precompress_i(*buf, d_nelmts, type, filavail,
+ cd_values, &minbits, &minval);
+
+ if(dtype_class==H5Z_SCALEOFFSET_CLS_FLOAT)
+ if(scale_type==0) { /* variable-minimum-bits method */
+ if(H5Z_scaleoffset_precompress_fd(*buf, d_nelmts, type, filavail,
+ cd_values, &minbits, &minval, D_val)==FAIL)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "pre-compression failed")
+ }
+
+ HDassert(minbits <= p.size * 8);
+
+ /* calculate buffer size after compression
+ * minbits and minval are stored in the front of the compressed buffer
+ */
+ p.minbits = minbits;
+ size_out = buf_offset + nbytes * p.minbits / (p.size * 8) + 1; /* may be 1 larger */
+
+ /* allocate memory space for compressed buffer */
+ if(NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for scaleoffset compression")
+
+ /* store minbits and minval in the front of output compressed buffer
+ * store byte by byte from least significant byte to most significant byte
+ * constant buffer size (21 bytes) is left for these two parameters
+ * 4 bytes for minbits, 1 byte for size of minval, 16 bytes for minval
+ */
+ for(i = 0; i < 4; i++)
+ ((unsigned char *)outbuf)[i] = (unsigned char)((minbits & ((uint32_t)0xff << i*8)) >> i*8);
+
+ ((unsigned char *)outbuf)[4] = sizeof(unsigned long long);
+
+ for(i = 0; i < sizeof(unsigned long long); i++)
+ ((unsigned char *)outbuf)[5+i] = (unsigned char)((minval & ((unsigned long long)0xff << i*8)) >> i*8);
+
+ /* Zero out remaining, unused bytes */
+ /* (Looks like an error in the original determination of how many
+ * bytes would be needed for parameters. - QAK, 2010/08/19)
+ */
+ HDmemset(outbuf + 13, 0, (size_t)8);
+
+ /* special case: minbits equal to full precision */
+ if(minbits == p.size * 8) {
+ HDmemcpy(outbuf + buf_offset, *buf, nbytes);
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = size_out;
+ ret_value = buf_offset + nbytes;
+ goto done;
+ }
+
+ /* compress the buffer if minbits not equal to zero
+ * minbits equal to zero only when fill value is not defined and
+ * all data elements have the same value
+ */
+ if(minbits != 0)
+ H5Z_scaleoffset_compress((unsigned char *)*buf, d_nelmts, outbuf + buf_offset, size_out - buf_offset, p);
+ }
+
+ /* free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* set return values */
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = size_out;
+ ret_value = size_out;
+
+done:
+ if(outbuf)
+ H5MM_xfree(outbuf);
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/* ============ Scaleoffset Algorithm ===============================================
+ * assume one byte has 8 bit
+ * assume padding bit is 0
+ * assume size of unsigned char is one byte
+ * assume one data item of certain datatype is stored continously in bytes
+ * atomic datatype is treated on byte basis
+ */
+
+
+/* change byte order of input buffer either from little-endian to big-endian
+ * or from big-endian to little-endian 2/21/2005
+ */
+static void
+H5Z_scaleoffset_convert(void *buf, unsigned d_nelmts, unsigned dtype_size)
+{
+ if(dtype_size > 1) {
+ size_t i, j;
+ unsigned char *buffer, temp;
+
+ buffer = (unsigned char *)buf;
+ for(i = 0; i < d_nelmts * dtype_size; i += dtype_size)
+ for(j = 0; j < dtype_size / 2; j++) {
+ /* swap pair of bytes */
+ temp = buffer[i + j];
+ buffer[i + j] = buffer[i + dtype_size - 1 - j];
+ buffer[i + dtype_size - 1 - j] = temp;
+ } /* end for */
+ } /* end if */
+} /* end H5Z_scaleoffset_convert() */
+
+/* return ceiling of floating-point log2 function
+ * receive unsigned integer as argument 3/10/2005
+ */
+static unsigned
+H5Z_scaleoffset_log2(unsigned long long num)
+{
+ unsigned v = 0;
+ unsigned long long lower_bound = 1; /* is power of 2, largest value <= num */
+ unsigned long long val = num;
+
+ while(val >>= 1) {
+ v++;
+ lower_bound <<= 1;
+ }
+
+ if(num == lower_bound)
+ return v;
+ else
+ return v + 1;
+}
+
+/* precompress for integer type */
+static void
+H5Z_scaleoffset_precompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type,
+ unsigned filavail, const unsigned cd_values[], uint32_t *minbits, unsigned long long *minval)
+{
+ if(type == t_uchar)
+ H5Z_scaleoffset_precompress_1(unsigned char, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_ushort)
+ H5Z_scaleoffset_precompress_1(unsigned short, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_uint)
+ H5Z_scaleoffset_precompress_1(unsigned int, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_ulong)
+ H5Z_scaleoffset_precompress_1(unsigned long, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_ulong_long)
+ H5Z_scaleoffset_precompress_1(unsigned long long, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_schar) {
+ signed char *buf = (signed char *)data, min = 0, max = 0, filval = 0;
+ unsigned char span;
+ unsigned i;
+
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */
+ H5Z_scaleoffset_get_filval_1(signed char, cd_values, filval);
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */
+ H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min)
+ if((unsigned char)(max - min) > (unsigned char)(~(unsigned char)0 - 2)) {
+ *minbits = sizeof(signed char)*8;
+ return;
+ }
+ span = (unsigned char)(max - min + 1);
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)(span+1));
+ } else /* minbits already set, only calculate min */
+ H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min)
+ if(*minbits != sizeof(signed char)*8) /* change values if minbits != full precision */
+ for(i = 0; i < d_nelmts; i++)
+ buf[i] = (signed char)((buf[i] == filval) ? (((unsigned char)1 << *minbits) - 1) : (buf[i] - min));
+ } else { /* fill value undefined */
+ if(*minbits == H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */
+ H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min)
+ if((unsigned char)(max - min) > (unsigned char)(~(unsigned char)0 - 2)) {
+ *minbits = sizeof(signed char)*8;
+ *minval = (unsigned long long)min;
+ return;
+ }
+ span = (unsigned char)(max - min + 1);
+ *minbits = H5Z_scaleoffset_log2((unsigned long long)span);
+ } else /* minbits already set, only calculate min */
+ H5Z_scaleoffset_min_2(i, d_nelmts, buf, min)
+ if(*minbits != sizeof(signed char) * 8) /* change values if minbits != full precision */
+ for(i = 0; i < d_nelmts; i++)
+ buf[i] = (signed char)(buf[i] - min);
+ }
+ *minval = (unsigned long long)min;
+ }
+ else if(type == t_short)
+ H5Z_scaleoffset_precompress_2(short, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_int)
+ H5Z_scaleoffset_precompress_2(int, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_long)
+ H5Z_scaleoffset_precompress_2(long, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+ else if(type == t_long_long)
+ H5Z_scaleoffset_precompress_2(long long, data, d_nelmts,
+ filavail, cd_values, minbits, minval)
+}
+
+/* postdecompress for integer type */
+static void
+H5Z_scaleoffset_postdecompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type,
+ unsigned filavail, const unsigned cd_values[], uint32_t minbits, unsigned long long minval)
+{
+ long long sminval = *(long long*)&minval; /* for signed integer types */
+
+ if(type == t_uchar)
+ H5Z_scaleoffset_postdecompress_1(unsigned char, data, d_nelmts, filavail,
+ cd_values, minbits, minval)
+ else if(type == t_ushort)
+ H5Z_scaleoffset_postdecompress_1(unsigned short, data, d_nelmts, filavail,
+ cd_values, minbits, minval)
+ else if(type == t_uint)
+ H5Z_scaleoffset_postdecompress_1(unsigned int, data, d_nelmts, filavail,
+ cd_values, minbits, minval)
+ else if(type == t_ulong)
+ H5Z_scaleoffset_postdecompress_1(unsigned long, data, d_nelmts, filavail,
+ cd_values, minbits, minval)
+ else if(type == t_ulong_long)
+ H5Z_scaleoffset_postdecompress_1(unsigned long long, data, d_nelmts, filavail,
+ cd_values, minbits, minval)
+ else if(type == t_schar) {
+ signed char *buf = (signed char *)data, filval = 0;
+ unsigned i;
+
+ if(filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */
+ H5Z_scaleoffset_get_filval_1(signed char, cd_values, filval)
+ for(i = 0; i < d_nelmts; i++)
+ buf[i] = (signed char)((buf[i] == (((unsigned char)1 << minbits) - 1)) ? filval : (buf[i] + sminval));
+ } else /* fill value undefined */
+ for(i = 0; i < d_nelmts; i++)
+ buf[i] = (signed char)(buf[i] + sminval);
+ }
+ else if(type == t_short)
+ H5Z_scaleoffset_postdecompress_2(short, data, d_nelmts, filavail,
+ cd_values, minbits, sminval)
+ else if(type == t_int)
+ H5Z_scaleoffset_postdecompress_2(int, data, d_nelmts, filavail,
+ cd_values, minbits, sminval)
+ else if(type == t_long)
+ H5Z_scaleoffset_postdecompress_2(long, data, d_nelmts, filavail,
+ cd_values, minbits, sminval)
+ else if(type == t_long_long)
+ H5Z_scaleoffset_postdecompress_2(long long, data, d_nelmts, filavail,
+ cd_values, minbits, sminval)
+}
+
+/* precompress for floating-point type, variable-minimum-bits method
+ success: non-negative, failure: negative 4/15/05 */
+static herr_t
+H5Z_scaleoffset_precompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type,
+ unsigned filavail, const unsigned cd_values[], uint32_t *minbits,
+ unsigned long long *minval, double D_val)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(type == t_float)
+ H5Z_scaleoffset_precompress_3(float, HDpowf, HDfabsf, HDroundf, HDlroundf, HDllroundf, data, d_nelmts,
+ filavail, cd_values, minbits, minval, D_val)
+ else if(type == t_double)
+ H5Z_scaleoffset_precompress_3(double, HDpow, HDfabs, HDround, HDlround, HDllround, data, d_nelmts,
+ filavail, cd_values, minbits, minval, D_val)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/* postdecompress for floating-point type, variable-minimum-bits method
+ success: non-negative, failure: negative 4/15/05 */
+static herr_t
+H5Z_scaleoffset_postdecompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type,
+ unsigned filavail, const unsigned cd_values[], uint32_t minbits,
+ unsigned long long minval, double D_val)
+{
+ long long sminval = (long long)minval; /* for signed integer types */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(type == t_float)
+ H5Z_scaleoffset_postdecompress_3(float, HDpowf, data, d_nelmts, filavail,
+ cd_values, minbits, sminval, D_val)
+ else if(type == t_double)
+ H5Z_scaleoffset_postdecompress_3(double, HDpow, data, d_nelmts, filavail,
+ cd_values, minbits, sminval, D_val)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+static void
+H5Z_scaleoffset_next_byte(size_t *j, unsigned *buf_len)
+{
+ ++(*j);
+ *buf_len = 8 * sizeof(unsigned char);
+}
+
+static void
+H5Z_scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset,
+ unsigned k, unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len,
+ parms_atomic p, unsigned dtype_len)
+{
+ unsigned dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ /* initialize value and bits of unsigned char to be copied */
+ val = buffer[*j];
+ if(k == begin_i)
+ dat_len = 8 - (dtype_len - p.minbits) % 8;
+ else
+ dat_len = 8;
+
+ if(*buf_len > dat_len) {
+ data[data_offset + k] = (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)~0 << dat_len)));
+ *buf_len -= dat_len;
+ } /* end if */
+ else {
+ data[data_offset + k] = (unsigned char)((val & ~((unsigned)(~0) << *buf_len)) << (dat_len - *buf_len));
+ dat_len -= *buf_len;
+ H5Z_scaleoffset_next_byte(j, buf_len);
+ if(dat_len == 0)
+ return;
+
+ val = buffer[*j];
+ data[data_offset + k] |= (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & ~((unsigned)(~0) << dat_len));
+ *buf_len -= dat_len;
+ } /* end else */
+}
+
+static void
+H5Z_scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, unsigned *buf_len, parms_atomic p)
+{
+ /* begin_i: the index of byte having first significant bit */
+ unsigned begin_i;
+ unsigned dtype_len;
+ int k;
+
+ HDassert(p.minbits > 0);
+
+ dtype_len = p.size * 8;
+
+ if(p.mem_order == H5Z_SCALEOFFSET_ORDER_LE) { /* little endian */
+ begin_i = p.size - 1 - (dtype_len - p.minbits) / 8;
+
+ for(k = (int)begin_i; k >= 0; k--)
+ H5Z_scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i,
+ buffer, j, buf_len, p, dtype_len);
+ }
+ else { /* big endian */
+ HDassert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE);
+
+ begin_i = (dtype_len - p.minbits) / 8;
+
+ for(k = (int)begin_i; k <= (int)(p.size - 1); k++)
+ H5Z_scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i,
+ buffer, j, buf_len, p, dtype_len);
+ }
+}
+
+static void
+H5Z_scaleoffset_decompress(unsigned char *data, unsigned d_nelmts,
+ unsigned char *buffer, parms_atomic p)
+{
+ /* i: index of data, j: index of buffer,
+ buf_len: number of bits to be filled in current byte */
+ size_t i, j;
+ unsigned buf_len;
+
+ /* must initialize to zeros */
+ for(i = 0; i < d_nelmts * p.size; i++)
+ data[i] = 0;
+
+ /* initialization before the loop */
+ j = 0;
+ buf_len = sizeof(unsigned char) * 8;
+
+ /* decompress */
+ for(i = 0; i < d_nelmts; i++)
+ H5Z_scaleoffset_decompress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p);
+}
+
+static void
+H5Z_scaleoffset_compress_one_byte(unsigned char *data, size_t data_offset,
+ unsigned k, unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len,
+ parms_atomic p, unsigned dtype_len)
+{
+ unsigned dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ /* initialize value and bits of unsigned char to be copied */
+ val = data[data_offset + k];
+ if(k == begin_i)
+ dat_len = 8 - (dtype_len - p.minbits) % 8;
+ else
+ dat_len = 8;
+
+ if(*buf_len > dat_len) {
+ buffer[*j] |= (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len));
+ *buf_len -= dat_len;
+ } else {
+ buffer[*j] |= (unsigned char)((unsigned)(val >> (dat_len - *buf_len)) & ~((unsigned)(~0) << *buf_len));
+ dat_len -= *buf_len;
+ H5Z_scaleoffset_next_byte(j, buf_len);
+ if(dat_len == 0)
+ return;
+
+ buffer[*j] = (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len));
+ *buf_len -= dat_len;
+ } /* end else */
+}
+
+static void
+H5Z_scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, unsigned *buf_len, parms_atomic p)
+{
+ /* begin_i: the index of byte having first significant bit */
+ unsigned begin_i;
+ unsigned dtype_len;
+ int k;
+
+ HDassert(p.minbits > 0);
+
+ dtype_len = p.size * 8;
+
+ if(p.mem_order == H5Z_SCALEOFFSET_ORDER_LE) { /* little endian */
+ begin_i = p.size - 1 - (dtype_len - p.minbits) / 8;
+
+ for(k = (int)begin_i; k >= 0; k--)
+ H5Z_scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i,
+ buffer, j, buf_len, p, dtype_len);
+ }
+ else { /* big endian */
+ HDassert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE);
+ begin_i = (dtype_len - p.minbits) / 8;
+
+ for(k = (int)begin_i; k <= (int)(p.size - 1); k++)
+ H5Z_scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i,
+ buffer, j, buf_len, p, dtype_len);
+ }
+}
+
+static void
+H5Z_scaleoffset_compress(unsigned char *data, unsigned d_nelmts,
+ unsigned char *buffer, size_t buffer_size, parms_atomic p)
+{
+ /* i: index of data, j: index of buffer,
+ buf_len: number of bits to be filled in current byte */
+ size_t i, j;
+ unsigned buf_len;
+
+ /* must initialize buffer to be zeros */
+ for(j = 0; j < buffer_size; j++)
+ buffer[j] = 0;
+
+ /* initialization before the loop */
+ j = 0;
+ buf_len = sizeof(unsigned char) * 8;
+
+ /* compress */
+ for(i = 0; i < d_nelmts; i++)
+ H5Z_scaleoffset_compress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p);
+}
+
diff --git a/src/H5Zshuffle.c b/src/H5Zshuffle.c
new file mode 100644
index 0000000..1fef1c1
--- /dev/null
+++ b/src/H5Zshuffle.c
@@ -0,0 +1,289 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5Zpkg.h" /* Data filters */
+
+/* Local function prototypes */
+static herr_t H5Z_set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static size_t H5Z_filter_shuffle(unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf);
+
+/* This message derives from H5Z */
+const H5Z_class2_t H5Z_SHUFFLE[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_SHUFFLE, /* Filter id number */
+ 1, /* encoder_present flag (set to true) */
+ 1, /* decoder_present flag (set to true) */
+ "shuffle", /* Filter name for debugging */
+ NULL, /* The "can apply" callback */
+ H5Z_set_local_shuffle, /* The "set local" callback */
+ H5Z_filter_shuffle, /* The actual filter function */
+}};
+
+/* Local macros */
+#define H5Z_SHUFFLE_PARM_SIZE 0 /* "Local" parameter for shuffling size */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local_shuffle
+ *
+ * Purpose: Set the "local" dataset parameter for data shuffling to be
+ * the size of the datatype.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id)
+{
+ H5P_genplist_t *dcpl_plist; /* Property list pointer */
+ const H5T_t *type; /* Datatype */
+ unsigned flags; /* Filter flags */
+ size_t cd_nelmts = H5Z_SHUFFLE_USER_NPARMS; /* Number of filter parameters */
+ unsigned cd_values[H5Z_SHUFFLE_TOTAL_NPARMS]; /* Filter parameters */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the plist structure */
+ if(NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get datatype */
+ if(NULL == (type = (const H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get the filter's current parameters */
+ if(H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SHUFFLE, &flags, &cd_nelmts, cd_values, (size_t)0, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get shuffle parameters")
+
+ /* Set "local" parameter for this dataset */
+ if((cd_values[H5Z_SHUFFLE_PARM_SIZE] = (unsigned)H5T_get_size(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Modify the filter's parameters for this dataset */
+ if(H5P_modify_filter(dcpl_plist, H5Z_FILTER_SHUFFLE, flags, (size_t)H5Z_SHUFFLE_TOTAL_NPARMS, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local shuffle parameters")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local_shuffle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_shuffle
+ *
+ * Purpose: Implement an I/O filter which "de-interlaces" a block of data
+ * by putting all the bytes in a byte-position for each element
+ * together in the block. For example, for 4-byte elements stored
+ * as: 012301230123, shuffling will store them as: 000111222333
+ * Usually, the bytes in each byte position are more related to
+ * each other and putting them together will increase compression.
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Kent Yang
+ * Wednesday, November 13, 2002
+ *
+ * Modifications:
+ * Quincey Koziol, November 13, 2002
+ * Cleaned up code.
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf)
+{
+ void *dest = NULL; /* Buffer to deposit [un]shuffled bytes into */
+ unsigned char *_src=NULL; /* Alias for source buffer */
+ unsigned char *_dest=NULL; /* Alias for destination buffer */
+ unsigned bytesoftype; /* Number of bytes per element */
+ size_t numofelements; /* Number of elements in buffer */
+ size_t i; /* Local index variables */
+#ifdef NO_DUFFS_DEVICE
+ size_t j; /* Local index variable */
+#endif /* NO_DUFFS_DEVICE */
+ size_t leftover; /* Extra bytes at end of buffer */
+ size_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Check arguments */
+ if (cd_nelmts!=H5Z_SHUFFLE_TOTAL_NPARMS || cd_values[H5Z_SHUFFLE_PARM_SIZE]==0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid shuffle parameters")
+
+ /* Get the number of bytes per element from the parameter block */
+ bytesoftype=cd_values[H5Z_SHUFFLE_PARM_SIZE];
+
+ /* Compute the number of elements in buffer */
+ numofelements=nbytes/bytesoftype;
+
+ /* Don't do anything for 1-byte elements, or "fractional" elements */
+ if(bytesoftype > 1 && numofelements > 1) {
+ /* Compute the leftover bytes if there are any */
+ leftover = nbytes%bytesoftype;
+
+ /* Allocate the destination buffer */
+ if (NULL==(dest = H5MM_malloc(nbytes)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for shuffle buffer")
+
+ if(flags & H5Z_FLAG_REVERSE) {
+ /* Get the pointer to the source buffer */
+ _src =(unsigned char *)(*buf);
+
+ /* Input; unshuffle */
+ for(i=0; i<bytesoftype; i++) {
+ _dest=((unsigned char *)dest)+i;
+#define DUFF_GUTS \
+ *_dest=*_src++; \
+ _dest+=bytesoftype;
+#ifdef NO_DUFFS_DEVICE
+ j = numofelements;
+ while(j > 0) {
+ DUFF_GUTS;
+
+ j--;
+ } /* end for */
+#else /* NO_DUFFS_DEVICE */
+ {
+ size_t duffs_index; /* Counting index for Duff's device */
+
+ duffs_index = (numofelements + 7) / 8;
+ switch (numofelements % 8) {
+ default:
+ HDassert(0 && "This Should never be executed!");
+ break;
+ case 0:
+ do
+ {
+ DUFF_GUTS
+ case 7:
+ DUFF_GUTS
+ case 6:
+ DUFF_GUTS
+ case 5:
+ DUFF_GUTS
+ case 4:
+ DUFF_GUTS
+ case 3:
+ DUFF_GUTS
+ case 2:
+ DUFF_GUTS
+ case 1:
+ DUFF_GUTS
+ } while (--duffs_index > 0);
+ } /* end switch */
+ }
+#endif /* NO_DUFFS_DEVICE */
+#undef DUFF_GUTS
+ } /* end for */
+
+ /* Add leftover to the end of data */
+ if(leftover>0) {
+ /* Adjust back to end of shuffled bytes */
+ _dest -= (bytesoftype - 1); /*lint !e794 _dest is initialized */
+ HDmemcpy((void*)_dest, (void*)_src, leftover);
+ }
+ } /* end if */
+ else {
+ /* Get the pointer to the destination buffer */
+ _dest =(unsigned char *)dest;
+
+ /* Output; shuffle */
+ for(i=0; i<bytesoftype; i++) {
+ _src=((unsigned char *)(*buf))+i;
+#define DUFF_GUTS \
+ *_dest++=*_src; \
+ _src+=bytesoftype;
+#ifdef NO_DUFFS_DEVICE
+ j = numofelements;
+ while(j > 0) {
+ DUFF_GUTS;
+
+ j--;
+ } /* end for */
+#else /* NO_DUFFS_DEVICE */
+ {
+ size_t duffs_index; /* Counting index for Duff's device */
+
+ duffs_index = (numofelements + 7) / 8;
+ switch (numofelements % 8) {
+ default:
+ HDassert(0 && "This Should never be executed!");
+ break;
+ case 0:
+ do
+ {
+ DUFF_GUTS
+ case 7:
+ DUFF_GUTS
+ case 6:
+ DUFF_GUTS
+ case 5:
+ DUFF_GUTS
+ case 4:
+ DUFF_GUTS
+ case 3:
+ DUFF_GUTS
+ case 2:
+ DUFF_GUTS
+ case 1:
+ DUFF_GUTS
+ } while (--duffs_index > 0);
+ } /* end switch */
+ }
+#endif /* NO_DUFFS_DEVICE */
+#undef DUFF_GUTS
+ } /* end for */
+
+ /* Add leftover to the end of data */
+ if(leftover>0) {
+ /* Adjust back to end of shuffled bytes */
+ _src -= (bytesoftype - 1); /*lint !e794 _src is initialized */
+ HDmemcpy((void*)_dest, (void*)_src, leftover);
+ }
+ } /* end else */
+
+ /* Free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set the buffer information to return */
+ *buf = dest;
+ *buf_size=nbytes;
+ } /* end else */
+
+ /* Set the return value */
+ ret_value = nbytes;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
diff --git a/src/H5Zszip.c b/src/H5Zszip.c
new file mode 100644
index 0000000..dd35859
--- /dev/null
+++ b/src/H5Zszip.c
@@ -0,0 +1,371 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Oprivate.h" /* Object headers */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5Sprivate.h" /* Dataspaces */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5Zpkg.h" /* Data filters */
+
+#ifdef H5_HAVE_FILTER_SZIP
+
+#ifdef H5_HAVE_SZLIB_H
+# include "szlib.h"
+#endif
+
+/* Local function prototypes */
+static htri_t H5Z_can_apply_szip(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static herr_t H5Z_set_local_szip(hid_t dcpl_id, hid_t type_id, hid_t space_id);
+static size_t H5Z_filter_szip (unsigned flags, size_t cd_nelmts,
+ const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf);
+
+/* This message derives from H5Z */
+H5Z_class2_t H5Z_SZIP[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ H5Z_FILTER_SZIP, /* Filter id number */
+ 1, /* Assume encoder present: check before registering */
+ 1, /* decoder_present flag (set to true) */
+ "szip", /* Filter name for debugging */
+ H5Z_can_apply_szip, /* The "can apply" callback */
+ H5Z_set_local_szip, /* The "set local" callback */
+ H5Z_filter_szip, /* The actual filter function */
+}};
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_can_apply_szip
+ *
+ * Purpose: Check the parameters for szip compression for validity and
+ * whether they fit a particular dataset.
+ *
+ * Note: This function currently range-checks for datatypes with
+ * 8-bit boundaries (8, 16, 24, etc.). It appears that the szip
+ * library can actually handle 1-24, 32 & 64 bit samples. If
+ * this becomes important, we should make the checks below more
+ * sophisticated and have them check for n-bit datatypes of the
+ * correct size, etc. - QAK
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5Z_can_apply_szip(hid_t H5_ATTR_UNUSED dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id)
+{
+ const H5T_t *type; /* Datatype */
+ unsigned dtype_size; /* Datatype's size (in bits) */
+ H5T_order_t dtype_order; /* Datatype's endianness order */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get datatype */
+ if(NULL == (type = H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get datatype's size, for checking the "bits-per-pixel" */
+ if((dtype_size = (8 * H5T_get_size(type))) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")
+
+ /* Range check datatype's size */
+ if(dtype_size > 32 && dtype_size != 64)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FALSE, "invalid datatype size")
+
+ /* Get datatype's endianness order */
+ if((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "can't retrieve datatype endianness order")
+
+ /* Range check datatype's endianness order */
+ /* (Note: this may not handle non-atomic datatypes well) */
+ if(dtype_order != H5T_ORDER_LE && dtype_order != H5T_ORDER_BE)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FALSE, "invalid datatype endianness order")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_can_apply_szip() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_set_local_szip
+ *
+ * Purpose: Set the "local" dataset parameters for szip compression.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Monday, April 7, 2003
+ *
+ * Modifications: Used new logic to set the size of the scanline parameter.
+ * Now SZIP compression can be applied to the chunk
+ * of any shape and size with only one restriction: the number
+ * of elements in the chunk has to be not less than number
+ * of elements (pixels) in the block (cd_values[H5Z_SZIP_PARM_PPB]
+ * parameter).
+ * Elena Pourmal, July 20, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_set_local_szip(hid_t dcpl_id, hid_t type_id, hid_t space_id)
+{
+ H5P_genplist_t *dcpl_plist; /* Property list pointer */
+ const H5T_t *type; /* Datatype */
+ const H5S_t *ds; /* Dataspace */
+ unsigned flags; /* Filter flags */
+ size_t cd_nelmts = H5Z_SZIP_USER_NPARMS; /* Number of filter parameters */
+ unsigned cd_values[H5Z_SZIP_TOTAL_NPARMS]; /* Filter parameters */
+ hsize_t dims[H5O_LAYOUT_NDIMS]; /* Dataspace (i.e. chunk) dimensions */
+ int ndims; /* Number of (chunk) dimensions */
+ H5T_order_t dtype_order; /* Datatype's endianness order */
+ size_t dtype_size; /* Datatype's size (in bits) */
+ size_t dtype_precision; /* Datatype's precision (in bits) */
+ size_t dtype_offset; /* Datatype's offset (in bits) */
+ hsize_t scanline; /* Size of dataspace's fastest changing dimension */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get the plist structure */
+ if(NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get datatype */
+ if(NULL == (type = H5I_object_verify(type_id, H5I_DATATYPE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
+
+ /* Get the filter's current parameters */
+ if(H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SZIP, &flags, &cd_nelmts, cd_values, 0, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get szip parameters")
+
+ /* Get datatype's size, for checking the "bits-per-pixel" */
+ if((dtype_size = (8 * H5T_get_size(type))) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size");
+
+ /* Get datatype's precision, in case is less than full bits */
+ if((dtype_precision = H5T_get_precision(type)) == 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype precision");
+
+ if(dtype_precision < dtype_size) {
+ dtype_offset = H5T_get_offset(type);
+ if(dtype_offset != 0)
+ dtype_precision = dtype_size;
+ } /* end if */
+ if(dtype_precision > 24) {
+ if(dtype_precision <= 32)
+ dtype_precision = 32;
+ else if(dtype_precision <= 64)
+ dtype_precision = 64;
+ } /* end if */
+
+ /* Set "local" parameter for this dataset's "bits-per-pixel" */
+ cd_values[H5Z_SZIP_PARM_BPP] = dtype_precision;
+
+ /* Get dataspace */
+ if(NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space")
+
+ /* Get dimensions for dataspace */
+ if((ndims = H5S_get_simple_extent_dims(ds, dims, NULL)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get dataspace dimensions")
+
+ /* Set "local" parameter for this dataset's "pixels-per-scanline" */
+ /* (Use the chunk's fastest changing dimension size) */
+ HDassert(ndims > 0);
+ scanline = dims[ndims - 1];
+
+ /* Adjust scanline if it is smaller than number of pixels per block or
+ if it is bigger than maximum pixels per scanline, or there are more than
+ SZ_MAX_BLOCKS_PER_SCANLINE blocks per scanline */
+
+ /* Check the pixels per block against the 'scanline' size */
+ if(scanline < cd_values[H5Z_SZIP_PARM_PPB]) {
+ hssize_t npoints; /* Number of points in the dataspace */
+
+ /* Get number of elements for the dataspace; use
+ total number of elements in the chunk to define the new 'scanline' size */
+ if((npoints = H5S_GET_EXTENT_NPOINTS(ds)) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get number of points in the dataspace")
+ if(npoints < cd_values[H5Z_SZIP_PARM_PPB])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "pixels per block greater than total number of elements in the chunk")
+ scanline = MIN((cd_values[H5Z_SZIP_PARM_PPB] * SZ_MAX_BLOCKS_PER_SCANLINE), npoints);
+ }
+ else {
+ if(scanline <= SZ_MAX_PIXELS_PER_SCANLINE)
+ scanline = MIN((cd_values[H5Z_SZIP_PARM_PPB] * SZ_MAX_BLOCKS_PER_SCANLINE), scanline);
+ else
+ scanline = cd_values[H5Z_SZIP_PARM_PPB] * SZ_MAX_BLOCKS_PER_SCANLINE;
+ } /* end else */
+
+ /* Assign the final value to the scanline */
+ H5_CHECKED_ASSIGN(cd_values[H5Z_SZIP_PARM_PPS], unsigned, scanline, hsize_t);
+
+ /* Get datatype's endianness order */
+ if((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+
+ /* Set the correct endianness flag for szip */
+ /* (Note: this may not handle non-atomic datatypes well) */
+ cd_values[H5Z_SZIP_PARM_MASK] &= ~(SZ_LSB_OPTION_MASK|SZ_MSB_OPTION_MASK);
+ switch(dtype_order) {
+ case H5T_ORDER_LE: /* Little-endian byte order */
+ cd_values[H5Z_SZIP_PARM_MASK] |= SZ_LSB_OPTION_MASK;
+ break;
+
+ case H5T_ORDER_BE: /* Big-endian byte order */
+ cd_values[H5Z_SZIP_PARM_MASK] |= SZ_MSB_OPTION_MASK;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
+ } /* end switch */
+
+ /* Modify the filter's parameters for this dataset */
+ if(H5P_modify_filter(dcpl_plist, H5Z_FILTER_SZIP, flags, H5Z_SZIP_TOTAL_NPARMS, cd_values) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local szip parameters")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_set_local_szip() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_filter_szip
+ *
+ * Purpose: Implement an I/O filter around the 'rice' algorithm in
+ * libsz
+ *
+ * Return: Success: Size of buffer filtered
+ * Failure: 0
+ *
+ * Programmer: Kent Yang
+ * Tuesday, April 1, 2003
+ *
+ * Modifications:
+ * Quincey Koziol, April 2, 2003
+ * Cleaned up code.
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5Z_filter_szip (unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
+ size_t nbytes, size_t *buf_size, void **buf)
+{
+ size_t ret_value = 0; /* Return value */
+ size_t size_out = 0; /* Size of output buffer */
+ unsigned char *outbuf = NULL; /* Pointer to new output buffer */
+ unsigned char *newbuf = NULL; /* Pointer to input buffer */
+ SZ_com_t sz_param; /* szip parameter block */
+
+ FUNC_ENTER_NOAPI(0)
+
+ /* Sanity check to make certain that we haven't drifted out of date with
+ * the mask options from the szlib.h header */
+ HDassert(H5_SZIP_ALLOW_K13_OPTION_MASK==SZ_ALLOW_K13_OPTION_MASK);
+ HDassert(H5_SZIP_CHIP_OPTION_MASK==SZ_CHIP_OPTION_MASK);
+ HDassert(H5_SZIP_EC_OPTION_MASK==SZ_EC_OPTION_MASK);
+ HDassert(H5_SZIP_LSB_OPTION_MASK==SZ_LSB_OPTION_MASK);
+ HDassert(H5_SZIP_MSB_OPTION_MASK==SZ_MSB_OPTION_MASK);
+ HDassert(H5_SZIP_NN_OPTION_MASK==SZ_NN_OPTION_MASK);
+ HDassert(H5_SZIP_RAW_OPTION_MASK==SZ_RAW_OPTION_MASK);
+
+ /* Check arguments */
+ if (cd_nelmts!=4)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid number of filter parameters")
+
+ /* Copy the filter parameters into the szip parameter block */
+ H5_CHECKED_ASSIGN(sz_param.options_mask, int, cd_values[H5Z_SZIP_PARM_MASK], unsigned);
+ H5_CHECKED_ASSIGN(sz_param.bits_per_pixel, int, cd_values[H5Z_SZIP_PARM_BPP], unsigned);
+ H5_CHECKED_ASSIGN(sz_param.pixels_per_block, int, cd_values[H5Z_SZIP_PARM_PPB], unsigned);
+ H5_CHECKED_ASSIGN(sz_param.pixels_per_scanline, int, cd_values[H5Z_SZIP_PARM_PPS], unsigned);
+
+ /* Input; uncompress */
+ if (flags & H5Z_FLAG_REVERSE) {
+ uint32_t stored_nalloc; /* Number of bytes the compressed block will expand into */
+ size_t nalloc; /* Number of bytes the compressed block will expand into */
+
+ /* Get the size of the uncompressed buffer */
+ newbuf = *buf;
+ UINT32DECODE(newbuf,stored_nalloc);
+ H5_CHECKED_ASSIGN(nalloc, size_t, stored_nalloc, uint32_t);
+
+ /* Allocate space for the uncompressed buffer */
+ if(NULL==(outbuf = H5MM_malloc(nalloc)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for szip decompression")
+
+ /* Decompress the buffer */
+ size_out=nalloc;
+ if(SZ_BufftoBuffDecompress(outbuf, &size_out, newbuf, nbytes-4, &sz_param) != SZ_OK)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "szip_filter: decompression failed")
+ HDassert(size_out==nalloc);
+
+ /* Free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set return values */
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = nalloc;
+ ret_value = size_out;
+ }
+ /* Output; compress */
+ else {
+ unsigned char *dst = NULL; /* Temporary pointer to new output buffer */
+
+ /* Allocate space for the compressed buffer & header (assume data won't get bigger) */
+ if(NULL==(dst=outbuf = H5MM_malloc(nbytes+4)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "unable to allocate szip destination buffer")
+
+ /* Encode the uncompressed length */
+ H5_CHECK_OVERFLOW(nbytes,size_t,uint32_t);
+ UINT32ENCODE(dst,nbytes);
+
+ /* Compress the buffer */
+ size_out = nbytes;
+ if(SZ_OK!= SZ_BufftoBuffCompress(dst, &size_out, *buf, nbytes, &sz_param))
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "overflow")
+ HDassert(size_out<=nbytes);
+
+ /* Free the input buffer */
+ H5MM_xfree(*buf);
+
+ /* Set return values */
+ *buf = outbuf;
+ outbuf = NULL;
+ *buf_size = nbytes+4;
+ ret_value = size_out+4;
+ }
+
+done:
+ if(outbuf)
+ H5MM_xfree(outbuf);
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+#endif /* H5_HAVE_FILTER_SZIP */
+
diff --git a/src/H5Ztrans.c b/src/H5Ztrans.c
new file mode 100644
index 0000000..d4b59a6
--- /dev/null
+++ b/src/H5Ztrans.c
@@ -0,0 +1,1796 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5VMprivate.h" /* H5VM_array_fill */
+#include "H5Zpkg.h" /* Data filters */
+
+
+/* Token types */
+typedef enum {
+ H5Z_XFORM_ERROR,
+ H5Z_XFORM_INTEGER, /* this represents an integer type in the data transform expression */
+ H5Z_XFORM_FLOAT, /* this represents a floating point type in the data transform expression */
+ H5Z_XFORM_SYMBOL,
+ H5Z_XFORM_PLUS,
+ H5Z_XFORM_MINUS,
+ H5Z_XFORM_MULT,
+ H5Z_XFORM_DIVIDE,
+ H5Z_XFORM_LPAREN,
+ H5Z_XFORM_RPAREN,
+ H5Z_XFORM_END
+} H5Z_token_type;
+
+
+typedef struct {
+ unsigned int num_ptrs;
+ void** ptr_dat_val;
+} H5Z_datval_ptrs;
+
+
+/* Used to represent values in transform expression */
+typedef union {
+ void *dat_val;
+ long int_val;
+ double float_val;
+} H5Z_num_val;
+
+typedef struct H5Z_node {
+ struct H5Z_node *lchild;
+ struct H5Z_node *rchild;
+ H5Z_token_type type;
+ H5Z_num_val value;
+} H5Z_node;
+
+struct H5Z_data_xform_t {
+ char* xform_exp;
+ H5Z_node* parse_root;
+ H5Z_datval_ptrs* dat_val_pointers;
+};
+
+typedef struct result {
+ H5Z_token_type type;
+ H5Z_num_val value;
+} H5Z_result;
+
+
+/* The token */
+typedef struct {
+ const char *tok_expr; /* Holds the original expression */
+
+ /* Current token values */
+ H5Z_token_type tok_type; /* The type of the current token */
+ const char *tok_begin; /* The beginning of the current token */
+ const char *tok_end; /* The end of the current token */
+
+ /* Previous token values */
+ H5Z_token_type tok_last_type; /* The type of the last token */
+ const char *tok_last_begin; /* The beginning of the last token */
+ const char *tok_last_end; /* The end of the last token */
+} H5Z_token;
+
+/* Local function prototypes */
+static H5Z_token *H5Z_get_token(H5Z_token *current);
+static H5Z_node *H5Z_parse_expression(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers);
+static H5Z_node *H5Z_parse_term(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers);
+static H5Z_node *H5Z_parse_factor(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers);
+static H5Z_node *H5Z_new_node(H5Z_token_type type);
+static void H5Z_do_op(H5Z_node* tree);
+static hbool_t H5Z_op_is_numbs(H5Z_node* _tree);
+static hbool_t H5Z_op_is_numbs2(H5Z_node* _tree);
+static hid_t H5Z_xform_find_type(const H5T_t* type);
+static herr_t H5Z_xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result* res);
+static void H5Z_xform_destroy_parse_tree(H5Z_node *tree);
+static void* H5Z_xform_parse(const char *expression, H5Z_datval_ptrs* dat_val_pointers);
+static void* H5Z_xform_copy_tree(H5Z_node* tree, H5Z_datval_ptrs* dat_val_pointers, H5Z_datval_ptrs* new_dat_val_pointers);
+static void H5Z_xform_reduce_tree(H5Z_node* tree);
+#ifdef H5Z_XFORM_DEBUG
+static void H5Z_XFORM_DEBUG(H5Z_node *tree);
+static void H5Z_print(H5Z_node *tree, FILE *stream);
+#endif /* H5Z_XFORM_DEBUG */
+
+/* PGCC (11.8-0) has trouble with the command *p++ = *p OP tree_val. It increments P first before
+ * doing the operation. So I break down the command into two lines:
+ * *p = *p OP tree_val; p++;
+ * Actually, the behavior of *p++ = *p OP tree_val is undefined. (SLU - 2012/3/19)
+ */
+#define H5Z_XFORM_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \
+{ \
+ size_t u; \
+ \
+ if(((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type != H5Z_XFORM_SYMBOL)) \
+ { \
+ TYPE* p; \
+ double tree_val; \
+ \
+ tree_val = ((RESR).type==H5Z_XFORM_INTEGER ? (double)(RESR).value.int_val : (RESR).value.float_val); \
+ p = (TYPE*)(RESL).value.dat_val; \
+ \
+ for(u = 0; u < (SIZE); u++) { \
+ *p = (TYPE)((double)*p OP tree_val); \
+ p++; \
+ } \
+ } \
+ else if(((RESR).type == H5Z_XFORM_SYMBOL) && ((RESL).type != H5Z_XFORM_SYMBOL)) \
+ { \
+ TYPE* p; \
+ double tree_val; \
+ \
+ /* The case that the left operand is nothing, like -x or +x */ \
+ if((RESL).type == H5Z_XFORM_ERROR) \
+ tree_val = 0; \
+ else \
+ tree_val = ((RESL).type==H5Z_XFORM_INTEGER ? (double)(RESL).value.int_val : (RESL).value.float_val); \
+ \
+ p = (TYPE*)(RESR).value.dat_val; \
+ for(u = 0; u < (SIZE); u++) { \
+ *p = (TYPE)(tree_val OP (double)*p); \
+ p++; \
+ } \
+ } \
+ else if( ((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type == H5Z_XFORM_SYMBOL)) \
+ { \
+ TYPE* pl = (TYPE*)(RESL).value.dat_val; \
+ TYPE* pr = (TYPE*)(RESR).value.dat_val; \
+ \
+ for(u = 0; u < (SIZE); u++) { \
+ *pl = (TYPE)(*pl OP *pr); \
+ pl++; pr++; \
+ } \
+ } \
+ else \
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unexpected type conversion operation") \
+}
+
+#if H5_SIZEOF_LONG_DOUBLE != 0
+#if CHAR_MIN >= 0
+#define H5Z_XFORM_TYPE_OP(RESL,RESR,TYPE,OP,SIZE) \
+{ \
+ if((TYPE) == H5T_NATIVE_CHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SCHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), signed char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_USHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_INT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UINT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_FLOAT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_DOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LDOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE)) \
+}
+#else /* CHAR_MIN >= 0 */
+#define H5Z_XFORM_TYPE_OP(RESL,RESR,TYPE,OP,SIZE) \
+{ \
+ if((TYPE) == H5T_NATIVE_CHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UCHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_USHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_INT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UINT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_FLOAT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_DOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LDOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE)) \
+}
+#endif /* CHAR_MIN >= 0 */
+#else
+#if CHAR_MIN >= 0
+#define H5Z_XFORM_TYPE_OP(RESL,RESR,TYPE,OP,SIZE) \
+{ \
+ if((TYPE) == H5T_NATIVE_CHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SCHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), signed char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_USHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_INT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UINT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_FLOAT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_DOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
+}
+#else /* CHAR_MIN >= 0 */
+#define H5Z_XFORM_TYPE_OP(RESL,RESR,TYPE,OP,SIZE) \
+{ \
+ if((TYPE) == H5T_NATIVE_CHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UCHAR) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned char, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_SHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_USHORT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_INT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_UINT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_LLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_ULLONG) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_FLOAT) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
+ else if((TYPE) == H5T_NATIVE_DOUBLE) \
+ H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
+}
+#endif /* CHAR_MIN >= 0 */
+#endif /*H5_SIZEOF_LONG_DOUBLE */
+
+#define H5Z_XFORM_DO_OP3(OP) \
+{ \
+ if((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type==H5Z_XFORM_INTEGER)) \
+ { \
+ tree->type = H5Z_XFORM_INTEGER; \
+ tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val; \
+ H5MM_xfree(tree->lchild); \
+ H5MM_xfree(tree->rchild); \
+ tree->lchild = NULL; \
+ tree->rchild = NULL; \
+ } \
+ else if( ( (tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) && \
+ ( (tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) \
+ { \
+ tree->type = H5Z_XFORM_FLOAT; \
+ tree->value.float_val = ((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val : (double)tree->lchild->value.int_val) OP \
+ ((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val : (double)tree->rchild->value.int_val); \
+ H5MM_xfree(tree->lchild); \
+ H5MM_xfree(tree->rchild); \
+ tree->lchild = NULL; \
+ tree->rchild = NULL; \
+ } \
+}
+
+#define H5Z_XFORM_DO_OP4(TYPE) \
+{ \
+ if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL) \
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") \
+ else \
+ { \
+ ret_value->type = (TYPE); \
+ if(tree->lchild) \
+ ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild, dat_val_pointers, new_dat_val_pointers); \
+ else \
+ ret_value->lchild = NULL; \
+ if(tree->rchild) \
+ ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild, dat_val_pointers, new_dat_val_pointers); \
+ else \
+ ret_value->rchild = NULL; \
+ } \
+}
+
+#define H5Z_XFORM_DO_OP5(TYPE, SIZE) \
+{ \
+ TYPE val = ((tree->type == H5Z_XFORM_INTEGER) ? (TYPE)tree->value.int_val : (TYPE)tree->value.float_val); \
+ H5VM_array_fill(array, &val, sizeof(TYPE), (SIZE)); \
+}
+
+/* The difference of this macro from H5Z_XFORM_DO_OP3 is that it handles the operations when the left operand is empty, like -x or +x.
+ * The reason that it's seperated from H5Z_XFORM_DO_OP3 is because compilers don't accept operations like *x or /x. So in H5Z_do_op,
+ * these two macros are called in different ways. (SLU 2012/3/20)
+ */
+#define H5Z_XFORM_DO_OP6(OP) \
+{ \
+ if(!tree->lchild && (tree->rchild->type==H5Z_XFORM_INTEGER)) \
+ { \
+ tree->type = H5Z_XFORM_INTEGER; \
+ tree->value.int_val = OP tree->rchild->value.int_val; \
+ H5MM_xfree(tree->rchild); \
+ tree->rchild = NULL; \
+ } \
+ else if(!tree->lchild && (tree->rchild->type==H5Z_XFORM_FLOAT)) \
+ { \
+ tree->type = H5Z_XFORM_FLOAT; \
+ tree->value.float_val = OP tree->rchild->value.float_val; \
+ H5MM_xfree(tree->rchild); \
+ tree->rchild = NULL; \
+ } \
+ else if((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type==H5Z_XFORM_INTEGER)) \
+ { \
+ tree->type = H5Z_XFORM_INTEGER; \
+ tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val; \
+ H5MM_xfree(tree->lchild); \
+ H5MM_xfree(tree->rchild); \
+ tree->lchild = NULL; \
+ tree->rchild = NULL; \
+ } \
+ else if( ( (tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) && \
+ ( (tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) \
+ { \
+ tree->type = H5Z_XFORM_FLOAT; \
+ tree->value.float_val = ((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val : (double)tree->lchild->value.int_val) OP \
+ ((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val : (double)tree->rchild->value.int_val); \
+ H5MM_xfree(tree->lchild); \
+ H5MM_xfree(tree->rchild); \
+ tree->lchild = NULL; \
+ tree->rchild = NULL; \
+ } \
+}
+
+/*
+ * Programmer: Bill Wendling <wendling@ncsa.uiuc.edu>
+ * 25. August 2003
+ */
+
+/*
+ * This is the context-free grammar for our expressions:
+ *
+ * expr := term | term '+ term | term '-' term
+ * term := factor | factor '*' factor | factor '/' factor
+ * factor := number |
+ * symbol |
+ * '-' factor | // unary minus
+ * '+' factor | // unary plus
+ * '(' expr ')'
+ * symbol := [a-zA-Z][a-zA-Z0-9]*
+ * number := H5Z_XFORM_INTEGER | FLOAT
+ * // H5Z_XFORM_INTEGER is a C long int
+ * // FLOAT is a C double
+ */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_unget_token
+ * Purpose: Rollback the H5Z_token to the previous H5Z_token retrieved. There
+ * should only need to be one level of rollback necessary
+ * for our grammar.
+ * Return: Always succeeds.
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+*
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_unget_token(H5Z_token *current)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* check args */
+ HDassert(current);
+
+ current->tok_type = current->tok_last_type;
+ current->tok_begin = current->tok_last_begin;
+ current->tok_end = current->tok_last_end;
+
+ FUNC_LEAVE_NOAPI_VOID
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_get_token
+ *
+ * Purpose: Determine what the next valid H5Z_token is in the expression
+ * string. The current position within the H5Z_token string is
+ * kept internal to the H5Z_token and handled by this and the
+ * unget_H5Z_token function.
+ *
+ * Return: Succeess: The passed in H5Z_token with a valid tok_type
+ * field.
+ * Failure: The passed in H5Z_token but with the tok_type
+ * field set to ERROR.
+ *
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5Z_token *
+H5Z_get_token(H5Z_token *current)
+{
+ H5Z_token *ret_value = current;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(current);
+
+ /* Save the last position for possible ungets */
+ current->tok_last_type = current->tok_type;
+ current->tok_last_begin = current->tok_begin;
+ current->tok_last_end = current->tok_end;
+
+ current->tok_begin = current->tok_end;
+
+ while (current->tok_begin[0] != '\0') {
+ if (HDisspace(current->tok_begin[0])) {
+ /* ignore whitespace */
+ } else if (HDisdigit(current->tok_begin[0]) ||
+ current->tok_begin[0] == '.') {
+ current->tok_end = current->tok_begin;
+
+ /*
+ * H5Z_XFORM_INTEGER := digit-sequence
+ * digit-sequence := digit | digit digit-sequence
+ * digit := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+ */
+ if (current->tok_end[0] != '.') {
+ /* is number */
+ current->tok_type = H5Z_XFORM_INTEGER;
+
+ while (HDisdigit(current->tok_end[0]))
+ ++current->tok_end;
+ }
+
+ /*
+ * float := digit-sequence exponent |
+ * dotted-digits exponent?
+ * dotted-digits := digit-sequence '.' digit-sequence? |
+ * '.' digit-sequence
+ * exponent := [Ee] [-+]? digit-sequence
+ */
+ if (current->tok_end[0] == '.' ||
+ current->tok_end[0] == 'e' ||
+ current->tok_end[0] == 'E') {
+ current->tok_type = H5Z_XFORM_FLOAT;
+
+ if (current->tok_end[0] == '.')
+ do {
+ ++current->tok_end;
+ } while (HDisdigit(current->tok_end[0]));
+
+ if (current->tok_end[0] == 'e' ||
+ current->tok_end[0] == 'E') {
+ ++current->tok_end;
+
+ if (current->tok_end[0] == '-' ||
+ current->tok_end[0] == '+')
+ ++current->tok_end;
+
+ if (!HDisdigit(current->tok_end[0])) {
+ current->tok_type = H5Z_XFORM_ERROR;
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number")
+ }
+
+ while (HDisdigit(current->tok_end[0]))
+ ++current->tok_end;
+ }
+
+ /* Check that this is a properly formatted numerical value */
+ if (HDisalpha(current->tok_end[0]) || current->tok_end[0] == '.') {
+ current->tok_type = H5Z_XFORM_ERROR;
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number")
+ }
+ }
+
+ break;
+ } else if (HDisalpha(current->tok_begin[0])) {
+ /* is symbol */
+ current->tok_type = H5Z_XFORM_SYMBOL;
+ current->tok_end = current->tok_begin;
+
+ while (HDisalnum(current->tok_end[0]))
+ ++current->tok_end;
+
+ break;
+ } else {
+ /* should be +, -, *, /, (, or ) */
+ switch (current->tok_begin[0]) {
+ case '+': current->tok_type = H5Z_XFORM_PLUS; break;
+ case '-': current->tok_type = H5Z_XFORM_MINUS; break;
+ case '*': current->tok_type = H5Z_XFORM_MULT; break;
+ case '/': current->tok_type = H5Z_XFORM_DIVIDE; break;
+ case '(': current->tok_type = H5Z_XFORM_LPAREN; break;
+ case ')': current->tok_type = H5Z_XFORM_RPAREN; break;
+ default:
+ current->tok_type = H5Z_XFORM_ERROR;
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Unknown H5Z_token in data transform expression ")
+ }
+
+ current->tok_end = current->tok_begin + 1;
+ break;
+ }
+
+ ++current->tok_begin;
+ }
+
+ if (current->tok_begin[0] == '\0')
+ current->tok_type = H5Z_XFORM_END;
+
+ /* Set return value */
+ ret_value = current;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_destroy_parse_tree
+ * Purpose: Recursively destroys the expression tree.
+ * Return: Nothing
+ * Programmer: Bill Wendling
+ * 25. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_xform_destroy_parse_tree(H5Z_node *tree)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (tree)
+ {
+ H5Z_xform_destroy_parse_tree(tree->lchild);
+ H5Z_xform_destroy_parse_tree(tree->rchild);
+ H5MM_xfree(tree);
+ tree = NULL;
+ }
+
+ FUNC_LEAVE_NOAPI_VOID
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_parse
+ *
+ * Purpose: Entry function for parsing the expression string.
+ *
+ * Return: Success: Valid H5Z_node ptr to an expression tree.
+ * NULLure: NULL
+ *
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5Z_xform_parse(const char *expression, H5Z_datval_ptrs* dat_val_pointers)
+{
+ H5Z_token tok;
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if(!expression)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "No expression provided?")
+
+ /* Set up the initial H5Z_token for parsing */
+ tok.tok_expr = tok.tok_begin = tok.tok_end = expression;
+
+ ret_value = (void*)H5Z_parse_expression(&tok, dat_val_pointers);
+
+ H5Z_xform_reduce_tree((H5Z_node*)ret_value);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_parse_expression
+ * Purpose: Beginning of the recursive descent parser to parse the
+ * expression. An expression is:
+ *
+ * expr := term | term '+' term | term '-' term
+ *
+ * Return: Success: Valid H5Z_node ptr to expression tree
+ * NULLure: NULL
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+*
+ *-------------------------------------------------------------------------
+ */
+static H5Z_node *
+H5Z_parse_expression(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers)
+{
+ H5Z_node *expr;
+ H5Z_node *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ expr = H5Z_parse_term(current, dat_val_pointers);
+
+ for (;;) {
+ H5Z_node *new_node;
+
+ current = H5Z_get_token(current);
+
+ switch(current->tok_type) {
+ case H5Z_XFORM_PLUS:
+ new_node = H5Z_new_node(H5Z_XFORM_PLUS);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(expr);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ }
+
+ new_node->lchild = expr;
+ new_node->rchild = H5Z_parse_term(current, dat_val_pointers);
+
+ if (!new_node->rchild) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ expr = new_node;
+ break;
+
+ case H5Z_XFORM_MINUS:
+ new_node = H5Z_new_node(H5Z_XFORM_MINUS);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(expr);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ }
+
+ new_node->lchild = expr;
+ new_node->rchild = H5Z_parse_term(current, dat_val_pointers);
+
+ if (!new_node->rchild) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ expr = new_node;
+ break;
+
+ case H5Z_XFORM_RPAREN:
+ H5Z_unget_token(current);
+ HGOTO_DONE(expr)
+
+ case H5Z_XFORM_END:
+ HGOTO_DONE(expr)
+
+ case H5Z_XFORM_ERROR:
+ case H5Z_XFORM_INTEGER:
+ case H5Z_XFORM_FLOAT:
+ case H5Z_XFORM_SYMBOL:
+ case H5Z_XFORM_MULT:
+ case H5Z_XFORM_DIVIDE:
+ case H5Z_XFORM_LPAREN:
+ default:
+ H5Z_xform_destroy_parse_tree(expr);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_parse_term
+ * Purpose: Parses a term in our expression language. A term is:
+ *
+ * term := factor | factor '*' factor | factor '/' factor
+ *
+ * Return: Success: Valid H5Z_node ptr to expression tree
+ * NULLure: NULL
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+*
+ *-------------------------------------------------------------------------
+ */
+static H5Z_node *
+H5Z_parse_term(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers)
+{
+ H5Z_node *term = NULL;
+ H5Z_node *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ term = H5Z_parse_factor(current, dat_val_pointers);
+
+ for (;;) {
+ H5Z_node *new_node;
+
+ current = H5Z_get_token(current);
+
+ switch (current->tok_type) {
+ case H5Z_XFORM_MULT:
+ new_node = H5Z_new_node(H5Z_XFORM_MULT);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(term);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ }
+
+ new_node->lchild = term;
+ new_node->rchild = H5Z_parse_factor(current, dat_val_pointers);
+
+ if (!new_node->rchild) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ term = new_node;
+ break;
+
+ case H5Z_XFORM_DIVIDE:
+ new_node = H5Z_new_node(H5Z_XFORM_DIVIDE);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(term);
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ }
+
+ new_node->lchild = term;
+ new_node->rchild = H5Z_parse_factor(current, dat_val_pointers);
+ term = new_node;
+
+ if (!new_node->rchild) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+ break;
+
+ case H5Z_XFORM_RPAREN:
+ H5Z_unget_token(current);
+ HGOTO_DONE(term)
+
+ case H5Z_XFORM_END:
+ HGOTO_DONE(term)
+
+ case H5Z_XFORM_INTEGER:
+ case H5Z_XFORM_FLOAT:
+ case H5Z_XFORM_SYMBOL:
+ case H5Z_XFORM_PLUS:
+ case H5Z_XFORM_MINUS:
+ case H5Z_XFORM_LPAREN:
+ H5Z_unget_token(current);
+ HGOTO_DONE(term)
+
+ case H5Z_XFORM_ERROR:
+ default:
+ H5Z_xform_destroy_parse_tree(term);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "bad transform type passed to data transform expression")
+ } /* end switch */
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_parse_factor
+ * Purpose: Parses a factor in our expression language. A factor is:
+ *
+ * factor := number | // C long or double
+ * symbol | // C identifier
+ * '-' factor | // unary minus
+ * '+' factor | // unary plus
+ * '(' expr ')'
+ *
+ * Return: Success: Valid H5Z_node ptr to expression tree
+ * NULLure: NULL
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5Z_node *
+H5Z_parse_factor(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers)
+{
+ H5Z_node *factor=NULL;
+ H5Z_node *new_node;
+ H5Z_node *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ current = H5Z_get_token(current);
+
+ switch (current->tok_type) {
+ case H5Z_XFORM_INTEGER:
+ factor = H5Z_new_node(H5Z_XFORM_INTEGER);
+
+ if (!factor)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ sscanf(current->tok_begin, "%ld", &factor->value.int_val);
+ break;
+
+ case H5Z_XFORM_FLOAT:
+ factor = H5Z_new_node(H5Z_XFORM_FLOAT);
+
+ if (!factor)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+ sscanf(current->tok_begin, "%lf", &factor->value.float_val);
+ break;
+
+ case H5Z_XFORM_SYMBOL:
+ factor = H5Z_new_node(H5Z_XFORM_SYMBOL);
+
+ if (!factor)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+
+ factor->value.dat_val = &(dat_val_pointers->ptr_dat_val[dat_val_pointers->num_ptrs]);
+ dat_val_pointers->num_ptrs++;
+ break;
+
+ case H5Z_XFORM_LPAREN:
+ factor = H5Z_parse_expression(current, dat_val_pointers);
+
+ if (!factor)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
+
+ current = H5Z_get_token(current);
+
+ if (current->tok_type != H5Z_XFORM_RPAREN) {
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error in data transform expression")
+ }
+ break;
+
+ case H5Z_XFORM_RPAREN:
+ /* We shouldn't see a ) right now */
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error: unexpected ')' ")
+
+ case H5Z_XFORM_PLUS:
+ /* unary + */
+ new_node = H5Z_parse_factor(current, dat_val_pointers);
+
+ if (new_node) {
+ if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
+ new_node->type != H5Z_XFORM_SYMBOL) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ factor = new_node;
+ new_node = H5Z_new_node(H5Z_XFORM_PLUS);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ new_node->rchild = factor;
+ factor = new_node;
+ } else {
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+ break;
+
+ case H5Z_XFORM_MINUS:
+ /* unary - */
+ new_node = H5Z_parse_factor(current, dat_val_pointers);
+
+ if (new_node) {
+ if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
+ new_node->type != H5Z_XFORM_SYMBOL) {
+ H5Z_xform_destroy_parse_tree(new_node);
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ factor = new_node;
+ new_node = H5Z_new_node(H5Z_XFORM_MINUS);
+
+ if (!new_node) {
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+
+ new_node->rchild = factor;
+ factor = new_node;
+ } else {
+ H5Z_xform_destroy_parse_tree(factor);
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
+ }
+ break;
+
+ case H5Z_XFORM_END:
+ break;
+
+ case H5Z_XFORM_MULT:
+ case H5Z_XFORM_DIVIDE:
+ case H5Z_XFORM_ERROR:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Invalid token while parsing data transform expression")
+
+ }
+
+ /* Set return value */
+ ret_value=factor;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_new_node
+ * Purpose: Create and initilize a new H5Z_node structure.
+ * Return: Success: Valid H5Z_node ptr
+ * NULLure: NULL
+ * Programmer: Bill Wendling
+ * 26. August 2003
+ * Modifications:
+ * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5Z_node *
+H5Z_new_node(H5Z_token_type type)
+{
+ H5Z_node *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(NULL == (ret_value = (H5Z_node *)H5MM_calloc(sizeof(H5Z_node))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to allocate space for nodes in the parse tree")
+
+ ret_value->type = type;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_eval
+ * Purpose: If the transform is trivial, this function applies it.
+ * Otherwise, it calls H5Z_xform_eval_full to do the full
+ * transform.
+ * Return: SUCCEED if transform applied succesfully, FAIL otherwise
+ * Programmer: Leon Arber
+ * 5/1/04
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_xform_eval(H5Z_data_xform_t *data_xform_prop, void* array, size_t array_size, const H5T_t *buf_type)
+{
+ H5Z_node *tree;
+ hid_t array_type;
+ H5Z_result res;
+ size_t i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(data_xform_prop);
+
+ tree = data_xform_prop->parse_root;
+
+ /* Get the datatype ID for the buffer's type */
+ if((array_type = H5Z_xform_find_type(buf_type)) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot perform data transform on this type.")
+
+ /* After this point, we're assured that the type of the array is handled by the eval code,
+ * so we no longer have to check for valid types
+ */
+
+ /* If it's a trivial data transform, perform it */
+ if(tree->type == H5Z_XFORM_INTEGER || tree->type == H5Z_XFORM_FLOAT) {
+ if(array_type == H5T_NATIVE_CHAR)
+ H5Z_XFORM_DO_OP5(char, array_size)
+#if CHAR_MIN >= 0
+ else if(array_type == H5T_NATIVE_SCHAR)
+ H5Z_XFORM_DO_OP5(signed char, array_size)
+#else /* CHAR_MIN >= 0 */
+ else if(array_type == H5T_NATIVE_UCHAR)
+ H5Z_XFORM_DO_OP5(unsigned char, array_size)
+#endif /* CHAR_MIN >= 0 */
+ else if(array_type == H5T_NATIVE_SHORT)
+ H5Z_XFORM_DO_OP5(short, array_size)
+ else if(array_type == H5T_NATIVE_USHORT)
+ H5Z_XFORM_DO_OP5(unsigned short, array_size)
+ else if(array_type == H5T_NATIVE_INT)
+ H5Z_XFORM_DO_OP5(int, array_size)
+ else if(array_type == H5T_NATIVE_UINT)
+ H5Z_XFORM_DO_OP5(unsigned int, array_size)
+ else if(array_type == H5T_NATIVE_LONG)
+ H5Z_XFORM_DO_OP5(long, array_size)
+ else if(array_type == H5T_NATIVE_ULONG)
+ H5Z_XFORM_DO_OP5(unsigned long, array_size)
+ else if(array_type == H5T_NATIVE_LLONG)
+ H5Z_XFORM_DO_OP5(long long, array_size)
+ else if(array_type == H5T_NATIVE_ULLONG)
+ H5Z_XFORM_DO_OP5(unsigned long long, array_size)
+ else if(array_type == H5T_NATIVE_FLOAT)
+ H5Z_XFORM_DO_OP5(float, array_size)
+ else if(array_type == H5T_NATIVE_DOUBLE)
+ H5Z_XFORM_DO_OP5(double, array_size)
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ else if(array_type == H5T_NATIVE_LDOUBLE)
+ H5Z_XFORM_DO_OP5(long double, array_size)
+#endif
+
+ } /* end if */
+ /* Otherwise, do the full data transform */
+ else {
+ /* Optimization for linear transform: */
+ if(data_xform_prop->dat_val_pointers->num_ptrs == 1)
+ data_xform_prop->dat_val_pointers->ptr_dat_val[0] = array;
+
+ /* If it's a quadratic transform, we have no choice but to store multiple copies of the data */
+ else {
+ for(i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++) {
+ if(NULL == (data_xform_prop->dat_val_pointers->ptr_dat_val[i] = (void*)H5MM_malloc(array_size * H5T_get_size((H5T_t *)H5I_object(array_type)))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "Ran out of memory trying to allocate space for data in data transform")
+
+ HDmemcpy(data_xform_prop->dat_val_pointers->ptr_dat_val[i], array, array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
+ } /* end for */
+ } /* end else */
+
+ if(H5Z_xform_eval_full(tree, array_size, array_type, &res) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
+
+ if(data_xform_prop->dat_val_pointers->num_ptrs > 1)
+ HDmemcpy(array, res.value.dat_val, array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
+
+ /* Free the temporary arrays we used */
+ if(data_xform_prop->dat_val_pointers->num_ptrs > 1)
+ for(i=0; i<data_xform_prop->dat_val_pointers->num_ptrs; i++)
+ H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
+ } /* end else */
+
+done:
+ if(ret_value < 0) {
+ /* If we ran out of memory above copying the array for temp storage (which we easily can for
+ * polynomial transforms of high order) we free those arrays which we already allocated */
+ if(data_xform_prop->dat_val_pointers->num_ptrs > 1)
+ for(i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++)
+ if(data_xform_prop->dat_val_pointers->ptr_dat_val[i])
+ H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_xform_eval() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_eval_full
+ * Purpose: Does a full evaluation of the parse tree contained in tree
+ * and applies this transform to array.
+ * Return: Nothing
+ * Programmer: Leon Arber
+ * 5/1/04
+ * Modifications:
+ *
+ *
+ * Notes: In the case of a polynomial data transform (ie, the left and right subtree
+ * are both of type H5Z_XFORM_SYMBOL), the convention is that the left hand side
+ * will accumulate changes and, at the end, the new data will be copied from the lhs.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5Z_xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result *res)
+{
+ H5Z_result resl, resr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* check args */
+ HDassert(tree);
+
+ HDmemset(&resl, 0, sizeof(H5Z_result));
+ HDmemset(&resr, 0, sizeof(H5Z_result));
+
+ if (tree->type == H5Z_XFORM_INTEGER) {
+ res->type = H5Z_XFORM_INTEGER;
+ res->value.int_val = tree->value.int_val;
+ } /* end if */
+ else if (tree->type == H5Z_XFORM_FLOAT) {
+ res->type = H5Z_XFORM_FLOAT;
+ res->value.float_val = tree->value.float_val;
+ } /* end if */
+ else if (tree->type == H5Z_XFORM_SYMBOL) {
+ res->type = H5Z_XFORM_SYMBOL;
+
+ /*since dat_val stores the address of the array which is really stored in the dat_val_pointers,
+ * here we make dat_val store a pointer to the array itself instead of the address of it so that the
+ * rest of the code below works normally. */
+ res->value.dat_val = *((void**)(tree->value.dat_val));
+ } /* end if */
+ else {
+ if(tree->lchild && H5Z_xform_eval_full(tree->lchild, array_size, array_type, &resl) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
+ if(H5Z_xform_eval_full(tree->rchild, array_size, array_type, &resr) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
+
+ res->type = H5Z_XFORM_SYMBOL;
+
+ /* For each type of operation:
+ * 1. See if "x" is on left hand side, right hand side, or if both sides are "x"
+ * 2. Figure out what type of data we're going to be manipulating
+ * 3. Do the operation on the data. */
+ switch (tree->type) {
+ case H5Z_XFORM_PLUS:
+ H5Z_XFORM_TYPE_OP(resl, resr, array_type, +, array_size)
+ break;
+
+ case H5Z_XFORM_MINUS:
+ H5Z_XFORM_TYPE_OP(resl, resr, array_type, -, array_size)
+ break;
+
+ case H5Z_XFORM_MULT:
+ H5Z_XFORM_TYPE_OP(resl, resr, array_type, *, array_size)
+ break;
+
+ case H5Z_XFORM_DIVIDE:
+ H5Z_XFORM_TYPE_OP(resl, resr, array_type, /, array_size)
+ break;
+
+ case H5Z_XFORM_ERROR:
+ case H5Z_XFORM_INTEGER:
+ case H5Z_XFORM_FLOAT:
+ case H5Z_XFORM_SYMBOL:
+ case H5Z_XFORM_LPAREN:
+ case H5Z_XFORM_RPAREN:
+ case H5Z_XFORM_END:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid expression tree")
+ } /* end switch */
+
+ /* The result stores a pointer to the new data */
+ /* So, if the left hand side got its data modified, the result stores a pointers
+ * to the left hand side's data, ditto for rhs */
+ if(resl.type == H5Z_XFORM_SYMBOL)
+ res->value.dat_val = resl.value.dat_val;
+ else if(resr.type == H5Z_XFORM_SYMBOL)
+ res->value.dat_val = resr.value.dat_val;
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error during transform evaluation")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_xform_eval_full() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_find_type
+ * Return: Native type of datatype that is passed in
+ * Programmer: Leon Arber, 4/20/04
+ * Modifications:
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+static hid_t
+H5Z_xform_find_type(const H5T_t* type)
+{
+ H5T_t *tmp; /* Temporary datatype */
+ hid_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(type);
+
+ /* Check for SHORT type */
+ if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SHORT))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_SHORT)
+ /* Check for INT type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_INT))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_INT)
+ /* Check for LONG type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LONG))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_LONG)
+ /* Check for LONGLONG type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LLONG))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_LLONG)
+ /* Check for UCHAR type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UCHAR))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_UCHAR)
+ /* Check for CHAR type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_CHAR))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_CHAR)
+ /* Check for SCHAR type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SCHAR))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_SCHAR)
+ /* Check for USHORT type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_USHORT))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_USHORT)
+ /* Check for UINT type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UINT))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_UINT)
+ /* Check for ULONG type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULONG))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_ULONG)
+ /* Check for ULONGLONG type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULLONG))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_ULLONG)
+ /* Check for FLOAT type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_FLOAT)
+ /* Check for DOUBLE type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_DOUBLE)
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ /* Check for LONGDOUBLE type */
+ else if((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LDOUBLE))
+ && 0 == H5T_cmp(type, tmp, FALSE))
+ HGOTO_DONE(H5T_NATIVE_LDOUBLE)
+#endif
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not find matching type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5Z_xform_find_type() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_copy_tree
+ * Purpose: Makes a copy of the parse tree passed in.
+ * Return: A pointer to a root for a new parse tree which is a copy
+ * of the one passed in.
+ * Programmer: Leon Arber
+ * April 1, 2004.
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5Z_xform_copy_tree(H5Z_node* tree, H5Z_datval_ptrs* dat_val_pointers, H5Z_datval_ptrs* new_dat_val_pointers)
+{
+ H5Z_node* ret_value=NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(tree);
+
+ if(tree->type == H5Z_XFORM_INTEGER)
+ {
+ if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree")
+ else
+ {
+ ret_value -> type = H5Z_XFORM_INTEGER;
+ ret_value ->value.int_val = tree->value.int_val;
+ ret_value -> lchild = NULL;
+ ret_value -> rchild = NULL;
+ }
+ }
+ else if (tree->type == H5Z_XFORM_FLOAT)
+ {
+ if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree")
+ else
+ {
+ ret_value -> type = H5Z_XFORM_FLOAT;
+ ret_value ->value.float_val = tree->value.float_val;
+ ret_value -> lchild = NULL;
+ ret_value -> rchild = NULL;
+ }
+ }
+ else if(tree->type == H5Z_XFORM_SYMBOL)
+ {
+ if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree")
+ else
+ {
+ ret_value -> type = H5Z_XFORM_SYMBOL;
+
+ ret_value -> value.dat_val = &(new_dat_val_pointers->ptr_dat_val[new_dat_val_pointers->num_ptrs]);
+ new_dat_val_pointers->num_ptrs++;
+ ret_value -> lchild = NULL;
+ ret_value -> rchild = NULL;
+ }
+ }
+ else if(tree->type == H5Z_XFORM_MULT)
+ H5Z_XFORM_DO_OP4(H5Z_XFORM_MULT)
+ else if(tree->type == H5Z_XFORM_PLUS)
+ H5Z_XFORM_DO_OP4(H5Z_XFORM_PLUS)
+ else if(tree->type == H5Z_XFORM_MINUS)
+ H5Z_XFORM_DO_OP4(H5Z_XFORM_MINUS)
+ else if(tree->type == H5Z_XFORM_DIVIDE)
+ H5Z_XFORM_DO_OP4(H5Z_XFORM_DIVIDE)
+ else
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error in parse tree while trying to copy")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_op_is_numbs
+ * Purpose: Internal function to facilitate the condition check in
+ * H5Z_xform_reduce_tree to reduce the bulkiness of the code.
+ * Return: TRUE or FALSE
+ * Programmer: Raymond Lu
+ * 15 March 2012
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5Z_op_is_numbs(H5Z_node* _tree)
+{
+ hbool_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(_tree);
+
+ if(((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT)) && ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))
+ ret_value = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_op_is_numbs2
+ * Purpose: Internal function to facilitate the condition check in
+ * H5Z_xform_reduce_tree to reduce the bulkiness of the code.
+ * The difference from H5Z_op_is_numbs is that the left child
+ * can be empty, like -x or +x.
+ * Return: TRUE or FALSE
+ * Programmer: Raymond Lu
+ * 15 March 2012
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5Z_op_is_numbs2(H5Z_node* _tree)
+{
+ hbool_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(_tree);
+
+ if((!_tree->lchild && ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT))) ||
+ ((_tree->lchild && ((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT))) && (_tree->rchild && ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))))
+ ret_value = TRUE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_reduce_tree
+ * Purpose: Simplifies parse tree passed in by performing any obvious
+ * and trivial arithemtic calculations.
+ *
+ * Return: None.
+ * Programmer: Leon Arber
+ * April 1, 2004.
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_xform_reduce_tree(H5Z_node* tree)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(tree) {
+ if((tree->type == H5Z_XFORM_DIVIDE) || (tree->type == H5Z_XFORM_MULT))
+ {
+ if(H5Z_op_is_numbs(tree))
+ H5Z_do_op(tree);
+ else
+ {
+ H5Z_xform_reduce_tree(tree->lchild);
+ if(H5Z_op_is_numbs(tree))
+ H5Z_do_op(tree);
+ else {
+ H5Z_xform_reduce_tree(tree->rchild);
+ if(H5Z_op_is_numbs(tree))
+ H5Z_do_op(tree);
+ }
+ }
+ } else if((tree->type == H5Z_XFORM_PLUS) || (tree->type == H5Z_XFORM_MINUS)) {
+ if(H5Z_op_is_numbs2(tree))
+ H5Z_do_op(tree);
+ else
+ {
+ H5Z_xform_reduce_tree(tree->lchild);
+ if(H5Z_op_is_numbs2(tree))
+ H5Z_do_op(tree);
+ else {
+ H5Z_xform_reduce_tree(tree->rchild);
+ if(H5Z_op_is_numbs2(tree))
+ H5Z_do_op(tree);
+ }
+ }
+ }
+
+ }
+
+ FUNC_LEAVE_NOAPI_VOID;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_do_op
+ * Purpose: If the root of the tree passed in points to a simple
+ * arithmetic operation and the left and right subtrees are both
+ * integer or floating point values, this function does that
+ * operation, free the left and rigt subtrees, and replaces
+ * the root with the result of the operation.
+ * Return: None.
+ * Programmer: Leon Arber
+ * April 1, 2004.
+ * Modifications:
+ * Raymond Lu
+ * 15 March 2012
+ * I added a new macro H5Z_XFORM_DO_OP6 to handle the special
+ * operations like -x or +x when the left operand is empty.
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5Z_do_op(H5Z_node* tree)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(tree->type == H5Z_XFORM_DIVIDE)
+ H5Z_XFORM_DO_OP3(/)
+ else if(tree->type == H5Z_XFORM_MULT)
+ H5Z_XFORM_DO_OP3(*)
+ else if(tree->type == H5Z_XFORM_PLUS)
+ H5Z_XFORM_DO_OP6(+)
+ else if(tree->type == H5Z_XFORM_MINUS)
+ H5Z_XFORM_DO_OP6(-)
+
+ FUNC_LEAVE_NOAPI_VOID;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_xform_create
+ *
+ * Purpose: Create a new data transform object from a string.
+ *
+ * Return:
+ * Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: May 4, 2004
+ *
+ * Comments:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5Z_data_xform_t *
+H5Z_xform_create(const char *expr)
+{
+ H5Z_data_xform_t *data_xform_prop = NULL;
+ unsigned int i;
+ unsigned int count = 0;
+ H5Z_data_xform_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ HDassert(expr);
+
+ /* Allocate space for the data transform information */
+ if(NULL == (data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform info")
+
+ if(NULL == (data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform array storage")
+
+ /* copy the user's string into the property */
+ if(NULL == (data_xform_prop->xform_exp = (char *)H5MM_xstrdup(expr)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform expression")
+
+ /* Find the number of times "x" is used in this equation, and allocate room for storing that many points */
+ for(i = 0; i < HDstrlen(expr); i++)
+ if(HDisalpha(expr[i]))
+ count++;
+
+ /* When there are no "x"'s in the equation (ie, simple transform case),
+ * we don't need to allocate any space since no array will have to be
+ * stored */
+ if(count > 0)
+ if(NULL == (data_xform_prop->dat_val_pointers->ptr_dat_val = (void **)H5MM_calloc(count * sizeof(void *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for pointers in transform array")
+
+ /* Initialize the num_ptrs field, which will be used to keep track of the number of copies
+ * of the data we have for polynomial transforms */
+ data_xform_prop->dat_val_pointers->num_ptrs = 0;
+
+ /* we generate the parse tree right here and store a pointer to its root in the property. */
+ if((data_xform_prop->parse_root = (H5Z_node *)H5Z_xform_parse(expr, data_xform_prop->dat_val_pointers))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to generate parse tree from expression")
+
+ /* Sanity check
+ * count should be the same num_ptrs */
+ if(count != data_xform_prop->dat_val_pointers->num_ptrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "error copying the parse tree, did not find correct number of \"variables\"")
+
+ /* Assign return value */
+ ret_value=data_xform_prop;
+
+
+done:
+ /* Clean up on error */
+ if(ret_value==NULL) {
+ if(data_xform_prop) {
+ if(data_xform_prop->parse_root)
+ H5Z_xform_destroy_parse_tree(data_xform_prop->parse_root);
+ if(data_xform_prop->xform_exp)
+ H5MM_xfree(data_xform_prop->xform_exp);
+ if(count > 0 && data_xform_prop->dat_val_pointers->ptr_dat_val)
+ H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
+ if(data_xform_prop->dat_val_pointers)
+ H5MM_xfree(data_xform_prop->dat_val_pointers);
+ H5MM_xfree(data_xform_prop);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5Z_xform_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_destroy
+ *
+ * Purpose: Destroy a data transform object.
+ *
+ * Return:
+ * Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: May 4, 2004
+ *
+ * Comments:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_xform_destroy(H5Z_data_xform_t *data_xform_prop)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if(data_xform_prop) {
+ /* Destroy the parse tree */
+ H5Z_xform_destroy_parse_tree(data_xform_prop->parse_root);
+
+ /* Free the expression */
+ H5MM_xfree(data_xform_prop->xform_exp);
+
+ /* Free the pointers to the temp. arrays, if there are any */
+ if(data_xform_prop->dat_val_pointers->num_ptrs > 0)
+ H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
+
+ /* Free the data storage struct */
+ H5MM_xfree(data_xform_prop->dat_val_pointers);
+
+ /* Free the node */
+ H5MM_xfree(data_xform_prop);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5Z_xform_destroy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_copy
+ *
+ * Purpose: Clone a data transform object.
+ *
+ * Return:
+ * Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: May 4, 2004
+ *
+ * Comments: This is an "in-place" copy, since this routine gets called
+ * after the top-level copy has been performed and this routine finishes
+ * the "deep" part of the copy.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Z_xform_copy(H5Z_data_xform_t **data_xform_prop)
+{
+ unsigned int i;
+ unsigned int count = 0;
+ H5Z_data_xform_t *new_data_xform_prop=NULL;
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(*data_xform_prop) {
+ /* Allocate new node */
+ if(NULL == (new_data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform info")
+
+ /* Copy string */
+ if(NULL == (new_data_xform_prop->xform_exp = (char *)H5MM_xstrdup((*data_xform_prop)->xform_exp)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform expression")
+
+ if(NULL == (new_data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform array storage")
+
+ /* Find the number of times "x" is used in this equation, and allocate room for storing that many points */
+ for(i = 0; i < HDstrlen(new_data_xform_prop->xform_exp); i++)
+ if(HDisalpha(new_data_xform_prop->xform_exp[i]))
+ count++;
+
+ if(count > 0)
+ if(NULL == (new_data_xform_prop->dat_val_pointers->ptr_dat_val = (void **)H5MM_calloc(count * sizeof(void *))))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for pointers in transform array")
+
+ /* Zero out num_pointers prior to H5Z_xform_cop_tree call; that call will increment it to the right amount */
+ new_data_xform_prop->dat_val_pointers->num_ptrs = 0;
+
+ /* Copy parse tree */
+ if((new_data_xform_prop->parse_root = (H5Z_node*)H5Z_xform_copy_tree((*data_xform_prop)->parse_root, (*data_xform_prop)->dat_val_pointers, new_data_xform_prop->dat_val_pointers)) == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree")
+
+ /* Sanity check
+ * count should be the same num_ptrs */
+ if(count != new_data_xform_prop->dat_val_pointers->num_ptrs)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree, did not find correct number of \"variables\"")
+
+ /* Copy new information on top of old information */
+ *data_xform_prop=new_data_xform_prop;
+ } /* end if */
+
+done:
+ /* Clean up on error */
+ if(ret_value<0) {
+ if(new_data_xform_prop) {
+ if(new_data_xform_prop->parse_root)
+ H5Z_xform_destroy_parse_tree(new_data_xform_prop->parse_root);
+ if(new_data_xform_prop->xform_exp)
+ H5MM_xfree(new_data_xform_prop->xform_exp);
+ H5MM_xfree(new_data_xform_prop);
+ } /* end if */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5Z_xform_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_noop
+ *
+ * Purpose: Checks if a data transform will be performed
+ *
+ * Return: TRUE for no data transform, FALSE for a data transform
+ *
+ * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu
+ *
+ * Date: May 4, 2004
+ *
+ * Comments: Can't fail
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5Z_xform_noop(const H5Z_data_xform_t *data_xform_prop)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ ret_value=(data_xform_prop ? FALSE : TRUE);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5Z_xform_noop() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Z_xform_extract_xform_str
+ *
+ * Purpose: Extracts the pointer to the data transform strings from the
+ * data transform property.`
+ * Return:
+ * Pointer to a copy of the string in the data_xform property.
+ *
+ * Programmer: Leon Arber, larber@ncsa.uiuc.edu
+ *
+ * Date: Sept. 4, 2004
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+const char *
+H5Z_xform_extract_xform_str(const H5Z_data_xform_t *data_xform_prop)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* There should be no way that this can be NULL since the function
+ * that calls this one checks to make sure it isn't before
+ * pasing them */
+ HDassert(data_xform_prop);
+
+ FUNC_LEAVE_NOAPI(data_xform_prop->xform_exp)
+} /* H5Z_xform_extract_xform_str() */
+
diff --git a/src/H5api_adpt.h b/src/H5api_adpt.h
new file mode 100644
index 0000000..0ff0f74
--- /dev/null
+++ b/src/H5api_adpt.h
@@ -0,0 +1,254 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * H5api_adpt.h
+ * Used for the HDF5 dll project
+ * Created by Patrick Lu on 1/12/99
+ */
+#ifndef H5API_ADPT_H
+#define H5API_ADPT_H
+
+
+/* This will only be defined if HDF5 was built with CMake */
+#ifdef H5_BUILT_AS_DYNAMIC_LIB
+
+#if defined(hdf5_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_DLL __declspec(dllexport)
+ #define H5_DLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_DLL __attribute__ ((visibility("default")))
+ #define H5_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_DLL __declspec(dllimport)
+ #define H5_DLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_DLL __attribute__ ((visibility("default")))
+ #define H5_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_DLL
+ #define H5_DLL
+ #define H5_DLLVAR extern
+#endif /* _HDF5DLL_ */
+
+#if defined(hdf5_test_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5TEST_DLL __declspec(dllexport)
+ #define H5TEST_DLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5TEST_DLL __attribute__ ((visibility("default")))
+ #define H5TEST_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5TEST_DLL __declspec(dllimport)
+ #define H5TEST_DLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5TEST_DLL __attribute__ ((visibility("default")))
+ #define H5TEST_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5TEST_DLL
+ #define H5TEST_DLL
+ #define H5TEST_DLLVAR extern
+#endif /* H5TEST_DLL */
+
+#if defined(hdf5_tools_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5TOOLS_DLL __declspec(dllexport)
+ #define H5TOOLS_DLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5TOOLS_DLL __attribute__ ((visibility("default")))
+ #define H5TOOLS_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5TOOLS_DLL __declspec(dllimport)
+ #define H5TOOLS_DLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5TOOLS_DLL __attribute__ ((visibility("default")))
+ #define H5TOOLS_DLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5TOOLS_DLL
+ #define H5TOOLS_DLL
+ #define H5TOOLS_DLLVAR extern
+#endif /* H5TOOLS_DLL */
+
+#if defined(hdf5_cpp_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_DLLCPP __declspec(dllexport)
+ #define H5_DLLCPPVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_DLLCPP __attribute__ ((visibility("default")))
+ #define H5_DLLCPPVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_DLLCPP __declspec(dllimport)
+ #define H5_DLLCPPVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_DLLCPP __attribute__ ((visibility("default")))
+ #define H5_DLLCPPVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_DLLCPP
+ #define H5_DLLCPP
+ #define H5_DLLCPPVAR extern
+#endif /* H5_DLLCPP */
+
+#if defined(hdf5_hl_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_HLDLL __declspec(dllexport)
+ #define H5_HLDLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_HLDLL __attribute__ ((visibility("default")))
+ #define H5_HLDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_HLDLL __declspec(dllimport)
+ #define H5_HLDLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_HLDLL __attribute__ ((visibility("default")))
+ #define H5_HLDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_HLDLL
+ #define H5_HLDLL
+ #define H5_HLDLLVAR extern
+#endif /* H5_HLDLL */
+
+#if defined(hdf5_hl_cpp_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_HLCPPDLL __declspec(dllexport)
+ #define H5_HLCPPDLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_HLCPPDLL __attribute__ ((visibility("default")))
+ #define H5_HLCPPDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_HLCPPDLL __declspec(dllimport)
+ #define H5_HLCPPDLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_HLCPPDLL __attribute__ ((visibility("default")))
+ #define H5_HLCPPDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_HLCPPDLL
+ #define H5_HLCPPDLL
+ #define H5_HLCPPDLLVAR extern
+#endif /* H5_HLCPPDLL */
+
+#if defined(hdf5_f90cstub_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_FCDLL __declspec(dllexport)
+ #define H5_FCDLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_FCDLL __attribute__ ((visibility("default")))
+ #define H5_FCDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_FCDLL __declspec(dllimport)
+ #define H5_FCDLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_FCDLL __attribute__ ((visibility("default")))
+ #define H5_FCDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_FCDLL
+ #define H5_FCDLL
+ #define H5_FCDLLVAR extern
+#endif /* H5_FCDLL */
+
+#if defined(hdf5_test_f90cstub_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_FCTESTDLL __declspec(dllexport)
+ #define H5_FCTESTDLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_FCTESTDLL __attribute__ ((visibility("default")))
+ #define H5_FCTESTDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define H5_FCTESTDLL __declspec(dllimport)
+ #define H5_FCTESTDLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define H5_FCTESTDLL __attribute__ ((visibility("default")))
+ #define H5_FCTESTDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef H5_FCTESTDLL
+ #define H5_FCTESTDLL
+ #define H5_FCTESTDLLVAR extern
+#endif /* H5_FCTESTDLL */
+
+#if defined(hdf5_hl_f90cstub_shared_EXPORTS)
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define HDF5_HL_F90CSTUBDLL __declspec(dllexport)
+ #define HDF5_HL_F90CSTUBDLLVAR extern __declspec(dllexport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define HDF5_HL_F90CSTUBDLL __attribute__ ((visibility("default")))
+ #define HDF5_HL_F90CSTUBDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#else
+ #if defined (_MSC_VER) /* MSVC Compiler Case */
+ #define HDF5_HL_F90CSTUBDLL __declspec(dllimport)
+ #define HDF5_HL_F90CSTUBDLLVAR __declspec(dllimport)
+ #elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
+ #define HDF5_HL_F90CSTUBDLL __attribute__ ((visibility("default")))
+ #define HDF5_HL_F90CSTUBDLLVAR extern __attribute__ ((visibility("default")))
+ #endif
+#endif
+
+#ifndef HDF5_HL_F90CSTUBDLL
+ #define HDF5_HL_F90CSTUBDLL
+ #define HDF5_HL_F90CSTUBDLLVAR extern
+#endif /* HDF5_HL_F90CSTUBDLL */
+
+#else
+ #define H5_DLL
+ #define H5_DLLVAR extern
+ #define H5TEST_DLL
+ #define H5TEST_DLLVAR extern
+ #define H5TOOLS_DLL
+ #define H5TOOLS_DLLVAR extern
+ #define H5_DLLCPP
+ #define H5_DLLCPPVAR extern
+ #define H5_HLDLL
+ #define H5_HLDLLVAR extern
+ #define H5_HLCPPDLL
+ #define H5_HLCPPDLLVAR extern
+ #define H5_FCDLL
+ #define H5_FCDLLVAR extern
+ #define H5_FCTESTDLL
+ #define H5_FCTESTDLLVAR extern
+ #define HDF5_HL_F90CSTUBDLL
+ #define HDF5_HL_F90CSTUBDLLVAR extern
+#endif /* H5_BUILT_AS_DYNAMIC_LIB */
+
+#endif /* H5API_ADPT_H */
diff --git a/src/H5checksum.c b/src/H5checksum.c
new file mode 100644
index 0000000..64d527e
--- /dev/null
+++ b/src/H5checksum.c
@@ -0,0 +1,494 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5checksum.c
+ * Aug 21 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal code for computing fletcher32 checksums
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Polynomial quotient */
+/* (same as the IEEE 802.3 (Ethernet) quotient) */
+#define H5_CRC_QUOTIENT 0x04C11DB7
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Table of CRCs of all 8-bit messages. */
+static uint32_t H5_crc_table[256];
+
+/* Flag: has the table been computed? */
+static hbool_t H5_crc_table_computed = FALSE;
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_checksum_fletcher32
+ *
+ * Purpose: This routine provides a generic, fast checksum algorithm for
+ * use in the library.
+ *
+ * Note: See the Wikipedia page for Fletcher's checksum:
+ * http://en.wikipedia.org/wiki/Fletcher%27s_checksum
+ * for more details, etc.
+ *
+ * Note #2: Per the information in RFC 3309:
+ * (http://tools.ietf.org/html/rfc3309)
+ * Fletcher's checksum is not reliable for small buffers.
+ *
+ * Note #3: The algorithm below differs from that given in the Wikipedia
+ * page by copying the data into 'sum1' in a more portable way
+ * and also by initializing 'sum1' and 'sum2' to 0 instead of
+ * 0xffff (for backward compatibility reasons with earlier
+ * HDF5 fletcher32 I/O filter routine, mostly).
+ *
+ * Return: 32-bit fletcher checksum of input buffer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Monday, August 21, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+uint32_t
+H5_checksum_fletcher32(const void *_data, size_t _len)
+{
+ const uint8_t *data = (const uint8_t *)_data; /* Pointer to the data to be summed */
+ size_t len = _len / 2; /* Length in 16-bit words */
+ uint32_t sum1 = 0, sum2 = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(_data);
+ HDassert(_len > 0);
+
+ /* Compute checksum for pairs of bytes */
+ /* (the magic "360" value is is the largest number of sums that can be
+ * performed without numeric overflow)
+ */
+ while (len) {
+ size_t tlen = len > 360 ? 360 : len;
+ len -= tlen;
+ do {
+ sum1 += (uint32_t)(((uint16_t)data[0]) << 8) | ((uint16_t)data[1]);
+ data += 2;
+ sum2 += sum1;
+ } while (--tlen);
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ }
+
+ /* Check for odd # of bytes */
+ if(_len % 2) {
+ sum1 += (uint32_t)(((uint16_t)*data) << 8);
+ sum2 += sum1;
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ } /* end if */
+
+ /* Second reduction step to reduce sums to 16 bits */
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+
+ FUNC_LEAVE_NOAPI((sum2 << 16) | sum1)
+} /* end H5_checksum_fletcher32() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_checksum_crc_make_table
+ *
+ * Purpose: Compute the CRC table for the CRC checksum algorithm
+ *
+ * Return: none
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5_checksum_crc_make_table(void)
+{
+ uint32_t c; /* Checksum for each byte value */
+ unsigned n, k; /* Local index variables */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Compute the checksum for each possible byte value */
+ for(n = 0; n < 256; n++) {
+ c = (uint32_t) n;
+ for(k = 0; k < 8; k++)
+ if(c & 1)
+ c = H5_CRC_QUOTIENT ^ (c >> 1);
+ else
+ c = c >> 1;
+ H5_crc_table[n] = c;
+ }
+ H5_crc_table_computed = TRUE;
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5_checksum_crc_make_table() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_checksum_crc_make_table
+ *
+ * Purpose: Update a running CRC with the bytes buf[0..len-1]--the CRC
+ * should be initialized to all 1's, and the transmitted value
+ * is the 1's complement of the final running CRC (see the
+ * H5_checksum_crc() routine below)).
+ *
+ * Return: 32-bit CRC checksum of input buffer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static uint32_t
+H5_checksum_crc_update(uint32_t crc, const uint8_t *buf, size_t len)
+{
+ size_t n; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Initialize the CRC table if necessary */
+ if(!H5_crc_table_computed)
+ H5_checksum_crc_make_table();
+
+ /* Update the CRC with the results from this buffer */
+ for(n = 0; n < len; n++)
+ crc = H5_crc_table[(crc ^ buf[n]) & 0xff] ^ (crc >> 8);
+
+ FUNC_LEAVE_NOAPI(crc)
+} /* end H5_checksum_crc_update() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_checksum_crc
+ *
+ * Purpose: This routine provides a generic checksum algorithm for
+ * use in the library.
+ *
+ * Note: This algorithm was based on the implementation described
+ * in the document describing the PNG image format:
+ * http://www.w3.org/TR/PNG/#D-CRCAppendix
+ *
+ * Return: 32-bit CRC checksum of input buffer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+uint32_t
+H5_checksum_crc(const void *_data, size_t len)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(_data);
+ HDassert(len > 0);
+
+ FUNC_LEAVE_NOAPI(H5_checksum_crc_update((uint32_t)0xffffffffL, (const uint8_t *)_data, len) ^ 0xffffffffL)
+} /* end H5_checksum_crc() */
+
+/*
+-------------------------------------------------------------------------------
+H5_lookup3_mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define H5_lookup3_rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
+#define H5_lookup3_mix(a,b,c) \
+{ \
+ a -= c; a ^= H5_lookup3_rot(c, 4); c += b; \
+ b -= a; b ^= H5_lookup3_rot(a, 6); a += c; \
+ c -= b; c ^= H5_lookup3_rot(b, 8); b += a; \
+ a -= c; a ^= H5_lookup3_rot(c,16); c += b; \
+ b -= a; b ^= H5_lookup3_rot(a,19); a += c; \
+ c -= b; c ^= H5_lookup3_rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+H5_lookup3_final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define H5_lookup3_final(a,b,c) \
+{ \
+ c ^= b; c -= H5_lookup3_rot(b,14); \
+ a ^= c; a -= H5_lookup3_rot(c,11); \
+ b ^= a; b -= H5_lookup3_rot(a,25); \
+ c ^= b; c -= H5_lookup3_rot(b,16); \
+ a ^= c; a -= H5_lookup3_rot(c,4); \
+ b ^= a; b -= H5_lookup3_rot(a,14); \
+ c ^= b; c -= H5_lookup3_rot(b,24); \
+}
+
+/*
+-------------------------------------------------------------------------------
+H5_checksum_lookup3() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = H5_checksum_lookup( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+uint32_t
+H5_checksum_lookup3(const void *key, size_t length, uint32_t initval)
+{
+ const uint8_t *k = (const uint8_t *)key;
+ uint32_t a, b, c; /* internal state */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(key);
+ HDassert(length > 0);
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ H5_lookup3_mix(a, b, c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : goto done;
+ default:
+ HDassert(0 && "This Should never be executed!");
+ }
+
+ H5_lookup3_final(a, b, c);
+
+done:
+ FUNC_LEAVE_NOAPI(c)
+} /* end H5_checksum_lookup3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_checksum_metadata
+ *
+ * Purpose: Provide a more abstract routine for checksumming metadata
+ * in a file, where the policy of which algorithm to choose
+ * is centralized.
+ *
+ * Return: checksum of input buffer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, August 22, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+uint32_t
+H5_checksum_metadata(const void *data, size_t len, uint32_t initval)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(data);
+ HDassert(len > 0);
+
+ /* Choose the appropriate checksum routine */
+ /* (use Bob Jenkin's "lookup3" algorithm for all buffer sizes) */
+ FUNC_LEAVE_NOAPI(H5_checksum_lookup3(data, len, initval))
+} /* end H5_checksum_metadata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_hash_string
+ *
+ * Purpose: Provide a simple & fast routine for hashing strings
+ *
+ * Note: This algorithm is the 'djb2' algorithm described on this page:
+ * http://www.cse.yorku.ca/~oz/hash.html
+ *
+ * Return: hash of input string (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 11, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+uint32_t
+H5_hash_string(const char *str)
+{
+ uint32_t hash = 5381;
+ int c;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(str);
+
+ while((c = *str++))
+ hash = ((hash << 5) + hash) + (uint32_t)c; /* hash * 33 + c */
+
+ FUNC_LEAVE_NOAPI(hash)
+} /* end H5_hash_string() */
+
diff --git a/src/H5config.h.in b/src/H5config.h.in
new file mode 100644
index 0000000..36139cc
--- /dev/null
+++ b/src/H5config.h.in
@@ -0,0 +1,657 @@
+/* src/H5config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define if C++ compiler recognizes offsetof */
+#undef CXX_HAVE_OFFSETOF
+
+/* Define if this is a debug build. */
+#undef DEBUG_BUILD
+
+/* Define the default plugins path to compile */
+#undef DEFAULT_PLUGINDIR
+
+/* Define if dev_t is a scalar */
+#undef DEV_T_IS_SCALAR
+
+/* Define to dummy `main' function (if any) required to link to the Fortran
+ libraries. */
+#undef FC_DUMMY_MAIN
+
+/* Define if F77 and FC dummy `main' functions are identical. */
+#undef FC_DUMMY_MAIN_EQ_F77
+
+/* Define to a macro mangling the given C identifier (in lower and upper
+ case), which must not contain underscores, for linking with Fortran. */
+#undef FC_FUNC
+
+/* As FC_FUNC, but for C identifiers containing underscores. */
+#undef FC_FUNC_
+
+/* Define if Fortran C_LONG_DOUBLE is different from C_DOUBLE */
+#undef FORTRAN_C_LONG_DOUBLE_IS_UNIQUE
+
+/* Define if we have Fortran C_LONG_DOUBLE */
+#undef FORTRAN_HAVE_C_LONG_DOUBLE
+
+/* Define if we have Fortran intrinsic C_SIZEOF */
+#undef FORTRAN_HAVE_C_SIZEOF
+
+/* Define if we have Fortran intrinsic SIZEOF */
+#undef FORTRAN_HAVE_SIZEOF
+
+/* Define if we have Fortran intrinsic STORAGE_SIZE */
+#undef FORTRAN_HAVE_STORAGE_SIZE
+
+/* Determine the size of C long double */
+#undef FORTRAN_SIZEOF_LONG_DOUBLE
+
+/* Define Fortran compiler ID */
+#undef Fortran_COMPILER_ID
+
+/* Define valid Fortran INTEGER KINDs */
+#undef H5CONFIG_F_IKIND
+
+/* Define number of valid Fortran INTEGER KINDs */
+#undef H5CONFIG_F_NUM_IKIND
+
+/* Define number of valid Fortran REAL KINDs */
+#undef H5CONFIG_F_NUM_RKIND
+
+/* Define valid Fortran REAL KINDs */
+#undef H5CONFIG_F_RKIND
+
+/* Define valid Fortran REAL KINDs Sizeof */
+#undef H5CONFIG_F_RKIND_SIZEOF
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define if the __attribute__(()) extension is present */
+#undef HAVE_ATTRIBUTE
+
+/* Define if the compiler understands C99 designated initialization of structs
+ and unions */
+#undef HAVE_C99_DESIGNATED_INITIALIZER
+
+/* Define if the compiler understands the __func__ keyword */
+#undef HAVE_C99_FUNC
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define if the function stack tracing code is to be compiled in */
+#undef HAVE_CODESTACK
+
+/* Define if Darwin or Mac OS X */
+#undef HAVE_DARWIN
+
+/* Define to 1 if you have the `difftime' function. */
+#undef HAVE_DIFFTIME
+
+/* Define if the direct I/O virtual file driver (VFD) should be compiled */
+#undef HAVE_DIRECT
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <dmalloc.h> header file. */
+#undef HAVE_DMALLOC_H
+
+/* Define if library information should be embedded in the executables */
+#undef HAVE_EMBEDDED_LIBINFO
+
+/* Define to 1 if you have the `fcntl' function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <features.h> header file. */
+#undef HAVE_FEATURES_H
+
+/* Define if support for deflate (zlib) filter is enabled */
+#undef HAVE_FILTER_DEFLATE
+
+/* Define if support for szip filter is enabled */
+#undef HAVE_FILTER_SZIP
+
+/* Determine if __float128 is available */
+#undef HAVE_FLOAT128
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `frexpf' function. */
+#undef HAVE_FREXPF
+
+/* Define to 1 if you have the `frexpl' function. */
+#undef HAVE_FREXPL
+
+/* Define if the compiler understands the __FUNCTION__ keyword */
+#undef HAVE_FUNCTION
+
+/* Determine if INTEGER*16 is available */
+#undef HAVE_Fortran_INTEGER_SIZEOF_16
+
+/* Define to 1 if you have the `GetConsoleScreenBufferInfo' function. */
+#undef HAVE_GETCONSOLESCREENBUFFERINFO
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `gettextinfo' function. */
+#undef HAVE_GETTEXTINFO
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if the compiler understands inline */
+#undef HAVE_INLINE
+
+/* Define if parallel library will contain instrumentation to detect correct
+ optimization operation */
+#undef HAVE_INSTRUMENTED_LIBRARY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `ioctl' function. */
+#undef HAVE_IOCTL
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+#undef HAVE_LIBDL
+
+/* Define to 1 if you have the `dmalloc' library (-ldmalloc). */
+#undef HAVE_LIBDMALLOC
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `mpe' library (-lmpe). */
+#undef HAVE_LIBMPE
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the `sz' library (-lsz). */
+#undef HAVE_LIBSZ
+
+/* Define to 1 if you have the `ws2_32' library (-lws2_32). */
+#undef HAVE_LIBWS2_32
+
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the `llround' function. */
+#undef HAVE_LLROUND
+
+/* Define to 1 if you have the `llroundf' function. */
+#undef HAVE_LLROUNDF
+
+/* Define to 1 if you have the `longjmp' function. */
+#undef HAVE_LONGJMP
+
+/* Define to 1 if you have the `lround' function. */
+#undef HAVE_LROUND
+
+/* Define to 1 if you have the `lroundf' function. */
+#undef HAVE_LROUNDF
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <mach/mach_time.h> header file. */
+#undef HAVE_MACH_MACH_TIME_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if we have MPE support */
+#undef HAVE_MPE
+
+/* Define to 1 if you have the <mpe.h> header file. */
+#undef HAVE_MPE_H
+
+/* Define if MPI_Comm_c2f and MPI_Comm_f2c exist */
+#undef HAVE_MPI_MULTI_LANG_Comm
+
+/* Define if MPI_Info_c2f and MPI_Info_f2c exist */
+#undef HAVE_MPI_MULTI_LANG_Info
+
+/* Define if we have parallel support */
+#undef HAVE_PARALLEL
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <quadmath.h> header file. */
+#undef HAVE_QUADMATH_H
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `rand_r' function. */
+#undef HAVE_RAND_R
+
+/* Define to 1 if you have the `round' function. */
+#undef HAVE_ROUND
+
+/* Define to 1 if you have the `roundf' function. */
+#undef HAVE_ROUNDF
+
+/* Define to 1 if you have the `setjmp' function. */
+#undef HAVE_SETJMP
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setsysinfo' function. */
+#undef HAVE_SETSYSINFO
+
+/* Define to 1 if you have the `siglongjmp' function. */
+#undef HAVE_SIGLONGJMP
+
+/* Define to 1 if you have the `signal' function. */
+#undef HAVE_SIGNAL
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetjmp' function. */
+#undef HAVE_SIGSETJMP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define if struct stat has the st_blocks field */
+#undef HAVE_STAT_ST_BLOCKS
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define if struct text_info is defined */
+#undef HAVE_STRUCT_TEXT_INFO
+
+/* Define if struct videoconfig is defined */
+#undef HAVE_STRUCT_VIDEOCONFIG
+
+/* Define to 1 if you have the `symlink' function. */
+#undef HAVE_SYMLINK
+
+/* Define to 1 if you have the `system' function. */
+#undef HAVE_SYSTEM
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/timeb.h> header file. */
+#undef HAVE_SYS_TIMEB_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <szlib.h> header file. */
+#undef HAVE_SZLIB_H
+
+/* Define if we have thread safe support */
+#undef HAVE_THREADSAFE
+
+/* Define if timezone is a global variable */
+#undef HAVE_TIMEZONE
+
+/* Define if the ioctl TIOCGETD is defined */
+#undef HAVE_TIOCGETD
+
+/* Define if the ioctl TIOGWINSZ is defined */
+#undef HAVE_TIOCGWINSZ
+
+/* Define to 1 if you have the `tmpfile' function. */
+#undef HAVE_TMPFILE
+
+/* Define if tm_gmtoff is a member of struct tm */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define if your system has window style path name. */
+#undef HAVE_WINDOW_PATH
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if you have the `_getvideoconfig' function. */
+#undef HAVE__GETVIDEOCONFIG
+
+/* Define to 1 if you have the `_scrsize' function. */
+#undef HAVE__SCRSIZE
+
+/* Define if the compiler understands __inline */
+#undef HAVE___INLINE
+
+/* Define if the compiler understands __inline__ */
+#undef HAVE___INLINE__
+
+/* Define if the high-level library headers should be included in hdf5.h */
+#undef INCLUDE_HL
+
+/* Define if your system can convert long double to (unsigned) long long
+ values correctly. */
+#undef LDOUBLE_TO_LLONG_ACCURATE
+
+/* Define if your system converts long double to (unsigned) long values with
+ special algorithm. */
+#undef LDOUBLE_TO_LONG_SPECIAL
+
+/* Define if your system can convert (unsigned) long long to long double
+ values correctly. */
+#undef LLONG_TO_LDOUBLE_CORRECT
+
+/* Define if your system can convert (unsigned) long to long double values
+ with special algorithm. */
+#undef LONG_TO_LDOUBLE_SPECIAL
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to enable internal memory allocation sanity checking. */
+#undef MEMORY_ALLOC_SANITY_CHECK
+
+/* Define if the metadata trace file code is to be compiled in */
+#undef METADATA_TRACE_FILE
+
+/* Define if we can violate pointer alignment restrictions */
+#undef NO_ALIGNMENT_RESTRICTIONS
+
+/* Define if deprecated public API symbols are disabled */
+#undef NO_DEPRECATED_SYMBOLS
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Determine the maximum decimal precision in C */
+#undef PAC_C_MAX_REAL_PRECISION
+
+/* Define Fortran Maximum Real Decimal Precision */
+#undef PAC_FC_MAX_REAL_PRECISION
+
+/* Width for printf() for type `long long' or `__int64', use `ll' */
+#undef PRINTF_LL_WIDTH
+
+/* The size of `bool', as computed by sizeof. */
+#undef SIZEOF_BOOL
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `double', as computed by sizeof. */
+#undef SIZEOF_DOUBLE
+
+/* The size of `float', as computed by sizeof. */
+#undef SIZEOF_FLOAT
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `int16_t', as computed by sizeof. */
+#undef SIZEOF_INT16_T
+
+/* The size of `int32_t', as computed by sizeof. */
+#undef SIZEOF_INT32_T
+
+/* The size of `int64_t', as computed by sizeof. */
+#undef SIZEOF_INT64_T
+
+/* The size of `int8_t', as computed by sizeof. */
+#undef SIZEOF_INT8_T
+
+/* The size of `int_fast16_t', as computed by sizeof. */
+#undef SIZEOF_INT_FAST16_T
+
+/* The size of `int_fast32_t', as computed by sizeof. */
+#undef SIZEOF_INT_FAST32_T
+
+/* The size of `int_fast64_t', as computed by sizeof. */
+#undef SIZEOF_INT_FAST64_T
+
+/* The size of `int_fast8_t', as computed by sizeof. */
+#undef SIZEOF_INT_FAST8_T
+
+/* The size of `int_least16_t', as computed by sizeof. */
+#undef SIZEOF_INT_LEAST16_T
+
+/* The size of `int_least32_t', as computed by sizeof. */
+#undef SIZEOF_INT_LEAST32_T
+
+/* The size of `int_least64_t', as computed by sizeof. */
+#undef SIZEOF_INT_LEAST64_T
+
+/* The size of `int_least8_t', as computed by sizeof. */
+#undef SIZEOF_INT_LEAST8_T
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long double', as computed by sizeof. */
+#undef SIZEOF_LONG_DOUBLE
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `ptrdiff_t', as computed by sizeof. */
+#undef SIZEOF_PTRDIFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `ssize_t', as computed by sizeof. */
+#undef SIZEOF_SSIZE_T
+
+/* The size of `uint16_t', as computed by sizeof. */
+#undef SIZEOF_UINT16_T
+
+/* The size of `uint32_t', as computed by sizeof. */
+#undef SIZEOF_UINT32_T
+
+/* The size of `uint64_t', as computed by sizeof. */
+#undef SIZEOF_UINT64_T
+
+/* The size of `uint8_t', as computed by sizeof. */
+#undef SIZEOF_UINT8_T
+
+/* The size of `uint_fast16_t', as computed by sizeof. */
+#undef SIZEOF_UINT_FAST16_T
+
+/* The size of `uint_fast32_t', as computed by sizeof. */
+#undef SIZEOF_UINT_FAST32_T
+
+/* The size of `uint_fast64_t', as computed by sizeof. */
+#undef SIZEOF_UINT_FAST64_T
+
+/* The size of `uint_fast8_t', as computed by sizeof. */
+#undef SIZEOF_UINT_FAST8_T
+
+/* The size of `uint_least16_t', as computed by sizeof. */
+#undef SIZEOF_UINT_LEAST16_T
+
+/* The size of `uint_least32_t', as computed by sizeof. */
+#undef SIZEOF_UINT_LEAST32_T
+
+/* The size of `uint_least64_t', as computed by sizeof. */
+#undef SIZEOF_UINT_LEAST64_T
+
+/* The size of `uint_least8_t', as computed by sizeof. */
+#undef SIZEOF_UINT_LEAST8_T
+
+/* The size of `unsigned', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED
+
+/* The size of `_Quad', as computed by sizeof. */
+#undef SIZEOF__QUAD
+
+/* The size of `__float128', as computed by sizeof. */
+#undef SIZEOF___FLOAT128
+
+/* The size of `__int64', as computed by sizeof. */
+#undef SIZEOF___INT64
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if strict file format checks are enabled */
+#undef STRICT_FORMAT_CHECKS
+
+/* Define if your system supports pthread_attr_setscope(&attribute,
+ PTHREAD_SCOPE_SYSTEM) call. */
+#undef SYSTEM_SCOPE_THREADS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define using v1.6 public API symbols by default */
+#undef USE_16_API_DEFAULT
+
+/* Define using v1.8 public API symbols by default */
+#undef USE_18_API_DEFAULT
+
+/* Define if a memory checking tool will be used on the library, to cause
+ library to be very picky about memory operations and also disable the
+ internal free list manager code. */
+#undef USING_MEMCHECKER
+
+/* Version number of package */
+#undef VERSION
+
+/* Data accuracy is prefered to speed during data conversions */
+#undef WANT_DATA_ACCURACY
+
+/* Check exception handling functions during data conversions */
+#undef WANT_DCONV_EXCEPTION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef ptrdiff_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef ssize_t
diff --git a/src/H5dbg.c b/src/H5dbg.c
new file mode 100644
index 0000000..dd50034
--- /dev/null
+++ b/src/H5dbg.c
@@ -0,0 +1,144 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5dbg.c
+ * Mar 4 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Generic debugging routines
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_buffer_dump
+ *
+ * Purpose: Dumps a buffer of memory in an octal dump form
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_buffer_dump(FILE *stream, int indent, const uint8_t *buf,
+ const uint8_t *marker, size_t buf_offset, size_t buf_size)
+{
+ size_t u, v; /* Local index variable */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /*
+ * Check arguments.
+ */
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(buf);
+ HDassert(marker);
+ HDassert(buf_size > 0);
+
+ /*
+ * Print the buffer in a VMS-style octal dump.
+ */
+ HDfprintf(stream, "%*sData follows (`__' indicates free region)...\n",
+ indent, "");
+ for(u = 0; u < buf_size; u += 16) {
+ uint8_t c;
+
+ HDfprintf(stream, "%*s %8d: ", indent, "", u + buf_offset);
+
+ /* Print the hex values */
+ for(v = 0; v < 16; v++) {
+ if(u + v < buf_size) {
+ if(marker[u + v])
+ HDfprintf(stream, "__ ");
+ else {
+ c = buf[buf_offset + u + v];
+ HDfprintf(stream, "%02x ", c);
+ } /* end else */
+ } /* end if */
+ else
+ fprintf(stream, " ");
+ if(7 == v)
+ HDfputc(' ', stream);
+ } /* end for */
+ HDfputc(' ', stream);
+
+ /* Print the character values */
+ for(v = 0; v < 16; v++) {
+ if(u + v < buf_size) {
+ if(marker[u + v])
+ HDfputc(' ', stream);
+ else {
+ c = buf[buf_offset + u + v];
+ if(HDisprint(c))
+ HDfputc(c, stream);
+ else
+ HDfputc('.', stream);
+ } /* end else */
+ } /* end if */
+ if(7 == v)
+ HDfputc(' ', stream);
+ } /* end for */
+
+ HDfputc('\n', stream);
+ } /* end for */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5_buffer_dump() */
+
diff --git a/src/H5detect.c b/src/H5detect.c
new file mode 100644
index 0000000..75a1dba
--- /dev/null
+++ b/src/H5detect.c
@@ -0,0 +1,1789 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*keep this declaration near the top of this file -RPM*/
+static const char *FileHeader = "\n\
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\
+ * Copyright by The HDF Group. *\n\
+ * Copyright by the Board of Trustees of the University of Illinois. *\n\
+ * All rights reserved. *\n\
+ * *\n\
+ * This file is part of HDF5. The full HDF5 copyright notice, including *\n\
+ * terms governing use, modification, and redistribution, is contained in *\n\
+ * the COPYING file, which can be found at the root of the source code *\n\
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *\n\
+ * If you do not have access to either file, you may request a copy from *\n\
+ * help@hdfgroup.org. *\n\
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *";
+/*
+ *
+ * Created: H5detect.c
+ * 10 Aug 1997
+ * Robb Matzke
+ *
+ * Purpose: This code was borrowed heavily from the `detect.c'
+ * program in the AIO distribution from Lawrence
+ * Livermore National Laboratory.
+ *
+ * Detects machine byte order and floating point
+ * format and generates a C source file (H5Tinit.c)
+ * to describe those paramters.
+ *
+ * Assumptions: We have an ANSI compiler. We're on a Unix like
+ * system or configure has detected those Unix
+ * features which aren't available. We're not
+ * running on a Vax or other machine with mixed
+ * endianess.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#undef NDEBUG
+#include "H5private.h"
+#include "H5Tpublic.h"
+#include "H5Rpublic.h"
+
+#define MAXDETECT 64
+
+/* The ALIGNMENT test code may generate the SIGBUS, SIGSEGV, or SIGILL signals.
+ * We use setjmp/longjmp in the signal handlers for recovery. But setjmp/longjmp
+ * do not necessary restore the signal blocking status while sigsetjmp/siglongjmp
+ * do. If sigsetjmp/siglongjmp are not supported, need to use sigprocmask to
+ * unblock the signal before doing longjmp.
+ */
+/* Define H5SETJMP/H5LONGJMP depending on if sigsetjmp/siglongjmp are */
+/* supported. */
+#if defined(H5_HAVE_SIGSETJMP) && defined(H5_HAVE_SIGLONGJMP)
+/* Always save blocked signals to be restore by siglongjmp. */
+#define H5JMP_BUF sigjmp_buf
+#define H5SETJMP(buf) HDsigsetjmp(buf, 1)
+#define H5LONGJMP(buf, val) HDsiglongjmp(buf, val)
+#define H5HAVE_SIGJMP /* sigsetjmp/siglongjmp are supported. */
+#elif defined(H5_HAVE_LONGJMP)
+#define H5JMP_BUF jmp_buf
+#define H5SETJMP(buf) HDsetjmp(buf)
+#define H5LONGJMP(buf, val) HDlongjmp(buf, val)
+#endif
+
+/* ALIGNMENT and signal-handling status codes */
+#define STA_NoALIGNMENT 0x0001 /* No ALIGNMENT Test */
+#define STA_NoHandlerVerify 0x0002 /* No signal handler Tests */
+
+
+/*
+ * This structure holds information about a type that
+ * was detected.
+ */
+typedef struct detected_t {
+ const char *varname;
+ unsigned int size; /* total byte size */
+ unsigned int precision; /* meaningful bits */
+ unsigned int offset; /* bit offset to meaningful bits */
+ int perm[32]; /* for detection of byte order */
+ hbool_t is_vax; /* for vax (float & double) only */
+ unsigned int sign; /* location of sign bit */
+ unsigned int mpos, msize, imp; /* information about mantissa */
+ unsigned int epos, esize; /* information about exponent */
+ unsigned long bias; /* exponent bias for floating pt */
+ unsigned int align; /* required byte alignment */
+ unsigned int comp_align; /* alignment for structure */
+} detected_t;
+
+/* This structure holds structure alignment for pointers, hvl_t, hobj_ref_t,
+ * hdset_reg_ref_t */
+typedef struct malign_t {
+ const char *name;
+ unsigned int comp_align; /* alignment for structure */
+} malign_t;
+
+/* global variables types detection code */
+H5_GCC_DIAG_OFF(larger-than=)
+static detected_t d_g[MAXDETECT];
+H5_GCC_DIAG_ON(larger-than=)
+static malign_t m_g[MAXDETECT];
+static volatile int nd_g = 0, na_g = 0;
+
+static void print_results(int nd, detected_t *d, int na, malign_t *m);
+static void iprint(detected_t *);
+static int byte_cmp(int, const void *, const void *, const unsigned char *);
+static unsigned int bit_cmp(unsigned int, int *, void *, void *, const unsigned char *);
+static void fix_order(int, int, int *, const char **);
+static unsigned int imp_bit(unsigned int, int *, void *, void *, const unsigned char *);
+static unsigned int find_bias(unsigned int, unsigned int, int *, void *);
+static void precision (detected_t*);
+static void print_header(void);
+static void detect_C89_integers(void);
+static void detect_C89_floats(void);
+static void detect_C99_integers(void);
+static void detect_C99_floats(void);
+static void detect_C99_integers8(void);
+static void detect_C99_integers16(void);
+static void detect_C99_integers32(void);
+static void detect_C99_integers64(void);
+static void detect_alignments(void);
+static unsigned int align_g[] = {1, 2, 4, 8, 16};
+static int align_status_g = 0; /* ALIGNMENT Signal Status */
+static int sigbus_handler_called_g = 0; /* how many times called */
+static int sigsegv_handler_called_g = 0;/* how many times called */
+static int sigill_handler_called_g = 0; /* how many times called */
+static int signal_handler_tested_g = 0; /* how many times tested */
+#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL)
+static int verify_signal_handlers(int signum, void (*handler)(int));
+#endif
+#ifdef H5JMP_BUF
+static H5JMP_BUF jbuf_g;
+#endif
+
+
+/*-------------------------------------------------------------------------
+ * Function: precision
+ *
+ * Purpose: Determine the precision and offset.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 18, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+precision (detected_t *d)
+{
+ unsigned int n;
+
+ if (0 == d->msize) {
+ /*
+ * An integer. The permutation can have negative values at the
+ * beginning or end which represent padding of bytes. We must adjust
+ * the precision and offset accordingly.
+ */
+ if (d->perm[0] < 0) {
+ /*
+ * Lower addresses are padded.
+ */
+ for (n = 0; n < d->size && d->perm[n] < 0; n++)
+ /*void*/;
+ d->precision = 8 * (d->size - n);
+ d->offset = 0;
+ } else if (d->perm[d->size - 1] < 0) {
+ /*
+ * Higher addresses are padded.
+ */
+ for (n = 0; n < d->size && d->perm[d->size - (n + 1)]; n++)
+ /*void*/;
+ d->precision = 8 * (d->size - n);
+ d->offset = 8 * n;
+ } else {
+ /*
+ * No padding.
+ */
+ d->precision = 8 * d->size;
+ d->offset = 0;
+ }
+ } else {
+ /* A floating point */
+ d->offset = MIN3(d->mpos, d->epos, d->sign);
+ d->precision = d->msize + d->esize + 1;
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: DETECT_I/DETECT_BYTE
+ *
+ * Purpose: These macro takes a type like `int' and a base name like
+ * `nati' and detects the byte order. The VAR is used to
+ * construct the names of the C variables defined.
+ *
+ * DETECT_I is used for types that are larger than one byte,
+ * DETECT_BYTE is used for types that are exactly one byte.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 12 1996
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 4 Nov 1996
+ * The INFO.perm now contains `-1' for bytes that aren't used and
+ * are always zero. This happens on the Cray for `short' where
+ * sizeof(short) is 8, but only the low-order 4 bytes are ever used.
+ *
+ * Robb Matzke, 4 Nov 1996
+ * Added a `padding' field to indicate how many zero bytes appear to
+ * the left (N) or right (-N) of the value.
+ *
+ * Robb Matzke, 5 Nov 1996
+ * Removed HFILE and CFILE arguments.
+ *
+ * Neil Fortner, 6 Sep 2013
+ * Split macro into DETECT_I and DETECT_BYTE macros, extracted
+ * common cod einto DETECT_I_BYTE_CORE. This was done to remove
+ * "will never be executed" warnings.
+ *
+ *-------------------------------------------------------------------------
+ */
+#define DETECT_I_BYTE_CORE(TYPE,VAR,INFO,DETECT_TYPE) { \
+ DETECT_TYPE _v; \
+ int _i, _j; \
+ unsigned char *_x; \
+ \
+ HDmemset(&INFO, 0, sizeof(INFO)); \
+ INFO.varname = #VAR; \
+ INFO.size = sizeof(TYPE); \
+ \
+ for(_i = sizeof(DETECT_TYPE), _v = 0; _i > 0; --_i) \
+ _v = (DETECT_TYPE) ((DETECT_TYPE) (_v << 8) + (DETECT_TYPE) _i); \
+ \
+ for(_i = 0, _x = (unsigned char *)&_v; _i < (signed)sizeof(DETECT_TYPE); _i++) { \
+ _j = (*_x++) - 1; \
+ HDassert(_j < (signed)sizeof(DETECT_TYPE)); \
+ INFO.perm[_i] = _j; \
+ } /* end for */ \
+ \
+ INFO.sign = ('U' != *(#VAR)); \
+ precision (&(INFO)); \
+ ALIGNMENT(TYPE, INFO); \
+ if(!HDstrcmp(INFO.varname, "SCHAR") || !HDstrcmp(INFO.varname, "SHORT") || \
+ !HDstrcmp(INFO.varname, "INT") || !HDstrcmp(INFO.varname, "LONG") || \
+ !HDstrcmp(INFO.varname, "LLONG")) { \
+ COMP_ALIGNMENT(TYPE, INFO.comp_align); \
+ } \
+}
+
+#define DETECT_BYTE(TYPE,VAR,INFO) { \
+ HDcompile_assert(sizeof(TYPE) == 1); \
+ \
+ DETECT_I_BYTE_CORE(TYPE,VAR,INFO,int) \
+}
+
+#define DETECT_I(TYPE,VAR,INFO) { \
+ HDcompile_assert(sizeof(TYPE) > 1); \
+ \
+ DETECT_I_BYTE_CORE(TYPE,VAR,INFO,TYPE) \
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: DETECT_F
+ *
+ * Purpose: This macro takes a floating point type like `double' and
+ * a base name like `natd' and detects byte order, mantissa
+ * location, exponent location, sign bit location, presence or
+ * absence of implicit mantissa bit, and exponent bias and
+ * initializes a detected_t structure with those properties.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 12 1996
+ *
+ *-------------------------------------------------------------------------
+ */
+#define DETECT_F(TYPE,VAR,INFO) { \
+ TYPE _v1, _v2, _v3; \
+ unsigned char _buf1[sizeof(TYPE)], _buf3[sizeof(TYPE)]; \
+ unsigned char _pad_mask[sizeof(TYPE)]; \
+ unsigned char _byte_mask; \
+ int _i, _j, _last = (-1); \
+ const char *_mesg; \
+ \
+ HDmemset(&INFO, 0, sizeof(INFO)); \
+ INFO.varname = #VAR; \
+ INFO.size = sizeof(TYPE); \
+ \
+ /* Initialize padding mask */ \
+ HDmemset(_pad_mask, 0, sizeof(_pad_mask)); \
+ \
+ /* Padding bits. Set a variable to 4.0, then flip each bit and see if \
+ * the modified variable is equal ("==") to the original. Build a \
+ * padding bitmask to indicate which bits in the type are padding (i.e. \
+ * have no effect on the value and should be ignored by subsequent \
+ * steps). This is necessary because padding bits can change arbitrarily \
+ * and interfere with detection of the various properties below unless we \
+ * know to ignore them. */ \
+ _v1 = (TYPE)4.0L; \
+ HDmemcpy(_buf1, (const void *)&_v1, sizeof(TYPE)); \
+ for(_i = 0; _i < (int)sizeof(TYPE); _i++) \
+ for(_byte_mask = (unsigned char)1; _byte_mask; _byte_mask = (unsigned char) (_byte_mask << 1)) { \
+ _buf1[_i] ^= _byte_mask; \
+ HDmemcpy((void *)&_v2, (const void *)_buf1, sizeof(TYPE)); \
+ H5_GCC_DIAG_OFF(float-equal) \
+ if(_v1 != _v2) \
+ _pad_mask[_i] |= _byte_mask; \
+ H5_GCC_DIAG_ON(float-equal) \
+ _buf1[_i] ^= _byte_mask; \
+ } /* end for */ \
+ \
+ /* Byte Order */ \
+ for(_i = 0, _v1 = (TYPE)0.0L, _v2 = (TYPE)1.0L; _i < (int)sizeof(TYPE); _i++) { \
+ _v3 = _v1; \
+ _v1 += _v2; \
+ _v2 /= (TYPE)256.0L; \
+ HDmemcpy(_buf1, (const void *)&_v1, sizeof(TYPE)); \
+ HDmemcpy(_buf3, (const void *)&_v3, sizeof(TYPE)); \
+ _j = byte_cmp(sizeof(TYPE), _buf3, _buf1, _pad_mask); \
+ if(_j >= 0) { \
+ INFO.perm[_i] = _j; \
+ _last = _i; \
+ } \
+ } \
+ fix_order(sizeof(TYPE), _last, INFO.perm, (const char**)&_mesg); \
+ \
+ if(!HDstrcmp(_mesg, "VAX")) \
+ INFO.is_vax = TRUE; \
+ \
+ /* Implicit mantissa bit */ \
+ _v1 = (TYPE)0.5L; \
+ _v2 = (TYPE)1.0L; \
+ INFO.imp = imp_bit (sizeof(TYPE), INFO.perm, &_v1, &_v2, _pad_mask); \
+ \
+ /* Sign bit */ \
+ _v1 = (TYPE)1.0L; \
+ _v2 = (TYPE)-1.0L; \
+ INFO.sign = bit_cmp (sizeof(TYPE), INFO.perm, &_v1, &_v2, _pad_mask); \
+ \
+ /* Mantissa */ \
+ INFO.mpos = 0; \
+ \
+ _v1 = (TYPE)1.0L; \
+ _v2 = (TYPE)1.5L; \
+ INFO.msize = bit_cmp (sizeof(TYPE), INFO.perm, &_v1, &_v2, _pad_mask); \
+ INFO.msize += 1 + (unsigned int) (INFO.imp ? 0 : 1) - INFO.mpos; \
+ \
+ /* Exponent */ \
+ INFO.epos = INFO.mpos + INFO.msize; \
+ \
+ INFO.esize = INFO.sign - INFO.epos; \
+ \
+ _v1 = (TYPE)1.0L; \
+ INFO.bias = find_bias (INFO.epos, INFO.esize, INFO.perm, &_v1); \
+ precision (&(INFO)); \
+ ALIGNMENT(TYPE, INFO); \
+ if(!HDstrcmp(INFO.varname, "FLOAT") || !HDstrcmp(INFO.varname, "DOUBLE") || \
+ !HDstrcmp(INFO.varname, "LDOUBLE")) { \
+ COMP_ALIGNMENT(TYPE,INFO.comp_align); \
+ } \
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: DETECT_M
+ *
+ * Purpose: This macro takes only miscellaneous structures or pointer
+ * (pointer, hvl_t, hobj_ref_t, hdset_reg_ref_t). It
+ * constructs the names and decides the alignment in structure.
+ *
+ * Return: void
+ *
+ * Programmer: Raymond Lu
+ * slu@ncsa.uiuc.edu
+ * Dec 9, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#define DETECT_M(TYPE,VAR,INFO) { \
+ INFO.name = #VAR; \
+ COMP_ALIGNMENT(TYPE, INFO.comp_align); \
+}
+
+/* Detect alignment for C structure */
+#define COMP_ALIGNMENT(TYPE,COMP_ALIGN) { \
+ struct { \
+ char c; \
+ TYPE x; \
+ } s; \
+ \
+ COMP_ALIGN = (unsigned int)((char*)(&(s.x)) - (char*)(&s)); \
+}
+
+#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL)
+#define ALIGNMENT(TYPE,INFO) { \
+ char *volatile _buf = NULL; \
+ TYPE _val = 1, _val2; \
+ volatile size_t _ano = 0; \
+ void (*_handler)(int) = HDsignal(SIGBUS, sigbus_handler); \
+ void (*_handler2)(int) = HDsignal(SIGSEGV, sigsegv_handler);\
+ void (*_handler3)(int) = HDsignal(SIGILL, sigill_handler); \
+ \
+ _buf = (char*)HDmalloc(sizeof(TYPE) + align_g[NELMTS(align_g) - 1]); \
+ if(H5SETJMP(jbuf_g)) _ano++; \
+ if(_ano < NELMTS(align_g)) { \
+ *((TYPE*)(_buf+align_g[_ano])) = _val; /*possible SIGBUS or SEGSEGV*/ \
+ _val2 = *((TYPE*)(_buf+align_g[_ano])); /*possible SIGBUS or SEGSEGV*/\
+ /* Cray Check: This section helps detect alignment on Cray's */ \
+ /* vector machines (like the SV1) which mask off */ \
+ /* pointer values when pointing to non-word aligned */ \
+ /* locations with pointers that are supposed to be */ \
+ /* word aligned. -QAK */ \
+ HDmemset(_buf, 0xff, sizeof(TYPE)+align_g[NELMTS(align_g)-1]); \
+ /*How to handle VAX types?*/ \
+ if(INFO.perm[0]) /* Big-Endian */ \
+ HDmemcpy(_buf+align_g[_ano]+(INFO.size-((INFO.offset+INFO.precision)/8)),((char *)&_val)+(INFO.size-((INFO.offset+INFO.precision)/8)),(size_t)(INFO.precision/8)); \
+ else /* Little-Endian */ \
+ HDmemcpy(_buf+align_g[_ano]+(INFO.offset/8),((char *)&_val)+(INFO.offset/8),(size_t)(INFO.precision/8)); \
+ _val2 = *((TYPE*)(_buf+align_g[_ano])); \
+ H5_GCC_DIAG_OFF(float-equal) \
+ if(_val!=_val2) \
+ H5LONGJMP(jbuf_g, 1); \
+ H5_GCC_DIAG_ON(float-equal) \
+ /* End Cray Check */ \
+ (INFO.align)=align_g[_ano]; \
+ } else { \
+ (INFO.align)=0; \
+ fprintf(stderr, "unable to calculate alignment for %s\n", #TYPE); \
+ } \
+ HDfree(_buf); \
+ HDsignal(SIGBUS, _handler); /*restore original handler*/ \
+ HDsignal(SIGSEGV, _handler2); /*restore original handler*/ \
+ HDsignal(SIGILL, _handler3); /*restore original handler*/ \
+}
+#else
+#define ALIGNMENT(TYPE,INFO) { \
+ align_status_g |= STA_NoALIGNMENT; \
+ (INFO.align)=0; \
+}
+#endif
+
+
+#if defined(H5LONGJMP) && defined(H5_HAVE_SIGNAL)
+/*-------------------------------------------------------------------------
+ * Function: sigsegv_handler
+ *
+ * Purpose: Handler for SIGSEGV. We use signal() instead of sigaction()
+ * because it's more portable to non-Posix systems. Although
+ * it's not nearly as nice to work with, it does the job for
+ * this simple stuff.
+ *
+ * Return: Returns via H5LONGJMP to jbuf_g.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, March 18, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+sigsegv_handler(int H5_ATTR_UNUSED signo)
+{
+#if !defined(H5HAVE_SIGJMP) && defined(H5_HAVE_SIGPROCMASK)
+ /* Use sigprocmask to unblock the signal if sigsetjmp/siglongjmp are not */
+ /* supported. */
+ sigset_t set;
+
+ HDsigemptyset(&set);
+ HDsigaddset(&set, SIGSEGV);
+ HDsigprocmask(SIG_UNBLOCK, &set, NULL);
+#endif
+
+ sigsegv_handler_called_g++;
+ HDsignal(SIGSEGV, sigsegv_handler);
+ H5LONGJMP(jbuf_g, SIGSEGV);
+}
+#endif
+
+
+#if defined(H5LONGJMP) && defined(H5_HAVE_SIGNAL)
+/*-------------------------------------------------------------------------
+ * Function: sigbus_handler
+ *
+ * Purpose: Handler for SIGBUS. We use signal() instead of sigaction()
+ * because it's more portable to non-Posix systems. Although
+ * it's not nearly as nice to work with, it does the job for
+ * this simple stuff.
+ *
+ * Return: Returns via H5LONGJMP to jbuf_g.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, March 18, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+sigbus_handler(int H5_ATTR_UNUSED signo)
+{
+#if !defined(H5HAVE_SIGJMP) && defined(H5_HAVE_SIGPROCMASK)
+ /* Use sigprocmask to unblock the signal if sigsetjmp/siglongjmp are not */
+ /* supported. */
+ sigset_t set;
+
+ HDsigemptyset(&set);
+ HDsigaddset(&set, SIGBUS);
+ HDsigprocmask(SIG_UNBLOCK, &set, NULL);
+#endif
+
+ sigbus_handler_called_g++;
+ HDsignal(SIGBUS, sigbus_handler);
+ H5LONGJMP(jbuf_g, SIGBUS);
+}
+#endif
+
+
+#if defined(H5LONGJMP) && defined(H5_HAVE_SIGNAL)
+/*-------------------------------------------------------------------------
+ * Function: sigill_handler
+ *
+ * Purpose: Handler for SIGILL. We use signal() instead of sigaction()
+ * because it's more portable to non-Posix systems. Although
+ * it's not nearly as nice to work with, it does the job for
+ * this simple stuff.
+ *
+ * Return: Returns via H5LONGJMP to jbuf_g.
+ *
+ * Programmer: Raymond Lu
+ * 28 October 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+sigill_handler(int H5_ATTR_UNUSED signo)
+{
+#if !defined(H5HAVE_SIGJMP) && defined(H5_HAVE_SIGPROCMASK)
+ /* Use sigprocmask to unblock the signal if sigsetjmp/siglongjmp are not */
+ /* supported. */
+ sigset_t set;
+
+ HDsigemptyset(&set);
+ HDsigaddset(&set, SIGILL);
+ HDsigprocmask(SIG_UNBLOCK, &set, NULL);
+#endif
+
+ sigill_handler_called_g++;
+ HDsignal(SIGILL, sigill_handler);
+ H5LONGJMP(jbuf_g, SIGILL);
+}
+#endif
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_results
+ *
+ * Purpose: Prints information about the detected data types.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 14, 1996
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+print_results(int nd, detected_t *d, int na, malign_t *misc_align)
+{
+ int byte_order=0; /*byte order of data types*/
+ int i, j;
+
+ /* Include files */
+ printf("\
+/****************/\n\
+/* Module Setup */\n\
+/****************/\n\
+\n\
+#include \"H5Tmodule.h\" /* This source code file is part of the H5T module */\n\
+\n\
+\n\
+/***********/\n\
+/* Headers */\n\
+/***********/\n\
+#include \"H5private.h\" /* Generic Functions */\n\
+#include \"H5Eprivate.h\" /* Error handling */\n\
+#include \"H5FLprivate.h\" /* Free Lists */\n\
+#include \"H5Iprivate.h\" /* IDs */\n\
+#include \"H5Tpkg.h\" /* Datatypes */\n\
+\n\
+\n\
+/****************/\n\
+/* Local Macros */\n\
+/****************/\n\
+\n\
+\n\
+/******************/\n\
+/* Local Typedefs */\n\
+/******************/\n\
+\n\
+\n\
+/********************/\n\
+/* Package Typedefs */\n\
+/********************/\n\
+\n\
+\n\
+/********************/\n\
+/* Local Prototypes */\n\
+/********************/\n\
+\n\
+\n\
+/********************/\n\
+/* Public Variables */\n\
+/********************/\n\
+\n\
+\n\
+/*****************************/\n\
+/* Library Private Variables */\n\
+/*****************************/\n\
+\n\
+\n\
+/*********************/\n\
+/* Package Variables */\n\
+/*********************/\n\
+\n\
+\n");
+ printf("\n\
+/*******************/\n\
+/* Local Variables */\n\
+/*******************/\n\
+\n");
+
+
+ /* The interface initialization function */
+ printf("\n\
+ \n\
+/*-------------------------------------------------------------------------\n\
+ * Function: H5T__init_native\n\
+ *\n\
+ * Purpose: Initialize pre-defined native datatypes from code generated\n\
+ * during the library configuration by H5detect.\n\
+ *\n\
+ * Return: Success: non-negative\n\
+ * Failure: negative\n\
+ *\n\
+ * Programmer: Robb Matzke\n\
+ * Wednesday, December 16, 1998\n\
+ *\n\
+ *-------------------------------------------------------------------------\n\
+ */\n\
+herr_t\n\
+H5T__init_native(void)\n\
+{\n\
+ H5T_t *dt = NULL;\n\
+ herr_t ret_value = SUCCEED;\n\
+\n\
+ FUNC_ENTER_PACKAGE\n");
+
+ for(i = 0; i < nd; i++) {
+ /* The native endianess of this machine */
+ /* The INFO.perm now contains `-1' for bytes that aren't used and
+ * are always zero. This happens on the Cray for `short' where
+ * sizeof(short) is 8, but only the low-order 4 bytes are ever used.
+ */
+ if(d[i].is_vax) /* the type is a VAX floating number */
+ byte_order=-1;
+ else {
+ for(j=0; j<32; j++) {
+ /*Find the 1st containing valid data*/
+ if(d[i].perm[j]>-1) {
+ byte_order=d[i].perm[j];
+ break;
+ }
+ }
+ }
+
+ /* Print a comment to describe this section of definitions. */
+ printf("\n /*\n");
+ iprint(d+i);
+ printf(" */\n");
+
+ /* The part common to fixed and floating types */
+ printf("\
+ if(NULL == (dt = H5T__alloc()))\n\
+ HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, FAIL, \"datatype allocation failed\")\n\
+ dt->shared->state = H5T_STATE_IMMUTABLE;\n\
+ dt->shared->type = H5T_%s;\n\
+ dt->shared->size = %d;\n",
+ d[i].msize ? "FLOAT" : "INTEGER",/*class */
+ d[i].size); /*size */
+
+ if(byte_order==-1)
+ printf("\
+ dt->shared->u.atomic.order = H5T_ORDER_VAX;\n");
+ else if(byte_order==0)
+ printf("\
+ dt->shared->u.atomic.order = H5T_ORDER_LE;\n");
+ else
+ printf("\
+ dt->shared->u.atomic.order = H5T_ORDER_BE;\n");
+
+ printf("\
+ dt->shared->u.atomic.offset = %d;\n\
+ dt->shared->u.atomic.prec = %d;\n\
+ dt->shared->u.atomic.lsb_pad = H5T_PAD_ZERO;\n\
+ dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO;\n",
+ d[i].offset, /*offset */
+ d[i].precision); /*precision */
+ /*HDassert((d[i].perm[0]>0)==(byte_order>0));*/ /* Double-check that byte-order doesn't change */
+
+ if (0 == d[i].msize) {
+ /* The part unique to fixed point types */
+ printf("\
+ dt->shared->u.atomic.u.i.sign = H5T_SGN_%s;\n",
+ d[i].sign ? "2" : "NONE");
+ } else {
+ /* The part unique to floating point types */
+ printf("\
+ dt->shared->u.atomic.u.f.sign = %d;\n\
+ dt->shared->u.atomic.u.f.epos = %d;\n\
+ dt->shared->u.atomic.u.f.esize = %d;\n\
+ dt->shared->u.atomic.u.f.ebias = 0x%08lx;\n\
+ dt->shared->u.atomic.u.f.mpos = %d;\n\
+ dt->shared->u.atomic.u.f.msize = %d;\n\
+ dt->shared->u.atomic.u.f.norm = H5T_NORM_%s;\n\
+ dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO;\n",
+ d[i].sign, /*sign location */
+ d[i].epos, /*exponent loc */
+ d[i].esize, /*exponent size */
+ (unsigned long)(d[i].bias), /*exponent bias */
+ d[i].mpos, /*mantissa loc */
+ d[i].msize, /*mantissa size */
+ d[i].imp ? "IMPLIED" : "NONE"); /*normalization */
+ }
+
+ /* Atomize the type */
+ printf("\
+ if((H5T_NATIVE_%s_g = H5I_register(H5I_DATATYPE, dt, FALSE)) < 0)\n\
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, \"can't register ID for built-in datatype\")\n",
+ d[i].varname);
+ printf(" H5T_NATIVE_%s_ALIGN_g = %lu;\n",
+ d[i].varname, (unsigned long)(d[i].align));
+
+ /* Variables for alignment of compound datatype */
+ if(!HDstrcmp(d[i].varname, "SCHAR") || !HDstrcmp(d[i].varname, "SHORT") ||
+ !HDstrcmp(d[i].varname, "INT") || !HDstrcmp(d[i].varname, "LONG") ||
+ !HDstrcmp(d[i].varname, "LLONG") || !HDstrcmp(d[i].varname, "FLOAT") ||
+ !HDstrcmp(d[i].varname, "DOUBLE") || !HDstrcmp(d[i].varname, "LDOUBLE")) {
+ printf(" H5T_NATIVE_%s_COMP_ALIGN_g = %lu;\n",
+ d[i].varname, (unsigned long)(d[i].comp_align));
+ }
+ }
+
+ /* Consider VAX a little-endian machine */
+ if(byte_order==0 || byte_order==-1) {
+ printf("\n\
+ /* Set the native order for this machine */\n\
+ H5T_native_order_g = H5T_ORDER_%s;\n", "LE");
+ } else {
+ printf("\n\
+ /* Set the native order for this machine */\n\
+ H5T_native_order_g = H5T_ORDER_%s;\n", "BE");
+ }
+
+ /* Structure alignment for pointers, hvl_t, hobj_ref_t, hdset_reg_ref_t */
+ printf("\n /* Structure alignment for pointers, hvl_t, hobj_ref_t, hdset_reg_ref_t */\n");
+ for(j=0; j<na; j++)
+ printf(" H5T_%s_COMP_ALIGN_g = %lu;\n", misc_align[j].name, (unsigned long)(misc_align[j].comp_align));
+
+ printf("\
+\n\
+done:\n\
+ if(ret_value < 0) {\n\
+ if(dt != NULL) {\n\
+ dt->shared = H5FL_FREE(H5T_shared_t, dt->shared);\n\
+ dt = H5FL_FREE(H5T_t, dt);\n\
+ } /* end if */\n\
+ } /* end if */\n\
+\n\
+ FUNC_LEAVE_NOAPI(ret_value);\n} /* end H5T__init_native() */\n");
+
+ /* Print the ALIGNMENT and signal-handling status as comments */
+ printf("\n"
+ "/****************************************/\n"
+ "/* ALIGNMENT and signal-handling status */\n"
+ "/****************************************/\n");
+ if (align_status_g & STA_NoALIGNMENT)
+ printf("/* ALIGNAMENT test is not available */\n");
+ if (align_status_g & STA_NoHandlerVerify)
+ printf("/* Signal handlers verify test is not available */\n");
+ /* The following is available in H5pubconf.h. Printing them here for */
+ /* convenience. */
+#ifdef H5_HAVE_SIGNAL
+ printf("/* Signal() support: yes */\n");
+#else
+ printf("/* Signal() support: no */\n");
+#endif
+#ifdef H5_HAVE_SETJMP
+ printf("/* setjmp() support: yes */\n");
+#else
+ printf("/* setjmp() support: no */\n");
+#endif
+#ifdef H5_HAVE_LONGJMP
+ printf("/* longjmp() support: yes */\n");
+#else
+ printf("/* longjmp() support: no */\n");
+#endif
+#ifdef H5_HAVE_SIGSETJMP
+ printf("/* sigsetjmp() support: yes */\n");
+#else
+ printf("/* sigsetjmp() support: no */\n");
+#endif
+#ifdef H5_HAVE_SIGLONGJMP
+ printf("/* siglongjmp() support: yes */\n");
+#else
+ printf("/* siglongjmp() support: no */\n");
+#endif
+#ifdef H5_HAVE_SIGPROCMASK
+ printf("/* sigprocmask() support: yes */\n");
+#else
+ printf("/* sigprocmask() support: no */\n");
+#endif
+
+ /* Print the statics of signal handlers called for debugging */
+ printf("\n"
+ "/******************************/\n"
+ "/* signal handlers statistics */\n"
+ "/******************************/\n");
+ printf("/* signal_handlers tested: %d times */\n", signal_handler_tested_g);
+ printf("/* sigbus_handler called: %d times */\n", sigbus_handler_called_g);
+ printf("/* sigsegv_handler called: %d times */\n", sigsegv_handler_called_g);
+ printf("/* sigill_handler called: %d times */\n", sigill_handler_called_g);
+} /* end print_results() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: iprint
+ *
+ * Purpose: Prints information about the fields of a floating point
+ * format.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 13, 1996
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+iprint(detected_t *d)
+{
+ unsigned int pass;
+
+ for (pass = (d->size - 1) / 4; ; --pass) {
+ unsigned int i, k;
+ /*
+ * Print the byte ordering above the bit fields.
+ */
+ printf(" * ");
+ for (i = MIN(pass * 4 + 3, d->size - 1); i >= pass * 4; --i) {
+ printf("%4d", d->perm[i]);
+ if (i > pass * 4) HDfputs(" ", stdout);
+ if (!i) break;
+ }
+
+ /*
+ * Print the bit fields
+ */
+ printf("\n * ");
+ for (i = MIN(pass * 4 + 3, d->size - 1), k = MIN(pass * 32 + 31,
+ 8 * d->size - 1); i >= pass * 4; --i) {
+ unsigned int j;
+
+ for (j = 8; j > 0; --j) {
+ if (k == d->sign && d->msize) {
+ HDputchar('S');
+ } else if (k >= d->epos && k < d->epos + d->esize) {
+ HDputchar('E');
+ } else if (k >= d->mpos && k < d->mpos + d->msize) {
+ HDputchar('M');
+ } else if (d->msize) {
+ HDputchar('?'); /*unknown floating point bit */
+ } else if (d->sign) {
+ HDputchar('I');
+ } else {
+ HDputchar('U');
+ }
+ --k;
+ }
+ if (i > pass * 4) HDputchar(' ');
+ if (!i) break;
+ }
+ HDputchar('\n');
+ if (!pass) break;
+ }
+
+ /*
+ * Is there an implicit bit in the mantissa.
+ */
+ if (d->msize) {
+ printf(" * Implicit bit? %s\n", d->imp ? "yes" : "no");
+ }
+
+ /*
+ * Alignment
+ */
+ if (0 == d->align) {
+ printf(" * Alignment: NOT CALCULATED\n");
+ } else if (1 == d->align) {
+ printf(" * Alignment: none\n");
+ } else {
+ printf(" * Alignment: %lu\n", (unsigned long) (d->align));
+ }
+
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: byte_cmp
+ *
+ * Purpose: Compares two chunks of memory A and B and returns the
+ * byte index into those arrays of the first byte that
+ * differs between A and B. Ignores differences where the
+ * corresponding bit in pad_mask is set to 0.
+ *
+ * Return: Success: Index of differing byte.
+ *
+ * Failure: -1 if all bytes are the same.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 12, 1996
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+byte_cmp(int n, const void *_a, const void *_b, const unsigned char *pad_mask)
+{
+ int i;
+ const unsigned char *a = (const unsigned char *) _a;
+ const unsigned char *b = (const unsigned char *) _b;
+
+ for(i = 0; i < n; i++)
+ if((a[i] & pad_mask[i]) != (b[i] & pad_mask[i]))
+ return i;
+
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: bit_cmp
+ *
+ * Purpose: Compares two bit vectors and returns the index for the
+ * first bit that differs between the two vectors. The
+ * size of the vector is NBYTES. PERM is a mapping from
+ * actual order to little endian. Ignores differences where
+ * the corresponding bit in pad_mask is set to 0.
+ *
+ * Return: Index of first differing bit.
+ *
+ *-------------------------------------------------------------------------
+ */
+static unsigned int
+bit_cmp(unsigned int nbytes, int *perm, void *_a, void *_b,
+ const unsigned char *pad_mask)
+{
+ unsigned int i;
+ unsigned char *a = (unsigned char *) _a;
+ unsigned char *b = (unsigned char *) _b;
+ unsigned char aa, bb;
+
+ for (i = 0; i < nbytes; i++) {
+ HDassert(perm[i] < (int) nbytes);
+ if ((aa = (unsigned char) (a[perm[i]] & pad_mask[perm[i]]))
+ != (bb = (unsigned char) (b[perm[i]] & pad_mask[perm[i]]))) {
+ unsigned int j;
+
+ for (j = 0; j < 8; j++, aa >>= 1, bb >>= 1) {
+ if ((aa & 1) != (bb & 1)) return i * 8 + j;
+ }
+ fprintf(stderr, "INTERNAL ERROR");
+ HDabort();
+ }
+ }
+ fprintf(stderr, "INTERNAL ERROR");
+ HDabort();
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: fix_order
+ *
+ * Purpose: Given an array PERM with elements FIRST through LAST
+ * initialized with zero origin byte numbers, this function
+ * creates a permutation vector that maps the actual order
+ * of a floating point number to little-endian.
+ *
+ * This function assumes that the mantissa byte ordering
+ * implies the total ordering.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 13, 1996
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+fix_order(int n, int last, int *perm, const char **mesg)
+{
+ int i;
+
+ if (last > 1) {
+ /*
+ * We have at least three points to consider.
+ */
+ if (perm[last] < perm[last - 1] && perm[last - 1] < perm[last - 2]) {
+ /*
+ * Little endian.
+ */
+ if (mesg) *mesg = "Little-endian";
+ for (i = 0; i < n; i++) perm[i] = i;
+
+ } else if (perm[last] > perm[last-1] && perm[last-1] > perm[last-2]) {
+ /*
+ * Big endian.
+ */
+ if (mesg) *mesg = "Big-endian";
+ for (i = 0; i < n; i++) perm[i] = (n - 1) - i;
+
+ } else {
+ /*
+ * Bi-endian machines like VAX.
+ * (NOTE: This is not an actual determination of the VAX-endianess.
+ * It could have some other endianess and fall into this
+ * case - JKM & QAK)
+ */
+ HDassert(0 == n % 2);
+ if (mesg) *mesg = "VAX";
+ for (i = 0; i < n; i += 2) {
+ perm[i] = (n - 2) - i;
+ perm[i + 1] = (n - 1) - i;
+ }
+ }
+ } else {
+ fprintf(stderr,
+ "Failed to detect byte order of %d-byte floating point.\n", n);
+ HDexit(1);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: imp_bit
+ *
+ * Purpose: Looks for an implicit bit in the mantissa. The value
+ * of _A should be 1.0 and the value of _B should be 0.5.
+ * Some floating-point formats discard the most significant
+ * bit of the mantissa after normalizing since it will always
+ * be a one (except for 0.0). If this is true for the native
+ * floating point values stored in _A and _B then the function
+ * returns non-zero.
+ *
+ * This function assumes that the exponent occupies higher
+ * order bits than the mantissa and that the most significant
+ * bit of the mantissa is next to the least signficant bit
+ * of the exponent.
+ *
+ *
+ * Return: Success: Non-zero if the most significant bit
+ * of the mantissa is discarded (ie, the
+ * mantissa has an implicit `one' as the
+ * most significant bit). Otherwise,
+ * returns zero.
+ *
+ * Failure: exit(1)
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 13, 1996
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 6 Nov 1996
+ * Fixed a bug that occurs with non-implicit architectures.
+ *
+ *-------------------------------------------------------------------------
+ */
+static unsigned int
+imp_bit(unsigned int n, int *perm, void *_a, void *_b, const unsigned char *pad_mask)
+{
+ unsigned char *a = (unsigned char *) _a;
+ unsigned char *b = (unsigned char *) _b;
+ unsigned int changed, major, minor;
+ unsigned int msmb; /* most significant mantissa bit */
+
+ /*
+ * Look for the least significant bit that has changed between
+ * A and B. This is the least significant bit of the exponent.
+ */
+ changed = bit_cmp(n, perm, a, b, pad_mask);
+
+ /*
+ * The bit to the right (less significant) of the changed bit should
+ * be the most significant bit of the mantissa. If it is non-zero
+ * then the format does not remove the leading `1' of the mantissa.
+ */
+ msmb = changed - 1;
+ major = msmb / 8;
+ minor = msmb % 8;
+
+ return (a[perm[major]] >> minor) & 0x01 ? 0 : 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: find_bias
+ *
+ * Purpose: Determines the bias of the exponent. This function should
+ * be called with _A having a value of `1'.
+ *
+ * Return: Success: The exponent bias.
+ *
+ * Failure:
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 13, 1996
+ *
+ * Modifications:
+ *
+ * Robb Matzke, 6 Nov 1996
+ * Fixed a bug with non-implicit architectures returning the
+ * wrong exponent bias.
+ *
+ *-------------------------------------------------------------------------
+ */
+H5_ATTR_PURE static unsigned int
+find_bias(unsigned int epos, unsigned int esize, int *perm, void *_a)
+{
+ unsigned char *a = (unsigned char *) _a;
+ unsigned char mask;
+ unsigned int b, shift = 0, nbits, bias = 0;
+
+ while (esize > 0) {
+ nbits = MIN(esize, (8 - epos % 8));
+ mask = (unsigned char) ((1 << nbits) - 1);
+ b = (unsigned int) (a[perm[epos / 8]] >> (epos % 8)) & mask;
+ bias |= b << shift;
+
+ shift += nbits;
+ esize -= nbits;
+ epos += nbits;
+ }
+ return bias;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_header
+ *
+ * Purpose: Prints the C file header for the generated file.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Mar 12 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+print_header(void)
+{
+
+ time_t now = HDtime(NULL);
+ struct tm *tm = HDlocaltime(&now);
+ char real_name[30];
+ char host_name[256];
+ int i;
+ const char *s;
+#ifdef H5_HAVE_GETPWUID
+ struct passwd *pwd = NULL;
+#else
+ int pwd = 1;
+#endif
+ static const char *month_name[] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ static const char *purpose = "\
+This machine-generated source code contains\n\
+information about the various integer and\n\
+floating point numeric formats found on this\n\
+architecture. The parameters below should be\n\
+checked carefully and errors reported to the\n\
+HDF5 maintainer.\n\
+\n\
+Each of the numeric formats listed below are\n\
+printed from most significant bit to least\n\
+significant bit even though the actual bytes\n\
+might be stored in a different order in\n\
+memory. The integers above each binary byte\n\
+indicate the relative order of the bytes in\n\
+memory; little-endian machines have\n\
+decreasing numbers while big-endian machines\n\
+have increasing numbers.\n\
+\n\
+The fields of the numbers are printed as\n\
+letters with `S' for the mantissa sign bit,\n\
+`M' for the mantissa magnitude, and `E' for\n\
+the exponent. The exponent has an associated\n\
+bias which can be subtracted to find the\n\
+true exponent. The radix point is assumed\n\
+to be before the first `M' bit. Any bit\n\
+of a floating-point value not falling into one\n\
+of these categories is printed as a question\n\
+mark. Bits of integer types are printed as\n\
+`I' for 2's complement and `U' for magnitude.\n\
+\n\
+If the most significant bit of the normalized\n\
+mantissa (always a `1' except for `0.0') is\n\
+not stored then an `implicit=yes' appears\n\
+under the field description. In thie case,\n\
+the radix point is still assumed to be\n\
+before the first `M' but after the implicit\n\
+bit.\n";
+
+ /*
+ * The real name is the first item from the passwd gecos field.
+ */
+#ifdef H5_HAVE_GETPWUID
+ {
+ size_t n;
+ char *comma;
+ if ((pwd = HDgetpwuid(HDgetuid()))) {
+ if ((comma = HDstrchr(pwd->pw_gecos, ','))) {
+ n = MIN(sizeof(real_name)-1, (unsigned)(comma-pwd->pw_gecos));
+ HDstrncpy(real_name, pwd->pw_gecos, n);
+ real_name[n] = '\0';
+ } else {
+ HDstrncpy(real_name, pwd->pw_gecos, sizeof(real_name));
+ real_name[sizeof(real_name) - 1] = '\0';
+ }
+ } else {
+ real_name[0] = '\0';
+ }
+ }
+#else
+ real_name[0] = '\0';
+#endif
+
+ /*
+ * The FQDM of this host or the empty string.
+ */
+#ifdef H5_HAVE_GETHOSTNAME
+ if (HDgethostname(host_name, sizeof(host_name)) < 0) {
+ host_name[0] = '\0';
+ }
+#else
+ host_name[0] = '\0';
+#endif
+
+ /*
+ * The file header: warning, copyright notice, build information.
+ */
+ printf("/* Generated automatically by H5detect -- do not edit */\n\n\n");
+ HDputs(FileHeader); /*the copyright notice--see top of this file */
+
+ printf(" *\n * Created:\t\t%s %2d, %4d\n",
+ month_name[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year);
+ if (pwd || real_name[0] || host_name[0]) {
+ printf(" *\t\t\t");
+ if (real_name[0]) printf("%s <", real_name);
+#ifdef H5_HAVE_GETPWUID
+ if (pwd) HDfputs(pwd->pw_name, stdout);
+#endif
+ if (host_name[0]) printf("@%s", host_name);
+ if (real_name[0]) printf(">");
+ HDputchar('\n');
+ }
+ printf(" *\n * Purpose:\t\t");
+ for (s = purpose; *s; s++) {
+ HDputchar(*s);
+ if ('\n' == *s && s[1]) printf(" *\t\t\t");
+ }
+
+ printf(" *\n * Modifications:\n *\n");
+ printf(" *\tDO NOT MAKE MODIFICATIONS TO THIS FILE!\n");
+ printf(" *\tIt was generated by code in `H5detect.c'.\n");
+
+ printf(" *\n *");
+ for (i = 0; i < 73; i++) HDputchar('-');
+ printf("\n */\n\n");
+
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C89_integers
+ *
+ * Purpose: Detect C89 integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C89_integers(void)
+{
+ DETECT_BYTE(signed char, SCHAR, d_g[nd_g]); nd_g++;
+ DETECT_BYTE(unsigned char, UCHAR, d_g[nd_g]); nd_g++;
+ DETECT_I(short, SHORT, d_g[nd_g]); nd_g++;
+ DETECT_I(unsigned short, USHORT, d_g[nd_g]); nd_g++;
+ DETECT_I(int, INT, d_g[nd_g]); nd_g++;
+ DETECT_I(unsigned int, UINT, d_g[nd_g]); nd_g++;
+ DETECT_I(long, LONG, d_g[nd_g]); nd_g++;
+ DETECT_I(unsigned long, ULONG, d_g[nd_g]); nd_g++;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C89_floats
+ *
+ * Purpose: Detect C89 floating point types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C89_floats(void)
+{
+ DETECT_F(float, FLOAT, d_g[nd_g]); nd_g++;
+ DETECT_F(double, DOUBLE, d_g[nd_g]); nd_g++;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_integers8
+ *
+ * Purpose: Detect C99 8 bit integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_integers8(void)
+{
+#if H5_SIZEOF_INT8_T>0
+ #if H5_SIZEOF_INT8_T==1
+ DETECT_BYTE(int8_t, INT8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(int8_t, INT8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+#if H5_SIZEOF_UINT8_T>0
+ #if H5_SIZEOF_UINT8_T==1
+ DETECT_BYTE(uint8_t, UINT8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(uint8_t, UINT8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+#if H5_SIZEOF_INT_LEAST8_T>0
+ #if H5_SIZEOF_INT_LEAST8_T==1
+ DETECT_BYTE(int_least8_t, INT_LEAST8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(int_least8_t, INT_LEAST8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+#if H5_SIZEOF_UINT_LEAST8_T>0
+ #if H5_SIZEOF_UINT_LEAST8_T==1
+ DETECT_BYTE(uint_least8_t, UINT_LEAST8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(uint_least8_t, UINT_LEAST8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+#if H5_SIZEOF_INT_FAST8_T>0
+ #if H5_SIZEOF_INT_FAST8_T==1
+ DETECT_BYTE(int_fast8_t, INT_FAST8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(int_fast8_t, INT_FAST8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+#if H5_SIZEOF_UINT_FAST8_T>0
+ #if H5_SIZEOF_UINT_FAST8_T==1
+ DETECT_BYTE(uint_fast8_t, UINT_FAST8, d_g[nd_g]); nd_g++;
+ #else
+ DETECT_I(uint_fast8_t, UINT_FAST8, d_g[nd_g]); nd_g++;
+ #endif
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_integers16
+ *
+ * Purpose: Detect C99 16 bit integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_integers16(void)
+{
+#if H5_SIZEOF_INT16_T>0
+ DETECT_I(int16_t, INT16, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT16_T>0
+ DETECT_I(uint16_t, UINT16, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_LEAST16_T>0
+ DETECT_I(int_least16_t, INT_LEAST16, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_LEAST16_T>0
+ DETECT_I(uint_least16_t, UINT_LEAST16, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_FAST16_T>0
+ DETECT_I(int_fast16_t, INT_FAST16, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_FAST16_T>0
+ DETECT_I(uint_fast16_t, UINT_FAST16, d_g[nd_g]); nd_g++;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_integers32
+ *
+ * Purpose: Detect C99 32 bit integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_integers32(void)
+{
+#if H5_SIZEOF_INT32_T>0
+ DETECT_I(int32_t, INT32, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT32_T>0
+ DETECT_I(uint32_t, UINT32, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_LEAST32_T>0
+ DETECT_I(int_least32_t, INT_LEAST32, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_LEAST32_T>0
+ DETECT_I(uint_least32_t, UINT_LEAST32, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_FAST32_T>0
+ DETECT_I(int_fast32_t, INT_FAST32, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_FAST32_T>0
+ DETECT_I(uint_fast32_t, UINT_FAST32, d_g[nd_g]); nd_g++;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_integers64
+ *
+ * Purpose: Detect C99 64 bit integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_integers64(void)
+{
+#if H5_SIZEOF_INT64_T>0
+ DETECT_I(int64_t, INT64, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT64_T>0
+ DETECT_I(uint64_t, UINT64, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_LEAST64_T>0
+ DETECT_I(int_least64_t, INT_LEAST64, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_LEAST64_T>0
+ DETECT_I(uint_least64_t, UINT_LEAST64, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_INT_FAST64_T>0
+ DETECT_I(int_fast64_t, INT_FAST64, d_g[nd_g]); nd_g++;
+#endif
+#if H5_SIZEOF_UINT_FAST64_T>0
+ DETECT_I(uint_fast64_t, UINT_FAST64, d_g[nd_g]); nd_g++;
+#endif
+
+#if H5_SIZEOF_LONG_LONG>0
+ DETECT_I(long long, LLONG, d_g[nd_g]); nd_g++;
+ DETECT_I(unsigned long long, ULLONG, d_g[nd_g]); nd_g++;
+#else
+ /*
+ * This architecture doesn't support an integer type larger than `long'
+ * so we'll just make H5T_NATIVE_LLONG the same as H5T_NATIVE_LONG since
+ * `long long' is probably equivalent to `long' here anyway.
+ */
+ DETECT_I(long, LLONG, d_g[nd_g]); nd_g++;
+ DETECT_I(unsigned long, ULLONG, d_g[nd_g]); nd_g++;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_integers
+ *
+ * Purpose: Detect C99 integer types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_integers(void)
+{
+ /* break it down to more subroutines so that each module subroutine */
+ /* is smaller and takes less time to compile with optimization on. */
+ detect_C99_integers8();
+ detect_C99_integers16();
+ detect_C99_integers32();
+ detect_C99_integers64();
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_C99_floats
+ *
+ * Purpose: Detect C99 floating point types
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_C99_floats(void)
+{
+#if H5_SIZEOF_DOUBLE == H5_SIZEOF_LONG_DOUBLE
+ /*
+ * If sizeof(double)==sizeof(long double) then assume that `long double'
+ * isn't supported and use `double' instead. This suppresses warnings on
+ * some systems and `long double' is probably the same as `double' here
+ * anyway.
+ */
+ DETECT_F(double, LDOUBLE, d_g[nd_g]); nd_g++;
+#elif H5_SIZEOF_LONG_DOUBLE !=0
+ DETECT_F(long double, LDOUBLE, d_g[nd_g]); nd_g++;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: detect_alignments
+ *
+ * Purpose: Detect structure alignments
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * 2004/05/20
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+detect_alignments(void)
+{
+ /* Detect structure alignment for pointers, hvl_t, hobj_ref_t, hdset_reg_ref_t */
+ DETECT_M(void *, POINTER, m_g[na_g]); na_g++;
+ DETECT_M(hvl_t, HVL, m_g[na_g]); na_g++;
+ DETECT_M(hobj_ref_t, HOBJREF, m_g[na_g]); na_g++;
+ DETECT_M(hdset_reg_ref_t, HDSETREGREF, m_g[na_g]); na_g++;
+}
+
+
+#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL)
+/* Verify the signal handler for signal signum works correctly multiple times.
+ * One possible cause of failure is that the signal handling is blocked or
+ * changed to SIG_DFL after H5LONGJMP.
+ * Return 0 for success, -1 for failure.
+ */
+static int verify_signal_handlers(int signum, void (*handler)(int))
+{
+ void (*save_handler)(int) = HDsignal(signum, handler);
+ volatile int i, val;
+ int ntries=5;
+ volatile int nfailures=0;
+ volatile int nsuccesses=0;
+
+ for (i=0;i<ntries; i++){
+ val=H5SETJMP(jbuf_g);
+ if (val==0)
+ {
+ /* send self the signal to trigger the handler */
+ signal_handler_tested_g++;
+ HDraise(signum);
+ /* Should not reach here. Record error. */
+ nfailures++;
+ }else{
+ if (val==signum){
+ /* return from signum handler. Record a sucess. */
+ nsuccesses++;
+ }else{
+ fprintf(stderr, "Unknown return value (%d) from H5SETJMP",
+ val);
+ nfailures++;
+ }
+ }
+ }
+ /* restore save handler, check results and report failures */
+ HDsignal(signum, save_handler);
+ if (nfailures>0 || nsuccesses != ntries){
+ fprintf(stderr, "verify_signal_handlers for signal %d did %d tries. "
+ "Found %d failures and %d successes\n",
+ signum, ntries, nfailures, nsuccesses);
+ return(-1);
+ }else{
+ /* all succeeded */
+ return(0);
+ }
+}
+#endif
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Main entry point.
+ *
+ * Return: Success: exit(0)
+ *
+ * Failure: exit(1)
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Jun 12, 1996
+ *
+ * Modifications:
+ * Albert Cheng, 2004/05/20
+ * Some compilers, e.g., Intel C v7.0, took a long time to compile
+ * with optimization when a module routine contains many code lines.
+ * Divide up all those types detections macros into subroutines, both
+ * to avoid the compiler optimization error and cleaner codes.
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+
+#if defined(H5_HAVE_SETSYSINFO) && defined(SSI_NVPAIRS)
+#if defined(UAC_NOPRINT) && defined(UAC_SIGBUS)
+ /*
+ * Make sure unaligned access generates SIGBUS and doesn't print warning
+ * messages so that we can detect alignment constraints on the DEC Alpha.
+ */
+ int nvpairs[2];
+ nvpairs[0] = SSIN_UACPROC;
+ nvpairs[1] = UAC_NOPRINT | UAC_SIGBUS;
+ if (setsysinfo(SSI_NVPAIRS, nvpairs, 1, 0, 0)<0) {
+ fprintf(stderr, "H5detect: unable to turn off UAC handling: %s\n",
+ HDstrerror(errno));
+ }
+#endif
+#endif
+
+#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL)
+ /* verify the SIGBUS and SIGSEGV handlers work properly */
+ if (verify_signal_handlers(SIGBUS, sigbus_handler) != 0) {
+ fprintf(stderr, "Signal handler %s for signal %d failed\n",
+ "sigbus_handler", SIGBUS);
+ }
+ if (verify_signal_handlers(SIGSEGV, sigsegv_handler) != 0) {
+ fprintf(stderr, "Signal handler %s for signal %d failed\n",
+ "sigsegv_handler", SIGSEGV);
+ }
+ if (verify_signal_handlers(SIGILL, sigill_handler) != 0) {
+ fprintf(stderr, "Signal handler %s for signal %d failed\n",
+ "sigill_handler", SIGILL);
+ }
+#else
+ align_status_g |= STA_NoHandlerVerify;
+#endif
+
+ print_header();
+
+ /* C89 integer types */
+ detect_C89_integers();
+
+ /* C99 integer types */
+ detect_C99_integers();
+
+ /* C89 floating point types */
+ detect_C89_floats();
+
+ /* C99 floating point types */
+ detect_C99_floats();
+
+ /* Detect structure alignment */
+ detect_alignments();
+
+ print_results (nd_g, d_g, na_g, m_g);
+
+ return 0;
+}
diff --git a/src/H5err.txt b/src/H5err.txt
new file mode 100644
index 0000000..3f5801f
--- /dev/null
+++ b/src/H5err.txt
@@ -0,0 +1,275 @@
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the COPYING file, which can be found at the root of the source code
+# distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
+# If you do not have access to either file, you may request a copy from
+# help@hdfgroup.org.
+#
+
+# This file is used to generate the various headers that are needed for the
+# error API. The bin/make_err script reads in this file and creates the
+# appropriate files in the src/ directory when the generated headers are out
+# of date with respect to this file.
+#
+# Blank lines and lines beginning with '#' are ignored
+#
+# The format of this file is as follows:
+# <type>,<major section, if minor type, otherwise omitted>,<name>,<description>
+#
+# For example, the following sample input shows two major errors and two minor
+# errors in each section:
+#
+# MAJOR, H5E_ARGS, Invalid arguments to routine
+# MAJOR, H5E_RESOURCE, Resource unavailable
+#
+# SECTION, ARGS, Argument errors
+# SECTION, RESOURCE, Resource errors
+#
+# MINOR, ARGS, H5E_UNINITIALIZED, Information is uinitialized
+# MINOR, ARGS, H5E_UNSUPPORTED, Feature is unsupported
+# MINOR, RESOURCE, H5E_NOSPACE, No space available for allocation
+# MINOR, RESOURCE, H5E_CANTCOPY, unable to copy object
+#
+# The section information is just used for grouping the information in the
+# files created and can have any value. They generally correspond to the
+# major errors, but don't have to. The section definition for each minor error
+# must come before any minor error that uses it.
+#
+# Programmer: Quincey Koziol
+# Creation Date: 2003/08/12
+
+# Major errors
+MAJOR, H5E_ARGS, Invalid arguments to routine
+MAJOR, H5E_RESOURCE, Resource unavailable
+MAJOR, H5E_INTERNAL, Internal error (too specific to document in detail)
+MAJOR, H5E_FILE, File accessibilty
+MAJOR, H5E_IO, Low-level I/O
+MAJOR, H5E_FUNC, Function entry/exit
+MAJOR, H5E_ATOM, Object atom
+MAJOR, H5E_CACHE, Object cache
+MAJOR, H5E_LINK, Links
+MAJOR, H5E_BTREE, B-Tree node
+MAJOR, H5E_SYM, Symbol table
+MAJOR, H5E_HEAP, Heap
+MAJOR, H5E_OHDR, Object header
+MAJOR, H5E_DATATYPE, Datatype
+MAJOR, H5E_DATASPACE, Dataspace
+MAJOR, H5E_DATASET, Dataset
+MAJOR, H5E_STORAGE, Data storage
+MAJOR, H5E_PLIST, Property lists
+MAJOR, H5E_ATTR, Attribute
+MAJOR, H5E_PLINE, Data filters
+MAJOR, H5E_EFL, External file list
+MAJOR, H5E_REFERENCE, References
+MAJOR, H5E_VFL, Virtual File Layer
+MAJOR, H5E_TST, Ternary Search Trees
+MAJOR, H5E_RS, Reference Counted Strings
+MAJOR, H5E_ERROR, Error API
+MAJOR, H5E_SLIST, Skip Lists
+MAJOR, H5E_FSPACE, Free Space Manager
+MAJOR, H5E_SOHM, Shared Object Header Messages
+MAJOR, H5E_EARRAY, Extensible Array
+MAJOR, H5E_FARRAY, Fixed Array
+MAJOR, H5E_PLUGIN, Plugin for dynamically loaded library
+MAJOR, H5E_PAGEBUF, Page Buffering
+MAJOR, H5E_NONE_MAJOR, No error
+
+# Sections (for grouping minor errors)
+SECTION, ARGS, Argument errors
+SECTION, RESOURCE, Resource errors
+SECTION, FILEACC, File accessibilty errors
+SECTION, FILE, Generic low-level file I/O errors
+SECTION, FUNC, Function entry/exit interface errors
+SECTION, ATOM, Object atom related errors
+SECTION, CACHE, Cache related errors
+SECTION, LINK, Link related errors
+SECTION, BTREE, B-tree related errors
+SECTION, OHDR, Object header related errors
+SECTION, GROUP, Group related errors
+SECTION, TYPECONV, Datatype conversion errors
+SECTION, DSPACE, Dataspace errors
+SECTION, PLIST, Property list errors
+SECTION, MPI, Parallel MPI errors
+SECTION, HEAP, Heap errors
+SECTION, FSPACE, Free space errors
+SECTION, PIPELINE, I/O pipeline errors
+SECTION, SYSTEM, System level errors
+SECTION, PLUGIN, Plugin errors
+SECTION, NONE, No error
+
+# Minor errors
+
+# Argument errors
+MINOR, ARGS, H5E_UNINITIALIZED, Information is uinitialized
+MINOR, ARGS, H5E_UNSUPPORTED, Feature is unsupported
+MINOR, ARGS, H5E_BADTYPE, Inappropriate type
+MINOR, ARGS, H5E_BADRANGE, Out of range
+MINOR, ARGS, H5E_BADVALUE, Bad value
+
+# Resource errors
+MINOR, RESOURCE, H5E_NOSPACE, No space available for allocation
+MINOR, RESOURCE, H5E_CANTALLOC, Can't allocate space
+MINOR, RESOURCE, H5E_CANTCOPY, Unable to copy object
+MINOR, RESOURCE, H5E_CANTFREE, Unable to free object
+MINOR, RESOURCE, H5E_ALREADYEXISTS, Object already exists
+MINOR, RESOURCE, H5E_CANTLOCK, Unable to lock object
+MINOR, RESOURCE, H5E_CANTUNLOCK, Unable to unlock object
+MINOR, RESOURCE, H5E_CANTGC, Unable to garbage collect
+MINOR, RESOURCE, H5E_CANTGETSIZE, Unable to compute size
+MINOR, RESOURCE, H5E_OBJOPEN, Object is already open
+
+# File accessibilty errors
+MINOR, FILEACC, H5E_FILEEXISTS, File already exists
+MINOR, FILEACC, H5E_FILEOPEN, File already open
+MINOR, FILEACC, H5E_CANTCREATE, Unable to create file
+MINOR, FILEACC, H5E_CANTOPENFILE, Unable to open file
+MINOR, FILEACC, H5E_CANTCLOSEFILE, Unable to close file
+MINOR, FILEACC, H5E_NOTHDF5, Not an HDF5 file
+MINOR, FILEACC, H5E_BADFILE, Bad file ID accessed
+MINOR, FILEACC, H5E_TRUNCATED, File has been truncated
+MINOR, FILEACC, H5E_MOUNT, File mount error
+
+# Generic low-level file I/O errors
+MINOR, FILE, H5E_SEEKERROR, Seek failed
+MINOR, FILE, H5E_READERROR, Read failed
+MINOR, FILE, H5E_WRITEERROR, Write failed
+MINOR, FILE, H5E_CLOSEERROR, Close failed
+MINOR, FILE, H5E_OVERFLOW, Address overflowed
+MINOR, FILE, H5E_FCNTL, File control (fcntl) failed
+
+# Function entry/exit interface errors
+MINOR, FUNC, H5E_CANTINIT, Unable to initialize object
+MINOR, FUNC, H5E_ALREADYINIT, Object already initialized
+MINOR, FUNC, H5E_CANTRELEASE, Unable to release object
+
+# Object atom related errors
+MINOR, ATOM, H5E_BADATOM, Unable to find atom information (already closed?)
+MINOR, ATOM, H5E_BADGROUP, Unable to find ID group information
+MINOR, ATOM, H5E_CANTREGISTER, Unable to register new atom
+MINOR, ATOM, H5E_CANTINC, Unable to increment reference count
+MINOR, ATOM, H5E_CANTDEC, Unable to decrement reference count
+MINOR, ATOM, H5E_NOIDS, Out of IDs for group
+
+# Cache related errors
+MINOR, CACHE, H5E_CANTFLUSH, Unable to flush data from cache
+MINOR, CACHE, H5E_CANTUNSERIALIZE, Unable to mark metadata as unserialized
+MINOR, CACHE, H5E_CANTSERIALIZE, Unable to serialize data from cache
+MINOR, CACHE, H5E_CANTTAG, Unable to tag metadata in the cache
+MINOR, CACHE, H5E_CANTLOAD, Unable to load metadata into cache
+MINOR, CACHE, H5E_PROTECT, Protected metadata error
+MINOR, CACHE, H5E_NOTCACHED, Metadata not currently cached
+MINOR, CACHE, H5E_SYSTEM, Internal error detected
+MINOR, CACHE, H5E_CANTINS, Unable to insert metadata into cache
+MINOR, CACHE, H5E_CANTPROTECT, Unable to protect metadata
+MINOR, CACHE, H5E_CANTUNPROTECT, Unable to unprotect metadata
+MINOR, CACHE, H5E_CANTPIN, Unable to pin cache entry
+MINOR, CACHE, H5E_CANTUNPIN, Unable to un-pin cache entry
+MINOR, CACHE, H5E_CANTMARKDIRTY, Unable to mark a pinned entry as dirty
+MINOR, CACHE, H5E_CANTMARKCLEAN, Unable to mark a pinned entry as clean
+MINOR, CACHE, H5E_CANTMARKUNSERIALIZED, Unable to mark an entry as unserialized
+MINOR, CACHE, H5E_CANTMARKSERIALIZED, Unable to mark an entry as serialized
+MINOR, CACHE, H5E_CANTDIRTY, Unable to mark metadata as dirty
+MINOR, CACHE, H5E_CANTCLEAN, Unable to mark metadata as clean
+MINOR, CACHE, H5E_CANTEXPUNGE, Unable to expunge a metadata cache entry
+MINOR, CACHE, H5E_CANTRESIZE, Unable to resize a metadata cache entry
+MINOR, CACHE, H5E_CANTDEPEND, Unable to create a flush dependency
+MINOR, CACHE, H5E_CANTUNDEPEND, Unable to destroy a flush dependency
+MINOR, CACHE, H5E_CANTNOTIFY, Unable to notify object about action
+MINOR, CACHE, H5E_LOGFAIL, Failure in the cache logging framework
+MINOR, CACHE, H5E_CANTCORK, Unable to cork an object
+MINOR, CACHE, H5E_CANTUNCORK, Unable to uncork an object
+
+# B-tree related errors
+MINOR, BTREE, H5E_NOTFOUND, Object not found
+MINOR, BTREE, H5E_EXISTS, Object already exists
+MINOR, BTREE, H5E_CANTENCODE, Unable to encode value
+MINOR, BTREE, H5E_CANTDECODE, Unable to decode value
+MINOR, BTREE, H5E_CANTSPLIT, Unable to split node
+MINOR, BTREE, H5E_CANTREDISTRIBUTE, Unable to redistribute records
+MINOR, BTREE, H5E_CANTSWAP, Unable to swap records
+MINOR, BTREE, H5E_CANTINSERT, Unable to insert object
+MINOR, BTREE, H5E_CANTLIST, Unable to list node
+MINOR, BTREE, H5E_CANTMODIFY, Unable to modify record
+MINOR, BTREE, H5E_CANTREMOVE, Unable to remove object
+
+# Object header related errors
+MINOR, OHDR, H5E_LINKCOUNT, Bad object header link count
+MINOR, OHDR, H5E_VERSION, Wrong version number
+MINOR, OHDR, H5E_ALIGNMENT, Alignment error
+MINOR, OHDR, H5E_BADMESG, Unrecognized message
+MINOR, OHDR, H5E_CANTDELETE, Can't delete message
+MINOR, OHDR, H5E_BADITER, Iteration failed
+MINOR, OHDR, H5E_CANTPACK, Can't pack messages
+MINOR, OHDR, H5E_CANTRESET, Can't reset object
+MINOR, OHDR, H5E_CANTRENAME, Unable to rename object
+
+# Group related errors
+MINOR, GROUP, H5E_CANTOPENOBJ, Can't open object
+MINOR, GROUP, H5E_CANTCLOSEOBJ, Can't close object
+MINOR, GROUP, H5E_COMPLEN, Name component is too long
+MINOR, GROUP, H5E_PATH, Problem with path to object
+
+# Datatype conversion errors
+MINOR, TYPECONV, H5E_CANTCONVERT, Can't convert datatypes
+MINOR, TYPECONV, H5E_BADSIZE, Bad size for object
+
+# Dataspace errors
+MINOR, DSPACE, H5E_CANTCLIP, Can't clip hyperslab region
+MINOR, DSPACE, H5E_CANTCOUNT, Can't count elements
+MINOR, DSPACE, H5E_CANTSELECT, Can't select hyperslab
+MINOR, DSPACE, H5E_CANTNEXT, Can't move to next iterator location
+MINOR, DSPACE, H5E_BADSELECT, Invalid selection
+MINOR, DSPACE, H5E_CANTCOMPARE, Can't compare objects
+MINOR, DSPACE, H5E_CANTAPPEND, Can't append object
+
+# Property list errors
+MINOR, PLIST, H5E_CANTGET, Can't get value
+MINOR, PLIST, H5E_CANTSET, Can't set value
+MINOR, PLIST, H5E_DUPCLASS, Duplicate class name in parent class
+MINOR, PLIST, H5E_SETDISALLOWED, Disallowed operation
+
+# Link errors
+MINOR, LINK, H5E_TRAVERSE, Link traversal failure
+MINOR, LINK, H5E_NLINKS, Too many soft links in path
+MINOR, LINK, H5E_NOTREGISTERED, Link class not registered
+MINOR, LINK, H5E_CANTMOVE, Can't move object
+MINOR, LINK, H5E_CANTSORT, Can't sort objects
+
+# Parallel MPI errors
+MINOR, MPI, H5E_MPI, Some MPI function failed
+MINOR, MPI, H5E_MPIERRSTR, MPI Error String
+MINOR, MPI, H5E_CANTRECV, Can't receive data
+
+# Heap errors
+MINOR, HEAP, H5E_CANTRESTORE, Can't restore condition
+MINOR, HEAP, H5E_CANTCOMPUTE, Can't compute value
+MINOR, HEAP, H5E_CANTEXTEND, Can't extend heap's space
+MINOR, HEAP, H5E_CANTATTACH, Can't attach object
+MINOR, HEAP, H5E_CANTUPDATE, Can't update object
+MINOR, HEAP, H5E_CANTOPERATE, Can't operate on object
+
+# Free space manager errors
+MINOR, FSPACE, H5E_CANTMERGE, Can't merge objects
+MINOR, FSPACE, H5E_CANTREVIVE, Can't revive object
+MINOR, FSPACE, H5E_CANTSHRINK, Can't shrink container
+
+# I/O pipeline errors
+MINOR, PIPELINE, H5E_NOFILTER, Requested filter is not available
+MINOR, PIPELINE, H5E_CALLBACK, Callback failed
+MINOR, PIPELINE, H5E_CANAPPLY, Error from filter 'can apply' callback
+MINOR, PIPELINE, H5E_SETLOCAL, Error from filter 'set local' callback
+MINOR, PIPELINE, H5E_NOENCODER, Filter present but encoding disabled
+MINOR, PIPELINE, H5E_CANTFILTER, Filter operation failed
+
+# System level errors
+MINOR, SYSTEM, H5E_SYSERRSTR, System error message
+
+# Plugin errors
+MINOR, PLUGIN, H5E_OPENERROR, Can't open directory or file
+
+# No error, for backward compatibility */
+MINOR, NONE, H5E_NONE_MINOR, No error
diff --git a/src/H5make_libsettings.c b/src/H5make_libsettings.c
new file mode 100644
index 0000000..1892806
--- /dev/null
+++ b/src/H5make_libsettings.c
@@ -0,0 +1,294 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*keep this declaration near the top of this file -RPM*/
+static const char *FileHeader = "\n\
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\
+ * Copyright by The HDF Group. *\n\
+ * Copyright by the Board of Trustees of the University of Illinois. *\n\
+ * All rights reserved. *\n\
+ * *\n\
+ * This file is part of HDF5. The full HDF5 copyright notice, including *\n\
+ * terms governing use, modification, and redistribution, is contained in *\n\
+ * the COPYING file, which can be found at the root of the source code *\n\
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *\n\
+ * If you do not have access to either file, you may request a copy from *\n\
+ * help@hdfgroup.org. *\n\
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *";
+/*
+ *
+ * Created: H5make_libsettings.c
+ * 17 Mar 2010
+ * Quincey Koziol
+ *
+ * Purpose: Generate the H5libsettings.c file from the
+ * libhdf5.settings file.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include "H5private.h"
+
+#define LIBSETTINGSFNAME "libhdf5.settings"
+
+
+/*-------------------------------------------------------------------------
+ * Function: insert_libhdf5_settings
+ *
+ * Purpose: insert the contents of libhdf5.settings into a file
+ * represented by flibinfo.
+ * Make it an empty string if H5_HAVE_EMBEDDED_LIBINFO is not
+ * defined, i.e., not enabled.
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * Apr 20, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+insert_libhdf5_settings(FILE *flibinfo)
+{
+#ifdef H5_HAVE_EMBEDDED_LIBINFO
+ FILE *fsettings; /* for files libhdf5.settings */
+ int inchar;
+ int bol = 0; /* indicates the beginning of a new line */
+
+ if(NULL == (fsettings = HDfopen(LIBSETTINGSFNAME, "r"))) {
+ HDperror(LIBSETTINGSFNAME);
+ HDexit(1);
+ } /* end if */
+
+ /* print variable definition and the string */
+ /* Do not use const else AIX strings does not show it. */
+ fprintf(flibinfo, "char H5libhdf5_settings[]=\n");
+ bol++;
+ while(EOF != (inchar = HDgetc(fsettings))) {
+ if(bol) {
+ /* Start a new line */
+ fprintf(flibinfo, "\t\"");
+ bol = 0;
+ } /* end if */
+ if(inchar == '\n') {
+ /* end of a line */
+ fprintf(flibinfo, "\\n\"\n");
+ bol++;
+ } /* end if */
+ else
+ HDputc(inchar, flibinfo);
+ } /* end while */
+ if(HDfeof(fsettings)) {
+ /* wrap up */
+ if(!bol)
+ /* EOF found without a new line */
+ fprintf(flibinfo, "\\n\"\n");
+ fprintf(flibinfo, ";\n\n");
+ } /* end if */
+ else {
+ fprintf(stderr, "Read errors encountered with %s\n", LIBSETTINGSFNAME);
+ HDexit(1);
+ } /* end else */
+ if(0 != HDfclose(fsettings)) {
+ HDperror(LIBSETTINGSFNAME);
+ HDexit(1);
+ } /* end if */
+#else
+ /* print variable definition and an empty string */
+ /* Do not use const else AIX strings does not show it. */
+ fprintf(flibinfo, "char H5libhdf5_settings[]=\"\";\n");
+#endif
+} /* insert_libhdf5_settings() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: make_libinfo
+ *
+ * Purpose: Create the embedded library information definition.
+ * This sets up for a potential extension that the declaration
+ * is printed to a file different from stdout.
+ *
+ * Return: void
+ *
+ * Programmer: Albert Cheng
+ * Sep 15, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+make_libinfo(void)
+{
+ /* print variable definition and then the string as a macro. */
+ insert_libhdf5_settings(stdout);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_header
+ *
+ * Purpose: Prints the header for the generated file.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Mar 12 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+print_header(void)
+{
+ time_t now = HDtime(NULL);
+ struct tm *tm = HDlocaltime(&now);
+ char real_name[30];
+ char host_name[256];
+ int i;
+ const char *s;
+#ifdef H5_HAVE_GETPWUID
+ struct passwd *pwd = NULL;
+#else
+ int pwd = 1;
+#endif
+ static const char *month_name[] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ static const char *purpose = "\
+This machine-generated source code contains\n\
+information about the library build configuration\n";
+
+ /*
+ * The real name is the first item from the passwd gecos field.
+ */
+#ifdef H5_HAVE_GETPWUID
+ {
+ size_t n;
+ char *comma;
+
+ if((pwd = HDgetpwuid(HDgetuid()))) {
+ if((comma = HDstrchr(pwd->pw_gecos, ','))) {
+ n = MIN(sizeof(real_name) - 1, (unsigned)(comma - pwd->pw_gecos));
+ HDstrncpy(real_name, pwd->pw_gecos, n);
+ real_name[n] = '\0';
+ } /* end if */
+ else {
+ HDstrncpy(real_name, pwd->pw_gecos, sizeof(real_name));
+ real_name[sizeof(real_name) - 1] = '\0';
+ } /* end else */
+ } /* end if */
+ else
+ real_name[0] = '\0';
+ }
+#else
+ real_name[0] = '\0';
+#endif
+
+ /*
+ * The FQDM of this host or the empty string.
+ */
+#ifdef H5_HAVE_GETHOSTNAME
+ if(HDgethostname(host_name, sizeof(host_name)) < 0)
+ host_name[0] = '\0';
+#else
+ host_name[0] = '\0';
+#endif
+
+ /*
+ * The file header: warning, copyright notice, build information.
+ */
+ printf("/* Generated automatically by H5make_libsettings -- do not edit */\n\n\n");
+ HDputs(FileHeader); /*the copyright notice--see top of this file */
+
+ printf(" *\n * Created:\t\t%s %2d, %4d\n",
+ month_name[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year);
+ if(pwd || real_name[0] || host_name[0]) {
+ printf(" *\t\t\t");
+ if(real_name[0])
+ printf("%s <", real_name);
+#ifdef H5_HAVE_GETPWUID
+ if(pwd)
+ HDfputs(pwd->pw_name, stdout);
+#endif
+ if(host_name[0])
+ printf("@%s", host_name);
+ if(real_name[0])
+ printf(">");
+ HDputchar('\n');
+ } /* end if */
+ printf(" *\n * Purpose:\t\t");
+ for(s = purpose; *s; s++) {
+ HDputchar(*s);
+ if('\n' == *s && s[1])
+ printf(" *\t\t\t");
+ } /* end for */
+
+ printf(" *\n * Modifications:\n *\n");
+ printf(" *\tDO NOT MAKE MODIFICATIONS TO THIS FILE!\n");
+ printf(" *\tIt was generated by code in `H5make_libsettings.c'.\n");
+
+ printf(" *\n *");
+ for(i = 0; i < 73; i++)
+ HDputchar('-');
+ printf("\n */\n\n");
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_footer
+ *
+ * Purpose: Prints the file footer for the generated file.
+ *
+ * Return: void
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 31 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+print_footer(void)
+{
+ /* nothing */
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Main entry point.
+ *
+ * Return: Success: exit(0)
+ *
+ * Failure: exit(1)
+ *
+ * Programmer: Albert Cheng
+ * 2010/4/1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ print_header();
+
+ /* Generate embedded library information variable definition */
+ make_libinfo();
+
+ print_footer();
+
+ HDexit(0);
+}
diff --git a/src/H5overflow.h b/src/H5overflow.h
new file mode 100644
index 0000000..8532af6
--- /dev/null
+++ b/src/H5overflow.h
@@ -0,0 +1,2252 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_overflow -- do not edit */
+/* Add new types to H5overflow.txt file */
+
+
+#ifndef _H5overflow_H
+#define _H5overflow_H
+
+
+/* Each type in this file is tested for assignment to the other types,
+ * and range checks are defined for bad assignments at run-time.
+ */
+
+/* Assignment checks for unsigned */
+
+/* src: unsigned, dst: int */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_INT
+ #define ASSIGN_unsigned_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_INT
+ #define ASSIGN_unsigned_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_INT */
+ #define ASSIGN_unsigned_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: int */
+
+/* src: unsigned, dst: int64_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_INT64_T
+ #define ASSIGN_unsigned_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_INT64_T
+ #define ASSIGN_unsigned_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_INT64_T */
+ #define ASSIGN_unsigned_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: int64_t */
+
+/* src: unsigned, dst: uint8_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_UINT8_T
+ #define ASSIGN_unsigned_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_UINT8_T
+ #define ASSIGN_unsigned_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_unsigned_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: uint8_t */
+
+/* src: unsigned, dst: uint16_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_UINT16_T
+ #define ASSIGN_unsigned_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_UINT16_T
+ #define ASSIGN_unsigned_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_unsigned_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: uint16_t */
+
+/* src: unsigned, dst: uint32_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_UINT32_T
+ #define ASSIGN_unsigned_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_UINT32_T
+ #define ASSIGN_unsigned_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_unsigned_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: uint32_t */
+
+/* src: unsigned, dst: uint64_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_UINT64_T
+ #define ASSIGN_unsigned_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_UINT64_T
+ #define ASSIGN_unsigned_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_unsigned_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: uint64_t */
+
+/* src: unsigned, dst: ptrdiff_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_unsigned_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_unsigned_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_unsigned_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: ptrdiff_t */
+
+/* src: unsigned, dst: size_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_SIZE_T
+ #define ASSIGN_unsigned_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_SIZE_T
+ #define ASSIGN_unsigned_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_unsigned_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: size_t */
+
+/* src: unsigned, dst: ssize_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_unsigned_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_unsigned_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_unsigned_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: ssize_t */
+
+/* src: unsigned, dst: haddr_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_HADDR_T
+ #define ASSIGN_unsigned_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_HADDR_T
+ #define ASSIGN_unsigned_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_unsigned_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: haddr_t */
+
+/* src: unsigned, dst: hsize_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_unsigned_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_unsigned_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_unsigned_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: hsize_t */
+
+/* src: unsigned, dst: hssize_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_unsigned_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_unsigned_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_unsigned_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: hssize_t */
+
+/* src: unsigned, dst: h5_stat_size_t */
+#if H5_SIZEOF_UNSIGNED < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_unsigned_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UNSIGNED > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_unsigned_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UNSIGNED == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_unsigned_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: unsigned dst: h5_stat_size_t */
+
+
+/* Assignment checks for int */
+
+/* src: int, dst: unsigned */
+#if H5_SIZEOF_INT < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_int_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_int_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_int_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: unsigned */
+
+/* src: int, dst: int64_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_INT64_T
+ #define ASSIGN_int_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_INT64_T
+ #define ASSIGN_int_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_INT64_T */
+ #define ASSIGN_int_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: int64_t */
+
+/* src: int, dst: uint8_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_UINT8_T
+ #define ASSIGN_int_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_UINT8_T
+ #define ASSIGN_int_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_int_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: uint8_t */
+
+/* src: int, dst: uint16_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_UINT16_T
+ #define ASSIGN_int_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_UINT16_T
+ #define ASSIGN_int_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_int_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: uint16_t */
+
+/* src: int, dst: uint32_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_UINT32_T
+ #define ASSIGN_int_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_UINT32_T
+ #define ASSIGN_int_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_int_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: uint32_t */
+
+/* src: int, dst: uint64_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_UINT64_T
+ #define ASSIGN_int_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_UINT64_T
+ #define ASSIGN_int_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_int_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: uint64_t */
+
+/* src: int, dst: ptrdiff_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_int_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_int_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_int_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: ptrdiff_t */
+
+/* src: int, dst: size_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_SIZE_T
+ #define ASSIGN_int_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_SIZE_T
+ #define ASSIGN_int_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_int_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: size_t */
+
+/* src: int, dst: ssize_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_int_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_int_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_int_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: ssize_t */
+
+/* src: int, dst: haddr_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_HADDR_T
+ #define ASSIGN_int_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_HADDR_T
+ #define ASSIGN_int_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_int_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: haddr_t */
+
+/* src: int, dst: hsize_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_int_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_int_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_int_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: hsize_t */
+
+/* src: int, dst: hssize_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_int_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_int_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_int_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: hssize_t */
+
+/* src: int, dst: h5_stat_size_t */
+#if H5_SIZEOF_INT < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_int_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_int_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_int_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int dst: h5_stat_size_t */
+
+
+/* Assignment checks for int64_t */
+
+/* src: int64_t, dst: unsigned */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_int64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_int64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_int64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: unsigned */
+
+/* src: int64_t, dst: int */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_INT
+ #define ASSIGN_int64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_INT
+ #define ASSIGN_int64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_INT */
+ #define ASSIGN_int64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: int */
+
+/* src: int64_t, dst: uint8_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_int64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_int64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_int64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: uint8_t */
+
+/* src: int64_t, dst: uint16_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_int64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_int64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_int64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: uint16_t */
+
+/* src: int64_t, dst: uint32_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_int64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_int64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_int64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: uint32_t */
+
+/* src: int64_t, dst: uint64_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_int64_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_int64_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_int64_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: uint64_t */
+
+/* src: int64_t, dst: ptrdiff_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_int64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_int64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_int64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: ptrdiff_t */
+
+/* src: int64_t, dst: size_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_int64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_int64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_int64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: size_t */
+
+/* src: int64_t, dst: ssize_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_int64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_int64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_int64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: ssize_t */
+
+/* src: int64_t, dst: haddr_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_int64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_int64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_int64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: haddr_t */
+
+/* src: int64_t, dst: hsize_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_int64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_int64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_int64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: hsize_t */
+
+/* src: int64_t, dst: hssize_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_int64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_int64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_int64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: hssize_t */
+
+/* src: int64_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_INT64_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_int64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_INT64_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_int64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_INT64_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_int64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: int64_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for uint8_t */
+
+/* src: uint8_t, dst: unsigned */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint8_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint8_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_uint8_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: unsigned */
+
+/* src: uint8_t, dst: int */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_INT
+ #define ASSIGN_uint8_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_INT
+ #define ASSIGN_uint8_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_INT */
+ #define ASSIGN_uint8_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: int */
+
+/* src: uint8_t, dst: int64_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_uint8_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_uint8_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_uint8_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: int64_t */
+
+/* src: uint8_t, dst: uint16_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint8_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint8_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_uint8_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: uint16_t */
+
+/* src: uint8_t, dst: uint32_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint8_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint8_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_uint8_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: uint32_t */
+
+/* src: uint8_t, dst: uint64_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint8_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint8_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_uint8_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: uint64_t */
+
+/* src: uint8_t, dst: ptrdiff_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint8_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint8_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_uint8_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: ptrdiff_t */
+
+/* src: uint8_t, dst: size_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint8_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint8_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_uint8_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: size_t */
+
+/* src: uint8_t, dst: ssize_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint8_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint8_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_uint8_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: ssize_t */
+
+/* src: uint8_t, dst: haddr_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint8_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint8_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_uint8_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: haddr_t */
+
+/* src: uint8_t, dst: hsize_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint8_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint8_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_uint8_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: hsize_t */
+
+/* src: uint8_t, dst: hssize_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint8_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint8_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_uint8_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: hssize_t */
+
+/* src: uint8_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_UINT8_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint8_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT8_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint8_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT8_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_uint8_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint8_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for uint16_t */
+
+/* src: uint16_t, dst: unsigned */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint16_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint16_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_uint16_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: unsigned */
+
+/* src: uint16_t, dst: int */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_INT
+ #define ASSIGN_uint16_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_INT
+ #define ASSIGN_uint16_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_INT */
+ #define ASSIGN_uint16_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: int */
+
+/* src: uint16_t, dst: int64_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_uint16_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_uint16_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_uint16_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: int64_t */
+
+/* src: uint16_t, dst: uint8_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint16_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint16_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_uint16_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: uint8_t */
+
+/* src: uint16_t, dst: uint32_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint16_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint16_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_uint16_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: uint32_t */
+
+/* src: uint16_t, dst: uint64_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint16_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint16_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_uint16_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: uint64_t */
+
+/* src: uint16_t, dst: ptrdiff_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint16_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint16_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_uint16_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: ptrdiff_t */
+
+/* src: uint16_t, dst: size_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint16_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint16_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_uint16_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: size_t */
+
+/* src: uint16_t, dst: ssize_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint16_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint16_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_uint16_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: ssize_t */
+
+/* src: uint16_t, dst: haddr_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint16_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint16_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_uint16_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: haddr_t */
+
+/* src: uint16_t, dst: hsize_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint16_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint16_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_uint16_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: hsize_t */
+
+/* src: uint16_t, dst: hssize_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint16_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint16_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_uint16_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: hssize_t */
+
+/* src: uint16_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_UINT16_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint16_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT16_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint16_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT16_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_uint16_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint16_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for uint32_t */
+
+/* src: uint32_t, dst: unsigned */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint32_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint32_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_uint32_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: unsigned */
+
+/* src: uint32_t, dst: int */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_INT
+ #define ASSIGN_uint32_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_INT
+ #define ASSIGN_uint32_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_INT */
+ #define ASSIGN_uint32_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: int */
+
+/* src: uint32_t, dst: int64_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_uint32_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_uint32_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_uint32_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: int64_t */
+
+/* src: uint32_t, dst: uint8_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint32_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint32_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_uint32_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: uint8_t */
+
+/* src: uint32_t, dst: uint16_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint32_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint32_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_uint32_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: uint16_t */
+
+/* src: uint32_t, dst: uint64_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint32_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_uint32_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_uint32_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: uint64_t */
+
+/* src: uint32_t, dst: ptrdiff_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint32_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint32_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_uint32_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: ptrdiff_t */
+
+/* src: uint32_t, dst: size_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint32_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint32_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_uint32_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: size_t */
+
+/* src: uint32_t, dst: ssize_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint32_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint32_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_uint32_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: ssize_t */
+
+/* src: uint32_t, dst: haddr_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint32_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint32_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_uint32_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: haddr_t */
+
+/* src: uint32_t, dst: hsize_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint32_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint32_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_uint32_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: hsize_t */
+
+/* src: uint32_t, dst: hssize_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint32_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint32_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_uint32_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: hssize_t */
+
+/* src: uint32_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_UINT32_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint32_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT32_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint32_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT32_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_uint32_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint32_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for uint64_t */
+
+/* src: uint64_t, dst: unsigned */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_uint64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_uint64_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: unsigned */
+
+/* src: uint64_t, dst: int */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_INT
+ #define ASSIGN_uint64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_INT
+ #define ASSIGN_uint64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_INT */
+ #define ASSIGN_uint64_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: int */
+
+/* src: uint64_t, dst: int64_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_uint64_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_uint64_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_uint64_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: int64_t */
+
+/* src: uint64_t, dst: uint8_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_uint64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_uint64_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: uint8_t */
+
+/* src: uint64_t, dst: uint16_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_uint64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_uint64_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: uint16_t */
+
+/* src: uint64_t, dst: uint32_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_uint64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_uint64_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: uint32_t */
+
+/* src: uint64_t, dst: ptrdiff_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_uint64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_uint64_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: ptrdiff_t */
+
+/* src: uint64_t, dst: size_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_uint64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_uint64_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: size_t */
+
+/* src: uint64_t, dst: ssize_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_uint64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_uint64_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: ssize_t */
+
+/* src: uint64_t, dst: haddr_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_uint64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_uint64_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: haddr_t */
+
+/* src: uint64_t, dst: hsize_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_uint64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_uint64_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: hsize_t */
+
+/* src: uint64_t, dst: hssize_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_uint64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_uint64_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: hssize_t */
+
+/* src: uint64_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_UINT64_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_UINT64_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_uint64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_UINT64_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_uint64_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: uint64_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for ptrdiff_t */
+
+/* src: ptrdiff_t, dst: unsigned */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_ptrdiff_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_ptrdiff_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_ptrdiff_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: unsigned */
+
+/* src: ptrdiff_t, dst: int */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_INT
+ #define ASSIGN_ptrdiff_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_INT
+ #define ASSIGN_ptrdiff_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_INT */
+ #define ASSIGN_ptrdiff_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: int */
+
+/* src: ptrdiff_t, dst: int64_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_ptrdiff_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_ptrdiff_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_ptrdiff_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: int64_t */
+
+/* src: ptrdiff_t, dst: uint8_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_ptrdiff_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_ptrdiff_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_ptrdiff_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: uint8_t */
+
+/* src: ptrdiff_t, dst: uint16_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_ptrdiff_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_ptrdiff_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_ptrdiff_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: uint16_t */
+
+/* src: ptrdiff_t, dst: uint32_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_ptrdiff_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_ptrdiff_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_ptrdiff_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: uint32_t */
+
+/* src: ptrdiff_t, dst: uint64_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_ptrdiff_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_ptrdiff_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_ptrdiff_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: uint64_t */
+
+/* src: ptrdiff_t, dst: size_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_ptrdiff_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_ptrdiff_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_ptrdiff_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: size_t */
+
+/* src: ptrdiff_t, dst: ssize_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_ptrdiff_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: ssize_t */
+
+/* src: ptrdiff_t, dst: haddr_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_ptrdiff_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_ptrdiff_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_ptrdiff_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: haddr_t */
+
+/* src: ptrdiff_t, dst: hsize_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_ptrdiff_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: hsize_t */
+
+/* src: ptrdiff_t, dst: hssize_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_ptrdiff_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_ptrdiff_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: hssize_t */
+
+/* src: ptrdiff_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_PTRDIFF_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_ptrdiff_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_PTRDIFF_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_ptrdiff_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_PTRDIFF_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_ptrdiff_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ptrdiff_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for size_t */
+
+/* src: size_t, dst: unsigned */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: unsigned */
+
+/* src: size_t, dst: int */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_INT
+ #define ASSIGN_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_INT
+ #define ASSIGN_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_INT */
+ #define ASSIGN_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: int */
+
+/* src: size_t, dst: int64_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: int64_t */
+
+/* src: size_t, dst: uint8_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: uint8_t */
+
+/* src: size_t, dst: uint16_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: uint16_t */
+
+/* src: size_t, dst: uint32_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: uint32_t */
+
+/* src: size_t, dst: uint64_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: uint64_t */
+
+/* src: size_t, dst: ptrdiff_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: ptrdiff_t */
+
+/* src: size_t, dst: ssize_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: ssize_t */
+
+/* src: size_t, dst: haddr_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: haddr_t */
+
+/* src: size_t, dst: hsize_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: hsize_t */
+
+/* src: size_t, dst: hssize_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: hssize_t */
+
+/* src: size_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_SIZE_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_size_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SIZE_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_size_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SIZE_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_size_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: size_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for ssize_t */
+
+/* src: ssize_t, dst: unsigned */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_ssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_ssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_ssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: unsigned */
+
+/* src: ssize_t, dst: int */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_INT
+ #define ASSIGN_ssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_INT
+ #define ASSIGN_ssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_INT */
+ #define ASSIGN_ssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: int */
+
+/* src: ssize_t, dst: int64_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_ssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_ssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_ssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: int64_t */
+
+/* src: ssize_t, dst: uint8_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_ssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_ssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_ssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: uint8_t */
+
+/* src: ssize_t, dst: uint16_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_ssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_ssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_ssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: uint16_t */
+
+/* src: ssize_t, dst: uint32_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_ssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_ssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_ssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: uint32_t */
+
+/* src: ssize_t, dst: uint64_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_ssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_ssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_ssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: uint64_t */
+
+/* src: ssize_t, dst: ptrdiff_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_ssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_ssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_ssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: ptrdiff_t */
+
+/* src: ssize_t, dst: size_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_ssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_ssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_ssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: size_t */
+
+/* src: ssize_t, dst: haddr_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_ssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_ssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_ssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: haddr_t */
+
+/* src: ssize_t, dst: hsize_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_ssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_ssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_ssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: hsize_t */
+
+/* src: ssize_t, dst: hssize_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_ssize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_ssize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_ssize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: hssize_t */
+
+/* src: ssize_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_SSIZE_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_ssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_SSIZE_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_ssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_SSIZE_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_ssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: ssize_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for haddr_t */
+
+/* src: haddr_t, dst: unsigned */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_haddr_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_haddr_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_haddr_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: unsigned */
+
+/* src: haddr_t, dst: int */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_INT
+ #define ASSIGN_haddr_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_INT
+ #define ASSIGN_haddr_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_INT */
+ #define ASSIGN_haddr_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: int */
+
+/* src: haddr_t, dst: int64_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_haddr_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_haddr_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_haddr_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: int64_t */
+
+/* src: haddr_t, dst: uint8_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_haddr_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_haddr_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_haddr_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: uint8_t */
+
+/* src: haddr_t, dst: uint16_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_haddr_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_haddr_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_haddr_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: uint16_t */
+
+/* src: haddr_t, dst: uint32_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_haddr_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_haddr_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_haddr_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: uint32_t */
+
+/* src: haddr_t, dst: uint64_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_haddr_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_haddr_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_haddr_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: uint64_t */
+
+/* src: haddr_t, dst: ptrdiff_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_haddr_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_haddr_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_haddr_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: ptrdiff_t */
+
+/* src: haddr_t, dst: size_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_haddr_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_haddr_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_haddr_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: size_t */
+
+/* src: haddr_t, dst: ssize_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_haddr_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_haddr_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_haddr_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: ssize_t */
+
+/* src: haddr_t, dst: hsize_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_haddr_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_haddr_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_haddr_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: hsize_t */
+
+/* src: haddr_t, dst: hssize_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_haddr_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_haddr_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_haddr_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: hssize_t */
+
+/* src: haddr_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_HADDR_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_haddr_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HADDR_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_haddr_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HADDR_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_haddr_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: haddr_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for hsize_t */
+
+/* src: hsize_t, dst: unsigned */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_hsize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_hsize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_hsize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: unsigned */
+
+/* src: hsize_t, dst: int */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_INT
+ #define ASSIGN_hsize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_INT
+ #define ASSIGN_hsize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_INT */
+ #define ASSIGN_hsize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: int */
+
+/* src: hsize_t, dst: int64_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_hsize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_hsize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_hsize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: int64_t */
+
+/* src: hsize_t, dst: uint8_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_hsize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_hsize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_hsize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: uint8_t */
+
+/* src: hsize_t, dst: uint16_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_hsize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_hsize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_hsize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: uint16_t */
+
+/* src: hsize_t, dst: uint32_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_hsize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_hsize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_hsize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: uint32_t */
+
+/* src: hsize_t, dst: uint64_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_hsize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_hsize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_hsize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: uint64_t */
+
+/* src: hsize_t, dst: ptrdiff_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_hsize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_hsize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_hsize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: ptrdiff_t */
+
+/* src: hsize_t, dst: size_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_hsize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_hsize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_hsize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: size_t */
+
+/* src: hsize_t, dst: ssize_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_hsize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_hsize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_hsize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: ssize_t */
+
+/* src: hsize_t, dst: haddr_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_hsize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_hsize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_hsize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: haddr_t */
+
+/* src: hsize_t, dst: hssize_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_hsize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_hsize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_hsize_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: hssize_t */
+
+/* src: hsize_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_HSIZE_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_hsize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSIZE_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_hsize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSIZE_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_hsize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hsize_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for hssize_t */
+
+/* src: hssize_t, dst: unsigned */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_hssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_hssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_hssize_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: unsigned */
+
+/* src: hssize_t, dst: int */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_INT
+ #define ASSIGN_hssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_INT
+ #define ASSIGN_hssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_INT */
+ #define ASSIGN_hssize_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: int */
+
+/* src: hssize_t, dst: int64_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_hssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_hssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_hssize_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: int64_t */
+
+/* src: hssize_t, dst: uint8_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_hssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_hssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_hssize_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: uint8_t */
+
+/* src: hssize_t, dst: uint16_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_hssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_hssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_hssize_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: uint16_t */
+
+/* src: hssize_t, dst: uint32_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_hssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_hssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_hssize_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: uint32_t */
+
+/* src: hssize_t, dst: uint64_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_hssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_hssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_hssize_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: uint64_t */
+
+/* src: hssize_t, dst: ptrdiff_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_hssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_hssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_hssize_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: ptrdiff_t */
+
+/* src: hssize_t, dst: size_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_hssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_hssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_hssize_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: size_t */
+
+/* src: hssize_t, dst: ssize_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_hssize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_hssize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_hssize_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: ssize_t */
+
+/* src: hssize_t, dst: haddr_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_hssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_hssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_hssize_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: haddr_t */
+
+/* src: hssize_t, dst: hsize_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_hssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_hssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_hssize_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: hsize_t */
+
+/* src: hssize_t, dst: h5_stat_size_t */
+#if H5_SIZEOF_HSSIZE_T < H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_hssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_HSSIZE_T > H5_SIZEOF_H5_STAT_SIZE_T
+ #define ASSIGN_hssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_HSSIZE_T == H5_SIZEOF_H5_STAT_SIZE_T */
+ #define ASSIGN_hssize_t_TO_h5_stat_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype)
+#endif /* src: hssize_t dst: h5_stat_size_t */
+
+
+/* Assignment checks for h5_stat_size_t */
+
+/* src: h5_stat_size_t, dst: unsigned */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_UNSIGNED
+ #define ASSIGN_h5_stat_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_UNSIGNED
+ #define ASSIGN_h5_stat_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_UNSIGNED */
+ #define ASSIGN_h5_stat_size_t_TO_unsigned(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: unsigned */
+
+/* src: h5_stat_size_t, dst: int */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_INT
+ #define ASSIGN_h5_stat_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_INT
+ #define ASSIGN_h5_stat_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_INT */
+ #define ASSIGN_h5_stat_size_t_TO_int(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: int */
+
+/* src: h5_stat_size_t, dst: int64_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_INT64_T
+ #define ASSIGN_h5_stat_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_INT64_T
+ #define ASSIGN_h5_stat_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_INT64_T */
+ #define ASSIGN_h5_stat_size_t_TO_int64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: int64_t */
+
+/* src: h5_stat_size_t, dst: uint8_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_UINT8_T
+ #define ASSIGN_h5_stat_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_UINT8_T
+ #define ASSIGN_h5_stat_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_UINT8_T */
+ #define ASSIGN_h5_stat_size_t_TO_uint8_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: uint8_t */
+
+/* src: h5_stat_size_t, dst: uint16_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_UINT16_T
+ #define ASSIGN_h5_stat_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_UINT16_T
+ #define ASSIGN_h5_stat_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_UINT16_T */
+ #define ASSIGN_h5_stat_size_t_TO_uint16_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: uint16_t */
+
+/* src: h5_stat_size_t, dst: uint32_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_UINT32_T
+ #define ASSIGN_h5_stat_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_UINT32_T
+ #define ASSIGN_h5_stat_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_UINT32_T */
+ #define ASSIGN_h5_stat_size_t_TO_uint32_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: uint32_t */
+
+/* src: h5_stat_size_t, dst: uint64_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_UINT64_T
+ #define ASSIGN_h5_stat_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_UINT64_T
+ #define ASSIGN_h5_stat_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_UINT64_T */
+ #define ASSIGN_h5_stat_size_t_TO_uint64_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: uint64_t */
+
+/* src: h5_stat_size_t, dst: ptrdiff_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_h5_stat_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_PTRDIFF_T
+ #define ASSIGN_h5_stat_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_PTRDIFF_T */
+ #define ASSIGN_h5_stat_size_t_TO_ptrdiff_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: ptrdiff_t */
+
+/* src: h5_stat_size_t, dst: size_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_SIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_SIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_SIZE_T */
+ #define ASSIGN_h5_stat_size_t_TO_size_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: size_t */
+
+/* src: h5_stat_size_t, dst: ssize_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_SSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_SSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_SSIZE_T */
+ #define ASSIGN_h5_stat_size_t_TO_ssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: ssize_t */
+
+/* src: h5_stat_size_t, dst: haddr_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_HADDR_T
+ #define ASSIGN_h5_stat_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_HADDR_T
+ #define ASSIGN_h5_stat_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_HADDR_T */
+ #define ASSIGN_h5_stat_size_t_TO_haddr_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: haddr_t */
+
+/* src: h5_stat_size_t, dst: hsize_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_HSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_HSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_HSIZE_T */
+ #define ASSIGN_h5_stat_size_t_TO_hsize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: hsize_t */
+
+/* src: h5_stat_size_t, dst: hssize_t */
+#if H5_SIZEOF_H5_STAT_SIZE_T < H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#elif H5_SIZEOF_H5_STAT_SIZE_T > H5_SIZEOF_HSSIZE_T
+ #define ASSIGN_h5_stat_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype)
+#else /* H5_SIZEOF_H5_STAT_SIZE_T == H5_SIZEOF_HSSIZE_T */
+ #define ASSIGN_h5_stat_size_t_TO_hssize_t(dst, dsttype, src, srctype) \
+ ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype)
+#endif /* src: h5_stat_size_t dst: hssize_t */
+
+#endif /* H5overflow_H */
+
diff --git a/src/H5overflow.txt b/src/H5overflow.txt
new file mode 100644
index 0000000..a9e5099
--- /dev/null
+++ b/src/H5overflow.txt
@@ -0,0 +1,44 @@
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the COPYING file, which can be found at the root of the source code
+# distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
+# If you do not have access to either file, you may request a copy from
+# help@hdfgroup.org.
+#
+
+# This file is used to generate the headers that is needed for detecting
+# overflows between types at run-time
+#
+# The bin/make_overflow script reads in this file and creates the appropriate
+# file in the src/ directory when the generated header is out of date with
+# respect to this file.
+#
+# Blank lines and lines beginning with '#' are ignored
+#
+# The format of this file is as follows:
+# <type>, <SIGNED|UNSIGNED>;
+#
+# Where <type> is a valid C type (like 'int8_t', 'hssize_t', etc. and whether
+# the type is signed or unsigned follows.
+#
+# Programmer: Quincey Koziol
+# Creation Date: 2009/04/09
+
+unsigned, UNSIGNED;
+int, SIGNED;
+int64_t, SIGNED;
+uint8_t, UNSIGNED;
+uint16_t, UNSIGNED;
+uint32_t, UNSIGNED;
+uint64_t, UNSIGNED;
+ptrdiff_t, SIGNED;
+size_t, UNSIGNED;
+ssize_t, SIGNED;
+haddr_t, UNSIGNED;
+hsize_t, UNSIGNED;
+hssize_t, SIGNED;
+h5_stat_size_t, UNSIGNED;
diff --git a/src/H5private.h b/src/H5private.h
new file mode 100644
index 0000000..c588154
--- /dev/null
+++ b/src/H5private.h
@@ -0,0 +1,2620 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Robb Matzke <matzke@llnl.gov>
+ * Friday, October 30, 1998
+ *
+ * Purpose: This file is included by all HDF5 library source files to
+ * define common things which are not defined in the HDF5 API.
+ * The configuration constants like H5_HAVE_UNISTD_H etc. are
+ * defined in H5config.h which is included by H5public.h.
+ *
+ */
+
+#ifndef _H5private_H
+#define _H5private_H
+
+#include "H5public.h" /* Include Public Definitions */
+
+/* include the pthread header */
+#ifdef H5_HAVE_THREADSAFE
+ #ifdef H5_HAVE_WIN32_API
+ #ifndef H5_HAVE_WIN_THREADS
+ #ifdef H5_HAVE_PTHREAD_H
+ #include <pthread.h>
+ #endif /* H5_HAVE_PTHREAD_H */
+ #endif /* H5_HAVE_WIN_THREADS */
+ #else /* H5_HAVE_WIN32_API */
+ #ifdef H5_HAVE_PTHREAD_H
+ #include <pthread.h>
+ #endif /* H5_HAVE_PTHREAD_H */
+ #endif /* H5_HAVE_WIN32_API */
+#endif /* H5_HAVE_THREADSAFE */
+
+/*
+ * Include ANSI-C header files.
+ */
+#ifdef H5_STDC_HEADERS
+# include <assert.h>
+# include <ctype.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <float.h>
+# include <limits.h>
+# include <math.h>
+# include <signal.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+/*
+ * If _POSIX_VERSION is defined in unistd.h then this system is Posix.1
+ * compliant. Otherwise all bets are off.
+ */
+#ifdef H5_HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+#ifdef _POSIX_VERSION
+# include <sys/wait.h>
+# include <pwd.h>
+#endif
+
+/*
+ * C9x integer types
+ */
+#ifndef __cplusplus
+#ifdef H5_HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#endif
+
+/*
+ * The `struct stat' data type for stat() and fstat(). This is a Posix file
+ * but often apears on non-Posix systems also. The `struct stat' is required
+ * for hdf5 to compile, although only a few fields are actually used.
+ */
+#ifdef H5_HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+/*
+ * If a program may include both `time.h' and `sys/time.h' then
+ * TIME_WITH_SYS_TIME is defined (see AC_HEADER_TIME in configure.ac).
+ * On some older systems, `sys/time.h' includes `time.h' but `time.h' is not
+ * protected against multiple inclusion, so programs should not explicitly
+ * include both files. This macro is useful in programs that use, for example,
+ * `struct timeval' or `struct timezone' as well as `struct tm'. It is best
+ * used in conjunction with `HAVE_SYS_TIME_H', whose existence is checked
+ * by `AC_CHECK_HEADERS(sys/time.h)' in configure.ac.
+ */
+#if defined(H5_TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#elif defined(H5_HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+
+/*
+ * Longjumps are used to detect alignment constrants
+ */
+#ifdef H5_HAVE_SETJMP_H
+# include <setjmp.h>
+#endif
+
+/*
+ * flock() in sys/file.h is used for the implemention of file locking.
+ */
+#if defined(H5_HAVE_FLOCK) && defined(H5_HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+
+/*
+ * Resource usage is not Posix.1 but HDF5 uses it anyway for some performance
+ * and debugging code if available.
+ */
+#ifdef H5_HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+/*
+ * Unix ioctls. These are used by h5ls (and perhaps others) to determine a
+ * resonable output width.
+ */
+#ifdef H5_HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+/*
+ * System information. These are needed on the DEC Alpha to turn off fixing
+ * of unaligned accesses by the operating system during detection of
+ * alignment constraints in H5detect.c:main().
+ */
+#ifdef H5_HAVE_SYS_SYSINFO_H
+# include <sys/sysinfo.h>
+#endif
+#ifdef H5_HAVE_SYS_PROC_H
+# include <sys/proc.h>
+#endif
+#ifdef H5_HAVE_IO_H
+# include <io.h>
+#endif
+
+/*
+ * Dynamic library handling. These are needed for dynamically loading I/O
+ * filters and VFDs.
+ */
+#ifdef H5_HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#ifdef H5_HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+/* Define the default VFD for this platform.
+ * Since the removal of the Windows VFD, this is sec2 for all platforms.
+ */
+#define H5_DEFAULT_VFD H5FD_SEC2
+
+#ifdef H5_HAVE_WIN32_API
+/* The following two defines must be before any windows headers are included */
+#define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
+#define NOGDI /* Exclude Graphic Display Interface macros */
+
+#ifdef H5_HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef H5_HAVE_THREADSAFE
+#include <process.h> /* For _beginthread() */
+#endif
+
+#include <windows.h>
+#include <direct.h> /* For _getcwd() */
+
+#endif /*H5_HAVE_WIN32_API*/
+
+/* Various ways that inline functions can be declared */
+#if defined(H5_HAVE___INLINE__)
+ /* GNU (alternative form) */
+ #define H5_INLINE __inline__
+#elif defined(H5_HAVE___INLINE)
+ /* Visual Studio */
+ #define H5_INLINE __inline
+#elif defined(H5_HAVE_INLINE)
+ /* GNU, C++
+ * Use "inline" as a last resort on the off-chance that there will
+ * be C++ problems.
+ */
+ #define H5_INLINE inline
+#else
+ #define H5_INLINE
+#endif /* inline choices */
+
+#ifndef F_OK
+# define F_OK 00
+# define W_OK 02
+# define R_OK 04
+#endif
+
+/*
+ * MPE Instrumentation support
+ */
+#ifdef H5_HAVE_MPE
+/*------------------------------------------------------------------------
+ * Purpose: Begin to collect MPE log information for a function. It should
+ * be ahead of the actual function's process.
+ *
+ * Programmer: Long Wang
+ *
+ *------------------------------------------------------------------------
+ */
+#include "mpe.h"
+/*
+ * #define eventa(func_name) h5_mpe_ ## func_name ## _a
+ * #define eventb(func_name) h5_mpe_ ## func_name ## _b
+ */
+#define eventa(func_name) h5_mpe_eventa
+#define eventb(func_name) h5_mpe_eventb
+#define MPE_LOG_VARS \
+ static int eventa(FUNC) = -1; \
+ static int eventb(FUNC) = -1; \
+ char p_event_start[128];
+
+/* Hardwire the color to "red", since that's what all the routines are using
+ * now. In the future, if we want to change that color for a given routine,
+ * we should define a "FUNC_ENTER_API_COLOR" macro which takes an extra 'color'
+ * parameter and then make additional FUNC_ENTER_<foo>_COLOR macros to get that
+ * color information down to the BEGIN_MPE_LOG macro (which should have a new
+ * BEGIN_MPE_LOG_COLOR variant). -QAK
+ */
+#define BEGIN_MPE_LOG \
+ if (H5_MPEinit_g){ \
+ sprintf(p_event_start, "start %s", FUNC); \
+ if (eventa(FUNC) == -1 && eventb(FUNC) == -1) { \
+ const char* p_color = "red"; \
+ eventa(FUNC)=MPE_Log_get_event_number(); \
+ eventb(FUNC)=MPE_Log_get_event_number(); \
+ MPE_Describe_state(eventa(FUNC), eventb(FUNC), FUNC, p_color); \
+ } \
+ MPE_Log_event(eventa(FUNC), 0, p_event_start); \
+ }
+
+
+/*------------------------------------------------------------------------
+ * Purpose: Finish the collection of MPE log information for a function.
+ * It should be after the actual function's process.
+ *
+ * Programmer: Long Wang
+ */
+#define FINISH_MPE_LOG \
+ if (H5_MPEinit_g) { \
+ MPE_Log_event(eventb(FUNC), 0, FUNC); \
+ }
+
+#else /* H5_HAVE_MPE */
+#define MPE_LOG_VARS /* void */
+#define BEGIN_MPE_LOG /* void */
+#define FINISH_MPE_LOG /* void */
+
+#endif /* H5_HAVE_MPE */
+
+/*
+ * dmalloc (debugging malloc) support
+ */
+#ifdef H5_HAVE_DMALLOC_H
+#include "dmalloc.h"
+#endif /* H5_HAVE_DMALLOC_H */
+
+/*
+ * NT doesn't define SIGBUS, but since NT only runs on processors
+ * that do not have alignment constraints a SIGBUS would never be
+ * raised, so we just replace it with SIGILL (which also should
+ * never be raised by the hdf5 library).
+ */
+#ifndef SIGBUS
+# define SIGBUS SIGILL
+#endif
+
+/*
+ * Does the compiler support the __attribute__(()) syntax? It's no
+ * big deal if we don't.
+ *
+ * Note that Solaris Studio supports attribute, but does not support the
+ * attributes we use.
+ *
+ * H5_ATTR_CONST is redefined in tools/h5repack/dynlib_rpk.c to quiet
+ * gcc warnings (it has to use the public API and can't include this
+ * file). Be sure to update that file if the #ifdefs change here.
+ */
+#ifdef __cplusplus
+# define H5_ATTR_FORMAT(X,Y,Z) /*void*/
+# define H5_ATTR_UNUSED /*void*/
+# define H5_ATTR_NORETURN /*void*/
+# define H5_ATTR_CONST /*void*/
+# define H5_ATTR_PURE /*void*/
+#else /* __cplusplus */
+#if defined(H5_HAVE_ATTRIBUTE) && !defined(__SUNPRO_C)
+# define H5_ATTR_FORMAT(X,Y,Z) __attribute__((format(X, Y, Z)))
+# define H5_ATTR_UNUSED __attribute__((unused))
+# define H5_ATTR_NORETURN __attribute__((noreturn))
+# define H5_ATTR_CONST __attribute__((const))
+# define H5_ATTR_PURE __attribute__((pure))
+#else
+# define H5_ATTR_FORMAT(X,Y,Z) /*void*/
+# define H5_ATTR_UNUSED /*void*/
+# define H5_ATTR_NORETURN /*void*/
+# define H5_ATTR_CONST /*void*/
+# define H5_ATTR_PURE /*void*/
+#endif
+#endif /* __cplusplus */
+
+/*
+ * Status return values for the `herr_t' type.
+ * Since some unix/c routines use 0 and -1 (or more precisely, non-negative
+ * vs. negative) as their return code, and some assumption had been made in
+ * the code about that, it is important to keep these constants the same
+ * values. When checking the success or failure of an integer-valued
+ * function, remember to compare against zero and not one of these two
+ * values.
+ */
+#define SUCCEED 0
+#define FAIL (-1)
+#define UFAIL (unsigned)(-1)
+
+/* number of members in an array */
+#ifndef NELMTS
+# define NELMTS(X) (sizeof(X)/sizeof(X[0]))
+#endif
+
+/* minimum of two, three, or four values */
+#undef MIN
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+#define MIN2(a,b) MIN(a,b)
+#define MIN3(a,b,c) MIN(a,MIN(b,c))
+#define MIN4(a,b,c,d) MIN(MIN(a,b),MIN(c,d))
+
+/* maximum of two, three, or four values */
+#undef MAX
+#define MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define MAX2(a,b) MAX(a,b)
+#define MAX3(a,b,c) MAX(a,MAX(b,c))
+#define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d))
+
+/* limit the middle value to be within a range (inclusive) */
+#define RANGE(LO,X,HI) MAX(LO,MIN(X,HI))
+
+/* absolute value */
+#ifndef ABS
+# define ABS(a) (((a)>=0) ? (a) : -(a))
+#endif
+
+/* sign of argument */
+#ifndef SIGN
+# define SIGN(a) ((a)>0 ? 1 : (a)<0 ? -1 : 0)
+#endif
+
+/* test for number that is a power of 2 */
+/* (from: http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2) */
+# define POWER_OF_TWO(n) (!(n & (n - 1)) && n)
+
+/* Raise an integer to a power of 2 */
+# define H5_EXP2(n) (1 << (n))
+
+/*
+ * HDF Boolean type.
+ */
+#ifndef FALSE
+ #define FALSE false
+#endif
+#ifndef TRUE
+ #define TRUE true
+#endif
+
+/*
+ * Numeric data types. Some of these might be defined in Posix.1g, otherwise
+ * we define them with the closest available type which is at least as large
+ * as the number of bits indicated in the type name. The `int8' types *must*
+ * be exactly one byte wide because we use it for pointer calculations to
+ * void* memory.
+ */
+#if H5_SIZEOF_INT8_T==0
+ typedef signed char int8_t;
+# undef H5_SIZEOF_INT8_T
+# define H5_SIZEOF_INT8_T H5_SIZEOF_CHAR
+#elif H5_SIZEOF_INT8_T==1
+#else
+# error "the int8_t type must be 1 byte wide"
+#endif
+
+#if H5_SIZEOF_UINT8_T==0
+ typedef unsigned char uint8_t;
+# undef H5_SIZEOF_UINT8_T
+# define H5_SIZEOF_UINT8_T H5_SIZEOF_CHAR
+#elif H5_SIZEOF_UINT8_T==1
+#else
+# error "the uint8_t type must be 1 byte wide"
+#endif
+
+#if H5_SIZEOF_INT16_T>=2
+#elif H5_SIZEOF_SHORT>=2
+ typedef short int16_t;
+# undef H5_SIZEOF_INT16_T
+# define H5_SIZEOF_INT16_T H5_SIZEOF_SHORT
+#elif H5_SIZEOF_INT>=2
+ typedef int int16_t;
+# undef H5_SIZEOF_INT16_T
+# define H5_SIZEOF_INT16_T H5_SIZEOF_INT
+#else
+# error "nothing appropriate for int16_t"
+#endif
+
+#if H5_SIZEOF_UINT16_T>=2
+#elif H5_SIZEOF_SHORT>=2
+ typedef unsigned short uint16_t;
+# undef H5_SIZEOF_UINT16_T
+# define H5_SIZEOF_UINT16_T H5_SIZEOF_SHORT
+#elif H5_SIZEOF_INT>=2
+ typedef unsigned uint16_t;
+# undef H5_SIZEOF_UINT16_T
+# define H5_SIZEOF_UINT16_T H5_SIZEOF_INT
+#else
+# error "nothing appropriate for uint16_t"
+#endif
+
+#if H5_SIZEOF_INT32_T>=4
+#elif H5_SIZEOF_SHORT>=4
+ typedef short int32_t;
+# undef H5_SIZEOF_INT32_T
+# define H5_SIZEOF_INT32_T H5_SIZEOF_SHORT
+#elif H5_SIZEOF_INT>=4
+ typedef int int32_t;
+# undef H5_SIZEOF_INT32_T
+# define H5_SIZEOF_INT32_T H5_SIZEOF_INT
+#elif H5_SIZEOF_LONG>=4
+ typedef long int32_t;
+# undef H5_SIZEOF_INT32_T
+# define H5_SIZEOF_INT32_T H5_SIZEOF_LONG
+#else
+# error "nothing appropriate for int32_t"
+#endif
+
+/*
+ * Maximum and minimum values. These should be defined in <limits.h> for the
+ * most part.
+ */
+#ifndef LLONG_MAX
+# define LLONG_MAX ((long long)(((unsigned long long)1 \
+ <<(8*sizeof(long long)-1))-1))
+# define LLONG_MIN ((long long)(-LLONG_MAX)-1)
+#endif
+#ifndef ULLONG_MAX
+# define ULLONG_MAX ((unsigned long long)((long long)(-1)))
+#endif
+#ifndef SIZET_MAX
+# define SIZET_MAX ((size_t)(ssize_t)(-1))
+# define SSIZET_MAX ((ssize_t)(((size_t)1<<(8*sizeof(ssize_t)-1))-1))
+#endif
+
+/*
+ * Maximum & minimum values for our typedefs.
+ */
+#define HSIZET_MAX ((hsize_t)ULLONG_MAX)
+#define HSSIZET_MAX ((hssize_t)LLONG_MAX)
+#define HSSIZET_MIN (~(HSSIZET_MAX))
+
+/*
+ * Types and max sizes for POSIX I/O.
+ * OS X (Darwin) is odd since the max I/O size does not match the types.
+ */
+#if defined(H5_HAVE_WIN32_API)
+# define h5_posix_io_t unsigned int
+# define h5_posix_io_ret_t int
+# define H5_POSIX_MAX_IO_BYTES INT_MAX
+#elif defined(H5_HAVE_DARWIN)
+# define h5_posix_io_t size_t
+# define h5_posix_io_ret_t ssize_t
+# define H5_POSIX_MAX_IO_BYTES INT_MAX
+#else
+# define h5_posix_io_t size_t
+# define h5_posix_io_ret_t ssize_t
+# define H5_POSIX_MAX_IO_BYTES SSIZET_MAX
+#endif
+
+/*
+ * A macro to portably increment enumerated types.
+ */
+#ifndef H5_INC_ENUM
+# define H5_INC_ENUM(TYPE,VAR) (VAR)=((TYPE)((VAR)+1))
+#endif
+
+/*
+ * A macro to portably decrement enumerated types.
+ */
+#ifndef H5_DEC_ENUM
+# define H5_DEC_ENUM(TYPE,VAR) (VAR)=((TYPE)((VAR)-1))
+#endif
+
+/* Double constant wrapper
+ *
+ * Quiets gcc warnings from -Wunsuffixed-float-constants.
+ *
+ * This is a really annoying warning since the standard specifies that
+ * constants of type double do NOT get a suffix so there's no way
+ * to specify a constant of type double. To quiet gcc, we specify floating
+ * point constants as type long double and cast to double.
+ *
+ * Note that this macro only needs to be used where using a double
+ * is important. For most code, suffixing constants with F will quiet the
+ * compiler and not produce erroneous code.
+ */
+#define H5_DOUBLE(S) ((double) S ## L)
+
+/*
+ * Methods to compare the equality of floating-point values:
+ *
+ * 1. H5_XXX_ABS_EQUAL - check if the difference is smaller than the
+ * Epsilon value. The Epsilon values, FLT_EPSILON, DBL_EPSILON,
+ * and LDBL_EPSILON, are defined by compiler in float.h.
+ *
+ * 2. H5_XXX_REL_EQUAL - check if the relative difference is smaller than a
+ * predefined value M. See if two values are relatively equal.
+ * It's the developer's responsibility not to pass in the value 0, which
+ * may cause the equation to fail.
+ */
+#define H5_FLT_ABS_EQUAL(X,Y) (HDfabsf((X)-(Y)) < FLT_EPSILON)
+#define H5_DBL_ABS_EQUAL(X,Y) (HDfabs ((X)-(Y)) < DBL_EPSILON)
+#define H5_LDBL_ABS_EQUAL(X,Y) (HDfabsl((X)-(Y)) < LDBL_EPSILON)
+
+#define H5_FLT_REL_EQUAL(X,Y,M) (HDfabsf(((Y)-(X)) / (X)) < (M))
+#define H5_DBL_REL_EQUAL(X,Y,M) (HDfabs (((Y)-(X)) / (X)) < (M))
+#define H5_LDBL_REL_EQUAL(X,Y,M) (HDfabsl(((Y)-(X)) / (X)) < (M))
+
+/* KiB, MiB, GiB, TiB, PiB, EiB - Used in profiling and timing code */
+#define H5_KB (1024.0F)
+#define H5_MB (1024.0F * 1024.0F)
+#define H5_GB (1024.0F * 1024.0F * 1024.0F)
+#define H5_TB (1024.0F * 1024.0F * 1024.0F * 1024.0F)
+#define H5_PB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F)
+#define H5_EB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F)
+
+#ifndef H5_HAVE_FLOCK
+/* flock() operations. Used in the source so we have to define them when
+ * the call is not available (e.g.: Windows). These should NOT be used
+ * with system-provided flock() calls since the values will come from the
+ * header file.
+ */
+#define LOCK_SH 0x01
+#define LOCK_EX 0x02
+#define LOCK_NB 0x04
+#define LOCK_UN 0x08
+#endif /* H5_HAVE_FLOCK */
+
+/*
+ * Data types and functions for timing certain parts of the library.
+ */
+typedef struct {
+ double utime; /*user time */
+ double stime; /*system time */
+ double etime; /*elapsed wall-clock time */
+} H5_timer_t;
+
+H5_DLL void H5_timer_reset (H5_timer_t *timer);
+H5_DLL void H5_timer_begin (H5_timer_t *timer);
+H5_DLL void H5_timer_end (H5_timer_t *sum/*in,out*/,
+ H5_timer_t *timer/*in,out*/);
+H5_DLL void H5_bandwidth(char *buf/*out*/, double nbytes, double nseconds);
+H5_DLL time_t H5_now(void);
+
+/* Depth of object copy */
+typedef enum {
+ H5_COPY_SHALLOW, /* Shallow copy from source to destination, just copy field pointers */
+ H5_COPY_DEEP /* Deep copy from source to destination, including duplicating fields pointed to */
+} H5_copy_depth_t;
+
+/* Common object copying udata (right now only used for groups and datasets) */
+typedef struct H5O_copy_file_ud_common_t {
+ struct H5O_pline_t *src_pline; /* Copy of filter pipeline for object */
+} H5O_copy_file_ud_common_t;
+
+/* Unique object "position" */
+typedef struct {
+ unsigned long fileno; /* The unique identifier for the file of the object */
+ haddr_t addr; /* The unique address of the object's header in that file */
+} H5_obj_t;
+
+/*
+ * Redefine all the POSIX functions. We should never see a POSIX
+ * function (or any other non-HDF5 function) in the source!
+ */
+
+/* Put all platform-specific definitions in the following file */
+/* so that the following definitions are platform free. */
+#include "H5win32defs.h" /* For Windows-specific definitions */
+
+#ifndef HDabort
+ #define HDabort() abort()
+#endif /* HDabort */
+#ifndef HDabs
+ #define HDabs(X) abs(X)
+#endif /* HDabs */
+#ifndef HDaccess
+ #define HDaccess(F,M) access(F, M)
+#endif /* HDaccess */
+#ifndef HDacos
+ #define HDacos(X) acos(X)
+#endif /* HDacos */
+#ifndef HDalarm
+ #ifdef H5_HAVE_ALARM
+ #define HDalarm(N) alarm(N)
+ #else /* H5_HAVE_ALARM */
+ #define HDalarm(N) (0)
+ #endif /* H5_HAVE_ALARM */
+#endif /* HDalarm */
+#ifndef HDasctime
+ #define HDasctime(T) asctime(T)
+#endif /* HDasctime */
+#ifndef HDasin
+ #define HDasin(X) asin(X)
+#endif /* HDasin */
+#ifndef HDasprintf
+ #define HDasprintf asprintf /*varargs*/
+#endif /* HDasprintf */
+#ifndef HDassert
+ #define HDassert(X) assert(X)
+#endif /* HDassert */
+#ifndef HDatan
+ #define HDatan(X) atan(X)
+#endif /* HDatan */
+#ifndef HDatan2
+ #define HDatan2(X,Y) atan2(X,Y)
+#endif /* HDatan2 */
+#ifndef HDatexit
+ #define HDatexit(F) atexit(F)
+#endif /* HDatexit */
+#ifndef HDatof
+ #define HDatof(S) atof(S)
+#endif /* HDatof */
+#ifndef HDatoi
+ #define HDatoi(S) atoi(S)
+#endif /* HDatoi */
+#ifndef HDatol
+ #define HDatol(S) atol(S)
+#endif /* HDatol */
+#ifndef HDatoll
+ #define HDatoll(S) atoll(S)
+#endif /* HDatol */
+#ifndef HDbsearch
+ #define HDbsearch(K,B,N,Z,F) bsearch(K,B,N,Z,F)
+#endif /* HDbsearch */
+#ifndef HDcalloc
+ #define HDcalloc(N,Z) calloc(N,Z)
+#endif /* HDcalloc */
+#ifndef HDceil
+ #define HDceil(X) ceil(X)
+#endif /* HDceil */
+#ifndef HDcfgetispeed
+ #define HDcfgetispeed(T) cfgetispeed(T)
+#endif /* HDcfgetispeed */
+#ifndef HDcfgetospeed
+ #define HDcfgetospeed(T) cfgetospeed(T)
+#endif /* HDcfgetospeed */
+#ifndef HDcfsetispeed
+ #define HDcfsetispeed(T,S) cfsetispeed(T,S)
+#endif /* HDcfsetispeed */
+#ifndef HDcfsetospeed
+ #define HDcfsetospeed(T,S) cfsetospeed(T,S)
+#endif /* HDcfsetospeed */
+#ifndef HDchdir
+ #define HDchdir(S) chdir(S)
+#endif /* HDchdir */
+#ifndef HDchmod
+ #define HDchmod(S,M) chmod(S,M)
+#endif /* HDchmod */
+#ifndef HDchown
+ #define HDchown(S,O,G) chown(S,O,G)
+#endif /* HDchown */
+#ifndef HDclearerr
+ #define HDclearerr(F) clearerr(F)
+#endif /* HDclearerr */
+#ifndef HDclock
+ #define HDclock() clock()
+#endif /* HDclock */
+#ifndef HDclose
+ #define HDclose(F) close(F)
+#endif /* HDclose */
+#ifndef HDclosedir
+ #define HDclosedir(D) closedir(D)
+#endif /* HDclosedir */
+#ifndef HDcos
+ #define HDcos(X) cos(X)
+#endif /* HDcos */
+#ifndef HDcosh
+ #define HDcosh(X) cosh(X)
+#endif /* HDcosh */
+#ifndef HDcreat
+ #define HDcreat(S,M) creat(S,M)
+#endif /* HDcreat */
+#ifndef HDctermid
+ #define HDctermid(S) ctermid(S)
+#endif /* HDctermid */
+#ifndef HDctime
+ #define HDctime(T) ctime(T)
+#endif /* HDctime */
+#ifndef HDcuserid
+ #define HDcuserid(S) cuserid(S)
+#endif /* HDcuserid */
+#ifndef HDdifftime
+ #ifdef H5_HAVE_DIFFTIME
+ #define HDdifftime(X,Y) difftime(X,Y)
+ #else /* H5_HAVE_DIFFTIME */
+ #define HDdifftime(X,Y) ((double)(X)-(double)(Y))
+ #endif /* H5_HAVE_DIFFTIME */
+#endif /* HDdifftime */
+#ifndef HDdiv
+ #define HDdiv(X,Y) div(X,Y)
+#endif /* HDdiv */
+#ifndef HDdup
+ #define HDdup(F) dup(F)
+#endif /* HDdup */
+#ifndef HDdup2
+ #define HDdup2(F,I) dup2(F,I)
+#endif /* HDdup2 */
+/* execl() variable arguments */
+/* execle() variable arguments */
+/* execlp() variable arguments */
+#ifndef HDexecv
+ #define HDexecv(S,AV) execv(S,AV)
+#endif /* HDexecv */
+#ifndef HDexecve
+ #define HDexecve(S,AV,E) execve(S,AV,E)
+#endif /* HDexecve */
+#ifndef HDexecvp
+ #define HDexecvp(S,AV) execvp(S,AV)
+#endif /* HDexecvp */
+#ifndef HDexit
+ #define HDexit(N) exit(N)
+#endif /* HDexit */
+#ifndef HD_exit
+ #define HD_exit(N) _exit(N)
+#endif /* HD_exit */
+#ifndef HDexp
+ #define HDexp(X) exp(X)
+#endif /* HDexp */
+#ifndef HDexp2
+ #define HDexp2(X) exp2(X)
+#endif /* HDexp2 */
+#ifndef HDfabs
+ #define HDfabs(X) fabs(X)
+#endif /* HDfabs */
+/* use ABS() because fabsf() fabsl() are not common yet. */
+#ifndef HDfabsf
+ #define HDfabsf(X) ABS(X)
+#endif /* HDfabsf */
+#ifndef HDfabsl
+ #define HDfabsl(X) ABS(X)
+#endif /* HDfabsl */
+#ifndef HDfclose
+ #define HDfclose(F) fclose(F)
+#endif /* HDfclose */
+#ifdef H5_HAVE_FCNTL
+ #ifndef HDfcntl
+ #define HDfcntl(F,C,...) fcntl(F,C,__VA_ARGS__)
+ #endif /* HDfcntl */
+#endif /* H5_HAVE_FCNTL */
+#ifndef HDfdopen
+ #define HDfdopen(N,S) fdopen(N,S)
+#endif /* HDfdopen */
+#ifndef HDfeof
+ #define HDfeof(F) feof(F)
+#endif /* HDfeof */
+#ifndef HDferror
+ #define HDferror(F) ferror(F)
+#endif /* HDferror */
+#ifndef HDfflush
+ #define HDfflush(F) fflush(F)
+#endif /* HDfflush */
+#ifndef HDfgetc
+ #define HDfgetc(F) fgetc(F)
+#endif /* HDfgetc */
+#ifndef HDfgetpos
+ #define HDfgetpos(F,P) fgetpos(F,P)
+#endif /* HDfgetpos */
+#ifndef HDfgets
+ #define HDfgets(S,N,F) fgets(S,N,F)
+#endif /* HDfgets */
+#ifndef HDfileno
+ #define HDfileno(F) fileno(F)
+#endif /* HDfileno */
+/* Since flock is so prevalent, always build these functions
+ * when possible to avoid them becoming dead code.
+ */
+#ifdef H5_HAVE_FCNTL
+H5_DLL int Pflock(int fd, int operation);
+#endif /* H5_HAVE_FCNTL */
+H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation);
+#ifndef HDflock
+ /* NOTE: flock(2) is not present on all POSIX systems.
+ * If it is not present, we try a flock() equivalent based on
+ * fcntl(2), then fall back to a function that always fails if
+ * it is not present at all (Windows uses a separate Wflock()
+ * function).
+ */
+ #if defined(H5_HAVE_FLOCK)
+ #define HDflock(F,L) flock(F,L)
+ #elif defined(H5_HAVE_FCNTL)
+ #define HDflock(F,L) Pflock(F,L)
+ #else
+ #define HDflock(F,L) Nflock(F,L)
+ #endif /* H5_HAVE_FLOCK */
+#endif /* HDflock */
+#ifndef HDfloor
+ #define HDfloor(X) floor(X)
+#endif /* HDfloor */
+#ifndef HDfmod
+ #define HDfmod(X,Y) fmod(X,Y)
+#endif /* HDfmod */
+#ifndef HDfopen
+ #define HDfopen(S,M) fopen(S,M)
+#endif /* HDfopen */
+#ifndef HDfork
+ #define HDfork() fork()
+#endif /* HDfork */
+#ifndef HDfpathconf
+ #define HDfpathconf(F,N) fpathconf(F,N)
+#endif /* HDfpathconf */
+H5_DLL int HDfprintf (FILE *stream, const char *fmt, ...);
+#ifndef HDfputc
+ #define HDfputc(C,F) fputc(C,F)
+#endif /* HDfputc */
+#ifndef HDfputs
+ #define HDfputs(S,F) fputs(S,F)
+#endif /* HDfputs */
+#ifndef HDfread
+ #define HDfread(M,Z,N,F) fread(M,Z,N,F)
+#endif /* HDfread */
+#ifndef HDfree
+ #define HDfree(M) free(M)
+#endif /* HDfree */
+#ifndef HDfreopen
+ #define HDfreopen(S,M,F) freopen(S,M,F)
+#endif /* HDfreopen */
+#ifndef HDfrexp
+ #define HDfrexp(X,N) frexp(X,N)
+#endif /* HDfrexp */
+/* Check for Cray-specific 'frexpf()' and 'frexpl()' routines */
+#ifndef HDfrexpf
+ #ifdef H5_HAVE_FREXPF
+ #define HDfrexpf(X,N) frexpf(X,N)
+ #else /* H5_HAVE_FREXPF */
+ #define HDfrexpf(X,N) frexp(X,N)
+ #endif /* H5_HAVE_FREXPF */
+#endif /* HDfrexpf */
+#ifndef HDfrexpl
+ #ifdef H5_HAVE_FREXPL
+ #define HDfrexpl(X,N) frexpl(X,N)
+ #else /* H5_HAVE_FREXPL */
+ #define HDfrexpl(X,N) frexp(X,N)
+ #endif /* H5_HAVE_FREXPL */
+#endif /* HDfrexpl */
+/* fscanf() variable arguments */
+#ifndef HDfseek
+ #define HDfseek(F,O,W) fseeko(F,O,W)
+#endif /* HDfseek */
+#ifndef HDfsetpos
+ #define HDfsetpos(F,P) fsetpos(F,P)
+#endif /* HDfsetpos */
+#ifndef HDfstat
+ #define HDfstat(F,B) fstat(F,B)
+#endif /* HDfstat */
+#ifndef HDlstat
+ #define HDlstat(S,B) lstat(S,B)
+#endif /* HDlstat */
+#ifndef HDstat
+ #define HDstat(S,B) stat(S,B)
+#endif /* HDstat */
+
+#ifndef H5_HAVE_WIN32_API
+/* These definitions differ in Windows and are defined in
+ * H5win32defs for that platform.
+ */
+typedef struct stat h5_stat_t;
+typedef off_t h5_stat_size_t;
+#define HDoff_t off_t
+#endif /* H5_HAVE_WIN32_API */
+
+#define H5_SIZEOF_H5_STAT_SIZE_T H5_SIZEOF_OFF_T
+
+#ifndef HDftell
+ #define HDftell(F) ftello(F)
+#endif /* HDftell */
+#ifndef HDftruncate
+ #define HDftruncate(F,L) ftruncate(F,L)
+#endif /* HDftruncate */
+#ifndef HDfwrite
+ #define HDfwrite(M,Z,N,F) fwrite(M,Z,N,F)
+#endif /* HDfwrite */
+#ifndef HDgetc
+ #define HDgetc(F) getc(F)
+#endif /* HDgetc */
+#ifndef HDgetchar
+ #define HDgetchar() getchar()
+#endif /* HDgetchar */
+#ifndef HDgetcwd
+ #define HDgetcwd(S,Z) getcwd(S,Z)
+#endif /* HDgetcwd */
+#ifndef HDgetdcwd
+ #define HDgetdcwd(D,S,Z) getcwd(S,Z)
+#endif /* HDgetdcwd */
+#ifndef HDgetdrive
+ #define HDgetdrive() 0
+#endif /* HDgetdrive */
+#ifndef HDgetegid
+ #define HDgetegid() getegid()
+#endif /* HDgetegid() */
+#ifndef HDgetenv
+ #define HDgetenv(S) getenv(S)
+#endif /* HDgetenv */
+#ifndef HDgeteuid
+ #define HDgeteuid() geteuid()
+#endif /* HDgeteuid */
+#ifndef HDgetgid
+ #define HDgetgid() getgid()
+#endif /* HDgetgid */
+#ifndef HDgetgrgid
+ #define HDgetgrgid(G) getgrgid(G)
+#endif /* HDgetgrgid */
+#ifndef HDgetgrnam
+ #define HDgetgrnam(S) getgrnam(S)
+#endif /* HDgetgrnam */
+#ifndef HDgetgroups
+ #define HDgetgroups(Z,G) getgroups(Z,G)
+#endif /* HDgetgroups */
+#ifndef HDgethostname
+ #define HDgethostname(N,L) gethostname(N,L)
+#endif /* HDgetlogin */
+#ifndef HDgetlogin
+ #define HDgetlogin() getlogin()
+#endif /* HDgetlogin */
+#ifndef HDgetpgrp
+ #define HDgetpgrp() getpgrp()
+#endif /* HDgetpgrp */
+#ifndef HDgetpid
+ #define HDgetpid() getpid()
+#endif /* HDgetpid */
+#ifndef HDgetppid
+ #define HDgetppid() getppid()
+#endif /* HDgetppid */
+#ifndef HDgetpwnam
+ #define HDgetpwnam(S) getpwnam(S)
+#endif /* HDgetpwnam */
+#ifndef HDgetpwuid
+ #define HDgetpwuid(U) getpwuid(U)
+#endif /* HDgetpwuid */
+#ifndef HDgetrusage
+ #define HDgetrusage(X,S) getrusage(X,S)
+#endif /* HDgetrusage */
+#ifndef HDgets
+ #define HDgets(S) gets(S)
+#endif /* HDgets */
+#ifndef HDgettimeofday
+ #define HDgettimeofday(S,P) gettimeofday(S,P)
+#endif /* HDgettimeofday */
+#ifndef HDgetuid
+ #define HDgetuid() getuid()
+#endif /* HDgetuid */
+#ifndef HDgmtime
+ #define HDgmtime(T) gmtime(T)
+#endif /* HDgmtime */
+#ifndef HDisalnum
+ #define HDisalnum(C) isalnum((int)(C)) /*cast for solaris warning*/
+#endif /* HDisalnum */
+#ifndef HDisalpha
+ #define HDisalpha(C) isalpha((int)(C)) /*cast for solaris warning*/
+#endif /* HDisalpha */
+#ifndef HDisatty
+ #define HDisatty(F) isatty(F)
+#endif /* HDisatty */
+#ifndef HDiscntrl
+ #define HDiscntrl(C) iscntrl((int)(C)) /*cast for solaris warning*/
+#endif /* HDiscntrl */
+#ifndef HDisdigit
+ #define HDisdigit(C) isdigit((int)(C)) /*cast for solaris warning*/
+#endif /* HDisdigit */
+#ifndef HDisgraph
+ #define HDisgraph(C) isgraph((int)(C)) /*cast for solaris warning*/
+#endif /* HDisgraph */
+#ifndef HDislower
+ #define HDislower(C) islower((int)(C)) /*cast for solaris warning*/
+#endif /* HDislower */
+#ifndef HDisprint
+ #define HDisprint(C) isprint((int)(C)) /*cast for solaris warning*/
+#endif /* HDisprint */
+#ifndef HDispunct
+ #define HDispunct(C) ispunct((int)(C)) /*cast for solaris warning*/
+#endif /* HDispunct */
+#ifndef HDisspace
+ #define HDisspace(C) isspace((int)(C)) /*cast for solaris warning*/
+#endif /* HDisspace */
+#ifndef HDisupper
+ #define HDisupper(C) isupper((int)(C)) /*cast for solaris warning*/
+#endif /* HDisupper */
+#ifndef HDisxdigit
+ #define HDisxdigit(C) isxdigit((int)(C)) /*cast for solaris warning*/
+#endif /* HDisxdigit */
+#ifndef HDkill
+ #define HDkill(P,S) kill(P,S)
+#endif /* HDkill */
+#ifndef HDlabs
+ #define HDlabs(X) labs(X)
+#endif /* HDlabs */
+#ifndef HDldexp
+ #define HDldexp(X,N) ldexp(X,N)
+#endif /* HDldexp */
+#ifndef HDldiv
+ #define HDldiv(X,Y) ldiv(X,Y)
+#endif /* HDldiv */
+#ifndef HDlink
+ #define HDlink(OLD,NEW) link(OLD,NEW)
+#endif /* HDlink */
+#ifndef HDllround
+ #define HDllround(V) llround(V)
+#endif /* HDround */
+#ifndef HDllroundf
+ #define HDllroundf(V) llroundf(V)
+#endif /* HDllroundf */
+#ifndef HDllroundl
+ #define HDllroundl(V) llroundl(V)
+#endif /* HDllroundl */
+#ifndef HDlocaleconv
+ #define HDlocaleconv() localeconv()
+#endif /* HDlocaleconv */
+#ifndef HDlocaltime
+ #define HDlocaltime(T) localtime(T)
+#endif /* HDlocaltime */
+#ifndef HDlog
+ #define HDlog(X) log(X)
+#endif /* HDlog */
+#ifndef HDlog10
+ #define HDlog10(X) log10(X)
+#endif /* HDlog10 */
+#ifndef HDlongjmp
+ #define HDlongjmp(J,N) longjmp(J,N)
+#endif /* HDlongjmp */
+#ifndef HDlround
+ #define HDlround(V) lround(V)
+#endif /* HDround */
+#ifndef HDlroundf
+ #define HDlroundf(V) lroundf(V)
+#endif /* HDlroundf */
+#ifndef HDlroundl
+ #define HDlroundl(V) lroundl(V)
+#endif /* HDroundl */
+#ifndef HDlseek
+ #define HDlseek(F,O,W) lseek(F,O,W)
+#endif /* HDlseek */
+#ifndef HDmalloc
+ #define HDmalloc(Z) malloc(Z)
+#endif /* HDmalloc */
+#ifndef HDposix_memalign
+ #define HDposix_memalign(P,A,Z) posix_memalign(P,A,Z)
+#endif /* HDposix_memalign */
+#ifndef HDmblen
+ #define HDmblen(S,N) mblen(S,N)
+#endif /* HDmblen */
+#ifndef HDmbstowcs
+ #define HDmbstowcs(P,S,Z) mbstowcs(P,S,Z)
+#endif /* HDmbstowcs */
+#ifndef HDmbtowc
+ #define HDmbtowc(P,S,Z) mbtowc(P,S,Z)
+#endif /* HDmbtowc */
+#ifndef HDmemchr
+ #define HDmemchr(S,C,Z) memchr(S,C,Z)
+#endif /* HDmemchr */
+#ifndef HDmemcmp
+ #define HDmemcmp(X,Y,Z) memcmp(X,Y,Z)
+#endif /* HDmemcmp */
+/*
+ * The (char*) casts are required for the DEC when optimizations are turned
+ * on and the source and/or destination are not aligned.
+ */
+#ifndef HDmemcpy
+ #define HDmemcpy(X,Y,Z) memcpy((char*)(X),(const char*)(Y),Z)
+#endif /* HDmemcpy */
+#ifndef HDmemmove
+ #define HDmemmove(X,Y,Z) memmove((char*)(X),(const char*)(Y),Z)
+#endif /* HDmemmove */
+#ifndef HDmemset
+ #define HDmemset(X,C,Z) memset(X,C,Z)
+#endif /* HDmemset */
+#ifndef HDmkdir
+ #define HDmkdir(S,M) mkdir(S,M)
+#endif /* HDmkdir */
+#ifndef HDmkfifo
+ #define HDmkfifo(S,M) mkfifo(S,M)
+#endif /* HDmkfifo */
+#ifndef HDmktime
+ #define HDmktime(T) mktime(T)
+#endif /* HDmktime */
+#ifndef HDmodf
+ #define HDmodf(X,Y) modf(X,Y)
+#endif /* HDmodf */
+#ifndef HDnanosleep
+ #define HDnanosleep(N, O) nanosleep(N, O)
+#endif /* HDnanosleep */
+#ifndef HDopen
+ #ifdef _O_BINARY
+ #define HDopen(S,F,M) open(S,F|_O_BINARY,M)
+ #else
+ #define HDopen(S,F,M) open(S,F,M)
+ #endif
+#endif /* HDopen */
+#ifndef HDopendir
+ #define HDopendir(S) opendir(S)
+#endif /* HDopendir */
+#ifndef HDpathconf
+ #define HDpathconf(S,N) pathconf(S,N)
+#endif /* HDpathconf */
+#ifndef HDpause
+ #define HDpause() pause()
+#endif /* HDpause */
+#ifndef HDperror
+ #define HDperror(S) perror(S)
+#endif /* HDperror */
+#ifndef HDpipe
+ #define HDpipe(F) pipe(F)
+#endif /* HDpipe */
+#ifndef HDpow
+ #define HDpow(X,Y) pow(X,Y)
+#endif /* HDpow */
+#ifndef HDpowf
+ #define HDpowf(X,Y) powf(X,Y)
+#endif /* HDpowf */
+#ifndef HDprintf
+ #define HDprintf(...) HDfprintf(stdout, __VA_ARGS__)
+#endif /* HDprintf */
+#ifndef HDputc
+ #define HDputc(C,F) putc(C,F)
+#endif /* HDputc*/
+#ifndef HDputchar
+ #define HDputchar(C) putchar(C)
+#endif /* HDputchar */
+#ifndef HDputs
+ #define HDputs(S) puts(S)
+#endif /* HDputs */
+#ifndef HDqsort
+ #define HDqsort(M,N,Z,F) qsort(M,N,Z,F)
+#endif /* HDqsort*/
+#ifndef HDraise
+ #define HDraise(N) raise(N)
+#endif /* HDraise */
+
+#ifdef H5_HAVE_RAND_R
+ #ifndef HDrandom
+ #define HDrandom() HDrand()
+ #endif /* HDrandom */
+ H5_DLL int HDrand(void);
+#elif H5_HAVE_RANDOM
+ #ifndef HDrand
+ #define HDrand() random()
+ #endif /* HDrand */
+ #ifndef HDrandom
+ #define HDrandom() random()
+ #endif /* HDrandom */
+#else /* H5_HAVE_RANDOM */
+ #ifndef HDrand
+ #define HDrand() rand()
+ #endif /* HDrand */
+ #ifndef HDrandom
+ #define HDrandom() rand()
+ #endif /* HDrandom */
+#endif /* H5_HAVE_RANDOM */
+
+#ifndef HDread
+ #define HDread(F,M,Z) read(F,M,Z)
+#endif /* HDread */
+#ifndef HDreaddir
+ #define HDreaddir(D) readdir(D)
+#endif /* HDreaddir */
+#ifndef HDrealloc
+ #define HDrealloc(M,Z) realloc(M,Z)
+#endif /* HDrealloc */
+#ifndef HDrealpath
+ #define HDrealpath(F1,F2) realpath(F1,F2)
+#endif /* HDrealloc */
+#ifndef HDremove
+ #define HDremove(S) remove(S)
+#endif /* HDremove */
+#ifndef HDrename
+ #define HDrename(OLD,NEW) rename(OLD,NEW)
+#endif /* HDrename */
+#ifndef HDrewind
+ #define HDrewind(F) rewind(F)
+#endif /* HDrewind */
+#ifndef HDrewinddir
+ #define HDrewinddir(D) rewinddir(D)
+#endif /* HDrewinddir */
+#ifndef HDround
+ #define HDround(V) round(V)
+#endif /* HDround */
+#ifndef HDroundf
+ #define HDroundf(V) roundf(V)
+#endif /* HDroundf */
+#ifndef HDroundl
+ #define HDroundl(V) roundl(V)
+#endif /* HDroundl */
+#ifndef HDrmdir
+ #define HDrmdir(S) rmdir(S)
+#endif /* HDrmdir */
+/* scanf() variable arguments */
+#ifndef HDselect
+ #define HDselect(N,RD,WR,ER,T) select(N,RD,WR,ER,T)
+#endif /* HDsetbuf */
+#ifndef HDsetbuf
+ #define HDsetbuf(F,S) setbuf(F,S)
+#endif /* HDsetbuf */
+#ifndef HDsetenv
+ #define HDsetenv(N,V,O) setenv(N,V,O)
+#endif /* HDsetenv */
+#ifndef HDsetgid
+ #define HDsetgid(G) setgid(G)
+#endif /* HDsetgid */
+#ifndef HDsetjmp
+ #define HDsetjmp(J) setjmp(J)
+#endif /* HDsetjmp */
+#ifndef HDsetlocale
+ #define HDsetlocale(N,S) setlocale(N,S)
+#endif /* HDsetlocale */
+#ifndef HDsetpgid
+ #define HDsetpgid(P,PG) setpgid(P,PG)
+#endif /* HDsetpgid */
+#ifndef HDsetsid
+ #define HDsetsid() setsid()
+#endif /* HDsetsid */
+#ifndef HDsetuid
+ #define HDsetuid(U) setuid(U)
+#endif /* HDsetuid */
+#ifndef HDsetvbuf
+ #define HDsetvbuf(F,S,M,Z) setvbuf(F,S,M,Z)
+#endif /* HDsetvbuf */
+#ifndef HDsigaddset
+ #define HDsigaddset(S,N) sigaddset(S,N)
+#endif /* HDsigaddset */
+#ifndef HDsigdelset
+ #define HDsigdelset(S,N) sigdelset(S,N)
+#endif /* HDsigdelset */
+#ifndef HDsigemptyset
+ #define HDsigemptyset(S) sigemptyset(S)
+#endif /* HDsigemptyset */
+#ifndef HDsigfillset
+ #define HDsigfillset(S) sigfillset(S)
+#endif /* HDsigfillset */
+#ifndef HDsigismember
+ #define HDsigismember(S,N) sigismember(S,N)
+#endif /* HDsigismember */
+#ifndef HDsiglongjmp
+ #define HDsiglongjmp(J,N) siglongjmp(J,N)
+#endif /* HDsiglongjmp */
+#ifndef HDsignal
+ #define HDsignal(N,F) signal(N,F)
+#endif /* HDsignal */
+#ifndef HDsigpending
+ #define HDsigpending(S) sigpending(S)
+#endif /* HDsigpending */
+#ifndef HDsigprocmask
+ #define HDsigprocmask(H,S,O) sigprocmask(H,S,O)
+#endif /* HDsigprocmask */
+#ifndef HDsigsetjmp
+ #define HDsigsetjmp(J,N) sigsetjmp(J,N)
+#endif /* HDsigsetjmp */
+#ifndef HDsigsuspend
+ #define HDsigsuspend(S) sigsuspend(S)
+#endif /* HDsigsuspend */
+#ifndef HDsin
+ #define HDsin(X) sin(X)
+#endif /* HDsin */
+#ifndef HDsinh
+ #define HDsinh(X) sinh(X)
+#endif /* HDsinh */
+#ifndef HDsleep
+ #define HDsleep(N) sleep(N)
+#endif /* HDsleep */
+#ifndef HDsnprintf
+ #define HDsnprintf snprintf /*varargs*/
+#endif /* HDsnprintf */
+#ifndef HDsprintf
+ #define HDsprintf sprintf /*varargs*/
+#endif /* HDsprintf */
+#ifndef HDsqrt
+ #define HDsqrt(X) sqrt(X)
+#endif /* HDsqrt */
+#ifdef H5_HAVE_RAND_R
+ H5_DLL void HDsrand(unsigned int seed);
+ #ifndef HDsrandom
+ #define HDsrandom(S) HDsrand(S)
+ #endif /* HDsrandom */
+#elif H5_HAVE_RANDOM
+ #ifndef HDsrand
+ #define HDsrand(S) srandom(S)
+ #endif /* HDsrand */
+ #ifndef HDsrandom
+ #define HDsrandom(S) srandom(S)
+ #endif /* HDsrandom */
+#else /* H5_HAVE_RAND_R */
+ #ifndef HDsrand
+ #define HDsrand(S) srand(S)
+ #endif /* HDsrand */
+ #ifndef HDsrandom
+ #define HDsrandom(S) srand(S)
+ #endif /* HDsrandom */
+#endif /* H5_HAVE_RAND_R */
+/* sscanf() variable arguments */
+
+#ifndef HDstrcat
+ #define HDstrcat(X,Y) strcat(X,Y)
+#endif /* HDstrcat */
+#ifndef HDstrchr
+ #define HDstrchr(S,C) strchr(S,C)
+#endif /* HDstrchr */
+#ifndef HDstrcmp
+ #define HDstrcmp(X,Y) strcmp(X,Y)
+#endif /* HDstrcmp */
+#ifndef HDstrcasecmp
+ #define HDstrcasecmp(X,Y) strcasecmp(X,Y)
+#endif /* HDstrcasecmp */
+#ifndef HDstrcoll
+ #define HDstrcoll(X,Y) strcoll(X,Y)
+#endif /* HDstrcoll */
+#ifndef HDstrcpy
+ #define HDstrcpy(X,Y) strcpy(X,Y)
+#endif /* HDstrcpy */
+#ifndef HDstrcspn
+ #define HDstrcspn(X,Y) strcspn(X,Y)
+#endif /* HDstrcspn */
+#ifndef HDstrerror
+ #define HDstrerror(N) strerror(N)
+#endif /* HDstrerror */
+#ifndef HDstrftime
+ #define HDstrftime(S,Z,F,T) strftime(S,Z,F,T)
+#endif /* HDstrftime */
+#ifndef HDstrlen
+ #define HDstrlen(S) strlen(S)
+#endif /* HDstrlen */
+#ifndef HDstrncat
+ #define HDstrncat(X,Y,Z) strncat(X,Y,Z)
+#endif /* HDstrncat */
+#ifndef HDstrncmp
+ #define HDstrncmp(X,Y,Z) strncmp(X,Y,Z)
+#endif /* HDstrncmp */
+#ifndef HDstrncpy
+ #define HDstrncpy(X,Y,Z) strncpy(X,Y,Z)
+#endif /* HDstrncpy */
+#ifndef HDstrpbrk
+ #define HDstrpbrk(X,Y) strpbrk(X,Y)
+#endif /* HDstrpbrk */
+#ifndef HDstrrchr
+ #define HDstrrchr(S,C) strrchr(S,C)
+#endif /* HDstrrchr */
+#ifndef HDstrspn
+ #define HDstrspn(X,Y) strspn(X,Y)
+#endif /* HDstrspn */
+#ifndef HDstrstr
+ #define HDstrstr(X,Y) strstr(X,Y)
+#endif /* HDstrstr */
+#ifndef HDstrtod
+ #define HDstrtod(S,R) strtod(S,R)
+#endif /* HDstrtod */
+#ifndef HDstrtok
+ #define HDstrtok(X,Y) strtok(X,Y)
+#endif /* HDstrtok */
+#ifndef HDstrtol
+ #define HDstrtol(S,R,N) strtol(S,R,N)
+#endif /* HDstrtol */
+#ifndef HDstrtoll
+ #ifdef H5_HAVE_STRTOLL
+ #define HDstrtoll(S,R,N) strtoll(S,R,N)
+ #else
+ H5_DLL int64_t HDstrtoll (const char *s, const char **rest, int base);
+ #endif /* H5_HAVE_STRTOLL */
+#endif /* HDstrtoll */
+#ifndef HDstrtoul
+ #define HDstrtoul(S,R,N) strtoul(S,R,N)
+#endif /* HDstrtoul */
+#ifndef HDstrtoull
+ #define HDstrtoull(S,R,N) strtoull(S,R,N)
+#endif /* HDstrtoul */
+#ifndef HDstrxfrm
+ #define HDstrxfrm(X,Y,Z) strxfrm(X,Y,Z)
+#endif /* HDstrxfrm */
+#ifdef H5_HAVE_SYMLINK
+ #ifndef HDsymlink
+ #define HDsymlink(F1,F2) symlink(F1,F2)
+ #endif /* HDsymlink */
+#endif /* H5_HAVE_SYMLINK */
+#ifndef HDsysconf
+ #define HDsysconf(N) sysconf(N)
+#endif /* HDsysconf */
+#ifndef HDsystem
+ #define HDsystem(S) system(S)
+#endif /* HDsystem */
+#ifndef HDtan
+ #define HDtan(X) tan(X)
+#endif /* HDtan */
+#ifndef HDtanh
+ #define HDtanh(X) tanh(X)
+#endif /* HDtanh */
+#ifndef HDtcdrain
+ #define HDtcdrain(F) tcdrain(F)
+#endif /* HDtcdrain */
+#ifndef HDtcflow
+ #define HDtcflow(F,A) tcflow(F,A)
+#endif /* HDtcflow */
+#ifndef HDtcflush
+ #define HDtcflush(F,N) tcflush(F,N)
+#endif /* HDtcflush */
+#ifndef HDtcgetattr
+ #define HDtcgetattr(F,T) tcgetattr(F,T)
+#endif /* HDtcgetattr */
+#ifndef HDtcgetpgrp
+ #define HDtcgetpgrp(F) tcgetpgrp(F)
+#endif /* HDtcgetpgrp */
+#ifndef HDtcsendbreak
+ #define HDtcsendbreak(F,N) tcsendbreak(F,N)
+#endif /* HDtcsendbreak */
+#ifndef HDtcsetattr
+ #define HDtcsetattr(F,O,T) tcsetattr(F,O,T)
+#endif /* HDtcsetattr */
+#ifndef HDtcsetpgrp
+ #define HDtcsetpgrp(F,N) tcsetpgrp(F,N)
+#endif /* HDtcsetpgrp */
+#ifndef HDtime
+ #define HDtime(T) time(T)
+#endif /* HDtime */
+#ifndef HDtimes
+ #define HDtimes(T) times(T)
+#endif /* HDtimes*/
+#ifndef HDtmpfile
+ #define HDtmpfile() tmpfile()
+#endif /* HDtmpfile */
+#ifndef HDtmpnam
+ #define HDtmpnam(S) tmpnam(S)
+#endif /* HDtmpnam */
+#ifndef HDtolower
+ #define HDtolower(C) tolower(C)
+#endif /* HDtolower */
+#ifndef HDtoupper
+ #define HDtoupper(C) toupper(C)
+#endif /* HDtoupper */
+#ifndef HDttyname
+ #define HDttyname(F) ttyname(F)
+#endif /* HDttyname */
+#ifndef HDtzset
+ #define HDtzset() tzset()
+#endif /* HDtzset */
+#ifndef HDumask
+ #define HDumask(N) umask(N)
+#endif /* HDumask */
+#ifndef HDuname
+ #define HDuname(S) uname(S)
+#endif /* HDuname */
+#ifndef HDungetc
+ #define HDungetc(C,F) ungetc(C,F)
+#endif /* HDungetc */
+#ifndef HDunlink
+ #define HDunlink(S) unlink(S)
+#endif /* HDunlink */
+#ifndef HDutime
+ #define HDutime(S,T) utime(S,T)
+#endif /* HDutime */
+#ifndef HDva_arg
+ #define HDva_arg(A,T) va_arg(A,T)
+#endif /* HDva_arg */
+#ifndef HDva_end
+ #define HDva_end(A) va_end(A)
+#endif /* HDva_end */
+#ifndef HDva_start
+ #define HDva_start(A,P) va_start(A,P)
+#endif /* HDva_start */
+#ifndef HDvasprintf
+ #define HDvasprintf(RET,FMT,A) vasprintf(RET,FMT,A)
+#endif /* HDvasprintf */
+#ifndef HDvfprintf
+ #define HDvfprintf(F,FMT,A) vfprintf(F,FMT,A)
+#endif /* HDvfprintf */
+#ifndef HDvprintf
+ #define HDvprintf(FMT,A) vprintf(FMT,A)
+#endif /* HDvprintf */
+#ifndef HDvsprintf
+ #define HDvsprintf(S,FMT,A) vsprintf(S,FMT,A)
+#endif /* HDvsprintf */
+#ifndef HDvsnprintf
+ #define HDvsnprintf(S,N,FMT,A) vsnprintf(S,N,FMT,A)
+#endif /* HDvsnprintf */
+#ifndef HDwait
+ #define HDwait(W) wait(W)
+#endif /* HDwait */
+#ifndef HDwaitpid
+ #define HDwaitpid(P,W,O) waitpid(P,W,O)
+#endif /* HDwaitpid */
+#ifndef HDwcstombs
+ #define HDwcstombs(S,P,Z) wcstombs(S,P,Z)
+#endif /* HDwcstombs */
+#ifndef HDwctomb
+ #define HDwctomb(S,C) wctomb(S,C)
+#endif /* HDwctomb */
+#ifndef HDwrite
+ #define HDwrite(F,M,Z) write(F,M,Z)
+#endif /* HDwrite */
+
+/*
+ * And now for a couple non-Posix functions... Watch out for systems that
+ * define these in terms of macros.
+ */
+#if !defined strdup && !defined H5_HAVE_STRDUP
+extern char *strdup(const char *s);
+#endif
+
+#ifndef HDstrdup
+ #define HDstrdup(S) strdup(S)
+#endif /* HDstrdup */
+
+#ifndef HDpthread_self
+ #define HDpthread_self() pthread_self()
+#endif /* HDpthread_self */
+
+/* Use this version of pthread_self for printing the thread ID */
+#ifndef HDpthread_self_ulong
+ #define HDpthread_self_ulong() ((unsigned long)pthread_self())
+#endif /* HDpthread_self_ulong */
+
+/* Macro for "stringizing" an integer in the C preprocessor (use H5_TOSTRING) */
+/* (use H5_TOSTRING, H5_STRINGIZE is just part of the implementation) */
+#define H5_STRINGIZE(x) #x
+#define H5_TOSTRING(x) H5_STRINGIZE(x)
+
+/* Macro for "glueing" together items, for re-scanning macros */
+#define H5_GLUE(x,y) x##y
+#define H5_GLUE3(x,y,z) x##y##z
+#define H5_GLUE4(w,x,y,z) w##x##y##z
+
+/*
+ * A macro for detecting over/under-flow when casting between types
+ */
+#ifndef NDEBUG
+#define H5_CHECK_OVERFLOW(var, vartype, casttype) \
+{ \
+ casttype _tmp_overflow = (casttype)(var); \
+ HDassert((var) == (vartype)_tmp_overflow); \
+}
+#else /* NDEBUG */
+#define H5_CHECK_OVERFLOW(var, vartype, casttype)
+#endif /* NDEBUG */
+
+/*
+ * A macro for detecting over/under-flow when assigning between types
+ */
+#ifndef NDEBUG
+#define ASSIGN_TO_SMALLER_SIZE(dst, dsttype, src, srctype) \
+{ \
+ srctype _tmp_src = (srctype)(src); \
+ dsttype _tmp_dst = (dsttype)(_tmp_src); \
+ HDassert(_tmp_src == (srctype)_tmp_dst); \
+ (dst) = _tmp_dst; \
+}
+
+#define ASSIGN_TO_LARGER_SIZE_SAME_SIGNED(dst, dsttype, src, srctype) \
+ (dst) = (dsttype)(src);
+
+#define ASSIGN_TO_LARGER_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype) \
+{ \
+ srctype _tmp_src = (srctype)(src); \
+ dsttype _tmp_dst = (dsttype)(_tmp_src); \
+ HDassert(_tmp_src >= 0); \
+ HDassert(_tmp_src == _tmp_dst); \
+ (dst) = _tmp_dst; \
+}
+
+#define ASSIGN_TO_LARGER_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype) \
+ (dst) = (dsttype)(src);
+
+#define ASSIGN_TO_SAME_SIZE_UNSIGNED_TO_SIGNED(dst, dsttype, src, srctype) \
+{ \
+ srctype _tmp_src = (srctype)(src); \
+ dsttype _tmp_dst = (dsttype)(_tmp_src); \
+ HDassert(_tmp_dst >= 0); \
+ HDassert(_tmp_src == (srctype)_tmp_dst); \
+ (dst) = _tmp_dst; \
+}
+
+#define ASSIGN_TO_SAME_SIZE_SIGNED_TO_UNSIGNED(dst, dsttype, src, srctype) \
+{ \
+ srctype _tmp_src = (srctype)(src); \
+ dsttype _tmp_dst = (dsttype)(_tmp_src); \
+ HDassert(_tmp_src >= 0); \
+ HDassert(_tmp_src == (srctype)_tmp_dst); \
+ (dst) = _tmp_dst; \
+}
+
+#define ASSIGN_TO_SAME_SIZE_SAME_SIGNED(dst, dsttype, src, srctype) \
+ (dst) = (dsttype)(src);
+
+/* Include the generated overflow header file */
+#include "H5overflow.h"
+
+/* Assign a variable to one of a different size (think safer dst = (dsttype)src").
+ * The code generated by the macro checks for overflows.
+ */
+#define H5_CHECKED_ASSIGN(dst, dsttype, src, srctype) \
+ H5_GLUE4(ASSIGN_,srctype,_TO_,dsttype)(dst,dsttype,src,srctype)\
+
+#else /* NDEBUG */
+#define H5_CHECKED_ASSIGN(dst, dsttype, src, srctype) \
+ (dst) = (dsttype)(src);
+#endif /* NDEBUG */
+
+#if defined(H5_HAVE_WINDOW_PATH)
+
+/* directory delimiter for Windows: slash and backslash are acceptable on Windows */
+#define H5_DIR_SLASH_SEPC '/'
+#define H5_DIR_SEPC '\\'
+#define H5_DIR_SEPS "\\"
+#define H5_CHECK_DELIMITER(SS) ((SS == H5_DIR_SEPC) || (SS == H5_DIR_SLASH_SEPC))
+#define H5_CHECK_ABSOLUTE(NAME) ((HDisalpha(NAME[0])) && (NAME[1] == ':') && (H5_CHECK_DELIMITER(NAME[2])))
+#define H5_CHECK_ABS_DRIVE(NAME) ((HDisalpha(NAME[0])) && (NAME[1] == ':'))
+#define H5_CHECK_ABS_PATH(NAME) (H5_CHECK_DELIMITER(NAME[0]))
+
+#define H5_GET_LAST_DELIMITER(NAME, ptr) { \
+ char *slash, *backslash; \
+ \
+ slash = HDstrrchr(NAME, H5_DIR_SLASH_SEPC); \
+ backslash = HDstrrchr(NAME, H5_DIR_SEPC); \
+ if(backslash > slash) \
+ (ptr = backslash); \
+ else \
+ (ptr = slash); \
+}
+
+#else /* H5_HAVE_WINDOW_PATH */
+
+#define H5_DIR_SEPC '/'
+#define H5_DIR_SEPS "/"
+#define H5_CHECK_DELIMITER(SS) (SS == H5_DIR_SEPC)
+#define H5_CHECK_ABSOLUTE(NAME) (H5_CHECK_DELIMITER(*NAME))
+#define H5_CHECK_ABS_DRIVE(NAME) (0)
+#define H5_CHECK_ABS_PATH(NAME) (0)
+#define H5_GET_LAST_DELIMITER(NAME, ptr) ptr = HDstrrchr(NAME, H5_DIR_SEPC);
+
+#endif /* H5_HAVE_WINDOW_PATH */
+
+#define H5_COLON_SEPC ':'
+
+
+/* Use FUNC to safely handle variations of C99 __func__ keyword handling */
+#ifdef H5_HAVE_C99_FUNC
+#define FUNC __func__
+#elif defined(H5_HAVE_FUNCTION)
+#define FUNC __FUNCTION__
+#else
+#error "We need __func__ or __FUNCTION__ to test function names!"
+#endif
+
+/*
+ * These macros check whether debugging has been requested for a certain
+ * package at run-time. Code for debugging is conditionally compiled by
+ * defining constants like `H5X_DEBUG'. In order to see the output though
+ * the code must be enabled at run-time with an environment variable
+ * HDF5_DEBUG which is a list of packages to debug.
+ *
+ * Note: If you add/remove items from this enum then be sure to update the
+ * information about the package in H5_init_library().
+ */
+typedef enum {
+ H5_PKG_A, /*Attributes */
+ H5_PKG_AC, /*Meta data cache */
+ H5_PKG_B, /*B-trees */
+ H5_PKG_D, /*Datasets */
+ H5_PKG_E, /*Error handling */
+ H5_PKG_F, /*Files */
+ H5_PKG_G, /*Groups */
+ H5_PKG_HG, /*Global heap */
+ H5_PKG_HL, /*Local heap */
+ H5_PKG_I, /*Interface */
+ H5_PKG_MF, /*File memory management */
+ H5_PKG_MM, /*Core memory management */
+ H5_PKG_O, /*Object headers */
+ H5_PKG_P, /*Property lists */
+ H5_PKG_S, /*Data spaces */
+ H5_PKG_T, /*Data types */
+ H5_PKG_V, /*Vector functions */
+ H5_PKG_Z, /*Raw data filters */
+ H5_NPKGS /*Must be last */
+} H5_pkg_t;
+
+typedef struct H5_debug_open_stream_t {
+ FILE *stream; /* Open output stream */
+ struct H5_debug_open_stream_t *next; /* Next open output stream */
+} H5_debug_open_stream_t;
+
+typedef struct H5_debug_t {
+ FILE *trace; /*API trace output stream */
+ hbool_t ttop; /*Show only top-level calls? */
+ hbool_t ttimes; /*Show trace event times? */
+ struct {
+ const char *name; /*package name */
+ FILE *stream; /*output stream or NULL */
+ } pkg[H5_NPKGS];
+ H5_debug_open_stream_t *open_stream; /* Stack of open output streams */
+} H5_debug_t;
+
+#ifdef H5_HAVE_PARALLEL
+extern hbool_t H5_coll_api_sanity_check_g;
+#endif /* H5_HAVE_PARALLEL */
+
+extern H5_debug_t H5_debug_g;
+#define H5DEBUG(X) (H5_debug_g.pkg[H5_PKG_##X].stream)
+/* Do not use const else AIX strings does not show it. */
+extern char H5libhdf5_settings[]; /* embedded library information */
+
+/*-------------------------------------------------------------------------
+ * Purpose: These macros are inserted automatically just after the
+ * FUNC_ENTER() macro of API functions and are used to trace
+ * application program execution. Unless H5_DEBUG_API has been
+ * defined they are no-ops.
+ *
+ * Arguments: R - Return type encoded as a string
+ * T - Argument types encoded as a string
+ * A0-An - Arguments. The number at the end of the macro name
+ * indicates the number of arguments.
+ *
+ * Programmer: Robb Matzke
+ *
+ * Modifications:
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5_DEBUG_API
+#define H5TRACE_DECL const char *RTYPE=NULL; \
+ double CALLTIME;
+#define H5TRACE0(R,T) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T)
+#define H5TRACE1(R,T,A0) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0)
+#define H5TRACE2(R,T,A0,A1) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1)
+#define H5TRACE3(R,T,A0,A1,A2) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2)
+#define H5TRACE4(R,T,A0,A1,A2,A3) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3)
+#define H5TRACE5(R,T,A0,A1,A2,A3,A4) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4)
+#define H5TRACE6(R,T,A0,A1,A2,A3,A4,A5) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5)
+#define H5TRACE7(R,T,A0,A1,A2,A3,A4,A5,A6) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5,#A6,A6)
+#define H5TRACE8(R,T,A0,A1,A2,A3,A4,A5,A6,A7) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5,#A6,A6,#A7,A7)
+#define H5TRACE9(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5,#A6,A6,#A7,A7,#A8,A8)
+#define H5TRACE10(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5,#A6,A6,#A7,A7,#A8,A8,#A9,A9)
+#define H5TRACE11(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) RTYPE=R; \
+ CALLTIME=H5_trace(NULL,FUNC,T,#A0,A0,#A1,A1,#A2,A2,#A3,A3, \
+ #A4,A4,#A5,A5,#A6,A6,#A7,A7,#A8,A8,#A9,A9, \
+ #A10,A10)
+#define H5TRACE_RETURN(V) if (RTYPE) { \
+ H5_trace(&CALLTIME,FUNC,RTYPE,NULL,V); \
+ RTYPE=NULL; \
+ }
+#else
+#define H5TRACE_DECL /*void*/
+#define H5TRACE0(R,T) /*void*/
+#define H5TRACE1(R,T,A0) /*void*/
+#define H5TRACE2(R,T,A0,A1) /*void*/
+#define H5TRACE3(R,T,A0,A1,A2) /*void*/
+#define H5TRACE4(R,T,A0,A1,A2,A3) /*void*/
+#define H5TRACE5(R,T,A0,A1,A2,A3,A4) /*void*/
+#define H5TRACE6(R,T,A0,A1,A2,A3,A4,A5) /*void*/
+#define H5TRACE7(R,T,A0,A1,A2,A3,A4,A5,A6) /*void*/
+#define H5TRACE8(R,T,A0,A1,A2,A3,A4,A5,A6,A7) /*void*/
+#define H5TRACE9(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8) /*void*/
+#define H5TRACE10(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9) /*void*/
+#define H5TRACE11(R,T,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) /*void*/
+#define H5TRACE_RETURN(V) /*void*/
+#endif
+
+H5_DLL double H5_trace(const double *calltime, const char *func, const char *type, ...);
+
+
+/*-------------------------------------------------------------------------
+ * Purpose: Register function entry for library initialization and code
+ * profiling.
+ *
+ * Notes: Every file must have a file-scope variable called
+ * `initialize_interface_g' of type hbool_t which is initialized
+ * to FALSE.
+ *
+ * Don't use local variable initializers which contain
+ * calls to other library functions since the initializer
+ * would happen before the FUNC_ENTER() gets called. Don't
+ * use initializers that require special cleanup code to
+ * execute if FUNC_ENTER() fails since a failing FUNC_ENTER()
+ * returns immediately without branching to the `done' label.
+ *
+ * Programmer: Quincey Koziol
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* `S' is the name of a function which is being tested to check if it's
+ * an API function.
+ *
+ * BADNESS:
+ * - Underscore at positions 2 or 3 (0-indexed string). Handles
+ * H5_ and H5X_.
+ * - Underscore at position 4 if position 3 is uppercase or a digit.
+ * Handles H5XY_.
+ */
+#define H5_IS_API(S) (\
+ '_'!=((const char *)S)[2] /* underscore at position 2 */ \
+ && '_'!=((const char *)S)[3] /* underscore at position 3 */ \
+ && !( /* NOT */ \
+ ((const char *)S)[4] /* pos 4 exists */ \
+ && (HDisupper(S[3]) || HDisdigit(S[3])) /* pos 3 dig | uc */ \
+ && '_'==((const char *)S)[4] /* pos 4 underscore */ \
+ )\
+)
+
+/* `S' is the name of a function which is being tested to check if it's */
+/* a public API function */
+#define H5_IS_PUB(S) (((HDisdigit(S[1]) || HDisupper(S[1])) && HDislower(S[2])) || \
+ ((HDisdigit(S[2]) || HDisupper(S[2])) && HDislower(S[3])) || \
+ (!S[4] || ((HDisdigit(S[3]) || HDisupper(S[3])) && HDislower(S[4]))))
+
+/* `S' is the name of a function which is being tested to check if it's */
+/* a private library function */
+#define H5_IS_PRIV(S) (((HDisdigit(S[1]) || HDisupper(S[1])) && '_' == S[2] && HDislower(S[3])) || \
+ ((HDisdigit(S[2]) || HDisupper(S[2])) && '_' == S[3] && HDislower(S[4])) || \
+ ((HDisdigit(S[3]) || HDisupper(S[3])) && '_' == S[4] && HDislower(S[5])))
+
+/* `S' is the name of a function which is being tested to check if it's */
+/* a package private function */
+#define H5_IS_PKG(S) (((HDisdigit(S[1]) || HDisupper(S[1])) && '_' == S[2] && '_' == S[3] && HDislower(S[4])) || \
+ ((HDisdigit(S[2]) || HDisupper(S[2])) && '_' == S[3] && '_' == S[4] && HDislower(S[5])) || \
+ ((HDisdigit(S[3]) || HDisupper(S[3])) && '_' == S[4] && '_' == S[5] && HDislower(S[6])))
+
+/* global library version information string */
+extern char H5_lib_vers_info_g[];
+
+/* Lock headers */
+#ifdef H5_HAVE_THREADSAFE
+
+/* Include required thread-safety header */
+#include "H5TSprivate.h"
+
+/* replacement structure for original global variable */
+typedef struct H5_api_struct {
+ H5TS_mutex_t init_lock; /* API entrance mutex */
+ hbool_t H5_libinit_g; /* Has the library been initialized? */
+ hbool_t H5_libterm_g; /* Is the library being shutdown? */
+} H5_api_t;
+
+/* Macros for accessing the global variables */
+#define H5_INIT_GLOBAL (H5_g.H5_libinit_g)
+#define H5_TERM_GLOBAL (H5_g.H5_libterm_g)
+
+/* Macro for first thread initialization */
+#ifdef H5_HAVE_WIN_THREADS
+#define H5_FIRST_THREAD_INIT InitOnceExecuteOnce(&H5TS_first_init_g, H5TS_win32_process_enter, NULL, NULL);
+#else
+#define H5_FIRST_THREAD_INIT pthread_once(&H5TS_first_init_g, H5TS_pthread_first_thread_init);
+#endif
+
+/* Macros for threadsafe HDF-5 Phase I locks */
+#define H5_API_LOCK \
+ H5TS_mutex_lock(&H5_g.init_lock);
+#define H5_API_UNLOCK \
+ H5TS_mutex_unlock(&H5_g.init_lock);
+
+/* Macros for thread cancellation-safe mechanism */
+#define H5_API_UNSET_CANCEL \
+ H5TS_cancel_count_inc();
+
+#define H5_API_SET_CANCEL \
+ H5TS_cancel_count_dec();
+
+extern H5_api_t H5_g;
+
+#else /* H5_HAVE_THREADSAFE */
+
+/* disable any first thread init mechanism */
+#define H5_FIRST_THREAD_INIT
+
+/* disable locks (sequential version) */
+#define H5_API_LOCK
+#define H5_API_UNLOCK
+
+/* disable cancelability (sequential version) */
+#define H5_API_UNSET_CANCEL
+#define H5_API_SET_CANCEL
+
+/* extern global variables */
+extern hbool_t H5_libinit_g; /* Has the library been initialized? */
+extern hbool_t H5_libterm_g; /* Is the library being shutdown? */
+
+/* Macros for accessing the global variables */
+#define H5_INIT_GLOBAL (H5_libinit_g)
+#define H5_TERM_GLOBAL (H5_libterm_g)
+
+#endif /* H5_HAVE_THREADSAFE */
+
+#ifdef H5_HAVE_CODESTACK
+
+/* Include required function stack header */
+#include "H5CSprivate.h"
+
+#define H5_PUSH_FUNC H5CS_push(FUNC);
+#define H5_POP_FUNC H5CS_pop();
+#else /* H5_HAVE_CODESTACK */
+#define H5_PUSH_FUNC /* void */
+#define H5_POP_FUNC /* void */
+#endif /* H5_HAVE_CODESTACK */
+
+#ifdef H5_HAVE_MPE
+extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */
+#endif
+
+/* Macros for referencing package initialization symbols */
+#define H5_PACKAGE_INIT_VAR(x) H5_GLUE(x, _init_g)
+#define H5_PACKAGE_INIT_FUNC(x) H5_GLUE(x, __init_package)
+
+/* Macros for defining package initialization routines */
+#ifdef H5_MY_PKG
+#define H5_PKG_INIT_VAR H5_PACKAGE_INIT_VAR(H5_MY_PKG)
+#define H5_PKG_INIT_FUNC H5_PACKAGE_INIT_FUNC(H5_MY_PKG)
+#define H5_PACKAGE_YES_INIT(err) \
+ /* Initialize this interface or bust */ \
+ if(!H5_PKG_INIT_VAR && !H5_TERM_GLOBAL) { \
+ H5_PKG_INIT_VAR = TRUE; \
+ if(H5_PKG_INIT_FUNC() < 0) { \
+ H5_PKG_INIT_VAR = FALSE; \
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, err, "interface initialization failed") \
+ } \
+ }
+#define H5_PACKAGE_NO_INIT(err) \
+ /* Initialize this interface or bust */ \
+ if(!H5_PKG_INIT_VAR && !H5_TERM_GLOBAL) \
+ H5_PKG_INIT_VAR = TRUE;
+#define H5_PACKAGE_INIT(pkg_init, err) H5_GLUE3(H5_PACKAGE_, pkg_init, _INIT)(err)
+#else /* H5_MY_PKG */
+#define H5_PKG_INIT_VAR (TRUE)
+#define H5_PACKAGE_INIT(pkg_init, err)
+#endif /* H5_MY_PKG */
+
+
+#ifndef NDEBUG
+#define FUNC_ENTER_CHECK_NAME(asrt) \
+ { \
+ static hbool_t func_check = FALSE; \
+ \
+ if(!func_check) { \
+ /* Check function naming status */ \
+ HDassert(asrt && "Function naming conventions are incorrect - check H5_IS_API|PUB|PRIV|PKG macros in H5private.h (this is usually due to an incorrect number of underscores)"); \
+ \
+ /* Don't check again */ \
+ func_check = TRUE; \
+ } /* end if */ \
+ } /* end scope */
+#else /* NDEBUG */
+#define FUNC_ENTER_CHECK_NAME(asrt)
+#endif /* NDEBUG */
+
+
+#define FUNC_ENTER_COMMON(asrt) \
+ hbool_t err_occurred = FALSE; \
+ \
+ FUNC_ENTER_CHECK_NAME(asrt);
+
+#define FUNC_ENTER_COMMON_NOERR(asrt) \
+ FUNC_ENTER_CHECK_NAME(asrt);
+
+/* Threadsafety initialization code for API routines */
+#define FUNC_ENTER_API_THREADSAFE \
+ /* Initialize the thread-safe code */ \
+ H5_FIRST_THREAD_INIT \
+ \
+ /* Grab the mutex for the library */ \
+ H5_API_UNSET_CANCEL \
+ H5_API_LOCK
+
+/* Local variables for API routines */
+#define FUNC_ENTER_API_VARS \
+ MPE_LOG_VARS \
+ H5TRACE_DECL
+
+#define FUNC_ENTER_API_COMMON \
+ FUNC_ENTER_API_VARS \
+ FUNC_ENTER_COMMON(H5_IS_API(FUNC)); \
+ FUNC_ENTER_API_THREADSAFE;
+
+#define FUNC_ENTER_API_INIT(err) \
+ /* Initialize the library */ \
+ if(!H5_INIT_GLOBAL && !H5_TERM_GLOBAL) { \
+ H5_INIT_GLOBAL = TRUE; \
+ if(H5_init_library() < 0) \
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, err, "library initialization failed") \
+ } /* end if */ \
+ \
+ /* Initialize the package, if appropriate */ \
+ H5_PACKAGE_INIT(H5_MY_PKG_INIT, err) \
+ \
+ /* Push the name of this function on the function stack */ \
+ H5_PUSH_FUNC \
+ \
+ BEGIN_MPE_LOG
+
+/* Use this macro for all "normal" API functions */
+#define FUNC_ENTER_API(err) {{ \
+ FUNC_ENTER_API_COMMON \
+ FUNC_ENTER_API_INIT(err); \
+ /* Clear thread error stack entering public functions */ \
+ H5E_clear_stack(NULL); \
+ {
+
+/*
+ * Use this macro for API functions that shouldn't clear the error stack
+ * like H5Eprint and H5Ewalk.
+ */
+#define FUNC_ENTER_API_NOCLEAR(err) {{ \
+ FUNC_ENTER_API_COMMON \
+ FUNC_ENTER_API_INIT(err); \
+ {
+
+/*
+ * Use this macro for API functions that shouldn't perform _any_ initialization
+ * of the library or an interface, just perform tracing, etc. Examples
+ * are: H5check_version, etc.
+ *
+ */
+#define FUNC_ENTER_API_NOINIT {{ \
+ FUNC_ENTER_API_COMMON \
+ H5_PUSH_FUNC \
+ BEGIN_MPE_LOG \
+ {
+
+/*
+ * Use this macro for API functions that shouldn't perform _any_ initialization
+ * of the library or an interface or push themselves on the function
+ * stack, just perform tracing, etc. Examples
+ * are: H5close, H5check_version, etc.
+ *
+ */
+#define FUNC_ENTER_API_NOINIT_NOERR_NOFS {{ \
+ FUNC_ENTER_API_VARS \
+ FUNC_ENTER_COMMON_NOERR(H5_IS_API(FUNC)); \
+ FUNC_ENTER_API_THREADSAFE; \
+ BEGIN_MPE_LOG \
+ {
+
+/* Note: this macro only works when there's _no_ interface initialization routine for the module */
+#define FUNC_ENTER_NOAPI_INIT(err) \
+ /* Initialize the package, if appropriate */ \
+ H5_PACKAGE_INIT(H5_MY_PKG_INIT, err) \
+ \
+ /* Push the name of this function on the function stack */ \
+ H5_PUSH_FUNC
+
+/* Use this macro for all "normal" non-API functions */
+#define FUNC_ENTER_NOAPI(err) { \
+ FUNC_ENTER_COMMON(!H5_IS_API(FUNC)); \
+ FUNC_ENTER_NOAPI_INIT(err) \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for all non-API functions, which propagate errors, but don't issue them */
+#define FUNC_ENTER_NOAPI_NOERR { \
+ FUNC_ENTER_COMMON_NOERR(!H5_IS_API(FUNC)); \
+ FUNC_ENTER_NOAPI_INIT(-) \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/*
+ * Use this macro for non-API functions which fall into these categories:
+ * - static functions, since they must be called from a function in the
+ * interface, the library and interface must already be
+ * initialized.
+ * - functions which are called during library shutdown, since we don't
+ * want to re-initialize the library.
+ */
+#define FUNC_ENTER_NOAPI_NOINIT { \
+ FUNC_ENTER_COMMON(!H5_IS_API(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/*
+ * Use this macro for non-API functions which fall into these categories:
+ * - static functions, since they must be called from a function in the
+ * interface, the library and interface must already be
+ * initialized.
+ * - functions which are called during library shutdown, since we don't
+ * want to re-initialize the library.
+ * - functions that propagate, but don't issue errors
+ */
+#define FUNC_ENTER_NOAPI_NOINIT_NOERR { \
+ FUNC_ENTER_COMMON_NOERR(!H5_IS_API(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/*
+ * Use this macro for non-API functions which fall into these categories:
+ * - functions which shouldn't push their name on the function stack
+ * (so far, just the H5CS routines themselves)
+ *
+ */
+#define FUNC_ENTER_NOAPI_NOFS { \
+ FUNC_ENTER_COMMON(!H5_IS_API(FUNC)); \
+ \
+ /* Initialize the package, if appropriate */ \
+ H5_PACKAGE_INIT(H5_MY_PKG_INIT, err) \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/*
+ * Use this macro for non-API functions which fall into these categories:
+ * - functions which shouldn't push their name on the function stack
+ * (so far, just the H5CS routines themselves)
+ *
+ * This macro is used for functions which fit the above categories _and_
+ * also don't use the 'FUNC' variable (i.e. don't push errors on the error stack)
+ *
+ */
+#define FUNC_ENTER_NOAPI_NOERR_NOFS { \
+ FUNC_ENTER_COMMON_NOERR(!H5_IS_API(FUNC)); \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use the following two macros as replacements for the FUNC_ENTER_NOAPI
+ * and FUNC_ENTER_NOAPI_NOINIT macros when the function needs to set
+ * up a metadata tag. */
+#define FUNC_ENTER_NOAPI_TAG(dxpl_id, tag, err) { \
+ haddr_t prev_tag = HADDR_UNDEF; \
+ hid_t tag_dxpl_id = dxpl_id; \
+ \
+ FUNC_ENTER_COMMON(!H5_IS_API(FUNC)); \
+ if(H5AC_tag(tag_dxpl_id, tag, &prev_tag)<0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ FUNC_ENTER_NOAPI_INIT(err) \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+#define FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, tag, err) { \
+ haddr_t prev_tag = HADDR_UNDEF; \
+ hid_t tag_dxpl_id = dxpl_id; \
+ \
+ FUNC_ENTER_COMMON(!H5_IS_API(FUNC)); \
+ if(H5AC_tag(tag_dxpl_id, tag, &prev_tag)<0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for all "normal" package-level functions */
+#define FUNC_ENTER_PACKAGE { \
+ FUNC_ENTER_COMMON(H5_IS_PKG(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for package-level functions which propgate errors, but don't issue them */
+#define FUNC_ENTER_PACKAGE_NOERR { \
+ FUNC_ENTER_COMMON_NOERR(H5_IS_PKG(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use the following macro as replacement for the FUNC_ENTER_PACKAGE
+ * macro when the function needs to set up a metadata tag. */
+#define FUNC_ENTER_PACKAGE_TAG(dxpl_id, tag, err) { \
+ haddr_t prev_tag = HADDR_UNDEF; \
+ hid_t tag_dxpl_id = dxpl_id; \
+ \
+ FUNC_ENTER_COMMON(H5_IS_PKG(FUNC)); \
+ if(H5AC_tag(tag_dxpl_id, tag, &prev_tag) < 0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for all "normal" staticly-scoped functions */
+#define FUNC_ENTER_STATIC { \
+ FUNC_ENTER_COMMON(H5_IS_PKG(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for staticly-scoped functions which propgate errors, but don't issue them */
+#define FUNC_ENTER_STATIC_NOERR { \
+ FUNC_ENTER_COMMON_NOERR(H5_IS_PKG(FUNC)); \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use this macro for staticly-scoped functions which propgate errors, but don't issue them */
+/* And that shouldn't push their name on the function stack */
+#define FUNC_ENTER_STATIC_NOERR_NOFS { \
+ FUNC_ENTER_COMMON_NOERR(H5_IS_PKG(FUNC)); \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+/* Use the following macro as replacement for the FUNC_ENTER_STATIC
+ * macro when the function needs to set up a metadata tag. */
+#define FUNC_ENTER_STATIC_TAG(dxpl_id, tag, err) { \
+ haddr_t prev_tag = HADDR_UNDEF; \
+ hid_t tag_dxpl_id = dxpl_id; \
+ \
+ FUNC_ENTER_COMMON(H5_IS_PKG(FUNC)); \
+ if(H5AC_tag(tag_dxpl_id, tag, &prev_tag) < 0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ H5_PUSH_FUNC \
+ if(H5_PKG_INIT_VAR || !H5_TERM_GLOBAL) {
+
+
+/*-------------------------------------------------------------------------
+ * Purpose: Register function exit for code profiling. This should be
+ * the last statement executed by a function.
+ *
+ * Programmer: Quincey Koziol
+ *
+ *-------------------------------------------------------------------------
+ */
+/* Threadsafety termination code for API routines */
+#define FUNC_LEAVE_API_THREADSAFE \
+ H5_API_UNLOCK \
+ H5_API_SET_CANCEL
+
+#define FUNC_LEAVE_API(ret_value) \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ FINISH_MPE_LOG \
+ H5TRACE_RETURN(ret_value); \
+ H5_POP_FUNC \
+ if(err_occurred) \
+ (void)H5E_dump_api_stack(TRUE); \
+ FUNC_LEAVE_API_THREADSAFE \
+ return(ret_value); \
+}} /*end scope from beginning of FUNC_ENTER*/
+
+/* Use this macro to match the FUNC_ENTER_API_NOFS macro */
+#define FUNC_LEAVE_API_NOFS(ret_value) \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ FINISH_MPE_LOG \
+ H5TRACE_RETURN(ret_value); \
+ FUNC_LEAVE_API_THREADSAFE \
+ return(ret_value); \
+}} /*end scope from beginning of FUNC_ENTER*/
+
+#define FUNC_LEAVE_NOAPI(ret_value) \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ H5_POP_FUNC \
+ return(ret_value); \
+} /*end scope from beginning of FUNC_ENTER*/
+
+#define FUNC_LEAVE_NOAPI_VOID \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ H5_POP_FUNC \
+ return; \
+} /*end scope from beginning of FUNC_ENTER*/
+
+/*
+ * Use this macro for non-API functions which fall into these categories:
+ * - functions which didn't push their name on the function stack
+ * (so far, just the H5CS routines themselves)
+ */
+#define FUNC_LEAVE_NOAPI_NOFS(ret_value) \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ return(ret_value); \
+} /*end scope from beginning of FUNC_ENTER*/
+
+/* Use this macro when exiting a function that set up a metadata tag */
+#define FUNC_LEAVE_NOAPI_TAG(ret_value, err) \
+ ; \
+ } /*end scope from end of FUNC_ENTER*/ \
+ if(H5AC_tag(tag_dxpl_id, prev_tag, NULL) < 0) \
+ HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, err, "unable to apply metadata tag") \
+ H5_POP_FUNC \
+ return(ret_value); \
+} /*end scope from beginning of FUNC_ENTER*/
+
+
+/****************************************/
+/* Revisions to FUNC_ENTER/LEAVE Macros */
+/****************************************/
+
+/* Macros to check if a package is initialized */
+#define H5_CHECK_PACKAGE_INIT_REG_YES(asrt) HDassert(H5_PACKAGE_INIT_VAR(pkg));
+#define H5_CHECK_PACKAGE_INIT_REG_NO(asrt)
+#define H5_CHECK_PACKAGE_INIT_INIT_YES(asrt)
+#define H5_CHECK_PACKAGE_INIT_INIT_NO(asrt)
+#define H5_CHECK_PACKAGE_INIT(pkg, pkg_init, init) H5_GLUE4(H5_CHECK_PACKAGE_INIT_, init, _, pkg_init)(pkg)
+
+/* Macros to initialize package, if a package initialization routine is defined */
+#define H5_PKG_YES_INIT(pkg) \
+ if(!H5_PACKAGE_INIT_VAR(pkg) && !H5_TERM_GLOBAL) { \
+ H5_PACKAGE_INIT_VAR(pkg) = TRUE; \
+ if(H5_PACKAGE_INIT_FUNC(pkg)() < 0) { \
+ H5_PACKAGE_INIT_VAR(pkg) = FALSE; \
+ /* (Can't use H5E_THROW here) */ \
+ H5E_PRINTF(H5E_CANTINIT, "interface initialization failed"); \
+ ret_value = fail_value; \
+ goto func_init_failed; \
+ } /* end if */ \
+ } /* end if */
+#define H5_PKG_NO_INIT(pkg) \
+ if(!H5_PACKAGE_INIT_VAR(pkg) && !H5_TERM_GLOBAL) \
+ H5_PACKAGE_INIT_VAR(pkg) = TRUE;
+#define H5_PKG_INIT(pkg_init, pkg) H5_GLUE3(H5_PKG_, pkg_init, _INIT)(pkg)
+
+/* Macros to declare package initialization function, if a package initialization routine is defined */
+#ifdef H5_PKG_SINGLE_SOURCE
+#define H5_PKG_DECLARE_YES_FUNC(pkg) static herr_t H5_PACKAGE_INIT_FUNC(pkg)(void);
+#else /* H5_PKG_SINGLE_SOURCE */
+#define H5_PKG_DECLARE_YES_FUNC(pkg) extern herr_t H5_PACKAGE_INIT_FUNC(pkg)(void);
+#endif /* H5_PKG_SINGLE_SOURCE */
+#define H5_PKG_DECLARE_NO_FUNC(pkg)
+
+/* Declare package initialization symbols (if in a package) */
+#ifdef H5_PKG_SINGLE_SOURCE
+#define H5_PKG_DECLARE_VAR(pkg) static hbool_t H5_PACKAGE_INIT_VAR(pkg);
+#else /* H5_PKG_SINGLE_SOURCE */
+#define H5_PKG_DECLARE_VAR(pkg) extern hbool_t H5_PACKAGE_INIT_VAR(pkg);
+#endif /* H5_PKG_SINGLE_SOURCE */
+#define H5_PKG_DECLARE_FUNC(pkg_init, pkg) H5_GLUE3(H5_PKG_DECLARE_, pkg_init, _FUNC)(pkg)
+#ifdef H5_MY_PKG
+H5_PKG_DECLARE_VAR(H5_MY_PKG)
+H5_PKG_DECLARE_FUNC(H5_MY_PKG_INIT, H5_MY_PKG)
+#endif /* H5_MY_PKG */
+
+/* API re-entrance variable */
+extern hbool_t H5_api_entered_g; /* Has library already been entered through API? */
+
+/* Macros for entering different scopes of routines */
+#define H5_PACKAGE_ENTER(pkg, pkg_init, init) \
+ FUNC_ENTER_CHECK_NAME(H5_IS_PKG(FUNC)) \
+ \
+ /* The library should be initialized already */ \
+ HDassert(H5_INIT_GLOBAL); \
+ \
+ /* This interface should be initialized already */ \
+ /* (except for package initialization routines :-) */ \
+ H5_CHECK_PACKAGE_INIT(pkg, pkg_init, init) \
+ \
+ /* Push the name of this function on the function stack */ \
+ H5_PUSH_FUNC \
+ \
+ /* Enter scope for this type of function */ \
+ {
+
+#define H5_PRIVATE_ENTER(pkg, pkg_init) \
+ FUNC_ENTER_CHECK_NAME(H5_IS_PRIV(FUNC)) \
+ \
+ /* The library should be initialized already */ \
+ HDassert(H5_INIT_GLOBAL); \
+ \
+ /* Initialize this interface if desired */ \
+ H5_PKG_INIT(pkg_init, pkg) \
+ \
+ /* Push the name of this function on the function stack */ \
+ H5_PUSH_FUNC \
+ \
+ /* Enter scope for this type of function */ \
+ {{
+
+#define H5_PUBLIC_ENTER(pkg, pkg_init) \
+ FUNC_ENTER_API_VARS \
+ FUNC_ENTER_API_THREADSAFE; \
+ FUNC_ENTER_CHECK_NAME(H5_IS_PUB(FUNC)) \
+ \
+ /* Clear thread error stack when entering public functions */ \
+ H5E_clear_stack(NULL); \
+ \
+ /* Initialize the library or bust */ \
+ if(!H5_INIT_GLOBAL && !H5_TERM_GLOBAL) { \
+ H5_INIT_GLOBAL = TRUE; \
+ if(H5_init_library() < 0) { \
+ /* (Can't use H5E_THROW here) */ \
+ H5E_PRINTF(H5E_CANTINIT, "interface initialization failed"); \
+ ret_value = fail_value; \
+ goto func_init_failed; \
+ } /* end if */ \
+ } /* end if */ \
+ \
+ /* Initialize this interface if desired */ \
+ H5_PKG_INIT(pkg_init, pkg) \
+ \
+ /* Check for re-entering API routine */ \
+ HDassert(!H5_api_entered_g); \
+ H5_api_entered_g = TRUE; \
+ \
+ /* Start logging MPI's MPE information */ \
+ BEGIN_MPE_LOG \
+ \
+ /* Push the name of this function on the function stack */ \
+ H5_PUSH_FUNC \
+ \
+ /* Enter scope for this type of function */ \
+ {{{
+
+/* Macros for substituting the package name */
+#define FUNC_ENT_STATIC(pkg, pkg_init) H5_PACKAGE_ENTER(pkg, pkg_init, REG)
+#define FUNC_ENT_PKGINIT(pkg, pkg_init) H5_PACKAGE_ENTER(pkg, pkg_init, INIT)
+#define FUNC_ENT_PKG(pkg, pkg_init) H5_PACKAGE_ENTER(pkg, pkg_init, REG)
+#define FUNC_ENT_PRIV(pkg, pkg_init) H5_PRIVATE_ENTER(pkg, pkg_init)
+#define FUNC_ENT_PUB(pkg, pkg_init) H5_PUBLIC_ENTER(pkg, pkg_init)
+
+/* Macros for substituting a function prefix */
+#define FUNC_PREFIX_STATIC static
+#define FUNC_PREFIX_PKGINIT
+#define FUNC_PREFIX_PKG
+#define FUNC_PREFIX_PRIV
+#define FUNC_PREFIX_PUB
+
+/* Macros for declaring error variables */
+/* Function can detect errors and has a specific error return value */
+#define FUNC_ERR_VAR_ERR(ret_typ, err) \
+ hbool_t past_catch = FALSE; \
+ ret_typ fail_value = err;
+/* Function can detect errors but cannot return an error value (Cleanup only) */
+#define FUNC_ERR_VAR_ERRCATCH(ret_typ, err) \
+ hbool_t past_catch = FALSE;
+/* Function has no need to detect or clean up from errors */
+#define FUNC_ERR_VAR_NOERR(ret_typ, err)
+
+/* Use this macro when entering all functions */
+#define BEGIN_FUNC(scope, use_err, ret_typ, ret_init, err, func) \
+H5_GLUE(FUNC_PREFIX_, scope) \
+ret_typ \
+func \
+/* Open function */ \
+{ \
+ ret_typ ret_value = ret_init; \
+ H5_GLUE(FUNC_ERR_VAR_, use_err)(ret_typ, err) \
+ H5_GLUE(FUNC_ENT_, scope)(H5_MY_PKG, H5_MY_PKG_INIT)
+
+/* Use this macro when entering functions that have no return value */
+#define BEGIN_FUNC_VOID(scope, use_err, func) \
+H5_GLUE(FUNC_PREFIX_, scope) \
+void \
+func \
+/* Open function */ \
+{ \
+ H5_GLUE(FUNC_ERR_VAR_, use_err)(void, -, -) \
+ H5_GLUE(FUNC_ENT_, scope)
+
+/* Macros for label when a function initialization can fail */
+#define H5_PRIV_YES_FUNC_INIT_FAILED func_init_failed:
+#define H5_PRIV_NO_FUNC_INIT_FAILED
+#define H5_PRIV_FUNC_INIT_FAILED(pkg_init) H5_GLUE3(H5_PRIV_, pkg_init, _FUNC_INIT_FAILED)
+
+/* Macros for leaving different scopes of routines */
+#define FUNC_LEAVE_PKGINIT \
+ /* Leave scope for this type of function */ \
+ } \
+ \
+ /* Pop the name of this function off the function stack */ \
+ H5_POP_FUNC
+
+#define FUNC_LEAVE_STATIC \
+ /* Leave scope for this type of function */ \
+ } \
+ \
+ /* Pop the name of this function off the function stack */ \
+ H5_POP_FUNC
+
+#define FUNC_LEAVE_PKG \
+ /* Leave scope for this type of function */ \
+ } \
+ \
+ /* Pop the name of this function off the function stack */ \
+ H5_POP_FUNC
+
+#define FUNC_LEAVE_PRIV \
+ /* Leave scope for this type of function */ \
+ }} \
+ \
+ /* Label for errors during FUNC_ENTER */ \
+ H5_PRIV_FUNC_INIT_FAILED(H5_MY_PKG_INIT) \
+ \
+ /* Pop the name of this function off the function stack */ \
+ H5_POP_FUNC
+
+#define FUNC_LEAVE_PUB \
+ /* Leave scope for this type of function */ \
+ }}} \
+ \
+ /* Label for errors during FUNC_ENTER */ \
+func_init_failed: \
+ \
+ /* Dump error stack if an error occurred during API routine */ \
+ if(ret_value == fail_value) \
+ (void)H5E_dump_api_stack(TRUE); \
+ \
+ /* Finish the API tracing info */ \
+ H5TRACE_RETURN(ret_value); \
+ \
+ /* Pop the name of this function off the function stack */ \
+ H5_POP_FUNC \
+ \
+ /* Finish the MPE tracing info */ \
+ FINISH_MPE_LOG \
+ \
+ /* Check for leaving API routine */ \
+ HDassert(H5_api_entered_g); \
+ H5_api_entered_g = FALSE; \
+ \
+ /* Release thread-safety semaphore */ \
+ FUNC_LEAVE_API_THREADSAFE
+
+/* Use this macro when leaving all functions */
+#define END_FUNC(scope) \
+ /* Scope-specific function conclusion */ \
+ H5_GLUE(FUNC_LEAVE_, scope) \
+ \
+ /* Leave routine */ \
+ return(ret_value); \
+ \
+ /* Close Function */ \
+}
+
+/* Use this macro when leaving void functions */
+#define END_FUNC_VOID(scope) \
+ /* Scope-specific function conclusion */ \
+ H5_GLUE(FUNC_LEAVE_, scope) \
+ \
+ /* Leave routine */ \
+ return; \
+ \
+ /* Close Function */ \
+}
+
+/* Macro to begin/end tagging (when FUNC_ENTER_*TAG macros are insufficient).
+ * Make sure to use HGOTO_ERROR_TAG and HGOTO_DONE_TAG between these macros! */
+#define H5_BEGIN_TAG(dxpl, tag, err) { \
+ haddr_t prv_tag = HADDR_UNDEF; \
+ hid_t my_dxpl_id = dxpl; \
+ if(H5AC_tag(my_dxpl_id, tag, &prv_tag) < 0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag")
+
+#define H5_END_TAG(err) \
+ if(H5AC_tag(my_dxpl_id, prv_tag, NULL) <0) \
+ HGOTO_ERROR(H5_MY_PKG_ERR, H5E_CANTTAG, err, "unable to apply metadata tag") \
+}
+
+/* Compile-time "assert" macro */
+#define HDcompile_assert(e) ((void)sizeof(char[ !!(e) ? 1 : -1]))
+/* Variants that are correct, but generate compile-time warnings in some circumstances:
+ #define HDcompile_assert(e) do { enum { compile_assert__ = 1 / (e) }; } while(0)
+ #define HDcompile_assert(e) do { typedef struct { unsigned int b: (e); } x; } while(0)
+*/
+
+/* Private functions, not part of the publicly documented API */
+H5_DLL herr_t H5_init_library(void);
+H5_DLL void H5_term_library(void);
+
+/* Functions to terminate interfaces */
+H5_DLL int H5A_term_package(void);
+H5_DLL int H5A_top_term_package(void);
+H5_DLL int H5AC_term_package(void);
+H5_DLL int H5D_term_package(void);
+H5_DLL int H5D_top_term_package(void);
+H5_DLL int H5E_term_package(void);
+H5_DLL int H5F_term_package(void);
+H5_DLL int H5FD_term_package(void);
+H5_DLL int H5FL_term_package(void);
+H5_DLL int H5FS_term_package(void);
+H5_DLL int H5G_term_package(void);
+H5_DLL int H5G_top_term_package(void);
+H5_DLL int H5I_term_package(void);
+H5_DLL int H5L_term_package(void);
+H5_DLL int H5P_term_package(void);
+H5_DLL int H5PL_term_package(void);
+H5_DLL int H5R_term_package(void);
+H5_DLL int H5R_top_term_package(void);
+H5_DLL int H5S_term_package(void);
+H5_DLL int H5S_top_term_package(void);
+H5_DLL int H5SL_term_package(void);
+H5_DLL int H5T_term_package(void);
+H5_DLL int H5T_top_term_package(void);
+H5_DLL int H5Z_term_package(void);
+
+/* Checksum functions */
+H5_DLL uint32_t H5_checksum_fletcher32(const void *data, size_t len);
+H5_DLL uint32_t H5_checksum_crc(const void *data, size_t len);
+H5_DLL uint32_t H5_checksum_lookup3(const void *data, size_t len, uint32_t initval);
+H5_DLL uint32_t H5_checksum_metadata(const void *data, size_t len, uint32_t initval);
+H5_DLL uint32_t H5_hash_string(const char *str);
+
+/* Time related routines */
+H5_DLL time_t H5_make_time(struct tm *tm);
+H5_DLL void H5_nanosleep(uint64_t nanosec);
+H5_DLL double H5_get_time(void);
+
+/* Functions for building paths, etc. */
+H5_DLL herr_t H5_build_extpath(const char *name, char **extpath /*out*/);
+H5_DLL herr_t H5_combine_path(const char *path1, const char *path2, char **full_name /*out*/);
+
+/* Functions for debugging */
+H5_DLL herr_t H5_buffer_dump(FILE *stream, int indent, const uint8_t *buf,
+ const uint8_t *marker, size_t buf_offset, size_t buf_size);
+
+#endif /* _H5private_H */
+
diff --git a/src/H5public.h b/src/H5public.h
new file mode 100644
index 0000000..496d8ce
--- /dev/null
+++ b/src/H5public.h
@@ -0,0 +1,349 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This file contains public declarations for the HDF5 module.
+ */
+#ifndef _H5public_H
+#define _H5public_H
+
+/* Include files for public use... */
+/*
+ * Since H5pubconf.h is a generated header file, it is messy to try
+ * to put a #ifndef _H5pubconf_H ... #endif guard in it.
+ * HDF5 has set an internal rule that it is being included here.
+ * Source files should NOT include H5pubconf.h directly but include
+ * it via H5public.h. The #ifndef _H5public_H guard above would
+ * prevent repeated include.
+ */
+#include "H5pubconf.h" /*from configure */
+
+/* API Version macro wrapper definitions */
+#include "H5version.h"
+
+#ifdef H5_HAVE_FEATURES_H
+#include <features.h> /*for setting POSIX, BSD, etc. compatibility */
+#endif
+#ifdef H5_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef H5_STDC_HEADERS
+# include <limits.h> /*for H5T_NATIVE_CHAR defn in H5Tpublic.h */
+#endif
+#ifndef __cplusplus
+# ifdef H5_HAVE_STDINT_H
+# include <stdint.h> /*for C9x types */
+# endif
+#else
+# ifdef H5_HAVE_STDINT_H_CXX
+# include <stdint.h> /*for C9x types when include from C++ */
+# endif
+#endif
+#ifdef H5_HAVE_INTTYPES_H
+# include <inttypes.h> /* For uint64_t on some platforms */
+#endif
+#ifdef H5_HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#ifdef H5_HAVE_PARALLEL
+# include <mpi.h>
+#ifndef MPI_FILE_NULL /*MPIO may be defined in mpi.h already */
+# include <mpio.h>
+#endif
+#endif
+
+
+/* Include the Windows API adapter header early */
+#include "H5api_adpt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Macros for enabling/disabling particular GCC warnings */
+/* (see the following web-sites for more info:
+ * http://www.dbp-consulting.com/tutorials/SuppressingGCCWarnings.html
+ * http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
+ */
+/* These pragmas are only implemented usefully in gcc 4.6+ */
+#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
+ #define H5_GCC_DIAG_STR(s) #s
+ #define H5_GCC_DIAG_JOINSTR(x,y) H5_GCC_DIAG_STR(x ## y)
+ #define H5_GCC_DIAG_DO_PRAGMA(x) _Pragma (#x)
+ #define H5_GCC_DIAG_PRAGMA(x) H5_GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
+
+ #define H5_GCC_DIAG_OFF(x) H5_GCC_DIAG_PRAGMA(push) H5_GCC_DIAG_PRAGMA(ignored H5_GCC_DIAG_JOINSTR(-W,x))
+ #define H5_GCC_DIAG_ON(x) H5_GCC_DIAG_PRAGMA(pop)
+#else
+ #define H5_GCC_DIAG_OFF(x)
+ #define H5_GCC_DIAG_ON(x)
+#endif
+
+/* Version numbers */
+#define H5_VERS_MAJOR 1 /* For major interface/format changes */
+#define H5_VERS_MINOR 10 /* For minor interface/format changes */
+#define H5_VERS_RELEASE 1 /* For tweaks, bug-fixes, or development */
+#define H5_VERS_SUBRELEASE "" /* For pre-releases like snap0 */
+ /* Empty string for real releases. */
+#define H5_VERS_INFO "HDF5 library version: 1.10.1" /* Full version string */
+
+#define H5check() H5check_version(H5_VERS_MAJOR,H5_VERS_MINOR, \
+ H5_VERS_RELEASE)
+
+/* macros for comparing the version */
+#define H5_VERSION_GE(Maj,Min,Rel) \
+ (((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR==Min) && (H5_VERS_RELEASE>=Rel)) || \
+ ((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR>Min)) || \
+ (H5_VERS_MAJOR>Maj))
+
+#define H5_VERSION_LE(Maj,Min,Rel) \
+ (((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR==Min) && (H5_VERS_RELEASE<=Rel)) || \
+ ((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR<Min)) || \
+ (H5_VERS_MAJOR<Maj))
+
+/*
+ * Status return values. Failed integer functions in HDF5 result almost
+ * always in a negative value (unsigned failing functions sometimes return
+ * zero for failure) while successfull return is non-negative (often zero).
+ * The negative failure value is most commonly -1, but don't bet on it. The
+ * proper way to detect failure is something like:
+ *
+ * if((dset = H5Dopen2(file, name)) < 0)
+ * fprintf(stderr, "unable to open the requested dataset\n");
+ */
+typedef int herr_t;
+
+
+/*
+ * Boolean type. Successful return values are zero (false) or positive
+ * (true). The typical true value is 1 but don't bet on it. Boolean
+ * functions cannot fail. Functions that return `htri_t' however return zero
+ * (false), positive (true), or negative (failure). The proper way to test
+ * for truth from a htri_t function is:
+ *
+ * if ((retval = H5Tcommitted(type))>0) {
+ * printf("data type is committed\n");
+ * } else if (!retval) {
+ * printf("data type is not committed\n");
+ * } else {
+ * printf("error determining whether data type is committed\n");
+ * }
+ */
+#ifdef H5_HAVE_STDBOOL_H
+ #include <stdbool.h>
+#else /* H5_HAVE_STDBOOL_H */
+ #ifndef __cplusplus
+ #if defined(H5_SIZEOF_BOOL) && (H5_SIZEOF_BOOL != 0)
+ #define bool _Bool
+ #else
+ #define bool unsigned int
+ #endif
+ #define true 1
+ #define false 0
+ #endif /* __cplusplus */
+#endif /* H5_HAVE_STDBOOL_H */
+typedef bool hbool_t;
+typedef int htri_t;
+
+/* Define the ssize_t type if it not is defined */
+#if H5_SIZEOF_SSIZE_T==0
+/* Undefine this size, we will re-define it in one of the sections below */
+#undef H5_SIZEOF_SSIZE_T
+#if H5_SIZEOF_SIZE_T==H5_SIZEOF_INT
+typedef int ssize_t;
+# define H5_SIZEOF_SSIZE_T H5_SIZEOF_INT
+#elif H5_SIZEOF_SIZE_T==H5_SIZEOF_LONG
+typedef long ssize_t;
+# define H5_SIZEOF_SSIZE_T H5_SIZEOF_LONG
+#elif H5_SIZEOF_SIZE_T==H5_SIZEOF_LONG_LONG
+typedef long long ssize_t;
+# define H5_SIZEOF_SSIZE_T H5_SIZEOF_LONG_LONG
+#else /* Can't find matching type for ssize_t */
+# error "nothing appropriate for ssize_t"
+#endif
+#endif
+
+/*
+ * The sizes of file objects have their own types defined here, use a 64-bit
+ * type.
+ */
+#if H5_SIZEOF_LONG_LONG >= 8
+H5_GCC_DIAG_OFF(long-long)
+typedef unsigned long long hsize_t;
+typedef signed long long hssize_t;
+H5_GCC_DIAG_ON(long-long)
+# define H5_SIZEOF_HSIZE_T H5_SIZEOF_LONG_LONG
+# define H5_SIZEOF_HSSIZE_T H5_SIZEOF_LONG_LONG
+#else
+# error "nothing appropriate for hsize_t"
+#endif
+#define HSIZE_UNDEF ((hsize_t)(hssize_t)(-1))
+
+/*
+ * File addresses have their own types.
+ */
+#if H5_SIZEOF_INT >= 8
+ typedef unsigned haddr_t;
+# define HADDR_UNDEF ((haddr_t)(-1))
+# define H5_SIZEOF_HADDR_T H5_SIZEOF_INT
+# ifdef H5_HAVE_PARALLEL
+# define HADDR_AS_MPI_TYPE MPI_UNSIGNED
+# endif /* H5_HAVE_PARALLEL */
+#elif H5_SIZEOF_LONG >= 8
+ typedef unsigned long haddr_t;
+# define HADDR_UNDEF ((haddr_t)(long)(-1))
+# define H5_SIZEOF_HADDR_T H5_SIZEOF_LONG
+# ifdef H5_HAVE_PARALLEL
+# define HADDR_AS_MPI_TYPE MPI_UNSIGNED_LONG
+# endif /* H5_HAVE_PARALLEL */
+#elif H5_SIZEOF_LONG_LONG >= 8
+ typedef unsigned long long haddr_t;
+# define HADDR_UNDEF ((haddr_t)(long long)(-1))
+# define H5_SIZEOF_HADDR_T H5_SIZEOF_LONG_LONG
+# ifdef H5_HAVE_PARALLEL
+# define HADDR_AS_MPI_TYPE MPI_LONG_LONG_INT
+# endif /* H5_HAVE_PARALLEL */
+#else
+# error "nothing appropriate for haddr_t"
+#endif
+#if H5_SIZEOF_HADDR_T == H5_SIZEOF_INT
+# define H5_PRINTF_HADDR_FMT "%u"
+#elif H5_SIZEOF_HADDR_T == H5_SIZEOF_LONG
+# define H5_PRINTF_HADDR_FMT "%lu"
+#elif H5_SIZEOF_HADDR_T == H5_SIZEOF_LONG_LONG
+# define H5_PRINTF_HADDR_FMT "%" H5_PRINTF_LL_WIDTH "u"
+#else
+# error "nothing appropriate for H5_PRINTF_HADDR_FMT"
+#endif
+#define HADDR_MAX (HADDR_UNDEF-1)
+
+/* uint32_t type is used for creation order field for messages. It may be
+ * defined in Posix.1g, otherwise it is defined here.
+ */
+#if H5_SIZEOF_UINT32_T>=4
+#elif H5_SIZEOF_SHORT>=4
+ typedef short uint32_t;
+# undef H5_SIZEOF_UINT32_T
+# define H5_SIZEOF_UINT32_T H5_SIZEOF_SHORT
+#elif H5_SIZEOF_INT>=4
+ typedef unsigned int uint32_t;
+# undef H5_SIZEOF_UINT32_T
+# define H5_SIZEOF_UINT32_T H5_SIZEOF_INT
+#elif H5_SIZEOF_LONG>=4
+ typedef unsigned long uint32_t;
+# undef H5_SIZEOF_UINT32_T
+# define H5_SIZEOF_UINT32_T H5_SIZEOF_LONG
+#else
+# error "nothing appropriate for uint32_t"
+#endif
+
+/* int64_t type is used for creation order field for links. It may be
+ * defined in Posix.1g, otherwise it is defined here.
+ */
+#if H5_SIZEOF_INT64_T>=8
+#elif H5_SIZEOF_INT>=8
+ typedef int int64_t;
+# undef H5_SIZEOF_INT64_T
+# define H5_SIZEOF_INT64_T H5_SIZEOF_INT
+#elif H5_SIZEOF_LONG>=8
+ typedef long int64_t;
+# undef H5_SIZEOF_INT64_T
+# define H5_SIZEOF_INT64_T H5_SIZEOF_LONG
+#elif H5_SIZEOF_LONG_LONG>=8
+ typedef long long int64_t;
+# undef H5_SIZEOF_INT64_T
+# define H5_SIZEOF_INT64_T H5_SIZEOF_LONG_LONG
+#else
+# error "nothing appropriate for int64_t"
+#endif
+
+/* uint64_t type is used for fields for H5O_info_t. It may be
+ * defined in Posix.1g, otherwise it is defined here.
+ */
+#if H5_SIZEOF_UINT64_T>=8
+#elif H5_SIZEOF_INT>=8
+ typedef unsigned uint64_t;
+# undef H5_SIZEOF_UINT64_T
+# define H5_SIZEOF_UINT64_T H5_SIZEOF_INT
+#elif H5_SIZEOF_LONG>=8
+ typedef unsigned long uint64_t;
+# undef H5_SIZEOF_UINT64_T
+# define H5_SIZEOF_UINT64_T H5_SIZEOF_LONG
+#elif H5_SIZEOF_LONG_LONG>=8
+ typedef unsigned long long uint64_t;
+# undef H5_SIZEOF_UINT64_T
+# define H5_SIZEOF_UINT64_T H5_SIZEOF_LONG_LONG
+#else
+# error "nothing appropriate for uint64_t"
+#endif
+
+/* Common iteration orders */
+typedef enum {
+ H5_ITER_UNKNOWN = -1, /* Unknown order */
+ H5_ITER_INC, /* Increasing order */
+ H5_ITER_DEC, /* Decreasing order */
+ H5_ITER_NATIVE, /* No particular order, whatever is fastest */
+ H5_ITER_N /* Number of iteration orders */
+} H5_iter_order_t;
+
+/* Iteration callback values */
+/* (Actually, any postive value will cause the iterator to stop and pass back
+ * that positive value to the function that called the iterator)
+ */
+#define H5_ITER_ERROR (-1)
+#define H5_ITER_CONT (0)
+#define H5_ITER_STOP (1)
+
+/*
+ * The types of indices on links in groups/attributes on objects.
+ * Primarily used for "<do> <foo> by index" routines and for iterating over
+ * links in groups/attributes on objects.
+ */
+typedef enum H5_index_t {
+ H5_INDEX_UNKNOWN = -1, /* Unknown index type */
+ H5_INDEX_NAME, /* Index on names */
+ H5_INDEX_CRT_ORDER, /* Index on creation order */
+ H5_INDEX_N /* Number of indices defined */
+} H5_index_t;
+
+/*
+ * Storage info struct used by H5O_info_t and H5F_info_t
+ */
+typedef struct H5_ih_info_t {
+ hsize_t index_size; /* btree and/or list */
+ hsize_t heap_size;
+} H5_ih_info_t;
+
+/* Functions in H5.c */
+H5_DLL herr_t H5open(void);
+H5_DLL herr_t H5close(void);
+H5_DLL herr_t H5dont_atexit(void);
+H5_DLL herr_t H5garbage_collect(void);
+H5_DLL herr_t H5set_free_list_limits (int reg_global_lim, int reg_list_lim,
+ int arr_global_lim, int arr_list_lim, int blk_global_lim,
+ int blk_list_lim);
+H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum,
+ unsigned *relnum);
+H5_DLL herr_t H5check_version(unsigned majnum, unsigned minnum,
+ unsigned relnum);
+H5_DLL herr_t H5is_library_threadsafe(hbool_t *is_ts);
+H5_DLL herr_t H5free_memory(void *mem);
+H5_DLL void *H5allocate_memory(size_t size, hbool_t clear);
+H5_DLL void *H5resize_memory(void *mem, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _H5public_H */
+
+
diff --git a/src/H5system.c b/src/H5system.c
new file mode 100644
index 0000000..7e25540
--- /dev/null
+++ b/src/H5system.c
@@ -0,0 +1,1239 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5system.c
+ * Aug 21 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: System call wrapper implementations.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5MMprivate.h" /* Memory management */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Track whether tzset routine was called */
+static hbool_t H5_ntzset = FALSE;
+
+
+/*-------------------------------------------------------------------------
+ * Function: HDfprintf
+ *
+ * Purpose: Prints the optional arguments under the control of the format
+ * string FMT to the stream STREAM. This function takes the
+ * same format as fprintf(3c) with a few added features:
+ *
+ * The conversion modifier `H' refers to the size of an
+ * `hsize_t' or `hssize_t' type. For instance, "0x%018Hx"
+ * prints an `hsize_t' value as a hex number right justified and
+ * zero filled in an 18-character field.
+ *
+ * The conversion `a' refers to an `haddr_t' type.
+ *
+ * Return: Success: Number of characters printed
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 9, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-07-27
+ * The `%a' format refers to an argument of `haddr_t' type
+ * instead of `haddr_t*' and the return value is correct.
+ *-------------------------------------------------------------------------
+ */
+int
+HDfprintf(FILE *stream, const char *fmt, ...)
+{
+ int n=0, nout = 0;
+ int fwidth, prec;
+ int zerofill;
+ int leftjust;
+ int plussign;
+ int ldspace;
+ int prefix;
+ char modifier[8];
+ int conv;
+ char *rest, format_templ[128];
+ int len;
+ const char *s;
+ va_list ap;
+
+ HDassert(stream);
+ HDassert(fmt);
+
+ va_start (ap, fmt);
+ while (*fmt) {
+ fwidth = prec = 0;
+ zerofill = 0;
+ leftjust = 0;
+ plussign = 0;
+ prefix = 0;
+ ldspace = 0;
+ modifier[0] = '\0';
+
+ if ('%'==fmt[0] && '%'==fmt[1]) {
+ HDputc ('%', stream);
+ fmt += 2;
+ nout++;
+ } else if ('%'==fmt[0]) {
+ s = fmt + 1;
+
+ /* Flags */
+ while(HDstrchr("-+ #", *s)) {
+ switch(*s) {
+ case '-':
+ leftjust = 1;
+ break;
+
+ case '+':
+ plussign = 1;
+ break;
+
+ case ' ':
+ ldspace = 1;
+ break;
+
+ case '#':
+ prefix = 1;
+ break;
+
+ default:
+ HDassert(0 && "Unknown format flag");
+ } /* end switch */ /*lint !e744 Switch statement doesn't _need_ default */
+ s++;
+ } /* end while */
+
+ /* Field width */
+ if(HDisdigit(*s)) {
+ zerofill = ('0' == *s);
+ fwidth = (int)HDstrtol (s, &rest, 10);
+ s = rest;
+ } /* end if */
+ else if ('*'==*s) {
+ fwidth = va_arg(ap, int);
+ if(fwidth < 0) {
+ leftjust = 1;
+ fwidth = -fwidth;
+ }
+ s++;
+ }
+
+ /* Precision */
+ if('.'==*s) {
+ s++;
+ if(HDisdigit(*s)) {
+ prec = (int)HDstrtol(s, &rest, 10);
+ s = rest;
+ } else if('*'==*s) {
+ prec = va_arg(ap, int);
+ s++;
+ }
+ if(prec < 1)
+ prec = 1;
+ }
+
+ /* Extra type modifiers */
+ if(HDstrchr("zZHhlqLI", *s)) {
+ switch(*s) {
+ /*lint --e{506} Don't issue warnings about constant value booleans */
+ /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */
+ case 'H':
+ if(sizeof(hsize_t) < sizeof(long))
+ modifier[0] = '\0';
+ else if(sizeof(hsize_t) == sizeof(long)) {
+ HDstrncpy(modifier, "l", sizeof(modifier));
+ modifier[sizeof(modifier) - 1] = '\0';
+ } /* end if */
+ else {
+ HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier));
+ modifier[sizeof(modifier) - 1] = '\0';
+ } /* end else */
+ break;
+
+ case 'Z':
+ case 'z':
+ if(sizeof(size_t) < sizeof(long))
+ modifier[0] = '\0';
+ else if(sizeof(size_t) == sizeof(long)) {
+ HDstrncpy(modifier, "l", sizeof(modifier));
+ modifier[sizeof(modifier) - 1] = '\0';
+ } /* end if */
+ else {
+ HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier));
+ modifier[sizeof(modifier) - 1] = '\0';
+ } /* end else */
+ break;
+
+ default:
+ /* Handle 'I64' modifier for Microsoft's "__int64" type */
+ if(*s=='I' && *(s+1)=='6' && *(s+2)=='4') {
+ modifier[0] = *s;
+ modifier[1] = *(s+1);
+ modifier[2] = *(s+2);
+ modifier[3] = '\0';
+ s += 2; /* Increment over 'I6', the '4' is taken care of below */
+ } /* end if */
+ else {
+ /* Handle 'll' for long long types */
+ if(*s=='l' && *(s+1)=='l') {
+ modifier[0] = *s;
+ modifier[1] = *s;
+ modifier[2] = '\0';
+ s++; /* Increment over first 'l', second is taken care of below */
+ } /* end if */
+ else {
+ modifier[0] = *s;
+ modifier[1] = '\0';
+ } /* end else */
+ } /* end else */
+ break;
+ }
+ s++;
+ }
+
+ /* Conversion */
+ conv = *s++;
+
+ /* Create the format template */
+ len = 0;
+ len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s", (leftjust ? "-" : ""),
+ (plussign ? "+" : ""), (ldspace ? " " : ""),
+ (prefix ? "#" : ""), (zerofill ? "0" : ""));
+ if(fwidth > 0)
+ len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
+ if(prec > 0)
+ len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), ".%d", prec);
+ if(*modifier)
+ len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%s", modifier);
+ HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%c", conv);
+
+ /* Conversion */
+ switch (conv) {
+ case 'd':
+ case 'i':
+ if(!HDstrcmp(modifier, "h")) {
+ short x = (short)va_arg(ap, int);
+ n = fprintf(stream, format_templ, x);
+ } else if(!*modifier) {
+ int x = va_arg(ap, int);
+ n = fprintf(stream, format_templ, x);
+ } else if(!HDstrcmp(modifier, "l")) {
+ long x = va_arg(ap, long);
+ n = fprintf(stream, format_templ, x);
+ } else {
+ int64_t x = va_arg(ap, int64_t);
+ n = fprintf(stream, format_templ, x);
+ }
+ break;
+
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if(!HDstrcmp(modifier, "h")) {
+ unsigned short x = (unsigned short)va_arg(ap, unsigned int);
+ n = fprintf(stream, format_templ, x);
+ } else if(!*modifier) {
+ unsigned int x = va_arg(ap, unsigned int); /*lint !e732 Loss of sign not really occuring */
+ n = fprintf(stream, format_templ, x);
+ } else if(!HDstrcmp(modifier, "l")) {
+ unsigned long x = va_arg(ap, unsigned long); /*lint !e732 Loss of sign not really occuring */
+ n = fprintf(stream, format_templ, x);
+ } else {
+ uint64_t x = va_arg(ap, uint64_t); /*lint !e732 Loss of sign not really occuring */
+ n = fprintf(stream, format_templ, x);
+ }
+ break;
+
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ if(!HDstrcmp(modifier, "h")) {
+ float x = (float)va_arg(ap, double);
+ n = fprintf(stream, format_templ, (double)x);
+ } else if(!*modifier || !HDstrcmp(modifier, "l")) {
+ double x = va_arg(ap, double);
+ n = fprintf(stream, format_templ, x);
+ } else {
+ /*
+ * Some compilers complain when `long double' and
+ * `double' are the same thing.
+ */
+#if H5_SIZEOF_LONG_DOUBLE != H5_SIZEOF_DOUBLE
+ long double x = va_arg(ap, long double);
+ n = fprintf(stream, format_templ, x);
+#else
+ double x = va_arg(ap, double);
+ n = fprintf(stream, format_templ, x);
+#endif
+ }
+ break;
+
+ case 'a':
+ {
+ haddr_t x = va_arg(ap, haddr_t); /*lint !e732 Loss of sign not really occuring */
+
+ if(H5F_addr_defined(x)) {
+ len = 0;
+ len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s",
+ (leftjust ? "-" : ""), (plussign ? "+" : ""),
+ (ldspace ? " " : ""), (prefix ? "#" : ""),
+ (zerofill ? "0" : ""));
+ if(fwidth > 0)
+ len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
+
+ /*lint --e{506} Don't issue warnings about constant value booleans */
+ /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */
+ if(sizeof(x) == H5_SIZEOF_INT) {
+ HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1)));
+ len++;
+ } /* end if */
+ else if(sizeof(x) == H5_SIZEOF_LONG) {
+ HDstrncat(format_templ, "lu", (sizeof(format_templ) - (size_t)(len + 1)));
+ len++;
+ } /* end if */
+ else if(sizeof(x) == H5_SIZEOF_LONG_LONG) {
+ HDstrncat(format_templ, H5_PRINTF_LL_WIDTH, (sizeof(format_templ) - (size_t)(len + 1)));
+ len += (int)sizeof(H5_PRINTF_LL_WIDTH);
+ HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1)));
+ len++;
+ }
+ n = fprintf(stream, format_templ, x);
+ } else {
+ len = 0;
+ HDstrncpy(format_templ, "%", (sizeof(format_templ) - (size_t)(len + 1)));
+ len++;
+ if(leftjust) {
+ HDstrncat(format_templ, "-", (sizeof(format_templ) - (size_t)(len + 1)));
+ len++;
+ } /* end if */
+ if(fwidth)
+ len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
+ HDstrncat(format_templ, "s", (sizeof(format_templ) - (size_t)(len + 1)));
+ fprintf(stream, format_templ, "UNDEF");
+ }
+ }
+ break;
+
+ case 'c':
+ {
+ char x = (char)va_arg(ap, int);
+ n = fprintf(stream, format_templ, x);
+ }
+ break;
+
+ case 's':
+ case 'p':
+ {
+ char *x = va_arg(ap, char*); /*lint !e64 Type mismatch not really occuring */
+ n = fprintf(stream, format_templ, x);
+ }
+ break;
+
+ case 'n':
+ format_templ[HDstrlen(format_templ) - 1] = 'u';
+ n = fprintf(stream, format_templ, nout);
+ break;
+
+ case 't':
+ {
+ htri_t tri_var = va_arg(ap, htri_t);
+
+ if(tri_var > 0)
+ fprintf(stream, "TRUE");
+ else if(!tri_var)
+ fprintf(stream, "FALSE");
+ else
+ fprintf(stream, "FAIL(%d)", (int)tri_var);
+ }
+ break;
+
+ default:
+ HDfputs(format_templ, stream);
+ n = (int)HDstrlen(format_templ);
+ break;
+ }
+ nout += n;
+ fmt = s;
+ } else {
+ HDputc(*fmt, stream);
+ fmt++;
+ nout++;
+ }
+ }
+ va_end(ap);
+ return nout;
+} /* end HDfprintf() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: HDstrtoll
+ *
+ * Purpose: Converts the string S to an int64_t value according to the
+ * given BASE, which must be between 2 and 36 inclusive, or be
+ * the special value zero.
+ *
+ * The string must begin with an arbitrary amount of white space
+ * (as determined by isspace(3c)) followed by a single optional
+ * `+' or `-' sign. If BASE is zero or 16 the string may then
+ * include a `0x' or `0X' prefix, and the number will be read in
+ * base 16; otherwise a zero BASE is taken as 10 (decimal)
+ * unless the next character is a `0', in which case it is taken
+ * as 8 (octal).
+ *
+ * The remainder of the string is converted to an int64_t in the
+ * obvious manner, stopping at the first character which is not
+ * a valid digit in the given base. (In bases above 10, the
+ * letter `A' in either upper or lower case represetns 10, `B'
+ * represents 11, and so forth, with `Z' representing 35.)
+ *
+ * If REST is not null, the address of the first invalid
+ * character in S is stored in *REST. If there were no digits
+ * at all, the original value of S is stored in *REST. Thus, if
+ * *S is not `\0' but **REST is `\0' on return the entire string
+ * was valid.
+ *
+ * Return: Success: The result.
+ *
+ * Failure: If the input string does not contain any
+ * digits then zero is returned and REST points
+ * to the original value of S. If an overflow
+ * or underflow occurs then the maximum or
+ * minimum possible value is returned and the
+ * global `errno' is set to ERANGE. If BASE is
+ * incorrect then zero is returned.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 9, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef HDstrtoll
+int64_t
+HDstrtoll(const char *s, const char **rest, int base)
+{
+ int64_t sign=1, acc=0;
+ hbool_t overflow = FALSE;
+
+ errno = 0;
+ if (!s || (base && (base<2 || base>36))) {
+ if (rest)
+ *rest = s;
+ return 0;
+ }
+
+ /* Skip white space */
+ while (HDisspace (*s)) s++;
+
+ /* Optional minus or plus sign */
+ if ('+'==*s) {
+ s++;
+ } else if ('-'==*s) {
+ sign = -1;
+ s++;
+ }
+
+ /* Zero base prefix */
+ if (0==base && '0'==*s && ('x'==s[1] || 'X'==s[1])) {
+ base = 16;
+ s += 2;
+ } else if (0==base && '0'==*s) {
+ base = 8;
+ s++;
+ } else if (0==base) {
+ base = 10;
+ }
+
+ /* Digits */
+ while ((base<=10 && *s>='0' && *s<'0'+base) ||
+ (base>10 && ((*s>='0' && *s<='9') ||
+ (*s>='a' && *s<'a'+base-10) ||
+ (*s>='A' && *s<'A'+base-10)))) {
+ if (!overflow) {
+ int64_t digit = 0;
+
+ if (*s>='0' && *s<='9')
+ digit = *s - '0';
+ else if (*s>='a' && *s<='z')
+ digit = (*s-'a')+10;
+ else
+ digit = (*s-'A')+10;
+
+ if (acc*base+digit < acc) {
+ overflow = TRUE;
+ } else {
+ acc = acc*base + digit;
+ }
+ }
+ s++;
+ }
+
+ /* Overflow */
+ if (overflow) {
+ if (sign>0) {
+ acc = ((uint64_t)1<<(8*sizeof(int64_t)-1))-1;
+ } else {
+ acc = (int64_t)((uint64_t)1<<(8*sizeof(int64_t)-1));
+ }
+ errno = ERANGE;
+ }
+
+ /* Return values */
+ acc *= sign;
+ if (rest)
+ *rest = s;
+ return acc;
+} /* end HDstrtoll() */
+#endif
+
+/*-------------------------------------------------------------------------
+ * Function: HDrand/HDsrand
+ *
+ * Purpose: Wrapper function for rand. If rand_r exists on this system,
+ * use it.
+ *
+ * Wrapper function for srand. If rand_r is available, it will keep
+ * track of the seed locally instead of using srand() which modifies
+ * global state and can break other programs.
+ *
+ * Return: Success: Random number from 0 to RAND_MAX
+ *
+ * Failure: Cannot fail.
+ *
+ * Programmer: Leon Arber
+ * March 6, 2006.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5_HAVE_RAND_R
+
+static unsigned int g_seed = 42;
+
+int HDrand(void)
+{
+ return rand_r(&g_seed);
+}
+
+void HDsrand(unsigned int seed)
+{
+ g_seed = seed;
+}
+#endif /* H5_HAVE_RAND_R */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: Pflock
+ *
+ * Purpose: Wrapper function for POSIX systems where flock(2) is not
+ * available.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+/* NOTE: Compile this all the time on POSIX systems, even when flock(2) is
+ * present so that it's less likely to become dead code.
+ */
+#ifdef H5_HAVE_FCNTL
+int
+Pflock(int fd, int operation) {
+
+ struct flock flk;
+
+ /* Set the lock type */
+ if(operation & LOCK_UN)
+ flk.l_type = F_UNLCK;
+ else if(operation & LOCK_SH)
+ flk.l_type = F_RDLCK;
+ else
+ flk.l_type = F_WRLCK;
+
+ /* Set the other flock struct values */
+ flk.l_whence = SEEK_SET;
+ flk.l_start = 0;
+ flk.l_len = 0; /* to EOF */
+ flk.l_pid = 0; /* not used with set */
+
+ /* Lock or unlock */
+ if(HDfcntl(fd, F_SETLK, flk) < 0)
+ return -1;
+
+ return 0;
+
+} /* end Pflock() */
+#endif /* H5_HAVE_FCNTL */
+
+
+/*-------------------------------------------------------------------------
+ * Function: Nflock
+ *
+ * Purpose: Wrapper function for systems where no file locking is
+ * available.
+ *
+ * Return: Failure: -1 (always fails)
+ *
+ *-------------------------------------------------------------------------
+ */
+int H5_ATTR_CONST
+Nflock(int H5_ATTR_UNUSED fd, int H5_ATTR_UNUSED operation) {
+ /* just fail */
+ return -1;
+} /* end Nflock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_make_time
+ *
+ * Purpose: Portability routine to abstract converting a 'tm' struct into
+ * a time_t value.
+ *
+ * Note: This is a little problematic because mktime() operates on
+ * local times. We convert to local time and then figure out the
+ * adjustment based on the local time zone and daylight savings
+ * setting.
+ *
+ * Return: Success: The value of timezone
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+time_t
+H5_make_time(struct tm *tm)
+{
+ time_t the_time; /* The converted time */
+#if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */
+ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
+ * variable declared in time.h. That variable was deprecated and in
+ * VS 2015 is removed, with _get_timezone replacing it.
+ */
+ long timezone = 0;
+#endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */
+ time_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(tm);
+
+ /* Initialize timezone information */
+ if(!H5_ntzset) {
+ HDtzset();
+ H5_ntzset = TRUE;
+ } /* end if */
+
+ /* Perform base conversion */
+ if((time_t)-1 == (the_time = HDmktime(tm)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCONVERT, FAIL, "badly formatted modification time message")
+
+ /* Adjust for timezones */
+#if defined(H5_HAVE_TM_GMTOFF)
+ /* BSD-like systems */
+ the_time += tm->tm_gmtoff;
+#elif defined(H5_HAVE_TIMEZONE)
+#if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */
+ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
+ * variable declared in time.h. That variable was deprecated and in
+ * VS 2015 is removed, with _get_timezone replacing it.
+ */
+ _get_timezone(&timezone);
+#endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */
+
+ the_time -= timezone - (tm->tm_isdst ? 3600 : 0);
+#else
+ /*
+ * The catch-all. If we can't convert a character string universal
+ * coordinated time to a time_t value reliably then we can't decode the
+ * modification time message. This really isn't as bad as it sounds -- the
+ * only way a user can get the modification time is from our internal
+ * query routines, which can gracefully recover.
+ */
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "unable to obtain local timezone information")
+#endif
+
+ /* Set return value */
+ ret_value = the_time;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_make_time() */
+
+#ifdef H5_HAVE_WIN32_API
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosecond units */
+#define _W32_FT_OFFSET (116444736000000000ULL)
+
+
+/*-------------------------------------------------------------------------
+ * Function: Wgettimeofday
+ *
+ * Purpose: Wrapper function for gettimeofday on Windows systems
+ *
+ * This function can get the time as well as a timezone
+ *
+ * Return: 0
+ *
+ * This implementation is taken from the Cygwin source distribution at
+ * src/winsup/mingw/mingwex/gettimeofday.c
+ *
+ * The original source code was contributed by
+ * Danny Smith <dannysmith@users.sourceforge.net>
+ * and released in the public domain.
+ *
+ * Programmer: Scott Wegner
+ * May 19, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wgettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ union {
+ unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
+ FILETIME ft;
+ } _now;
+
+ static int tzsetflag;
+
+ if(tv) {
+ GetSystemTimeAsFileTime (&_now.ft);
+ tv->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
+ tv->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
+ }
+
+ if(tz) {
+ if(!tzsetflag) {
+ _tzset();
+ tzsetflag = 1;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ /* Always return 0 as per Open Group Base Specifications Issue 6.
+ Do not set errno on error. */
+ return 0;
+} /* end Wgettimeofday() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: Wsetenv
+ *
+ * Purpose: Wrapper function for setenv on Windows systems.
+ * Interestingly, getenv *is* available in the Windows
+ * POSIX layer, just not setenv.
+ *
+ * Return: Success: 0
+ * Failure: non-zero error code
+ *
+ * Programmer: Dana Robinson
+ * February 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wsetenv(const char *name, const char *value, int overwrite)
+{
+ size_t bufsize;
+ errno_t err;
+
+ /* If we're not overwriting, check if the environment variable exists.
+ * If it does (i.e.: the required buffer size to store the variable's
+ * value is non-zero), then return an error code.
+ */
+ if(!overwrite) {
+ err = getenv_s(&bufsize, NULL, 0, name);
+ if (err || bufsize)
+ return (int)err;
+ } /* end if */
+
+ return (int)_putenv_s(name, value);
+} /* end Wsetenv() */
+
+#ifdef H5_HAVE_WINSOCK2_H
+#pragma comment(lib, "advapi32.lib")
+#endif
+
+#define WloginBuffer_count 256
+static char Wlogin_buffer[WloginBuffer_count];
+
+char*
+Wgetlogin()
+{
+
+#ifdef H5_HAVE_WINSOCK2_H
+ long bufferCount = WloginBuffer_count;
+ if (GetUserName(Wlogin_buffer, &bufferCount) == 0)
+ return (Wlogin_buffer);
+ else
+#endif /* H5_HAVE_WINSOCK2_H */
+ return NULL;
+}
+
+int c99_snprintf(char* str, size_t size, const char* format, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, format);
+ count = c99_vsnprintf(str, size, format, ap);
+ va_end(ap);
+
+ return count;
+}
+
+int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
+{
+ int count = -1;
+
+ if (size != 0)
+ count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+ if (count == -1)
+ count = _vscprintf(format, ap);
+
+ return count;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: Wflock
+ *
+ * Purpose: Wrapper function for flock on Windows systems
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wflock(int H5_ATTR_UNUSED fd, int H5_ATTR_UNUSED operation) {
+
+/* This is a no-op while we implement a Win32 VFD */
+#if 0
+int
+Wflock(int fd, int operation) {
+
+ HANDLE hFile;
+ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+ DWORD dwReserved = 0;
+ /* MAXDWORD for entire file */
+ DWORD nNumberOfBytesToLockLow = MAXDWORD;
+ DWORD nNumberOfBytesToLockHigh = MAXDWORD;
+ /* Must initialize OVERLAPPED struct */
+ OVERLAPPED overlapped = {0};
+
+ /* Get Windows HANDLE */
+ hFile = _get_osfhandle(fd);
+
+ /* Convert to Windows flags */
+ if(operation & LOCK_EX)
+ dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ /* Lock or unlock */
+ if(operation & LOCK_UN)
+ if(0 == UnlockFileEx(hFile, dwReserved, nNumberOfBytesToLockLow,
+ nNumberOfBytesToLockHigh, &overlapped))
+ return -1;
+ else
+ if(0 == LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow,
+ nNumberOfBytesToLockHigh, &overlapped))
+ return -1;
+#endif /* 0 */
+ return 0;
+} /* end Wflock() */
+
+
+ /*--------------------------------------------------------------------------
+ * Function: Wnanosleep
+ *
+ * Purpose: Sleep for a given # of nanoseconds (Windows version)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * Fall 2016
+ *--------------------------------------------------------------------------
+ */
+int
+Wnanosleep(const struct timespec *req, struct timespec *rem)
+{
+ /* XXX: Currently just a placeholder */
+ return 0;
+
+} /* end Wnanosleep() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: Wllround, Wllroundf, Wlround, Wlroundf, Wround, Wroundf
+ *
+ * Purpose: Wrapper function for round functions for use with VS2012
+ * and earlier.
+ *
+ * Return: The rounded value that was passed in.
+ *
+ * Programmer: Dana Robinson
+ * December 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+long long
+Wllround(double arg)
+{
+ return (long long)(arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5));
+}
+
+long long
+Wllroundf(float arg)
+{
+ return (long long)(arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F));
+}
+
+long
+Wlround(double arg)
+{
+ return (long)(arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5));
+}
+
+long
+Wlroundf(float arg)
+{
+ return (long)(arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F));
+}
+
+double
+Wround(double arg)
+{
+ return arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5);
+}
+
+float
+Wroundf(float arg)
+{
+ return arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F);
+}
+
+#endif /* H5_HAVE_WIN32_API */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_build_extpath
+ *
+ * Purpose: To build the path for later searching of target file for external
+ * links and external files. This path can be either:
+ * 1. The absolute path of NAME
+ * or
+ * 2. The current working directory + relative path of NAME
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi
+ * April 2, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+#define MAX_PATH_LEN 1024
+
+herr_t
+H5_build_extpath(const char *name, char **extpath /*out*/)
+{
+ char *full_path = NULL; /* Pointer to the full path, as built or passed in */
+ char *cwdpath = NULL; /* Pointer to the current working directory path */
+ char *new_name = NULL; /* Pointer to the name of the file */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(name);
+ HDassert(extpath);
+
+ /* Clear external path pointer to begin with */
+ *extpath = NULL;
+
+ /*
+ * Unix: name[0] is a "/"
+ * Windows: name[0-2] is "<drive letter>:\" or "<drive-letter>:/"
+ */
+ if(H5_CHECK_ABSOLUTE(name)) {
+ if(NULL == (full_path = (char *)H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end if */
+ else { /* relative pathname */
+ char *retcwd;
+ size_t name_len;
+ int drive;
+
+ if(NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+ name_len = HDstrlen(name) + 1;
+ if(NULL == (new_name = (char *)H5MM_malloc(name_len)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /*
+ * Windows: name[0-1] is "<drive-letter>:"
+ * Get current working directory on the drive specified in NAME
+ * Unix: does not apply
+ */
+ if(H5_CHECK_ABS_DRIVE(name)) {
+ drive = name[0] - 'A' + 1;
+ retcwd = HDgetdcwd(drive, cwdpath, MAX_PATH_LEN);
+ HDstrncpy(new_name, &name[2], name_len);
+ } /* end if */
+ /*
+ * Windows: name[0] is a '/' or '\'
+ * Get current drive
+ * Unix: does not apply
+ */
+ else if(H5_CHECK_ABS_PATH(name) && (0 != (drive = HDgetdrive()))) {
+ HDsnprintf(cwdpath, MAX_PATH_LEN, "%c:%c", (drive + 'A' - 1), name[0]);
+ retcwd = cwdpath;
+ HDstrncpy(new_name, &name[1], name_len);
+ }
+ /* totally relative for Unix and Windows: get current working directory */
+ else {
+ retcwd = HDgetcwd(cwdpath, MAX_PATH_LEN);
+ HDstrncpy(new_name, name, name_len);
+ } /* end if */
+
+ if(retcwd != NULL) {
+ size_t cwdlen;
+ size_t path_len;
+
+ HDassert(cwdpath);
+ cwdlen = HDstrlen(cwdpath);
+ HDassert(cwdlen);
+ HDassert(new_name);
+ path_len = cwdlen + HDstrlen(new_name) + 2;
+ if(NULL == (full_path = (char *)H5MM_malloc(path_len)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ HDstrncpy(full_path, cwdpath, cwdlen + 1);
+ if(!H5_CHECK_DELIMITER(cwdpath[cwdlen - 1]))
+ HDstrncat(full_path, H5_DIR_SEPS, HDstrlen(H5_DIR_SEPS));
+ HDstrncat(full_path, new_name, HDstrlen(new_name));
+ } /* end if */
+ } /* end else */
+
+ /* strip out the last component (the file name itself) from the path */
+ if(full_path) {
+ char *ptr = NULL;
+
+ H5_GET_LAST_DELIMITER(full_path, ptr)
+ HDassert(ptr);
+ *++ptr = '\0';
+ *extpath = full_path;
+ } /* end if */
+
+done:
+ /* Release resources */
+ if(cwdpath)
+ H5MM_xfree(cwdpath);
+ if(new_name)
+ H5MM_xfree(new_name);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_build_extpath() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5_combine_path
+ *
+ * Purpose: If path2 is relative, interpret path2 as relative to path1
+ * and store the result in full_name. Otherwise store path2
+ * in full_name.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Steffen Kiess
+ * June 22, 2015
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5_combine_path(const char* path1, const char* path2, char **full_name /*out*/)
+{
+ size_t path1_len; /* length of path1 */
+ size_t path2_len; /* length of path2 */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(path1);
+ HDassert(path2);
+
+ path1_len = HDstrlen(path1);
+ path2_len = HDstrlen(path2);
+
+ if(*path1 == '\0' || H5_CHECK_ABSOLUTE(path2)) {
+
+ /* If path1 is empty or path2 is absolute, simply use path2 */
+ if(NULL == (*full_name = (char *)H5MM_strdup(path2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ } /* end if */
+ else if(H5_CHECK_ABS_PATH(path2)) {
+
+ /* On windows path2 is a path absolute name */
+ if (H5_CHECK_ABSOLUTE(path1) || H5_CHECK_ABS_DRIVE(path1)) {
+ /* path1 is absolute or drive absolute and path2 is path absolute.
+ * Use the drive letter of path1 + path2
+ */
+ if(NULL == (*full_name = (char *)H5MM_malloc(path2_len + 3)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate path2 buffer")
+ HDsnprintf(*full_name, (path2_len + 3), "%c:%s", path1[0], path2);
+ } /* end if */
+ else {
+ /* On windows path2 is path absolute name ("\foo\bar"),
+ * path1 does not have a drive letter (i.e. is "a\b" or "\a\b").
+ * Use path2.
+ */
+ if(NULL == (*full_name = (char *)H5MM_strdup(path2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end else */
+
+ } /* end else if */
+ else {
+
+ /* Relative path2:
+ * Allocate a buffer to hold path1 + path2 + possibly the delimiter
+ * + terminating null byte
+ */
+ if(NULL == (*full_name = (char *)H5MM_malloc(path1_len + path2_len + 2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer")
+
+ /* Compose the full file name */
+ HDsnprintf(*full_name, (path1_len + path2_len + 2), "%s%s%s", path1,
+ (H5_CHECK_DELIMITER(path1[path1_len - 1]) ? "" : H5_DIR_SEPS), path2);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_combine_path() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5_nanosleep
+ *
+ * Purpose: Sleep for a given # of nanoseconds
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * October 01, 2016
+ *--------------------------------------------------------------------------
+ */
+void
+H5_nanosleep(uint64_t nanosec)
+{
+ struct timespec sleeptime; /* Struct to hold time to sleep */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set up time to sleep */
+ sleeptime.tv_sec = 0;
+ sleeptime.tv_nsec = (long)nanosec;
+
+ HDnanosleep(&sleeptime, NULL);
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5_nanosleep() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5_get_time
+ *
+ * Purpose: Get the current time, as the time of seconds after the UNIX epoch
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * October 05, 2016
+ *--------------------------------------------------------------------------
+ */
+double
+H5_get_time(void)
+{
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval curr_time;
+#endif /* H5_HAVE_GETTIMEOFDAY */
+ double ret_value = (double)0.0f;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&curr_time, NULL);
+
+ ret_value = (double)curr_time.tv_sec + ((double)curr_time.tv_usec / (double)1000000.0f);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_get_time() */
+
+
diff --git a/src/H5timer.c b/src/H5timer.c
new file mode 100644
index 0000000..0ba8bd1
--- /dev/null
+++ b/src/H5timer.c
@@ -0,0 +1,271 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5timer.c
+ * Aug 21 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal 'timer' routines & support routines.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+
+/* We need this for the struct rusage declaration */
+#if defined(H5_HAVE_GETRUSAGE) && defined(H5_HAVE_SYS_RESOURCE_H)
+# include <sys/resource.h>
+#endif
+
+#if defined(H5_HAVE_GETTIMEOFDAY) && defined(H5_HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_reset
+ *
+ * Purpose: Resets the timer struct to zero. Use this to reset a timer
+ * that's being used as an accumulator for summing times.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5_timer_reset (H5_timer_t *timer)
+{
+ HDassert(timer);
+ HDmemset(timer, 0, sizeof *timer);
+} /* end H5_timer_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_begin
+ *
+ * Purpose: Initialize a timer to time something.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5_timer_begin (H5_timer_t *timer)
+{
+#ifdef H5_HAVE_GETRUSAGE
+ struct rusage rusage;
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ struct timeval etime;
+#endif
+
+ HDassert(timer);
+
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage (RUSAGE_SELF, &rusage);
+ timer->utime = (double)rusage.ru_utime.tv_sec +
+ ((double)rusage.ru_utime.tv_usec / (double)1e6F);
+ timer->stime = (double)rusage.ru_stime.tv_sec +
+ ((double)rusage.ru_stime.tv_usec / (double)1e6F);
+#else
+ timer->utime = 0.0F;
+ timer->stime = 0.0F;
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday (&etime, NULL);
+ timer->etime = (double)etime.tv_sec + ((double)etime.tv_usec / (double)1e6F);
+#else
+ timer->etime = 0.0F;
+#endif
+} /* end H5_timer_begin() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_end
+ *
+ * Purpose: This function should be called at the end of a timed region.
+ * The SUM is an optional pointer which will accumulate times.
+ * TMS is the same struct that was passed to H5_timer_start().
+ * On return, TMS will contain total times for the timed region.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, April 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5_timer_end (H5_timer_t *sum/*in,out*/, H5_timer_t *timer/*in,out*/)
+{
+ H5_timer_t now;
+
+ HDassert(timer);
+ H5_timer_begin(&now);
+
+ timer->utime = MAX((double)0.0F, now.utime - timer->utime);
+ timer->stime = MAX((double)0.0F, now.stime - timer->stime);
+ timer->etime = MAX((double)0.0F, now.etime - timer->etime);
+
+ if (sum) {
+ sum->utime += timer->utime;
+ sum->stime += timer->stime;
+ sum->etime += timer->etime;
+ }
+} /* end H5_timer_end() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_bandwidth
+ *
+ * Purpose: Prints the bandwidth (bytes per second) in a field 10
+ * characters wide widh four digits of precision like this:
+ *
+ * NaN If <=0 seconds
+ * 1234. TB/s
+ * 123.4 TB/s
+ * 12.34 GB/s
+ * 1.234 MB/s
+ * 4.000 kB/s
+ * 1.000 B/s
+ * 0.000 B/s If NBYTES==0
+ * 1.2345e-10 For bandwidth less than 1
+ * 6.7893e+94 For exceptionally large values
+ * 6.678e+106 For really big values
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 5, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5_bandwidth(char *buf/*out*/, double nbytes, double nseconds)
+{
+ double bw;
+
+ if(nseconds <= (double)0.0F)
+ HDstrcpy(buf, " NaN");
+ else {
+ bw = nbytes/nseconds;
+ if(H5_DBL_ABS_EQUAL(bw, (double)0.0F))
+ HDstrcpy(buf, "0.000 B/s");
+ else if(bw < (double)1.0F)
+ sprintf(buf, "%10.4e", bw);
+ else if(bw < (double)H5_KB) {
+ sprintf(buf, "%05.4f", bw);
+ HDstrcpy(buf+5, " B/s");
+ } else if(bw < (double)H5_MB) {
+ sprintf(buf, "%05.4f", bw / (double)H5_KB);
+ HDstrcpy(buf+5, " kB/s");
+ } else if(bw < (double)H5_GB) {
+ sprintf(buf, "%05.4f", bw / (double)H5_MB);
+ HDstrcpy(buf+5, " MB/s");
+ } else if(bw < (double)H5_TB) {
+ sprintf(buf, "%05.4f", bw / (double)H5_GB);
+ HDstrcpy(buf+5, " GB/s");
+ } else if(bw < (double)H5_PB) {
+ sprintf(buf, "%05.4f", bw / (double)H5_TB);
+ HDstrcpy(buf+5, " TB/s");
+ } else {
+ sprintf(buf, "%10.4e", bw);
+ if(HDstrlen(buf) > 10)
+ sprintf(buf, "%10.3e", bw);
+ }
+ }
+} /* end H5_bandwidth() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_now
+ *
+ * Purpose: Retrieves the current time, as seconds after the UNIX epoch.
+ *
+ * Return: # of seconds from the epoch (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+time_t
+H5_now(void)
+{
+ time_t now; /* Current time */
+
+#ifdef H5_HAVE_GETTIMEOFDAY
+ {
+ struct timeval now_tv;
+
+ HDgettimeofday(&now_tv, NULL);
+ now = now_tv.tv_sec;
+ }
+#else /* H5_HAVE_GETTIMEOFDAY */
+ now = HDtime(NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ return(now);
+} /* end H5_now() */
+
diff --git a/src/H5trace.c b/src/H5trace.c
new file mode 100644
index 0000000..9fb8a72
--- /dev/null
+++ b/src/H5trace.c
@@ -0,0 +1,2658 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5trace.c
+ * Aug 21 2006
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Internal code for tracing API calls
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+#define H5I_FRIEND /*suppress error about including H5Ipkg */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5Ipkg.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+
+#ifdef H5_HAVE_PARALLEL
+/* datatypes of predefined drivers needed by H5_trace() */
+#include "H5FDmpio.h"
+#endif /* H5_HAVE_PARALLEL */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5_trace
+ *
+ * Purpose: This function is called whenever an API function is called
+ * and tracing is turned on. If RETURNING is non-zero then
+ * the caller is about to return and RETURNING points to the
+ * time for the corresponding function call event. Otherwise
+ * we print the function name and the arguments.
+ *
+ * The TYPE argument is a string which gives the type of each of
+ * the following argument pairs. Each type is zero or more
+ * asterisks (one for each level of indirection, although some
+ * types have one level of indirection already implied) followed
+ * by either one letter (lower case) or two letters (first one
+ * uppercase).
+ *
+ * The variable argument list consists of pairs of values. Each
+ * pair is a string which is the formal argument name in the
+ * calling function, followed by the argument value. The type
+ * of the argument value is given by the TYPE string.
+ *
+ * Note: The TYPE string is meant to be terse and is generated by a
+ * separate perl script.
+ *
+ * WARNING: DO NOT CALL ANY HDF5 FUNCTION THAT CALLS FUNC_ENTER(). DOING
+ * SO MAY CAUSE H5_trace() TO BE INVOKED RECURSIVELY OR MAY
+ * CAUSE LIBRARY INITIALIZATIONS THAT ARE NOT DESIRED.
+ *
+ * Return: Execution time for an API call
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, June 16, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+double
+H5_trace(const double *returning, const char *func, const char *type, ...)
+{
+ va_list ap;
+ char buf[64], *rest;
+ const char *argname;
+ int argno = 0, ptr, asize_idx;
+ hssize_t asize[16];
+ hssize_t i;
+ void *vp = NULL;
+ FILE *out = H5_debug_g.trace;
+ H5_timer_t event_time;
+ static H5_timer_t first_time = {0.0F, 0.0F, 0.0F};
+ static int current_depth = 0;
+ static int last_call_depth = 0;
+
+ /* FUNC_ENTER() should not be called */
+
+ if(!out)
+ return 0.0F; /*tracing is off*/
+ va_start(ap, type);
+
+ if(H5_debug_g.ttop) {
+ if(returning) {
+ if(current_depth > 1) {
+ --current_depth;
+ return 0.0F;
+ } /* end if */
+ } /* end if */
+ else {
+ if(current_depth > 0) {
+ /*do not update last_call_depth*/
+ current_depth++;
+ return 0.0F;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Get time for event */
+ if(H5_DBL_ABS_EQUAL(first_time.etime, H5_DOUBLE(0.0)))
+ H5_timer_begin(&first_time);
+ if(H5_debug_g.ttimes)
+ H5_timer_begin(&event_time);
+ else
+ HDmemset(&event_time, 0, sizeof event_time);
+
+ /* Print the first part of the line. This is the indication of the
+ * nesting depth followed by the function name and either start of
+ * argument list or start of return value. If this call is for a
+ * function return and no other calls have been made to H5_trace()
+ * since the one for the function call, then we're continuing
+ * the same line. */
+ if(returning) {
+ HDassert(current_depth > 0);
+ --current_depth;
+ if(current_depth < last_call_depth) {
+ /* We are at the beginning of a line */
+ if(H5_debug_g.ttimes) {
+ char tmp[128];
+
+ sprintf(tmp, "%.6f", event_time.etime-first_time.etime);
+ fprintf(out, " %*s ", (int)HDstrlen(tmp), "");
+ } /* end if */
+ for(i = 0; i < current_depth; i++)
+ HDfputc('+', out);
+ fprintf(out, "%*s%s = ", 2*current_depth, "", func);
+ } /* end if */
+ else {
+ /* Continue current line with return value */
+ fprintf(out, " = ");
+ } /* end else */
+ } /* end if */
+ else {
+ if(current_depth>last_call_depth)
+ HDfputs(" = <delayed>\n", out);
+ if(H5_debug_g.ttimes)
+ fprintf(out, "@%.6f ", event_time.etime - first_time.etime);
+ for(i = 0; i < current_depth; i++)
+ HDfputc('+', out);
+ fprintf(out, "%*s%s(", 2*current_depth, "", func);
+ } /* end else */
+
+ /* Clear array sizes */
+ for(i = 0; i < (hssize_t)NELMTS(asize); i++)
+ asize[i] = -1;
+
+ /* Parse the argument types */
+ for(argno = 0; *type; argno++, type += (HDisupper(*type) ? 2 : 1)) {
+ /* Count levels of indirection */
+ for(ptr = 0; '*' == *type; type++)
+ ptr++;
+ if('[' == *type) {
+ if('a' == type[1]) {
+ asize_idx = (int)HDstrtol(type + 2, &rest, 10);
+ HDassert(0 <= asize_idx && asize_idx < (int) NELMTS(asize));
+ HDassert(']'==*rest);
+ type = rest + 1;
+ } else {
+ rest = (char *)HDstrchr(type, ']');
+ HDassert(rest);
+ type = rest + 1;
+ asize_idx = -1;
+ }
+ } /* end if */
+ else
+ asize_idx = -1;
+
+ /*
+ * The argument name. Leave off the `_id' part. If the argument
+ * name is the null pointer then don't print the argument or the
+ * following `='. This is used for return values.
+ */
+ argname = va_arg(ap, char *); /*lint !e64 Type mismatch not really occuring */
+ if(argname) {
+ unsigned n = (unsigned)MAX (0, (int)HDstrlen(argname) - 3); /*lint !e666 Allow expression with side effects */
+
+ if(!HDstrcmp(argname + n, "_id")) {
+ HDstrncpy(buf, argname, (size_t)MIN((int)sizeof(buf) - 1, n));
+ buf[MIN((int)sizeof(buf) - 1, n)] = '\0';
+ argname = buf;
+ } /* end if */
+ fprintf(out, "%s%s=", argno?", ":"", argname);
+ } /* end if */
+ else
+ argname = "";
+
+ /* The value */
+ if(ptr)
+ vp = va_arg(ap, void *); /*lint !e64 Type mismatch not really occuring */
+ switch(type[0]) {
+ case 'a':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ haddr_t addr = va_arg(ap, haddr_t); /*lint !e732 Loss of sign not really occuring */
+
+ HDfprintf(out, "%a", addr);
+ } /* end else */
+ break;
+
+ case 'b':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ /* Can't pass hbool_t to va_arg() */
+ hbool_t bool_var = (hbool_t)va_arg(ap, int);
+ if(TRUE == bool_var)
+ fprintf(out, "TRUE");
+ else if(!bool_var)
+ fprintf(out, "FALSE");
+ else
+ fprintf(out, "TRUE(%u)", (unsigned)bool_var);
+ }
+ break;
+
+ case 'd':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ double dbl = va_arg(ap, double);
+
+ fprintf(out, "%g", dbl);
+ } /* end else */
+ break;
+
+ case 'D':
+ switch(type[1]) {
+ case 'a':
+ if(ptr) {
+ if(vp)
+ fprintf (out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_alloc_time_t alloc_time = (H5D_alloc_time_t)va_arg(ap, int);
+
+ switch(alloc_time) {
+ case H5D_ALLOC_TIME_ERROR:
+ fprintf(out, "H5D_ALLOC_TIME_ERROR");
+ break;
+
+ case H5D_ALLOC_TIME_DEFAULT:
+ fprintf(out, "H5D_ALLOC_TIME_DEFAULT");
+ break;
+
+ case H5D_ALLOC_TIME_EARLY:
+ fprintf(out, "H5D_ALLOC_TIME_EARLY");
+ break;
+
+ case H5D_ALLOC_TIME_LATE:
+ fprintf(out, "H5D_ALLOC_TIME_LATE");
+ break;
+
+ case H5D_ALLOC_TIME_INCR:
+ fprintf(out, "H5D_ALLOC_TIME_INCR");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)alloc_time);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'c':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5FD_mpio_collective_opt_t opt = (H5FD_mpio_collective_opt_t)va_arg(ap, int);
+
+ switch(opt) {
+ case H5FD_MPIO_COLLECTIVE_IO:
+ fprintf(out, "H5FD_MPIO_COLLECTIVE_IO");
+ break;
+
+ case H5FD_MPIO_INDIVIDUAL_IO:
+ fprintf(out, "H5FD_MPIO_INDIVIDUAL_IO");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)opt);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'f':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_fill_time_t fill_time = (H5D_fill_time_t)va_arg(ap, int);
+
+ switch(fill_time) {
+ case H5D_FILL_TIME_ERROR:
+ fprintf(out, "H5D_FILL_TIME_ERROR");
+ break;
+
+ case H5D_FILL_TIME_ALLOC:
+ fprintf(out, "H5D_FILL_TIME_ALLOC");
+ break;
+
+ case H5D_FILL_TIME_NEVER:
+ fprintf(out, "H5D_FILL_TIME_NEVER");
+ break;
+
+ case H5D_FILL_TIME_IFSET:
+ fprintf(out, "H5D_FILL_TIME_IFSET");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)fill_time);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'F':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_fill_value_t fill_value = (H5D_fill_value_t)va_arg(ap, int);
+
+ switch(fill_value) {
+ case H5D_FILL_VALUE_ERROR:
+ fprintf(out, "H5D_FILL_VALUE_ERROR");
+ break;
+
+ case H5D_FILL_VALUE_UNDEFINED:
+ fprintf(out, "H5D_FILL_VALUE_UNDEFINED");
+ break;
+
+ case H5D_FILL_VALUE_DEFAULT:
+ fprintf(out, "H5D_FILL_VALUE_DEFAULT");
+ break;
+
+ case H5D_FILL_VALUE_USER_DEFINED:
+ fprintf(out, "H5D_FILL_VALUE_USER_DEFINED");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)fill_value);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'h':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5FD_mpio_chunk_opt_t opt = (H5FD_mpio_chunk_opt_t)va_arg(ap, int);
+
+ switch(opt) {
+ case H5FD_MPIO_CHUNK_DEFAULT:
+ fprintf(out, "H5FD_MPIO_CHUNK_DEFAULT");
+ break;
+
+ case H5FD_MPIO_CHUNK_ONE_IO:
+ fprintf(out, "H5FD_MPIO_CHUNK_ONE_IO");
+ break;
+
+ case H5FD_MPIO_CHUNK_MULTI_IO:
+ fprintf(out, "H5FD_MPIO_CHUNK_MULTI_IO");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)opt);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'i':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_mpio_actual_io_mode_t actual_io_mode = (H5D_mpio_actual_io_mode_t)va_arg(ap, int);
+
+ switch(actual_io_mode) {
+ case H5D_MPIO_NO_COLLECTIVE:
+ fprintf(out, "H5D_MPIO_NO_COLLECTIVE");
+ break;
+
+ case H5D_MPIO_CHUNK_INDEPENDENT:
+ fprintf(out, "H5D_MPIO_CHUNK_INDEPENDENT");
+ break;
+
+ case H5D_MPIO_CHUNK_COLLECTIVE:
+ fprintf(out, "H5D_MPIO_CHUNK_COLLECTIVE");
+ break;
+
+ case H5D_MPIO_CHUNK_MIXED:
+ fprintf(out, "H5D_MPIO_CHUNK_MIXED");
+ break;
+
+ case H5D_MPIO_CONTIGUOUS_COLLECTIVE:
+ fprintf(out, "H5D_MPIO_CONTIGUOUS_COLLECTIVE");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)actual_io_mode);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'k':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_chunk_index_t idx = (H5D_chunk_index_t)va_arg(ap, int);
+
+ switch(idx) {
+ case H5D_CHUNK_IDX_BTREE:
+ fprintf(out, "H5D_CHUNK_IDX_BTREE");
+ break;
+
+ case H5D_CHUNK_IDX_NONE:
+ fprintf(out, "H5D_CHUNK_IDX_NONE");
+ break;
+
+ case H5D_CHUNK_IDX_FARRAY:
+ fprintf(out, "H5D_CHUNK_IDX_FARRAY");
+ break;
+
+ case H5D_CHUNK_IDX_EARRAY:
+ fprintf(out, "H5D_CHUNK_IDX_EARRAY");
+ break;
+
+ case H5D_CHUNK_IDX_BT2:
+ fprintf(out, "H5D_CHUNK_IDX_BT2");
+ break;
+
+ case H5D_CHUNK_IDX_SINGLE:
+ fprintf(out, "H5D_CHUNK_IDX_SINGLE");
+ break;
+
+ case H5D_CHUNK_IDX_NTYPES:
+ fprintf(out, "ERROR: H5D_CHUNK_IDX_NTYPES (invalid value)");
+ break;
+
+ default:
+ fprintf(out, "UNKNOWN VALUE: %ld", (long)idx);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'l':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_layout_t layout = (H5D_layout_t)va_arg(ap, int);
+
+ switch(layout) {
+ case H5D_LAYOUT_ERROR:
+ fprintf(out, "H5D_LAYOUT_ERROR");
+ break;
+
+ case H5D_COMPACT:
+ fprintf(out, "H5D_COMPACT");
+ break;
+
+ case H5D_CONTIGUOUS:
+ fprintf(out, "H5D_CONTIGUOUS");
+ break;
+
+ case H5D_CHUNKED:
+ fprintf(out, "H5D_CHUNKED");
+ break;
+
+ case H5D_VIRTUAL:
+ fprintf(out, "H5D_VIRTUAL");
+ break;
+
+ case H5D_NLAYOUTS:
+ fprintf(out, "H5D_NLAYOUTS");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)layout);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'n':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_mpio_no_collective_cause_t nocol_cause_mode = (H5D_mpio_no_collective_cause_t)va_arg(ap, int);
+ hbool_t flag_already_displayed = FALSE;
+
+ /* Check for all bit-flags which might be set */
+ if(nocol_cause_mode & H5D_MPIO_COLLECTIVE) {
+ fprintf(out, "H5D_MPIO_COLLECTIVE");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_SET_INDEPENDENT) {
+ fprintf(out, "%sH5D_MPIO_SET_INDEPENDENT", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_DATATYPE_CONVERSION) {
+ fprintf(out, "%sH5D_MPIO_DATATYPE_CONVERSION", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_DATA_TRANSFORMS) {
+ fprintf(out, "%sH5D_MPIO_DATA_TRANSFORMS", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED) {
+ fprintf(out, "%sH5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES) {
+ fprintf(out, "%sH5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET) {
+ fprintf(out, "%sH5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+ if(nocol_cause_mode & H5D_MPIO_FILTERS) {
+ fprintf(out, "%sH5D_MPIO_FILTERS", flag_already_displayed ? " | " : "");
+ flag_already_displayed = TRUE;
+ } /* end if */
+
+ /* Display '<none>' if there's no flags set */
+ if(!flag_already_displayed)
+ fprintf(out, "<none>");
+ } /* end else */
+ break;
+
+ case 'o':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_mpio_actual_chunk_opt_mode_t chunk_opt_mode = (H5D_mpio_actual_chunk_opt_mode_t)va_arg(ap, int);
+
+ switch(chunk_opt_mode) {
+ case H5D_MPIO_NO_CHUNK_OPTIMIZATION:
+ fprintf(out, "H5D_MPIO_NO_CHUNK_OPTIMIZATION");
+ break;
+
+ case H5D_MPIO_LINK_CHUNK:
+ fprintf(out, "H5D_MPIO_LINK_CHUNK");
+ break;
+
+ case H5D_MPIO_MULTI_CHUNK:
+ fprintf(out, "H5D_MPIO_MULTI_CHUNK");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)chunk_opt_mode);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_space_status_t space_status = (H5D_space_status_t)va_arg(ap, int);
+
+ switch(space_status) {
+ case H5D_SPACE_STATUS_NOT_ALLOCATED:
+ fprintf(out, "H5D_SPACE_STATUS_NOT_ALLOCATED");
+ break;
+
+ case H5D_SPACE_STATUS_PART_ALLOCATED:
+ fprintf(out, "H5D_SPACE_STATUS_PART_ALLOCATED");
+ break;
+
+ case H5D_SPACE_STATUS_ALLOCATED:
+ fprintf(out, "H5D_SPACE_STATUS_ALLOCATED");
+ break;
+
+ case H5D_SPACE_STATUS_ERROR:
+ fprintf(out, "H5D_SPACE_STATUS_ERROR");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)space_status);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5FD_mpio_xfer_t transfer = (H5FD_mpio_xfer_t)va_arg(ap, int);
+
+ switch(transfer) {
+ case H5FD_MPIO_INDEPENDENT:
+ fprintf(out, "H5FD_MPIO_INDEPENDENT");
+ break;
+
+ case H5FD_MPIO_COLLECTIVE:
+ fprintf(out, "H5FD_MPIO_COLLECTIVE");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)transfer);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'v':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5D_vds_view_t view = (H5D_vds_view_t)va_arg(ap, int);
+
+ switch(view) {
+ case H5D_VDS_ERROR:
+ fprintf(out, "H5D_VDS_ERROR");
+ break;
+
+ case H5D_VDS_FIRST_MISSING:
+ fprintf(out, "H5D_VDS_FIRST_MISSING");
+ break;
+
+ case H5D_VDS_LAST_AVAILABLE:
+ fprintf(out, "H5D_VDS_LAST_AVAILABLE");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)view);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf (out, "BADTYPE(D%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'e':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ herr_t status = va_arg(ap, herr_t);
+
+ if(status >= 0)
+ fprintf(out, "SUCCEED");
+ else
+ fprintf(out, "FAIL");
+ } /* end else */
+ break;
+
+ case 'E':
+ switch(type[1]) {
+ case 'd':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5E_direction_t direction = (H5E_direction_t)va_arg(ap, int);
+
+ switch(direction) {
+ case H5E_WALK_UPWARD:
+ fprintf(out, "H5E_WALK_UPWARD");
+ break;
+
+ case H5E_WALK_DOWNWARD:
+ fprintf(out, "H5E_WALK_DOWNWARD");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)direction);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'e':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5E_error2_t *error = va_arg(ap, H5E_error2_t *); /*lint !e64 Type mismatch not really occuring */
+
+ fprintf(out, "0x%lx", (unsigned long)error);
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5E_type_t etype = (H5E_type_t)va_arg(ap, int);
+
+ switch(etype) {
+ case H5E_MAJOR:
+ fprintf(out, "H5E_MAJOR");
+ break;
+
+ case H5E_MINOR:
+ fprintf(out, "H5E_MINOR");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)etype);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(E%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'F':
+ switch(type[1]) {
+ case 'd':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5F_close_degree_t degree = (H5F_close_degree_t)va_arg(ap, int);
+
+ switch(degree) {
+ case H5F_CLOSE_DEFAULT:
+ fprintf(out, "H5F_CLOSE_DEFAULT");
+ break;
+
+ case H5F_CLOSE_WEAK:
+ fprintf(out, "H5F_CLOSE_WEAK");
+ break;
+
+ case H5F_CLOSE_SEMI:
+ fprintf(out, "H5F_CLOSE_SEMI");
+ break;
+
+ case H5F_CLOSE_STRONG:
+ fprintf(out, "H5F_CLOSE_STRONG");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)degree);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'f':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5F_fspace_strategy_t fs_strategy = (H5F_fspace_strategy_t)va_arg(ap, int);
+
+ switch(fs_strategy) {
+ case H5F_FSPACE_STRATEGY_FSM_AGGR:
+ fprintf(out, "H5F_FSPACE_STRATEGY_FSM_AGGR");
+ break;
+
+ case H5F_FSPACE_STRATEGY_PAGE:
+ fprintf(out, "H5F_FSPACE_STRATEGY_PAGE");
+ break;
+
+ case H5F_FSPACE_STRATEGY_AGGR:
+ fprintf(out, "H5F_FSPACE_STRATEGY_AGGR");
+ break;
+
+ case H5F_FSPACE_STRATEGY_NONE:
+ fprintf(out, "H5F_FSPACE_STRATEGY_NONE");
+ break;
+
+ case H5F_FSPACE_STRATEGY_NTYPES:
+ default:
+ fprintf(out, "%ld", (long)fs_strategy);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'm':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5F_mem_t mem_type = (H5F_mem_t)va_arg(ap, int);
+
+ switch(mem_type) {
+ case H5FD_MEM_NOLIST:
+ fprintf(out, "H5FD_MEM_NOLIST");
+ break;
+
+ case H5FD_MEM_DEFAULT:
+ fprintf(out, "H5FD_MEM_DEFAULT");
+ break;
+
+ case H5FD_MEM_SUPER:
+ fprintf(out, "H5FD_MEM_SUPER");
+ break;
+
+ case H5FD_MEM_BTREE:
+ fprintf(out, "H5FD_MEM_BTREE");
+ break;
+
+ case H5FD_MEM_DRAW:
+ fprintf(out, "H5FD_MEM_DRAW");
+ break;
+
+ case H5FD_MEM_GHEAP:
+ fprintf(out, "H5FD_MEM_GHEAP");
+ break;
+
+ case H5FD_MEM_LHEAP:
+ fprintf(out, "H5FD_MEM_LHEAP");
+ break;
+
+ case H5FD_MEM_OHDR:
+ fprintf(out, "H5FD_MEM_OHDR");
+ break;
+
+ case H5FD_MEM_NTYPES:
+ default:
+ fprintf(out, "%ld", (long)mem_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5F_scope_t scope = (H5F_scope_t)va_arg(ap, int);
+
+ switch(scope) {
+ case H5F_SCOPE_LOCAL:
+ fprintf(out, "H5F_SCOPE_LOCAL");
+ break;
+
+ case H5F_SCOPE_GLOBAL:
+ fprintf(out, "H5F_SCOPE_GLOBAL");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)scope);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ break;
+
+ case 'v':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5F_libver_t libver_vers = (H5F_libver_t)va_arg(ap, int);
+
+ switch(libver_vers) {
+ case H5F_LIBVER_EARLIEST:
+ fprintf(out, "H5F_LIBVER_EARLIEST");
+ break;
+
+ case H5F_LIBVER_LATEST:
+ fprintf(out, "H5F_LIBVER_LATEST");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)libver_vers);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(F%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'G':
+ switch(type[1]) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+ case 'o':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5G_obj_t obj_type = (H5G_obj_t)va_arg(ap, int);
+
+ switch(obj_type) {
+ case H5G_UNKNOWN:
+ fprintf(out, "H5G_UNKNOWN");
+ break;
+
+ case H5G_GROUP:
+ fprintf(out, "H5G_GROUP");
+ break;
+
+ case H5G_DATASET:
+ fprintf(out, "H5G_DATASET");
+ break;
+
+ case H5G_TYPE:
+ fprintf(out, "H5G_TYPE");
+ break;
+
+ case H5G_LINK:
+ fprintf(out, "H5G_LINK");
+ break;
+
+ case H5G_UDLINK:
+ fprintf(out, "H5G_UDLINK");
+ break;
+
+ case H5G_RESERVED_5:
+ case H5G_RESERVED_6:
+ case H5G_RESERVED_7:
+ fprintf(out, "H5G_RESERVED(%ld)", (long)obj_type);
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)obj_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf (out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5G_stat_t *statbuf = va_arg(ap, H5G_stat_t*); /*lint !e64 Type mismatch not really occuring */
+
+ fprintf(out, "0x%lx", (unsigned long)statbuf);
+ }
+ break;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+ default:
+ fprintf(out, "BADTYPE(G%c)", type[1]);
+ goto error;
+ }
+ break;
+
+ case 'h':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ hsize_t *p = (hsize_t *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++) {
+ if(H5S_UNLIMITED == p[i])
+ HDfprintf(out, "%sH5S_UNLIMITED", (i ? ", " : ""));
+ else
+ HDfprintf(out, "%s%Hu", (i ? ", " : ""), p[i]);
+ } /* end for */
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ hsize_t hsize = va_arg(ap, hsize_t); /*lint !e732 Loss of sign not really occuring */
+
+ if(H5S_UNLIMITED == hsize)
+ HDfprintf(out, "H5S_UNLIMITED");
+ else {
+ HDfprintf(out, "%Hu", hsize);
+ asize[argno] = (hssize_t)hsize;
+ } /* end else */
+ } /* end else */
+ break;
+
+ case 'H':
+ switch(type[1]) {
+ case 's':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ hssize_t *p = (hssize_t *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%Hd", (i ? ", " : ""), p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ hssize_t hssize = va_arg(ap, hssize_t);
+
+ HDfprintf(out, "%Hd", hssize);
+ asize[argno] = (hssize_t)hssize;
+ } /* end else */
+ break;
+
+ default:
+ fprintf (out, "BADTYPE(H%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'i':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ hid_t obj = va_arg(ap, hid_t);
+
+ if(H5P_DEFAULT == obj)
+ fprintf(out, "H5P_DEFAULT");
+ else if(obj < 0)
+ fprintf(out, "FAIL");
+ else {
+ switch(H5I_TYPE(obj)) { /* Use internal H5I macro instead of function call */
+ case H5I_UNINIT:
+ fprintf(out, "%ld (uninit - error)", (long)obj);
+ break;
+
+ case H5I_BADID:
+ fprintf(out, "%ld (error)", (long)obj);
+ break;
+
+ case H5I_FILE:
+ fprintf(out, "%ld (file)", (long)obj);
+ break;
+
+ case H5I_GROUP:
+ fprintf(out, "%ld (group)", (long)obj);
+ break;
+
+ case H5I_DATATYPE:
+ if(obj == H5T_NATIVE_SCHAR_g)
+ fprintf(out, "H5T_NATIVE_SCHAR");
+ else if(obj == H5T_NATIVE_UCHAR_g)
+ fprintf(out, "H5T_NATIVE_UCHAR");
+ else if(obj == H5T_NATIVE_SHORT_g)
+ fprintf(out, "H5T_NATIVE_SHORT");
+ else if(obj == H5T_NATIVE_USHORT_g)
+ fprintf(out, "H5T_NATIVE_USHORT");
+ else if(obj == H5T_NATIVE_INT_g)
+ fprintf(out, "H5T_NATIVE_INT");
+ else if(obj == H5T_NATIVE_UINT_g)
+ fprintf(out, "H5T_NATIVE_UINT");
+ else if(obj == H5T_NATIVE_LONG_g)
+ fprintf(out, "H5T_NATIVE_LONG");
+ else if(obj == H5T_NATIVE_ULONG_g)
+ fprintf(out, "H5T_NATIVE_ULONG");
+ else if(obj == H5T_NATIVE_LLONG_g)
+ fprintf(out, "H5T_NATIVE_LLONG");
+ else if(obj == H5T_NATIVE_ULLONG_g)
+ fprintf(out, "H5T_NATIVE_ULLONG");
+ else if(obj == H5T_NATIVE_FLOAT_g)
+ fprintf(out, "H5T_NATIVE_FLOAT");
+ else if(obj == H5T_NATIVE_DOUBLE_g)
+ fprintf(out, "H5T_NATIVE_DOUBLE");
+#if H5_SIZEOF_LONG_DOUBLE !=0
+ else if(obj == H5T_NATIVE_LDOUBLE_g)
+ fprintf(out, "H5T_NATIVE_LDOUBLE");
+#endif
+ else if(obj == H5T_IEEE_F32BE_g)
+ fprintf(out, "H5T_IEEE_F32BE");
+ else if(obj == H5T_IEEE_F32LE_g)
+ fprintf(out, "H5T_IEEE_F32LE");
+ else if(obj == H5T_IEEE_F64BE_g)
+ fprintf(out, "H5T_IEEE_F64BE");
+ else if(obj == H5T_IEEE_F64LE_g)
+ fprintf(out, "H5T_IEEE_F64LE");
+ else if(obj == H5T_STD_I8BE_g)
+ fprintf(out, "H5T_STD_I8BE");
+ else if(obj == H5T_STD_I8LE_g)
+ fprintf(out, "H5T_STD_I8LE");
+ else if(obj == H5T_STD_I16BE_g)
+ fprintf(out, "H5T_STD_I16BE");
+ else if(obj == H5T_STD_I16LE_g)
+ fprintf(out, "H5T_STD_I16LE");
+ else if(obj == H5T_STD_I32BE_g)
+ fprintf(out, "H5T_STD_I32BE");
+ else if(obj == H5T_STD_I32LE_g)
+ fprintf(out, "H5T_STD_I32LE");
+ else if(obj == H5T_STD_I64BE_g)
+ fprintf(out, "H5T_STD_I64BE");
+ else if(obj == H5T_STD_I64LE_g)
+ fprintf(out, "H5T_STD_I64LE");
+ else if(obj == H5T_STD_U8BE_g)
+ fprintf(out, "H5T_STD_U8BE");
+ else if(obj == H5T_STD_U8LE_g)
+ fprintf(out, "H5T_STD_U8LE");
+ else if(obj == H5T_STD_U16BE_g)
+ fprintf(out, "H5T_STD_U16BE");
+ else if(obj == H5T_STD_U16LE_g)
+ fprintf(out, "H5T_STD_U16LE");
+ else if(obj == H5T_STD_U32BE_g)
+ fprintf(out, "H5T_STD_U32BE");
+ else if(obj == H5T_STD_U32LE_g)
+ fprintf(out, "H5T_STD_U32LE");
+ else if(obj == H5T_STD_U64BE_g)
+ fprintf(out, "H5T_STD_U64BE");
+ else if(obj == H5T_STD_U64LE_g)
+ fprintf(out, "H5T_STD_U64LE");
+ else if(obj == H5T_STD_B8BE_g)
+ fprintf(out, "H5T_STD_B8BE");
+ else if(obj == H5T_STD_B8LE_g)
+ fprintf(out, "H5T_STD_B8LE");
+ else if(obj == H5T_STD_B16BE_g)
+ fprintf(out, "H5T_STD_B16BE");
+ else if(obj == H5T_STD_B16LE_g)
+ fprintf(out, "H5T_STD_B16LE");
+ else if(obj == H5T_STD_B32BE_g)
+ fprintf(out, "H5T_STD_B32BE");
+ else if(obj == H5T_STD_B32LE_g)
+ fprintf(out, "H5T_STD_B32LE");
+ else if(obj == H5T_STD_B64BE_g)
+ fprintf(out, "H5T_STD_B64BE");
+ else if(obj == H5T_STD_B64LE_g)
+ fprintf(out, "H5T_STD_B64LE");
+ else if(obj == H5T_C_S1_g)
+ fprintf(out, "H5T_C_S1");
+ else if(obj == H5T_FORTRAN_S1_g)
+ fprintf(out, "H5T_FORTRAN_S1");
+ else
+ fprintf(out, "%ld (dtype)", (long)obj);
+ break;
+
+ case H5I_DATASPACE:
+ fprintf(out, "%ld (dspace)", (long)obj);
+ /* Save the rank of simple data spaces for arrays */
+ /* This may generate recursive call to the library... -QAK */
+ {
+ H5S_t *space;
+
+ if(NULL != (space = (H5S_t *)H5I_object(obj)))
+ if(H5S_SIMPLE == H5S_GET_EXTENT_TYPE(space))
+ asize[argno] = H5S_GET_EXTENT_NDIMS(space);
+ }
+ break;
+
+ case H5I_DATASET:
+ fprintf(out, "%ld (dset)", (long)obj);
+ break;
+
+ case H5I_ATTR:
+ fprintf(out, "%ld (attr)", (long)obj);
+ break;
+
+ case H5I_REFERENCE:
+ fprintf(out, "%ld (reference)", (long)obj);
+ break;
+
+ case H5I_VFL:
+ fprintf(out, "%ld (file driver)", (long)obj);
+ break;
+
+ case H5I_GENPROP_CLS:
+ fprintf(out, "%ld (genprop class)", (long)obj);
+ break;
+
+ case H5I_GENPROP_LST:
+ fprintf(out, "%ld (genprop list)", (long)obj);
+ break;
+
+ case H5I_ERROR_CLASS:
+ fprintf(out, "%ld (err class)", (long)obj);
+ break;
+
+ case H5I_ERROR_MSG:
+ fprintf(out, "%ld (err msg)", (long)obj);
+ break;
+
+ case H5I_ERROR_STACK:
+ fprintf(out, "%ld (err stack)", (long)obj);
+ break;
+
+ case H5I_NTYPES:
+ fprintf (out, "%ld (ntypes - error)", (long)obj);
+ break;
+
+ default:
+ fprintf(out, "%ld (unknown class)", (long)obj);
+ break;
+ } /* end switch */
+ } /* end else */
+ } /* end else */
+ break;
+
+ case 'I':
+ switch (type[1]) {
+ case 'i':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5_index_t idx_type = (H5_index_t)va_arg(ap, int);
+
+ switch(idx_type) {
+ case H5_INDEX_UNKNOWN:
+ fprintf(out, "H5_INDEX_UNKNOWN");
+ break;
+
+ case H5_INDEX_NAME:
+ fprintf(out, "H5_INDEX_NAME");
+ break;
+
+ case H5_INDEX_CRT_ORDER:
+ fprintf(out, "H5_INDEX_CRT_ORDER");
+ break;
+
+ case H5_INDEX_N:
+ fprintf(out, "H5_INDEX_N");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)idx_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'o':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5_iter_order_t order = (H5_iter_order_t)va_arg(ap, int);
+
+ switch(order) {
+ case H5_ITER_UNKNOWN:
+ fprintf(out, "H5_ITER_UNKNOWN");
+ break;
+
+ case H5_ITER_INC:
+ fprintf(out, "H5_ITER_INC");
+ break;
+
+ case H5_ITER_DEC:
+ fprintf(out, "H5_ITER_DEC");
+ break;
+
+ case H5_ITER_NATIVE:
+ fprintf(out, "H5_ITER_NATIVE");
+ break;
+
+ case H5_ITER_N:
+ fprintf(out, "H5_ITER_N");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)order);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ int *p = (int*)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ fprintf(out, "%s%d", (i ? ", " : ""), p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ int is = va_arg(ap, int);
+
+ fprintf (out, "%d", is);
+ asize[argno] = is;
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5I_type_t id_type = (H5I_type_t)va_arg(ap, int);
+
+ switch (id_type) {
+ case H5I_UNINIT:
+ fprintf(out, "H5I_UNINIT");
+ break;
+
+ case H5I_BADID:
+ fprintf(out, "H5I_BADID");
+ break;
+
+ case H5I_FILE:
+ fprintf(out, "H5I_FILE");
+ break;
+
+ case H5I_GROUP:
+ fprintf(out, "H5I_GROUP");
+ break;
+
+ case H5I_DATATYPE:
+ fprintf(out, "H5I_DATATYPE");
+ break;
+
+ case H5I_DATASPACE:
+ fprintf(out, "H5I_DATASPACE");
+ break;
+
+ case H5I_DATASET:
+ fprintf(out, "H5I_DATASET");
+ break;
+
+ case H5I_ATTR:
+ fprintf(out, "H5I_ATTR");
+ break;
+
+ case H5I_REFERENCE:
+ fprintf(out, "H5I_REFERENCE");
+ break;
+
+ case H5I_VFL:
+ fprintf(out, "H5I_VFL");
+ break;
+
+ case H5I_GENPROP_CLS:
+ fprintf(out, "H5I_GENPROP_CLS");
+ break;
+
+ case H5I_GENPROP_LST:
+ fprintf(out, "H5I_GENPROP_LST");
+ break;
+
+ case H5I_ERROR_CLASS:
+ fprintf(out, "H5I_ERROR_CLASS");
+ break;
+
+ case H5I_ERROR_MSG:
+ fprintf(out, "H5I_ERROR_MSG");
+ break;
+
+ case H5I_ERROR_STACK:
+ fprintf(out, "H5I_ERROR_STACK");
+ break;
+
+ case H5I_NTYPES:
+ fprintf(out, "H5I_NTYPES");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)id_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'u':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ unsigned *p = (unsigned*)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%u", i?", ":"", p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ unsigned iu = va_arg(ap, unsigned); /*lint !e732 Loss of sign not really occuring */
+
+ fprintf(out, "%u", iu);
+ asize[argno] = iu;
+ } /* end else */
+ break;
+
+ default:
+ fprintf (out, "BADTYPE(I%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'L':
+ switch(type[1]) {
+ case 'l':
+ if(ptr) {
+ if(vp)
+ fprintf (out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5L_type_t link_type = (H5L_type_t)va_arg(ap, int);
+
+ switch(link_type) {
+ case H5L_TYPE_ERROR:
+ fprintf(out, "H5L_TYPE_ERROR");
+ break;
+
+ case H5L_TYPE_HARD:
+ fprintf(out, "H5L_TYPE_HARD");
+ break;
+
+ case H5L_TYPE_SOFT:
+ fprintf(out, "H5L_TYPE_SOFT");
+ break;
+
+ case H5L_TYPE_EXTERNAL:
+ fprintf(out, "H5L_TYPE_EXTERNAL");
+ break;
+
+ case H5L_TYPE_MAX:
+ fprintf(out, "H5L_TYPE_MAX");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)link_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(G%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'M':
+ switch(type[1]) {
+ case 'c':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+#ifdef H5_HAVE_PARALLEL
+ else {
+ MPI_Comm comm = va_arg(ap, MPI_Comm);
+
+ fprintf(out, "%ld", (long)comm);
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+ break;
+
+ case 'i':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+#ifdef H5_HAVE_PARALLEL
+ else {
+ MPI_Info info = va_arg(ap, MPI_Info);
+
+ fprintf(out, "%ld", (long)info);
+ } /* end else */
+#endif /* H5_HAVE_PARALLEL */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5FD_mem_t mt = (H5FD_mem_t)va_arg(ap, int);
+
+ switch(mt) {
+ case H5FD_MEM_NOLIST:
+ fprintf(out, "H5FD_MEM_NOLIST");
+ break;
+
+ case H5FD_MEM_DEFAULT:
+ fprintf(out, "H5FD_MEM_DEFAULT");
+ break;
+
+ case H5FD_MEM_SUPER:
+ fprintf(out, "H5FD_MEM_SUPER");
+ break;
+
+ case H5FD_MEM_BTREE:
+ fprintf(out, "H5FD_MEM_BTREE");
+ break;
+
+ case H5FD_MEM_DRAW:
+ fprintf(out, "H5FD_MEM_DRAW");
+ break;
+
+ case H5FD_MEM_GHEAP:
+ fprintf(out, "H5FD_MEM_GHEAP");
+ break;
+
+ case H5FD_MEM_LHEAP:
+ fprintf(out, "H5FD_MEM_LHEAP");
+ break;
+
+ case H5FD_MEM_OHDR:
+ fprintf(out, "H5FD_MEM_OHDR");
+ break;
+
+ case H5FD_MEM_NTYPES:
+ fprintf(out, "H5FD_MEM_NTYPES");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)mt);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'o':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ off_t offset = va_arg(ap, off_t);
+
+ fprintf (out, "%ld", (long)offset);
+ } /* end else */
+ break;
+
+ case 'O':
+ switch(type[1]) {
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5O_type_t objtype = (H5O_type_t)va_arg(ap, int);
+
+ switch(objtype) {
+ case H5O_TYPE_UNKNOWN:
+ fprintf(out, "H5O_TYPE_UNKNOWN");
+ break;
+
+ case H5O_TYPE_GROUP:
+ fprintf(out, "H5O_TYPE_GROUP");
+ break;
+
+ case H5O_TYPE_DATASET:
+ fprintf(out, "H5O_TYPE_DATASET");
+ break;
+
+ case H5O_TYPE_NAMED_DATATYPE:
+ fprintf(out, "H5O_TYPE_NAMED_DATATYPE");
+ break;
+
+ case H5O_TYPE_NTYPES:
+ fprintf(out, "H5O_TYPE_TYPES");
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(%ld)", (long)objtype);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(S%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'p':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ hid_t pclass_id = va_arg(ap, hid_t);
+ char *class_name = NULL;
+ H5P_genclass_t *pclass;
+
+ /* Get the class name and print it */
+ /* (This may generate recursive call to the library... -QAK) */
+ if(NULL != (pclass = (H5P_genclass_t *)H5I_object(pclass_id)) &&
+ NULL != (class_name = H5P_get_class_name(pclass))) {
+ fprintf(out, "%s", class_name);
+ H5MM_xfree(class_name);
+ } /* end if */
+ else
+ fprintf(out, "%ld", (long)pclass_id);
+ } /* end else */
+ break;
+
+ case 'r':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ hobj_ref_t ref = va_arg(ap, hobj_ref_t); /*lint !e732 Loss of sign not really occuring */
+
+ HDfprintf(out, "Reference Object=%a", ref);
+ } /* end else */
+ break;
+
+ case 'R':
+ switch(type[1]) {
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5R_type_t reftype = (H5R_type_t)va_arg(ap, int);
+
+ switch(reftype) {
+ case H5R_BADTYPE:
+ fprintf(out, "H5R_BADTYPE");
+ break;
+
+ case H5R_OBJECT:
+ fprintf(out, "H5R_OBJECT");
+ break;
+
+ case H5R_DATASET_REGION:
+ fprintf(out, "H5R_DATASET_REGION");
+ break;
+
+ case H5R_MAXTYPE:
+ fprintf(out, "H5R_MAXTYPE");
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(%ld)", (long)reftype);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(S%c)", type[1]);
+ goto error;
+ }
+ break;
+
+ case 'S':
+ switch(type[1]) {
+ case 'c':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5S_class_t cls = (H5S_class_t)va_arg(ap, int);
+
+ switch(cls) {
+ case H5S_NO_CLASS:
+ fprintf(out, "H5S_NO_CLASS");
+ break;
+
+ case H5S_SCALAR:
+ fprintf(out, "H5S_SCALAR");
+ break;
+
+ case H5S_SIMPLE:
+ fprintf(out, "H5S_SIMPLE");
+ break;
+
+ case H5S_NULL:
+ fprintf(out, "H5S_NULL");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)cls);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5S_seloper_t so = (H5S_seloper_t)va_arg(ap, int);
+
+ switch(so) {
+ case H5S_SELECT_NOOP:
+ fprintf(out, "H5S_NOOP");
+ break;
+
+ case H5S_SELECT_SET:
+ fprintf(out, "H5S_SELECT_SET");
+ break;
+
+ case H5S_SELECT_OR:
+ fprintf(out, "H5S_SELECT_OR");
+ break;
+
+ case H5S_SELECT_AND:
+ fprintf(out, "H5S_SELECT_AND");
+ break;
+
+ case H5S_SELECT_XOR:
+ fprintf(out, "H5S_SELECT_XOR");
+ break;
+
+ case H5S_SELECT_NOTB:
+ fprintf(out, "H5S_SELECT_NOTB");
+ break;
+
+ case H5S_SELECT_NOTA:
+ fprintf(out, "H5S_SELECT_NOTA");
+ break;
+
+ case H5S_SELECT_APPEND:
+ fprintf(out, "H5S_SELECT_APPEND");
+ break;
+
+ case H5S_SELECT_PREPEND:
+ fprintf(out, "H5S_SELECT_PREPEND");
+ break;
+
+ case H5S_SELECT_INVALID:
+ fprintf(out, "H5S_SELECT_INVALID");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)so);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5S_sel_type st = (H5S_sel_type)va_arg(ap, int);
+
+ switch(st) {
+ case H5S_SEL_ERROR:
+ fprintf(out, "H5S_SEL_ERROR");
+ break;
+
+ case H5S_SEL_NONE:
+ fprintf(out, "H5S_SEL_NONE");
+ break;
+
+ case H5S_SEL_POINTS:
+ fprintf(out, "H5S_SEL_POINTS");
+ break;
+
+ case H5S_SEL_HYPERSLABS:
+ fprintf(out, "H5S_SEL_HYPERSLABS");
+ break;
+
+ case H5S_SEL_ALL:
+ fprintf(out, "H5S_SEL_ALL");
+ break;
+
+ case H5S_SEL_N:
+ fprintf(out, "H5S_SEL_N");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)st);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(S%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ const char *str = va_arg(ap, const char *); /*lint !e64 Type mismatch not really occuring */
+
+ fprintf(out, "\"%s\"", str);
+ } /* end else */
+ break;
+
+ case 'T':
+ switch(type[1]) {
+ case 'c':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_cset_t cset = (H5T_cset_t)va_arg(ap, int);
+
+ switch(cset) {
+ case H5T_CSET_ERROR:
+ fprintf(out, "H5T_CSET_ERROR");
+ break;
+
+ case H5T_CSET_ASCII:
+ fprintf(out, "H5T_CSET_ASCII");
+ break;
+
+ case H5T_CSET_UTF8:
+ fprintf(out, "H5T_CSET_UTF8");
+ break;
+
+ case H5T_CSET_RESERVED_2:
+ case H5T_CSET_RESERVED_3:
+ case H5T_CSET_RESERVED_4:
+ case H5T_CSET_RESERVED_5:
+ case H5T_CSET_RESERVED_6:
+ case H5T_CSET_RESERVED_7:
+ case H5T_CSET_RESERVED_8:
+ case H5T_CSET_RESERVED_9:
+ case H5T_CSET_RESERVED_10:
+ case H5T_CSET_RESERVED_11:
+ case H5T_CSET_RESERVED_12:
+ case H5T_CSET_RESERVED_13:
+ case H5T_CSET_RESERVED_14:
+ case H5T_CSET_RESERVED_15:
+ fprintf(out, "H5T_CSET_RESERVED_%ld", (long)cset);
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)cset);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'd':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_direction_t direct = (H5T_direction_t)va_arg(ap, int);
+
+ switch(direct) {
+ case H5T_DIR_DEFAULT:
+ fprintf(out, "H5T_DIR_DEFAULT");
+ break;
+
+ case H5T_DIR_ASCEND:
+ fprintf(out, "H5T_DIR_ASCEND");
+ break;
+
+ case H5T_DIR_DESCEND:
+ fprintf(out, "H5T_DIR_DESCEND");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)direct);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'e':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_pers_t pers = (H5T_pers_t)va_arg(ap, int);
+
+ switch(pers) {
+ case H5T_PERS_DONTCARE:
+ fprintf(out, "H5T_PERS_DONTCARE");
+ break;
+
+ case H5T_PERS_SOFT:
+ fprintf(out, "H5T_PERS_SOFT");
+ break;
+
+ case H5T_PERS_HARD:
+ fprintf(out, "H5T_PERS_HARD");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)pers);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'n':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_norm_t norm = (H5T_norm_t)va_arg(ap, int);
+
+ switch(norm) {
+ case H5T_NORM_ERROR:
+ fprintf(out, "H5T_NORM_ERROR");
+ break;
+
+ case H5T_NORM_IMPLIED:
+ fprintf(out, "H5T_NORM_IMPLIED");
+ break;
+
+ case H5T_NORM_MSBSET:
+ fprintf(out, "H5T_NORM_MSBSET");
+ break;
+
+ case H5T_NORM_NONE:
+ fprintf(out, "H5T_NORM_NONE");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)norm);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'o':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_order_t order = (H5T_order_t)va_arg(ap, int);
+
+ switch(order) {
+ case H5T_ORDER_ERROR:
+ fprintf(out, "H5T_ORDER_ERROR");
+ break;
+
+ case H5T_ORDER_LE:
+ fprintf(out, "H5T_ORDER_LE");
+ break;
+
+ case H5T_ORDER_BE:
+ fprintf(out, "H5T_ORDER_BE");
+ break;
+
+ case H5T_ORDER_VAX:
+ fprintf(out, "H5T_ORDER_VAX");
+ break;
+
+ case H5T_ORDER_MIXED:
+ fprintf(out, "H5T_ORDER_MIXED");
+ break;
+
+ case H5T_ORDER_NONE:
+ fprintf(out, "H5T_ORDER_NONE");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)order);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'p':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_pad_t pad = (H5T_pad_t)va_arg(ap, int);
+
+ switch(pad) {
+ case H5T_PAD_ERROR:
+ fprintf(out, "H5T_PAD_ERROR");
+ break;
+
+ case H5T_PAD_ZERO:
+ fprintf(out, "H5T_PAD_ZERO");
+ break;
+
+ case H5T_PAD_ONE:
+ fprintf(out, "H5T_PAD_ONE");
+ break;
+
+ case H5T_PAD_BACKGROUND:
+ fprintf(out, "H5T_PAD_BACKGROUND");
+ break;
+
+ case H5T_NPAD:
+ fprintf(out, "H5T_NPAD");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)pad);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_sign_t sign = (H5T_sign_t)va_arg(ap, int);
+
+ switch(sign) {
+ case H5T_SGN_ERROR:
+ fprintf(out, "H5T_SGN_ERROR");
+ break;
+
+ case H5T_SGN_NONE:
+ fprintf(out, "H5T_SGN_NONE");
+ break;
+
+ case H5T_SGN_2:
+ fprintf(out, "H5T_SGN_2");
+ break;
+
+ case H5T_NSGN:
+ fprintf(out, "H5T_NSGN");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)sign);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_class_t type_class = (H5T_class_t)va_arg(ap, int);
+
+ switch(type_class) {
+ case H5T_NO_CLASS:
+ fprintf(out, "H5T_NO_CLASS");
+ break;
+
+ case H5T_INTEGER:
+ fprintf(out, "H5T_INTEGER");
+ break;
+
+ case H5T_FLOAT:
+ fprintf(out, "H5T_FLOAT");
+ break;
+
+ case H5T_TIME:
+ fprintf(out, "H5T_TIME");
+ break;
+
+ case H5T_STRING:
+ fprintf(out, "H5T_STRING");
+ break;
+
+ case H5T_BITFIELD:
+ fprintf(out, "H5T_BITFIELD");
+ break;
+
+ case H5T_OPAQUE:
+ fprintf(out, "H5T_OPAQUE");
+ break;
+
+ case H5T_COMPOUND:
+ fprintf(out, "H5T_COMPOUND");
+ break;
+
+ case H5T_REFERENCE:
+ fprintf(out, "H5T_REFERENCE");
+ break;
+
+ case H5T_ENUM:
+ fprintf(out, "H5T_ENUM");
+ break;
+
+ case H5T_VLEN:
+ fprintf(out, "H5T_VLEN");
+ break;
+
+ case H5T_ARRAY:
+ fprintf(out, "H5T_ARRAY");
+ break;
+
+ case H5T_NCLASSES:
+ fprintf(out, "H5T_NCLASSES");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)type_class);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'z':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5T_str_t str = (H5T_str_t)va_arg(ap, int);
+
+ switch(str) {
+ case H5T_STR_ERROR:
+ fprintf(out, "H5T_STR_ERROR");
+ break;
+
+ case H5T_STR_NULLTERM:
+ fprintf(out, "H5T_STR_NULLTERM");
+ break;
+
+ case H5T_STR_NULLPAD:
+ fprintf(out, "H5T_STR_NULLPAD");
+ break;
+
+ case H5T_STR_SPACEPAD:
+ fprintf(out, "H5T_STR_SPACEPAD");
+ break;
+
+ case H5T_STR_RESERVED_3:
+ case H5T_STR_RESERVED_4:
+ case H5T_STR_RESERVED_5:
+ case H5T_STR_RESERVED_6:
+ case H5T_STR_RESERVED_7:
+ case H5T_STR_RESERVED_8:
+ case H5T_STR_RESERVED_9:
+ case H5T_STR_RESERVED_10:
+ case H5T_STR_RESERVED_11:
+ case H5T_STR_RESERVED_12:
+ case H5T_STR_RESERVED_13:
+ case H5T_STR_RESERVED_14:
+ case H5T_STR_RESERVED_15:
+ fprintf(out, "H5T_STR_RESERVED(%ld)",(long)str);
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)str);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ default:
+ fprintf (out, "BADTYPE(T%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 't':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ htri_t tri_var = va_arg (ap, htri_t);
+
+ if(tri_var>0)
+ fprintf (out, "TRUE");
+ else if(!tri_var)
+ fprintf (out, "FALSE");
+ else
+ fprintf(out, "FAIL(%d)", (int)tri_var);
+ } /* end else */
+ break;
+
+ case 'U':
+ switch(type[1]) {
+ case 'l':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ unsigned long *p = (unsigned long *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%lu", i?", ":"", p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ unsigned long iul = va_arg(ap, unsigned long); /*lint !e732 Loss of sign not really occuring */
+
+ fprintf(out, "%lu", iul);
+ asize[argno] = (hssize_t)iul;
+ } /* end else */
+ break;
+
+ case 'L':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ unsigned long long *p = (unsigned long long *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%llu", i?", ":"", p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ unsigned long long iull = va_arg(ap, unsigned long long); /*lint !e732 Loss of sign not really occuring */
+
+ fprintf(out, "%llu", iull);
+ asize[argno] = (hssize_t)iull;
+ } /* end else */
+ break;
+
+ default:
+ fprintf (out, "BADTYPE(U%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ case 'x':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ void **p = (void**)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++) {
+ if(p[i])
+ fprintf(out, "%s0x%lx", (i ? ", " : ""), (unsigned long)(p[i]));
+ else
+ fprintf(out, "%sNULL", (i ? ", " : ""));
+ } /* end for */
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ vp = va_arg (ap, void *); /*lint !e64 Type mismatch not really occuring */
+
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end else */
+ break;
+
+ case 'z':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ size_t *p = (size_t *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%Zu", (i ? ", " : ""), p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ size_t size = va_arg(ap, size_t); /*lint !e732 Loss of sign not really occuring */
+
+ HDfprintf(out, "%Zu", size);
+ asize[argno] = (hssize_t)size;
+ } /* end else */
+ break;
+
+ case 'Z':
+ switch (type[1]) {
+ case 'a':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5Z_SO_scale_type_t scale_type = (H5Z_SO_scale_type_t)va_arg(ap, int);
+
+ switch(scale_type) {
+ case H5Z_SO_FLOAT_DSCALE:
+ fprintf(out, "H5Z_SO_FLOAT_DSCALE");
+ break;
+
+ case H5Z_SO_FLOAT_ESCALE:
+ fprintf(out, "H5Z_SO_FLOAT_ESCALE");
+ break;
+
+ case H5Z_SO_INT:
+ fprintf(out, "H5Z_SO_INT");
+ break;
+
+ default:
+ fprintf(out, "%ld", (long)scale_type);
+ break;
+ } /* end switch */
+ } /* end else */
+ break;
+
+ case 'c':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5Z_class2_t *filter = va_arg(ap, H5Z_class2_t*); /*lint !e64 Type mismatch not really occuring */
+
+ fprintf(out, "0x%lx", (unsigned long)filter);
+ } /* end else */
+ break;
+
+ case 'e':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5Z_EDC_t edc = (H5Z_EDC_t)va_arg(ap, int);
+
+ if(H5Z_DISABLE_EDC == edc)
+ fprintf(out, "H5Z_DISABLE_EDC");
+ else if (H5Z_ENABLE_EDC == edc)
+ fprintf(out, "H5Z_ENABLE_EDC");
+ else
+ fprintf(out, "%ld", (long)edc);
+ } /* end else */
+ break;
+
+ case 'f':
+ if(ptr) {
+ if(vp)
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ H5Z_filter_t id = va_arg(ap, H5Z_filter_t);
+
+ if(H5Z_FILTER_DEFLATE == id)
+ fprintf(out, "H5Z_FILTER_DEFLATE");
+ else
+ fprintf(out, "%ld", (long)id);
+ } /* end else */
+ break;
+
+ case 's':
+ if(ptr) {
+ if(vp) {
+ fprintf(out, "0x%lx", (unsigned long)vp);
+ if(asize_idx >= 0 && asize[asize_idx] >= 0) {
+ ssize_t *p = (ssize_t *)vp;
+
+ fprintf(out, " {");
+ for(i = 0; i < asize[asize_idx]; i++)
+ HDfprintf(out, "%s%Zd", (i ? ", " : ""), p[i]);
+ fprintf(out, "}");
+ } /* end if */
+ } /* end if */
+ else
+ fprintf(out, "NULL");
+ } /* end if */
+ else {
+ ssize_t ssize = va_arg(ap, ssize_t);
+
+ HDfprintf(out, "%Zd", ssize);
+ asize[argno] = (hssize_t)ssize;
+ } /* end else */
+ break;
+
+ default:
+ fprintf(out, "BADTYPE(Z%c)", type[1]);
+ goto error;
+ } /* end switch */
+ break;
+
+ default:
+ if(HDisupper(type[0]))
+ fprintf(out, "BADTYPE(%c%c)", type[0], type[1]);
+ else
+ fprintf(out, "BADTYPE(%c)", type[0]);
+ goto error;
+ } /* end switch */
+ } /* end for */
+
+ /* Display event time for return */
+ if(returning && H5_debug_g.ttimes)
+ fprintf(out, " @%.6f [dt=%.6f]", (event_time.etime - first_time.etime),
+ (event_time.etime - *returning));
+
+error:
+ va_end(ap);
+ if(returning)
+ fprintf(out, ";\n");
+ else {
+ last_call_depth = current_depth++;
+ fprintf (out, ")");
+ } /* end else */
+ HDfflush(out);
+
+ return event_time.etime;
+} /* end H5_trace() */
+
diff --git a/src/H5vers.txt b/src/H5vers.txt
new file mode 100644
index 0000000..0303bf5
--- /dev/null
+++ b/src/H5vers.txt
@@ -0,0 +1,75 @@
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the COPYING file, which can be found at the root of the source code
+# distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
+# If you do not have access to either file, you may request a copy from
+# help@hdfgroup.org.
+#
+
+# This file is used to generate the various headers that are needed for
+# versioning the public symbols for the library.
+#
+# The bin/make_vers script reads in this file and creates the appropriate files
+# in the src/ directory when the generated headers are out of date with respect
+# to this file.
+#
+# Blank lines and lines beginning with '#' are ignored
+#
+# The format of this file is as follows:
+# <type>: <base routine name>; <list of parameter types for function>; <version introduced>, <list of revised versions>
+#
+# Where <type> is either 'FUNCTION' or 'TYPEDEF'
+#
+# For example, the following sample input shows two functions with different
+# API versions for each. The example below shows H5Gfoo being added to the
+# library in the v1.0 branch and revised in the v1.4 and v1.8 branches (so
+# there should be three versioned names for the routine: H5Gfoo1, H5Gfoo2 and
+# H5Gfoo3). H5Gbar is shown as being added to the library in the v1.2 branch
+# (so the "base" version of the API name wouldn't appear if the library
+# was configured with the default API interface corresponding to v1.0) and
+# revised in the v1.6 branch (so there should be two versioned names for the
+# routine: H5Gbar1 and H5Gbar2).
+#
+# FUNCTION: H5Gfoo; ; v10, v14, v18
+# FUNCTION: H5Gbar; ; v12, v16
+#
+# Programmer: Quincey Koziol
+# Creation Date: 2007/07/10
+
+# API function names
+# (although not required, it's easier to compare this file with the headers
+# generated if the list below is in alphanumeric sort order - QAK)
+FUNCTION: H5Acreate; ; v10, v18
+FUNCTION: H5Aiterate; H5A_operator; v10, v18
+FUNCTION: H5Dcreate; ; v10, v18
+FUNCTION: H5Dopen; ; v10, v18
+FUNCTION: H5Eclear; ; v10, v18
+FUNCTION: H5Eget_auto; ; v10, v18
+FUNCTION: H5Eprint; ; v10, v18
+FUNCTION: H5Epush; ; v14, v18
+FUNCTION: H5Eset_auto; ; v10, v18
+FUNCTION: H5Ewalk; H5E_walk, H5E_error; v10, v18
+FUNCTION: H5Fget_info; H5F_info; v18, v110
+FUNCTION: H5Gcreate; ; v10, v18
+FUNCTION: H5Gopen; ; v10, v18
+FUNCTION: H5Pget_filter; ; v10, v18
+FUNCTION: H5Pget_filter_by_id; ; v16, v18
+FUNCTION: H5Pinsert; ; v14, v18
+FUNCTION: H5Pregister; ; v14, v18
+FUNCTION: H5Rdereference; ; v10, v110
+FUNCTION: H5Rget_obj_type; ; v16, v18
+FUNCTION: H5Tarray_create; ; v14, v18
+FUNCTION: H5Tcommit; ; v10, v18
+FUNCTION: H5Tget_array_dims; ; v14, v18
+FUNCTION: H5Topen; ; v10, v18
+
+# API typedefs
+# (although not required, it's easier to compare this file with the headers
+# generated if the list below is in alphanumeric sort order - QAK)
+TYPEDEF: H5E_auto; v10, v18
+TYPEDEF: H5Z_class; v16, v18
+
diff --git a/src/H5version.h b/src/H5version.h
new file mode 100644
index 0000000..075274e
--- /dev/null
+++ b/src/H5version.h
@@ -0,0 +1,562 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Generated automatically by bin/make_vers -- do not edit */
+/* Add new versioned symbols to H5vers.txt file */
+
+
+#ifndef _H5version_H
+#define _H5version_H
+
+/* Issue error if contradicting macros have been defined. */
+#if (defined(H5_USE_16_API) || defined(H5_USE_18_API)) && defined(H5_NO_DEPRECATED_SYMBOLS)
+ #error "Can't choose old API versions when deprecated APIs are disabled"
+#endif /* (defined(H5_USE_16_API) || defined(H5_USE_18_API)) && defined(H5_NO_DEPRECATED_SYMBOLS) */
+
+
+/* If a particular "global" version of the library's interfaces is chosen,
+ * set the versions for the API symbols affected.
+ *
+ * Note: If an application has already chosen a particular version for an
+ * API symbol, the individual API version macro takes priority.
+ */
+#if defined(H5_USE_16_API_DEFAULT) && !defined(H5_USE_16_API)
+ #define H5_USE_16_API 1
+#endif /* H5_USE_16_API_DEFAULT && !H5_USE_16_API */
+
+#if defined(H5_USE_18_API_DEFAULT) && !defined(H5_USE_18_API)
+ #define H5_USE_18_API 1
+#endif /* H5_USE_18_API_DEFAULT && !H5_USE_18_API */
+
+
+#ifdef H5_USE_16_API
+
+/*************/
+/* Functions */
+/*************/
+
+#if !defined(H5Acreate_vers)
+ #define H5Acreate_vers 1
+#endif /* !defined(H5Acreate_vers) */
+
+#if !defined(H5Aiterate_vers)
+ #define H5Aiterate_vers 1
+#endif /* !defined(H5Aiterate_vers) */
+
+#if !defined(H5Dcreate_vers)
+ #define H5Dcreate_vers 1
+#endif /* !defined(H5Dcreate_vers) */
+
+#if !defined(H5Dopen_vers)
+ #define H5Dopen_vers 1
+#endif /* !defined(H5Dopen_vers) */
+
+#if !defined(H5Eclear_vers)
+ #define H5Eclear_vers 1
+#endif /* !defined(H5Eclear_vers) */
+
+#if !defined(H5Eget_auto_vers)
+ #define H5Eget_auto_vers 1
+#endif /* !defined(H5Eget_auto_vers) */
+
+#if !defined(H5Eprint_vers)
+ #define H5Eprint_vers 1
+#endif /* !defined(H5Eprint_vers) */
+
+#if !defined(H5Epush_vers)
+ #define H5Epush_vers 1
+#endif /* !defined(H5Epush_vers) */
+
+#if !defined(H5Eset_auto_vers)
+ #define H5Eset_auto_vers 1
+#endif /* !defined(H5Eset_auto_vers) */
+
+#if !defined(H5Ewalk_vers)
+ #define H5Ewalk_vers 1
+#endif /* !defined(H5Ewalk_vers) */
+
+#if !defined(H5Gcreate_vers)
+ #define H5Gcreate_vers 1
+#endif /* !defined(H5Gcreate_vers) */
+
+#if !defined(H5Gopen_vers)
+ #define H5Gopen_vers 1
+#endif /* !defined(H5Gopen_vers) */
+
+#if !defined(H5Pget_filter_vers)
+ #define H5Pget_filter_vers 1
+#endif /* !defined(H5Pget_filter_vers) */
+
+#if !defined(H5Pget_filter_by_id_vers)
+ #define H5Pget_filter_by_id_vers 1
+#endif /* !defined(H5Pget_filter_by_id_vers) */
+
+#if !defined(H5Pinsert_vers)
+ #define H5Pinsert_vers 1
+#endif /* !defined(H5Pinsert_vers) */
+
+#if !defined(H5Pregister_vers)
+ #define H5Pregister_vers 1
+#endif /* !defined(H5Pregister_vers) */
+
+#if !defined(H5Rdereference_vers)
+ #define H5Rdereference_vers 1
+#endif /* !defined(H5Rdereference_vers) */
+
+#if !defined(H5Rget_obj_type_vers)
+ #define H5Rget_obj_type_vers 1
+#endif /* !defined(H5Rget_obj_type_vers) */
+
+#if !defined(H5Tarray_create_vers)
+ #define H5Tarray_create_vers 1
+#endif /* !defined(H5Tarray_create_vers) */
+
+#if !defined(H5Tcommit_vers)
+ #define H5Tcommit_vers 1
+#endif /* !defined(H5Tcommit_vers) */
+
+#if !defined(H5Tget_array_dims_vers)
+ #define H5Tget_array_dims_vers 1
+#endif /* !defined(H5Tget_array_dims_vers) */
+
+#if !defined(H5Topen_vers)
+ #define H5Topen_vers 1
+#endif /* !defined(H5Topen_vers) */
+
+/************/
+/* Typedefs */
+/************/
+
+#if !defined(H5E_auto_t_vers)
+ #define H5E_auto_t_vers 1
+#endif /* !defined(H5E_auto_t_vers) */
+
+#if !defined(H5Z_class_t_vers)
+ #define H5Z_class_t_vers 1
+#endif /* !defined(H5Z_class_t_vers) */
+
+#endif /* H5_USE_16_API */
+
+#ifdef H5_USE_18_API
+
+/*************/
+/* Functions */
+/*************/
+
+#if !defined(H5Acreate_vers)
+ #define H5Acreate_vers 2
+#endif /* !defined(H5Acreate_vers) */
+
+#if !defined(H5Aiterate_vers)
+ #define H5Aiterate_vers 2
+#endif /* !defined(H5Aiterate_vers) */
+
+#if !defined(H5Dcreate_vers)
+ #define H5Dcreate_vers 2
+#endif /* !defined(H5Dcreate_vers) */
+
+#if !defined(H5Dopen_vers)
+ #define H5Dopen_vers 2
+#endif /* !defined(H5Dopen_vers) */
+
+#if !defined(H5Eclear_vers)
+ #define H5Eclear_vers 2
+#endif /* !defined(H5Eclear_vers) */
+
+#if !defined(H5Eget_auto_vers)
+ #define H5Eget_auto_vers 2
+#endif /* !defined(H5Eget_auto_vers) */
+
+#if !defined(H5Eprint_vers)
+ #define H5Eprint_vers 2
+#endif /* !defined(H5Eprint_vers) */
+
+#if !defined(H5Epush_vers)
+ #define H5Epush_vers 2
+#endif /* !defined(H5Epush_vers) */
+
+#if !defined(H5Eset_auto_vers)
+ #define H5Eset_auto_vers 2
+#endif /* !defined(H5Eset_auto_vers) */
+
+#if !defined(H5Ewalk_vers)
+ #define H5Ewalk_vers 2
+#endif /* !defined(H5Ewalk_vers) */
+
+#if !defined(H5Fget_info_vers)
+ #define H5Fget_info_vers 1
+#endif /* !defined(H5Fget_info_vers) */
+
+#if !defined(H5Gcreate_vers)
+ #define H5Gcreate_vers 2
+#endif /* !defined(H5Gcreate_vers) */
+
+#if !defined(H5Gopen_vers)
+ #define H5Gopen_vers 2
+#endif /* !defined(H5Gopen_vers) */
+
+#if !defined(H5Pget_filter_vers)
+ #define H5Pget_filter_vers 2
+#endif /* !defined(H5Pget_filter_vers) */
+
+#if !defined(H5Pget_filter_by_id_vers)
+ #define H5Pget_filter_by_id_vers 2
+#endif /* !defined(H5Pget_filter_by_id_vers) */
+
+#if !defined(H5Pinsert_vers)
+ #define H5Pinsert_vers 2
+#endif /* !defined(H5Pinsert_vers) */
+
+#if !defined(H5Pregister_vers)
+ #define H5Pregister_vers 2
+#endif /* !defined(H5Pregister_vers) */
+
+#if !defined(H5Rdereference_vers)
+ #define H5Rdereference_vers 1
+#endif /* !defined(H5Rdereference_vers) */
+
+#if !defined(H5Rget_obj_type_vers)
+ #define H5Rget_obj_type_vers 2
+#endif /* !defined(H5Rget_obj_type_vers) */
+
+#if !defined(H5Tarray_create_vers)
+ #define H5Tarray_create_vers 2
+#endif /* !defined(H5Tarray_create_vers) */
+
+#if !defined(H5Tcommit_vers)
+ #define H5Tcommit_vers 2
+#endif /* !defined(H5Tcommit_vers) */
+
+#if !defined(H5Tget_array_dims_vers)
+ #define H5Tget_array_dims_vers 2
+#endif /* !defined(H5Tget_array_dims_vers) */
+
+#if !defined(H5Topen_vers)
+ #define H5Topen_vers 2
+#endif /* !defined(H5Topen_vers) */
+
+/************/
+/* Typedefs */
+/************/
+
+#if !defined(H5E_auto_t_vers)
+ #define H5E_auto_t_vers 2
+#endif /* !defined(H5E_auto_t_vers) */
+
+#if !defined(H5Z_class_t_vers)
+ #define H5Z_class_t_vers 2
+#endif /* !defined(H5Z_class_t_vers) */
+
+#endif /* H5_USE_18_API */
+
+
+/* Choose the correct version of each API symbol, defaulting to the latest
+ * version of each. The "best" name for API parameters/data structures
+ * that have changed definitions is also set. An error is issued for
+ * specifying an invalid API version.
+ */
+
+/*************/
+/* Functions */
+/*************/
+
+#if !defined(H5Acreate_vers) || H5Acreate_vers == 2
+ #ifndef H5Acreate_vers
+ #define H5Acreate_vers 2
+ #endif /* H5Acreate_vers */
+ #define H5Acreate H5Acreate2
+#elif H5Acreate_vers == 1
+ #define H5Acreate H5Acreate1
+#else /* H5Acreate_vers */
+ #error "H5Acreate_vers set to invalid value"
+#endif /* H5Acreate_vers */
+
+#if !defined(H5Aiterate_vers) || H5Aiterate_vers == 2
+ #ifndef H5Aiterate_vers
+ #define H5Aiterate_vers 2
+ #endif /* H5Aiterate_vers */
+ #define H5Aiterate H5Aiterate2
+ #define H5A_operator_t H5A_operator2_t
+#elif H5Aiterate_vers == 1
+ #define H5Aiterate H5Aiterate1
+ #define H5A_operator_t H5A_operator1_t
+#else /* H5Aiterate_vers */
+ #error "H5Aiterate_vers set to invalid value"
+#endif /* H5Aiterate_vers */
+
+#if !defined(H5Dcreate_vers) || H5Dcreate_vers == 2
+ #ifndef H5Dcreate_vers
+ #define H5Dcreate_vers 2
+ #endif /* H5Dcreate_vers */
+ #define H5Dcreate H5Dcreate2
+#elif H5Dcreate_vers == 1
+ #define H5Dcreate H5Dcreate1
+#else /* H5Dcreate_vers */
+ #error "H5Dcreate_vers set to invalid value"
+#endif /* H5Dcreate_vers */
+
+#if !defined(H5Dopen_vers) || H5Dopen_vers == 2
+ #ifndef H5Dopen_vers
+ #define H5Dopen_vers 2
+ #endif /* H5Dopen_vers */
+ #define H5Dopen H5Dopen2
+#elif H5Dopen_vers == 1
+ #define H5Dopen H5Dopen1
+#else /* H5Dopen_vers */
+ #error "H5Dopen_vers set to invalid value"
+#endif /* H5Dopen_vers */
+
+#if !defined(H5Eclear_vers) || H5Eclear_vers == 2
+ #ifndef H5Eclear_vers
+ #define H5Eclear_vers 2
+ #endif /* H5Eclear_vers */
+ #define H5Eclear H5Eclear2
+#elif H5Eclear_vers == 1
+ #define H5Eclear H5Eclear1
+#else /* H5Eclear_vers */
+ #error "H5Eclear_vers set to invalid value"
+#endif /* H5Eclear_vers */
+
+#if !defined(H5Eget_auto_vers) || H5Eget_auto_vers == 2
+ #ifndef H5Eget_auto_vers
+ #define H5Eget_auto_vers 2
+ #endif /* H5Eget_auto_vers */
+ #define H5Eget_auto H5Eget_auto2
+#elif H5Eget_auto_vers == 1
+ #define H5Eget_auto H5Eget_auto1
+#else /* H5Eget_auto_vers */
+ #error "H5Eget_auto_vers set to invalid value"
+#endif /* H5Eget_auto_vers */
+
+#if !defined(H5Eprint_vers) || H5Eprint_vers == 2
+ #ifndef H5Eprint_vers
+ #define H5Eprint_vers 2
+ #endif /* H5Eprint_vers */
+ #define H5Eprint H5Eprint2
+#elif H5Eprint_vers == 1
+ #define H5Eprint H5Eprint1
+#else /* H5Eprint_vers */
+ #error "H5Eprint_vers set to invalid value"
+#endif /* H5Eprint_vers */
+
+#if !defined(H5Epush_vers) || H5Epush_vers == 2
+ #ifndef H5Epush_vers
+ #define H5Epush_vers 2
+ #endif /* H5Epush_vers */
+ #define H5Epush H5Epush2
+#elif H5Epush_vers == 1
+ #define H5Epush H5Epush1
+#else /* H5Epush_vers */
+ #error "H5Epush_vers set to invalid value"
+#endif /* H5Epush_vers */
+
+#if !defined(H5Eset_auto_vers) || H5Eset_auto_vers == 2
+ #ifndef H5Eset_auto_vers
+ #define H5Eset_auto_vers 2
+ #endif /* H5Eset_auto_vers */
+ #define H5Eset_auto H5Eset_auto2
+#elif H5Eset_auto_vers == 1
+ #define H5Eset_auto H5Eset_auto1
+#else /* H5Eset_auto_vers */
+ #error "H5Eset_auto_vers set to invalid value"
+#endif /* H5Eset_auto_vers */
+
+#if !defined(H5Ewalk_vers) || H5Ewalk_vers == 2
+ #ifndef H5Ewalk_vers
+ #define H5Ewalk_vers 2
+ #endif /* H5Ewalk_vers */
+ #define H5Ewalk H5Ewalk2
+ #define H5E_error_t H5E_error2_t
+ #define H5E_walk_t H5E_walk2_t
+#elif H5Ewalk_vers == 1
+ #define H5Ewalk H5Ewalk1
+ #define H5E_error_t H5E_error1_t
+ #define H5E_walk_t H5E_walk1_t
+#else /* H5Ewalk_vers */
+ #error "H5Ewalk_vers set to invalid value"
+#endif /* H5Ewalk_vers */
+
+#if !defined(H5Fget_info_vers) || H5Fget_info_vers == 2
+ #ifndef H5Fget_info_vers
+ #define H5Fget_info_vers 2
+ #endif /* H5Fget_info_vers */
+ #define H5Fget_info H5Fget_info2
+ #define H5F_info_t H5F_info2_t
+#elif H5Fget_info_vers == 1
+ #define H5Fget_info H5Fget_info1
+ #define H5F_info_t H5F_info1_t
+#else /* H5Fget_info_vers */
+ #error "H5Fget_info_vers set to invalid value"
+#endif /* H5Fget_info_vers */
+
+#if !defined(H5Gcreate_vers) || H5Gcreate_vers == 2
+ #ifndef H5Gcreate_vers
+ #define H5Gcreate_vers 2
+ #endif /* H5Gcreate_vers */
+ #define H5Gcreate H5Gcreate2
+#elif H5Gcreate_vers == 1
+ #define H5Gcreate H5Gcreate1
+#else /* H5Gcreate_vers */
+ #error "H5Gcreate_vers set to invalid value"
+#endif /* H5Gcreate_vers */
+
+#if !defined(H5Gopen_vers) || H5Gopen_vers == 2
+ #ifndef H5Gopen_vers
+ #define H5Gopen_vers 2
+ #endif /* H5Gopen_vers */
+ #define H5Gopen H5Gopen2
+#elif H5Gopen_vers == 1
+ #define H5Gopen H5Gopen1
+#else /* H5Gopen_vers */
+ #error "H5Gopen_vers set to invalid value"
+#endif /* H5Gopen_vers */
+
+#if !defined(H5Pget_filter_vers) || H5Pget_filter_vers == 2
+ #ifndef H5Pget_filter_vers
+ #define H5Pget_filter_vers 2
+ #endif /* H5Pget_filter_vers */
+ #define H5Pget_filter H5Pget_filter2
+#elif H5Pget_filter_vers == 1
+ #define H5Pget_filter H5Pget_filter1
+#else /* H5Pget_filter_vers */
+ #error "H5Pget_filter_vers set to invalid value"
+#endif /* H5Pget_filter_vers */
+
+#if !defined(H5Pget_filter_by_id_vers) || H5Pget_filter_by_id_vers == 2
+ #ifndef H5Pget_filter_by_id_vers
+ #define H5Pget_filter_by_id_vers 2
+ #endif /* H5Pget_filter_by_id_vers */
+ #define H5Pget_filter_by_id H5Pget_filter_by_id2
+#elif H5Pget_filter_by_id_vers == 1
+ #define H5Pget_filter_by_id H5Pget_filter_by_id1
+#else /* H5Pget_filter_by_id_vers */
+ #error "H5Pget_filter_by_id_vers set to invalid value"
+#endif /* H5Pget_filter_by_id_vers */
+
+#if !defined(H5Pinsert_vers) || H5Pinsert_vers == 2
+ #ifndef H5Pinsert_vers
+ #define H5Pinsert_vers 2
+ #endif /* H5Pinsert_vers */
+ #define H5Pinsert H5Pinsert2
+#elif H5Pinsert_vers == 1
+ #define H5Pinsert H5Pinsert1
+#else /* H5Pinsert_vers */
+ #error "H5Pinsert_vers set to invalid value"
+#endif /* H5Pinsert_vers */
+
+#if !defined(H5Pregister_vers) || H5Pregister_vers == 2
+ #ifndef H5Pregister_vers
+ #define H5Pregister_vers 2
+ #endif /* H5Pregister_vers */
+ #define H5Pregister H5Pregister2
+#elif H5Pregister_vers == 1
+ #define H5Pregister H5Pregister1
+#else /* H5Pregister_vers */
+ #error "H5Pregister_vers set to invalid value"
+#endif /* H5Pregister_vers */
+
+#if !defined(H5Rdereference_vers) || H5Rdereference_vers == 2
+ #ifndef H5Rdereference_vers
+ #define H5Rdereference_vers 2
+ #endif /* H5Rdereference_vers */
+ #define H5Rdereference H5Rdereference2
+#elif H5Rdereference_vers == 1
+ #define H5Rdereference H5Rdereference1
+#else /* H5Rdereference_vers */
+ #error "H5Rdereference_vers set to invalid value"
+#endif /* H5Rdereference_vers */
+
+#if !defined(H5Rget_obj_type_vers) || H5Rget_obj_type_vers == 2
+ #ifndef H5Rget_obj_type_vers
+ #define H5Rget_obj_type_vers 2
+ #endif /* H5Rget_obj_type_vers */
+ #define H5Rget_obj_type H5Rget_obj_type2
+#elif H5Rget_obj_type_vers == 1
+ #define H5Rget_obj_type H5Rget_obj_type1
+#else /* H5Rget_obj_type_vers */
+ #error "H5Rget_obj_type_vers set to invalid value"
+#endif /* H5Rget_obj_type_vers */
+
+#if !defined(H5Tarray_create_vers) || H5Tarray_create_vers == 2
+ #ifndef H5Tarray_create_vers
+ #define H5Tarray_create_vers 2
+ #endif /* H5Tarray_create_vers */
+ #define H5Tarray_create H5Tarray_create2
+#elif H5Tarray_create_vers == 1
+ #define H5Tarray_create H5Tarray_create1
+#else /* H5Tarray_create_vers */
+ #error "H5Tarray_create_vers set to invalid value"
+#endif /* H5Tarray_create_vers */
+
+#if !defined(H5Tcommit_vers) || H5Tcommit_vers == 2
+ #ifndef H5Tcommit_vers
+ #define H5Tcommit_vers 2
+ #endif /* H5Tcommit_vers */
+ #define H5Tcommit H5Tcommit2
+#elif H5Tcommit_vers == 1
+ #define H5Tcommit H5Tcommit1
+#else /* H5Tcommit_vers */
+ #error "H5Tcommit_vers set to invalid value"
+#endif /* H5Tcommit_vers */
+
+#if !defined(H5Tget_array_dims_vers) || H5Tget_array_dims_vers == 2
+ #ifndef H5Tget_array_dims_vers
+ #define H5Tget_array_dims_vers 2
+ #endif /* H5Tget_array_dims_vers */
+ #define H5Tget_array_dims H5Tget_array_dims2
+#elif H5Tget_array_dims_vers == 1
+ #define H5Tget_array_dims H5Tget_array_dims1
+#else /* H5Tget_array_dims_vers */
+ #error "H5Tget_array_dims_vers set to invalid value"
+#endif /* H5Tget_array_dims_vers */
+
+#if !defined(H5Topen_vers) || H5Topen_vers == 2
+ #ifndef H5Topen_vers
+ #define H5Topen_vers 2
+ #endif /* H5Topen_vers */
+ #define H5Topen H5Topen2
+#elif H5Topen_vers == 1
+ #define H5Topen H5Topen1
+#else /* H5Topen_vers */
+ #error "H5Topen_vers set to invalid value"
+#endif /* H5Topen_vers */
+
+/************/
+/* Typedefs */
+/************/
+
+#if !defined(H5E_auto_t_vers) || H5E_auto_t_vers == 2
+ #ifndef H5E_auto_t_vers
+ #define H5E_auto_t_vers 2
+ #endif /* H5E_auto_t_vers */
+ #define H5E_auto_t H5E_auto2_t
+#elif H5E_auto_t_vers == 1
+ #define H5E_auto_t H5E_auto1_t
+#else /* H5E_auto_t_vers */
+ #error "H5E_auto_t_vers set to invalid value"
+#endif /* H5E_auto_t_vers */
+
+
+#if !defined(H5Z_class_t_vers) || H5Z_class_t_vers == 2
+ #ifndef H5Z_class_t_vers
+ #define H5Z_class_t_vers 2
+ #endif /* H5Z_class_t_vers */
+ #define H5Z_class_t H5Z_class2_t
+#elif H5Z_class_t_vers == 1
+ #define H5Z_class_t H5Z_class1_t
+#else /* H5Z_class_t_vers */
+ #error "H5Z_class_t_vers set to invalid value"
+#endif /* H5Z_class_t_vers */
+
+#endif /* H5version_H */
+
diff --git a/src/H5win32defs.h b/src/H5win32defs.h
new file mode 100644
index 0000000..0149faa
--- /dev/null
+++ b/src/H5win32defs.h
@@ -0,0 +1,153 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Scott Wegner
+ * June 3, 2008
+ *
+ * Purpose: This file is used to map HDF macros to Windows functions. This
+ * should get included H5private mappings, so as to override them.
+ * Any macro not mapped here, however, will receive a similar mapping
+ * inside H5private.h
+ *
+ */
+
+/*
+ * _MSC_VER = 1900 VS2015
+ * _MSC_VER = 1800 VS2013
+ * _MSC_VER = 1700 VS2012
+ */
+#ifdef H5_HAVE_WIN32_API
+
+typedef struct _stati64 h5_stat_t;
+typedef __int64 h5_stat_size_t;
+
+#define HDaccess(F,M) _access(F,M)
+#define HDchdir(S) _chdir(S)
+#define HDclose(F) _close(F)
+#define HDdup(F) _dup(F)
+#define HDfdopen(N,S) _fdopen(N,S)
+#define HDfileno(F) _fileno(F)
+#define HDfstat(F,B) _fstati64(F,B)
+#define HDisatty(F) _isatty(F)
+#define HDgetcwd(S,Z) _getcwd(S,Z)
+#define HDgetdcwd(D,S,Z) _getdcwd(D,S,Z)
+#define HDgetdrive() _getdrive()
+#define HDlseek(F,O,W) _lseeki64(F,O,W)
+#define HDlstat(S,B) _lstati64(S,B)
+#define HDmkdir(S,M) _mkdir(S)
+#define HDnanosleep(N, O) Wnanosleep(N, O)
+#define HDoff_t __int64
+/* _O_BINARY must be set in Windows to avoid CR-LF <-> LF EOL
+ * transformations when performing I/O.
+ */
+#define HDopen(S,F,M) _open(S,F|_O_BINARY,M)
+#define HDread(F,M,Z) _read(F,M,Z)
+#define HDrmdir(S) _rmdir(S)
+#define HDsetvbuf(F,S,M,Z) setvbuf(F,S,M,(Z>1?Z:2))
+#define HDsleep(S) Sleep(S*1000)
+#define HDstat(S,B) _stati64(S,B)
+#define HDstrcasecmp(A,B) _stricmp(A,B)
+#define HDstrdup(S) _strdup(S)
+#define HDtzset() _tzset()
+#define HDunlink(S) _unlink(S)
+#define HDwrite(F,M,Z) _write(F,M,Z)
+
+#ifdef H5_HAVE_VISUAL_STUDIO
+
+#if (_MSC_VER < 1800)
+ #ifndef H5_HAVE_STRTOLL
+ #define HDstrtoll(S,R,N) _strtoi64(S,R,N)
+ #endif /* H5_HAVE_STRTOLL */
+ #ifndef H5_HAVE_STRTOULL
+ #define HDstrtoull(S,R,N) _strtoui64(S,R,N)
+ #endif /* H5_HAVE_STRTOULL */
+#endif /* MSC_VER < 1800 */
+
+/*
+ * The (void*) cast just avoids a compiler warning in H5_HAVE_VISUAL_STUDIO
+ */
+#define HDmemset(X,C,Z) memset((void*)(X),C,Z)
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+/* time.h before VS2015 does not include timespec */
+#if (_MSC_VER < 1900)
+struct timespec
+{
+ time_t tv_sec; /* Seconds - >= 0 */
+ long tv_nsec; /* Nanoseconds - [0, 999999999] */
+};
+#endif /* MSC_VER < 1900 */
+
+/* The round functions do not exist in VS2012 and earlier */
+#if (_MSC_VER <= 1700)
+#define HDllround(V) Wllround(V)
+#define HDllroundf(V) Wllroundf(V)
+#define HDlround(V) Wlround(V)
+#define HDlroundf(V) Wlroundf(V)
+#define HDround(V) Wround(V)
+#define HDroundf(V) Wroundf(V)
+#endif /* MSC_VER < 1700 */
+
+#endif /* H5_HAVE_VISUAL_STUDIO */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+ H5_DLL int Wgettimeofday(struct timeval *tv, struct timezone *tz);
+ H5_DLL int Wsetenv(const char *name, const char *value, int overwrite);
+ H5_DLL int Wflock(int fd, int operation);
+ H5_DLL char* Wgetlogin(void);
+ H5_DLL int c99_snprintf(char* str, size_t size, const char* format, ...);
+ H5_DLL int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap);
+ H5_DLL int Wnanosleep(const struct timespec *req, struct timespec *rem);
+
+ /* Round functions only needed for VS2012 and earlier.
+ * They are always built to ensure they don't go stale and
+ * can be deleted (along with their #defines, above) when we
+ * drop VS2012 support.
+ */
+ H5_DLL long long Wllround(double arg);
+ H5_DLL long long Wllroundf(float arg);
+ H5_DLL long Wlround(double arg);
+ H5_DLL long Wlroundf(float arg);
+ H5_DLL double Wround(double arg);
+ H5_DLL float Wroundf(float arg);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define HDgettimeofday(V,Z) Wgettimeofday(V,Z)
+#define HDsetenv(N,V,O) Wsetenv(N,V,O)
+#define HDflock(F,L) Wflock(F,L)
+#define HDgetlogin() Wgetlogin()
+#define HDsnprintf c99_snprintf /*varargs*/
+#define HDvsnprintf c99_vsnprintf /*varargs*/
+
+/* Non-POSIX functions */
+
+/* Don't use actual pthread_self on Windows because the return
+ * type cannot be cast as a ulong like other systems. */
+#define HDpthread_self_ulong() ((unsigned long)GetCurrentThreadId())
+
+#ifndef H5_HAVE_MINGW
+#define HDftruncate(F,L) _chsize_s(F,L)
+#define HDfseek(F,O,W) _fseeki64(F,O,W)
+#endif /* H5_HAVE_MINGW */
+
+#endif /* H5_HAVE_WIN32_API */
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..0b664a7
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,205 @@
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the COPYING file, which can be found at the root of the source code
+# distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
+# If you do not have access to either file, you may request a copy from
+# help@hdfgroup.org.
+##
+## Makefile.am
+## Run automake to generate a Makefile.in from this file.
+#
+# HDF5 Library Makefile(.in)
+#
+
+include $(top_srcdir)/config/commence.am
+include $(top_srcdir)/config/lt_vers.am
+
+
+# How to build H5detect for number format detection.
+# Use -g to force no optimization since many compilers (e.g., Intel) takes
+# a long time to compile it with any optimization on. H5detect is used
+# to generate H5Tinit.c once. So, optimization is not critical.
+noinst_PROGRAMS = H5detect H5make_libsettings
+
+# Our main target, the HDF5 library
+lib_LTLIBRARIES=libhdf5.la
+
+# Add libtool numbers to the HDF5 library (from config/lt_vers.am)
+libhdf5_la_LDFLAGS= -version-info $(LT_VERS_INTERFACE):$(LT_VERS_REVISION):$(LT_VERS_AGE) $(AM_LDFLAGS)
+
+# H5Tinit.c and H5lib_settings.c are generated files and should be cleaned.
+MOSTLYCLEANFILES=H5Tinit.c H5lib_settings.c
+# H5pubconf.h is generated by configure, and should be cleaned.
+DISTCLEANFILES=H5pubconf.h
+
+# library sources
+libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \
+ H5A.c H5Abtree2.c H5Adense.c H5Adeprec.c H5Aint.c H5Atest.c \
+ H5AC.c H5ACdbg.c H5AClog.c H5ACproxy_entry.c \
+ H5B.c H5Bcache.c H5Bdbg.c \
+ H5B2.c H5B2cache.c H5B2dbg.c H5B2hdr.c H5B2int.c H5B2internal.c \
+ H5B2leaf.c H5B2stat.c H5B2test.c \
+ H5C.c H5Cdbg.c H5Cepoch.c H5Cimage.c H5Clog.c H5Cprefetched.c \
+ H5Cquery.c H5Ctag.c H5Ctest.c \
+ H5CS.c \
+ H5D.c H5Dbtree.c H5Dbtree2.c H5Dchunk.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \
+ H5Ddeprec.c H5Dearray.c H5Defl.c H5Dfarray.c H5Dfill.c H5Dint.c \
+ H5Dio.c H5Dlayout.c H5Dnone.c \
+ H5Doh.c H5Dscatgath.c H5Dselect.c \
+ H5Dsingle.c H5Dtest.c H5Dvirtual.c \
+ H5E.c H5Edeprec.c H5Eint.c \
+ H5EA.c H5EAcache.c H5EAdbg.c H5EAdblkpage.c H5EAdblock.c H5EAhdr.c \
+ H5EAiblock.c H5EAint.c H5EAsblock.c H5EAstat.c H5EAtest.c \
+ H5F.c H5Fint.c H5Faccum.c H5Fcwfs.c \
+ H5Fdbg.c H5Fdeprec.c H5Fefc.c H5Ffake.c H5Fio.c \
+ H5Fmount.c H5Fquery.c \
+ H5Fsfile.c H5Fspace.c H5Fsuper.c H5Fsuper_cache.c H5Ftest.c \
+ H5FA.c H5FAcache.c H5FAdbg.c H5FAdblock.c H5FAdblkpage.c H5FAhdr.c \
+ H5FAint.c H5FAstat.c H5FAtest.c \
+ H5FD.c H5FDcore.c \
+ H5FDfamily.c H5FDint.c H5FDlog.c \
+ H5FDmulti.c H5FDsec2.c H5FDspace.c H5FDstdio.c H5FDtest.c \
+ H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c H5FSsection.c \
+ H5FSstat.c H5FStest.c \
+ H5G.c H5Gbtree2.c H5Gcache.c \
+ H5Gcompact.c H5Gdense.c H5Gdeprec.c H5Gent.c \
+ H5Gint.c H5Glink.c \
+ H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c H5Goh.c H5Groot.c H5Gstab.c H5Gtest.c \
+ H5Gtraverse.c \
+ H5HF.c H5HFbtree2.c H5HFcache.c H5HFdbg.c H5HFdblock.c H5HFdtable.c \
+ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c H5HFsection.c \
+ H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \
+ H5HG.c H5HGcache.c H5HGdbg.c H5HGquery.c \
+ H5HL.c H5HLcache.c H5HLdbg.c H5HLint.c H5HLprfx.c H5HLdblk.c\
+ H5HP.c H5I.c H5Itest.c H5L.c H5Lexternal.c H5lib_settings.c \
+ H5MF.c H5MFaggr.c H5MFdbg.c H5MFsection.c \
+ H5MM.c H5MP.c H5MPtest.c \
+ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \
+ H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ocache_image.c \
+ H5Ochunk.c \
+ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \
+ H5Ofill.c H5Oflush.c H5Ofsinfo.c H5Oginfo.c \
+ H5Olayout.c \
+ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \
+ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \
+ H5Osdspace.c H5Oshared.c \
+ H5Oshmesg.c \
+ H5Ostab.c \
+ H5Otest.c H5Ounknown.c \
+ H5P.c H5Pacpl.c H5Pdapl.c H5Pdcpl.c \
+ H5Pdeprec.c H5Pdxpl.c H5Pencdec.c \
+ H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \
+ H5Pgcpl.c H5Pint.c \
+ H5Plapl.c H5Plcpl.c H5Pocpl.c H5Pocpypl.c H5Pstrcpl.c H5Ptest.c \
+ H5PB.c \
+ H5PL.c \
+ H5R.c H5Rdeprec.c \
+ H5UC.c \
+ H5RS.c \
+ H5S.c H5Sall.c H5Sdbg.c H5Shyper.c H5Snone.c H5Spoint.c \
+ H5Sselect.c H5Stest.c \
+ H5SL.c \
+ H5SM.c H5SMbtree2.c H5SMcache.c H5SMmessage.c H5SMtest.c \
+ H5ST.c \
+ H5T.c H5Tarray.c H5Tbit.c H5Tcommit.c H5Tcompound.c H5Tconv.c \
+ H5Tcset.c H5Tdbg.c H5Tdeprec.c H5Tenum.c H5Tfields.c \
+ H5Tfixed.c \
+ H5Tfloat.c H5Tinit.c H5Tnative.c H5Toffset.c H5Toh.c \
+ H5Topaque.c \
+ H5Torder.c \
+ H5Tpad.c H5Tprecis.c H5Tstrpad.c H5Tvisit.c H5Tvlen.c H5TS.c H5VM.c H5WB.c H5Z.c \
+ H5Zdeflate.c H5Zfletcher32.c H5Znbit.c H5Zshuffle.c \
+ H5Zscaleoffset.c H5Zszip.c H5Ztrans.c
+
+# Only compile parallel sources if necessary
+if BUILD_PARALLEL_CONDITIONAL
+ libhdf5_la_SOURCES += H5ACmpio.c H5Cmpio.c H5Dmpio.c H5Fmpi.c H5FDmpi.c H5FDmpio.c H5Smpio.c
+endif
+
+# Only compile the direct VFD if necessary
+if DIRECT_VFD_CONDITIONAL
+ libhdf5_la_SOURCES += H5FDdirect.c
+endif
+
+# Public headers
+include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5version.h \
+ H5Apublic.h H5ACpublic.h \
+ H5Cpublic.h H5Dpublic.h \
+ H5Epubgen.h H5Epublic.h H5Fpublic.h \
+ H5FDpublic.h H5FDcore.h H5FDdirect.h \
+ H5FDfamily.h H5FDlog.h H5FDmpi.h H5FDmpio.h \
+ H5FDmulti.h H5FDsec2.h H5FDstdio.h \
+ H5Gpublic.h H5Ipublic.h H5Lpublic.h \
+ H5MMpublic.h H5Opublic.h H5Ppublic.h \
+ H5PLextern.h H5PLpublic.h \
+ H5Rpublic.h H5Spublic.h \
+ H5Tpublic.h H5Zpublic.h
+
+# install libhdf5.settings in lib directory
+settingsdir=$(libdir)
+settings_DATA=libhdf5.settings
+
+# Number format detection
+# The LD_LIBRARY_PATH setting is a kludge.
+# Things should have been all set during H5detect making.
+# Remove the generated .c file if errors occur unless HDF5_Make_Ignore
+# is set to ignore the error.
+H5Tinit.c: H5detect$(EXEEXT)
+ LD_LIBRARY_PATH="$$LD_LIBRARY_PATH`echo $(LDFLAGS) | \
+ sed -e 's/-L/:/g' -e 's/ //g'`" \
+ $(RUNSERIAL) ./H5detect$(EXEEXT) > $@ || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ ($(RM) $@ ; exit 1)
+
+# Build configuration header file generation
+# The LD_LIBRARY_PATH setting is a kludge.
+# Things should have been all set during H5make_libsettings making.
+# Remove the generated .c file if errors occur unless HDF5_Make_Ignore
+# is set to ignore the error.
+H5lib_settings.c: H5make_libsettings$(EXEEXT) libhdf5.settings
+ LD_LIBRARY_PATH="$$LD_LIBRARY_PATH`echo $(LDFLAGS) | \
+ sed -e 's/-L/:/g' -e 's/ //g'`" \
+ $(RUNSERIAL) ./H5make_libsettings$(EXEEXT) > $@ || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ ($(RM) $@ ; exit 1)
+
+# Error header generation
+#
+# Actually, H5Einit.h, H5Eterm.h, H5Edefin.h and H5Epubgen.h all
+# depend on H5err.txt, but the perl script generates them all, so just
+# list one here.
+$(top_srcdir)/src/H5Edefin.h: $(top_srcdir)/src/H5err.txt
+ perl $(top_srcdir)/bin/make_err $?
+
+# API version macro generation
+$(top_srcdir)/src/H5version.h: $(top_srcdir)/src/H5vers.txt
+ perl $(top_srcdir)/bin/make_vers $?
+
+# Assignment overflow macro generation
+$(top_srcdir)/src/H5overflow.h: $(top_srcdir)/src/H5overflow.txt
+ perl $(top_srcdir)/bin/make_overflow $?
+
+# Add TRACE macros to library source files. This is done via the trace script
+# in the hdf5/bin directory. If the file contains HDF5 API macros, a "clean"
+# version of the source file is saved with a tilde (~) after its name and
+# tracing information is inserted. trace should have no effect on files
+# without HDF5 macros.
+.PHONY: trace
+
+trace: $(libhdf5_la_SOURCES)
+ @for dep in $? dummy; do \
+ if test $$dep != "dummy" -a -n "$(PERL)"; then \
+ case "$$dep" in \
+ *.c) \
+ $(TRACE) $$dep; \
+ ;; \
+ esac; \
+ fi; \
+ done
+
+include $(top_srcdir)/config/conclude.am
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..9dff057
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,2109 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the COPYING file, which can be found at the root of the source code
+# distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
+# If you do not have access to either file, you may request a copy from
+# help@hdfgroup.org.
+#
+# HDF5 Library Makefile(.in)
+#
+
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = H5detect$(EXEEXT) H5make_libsettings$(EXEEXT)
+
+# Only compile parallel sources if necessary
+@BUILD_PARALLEL_CONDITIONAL_TRUE@am__append_1 = H5ACmpio.c H5Cmpio.c H5Dmpio.c H5Fmpi.c H5FDmpi.c H5FDmpio.c H5Smpio.c
+
+# Only compile the direct VFD if necessary
+@DIRECT_VFD_CONDITIONAL_TRUE@am__append_2 = H5FDdirect.c
+TESTS =
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/aclocal_cxx.m4 \
+ $(top_srcdir)/m4/aclocal_fc.m4 \
+ $(top_srcdir)/m4/ax_check_class.m4 \
+ $(top_srcdir)/m4/ax_check_classpath.m4 \
+ $(top_srcdir)/m4/ax_check_java_home.m4 \
+ $(top_srcdir)/m4/ax_check_junit.m4 \
+ $(top_srcdir)/m4/ax_java_options.m4 \
+ $(top_srcdir)/m4/ax_jni_include_dir.m4 \
+ $(top_srcdir)/m4/ax_prog_jar.m4 \
+ $(top_srcdir)/m4/ax_prog_java.m4 \
+ $(top_srcdir)/m4/ax_prog_java_works.m4 \
+ $(top_srcdir)/m4/ax_prog_javac.m4 \
+ $(top_srcdir)/m4/ax_prog_javac_works.m4 \
+ $(top_srcdir)/m4/ax_prog_javadoc.m4 \
+ $(top_srcdir)/m4/ax_try_compile_java.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = H5config.h $(top_builddir)/fortran/src/H5config_f.inc
+CONFIG_CLEAN_FILES = libhdf5.settings
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(settingsdir)" \
+ "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libhdf5_la_LIBADD =
+am__libhdf5_la_SOURCES_DIST = H5.c H5checksum.c H5dbg.c H5system.c \
+ H5timer.c H5trace.c H5A.c H5Abtree2.c H5Adense.c H5Adeprec.c \
+ H5Aint.c H5Atest.c H5AC.c H5ACdbg.c H5AClog.c \
+ H5ACproxy_entry.c H5B.c H5Bcache.c H5Bdbg.c H5B2.c H5B2cache.c \
+ H5B2dbg.c H5B2hdr.c H5B2int.c H5B2internal.c H5B2leaf.c \
+ H5B2stat.c H5B2test.c H5C.c H5Cdbg.c H5Cepoch.c H5Cimage.c \
+ H5Clog.c H5Cprefetched.c H5Cquery.c H5Ctag.c H5Ctest.c H5CS.c \
+ H5D.c H5Dbtree.c H5Dbtree2.c H5Dchunk.c H5Dcompact.c \
+ H5Dcontig.c H5Ddbg.c H5Ddeprec.c H5Dearray.c H5Defl.c \
+ H5Dfarray.c H5Dfill.c H5Dint.c H5Dio.c H5Dlayout.c H5Dnone.c \
+ H5Doh.c H5Dscatgath.c H5Dselect.c H5Dsingle.c H5Dtest.c \
+ H5Dvirtual.c H5E.c H5Edeprec.c H5Eint.c H5EA.c H5EAcache.c \
+ H5EAdbg.c H5EAdblkpage.c H5EAdblock.c H5EAhdr.c H5EAiblock.c \
+ H5EAint.c H5EAsblock.c H5EAstat.c H5EAtest.c H5F.c H5Fint.c \
+ H5Faccum.c H5Fcwfs.c H5Fdbg.c H5Fdeprec.c H5Fefc.c H5Ffake.c \
+ H5Fio.c H5Fmount.c H5Fquery.c H5Fsfile.c H5Fspace.c H5Fsuper.c \
+ H5Fsuper_cache.c H5Ftest.c H5FA.c H5FAcache.c H5FAdbg.c \
+ H5FAdblock.c H5FAdblkpage.c H5FAhdr.c H5FAint.c H5FAstat.c \
+ H5FAtest.c H5FD.c H5FDcore.c H5FDfamily.c H5FDint.c H5FDlog.c \
+ H5FDmulti.c H5FDsec2.c H5FDspace.c H5FDstdio.c H5FDtest.c \
+ H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c \
+ H5FSsection.c H5FSstat.c H5FStest.c H5G.c H5Gbtree2.c \
+ H5Gcache.c H5Gcompact.c H5Gdense.c H5Gdeprec.c H5Gent.c \
+ H5Gint.c H5Glink.c H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c \
+ H5Goh.c H5Groot.c H5Gstab.c H5Gtest.c H5Gtraverse.c H5HF.c \
+ H5HFbtree2.c H5HFcache.c H5HFdbg.c H5HFdblock.c H5HFdtable.c \
+ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c \
+ H5HFsection.c H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \
+ H5HG.c H5HGcache.c H5HGdbg.c H5HGquery.c H5HL.c H5HLcache.c \
+ H5HLdbg.c H5HLint.c H5HLprfx.c H5HLdblk.c H5HP.c H5I.c \
+ H5Itest.c H5L.c H5Lexternal.c H5lib_settings.c H5MF.c \
+ H5MFaggr.c H5MFdbg.c H5MFsection.c H5MM.c H5MP.c H5MPtest.c \
+ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c H5Oattribute.c \
+ H5Obogus.c H5Obtreek.c H5Ocache.c H5Ocache_image.c H5Ochunk.c \
+ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \
+ H5Ofill.c H5Oflush.c H5Ofsinfo.c H5Oginfo.c H5Olayout.c \
+ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c H5Oname.c \
+ H5Onull.c H5Opline.c H5Orefcount.c H5Osdspace.c H5Oshared.c \
+ H5Oshmesg.c H5Ostab.c H5Otest.c H5Ounknown.c H5P.c H5Pacpl.c \
+ H5Pdapl.c H5Pdcpl.c H5Pdeprec.c H5Pdxpl.c H5Pencdec.c \
+ H5Pfapl.c H5Pfcpl.c H5Pfmpl.c H5Pgcpl.c H5Pint.c H5Plapl.c \
+ H5Plcpl.c H5Pocpl.c H5Pocpypl.c H5Pstrcpl.c H5Ptest.c H5PB.c \
+ H5PL.c H5R.c H5Rdeprec.c H5UC.c H5RS.c H5S.c H5Sall.c H5Sdbg.c \
+ H5Shyper.c H5Snone.c H5Spoint.c H5Sselect.c H5Stest.c H5SL.c \
+ H5SM.c H5SMbtree2.c H5SMcache.c H5SMmessage.c H5SMtest.c \
+ H5ST.c H5T.c H5Tarray.c H5Tbit.c H5Tcommit.c H5Tcompound.c \
+ H5Tconv.c H5Tcset.c H5Tdbg.c H5Tdeprec.c H5Tenum.c H5Tfields.c \
+ H5Tfixed.c H5Tfloat.c H5Tinit.c H5Tnative.c H5Toffset.c \
+ H5Toh.c H5Topaque.c H5Torder.c H5Tpad.c H5Tprecis.c \
+ H5Tstrpad.c H5Tvisit.c H5Tvlen.c H5TS.c H5VM.c H5WB.c H5Z.c \
+ H5Zdeflate.c H5Zfletcher32.c H5Znbit.c H5Zshuffle.c \
+ H5Zscaleoffset.c H5Zszip.c H5Ztrans.c H5ACmpio.c H5Cmpio.c \
+ H5Dmpio.c H5Fmpi.c H5FDmpi.c H5FDmpio.c H5Smpio.c H5FDdirect.c
+@BUILD_PARALLEL_CONDITIONAL_TRUE@am__objects_1 = H5ACmpio.lo \
+@BUILD_PARALLEL_CONDITIONAL_TRUE@ H5Cmpio.lo H5Dmpio.lo \
+@BUILD_PARALLEL_CONDITIONAL_TRUE@ H5Fmpi.lo H5FDmpi.lo \
+@BUILD_PARALLEL_CONDITIONAL_TRUE@ H5FDmpio.lo H5Smpio.lo
+@DIRECT_VFD_CONDITIONAL_TRUE@am__objects_2 = H5FDdirect.lo
+am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \
+ H5timer.lo H5trace.lo H5A.lo H5Abtree2.lo H5Adense.lo \
+ H5Adeprec.lo H5Aint.lo H5Atest.lo H5AC.lo H5ACdbg.lo \
+ H5AClog.lo H5ACproxy_entry.lo H5B.lo H5Bcache.lo H5Bdbg.lo \
+ H5B2.lo H5B2cache.lo H5B2dbg.lo H5B2hdr.lo H5B2int.lo \
+ H5B2internal.lo H5B2leaf.lo H5B2stat.lo H5B2test.lo H5C.lo \
+ H5Cdbg.lo H5Cepoch.lo H5Cimage.lo H5Clog.lo H5Cprefetched.lo \
+ H5Cquery.lo H5Ctag.lo H5Ctest.lo H5CS.lo H5D.lo H5Dbtree.lo \
+ H5Dbtree2.lo H5Dchunk.lo H5Dcompact.lo H5Dcontig.lo H5Ddbg.lo \
+ H5Ddeprec.lo H5Dearray.lo H5Defl.lo H5Dfarray.lo H5Dfill.lo \
+ H5Dint.lo H5Dio.lo H5Dlayout.lo H5Dnone.lo H5Doh.lo \
+ H5Dscatgath.lo H5Dselect.lo H5Dsingle.lo H5Dtest.lo \
+ H5Dvirtual.lo H5E.lo H5Edeprec.lo H5Eint.lo H5EA.lo \
+ H5EAcache.lo H5EAdbg.lo H5EAdblkpage.lo H5EAdblock.lo \
+ H5EAhdr.lo H5EAiblock.lo H5EAint.lo H5EAsblock.lo H5EAstat.lo \
+ H5EAtest.lo H5F.lo H5Fint.lo H5Faccum.lo H5Fcwfs.lo H5Fdbg.lo \
+ H5Fdeprec.lo H5Fefc.lo H5Ffake.lo H5Fio.lo H5Fmount.lo \
+ H5Fquery.lo H5Fsfile.lo H5Fspace.lo H5Fsuper.lo \
+ H5Fsuper_cache.lo H5Ftest.lo H5FA.lo H5FAcache.lo H5FAdbg.lo \
+ H5FAdblock.lo H5FAdblkpage.lo H5FAhdr.lo H5FAint.lo \
+ H5FAstat.lo H5FAtest.lo H5FD.lo H5FDcore.lo H5FDfamily.lo \
+ H5FDint.lo H5FDlog.lo H5FDmulti.lo H5FDsec2.lo H5FDspace.lo \
+ H5FDstdio.lo H5FDtest.lo H5FL.lo H5FO.lo H5FS.lo H5FScache.lo \
+ H5FSdbg.lo H5FSint.lo H5FSsection.lo H5FSstat.lo H5FStest.lo \
+ H5G.lo H5Gbtree2.lo H5Gcache.lo H5Gcompact.lo H5Gdense.lo \
+ H5Gdeprec.lo H5Gent.lo H5Gint.lo H5Glink.lo H5Gloc.lo \
+ H5Gname.lo H5Gnode.lo H5Gobj.lo H5Goh.lo H5Groot.lo H5Gstab.lo \
+ H5Gtest.lo H5Gtraverse.lo H5HF.lo H5HFbtree2.lo H5HFcache.lo \
+ H5HFdbg.lo H5HFdblock.lo H5HFdtable.lo H5HFhdr.lo H5HFhuge.lo \
+ H5HFiblock.lo H5HFiter.lo H5HFman.lo H5HFsection.lo \
+ H5HFspace.lo H5HFstat.lo H5HFtest.lo H5HFtiny.lo H5HG.lo \
+ H5HGcache.lo H5HGdbg.lo H5HGquery.lo H5HL.lo H5HLcache.lo \
+ H5HLdbg.lo H5HLint.lo H5HLprfx.lo H5HLdblk.lo H5HP.lo H5I.lo \
+ H5Itest.lo H5L.lo H5Lexternal.lo H5lib_settings.lo H5MF.lo \
+ H5MFaggr.lo H5MFdbg.lo H5MFsection.lo H5MM.lo H5MP.lo \
+ H5MPtest.lo H5O.lo H5Oainfo.lo H5Oalloc.lo H5Oattr.lo \
+ H5Oattribute.lo H5Obogus.lo H5Obtreek.lo H5Ocache.lo \
+ H5Ocache_image.lo H5Ochunk.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo \
+ H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo H5Oflush.lo \
+ H5Ofsinfo.lo H5Oginfo.lo H5Olayout.lo H5Olinfo.lo H5Olink.lo \
+ H5Omessage.lo H5Omtime.lo H5Oname.lo H5Onull.lo H5Opline.lo \
+ H5Orefcount.lo H5Osdspace.lo H5Oshared.lo H5Oshmesg.lo \
+ H5Ostab.lo H5Otest.lo H5Ounknown.lo H5P.lo H5Pacpl.lo \
+ H5Pdapl.lo H5Pdcpl.lo H5Pdeprec.lo H5Pdxpl.lo H5Pencdec.lo \
+ H5Pfapl.lo H5Pfcpl.lo H5Pfmpl.lo H5Pgcpl.lo H5Pint.lo \
+ H5Plapl.lo H5Plcpl.lo H5Pocpl.lo H5Pocpypl.lo H5Pstrcpl.lo \
+ H5Ptest.lo H5PB.lo H5PL.lo H5R.lo H5Rdeprec.lo H5UC.lo H5RS.lo \
+ H5S.lo H5Sall.lo H5Sdbg.lo H5Shyper.lo H5Snone.lo H5Spoint.lo \
+ H5Sselect.lo H5Stest.lo H5SL.lo H5SM.lo H5SMbtree2.lo \
+ H5SMcache.lo H5SMmessage.lo H5SMtest.lo H5ST.lo H5T.lo \
+ H5Tarray.lo H5Tbit.lo H5Tcommit.lo H5Tcompound.lo H5Tconv.lo \
+ H5Tcset.lo H5Tdbg.lo H5Tdeprec.lo H5Tenum.lo H5Tfields.lo \
+ H5Tfixed.lo H5Tfloat.lo H5Tinit.lo H5Tnative.lo H5Toffset.lo \
+ H5Toh.lo H5Topaque.lo H5Torder.lo H5Tpad.lo H5Tprecis.lo \
+ H5Tstrpad.lo H5Tvisit.lo H5Tvlen.lo H5TS.lo H5VM.lo H5WB.lo \
+ H5Z.lo H5Zdeflate.lo H5Zfletcher32.lo H5Znbit.lo H5Zshuffle.lo \
+ H5Zscaleoffset.lo H5Zszip.lo H5Ztrans.lo $(am__objects_1) \
+ $(am__objects_2)
+libhdf5_la_OBJECTS = $(am_libhdf5_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libhdf5_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libhdf5_la_LDFLAGS) $(LDFLAGS) -o $@
+PROGRAMS = $(noinst_PROGRAMS)
+H5detect_SOURCES = H5detect.c
+H5detect_OBJECTS = H5detect.$(OBJEXT)
+H5detect_LDADD = $(LDADD)
+H5make_libsettings_SOURCES = H5make_libsettings.c
+H5make_libsettings_OBJECTS = H5make_libsettings.$(OBJEXT)
+H5make_libsettings_LDADD = $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/fortran/src
+depcomp = $(SHELL) $(top_srcdir)/bin/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libhdf5_la_SOURCES) H5detect.c H5make_libsettings.c
+DIST_SOURCES = $(am__libhdf5_la_SOURCES_DIST) H5detect.c \
+ H5make_libsettings.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(settings_DATA)
+HEADERS = $(include_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)H5config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.sh.log=.log)
+SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/bin/test-driver
+SH_LOG_COMPILE = $(SH_LOG_COMPILER) $(AM_SH_LOG_FLAGS) $(SH_LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__DIST_COMMON = $(srcdir)/H5config.h.in $(srcdir)/Makefile.in \
+ $(srcdir)/libhdf5.settings.in $(top_srcdir)/bin/depcomp \
+ $(top_srcdir)/bin/test-driver $(top_srcdir)/config/commence.am \
+ $(top_srcdir)/config/conclude.am \
+ $(top_srcdir)/config/lt_vers.am COPYING
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADD_PARALLEL_FILES = @ADD_PARALLEL_FILES@
+AMTAR = @AMTAR@
+
+# H5_CFLAGS holds flags that should be used when building hdf5,
+# but which should not be exported to h5cc for building other programs.
+# AM_CFLAGS is an automake construct which should be used by Makefiles
+# instead of CFLAGS, as CFLAGS is reserved solely for the user to define.
+# This applies to FCFLAGS, CXXFLAGS, CPPFLAGS, and LDFLAGS as well.
+AM_CFLAGS = @AM_CFLAGS@ @H5_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ @H5_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@ @H5_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_FCFLAGS = @AM_FCFLAGS@ @H5_FCFLAGS@
+AM_JAVACFLAGS = @AM_JAVACFLAGS@
+AM_JAVAFLAGS = @AM_JAVAFLAGS@
+AM_JNIFLAGS = @AM_JNIFLAGS@
+AM_LDFLAGS = @AM_LDFLAGS@ @H5_LDFLAGS@
+AR = @AR@
+ASSERTS = @ASSERTS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_MODE = @BUILD_MODE@
+BYTESEX = @BYTESEX@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CODESTACK = @CODESTACK@
+CONFIG_DATE = @CONFIG_DATE@
+CONFIG_MODE = @CONFIG_MODE@
+CONFIG_USER = @CONFIG_USER@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXX_VERSION = @CXX_VERSION@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_API_VERSION = @DEFAULT_API_VERSION@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_SYMBOLS = @DEPRECATED_SYMBOLS@
+DEV_WARNINGS = @DEV_WARNINGS@
+DIRECT_VFD = @DIRECT_VFD@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTERNAL_FILTERS = @EXTERNAL_FILTERS@
+
+# Make sure that these variables are exported to the Makefiles
+F9XMODEXT = @F9XMODEXT@
+F9XMODFLAG = @F9XMODFLAG@
+F9XSUFFIXFLAG = @F9XSUFFIXFLAG@
+FC = @FC@
+FCFLAGS = @FCFLAGS@
+FCFLAGS_f90 = @FCFLAGS_f90@
+FCLIBS = @FCLIBS@
+FC_VERSION = @FC_VERSION@
+FGREP = @FGREP@
+FORTRAN_C_LONG_DOUBLE_IS_UNIQUE = @FORTRAN_C_LONG_DOUBLE_IS_UNIQUE@
+FORTRAN_HAVE_C_LONG_DOUBLE = @FORTRAN_HAVE_C_LONG_DOUBLE@
+FORTRAN_SIZEOF_LONG_DOUBLE = @FORTRAN_SIZEOF_LONG_DOUBLE@
+FSEARCH_DIRS = @FSEARCH_DIRS@
+Fortran_COMPILER_ID = @Fortran_COMPILER_ID@
+GREP = @GREP@
+H5CONFIG_F_IKIND = @H5CONFIG_F_IKIND@
+H5CONFIG_F_NUM_IKIND = @H5CONFIG_F_NUM_IKIND@
+H5CONFIG_F_NUM_RKIND = @H5CONFIG_F_NUM_RKIND@
+H5CONFIG_F_RKIND = @H5CONFIG_F_RKIND@
+H5CONFIG_F_RKIND_SIZEOF = @H5CONFIG_F_RKIND_SIZEOF@
+H5_CFLAGS = @H5_CFLAGS@
+H5_CLASSPATH = @H5_CLASSPATH@
+H5_CPPFLAGS = @H5_CPPFLAGS@
+H5_CXXFLAGS = @H5_CXXFLAGS@
+H5_FCFLAGS = @H5_FCFLAGS@
+H5_FORTRAN_SHARED = @H5_FORTRAN_SHARED@
+H5_JAVACFLAGS = @H5_JAVACFLAGS@
+H5_JAVAFLAGS = @H5_JAVAFLAGS@
+H5_JNIFLAGS = @H5_JNIFLAGS@
+H5_LDFLAGS = @H5_LDFLAGS@
+H5_VERSION = @H5_VERSION@
+HADDR_T = @HADDR_T@
+HAVE_DMALLOC = @HAVE_DMALLOC@
+HAVE_Fortran_INTEGER_SIZEOF_16 = @HAVE_Fortran_INTEGER_SIZEOF_16@
+HAVE_PTHREAD = @HAVE_PTHREAD@
+HDF5_HL = @HDF5_HL@
+HDF5_INTERFACES = @HDF5_INTERFACES@
+HDF_CXX = @HDF_CXX@
+HDF_FORTRAN = @HDF_FORTRAN@
+HDF_JAVA = @HDF_JAVA@
+HID_T = @HID_T@
+HL = @HL@
+HL_FOR = @HL_FOR@
+HSIZE_T = @HSIZE_T@
+HSSIZE_T = @HSSIZE_T@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTRUMENT_LIBRARY = @INSTRUMENT_LIBRARY@
+INTERNAL_DEBUG_OUTPUT = @INTERNAL_DEBUG_OUTPUT@
+JAR = @JAR@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+JAVACFLAGS = @JAVACFLAGS@
+JAVADOC = @JAVADOC@
+JAVAFLAGS = @JAVAFLAGS@
+JAVAPREFIX = @JAVAPREFIX@
+JAVA_JUNIT = @JAVA_JUNIT@
+JAVA_PATH_NAME = @JAVA_PATH_NAME@
+JAVA_VERSION = @JAVA_VERSION@
+JNIFLAGS = @JNIFLAGS@
+JUNIT = @JUNIT@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LL_PATH = @LL_PATH@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_STATIC_EXEC = @LT_STATIC_EXEC@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MEMORYALLOCSANITYCHECK = @MEMORYALLOCSANITYCHECK@
+METADATATRACEFILE = @METADATATRACEFILE@
+MKDIR_P = @MKDIR_P@
+MPE = @MPE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJECT_NAMELEN_DEFAULT_F = @OBJECT_NAMELEN_DEFAULT_F@
+OBJEXT = @OBJEXT@
+OPTIMIZATION = @OPTIMIZATION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PAC_C_MAX_REAL_PRECISION = @PAC_C_MAX_REAL_PRECISION@
+PAC_FC_ALL_INTEGER_KINDS = @PAC_FC_ALL_INTEGER_KINDS@
+PAC_FC_ALL_INTEGER_KINDS_SIZEOF = @PAC_FC_ALL_INTEGER_KINDS_SIZEOF@
+PAC_FC_ALL_REAL_KINDS = @PAC_FC_ALL_REAL_KINDS@
+PAC_FC_ALL_REAL_KINDS_SIZEOF = @PAC_FC_ALL_REAL_KINDS_SIZEOF@
+PAC_FC_MAX_REAL_PRECISION = @PAC_FC_MAX_REAL_PRECISION@
+PAC_FORTRAN_NATIVE_DOUBLE_KIND = @PAC_FORTRAN_NATIVE_DOUBLE_KIND@
+PAC_FORTRAN_NATIVE_DOUBLE_SIZEOF = @PAC_FORTRAN_NATIVE_DOUBLE_SIZEOF@
+PAC_FORTRAN_NATIVE_INTEGER_KIND = @PAC_FORTRAN_NATIVE_INTEGER_KIND@
+PAC_FORTRAN_NATIVE_INTEGER_SIZEOF = @PAC_FORTRAN_NATIVE_INTEGER_SIZEOF@
+PAC_FORTRAN_NATIVE_REAL_KIND = @PAC_FORTRAN_NATIVE_REAL_KIND@
+PAC_FORTRAN_NATIVE_REAL_SIZEOF = @PAC_FORTRAN_NATIVE_REAL_SIZEOF@
+PAC_FORTRAN_NUM_INTEGER_KINDS = @PAC_FORTRAN_NUM_INTEGER_KINDS@
+PARALLEL = @PARALLEL@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PROFILING = @PROFILING@
+RANLIB = @RANLIB@
+ROOT = @ROOT@
+RUNPARALLEL = @RUNPARALLEL@
+RUNSERIAL = @RUNSERIAL@
+R_INTEGER = @R_INTEGER@
+R_LARGE = @R_LARGE@
+SEARCH = @SEARCH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIZE_T = @SIZE_T@
+STATIC_EXEC = @STATIC_EXEC@
+STATIC_SHARED = @STATIC_SHARED@
+STRICT_FORMAT_CHECKS = @STRICT_FORMAT_CHECKS@
+STRIP = @STRIP@
+SYMBOLS = @SYMBOLS@
+TESTPARALLEL = @TESTPARALLEL@
+TESTS_JUNIT = @TESTS_JUNIT@
+THREADSAFE = @THREADSAFE@
+TIME = @TIME@
+TR = @TR@
+TRACE_API = @TRACE_API@
+UNAME_INFO = @UNAME_INFO@
+USE_FILTER_DEFLATE = @USE_FILTER_DEFLATE@
+USE_FILTER_SZIP = @USE_FILTER_SZIP@
+USINGMEMCHECKER = @USINGMEMCHECKER@
+UUDECODE = @UUDECODE@
+VERSION = @VERSION@
+WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
+_ACJNI_JAVAC = @_ACJNI_JAVAC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_FC = @ac_ct_FC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+
+# Install directories that automake doesn't know about
+docdir = $(exec_prefix)/doc
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Shell commands used in Makefiles
+RM = rm -f
+CP = cp
+
+# Some machines need a command to run executables; this is that command
+# so that our tests will run.
+# We use RUNEXEC instead of RUNSERIAL directly because it may be that
+# some tests need to be run with a different command. Older versions
+# of the makefiles used the command
+# $(LIBTOOL) --mode=execute
+# in some directories, for instance.
+RUNEXEC = $(RUNSERIAL)
+
+# Libraries to link to while building
+LIBHDF5 = $(top_builddir)/src/libhdf5.la
+LIBH5TEST = $(top_builddir)/test/libh5test.la
+LIBH5F = $(top_builddir)/fortran/src/libhdf5_fortran.la
+LIBH5FTEST = $(top_builddir)/fortran/test/libh5test_fortran.la
+LIBH5CPP = $(top_builddir)/c++/src/libhdf5_cpp.la
+LIBH5JNI = $(top_builddir)/java/src/jni/libhdf5_java.la
+LIBH5TOOLS = $(top_builddir)/tools/lib/libh5tools.la
+LIBH5_HL = $(top_builddir)/hl/src/libhdf5_hl.la
+LIBH5F_HL = $(top_builddir)/hl/fortran/src/libhdf5hl_fortran.la
+LIBH5CPP_HL = $(top_builddir)/hl/c++/src/libhdf5_hl_cpp.la
+
+# Note that in svn revision 19400 the '/' after DESTDIR in H5* variables below
+# has been removed. According to the official description of DESTDIR by Gnu at
+# http://www.gnu.org/prep/standards/html_node/DESTDIR.html, DESTDIR is
+# prepended to the normal and complete install path that it precedes for the
+# purpose of installing in a temporary directory which is useful for building
+# rpms and other packages. The '/' after ${DESTDIR} will be followed by another
+# '/' at the beginning of the normal install path. When DESTDIR is empty the
+# path then begins with '//', which is incorrect and causes problems at least for
+# Cygwin.
+
+# Scripts used to build examples
+# If only shared libraries have been installed, have h5cc build examples with
+# shared libraries instead of static libraries
+H5CC = ${DESTDIR}$(bindir)/h5cc
+H5CC_PP = ${DESTDIR}$(bindir)/h5pcc
+H5FC = ${DESTDIR}$(bindir)/h5fc
+H5FC_PP = ${DESTDIR}$(bindir)/h5pfc
+H5CPP = ${DESTDIR}$(bindir)/h5c++
+ACLOCAL_AMFLAGS = "-I m4"
+
+# The trace script; this is used on source files from the C library to
+# insert tracing macros.
+TRACE = perl $(top_srcdir)/bin/trace
+
+# .chkexe files are used to mark tests that have run successfully.
+# .chklog files are output from those tests.
+# *.clog and *.clog2 are from the MPE option.
+CHECK_CLEANFILES = *.chkexe *.chklog *.clog *.clog2
+LT_VERS_INTERFACE = 101
+LT_VERS_REVISION = 0
+LT_VERS_AGE = 0
+LT_CXX_VERS_INTERFACE = 101
+LT_CXX_VERS_REVISION = 0
+LT_CXX_VERS_AGE = 0
+LT_F_VERS_INTERFACE = 101
+LT_F_VERS_REVISION = 0
+LT_F_VERS_AGE = 1
+LT_HL_VERS_INTERFACE = 100
+LT_HL_VERS_REVISION = 1
+LT_HL_VERS_AGE = 0
+LT_HL_CXX_VERS_INTERFACE = 101
+LT_HL_CXX_VERS_REVISION = 0
+LT_HL_CXX_VERS_AGE = 1
+LT_HL_F_VERS_INTERFACE = 100
+LT_HL_F_VERS_REVISION = 1
+LT_HL_F_VERS_AGE = 0
+LT_JAVA_VERS_INTERFACE = 101
+LT_JAVA_VERS_REVISION = 0
+LT_JAVA_VERS_AGE = 1
+LT_TOOLS_VERS_INTERFACE = 100
+LT_TOOLS_VERS_REVISION = 1
+LT_TOOLS_VERS_AGE = 0
+
+# Our main target, the HDF5 library
+lib_LTLIBRARIES = libhdf5.la
+
+# Add libtool numbers to the HDF5 library (from config/lt_vers.am)
+libhdf5_la_LDFLAGS = -version-info $(LT_VERS_INTERFACE):$(LT_VERS_REVISION):$(LT_VERS_AGE) $(AM_LDFLAGS)
+
+# H5Tinit.c and H5lib_settings.c are generated files and should be cleaned.
+MOSTLYCLEANFILES = H5Tinit.c H5lib_settings.c
+# H5pubconf.h is generated by configure, and should be cleaned.
+DISTCLEANFILES = H5pubconf.h
+
+# library sources
+libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c \
+ H5trace.c H5A.c H5Abtree2.c H5Adense.c H5Adeprec.c H5Aint.c \
+ H5Atest.c H5AC.c H5ACdbg.c H5AClog.c H5ACproxy_entry.c H5B.c \
+ H5Bcache.c H5Bdbg.c H5B2.c H5B2cache.c H5B2dbg.c H5B2hdr.c \
+ H5B2int.c H5B2internal.c H5B2leaf.c H5B2stat.c H5B2test.c \
+ H5C.c H5Cdbg.c H5Cepoch.c H5Cimage.c H5Clog.c H5Cprefetched.c \
+ H5Cquery.c H5Ctag.c H5Ctest.c H5CS.c H5D.c H5Dbtree.c \
+ H5Dbtree2.c H5Dchunk.c H5Dcompact.c H5Dcontig.c H5Ddbg.c \
+ H5Ddeprec.c H5Dearray.c H5Defl.c H5Dfarray.c H5Dfill.c \
+ H5Dint.c H5Dio.c H5Dlayout.c H5Dnone.c H5Doh.c H5Dscatgath.c \
+ H5Dselect.c H5Dsingle.c H5Dtest.c H5Dvirtual.c H5E.c \
+ H5Edeprec.c H5Eint.c H5EA.c H5EAcache.c H5EAdbg.c \
+ H5EAdblkpage.c H5EAdblock.c H5EAhdr.c H5EAiblock.c H5EAint.c \
+ H5EAsblock.c H5EAstat.c H5EAtest.c H5F.c H5Fint.c H5Faccum.c \
+ H5Fcwfs.c H5Fdbg.c H5Fdeprec.c H5Fefc.c H5Ffake.c H5Fio.c \
+ H5Fmount.c H5Fquery.c H5Fsfile.c H5Fspace.c H5Fsuper.c \
+ H5Fsuper_cache.c H5Ftest.c H5FA.c H5FAcache.c H5FAdbg.c \
+ H5FAdblock.c H5FAdblkpage.c H5FAhdr.c H5FAint.c H5FAstat.c \
+ H5FAtest.c H5FD.c H5FDcore.c H5FDfamily.c H5FDint.c H5FDlog.c \
+ H5FDmulti.c H5FDsec2.c H5FDspace.c H5FDstdio.c H5FDtest.c \
+ H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c \
+ H5FSsection.c H5FSstat.c H5FStest.c H5G.c H5Gbtree2.c \
+ H5Gcache.c H5Gcompact.c H5Gdense.c H5Gdeprec.c H5Gent.c \
+ H5Gint.c H5Glink.c H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c \
+ H5Goh.c H5Groot.c H5Gstab.c H5Gtest.c H5Gtraverse.c H5HF.c \
+ H5HFbtree2.c H5HFcache.c H5HFdbg.c H5HFdblock.c H5HFdtable.c \
+ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c \
+ H5HFsection.c H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \
+ H5HG.c H5HGcache.c H5HGdbg.c H5HGquery.c H5HL.c H5HLcache.c \
+ H5HLdbg.c H5HLint.c H5HLprfx.c H5HLdblk.c H5HP.c H5I.c \
+ H5Itest.c H5L.c H5Lexternal.c H5lib_settings.c H5MF.c \
+ H5MFaggr.c H5MFdbg.c H5MFsection.c H5MM.c H5MP.c H5MPtest.c \
+ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c H5Oattribute.c \
+ H5Obogus.c H5Obtreek.c H5Ocache.c H5Ocache_image.c H5Ochunk.c \
+ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \
+ H5Ofill.c H5Oflush.c H5Ofsinfo.c H5Oginfo.c H5Olayout.c \
+ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c H5Oname.c \
+ H5Onull.c H5Opline.c H5Orefcount.c H5Osdspace.c H5Oshared.c \
+ H5Oshmesg.c H5Ostab.c H5Otest.c H5Ounknown.c H5P.c H5Pacpl.c \
+ H5Pdapl.c H5Pdcpl.c H5Pdeprec.c H5Pdxpl.c H5Pencdec.c \
+ H5Pfapl.c H5Pfcpl.c H5Pfmpl.c H5Pgcpl.c H5Pint.c H5Plapl.c \
+ H5Plcpl.c H5Pocpl.c H5Pocpypl.c H5Pstrcpl.c H5Ptest.c H5PB.c \
+ H5PL.c H5R.c H5Rdeprec.c H5UC.c H5RS.c H5S.c H5Sall.c H5Sdbg.c \
+ H5Shyper.c H5Snone.c H5Spoint.c H5Sselect.c H5Stest.c H5SL.c \
+ H5SM.c H5SMbtree2.c H5SMcache.c H5SMmessage.c H5SMtest.c \
+ H5ST.c H5T.c H5Tarray.c H5Tbit.c H5Tcommit.c H5Tcompound.c \
+ H5Tconv.c H5Tcset.c H5Tdbg.c H5Tdeprec.c H5Tenum.c H5Tfields.c \
+ H5Tfixed.c H5Tfloat.c H5Tinit.c H5Tnative.c H5Toffset.c \
+ H5Toh.c H5Topaque.c H5Torder.c H5Tpad.c H5Tprecis.c \
+ H5Tstrpad.c H5Tvisit.c H5Tvlen.c H5TS.c H5VM.c H5WB.c H5Z.c \
+ H5Zdeflate.c H5Zfletcher32.c H5Znbit.c H5Zshuffle.c \
+ H5Zscaleoffset.c H5Zszip.c H5Ztrans.c $(am__append_1) \
+ $(am__append_2)
+
+# Public headers
+include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5version.h \
+ H5Apublic.h H5ACpublic.h \
+ H5Cpublic.h H5Dpublic.h \
+ H5Epubgen.h H5Epublic.h H5Fpublic.h \
+ H5FDpublic.h H5FDcore.h H5FDdirect.h \
+ H5FDfamily.h H5FDlog.h H5FDmpi.h H5FDmpio.h \
+ H5FDmulti.h H5FDsec2.h H5FDstdio.h \
+ H5Gpublic.h H5Ipublic.h H5Lpublic.h \
+ H5MMpublic.h H5Opublic.h H5Ppublic.h \
+ H5PLextern.h H5PLpublic.h \
+ H5Rpublic.h H5Spublic.h \
+ H5Tpublic.h H5Zpublic.h
+
+
+# install libhdf5.settings in lib directory
+settingsdir = $(libdir)
+settings_DATA = libhdf5.settings
+
+# Automake needs to be taught how to build lib, dyn, progs and tests targets.
+# These will be filled in automatically for the most part (e.g.,
+# lib_LIBRARIES are built for lib target), but EXTRA_LIB, EXTRA_PROG, and
+# EXTRA_TEST variables are supplied to allow the user to force targets to
+# be built at certain times.
+LIB = $(lib_LIBRARIES) $(lib_LTLIBRARIES) $(noinst_LIBRARIES) \
+ $(noinst_LTLIBRARIES) $(check_LIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LIB)
+
+DYN = $(dyn_LTLIBRARIES)
+PROGS = $(bin_PROGRAMS) $(bin_SCRIPTS) $(noinst_PROGRAMS) $(noinst_SCRIPTS) \
+ $(EXTRA_PROG)
+
+chk_TESTS = $(check_PROGRAMS) $(check_SCRIPTS) $(EXTRA_TEST)
+dyndir = $(libdir)
+TEST_EXTENSIONS = .sh
+SH_LOG_COMPILER = $(SHELL)
+AM_SH_LOG_FLAGS =
+TEST_PROG_CHKEXE = $(TEST_PROG:=.chkexe_)
+TEST_PROG_PARA_CHKEXE = $(TEST_PROG_PARA:=.chkexe_)
+TEST_SCRIPT_CHKSH = $(TEST_SCRIPT:=.chkexe_)
+TEST_SCRIPT_PARA_CHKSH = $(TEST_SCRIPT_PARA:=.chkexe_)
+all: H5config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .sh .sh$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/commence.am $(top_srcdir)/config/lt_vers.am $(top_srcdir)/config/conclude.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/config/commence.am $(top_srcdir)/config/lt_vers.am $(top_srcdir)/config/conclude.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+H5config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/H5config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/H5config.h
+$(srcdir)/H5config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f H5config.h stamp-h1
+libhdf5.settings: $(top_builddir)/config.status $(srcdir)/libhdf5.settings.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libhdf5.la: $(libhdf5_la_OBJECTS) $(libhdf5_la_DEPENDENCIES) $(EXTRA_libhdf5_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libhdf5_la_LINK) -rpath $(libdir) $(libhdf5_la_OBJECTS) $(libhdf5_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+H5detect$(EXEEXT): $(H5detect_OBJECTS) $(H5detect_DEPENDENCIES) $(EXTRA_H5detect_DEPENDENCIES)
+ @rm -f H5detect$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(H5detect_OBJECTS) $(H5detect_LDADD) $(LIBS)
+
+H5make_libsettings$(EXEEXT): $(H5make_libsettings_OBJECTS) $(H5make_libsettings_DEPENDENCIES) $(EXTRA_H5make_libsettings_DEPENDENCIES)
+ @rm -f H5make_libsettings$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(H5make_libsettings_OBJECTS) $(H5make_libsettings_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5A.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5AC.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5ACdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5AClog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5ACmpio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5ACproxy_entry.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Abtree2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Adense.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Adeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Aint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Atest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2dbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2hdr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2int.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2internal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2leaf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2stat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5B2test.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Bcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Bdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5C.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5CS.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cepoch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cimage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Clog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cmpio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cprefetched.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Cquery.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ctag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ctest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5D.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dbtree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dbtree2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dchunk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dcompact.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dcontig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ddbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ddeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dearray.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Defl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dfarray.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dfill.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dlayout.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dmpio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dnone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Doh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dscatgath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dselect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dsingle.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Dvirtual.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5E.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EA.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAdblkpage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAdblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAhdr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAiblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAsblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5EAtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Edeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Eint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5F.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FA.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAdblkpage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAdblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAhdr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FAtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FD.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDdirect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDfamily.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDlog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDmpi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDmpio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDmulti.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDsec2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDspace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDstdio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FL.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FO.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FS.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FScache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FSdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FSint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FSsection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FSstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FStest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Faccum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fcwfs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fdeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fefc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ffake.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fmount.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fmpi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fquery.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fsfile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fspace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fsuper.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Fsuper_cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ftest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5G.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gbtree2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gcompact.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gdense.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gdeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gent.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Glink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gnode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gobj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Goh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Groot.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gstab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gtraverse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HF.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFbtree2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFdblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFdtable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFhdr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFhuge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFiblock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFiter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFman.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFsection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFspace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HFtiny.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HG.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HGcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HGdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HGquery.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HL.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HLcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HLdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HLdblk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HLint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HLprfx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5HP.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5I.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Itest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5L.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Lexternal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MF.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MFaggr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MFdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MFsection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MP.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MPtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5O.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oainfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oalloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oattr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oattribute.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obogus.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obtreek.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache_image.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ochunk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocont.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocopy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odrvinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odtype.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oefl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ofill.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oflush.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ofsinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oginfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Olayout.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Olinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Olink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Omessage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Omtime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Onull.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Opline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Orefcount.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Osdspace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshared.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshmesg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ostab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Otest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ounknown.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5P.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5PB.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5PL.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pacpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pdapl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pdcpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pdeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pdxpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pencdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pfapl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pfcpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pfmpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pgcpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Plapl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Plcpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pocpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pocpypl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Pstrcpl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ptest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5R.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5RS.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Rdeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5S.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SL.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SMbtree2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SMcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SMmessage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5SMtest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5ST.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Sall.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Sdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Shyper.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Smpio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Snone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Spoint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Sselect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Stest.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5T.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5TS.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tarray.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tbit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tcommit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tcompound.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tconv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tcset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tdbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tdeprec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tenum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tfields.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tfixed.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tfloat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tinit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tnative.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Toffset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Toh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Topaque.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Torder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tpad.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tprecis.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tstrpad.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tvisit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Tvlen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5UC.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5VM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5WB.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Z.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Zdeflate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Zfletcher32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Znbit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Zscaleoffset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Zshuffle.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Zszip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ztrans.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5checksum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5dbg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5detect.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5lib_settings.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5make_libsettings.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5system.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5timer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5trace.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-settingsDATA: $(settings_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(settings_DATA)'; test -n "$(settingsdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(settingsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(settingsdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(settingsdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(settingsdir)" || exit $$?; \
+ done
+
+uninstall-settingsDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(settings_DATA)'; test -n "$(settingsdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(settingsdir)'; $(am__uninstall_files_from_dir)
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+.sh.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.sh$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) \
+ H5config.h all-local
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(settingsdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS install-settingsDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-local
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-settingsDATA
+
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-TESTS \
+ check-am clean clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-settingsDATA install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool mostlyclean-local pdf \
+ pdf-am ps ps-am recheck tags tags-am uninstall uninstall-am \
+ uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-settingsDATA
+
+.PRECIOUS: Makefile
+
+
+# List all build rules defined by HDF5 Makefiles as "PHONY" targets here.
+# This tells the Makefiles that these targets are not files to be built but
+# commands that should be executed even if a file with the same name already
+# exists.
+.PHONY: build-check-clean build-check-p build-check-s build-lib build-progs \
+ build-tests check-clean check-install check-p check-s check-vfd \
+ install-doc lib progs tests uninstall-doc _exec_check-s _test help
+
+help:
+ @$(top_srcdir)/bin/makehelp
+
+# Number format detection
+# The LD_LIBRARY_PATH setting is a kludge.
+# Things should have been all set during H5detect making.
+# Remove the generated .c file if errors occur unless HDF5_Make_Ignore
+# is set to ignore the error.
+H5Tinit.c: H5detect$(EXEEXT)
+ LD_LIBRARY_PATH="$$LD_LIBRARY_PATH`echo $(LDFLAGS) | \
+ sed -e 's/-L/:/g' -e 's/ //g'`" \
+ $(RUNSERIAL) ./H5detect$(EXEEXT) > $@ || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ ($(RM) $@ ; exit 1)
+
+# Build configuration header file generation
+# The LD_LIBRARY_PATH setting is a kludge.
+# Things should have been all set during H5make_libsettings making.
+# Remove the generated .c file if errors occur unless HDF5_Make_Ignore
+# is set to ignore the error.
+H5lib_settings.c: H5make_libsettings$(EXEEXT) libhdf5.settings
+ LD_LIBRARY_PATH="$$LD_LIBRARY_PATH`echo $(LDFLAGS) | \
+ sed -e 's/-L/:/g' -e 's/ //g'`" \
+ $(RUNSERIAL) ./H5make_libsettings$(EXEEXT) > $@ || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ ($(RM) $@ ; exit 1)
+
+# Error header generation
+#
+# Actually, H5Einit.h, H5Eterm.h, H5Edefin.h and H5Epubgen.h all
+# depend on H5err.txt, but the perl script generates them all, so just
+# list one here.
+$(top_srcdir)/src/H5Edefin.h: $(top_srcdir)/src/H5err.txt
+ perl $(top_srcdir)/bin/make_err $?
+
+# API version macro generation
+$(top_srcdir)/src/H5version.h: $(top_srcdir)/src/H5vers.txt
+ perl $(top_srcdir)/bin/make_vers $?
+
+# Assignment overflow macro generation
+$(top_srcdir)/src/H5overflow.h: $(top_srcdir)/src/H5overflow.txt
+ perl $(top_srcdir)/bin/make_overflow $?
+
+# Add TRACE macros to library source files. This is done via the trace script
+# in the hdf5/bin directory. If the file contains HDF5 API macros, a "clean"
+# version of the source file is saved with a tilde (~) after its name and
+# tracing information is inserted. trace should have no effect on files
+# without HDF5 macros.
+.PHONY: trace
+
+trace: $(libhdf5_la_SOURCES)
+ @for dep in $? dummy; do \
+ if test $$dep != "dummy" -a -n "$(PERL)"; then \
+ case "$$dep" in \
+ *.c) \
+ $(TRACE) $$dep; \
+ ;; \
+ esac; \
+ fi; \
+ done
+
+# lib/progs/tests targets recurse into subdirectories. build-* targets
+# build files in this directory.
+build-dyn: $(DYN)
+build-lib: $(LIB)
+build-progs: $(LIB) $(PROGS)
+build-tests: $(LIB) $(PROGS) $(chk_TESTS)
+
+# General rule for recursive building targets.
+# BUILT_SOURCES contain targets that need to be built before anything else
+# in the directory (e.g., for Fortran type detection)
+lib dyn progs tests check-s check-p :: $(BUILT_SOURCES)
+ @$(MAKE) $(AM_MAKEFLAGS) build-$@ || exit 1;
+ @for d in X $(SUBDIRS); do \
+ if test $$d != X && test $$d != .; then \
+ (set -x; cd $$d && $(MAKE) $(AM_MAKEFLAGS) $@) || exit 1; \
+ fi; \
+ done
+
+# General rule for recursive cleaning targets. Like the rule above,
+# but doesn't require building BUILT_SOURCES.
+check-clean ::
+ @$(MAKE) $(AM_MAKEFLAGS) build-$@ || exit 1;
+ @for d in X $(SUBDIRS); do \
+ if test $$d != X && test $$d != .; then \
+ (set -x; cd $$d && $(MAKE) $(AM_MAKEFLAGS) $@) || exit 1; \
+ fi; \
+ done
+
+# Tell Automake to build tests when the user types `make all' (this is
+# not its default behavior). Also build EXTRA_LIB and EXTRA_PROG since
+# Automake won't build them automatically, either.
+all-local: $(EXTRA_LIB) $(EXTRA_PROG) $(chk_TESTS)
+
+# make install-doc doesn't do anything outside of doc directory, but
+# Makefiles should recognize it.
+# UPDATE: docs no longer reside in this build tree, so this target
+# is depreciated.
+install-doc uninstall-doc:
+ @echo "Nothing to be done."
+
+# clean up files generated by tests so they can be re-run.
+build-check-clean:
+ $(RM) -rf $(CHECK_CLEANFILES)
+
+# run check-clean whenever mostlyclean is run
+mostlyclean-local: build-check-clean
+
+# check-install is just a synonym for installcheck
+check-install: installcheck
+
+# Run each test in order, passing $(TEST_FLAGS) to the program.
+# Since tests are done in a shell loop, "make -i" does apply inside it.
+# Set HDF5_Make_Ignore to a non-blank string to ignore errors inside the loop.
+# The timestamps give a rough idea how much time the tests use.
+#
+# Note that targets in chk_TESTS (defined above) will be built when the user
+# types 'make tests' or 'make check', but only programs in TEST_PROG,
+# TEST_PROG_PARA, or TEST_SCRIPT will actually be executed.
+check-TESTS: test
+
+test _test:
+ @$(MAKE) build-check-s
+ @$(MAKE) build-check-p
+
+# Actual execution of check-s.
+build-check-s: $(LIB) $(PROGS) $(chk_TESTS)
+ @if test -n "$(TEST_PROG)$(TEST_SCRIPT)"; then \
+ echo "===Serial tests in `echo ${PWD} | sed -e s:.*/::` begin `date`==="; \
+ fi
+ @$(MAKE) $(AM_MAKEFLAGS) _exec_check-s
+ @if test -n "$(TEST_PROG)$(TEST_SCRIPT)"; then \
+ echo "===Serial tests in `echo ${PWD} | sed -e s:.*/::` ended `date`===";\
+ fi
+
+_exec_check-s: $(TEST_PROG_CHKEXE) $(TEST_SCRIPT_CHKSH)
+
+# The dummy.chkexe here prevents the target from being
+# empty if there are no tests in the current directory.
+# $${log} is the log file.
+# $${tname} is the name of test.
+$(TEST_PROG_CHKEXE) $(TEST_PROG_PARA_CHKEXE) dummy.chkexe_:
+ @if test "X$@" != "X.chkexe_" && test "X$@" != "Xdummy.chkexe_"; then \
+ tname=$(@:.chkexe_=)$(EXEEXT);\
+ log=$(@:.chkexe_=.chklog); \
+ echo "============================"; \
+ if $(top_srcdir)/bin/newer $(@:.chkexe_=.chkexe) $${tname}; then \
+ echo "No need to test $${tname} again."; \
+ else \
+ echo "============================" > $${log}; \
+ if test "X$(FORTRAN_API)" = "Xyes"; then \
+ echo "Fortran API: Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "Fortran API: $(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ elif test "X$(CXX_API)" = "Xyes"; then \
+ echo "C++ API: Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "C++ API: $(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log};\
+ else \
+ echo "Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "$(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ fi; \
+ echo "============================" >> $${log}; \
+ srcdir="$(srcdir)" \
+ $(TIME) $(RUNEXEC) ./$${tname} $(TEST_FLAGS) >> $${log} 2>&1 \
+ && touch $(@:.chkexe_=.chkexe) || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ (cat $${log} && false) || exit 1; \
+ echo "" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)" >> $${log}; \
+ echo "============================" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)"; \
+ cat $${log}; \
+ fi; \
+ fi
+
+# The dummysh.chkexe here prevents the target from being
+# empty if there are no tests in the current directory.
+# $${log} is the log file.
+# $${tname} is the name of test.
+$(TEST_SCRIPT_CHKSH) $(TEST_SCRIPT_PARA_CHKSH) dummysh.chkexe_:
+ @if test "X$@" != "X.chkexe_" && test "X$@" != "Xdummysh.chkexe_"; then \
+ cmd=$(@:.chkexe_=);\
+ tname=`basename $$cmd`;\
+ chkname=`basename $(@:.chkexe_=.chkexe)`;\
+ log=`basename $(@:.chkexe_=.chklog)`; \
+ echo "============================"; \
+ if $(top_srcdir)/bin/newer $${chkname} $$cmd $(SCRIPT_DEPEND); then \
+ echo "No need to test $${tname} again."; \
+ else \
+ echo "============================" > $${log}; \
+ if test "X$(FORTRAN_API)" = "Xyes"; then \
+ echo "Fortran API: Testing $${tname} $(TEST_FLAGS)"; \
+ echo "Fortran API: $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ elif test "X$(CXX_API)" = "Xyes"; then \
+ echo "C++ API: Testing $${tname} $(TEST_FLAGS)"; \
+ echo "C++ API: $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ else \
+ echo "Testing $${tname} $(TEST_FLAGS)"; \
+ echo "$${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ fi; \
+ echo "============================" >> $${log}; \
+ RUNSERIAL="$(RUNSERIAL)" RUNPARALLEL="$(RUNPARALLEL)" \
+ srcdir="$(srcdir)" \
+ $(TIME) $(SHELL) $$cmd $(TEST_FLAGS) >> $${log} 2>&1 \
+ && touch $${chkname} || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ (cat $${log} && false) || exit 1; \
+ echo "" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)" >> $${log}; \
+ echo "============================" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)"; \
+ cat $${log}; \
+ fi; \
+ echo "============================"; \
+ fi
+
+# Actual execution of check-p.
+build-check-p: $(LIB) $(PROGS) $(chk_TESTS)
+ @if test -n "$(TEST_PROG_PARA)$(TEST_SCRIPT_PARA)"; then \
+ echo "===Parallel tests in `echo ${PWD} | sed -e s:.*/::` begin `date`==="; \
+ fi
+ @if test -n "$(TEST_PROG_PARA)"; then \
+ echo "**** Hint ****"; \
+ echo "Parallel test files reside in the current directory" \
+ "by default."; \
+ echo "Set HDF5_PARAPREFIX to use another directory. E.g.,"; \
+ echo " HDF5_PARAPREFIX=/PFS/user/me"; \
+ echo " export HDF5_PARAPREFIX"; \
+ echo " make check"; \
+ echo "**** end of Hint ****"; \
+ fi
+ @for test in $(TEST_PROG_PARA) dummy; do \
+ if test $$test != dummy; then \
+ $(MAKE) $(AM_MAKEFLAGS) $$test.chkexe_ \
+ RUNEXEC="$(RUNPARALLEL)" || exit 1; \
+ fi; \
+ done
+ @for test in $(TEST_SCRIPT_PARA) dummy; do \
+ if test $$test != dummy; then \
+ $(MAKE) $(AM_MAKEFLAGS) $$test.chkexe_ || exit 1; \
+ fi; \
+ done
+ @if test -n "$(TEST_PROG_PARA)$(TEST_SCRIPT_PARA)"; then \
+ echo "===Parallel tests in `echo ${PWD} | sed -e s:.*/::` ended `date`===";\
+ fi
+
+# Run test with different Virtual File Driver
+check-vfd: $(LIB) $(PROGS) $(chk_TESTS)
+ @for vfd in $(VFD_LIST) dummy; do \
+ if test $$vfd != dummy; then \
+ echo "============================"; \
+ echo "Testing Virtual File Driver $$vfd"; \
+ echo "============================"; \
+ $(MAKE) $(AM_MAKEFLAGS) check-clean || exit 1; \
+ HDF5_DRIVER=$$vfd $(MAKE) $(AM_MAKEFLAGS) check || exit 1; \
+ fi; \
+ done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/hdf5.h b/src/hdf5.h
new file mode 100644
index 0000000..fc4541a
--- /dev/null
+++ b/src/hdf5.h
@@ -0,0 +1,54 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * This is the main public HDF5 include file. Put further information in
+ * a particular header file and include that here, don't fill this file with
+ * lots of gunk...
+ */
+#ifndef _HDF5_H
+#define _HDF5_H
+
+#include "H5public.h"
+#include "H5Apublic.h" /* Attributes */
+#include "H5ACpublic.h" /* Metadata cache */
+#include "H5Dpublic.h" /* Datasets */
+#include "H5Epublic.h" /* Errors */
+#include "H5Fpublic.h" /* Files */
+#include "H5FDpublic.h" /* File drivers */
+#include "H5Gpublic.h" /* Groups */
+#include "H5Ipublic.h" /* ID management */
+#include "H5Lpublic.h" /* Links */
+#include "H5MMpublic.h" /* Memory management */
+#include "H5Opublic.h" /* Object headers */
+#include "H5Ppublic.h" /* Property lists */
+#include "H5PLpublic.h" /* Plugins */
+#include "H5Rpublic.h" /* References */
+#include "H5Spublic.h" /* Dataspaces */
+#include "H5Tpublic.h" /* Datatypes */
+#include "H5Zpublic.h" /* Data filters */
+
+/* Predefined file drivers */
+#include "H5FDcore.h" /* Files stored entirely in memory */
+#include "H5FDdirect.h" /* Linux direct I/O */
+#include "H5FDfamily.h" /* File families */
+#include "H5FDlog.h" /* sec2 driver with I/O logging (for debugging) */
+#include "H5FDmpi.h" /* MPI-based file drivers */
+#include "H5FDmulti.h" /* Usage-partitioned file family */
+#include "H5FDsec2.h" /* POSIX unbuffered file I/O */
+#include "H5FDstdio.h" /* Standard C buffered I/O */
+#ifdef H5_HAVE_WINDOWS
+#include "H5FDwindows.h" /* Windows buffered I/O */
+#endif
+
+#endif
diff --git a/src/libhdf5.settings.in b/src/libhdf5.settings.in
new file mode 100644
index 0000000..8017594
--- /dev/null
+++ b/src/libhdf5.settings.in
@@ -0,0 +1,85 @@
+ SUMMARY OF THE HDF5 CONFIGURATION
+ =================================
+
+General Information:
+-------------------
+ HDF5 Version: @H5_VERSION@
+ Configured on: @CONFIG_DATE@
+ Configured by: @CONFIG_USER@
+ Host system: @host_cpu@-@host_vendor@-@host_os@
+ Uname information: @UNAME_INFO@
+ Byte sex: @BYTESEX@
+ Installation point: @prefix@
+
+Compiling Options:
+------------------
+ Build Mode: @BUILD_MODE@
+ Debugging Symbols: @SYMBOLS@
+ Asserts: @ASSERTS@
+ Profiling: @PROFILING@
+ Optimization Level: @OPTIMIZATION@
+
+Linking Options:
+----------------
+ Libraries: @STATIC_SHARED@
+ Statically Linked Executables: @LT_STATIC_EXEC@
+ LDFLAGS: @LDFLAGS@
+ H5_LDFLAGS: @H5_LDFLAGS@
+ AM_LDFLAGS: @AM_LDFLAGS@
+ Extra libraries: @LIBS@
+ Archiver: @AR@
+ Ranlib: @RANLIB@
+
+Languages:
+----------
+ C: yes
+ C Compiler: @CC_VERSION@
+ CPPFLAGS: @CPPFLAGS@
+ H5_CPPFLAGS: @H5_CPPFLAGS@
+ AM_CPPFLAGS: @AM_CPPFLAGS@
+ C Flags: @CFLAGS@
+ H5 C Flags: @H5_CFLAGS@
+ AM C Flags: @AM_CFLAGS@
+ Shared C Library: @enable_shared@
+ Static C Library: @enable_static@
+
+
+ Fortran: @HDF_FORTRAN@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ Fortran Compiler: @FC_VERSION@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ Fortran Flags: @FCFLAGS@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ H5 Fortran Flags: @H5_FCFLAGS@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ AM Fortran Flags: @AM_FCFLAGS@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ Shared Fortran Library: @H5_FORTRAN_SHARED@
+@BUILD_FORTRAN_CONDITIONAL_TRUE@ Static Fortran Library: @enable_static@
+
+ C++: @HDF_CXX@
+@BUILD_CXX_CONDITIONAL_TRUE@ C++ Compiler: @CXX_VERSION@
+@BUILD_CXX_CONDITIONAL_TRUE@ C++ Flags: @CXXFLAGS@
+@BUILD_CXX_CONDITIONAL_TRUE@ H5 C++ Flags: @H5_CXXFLAGS@
+@BUILD_CXX_CONDITIONAL_TRUE@ AM C++ Flags: @AM_CXXFLAGS@
+@BUILD_CXX_CONDITIONAL_TRUE@ Shared C++ Library: @enable_shared@
+@BUILD_CXX_CONDITIONAL_TRUE@ Static C++ Library: @enable_static@
+
+ Java: @HDF_JAVA@
+@BUILD_JAVA_CONDITIONAL_TRUE@ Java Compiler: @JAVA_VERSION@
+
+
+Features:
+---------
+ Parallel HDF5: @PARALLEL@
+ High-level library: @HDF5_HL@
+ Threadsafety: @THREADSAFE@
+ Default API mapping: @DEFAULT_API_VERSION@
+ With deprecated public symbols: @DEPRECATED_SYMBOLS@
+ I/O filters (external): @EXTERNAL_FILTERS@
+ MPE: @MPE@
+ Direct VFD: @DIRECT_VFD@
+ dmalloc: @HAVE_DMALLOC@
+ Packages w/ extra debug output: @INTERNAL_DEBUG_OUTPUT@
+ API tracing: @TRACE_API@
+ Using memory checker: @USINGMEMCHECKER@
+Memory allocation sanity checks: @MEMORYALLOCSANITYCHECK@
+ Metadata trace file: @METADATATRACEFILE@
+ Function stack tracing: @CODESTACK@
+ Strict file format checks: @STRICT_FORMAT_CHECKS@
+ Optimization instrumentation: @INSTRUMENT_LIBRARY@